# How to skin menus [SOLVED]



## Fredeke (Dec 14, 2018)

Hi again everyone.

I just started my first skinned script, so I might have a lot of questions for the next few weeks... Here's the first one 

I'm having a hard time determining which UI elements are skinnable (I mean, for which kind can I provide a custom picture to replace its generic look)

( - Already solved: I wanted to skin knobs, and since they were not skinnable, I had to emulate them with knob-skinned sliders, and that works fine. )

( - I also wanted to skin buttons, and since they are skinnable and there's plenty info on how to do this, I achieved it easily. )

- But, are _menus_ skinnable ? If so, I'd like to see an example of code for this.

- How about _labels_ ? (Example welcome too)

- If menus and/or labels are not skinnable, which class of element can I emulate them with ? (Like, buttons with changing picture, for example ?) - and how to do that ? (Here I don't necessarily need the code, but at least the principle in plain English)

Thank you all in advance.


----------



## polypx (Dec 14, 2018)

A menu can have a graphic, but only for it's "closed" state. When it's open it looks the same as you see it now.
A label can have a graphic.


----------



## EvilDragon (Dec 14, 2018)

Actually ui_menus do use frames 1, 3 and 5 of the regular 6-frame button graphic. It's just often covered by what pops up so you don't see it.


----------



## Fredeke (Dec 14, 2018)

@polypx : well that's better than nothing anyway, and maybe sufficient for me not to bother with a workaround...

@EvilDragon : I am much interested in what you're saying, but I'm not really getting it. Could you elaborate please ? ( I know what a 6-frame button graphic is, but that's about it)


----------



## polypx (Dec 14, 2018)

EvilDragon said:


> Actually ui_menus do use frames 1, 3 and 5 of the regular 6-frame button graphic. It's just often covered by what pops up so you don't see it.



Ah right, I noticed the rollover before, but never the mouse down.  In any case, in terms of customisation, what I meant was you can't customize the popup once it's "popped up". You can't even set those fonts.


----------



## Fredeke (Dec 14, 2018)

Ok, so I'm trying to do as you suggest... And here's already my next question:

Since the menu's pop-up cannot be customized, I've got to populate it with add_menu_item(), right ?
Then how do I prevent the text of the selected entry from showing on top of my custom picture ?

(in short... Which $CONTROL_PAR do I need to _HIDE ?  )


----------



## P.N. (Dec 14, 2018)

Fredeke said:


> Then how do I prevent the text of the selected entry to show on top of my custom picture ?



Move it away with $CONTROL_PAR_TEXTPOS_Y.


----------



## Fredeke (Dec 14, 2018)

@P.N. : Dirty, funny and efficient solution :-D I just followed your advice and it works. Is it really the proper way however ?


----------



## EvilDragon (Dec 14, 2018)

Yes that's the proper/only possible way.


----------



## Fredeke (Dec 14, 2018)

I mourn my customized pop-ups, but I'll probably stick to your way because a workaround would add complexity to an already extensive script. I'll first implement your advices and see how it looks.

One thing I still don't get (and I believe EvilDragon tried to explain) : how would you change the menu's graphic according to the selected entry ?


----------



## P.N. (Dec 14, 2018)

At least for Kontakt 5. Maybe K6 will have a dedicated command for this in the future...

I read they added the $CONTROL_PAR_TEXTPOS_Y for value_edits, which is very welcome, so.. who knows?

Cheers.


----------



## P.N. (Dec 14, 2018)

Fredeke said:


> One thing I still don't get (and I believe EvilDragon tried to explain) : how would you change the menu's graphic according to the selected entry ?



Evil Dragon was talking about the image states for the menu graphic element.

What you need is a label, with picture states that are updated based on the selected entry.

You place it under the menu (it will be under by default). Make your menu graphics transparent (maybe just add picture state 5 for mouse over) and that's it.


----------



## polypx (Dec 14, 2018)

Fredeke said:


> how would you change the menu's graphic according to the selected entry ?


Stick a label over top and $CONTROL_PAR_PICTURE_STATE


----------



## Fredeke (Dec 14, 2018)

Ok I almost got it.

What do you mean by "updating the picture states" ? To what command do you refer ? Do you mean changing the picture file ? (And why is it easier to do with labels than menus ?)


----------



## P.N. (Dec 14, 2018)

Fredeke said:


> To what command do you refer ?





polypx said:


> Stick a label over top and $CONTROL_PAR_PICTURE_STATE






Fredeke said:


> Do you mean changing the picture file ?


This would be an extra step for something deeper, which may not be what you need now.
(it gets dirtier... )


----------



## Fredeke (Dec 14, 2018)

Right.
Now N.I.'s manual is pretty laconic about $CONTROL_PAR_PICTURE_STATE. All it says is : "the picture state of the control for tables, value edits and labels."
... So, what is a picture state ? And what values can I give it ? (Anything to do with 1 to 6, maybe ?)


----------



## P.N. (Dec 14, 2018)

Fredeke, i'll make a quick example and post it here later.


----------



## Fredeke (Dec 14, 2018)

@P.N. : Yes, please ! And later is fine, since I've got to go for now. 
Good evening (or morning, or something)


----------



## Mike Greene (Dec 14, 2018)

Fredeke said:


> Now N.I.'s manual is pretty laconic about $CONTROL_PAR_PICTURE_STATE. All it says is : "the picture state of the control for tables, value edits and labels."
> ... So, what is a picture state ? And what values can I give it ? (Anything to do with 1 to 6, maybe ?)


For some reason, they explain this in the Developers Guide (which dates back to Kontakt 4), but I don't think it's in the regular KSP manual. So if you don't have this already, here is the documentation from the Developers' Guide:

*5.5 Preparing Image Files

5.5.1 Accompanying Text File *

Each image must be accompanied by a text (.txt) file of the same name containing important information on how KONTAKT should read this image. If a text file is not provided, any image file in the user picture folder will have a default one generated. If the image file is in the factory folder a text file will not be generated, but the image will be read by KONTAKT as if the values were set to default.

Here is an example of the content of one of these text files:
Has Alpha Channel: yes
Number of Animations: 6
Horizontal Animation: no
Vertical Resizable: no
Horizontal Resizable: yes
Fixed Top: 0
Fixed Bottom: 0
Fixed Left: 0
Fixed Right: 17

The list explained:

* Has Alpha Chann*el: (yes or no) tells KONTAKT whether or not the image file contains a transparent (alpha) layer. If in doubt, set this to “yes”, as this will cause no problems either way.

* Number of animation*s: sets the number of frames in the image. KONTAKT then equally divides the image using this number.

* Horizontal Animatio*n: (yes or no) designates in what direction the image should be split.

* Vertical Resizabl*e: (yes or no) if set to yes, it is possible to adjust the height of the image file in KONTAKT using the $CONTROL_PAR_HEIGHT constant in the set_control_par command.

* Horizontal Resizabl*e: (yes or no) if set to yes, it is possible to adjust the width of the image file in KONTAKT using the using the $CONTROL_PAR_WIDTH constant.

* Fixed Top/Bottom/Left/Righ*t: if you wish to be able to resize an image, but keep a certain area around the edge intact, simply set the number of pixels in the desired area. In the above example, the image is able to be resized horizontally, but the 17 pixels on the right side of the image will not be stretched.

It is important to note that KONTAKT is currently very sensitive about text file line break encoding. In our experience, the safest software to use is Notepad on Windows. This is unfortunately also true for scripts that link to external text files.

Please take note that wallpapers also need a text file although the text file’s parameters will be ignored.

*5.5.2 Animations *

Image files to be used in KONTAKT must be saved as *.png files. In order for KONTAKT to treat the image correctly, it must be provided in as stack of animations. So if you want one knob with 100 states, you need to build a very long image with all of these states in a row or column. KONTAKT will read the file top to bottom or left to right, depending on the setting of the .txt file. So your lowest value for a knob should be at the top or left and the highest at the bottom or right.

*5.5.3 Switches and Dropdowns *

Switches and Dropdowns should always have six animations, in a set order:

State

1 Off
2 On
3 Off, mouse down
4 On, mouse down
5 Off, mouse over
6 On, mouse over
The following script will illustrate the different states of a switch.

► First, copy the image and text files “switch_state_example” to the KONTAKT 4 user pictures folder. Then copy and paste the following script into a new KONTAKT instrument:

on init
make_perfview
declare ui_switch $switch_states
set_control_par_str(get_ui_id($switch_states),$CONTROL_PAR_TEXT,"")
set_control_par_str(get_ui_id($switch_states),$CONTROL_PAR_PICTURE,...
"switch_state_example")
end on

This will produce a single button that changes color depending on its state:

State
1 Off Black
2 On Red
3 Off, mouse down Orange
4 On, mouse down Yellow
5 Off, mouse over Purple
6 On, mouse over Green

Image files must always have six animations, even if you only plan to use the basic on/off. In this case, just triplicate the two on/off animations to bring the total up to six.


----------



## P.N. (Dec 14, 2018)

Here's an nki with 2 possible scenarious:

The first would be the typical menu, with fixed mouse over image:





The second would update the menu mouse over image with something that matches the labels:





Since i tried to include both scenarious in one nki, some of the code may be confusing.
Let me know.
You could use string arrays for the dynamic menu images, but it wasn't necessary in this case as the images are numbered according to the menu values.

You could ditch the menu image completely if it's not something you need.
In that case, simply leave the menu images transparent.

Cheers.

EDIT: Forgot to include the code:



Spoiler: Code





```
on init
    {General}
    set_ui_height_px(278)
    set_ui_color(994948fh)
    make_perfview
    
    {Positions}
    declare $pos_x := 227
    declare $pos_y := 50
    declare $offset := 3
    
    {Menu}
    declare ui_menu $menu
    set_control_par_str(get_ui_id($menu),$CONTROL_PAR_PICTURE,"menu_outline")
    set_control_par(get_ui_id($menu),$CONTROL_PAR_TEXTPOS_Y,200)
    move_control_px($menu,$pos_x,$pos_y)
    make_persistent($menu)
    
    {Menu Entries}
    add_menu_item($menu,"SQUARE",0)
    add_menu_item($menu,"CIRCLE",1)
    add_menu_item($menu,"TRIANGLE",2)
    
    {Menu Label}
    declare ui_label $menu_entries_label(1,1)
    set_control_par_str(get_ui_id($menu_entries_label),$CONTROL_PAR_TEXT,"")
    set_control_par_str(get_ui_id($menu_entries_label),$CONTROL_PAR_PICTURE,"menu_entries_label")
    move_control_px($menu_entries_label,$pos_x+$offset,$pos_y+$offset)
    
    {Option}
    declare ui_button $option
    set_control_par(get_ui_id($option),$CONTROL_PAR_WIDTH,181)
    set_control_par_str(get_ui_id($option),$CONTROL_PAR_TEXT,"")
    set_control_par(get_ui_id($option),$CONTROL_PAR_TEXT_ALIGNMENT,1)
    move_control_px($option,$pos_x+$offset,$pos_y-30)
    make_persistent($option)
    
    declare !option_text[2]
    !option_text[0] := "FIXED MENU MOUSE OVER IMAGE"
    !option_text[1] := "DYNAMIC MENU MOUSE OVER IMAGE"
    
end on

function menu_update
    set_control_par(get_ui_id($menu_entries_label),$CONTROL_PAR_PICTURE_STATE,$menu)
    
    if($option = 0)
        set_control_par_str(get_ui_id($menu),$CONTROL_PAR_PICTURE,"menu_outline")
    else
        set_control_par_str(get_ui_id($menu),$CONTROL_PAR_PICTURE,"menu_outline" & "_" & $menu)
    end if
    
    set_control_par_str(get_ui_id($option),$CONTROL_PAR_TEXT,!option_text[$option])

end function

on persistence_changed
    call menu_update
end on

on ui_control($menu)
    call menu_update
end on

on ui_control($option)
    call menu_update
end on
```


----------



## EvilDragon (Dec 14, 2018)

It is *always *a better idea to use picture state changing as much as possible rather than on the fly swapping the image. Just FYI.


----------



## P.N. (Dec 14, 2018)

EvilDragon said:


> It is *always *a better idea to use picture state changing as much as possible rather than on the fly swapping the image. Just FYI.



Was that in response to the example? It's using picture state...
There's just an optional situation where the user could swap the menu's image (not the label) on the fly to accomodate a more graphically pleasing result. That's it... 

(Imagine if i had posted an animated menu... :D)


----------



## EvilDragon (Dec 14, 2018)

P.N. said:


> There's just an optional situation where the user could swap the menu's image (not the label) on the fly to accomodate a more graphically pleasing result. That's it...



Yes, that's what I was referring to. You can still do the same thing with picture state and a label.


----------



## P.N. (Dec 15, 2018)

EvilDragon said:


> Yes, that's what I was referring to. You can still do the same thing with picture state and a label.



It's not the same thing, ED. The second scenario with the on-the-fly dynamic images means that the mouse over functionality for the menu remains coherent with the selected entry images.
It's really just the icing on the cake, nothing else.

Please try the example as it shows this in action.

In this case, the label could be completely ignored/removed (though it could still be kept in case of an animated menu...)

I'm just trying to show options to make the GUI prettier/more flexible.


----------



## Fredeke (Dec 15, 2018)

Ok guys, thanks a lot !

I've got a lot to do today, and assimilating the lessons from P.N.'s example will probably take me part of the afternoon, but I'll get back here ASAP with feedback (and possibly more questions  )]


----------



## Fredeke (Dec 15, 2018)

Ok I'm back.

@P.N.: First of all, your example was very clear. Thank you.

Here's what I understand from it (which I believe is about everything). Please correct me if I'm wrong :

- The picture state is the frame index in an animation strip. For example, if a picture file has its Number of Animations set to 6, then there are 6 picture states, numbered from 0 to 5.

- The graphic for a menu must always have 6 states, of which only states 0, 2 and 4 (that is the 1st, 3rd and 5th ones) are used, for mouse over and mouse down effects, as EvilDragon explained earlier.

The reason for this is that menus use the same state scheme as buttons, but only _off_ states are used, because menus aren't binary on/off controls.

- Since the 'animatability' of the menu's graphic is already taken by mouse effects, an underlying label must contain the actual menu's graphics, of which each state corresponds to each possible menu item.

I still don't get why this is better than swapping whole picture files, but I find it actually convenient, so ok.

- The menu doesn't need to be hidden in order to reveal the underlying label. It only needs a mostly transparent picture, and its text content moved away via an intentionally excessive pixel offset.

That was a very educative example, aimed right at my expertise level 

Just one remark, in case you didn't realize : I had to update from Kontakt 5.2 to 6.0 in order to open your example. The only reason I can see for that is your use of the persistence_changed callback. Anyway, I'm glad I updated.


----------



## P.N. (Dec 15, 2018)

Fredeke said:


> I don't get why this is better than swapping whole picture files, but I find it actually convenient, so ok.



Imagine you have 30 entries - you'd need 30 different images for the menu instead of 1 single pixel strip with image states.

The reason i included the "dynamic mouse over" version was just to show you the 2 different methods.
If the image swapping method makes sense for you, or improves your presentation, that's up to you.

The reason for not doing it would be efficiency and resources management - but please don't take my word on this as i never ran tests that could show a palpable decrease in performance.

Again, if you are happy with the menu's fixed mouse over interactivity (or if you don't even need graphics for that), stick with the label and picture state approach as that's the fastest/easiest way.



Fredeke said:


> Just one thing (though this is probably just a detail) : what is the persistence_changed callback ? I couldn't find it in KSP5's reference. Is it KSP6 ? (I had to update my Kontakt version in order to run your example)



It's in the K5 reference manual, yes. It could be summarized as... an extension of the init portion of the script, or even a "kind of special function" that is automatically called upon after "on init".


----------



## Fredeke (Dec 15, 2018)

P.N. said:


> It's in the K5 reference manual, yes. It could be summarized as... an extension of the init portion of the script, or even a "kind of special function" that is automatically called upon after "on init".



Seems like they introduced it in version 5.7, or sometime between 5.2 and 5.7 anyway. However, in your exemple, I believe it would make the menu_update function be executed twice each time once is needed. Not a big deal in this case, of course.


----------



## P.N. (Dec 15, 2018)

Fredeke said:


> Just one remark, in case you didn't realize : I had to update from Kontakt 5.2 to 6.0 in order to open your example. The only reason I can see for that is your use of the persistence_changed callback. Anyway, I'm glad I updated.



Oh, that. Sorry about that. It was not related to the persistence callback.
I made the nki in 5.7.0. which is the oldest version i use for examples.

You needed the update! :D


----------



## Fredeke (Dec 15, 2018)

P.N. said:


> You needed the update! :D



Yes I did. But I'm still going to develop in 5.2 for broader compatibility. That is, until I find a newer command that I can't live without !


----------



## P.N. (Dec 15, 2018)

The nki wouldn't work because it was a more recent version, but did you try the code directly in 5.2? I'm almost sure persistence changed arrived with the first release of K5...


----------



## Fredeke (Dec 15, 2018)

I just copypasted your script in Kontakt 5.2, and there are two things it can't parse : command _set_ui_color_ and callback _persistence_changed_. After confronting different versions of the reference manual, it seems they were both added in 5.7. Or some time in between.

_set_ui_color_ is a fine addition btw (could become that new command I can't live without  ).


----------



## P.N. (Dec 15, 2018)

I could swear persistence changed came with vanilla k5... 
But i only started scripting in 5.5 or something...
Thank you for the information. 

You should check out other useful commands and controls that were added.
XY pad, increased width, etc. Too much stuff to remember...


----------



## Fredeke (Dec 15, 2018)

P.N. said:


> You should check out other useful commands and controls that were added.
> XY pad, increased width, etc. Too much stuff to remember...



Sounds appealing !

But do you know which portion of the user base still uses older versions ? I arbitrarily chose version 5.2 because that's the one I have... but are still many people using versions 3 or 4, for example ? Or is everybody at least on version 5.7 ? I should aim at the best possible compromise between language maturity (if we can ever call it that !) and customer base.

And I really don't know the versographics (that's my portmanteau of _version_ and _demographics_) of Kontakt because I actually never use it to make music (not nerdy enough for me - I am more of a Renoise guy), I just use it to make commercial libraries, of which I hope to release the first soon.


----------



## EvilDragon (Dec 15, 2018)

P.N. said:


> I'm almost sure persistence changed arrived with the first release of K5...



persistence_changed was added along with snapshots in Kontakt 5.4.



Fredeke said:


> But do you know which portion of the user base still uses older versions ?



Here's a related thread: https://vi-control.net/community/th...t-version-of-kontakt-you-primarily-use.77799/

Looks like at least in this sample of users, most are on latest versions. You don't have to worry about going too far back. Certainly not to K5.2 (or did you mean K5.5.2?).


----------



## P.N. (Dec 15, 2018)

Fredeke said:


> Seems like they introduced it in version 5.7, or sometime between 5.2 and 5.7 anyway.





EvilDragon said:


> persistence_changed was added along with snapshots in Kontakt 5.4.



Thank you both for the correction.
Persistence changed is one of those things i really take for granted and i cannot imagine doing a script without it, for all the reasons you know.


----------



## geronimo (Dec 16, 2018)

P.N. said:


> I read they added the $CONTROL_PAR_TEXTPOS_Y for value_edits, which is very welcome, so.. who knows?



Since we're overflowing with graphical and technical discussion, I wonder about the practical utility of this function of shifting the whole text on the Value edit ..?


----------



## P.N. (Dec 16, 2018)

In K5, if you don't use the default font, your text won't align properly with the arrows, for example.
Since value edit doesn't support textpos in K5, you're stuck with this offset...


----------



## Fredeke (Dec 16, 2018)

EvilDragon said:


> Looks like at least in this sample of users, most are on latest versions. You don't have to worry about going too far back. Certainly not to K5.2 (or did you mean K5.5.2?).



No, I really meant 5.2  - I did't realize I was being so backwards !

Maybe I could aim at 5.7, which seems to be some kind of milestone (I'm not sure but I think it's the oldest updatable one to 6.0). Or maybe 5.8, which seems to be almost everybody's version.


----------



## Fredeke (Dec 16, 2018)

Ok guys... As you know I implemented P.N.'s example (which was the solution everybody was trying to explain to me) with success.

Then I wanted to devise a way of customizing the drop-down part of the menu as well. It took me a while, and the code is much, much longer :



Spoiler: code





```
on init
  declare $mn_unison := 0
  declare ui_button $mbt_unison
  declare ui_button $mbt_unison_analog
  declare ui_button $mbt_unison_digital
  declare ui_button $mbt_unison_hybrid
  declare ui_label  $mlb_unison (1,1)
  set_control_par_str (get_ui_id ($mbt_unison), $CONTROL_PAR_PICTURE, "mn-unison--")
  set_control_par_str (get_ui_id ($mlb_unison), $CONTROL_PAR_PICTURE, "mn-unison")
  set_control_par_str (get_ui_id ($mbt_unison), $CONTROL_PAR_TEXT, "")
  set_control_par_str (get_ui_id ($mlb_unison), $CONTROL_PAR_TEXT, "")
  set_control_par (get_ui_id ($mbt_unison), $CONTROL_PAR_POS_X, 388)
  set_control_par (get_ui_id ($mbt_unison), $CONTROL_PAR_POS_Y, 72)
  set_control_par (get_ui_id ($mlb_unison), $CONTROL_PAR_POS_X, 393)
  set_control_par (get_ui_id ($mlb_unison), $CONTROL_PAR_POS_Y, 75)
  set_control_par (get_ui_id ($mbt_unison), $CONTROL_PAR_WIDTH,  99)
  set_control_par (get_ui_id ($mbt_unison), $CONTROL_PAR_HEIGHT, 14)
  set_control_par (get_ui_id ($mlb_unison), $CONTROL_PAR_WIDTH,  91)
  set_control_par (get_ui_id ($mlb_unison), $CONTROL_PAR_HEIGHT, 12)
  set_control_par_str (get_ui_id ($mbt_unison_analog),  $CONTROL_PAR_PICTURE, "mn-unison--analog")
  set_control_par_str (get_ui_id ($mbt_unison_digital), $CONTROL_PAR_PICTURE, "mn-unison--digital")
  set_control_par_str (get_ui_id ($mbt_unison_hybrid),  $CONTROL_PAR_PICTURE, "mn-unison--hybrid")
  set_control_par_str (get_ui_id ($mbt_unison_analog),  $CONTROL_PAR_TEXT, "")
  set_control_par_str (get_ui_id ($mbt_unison_digital), $CONTROL_PAR_TEXT, "")
  set_control_par_str (get_ui_id ($mbt_unison_hybrid),  $CONTROL_PAR_TEXT, "")
  set_control_par (get_ui_id ($mbt_unison_analog),  $CONTROL_PAR_POS_X, 388)
  set_control_par (get_ui_id ($mbt_unison_digital), $CONTROL_PAR_POS_X, 388)
  set_control_par (get_ui_id ($mbt_unison_hybrid),  $CONTROL_PAR_POS_X, 388)
  set_control_par (get_ui_id ($mbt_unison_analog),  $CONTROL_PAR_POS_Y,  74)
  set_control_par (get_ui_id ($mbt_unison_digital), $CONTROL_PAR_POS_Y,  86)
  set_control_par (get_ui_id ($mbt_unison_hybrid),  $CONTROL_PAR_POS_Y,  98)
  set_control_par (get_ui_id ($mbt_unison_analog),  $CONTROL_PAR_WIDTH,  99)
  set_control_par (get_ui_id ($mbt_unison_analog),  $CONTROL_PAR_HEIGHT, 16)
  set_control_par (get_ui_id ($mbt_unison_digital), $CONTROL_PAR_WIDTH,  99)
  set_control_par (get_ui_id ($mbt_unison_digital), $CONTROL_PAR_HEIGHT, 16)
  set_control_par (get_ui_id ($mbt_unison_hybrid),  $CONTROL_PAR_WIDTH,  99)
  set_control_par (get_ui_id ($mbt_unison_hybrid),  $CONTROL_PAR_HEIGHT, 16)
  set_control_par (get_ui_id ($mbt_unison_analog),  $CONTROL_PAR_HIDE, $HIDE_WHOLE_CONTROL)
  set_control_par (get_ui_id ($mbt_unison_digital), $CONTROL_PAR_HIDE, $HIDE_WHOLE_CONTROL)
  set_control_par (get_ui_id ($mbt_unison_hybrid),  $CONTROL_PAR_HIDE, $HIDE_WHOLE_CONTROL)
end on

function mn_unison
  if ($mbt_unison = 1)
    set_control_par (get_ui_id ($mbt_unison_analog),  $CONTROL_PAR_HIDE, $HIDE_PART_NOTHING)
    set_control_par (get_ui_id ($mbt_unison_digital), $CONTROL_PAR_HIDE, $HIDE_PART_NOTHING)
    set_control_par (get_ui_id ($mbt_unison_hybrid),  $CONTROL_PAR_HIDE, $HIDE_PART_NOTHING)
  else
    set_control_par (get_ui_id ($mlb_unison), $CONTROL_PAR_PICTURE_STATE, $mn_unison)
    set_control_par (get_ui_id ($mbt_unison_analog),  $CONTROL_PAR_HIDE, $HIDE_WHOLE_CONTROL)
    set_control_par (get_ui_id ($mbt_unison_digital), $CONTROL_PAR_HIDE, $HIDE_WHOLE_CONTROL)
    set_control_par (get_ui_id ($mbt_unison_hybrid),  $CONTROL_PAR_HIDE, $HIDE_WHOLE_CONTROL)
  end if
  $mbt_unison_analog := 0
  $mbt_unison_digital := 0
  $mbt_unison_hybrid := 0
  select ($mn_unison)
   case 0
    $mbt_unison_analog := 1
   case 1
    $mbt_unison_digital := 1
   case 2
    $mbt_unison_hybrid := 1
  end select
end function
on ui_control ($mbt_unison)
  call mn_unison
end on
on ui_control ($mbt_unison_analog)
  $mn_unison := 0
  $mbt_unison := 0
  call mn_unison
end on
on ui_control ($mbt_unison_digital)
  $mn_unison := 1
  $mbt_unison := 0
  call mn_unison
end on
on ui_control ($mbt_unison_hybrid)
  $mn_unison := 2
  $mbt_unison := 0
  call mn_unison
end on
```




It displays a menu I call "unison", containing 3 items: "analog", "digital" and "hybrid", by simulating a menu's behaviour using only labels and buttons.

The result looks gorgeous of course. But you can basically multiply the code's length by the number of items... And the example here is for only 3 items !

So now the question is: does it add too much complexity to my script ? I mean I haven't started the serious coding yet, and when I do, I hope my code won't get so convoluted that I get lost in it.
So I have a choice to make... But I'm glad I tried anyway.

Thanks everybody for getting me going !
I needed this conversation in order to know the strenghts and limitations of KSP in regard to what I'm trying to do, and also to teach me the few concepts I was missing (like picture states etc.)

NOTE TO PEOPLE COMING TO THIS THREAD BECAUSE OF THE [SOLVED] TAG : Go read P.N.'s solution a few posts earlier, it's much simpler than this one - and probably the proper way to do it.


----------



## EvilDragon (Dec 16, 2018)

Within the spoiler tag you should've used the CODE tags, so that all the indents are preserved. As it is, they're not preserved, which ain't cool looking at 



Fredeke said:


> But this is for merely 3 items, and you can basically multiply the code's length by the number of items !



This is where you should start to use functions to make things easier and more scalable.

But yes, overall that solution is really not very efficient in the long run. People are used to how the popup menu in Kontakt looks, anyways, I wouldn't bother


----------



## Fredeke (Dec 16, 2018)

EvilDragon said:


> Within the spoiler tag you should've used the CODE tags, so that all the indents are preserved. As it is, they're not preserved, which ain't cool looking at



I'll do that right away.



EvilDragon said:


> This is where you should start to use functions to make things easier and more scalable.



Unfortunately there are extreme limitations to functions in KSP, which really limit their usefulness :
- a function must be declared before any call to it
- you can't pass arguments to a function
- a function can't return a result.

I'm not sure what I can do with those limitations. Unless they were lifted since version 5.2 ?
To me, they mean that you can use a function to perform one exact same task several times, but hardly to perform variations on a task (like drawing similar but different elements - like menus or menu items...). There are of course workarounds, but I'm not sure they would make things simpler.

The ideal would be to create a "menu" object class, but KSP isn't object-oriented at all.

I do understand the reason for such limitations : the language must be interpreted in real time, and the interpreter can be encapsulated in a VST plugin, hosted by who knows which DAW... Those are many layers slowing down your scripts, hence the language must be rudimentary in order to be interpreted as fast as possible. That is why my version 5.2 did not even support real numbers (only integers) ! At least it was nice to learn that I can use real numbers now 



EvilDragon said:


> But yes, overall that solution is really not very efficient in the long run. People are used to how the popup menu in Kontakt looks, anyways, I wouldn't bother



I hate to admit it, but you may be right.


----------



## P.N. (Dec 16, 2018)

Fredeke said:


> - you can't pass arguments (aka parameters) to a function
> - a function can't return a result.





Fredeke said:


> The ideal would be to create a "menu" object class, but KSP isn't object-oriented at all.



You are not limited to write in native KSP. You may use a more advanced "KSP" synthax (i'm not sure what's the official name for it - Sublime KSP?) and compile it after.
It also comes with advanced modules and features that you'd find in other high level languages.

You should definitely check it out.


----------



## EvilDragon (Dec 16, 2018)

Yes, use SublimeKSP. Function arguments and returns are just another variable. The way I usually do it is create variables that are returns and args, and encapsulate them in a macro that calls a function, which makes for a leaner compiled script compared to SublimeKSP's own callable functions with args/rets (especially with larger functions). Like so:


```
on init
    declare ui_button $Button

    family funs
        declare arg1
        declare arg2
        declare value
    end family
end on

function _DoSomething()
    funs.value := funs.arg1 * funs.arg2
end function

macro DoSomething(#arg1#, #arg2#)
    funs.arg1 := #arg1#
    funs.arg2 := #arg2#
    call _DoSomething()
end macro

{ example usecase }

on ui_control ($Button)
    DoSomething(random(1, 100), random(1, 100))
    message(funs.arg1 & " * " & funs.arg2 & " = " & funs.value)
    $Button := 0
end on
```

Might not be very convincing with a single-line example function like above, but as I said, with larger functions it pays off much more.


----------



## Fredeke (Dec 17, 2018)

P.N. said:


> You are not limited to write in native KSP. You may use a more advanced "KSP" synthax (i'm not sure what's the official name for it - Sublime KSP?) and compile it after.
> It also comes with advanced modules and features that you'd find in other high level languages.
> 
> You should definitely check it out.





EvilDragon said:


> Yes, use SublimeKSP. Function arguments and returns are just another variable. The way I usually do it is create variables that are returns and args, and encapsulate them in a macro that calls a function, which makes for a leaner compiled script compared to SublimeKSP's own callable functions with args/rets (especially with larger functions).


Waw ! Indeed I should !
I thought Sublime was just another syntax-highlighting text editor, but apparently it is much more than that. 
I'll go check it out now.


----------



## EvilDragon (Dec 17, 2018)

Sublime Text on its own IS just a text editor, but SublimeKSP is an add-on for it.

https://github.com/nojanath/SublimeKSP


----------



## Fredeke (Dec 17, 2018)

Hey I might need some help with SublimeKSP. I've installed it (hopefully properly), and my scripts get highlighted, but all "KSP: ..." entries in Sublime's Tools menu are disabled (except for "copy as BB code"). So I can't compile or anything. The keyboard shortcuts mentioned in Nils' brief documentation don't do anything either. What am I missing ?

[EDIT: maybe this question deserves a new thread. Here it is: https://vi-control.net/community/threads/77866/ ]


----------



## geronimo (Dec 17, 2018)

Are you on PC or with an Apple machine ?
With a Mac, compile function (convert) --> Command K


----------



## Fredeke (Dec 17, 2018)

On a PC. Usually that would mean it's Ctrl-K, but Nils says it's F5. Anyway, neither of these work.

Let's continue the discussion there: https://vi-control.net/community/threads/77866/


----------

