this is an update to the v1.0 drag & drop script. You can now set horizontal draggables or vertical draggables like lists (see animation below). For real use cases also see Rearrange FX Slots via Draggables
drag n drop Script v2.0:
Vertical & Horizontal Draggables
- NKI file: open script tab
- ksp script files (vanilla ksp)
- ksp functions (sublime text)
License:
MIT International License.
https://blog.yummybeats.com/license-text-mit/
You may use this script, modify it, build upon it, as you like (also commercially), as long as you keep all credits within the code visible to others. You may put them into an extra open script tab or inside an about section of your instrument. If you would like to remove the credits or publish them somewhere else, please contact us
YOU MAY NOT commercialize, share, distribute, whatsoever the included image files and other media (©2025 all rights reserved).
Related POSTs
Content
-
preliminary definitions
-
version history
-
global vars / USAGE
-
installation & setup (vanilla)
-
installation & setup (sublime)
-
docs 2.0: all changes explained premium
preliminary definitions
A few definitions in advance.
In the following there are 2 movement terms used: same and opposite direction
Terms used:
- same direction refers to all x-movements for the horizontal drag & drop and to all y-movements for vertical drag & drop.
- opposite direction refers to all y-movements for the horizontal drag & drop and to all x-movements for vertical drag & drop.
Color coding:
- The pink marker refers to any horizontal movements, the x-axis or or x-positions
- The purple marker refers to any vertical movements, the y-axis or y-positions
Version History
Vanilla KSP
v2.0 drag & drop code has been refined. Vertical and horizontal cursor movement is possible now
Note: Vanilla is not updated anymore
Sublime KSP
v2.0 drag & drop code has been refined. Vertical and horizontal cursor movement is possible now
v2.1 yb_dd_onclick function added
v2.2 all vars are persistent now. So the latest cursor positions are saved and recalled
DOCS – Global vars & usage
%dd_cursor_index
(both vanilla & sublime)
- holds all positions (key) and current cursor index (val) at the position
- each key gets updated with the new cursor index after each cursor movement on mouse release
so the array keys represent the fixed position ([0]: 1st pos, [1]: 2nd pos, and so on)
and the value is the current cursor index on that position.
Use this array to to rearrange multiple items at once like anything from FX chains to data lists or samples, you name it.
Also read rearrange FX Slots, the probably most common use case
$dd_this_cursor
(both vanilla & sublime)
holds the current selected cursor index
use this to rearrange a single item, or to get/display the current selected cursor index
Also read rearrange FX Slots, the probably most common use case
$dd_pos
(both vanilla & sublime
holds the current selected cursor’s position
use this to rearrange a single item, or to get/display the current position
Also read rearrange FX Slots, the probably most common use case
[sublime only]
function yb_dd_rearrange(index,pos,index_all)
This function is always called on every mouse release after dragging an element to a new position.
use this function to rearrange anything by simply adding your code into this function or by calling other functions within this function. Use the function’s local arguments (which are nice & short) to pass all necessary parameters:
index
equivalent to $dd_this_cursor
, is passing the current selected cursor index
pos
equivalent to $dd_pos
, is passing the current selected cursor’s position
index_all
equivalent to %dd_cursor_index
, is passing the complete array with all positions and indices
function yb_dd_onclick(index,pos,index_all)
This function is called when clicking on a cursor. You can use it for example to open a specific fx dialog.
index
is holding the current selected cursor index
pos
is holding the current position of the clicked cursor
index_all
is holding the complete array of all cursors whereas the key represents the cursor position and the value the cursor’s index currently residing on that position.
installing the script (vanilla ksp)
- copy the whole code from inside the on init into your on init. It is best to place the code somewhere below yours.
But don’t copy the “on init” “end on” again - copy the whole code from below the on init somewhere below your on init.
- Put the copyright notice in a visible location (e.g. into an extra open script tab or into an about section of your instrument).
on init {### YOUR CODE ###} {YUMMYBEAT'S KSP DRAG & DROP SCRIPT} end on {### YOUR CODE ### } {YUMMYBEAT'S KSP DRAG & DROP SCRIPT} on ui_control (?dd_area) {.....} end on
setup: defining the Drag & Drop Area
{SET DRAG & DROP AREA} declare const $DD_NUM_CURSOR := 8 {set the amount of total cursors; max = 16} declare const $DD_AREA_WIDTH := 400 {set the drop down area width} declare const $DD_AREA_HEIGHT := 148 {set the drop down area height (this should equal the cursor image height)} declare const $DD_AREA_JUSTIFY := 1 {justify the drag & drop area: 1 = center; 0 = left} declare const $DD_AREA_POS_X := 0 {left indent; set to 0 when align = center} declare const $DD_AREA_POS_Y := 100 {position the drag & drop area vertically} declare const $DD_DIRECTION := 1 {0:= horizontal; 1 = vertical} $DD_MOUSE_X := 0 {set mouse behavior X: default = 0; min = 1; max = 1000} $DD_MOUSE_Y := 0 {set mouse behavior Y: default = 0; min = 1; max = 1000}
$DD_DIRECTION
[NEW]
switch between 0 = horizontal list vs 1 = vertical list
$DD_MOUSE_X; $DD_MOUSE_Y
[NEW]
sets custom drag movement speed.
leave 0 for default / automatic setting
Max speed is 1000; Lowest speed is 1 (almost no movement)
$DD_MOUSE_X: horizontally
$DD_MOUSE_Y: vertically
Note:
- setting a custom value for both directions will create a completely free omnidirectional cursor movement while still having the sorting function feature, just try it yourself.
- If only same direction values are set, the movement speed can only be slowed down (since the default setting, is already max speed), resulting in a unidirectional movement (default behavior)
- If only opposite direction values are set, the movement speed can only be increased (since the default setting is already lowest speed), resulting in the above mentioned bidirectional cursor movements (since the same direction’s default setting is max already)
Cases:
$DD_DIRECTION = 0: $DD_MOUSE_X = same movement
$DD_DIRECTION = 0: $DD_MOUSE_Y = opposite movement speed
$DD_DIRECTION = 1: $DD_MOUSE_X = opposite movement
$DD_DIRECTION = 1: $DD_MOUSE_Y = same movement
Examples:
1. Horizontal Drag & Drop: One Direction, Cursor movement default but slowed down
$DD_DIRECTION = 0, $DD_MOUSE_X = 100
$DD_DIRECTION = 0: $DD_MOUSE_Y = 0
2.Horizontal Drag & Drop: Omnidirectional, Cursor movement max
$DD_DIRECTION = 0, $DD_MOUSE_X = 1000
$DD_DIRECTION = 0: $DD_MOUSE_Y = 1000
3. Vertical Drag & Drop: One Direction, Cursor movement default but slowed down
$DD_DIRECTION = 1: $DD_MOUSE_X = 1
$DD_DIRECTION = 1: $DD_MOUSE_Y = 100
4. Vertical Drag & Drop: Omnidirectional, same direction max <=> opposite direction slow
$DD_DIRECTION = 1: $DD_MOUSE_X = 100
$DD_DIRECTION = 1: $DD_MOUSE_Y = 0
$DD_NUM_CURSOR
defines the number of cursors (max 16)
$DD_AREA_WIDTH
sets the total width of the drag & drop area in pixels
$DD_AREA_HEIGHT
defines the total height of the drag & drop area in pixels
$DD_AREA_JUSTIFY
defines the horizontal alignment of the the whole drag & drop area within your UI.
0 = Left
1 = centered
$DD_AREA_POS_X
positions the drag&drop area accross the x-axis in pixels depending on the $DD_AREA_ALIGN settings. Negative values are allowed but only have effect at centered alignment.
If $DD_AREA_ALIGN the origin is the very left.
if $DD_AREA_ALIGN = 1 the origin is the center of your UI
$DD_AREA_POS_Y
positions the drag&drop area across the y-axis in pixels. Negative values have no effect.
installing the script (sublime text)
- put this in the top of the on init (before calling any functions):
declare !cursor_img[] := ("cursor_list_0","cursor_list_1","cursor_list_2","cursor_list_3","cursor_list_4","cursor_list_5","cursor_list_6","cursor_list_7") declare const DD_CURSOR_COUNT := cursor_img.SIZE
- in the KSP folder open “ksp_draggables_v2-1_xy (sublime).ksp” and copy all the required functions somewhere into your script. Preferably under the “on init”:
REQUIRED FUNCTIONS: yb_init_ddarea, yb_dragndrop_colision, yb_justify_content, yb_dd_rearrange,yb_dd_onclick
OPTIONAL FUNCTIONS: yb_set_ui - Call the
yb_init_ddarea
function without the “call” expression anywhere inside the on init and pass all arguments. Read the little SETUP box below - Add an on ui_control for ?dd_area and call the yb_dd_oncontrol like so:
on ui_control (?dd_area) yb_dd_oncontrol end on
- please copy the credits & copyright notice (from inside the script) somewhere clearly visible e.g. into another open script tab or into an about section of your instrument.
If you would like to completely remove the copyright notice, shorten it or place it somewhere else, please get in touch @ https://yummybeats.com/contact
SETUP: defining the Drag & Drop Area
declare !cursor_img[] := ("cursor_list_0","cursor_list_1","cursor_list_2",...) //
- add custom cursor images. Simply replace all values with your filenames without file extension (.png)
- The images should be formatted like a button with 6 states, learn more (don’t forget to add the txt file)
- To use more than 8 cursors simply extend the array. Up to 16 cursors allowed. A max cursor count would looks like this:
declare !cursor_img[] := (“cursor_0”, “cursor_1”, “cursor_2”, “cursor_3”, “cursor_4”, “cursor_5”, “cursor_6”, “cursor_7”, “cursor_8”, “cursor_9”, “cursor_10”, “cursor_11”, “cursor_12”, “cursor_13”, “cursor_14”, “cursor_15”)
Passing the Arguments & defining the DD area
yb_init_ddarea(ui_width,ui_height,dd_width,dd_height,dd_justify,dd_posx,dd_posy,dd_direction,dd_mouse_x,dd_mouse_y,dd_array_cursorimg) //
ui_width
pass the total width of your UI in pixels e.g. 800ui_height
pass the height of your UI in pixels e.g. 400dd_width
pass the width of the drag n drop areadd_height
pass the height of the drag n drop areadd_justify
justify the dd_area along the x-axis … 0=left/start, 1=center, 2= right/enddd_align
align the dd_area along the y-axis … 0=top; 1=center; 2=bottomdd_posx
move the dd_area across the x-axis depending on the justification (negatives values = left; positive values = right)dd_posy
move the dd_area across the y-axis depending on the alignment (negatives values = up; positive values = down)dd_direction
0=horizontal cursor movement; 1=vertical cursor movementdd_mouse_x
drag speed across the x-axis 0=default; 1000=max (note: both values above 0 means free cursor movement in 2D space) (read vanilla for detailed explanation)dd_mouse_y
drag speed across the y-axis 0=default; 1000=max (note: both values above 0 means free cursor movement in 2D space) (read vanilla for detailed explanation)dd_array_cursorimg
used to pass the cursor image array, so always keep it set to “cursor_img” unless you are using a custom array for the images
example
on init //declare const $UI_WIDTH := 800 //NOT REQUIRED BUT RECOMMENDED TO SIMPLIFY REPEATING UI SETTINGS //declare const $UI_HEIGHT := 400 //NOT REQUIRED BUT RECOMMENDED TO SIMPLIFY REPEATING UI SETTINGS // PUT THIS BEFORE CALLING yb_init_ddarea declare !cursor_img[] := ("cursor_list_0","cursor_list_1","cursor_list_2","cursor_list_3","cursor_list_4","cursor_list_5","cursor_list_6","cursor_list_7") declare const DD_CURSOR_COUNT := cursor_img.SIZE // CALL THE FUNCTION(S) yb_init_ddarea(800,400,228,224,1,0,100,1,0,0,cursor_img) yb_set_ui (800,400,"wp2","yb_ico") yb_decalre_display(800,400,160,28,-6,"",1,2) message("") end on on ui_control (?dd_area) yb_dd_oncontrol end on function yb_init_ddarea(ui_width,ui_height,dd_width,dd_height,dd_justify,dd_posx,dd_posy,dd_direction,dd_mouse_x,dd_mouse_y,dd_array_cursorimg) end function function yb_dd_oncontrol end function function yb_dd_rearrange(index,pos,index_all) end function function yb_justify_content(id,ui_width,type,width,pos) end function function yb_align_item(id,ui_height,type,height,pos) end function function yb_set_ui(width,height,wallpaper,icon) end function function yb_decalre_display(ui_width,ui_height,width,height,pos,picture,justify,align) end function
DOCS v2.0: All changes explained (vanilla ksp)
The following explains all new features that have been added to v1.0
To delve deeper for a better understanding please also read the main v1.0 docs
premium content
unlock the full article
including all downloads!
unlock premium content
HarryG
Hi again, I want to show a panel containing sliders related on the selected fx, when the user clicks on one of the cursor. I declared an Array containing all my panels, and then put this line of code in the yb_dd_onclick function : set_control_par(%fxPanel_uID[index], $CONTROL_PAR_HIDE, $HIDE_PART_NOTHING). I can't make it work, how am I supposed to do in order to show the panel related to the cursor when the user clicks on it ? ThanksYummyBeats
Hey, are your FX static or can the user swap the fx? Because the latter is unfortunately way too complex for the comments
But if your FX are always linked to a specific cursor, make sure that your %fxPanel_uID array keys represent the cursor indices (not the cursor positions). So let's assume that the compressor fx is always linked to cursor index 3, %fxPanel_uID[3] would always be your compressor panel.
Then first store the compressor panel ui_id to key 3 like so:
%fxPanel_uID[3] := get_ui_id($panel_comp)
Now just show the panel like you did. Within onclick or the rearrange function
set_control_par(%fxPanel_uID[index]
should already work. Otherwise useset_control_par(%fxPanel_uID[$dd_cursor_idx], $CONTROL_PAR_HIDE, $HIDE_PART_NOTHING)
If it is not working you may have other issues e.g. not set the z_layers correctly so that the panel is covered by another panel?!
HarryG
Thanks everything works, now I'm trying to make a "radio button" function that hides every panels except the one of the cursor that is selected. Because now, let's say I click on cursor 2, the cursor2panel shows up, but if I click on cursor 3, the cursor3panel shows up too but the cursor 2 panel is still visible, so they are overriding. I only want a single panel to be shown at a time. I thought of a flag function with 8 cases for every selected cursor but is there a more efficient way to achieve that ? Thank youYummyBeats
Great!
I see, the best way to achieve this would be to add a function which hides all panels first, then just show the one panel of the related cursor with another function.
To hide all panels first just iterate through the whole %fxPanel_uID like so:
Then you can call the following function and pass the index of the panel you want to show again.
E.g. in a button's
on ui_control
callback or inside the onclick function or anywhere you wantHarryG
Works perfectly thank you ! I just had to delete the (idx) of the openPanel function and replace it with "$dd_this_cursor" for it to work with the onclick function, otherwise I would conflicts. Now, i'm trying to add a Bypass button for each cursor that would be on the cursor's image, and would follow the cursor when I drag it to another position. I assume i would have to incorporate a switch array into the yb_init_ddarea right ?YummyBeats
Hmm, actually it should also work without conflicts if you pass index within the onclick function like so:But yeah,
openPanel($dd_this_cursor)
is also perfectly fine. If it works it works :)Regarding the moving bypass button, well to be honest I don't think this is possible. At least it sounds very complicated since it requires cursor movement tracking etc. I can't help you on this one, sorry. I would drop this idea anyway and just add the bypass button to the fx panel. And then swap the cursor's pictures to indicate a bypassed status. It just sounds far too time-consuming for the small added value you get with this concept, if it works at all (you know 2 separate movements not really synced to each other..very sketchy).
HarryG
Yes it works ! ThanksYummyBeats
That's greatHarryG
Hi, I'm having a hard time installing the script with sublime. When I copy the "declare !cursor_img" and the "declare const DD_CURSOR_COUNT" at the very top of the on init, and compile the code, sublime tells me this : Syntax error (line 8) declare !cursor_img[] := ("cursor_list_0","cursor_list_1","cursor_list_2","cursor_list_3","cursor_list_4","cursor_list_5","cursor_list_6","cursor_list_7"). What am I doing wrong ? I've completed the installation process for sublime and the sublime error remains. Sublime is fully updated. ThanksYummyBeats
Hi,That's weird. Have you tried to compile the included ksp script as is (just for testing if it works). Because I can confirm that this file works without any issues on my side.
If it doesn't work on your side you probably still need to update your ksp plugin. Some older plugin versions may not be able to handle the "one-line-array" syntax
If it does work on your side you probably really have some syntax issues somewhere in your code, so double check every line. Or you didn't add all the dependent functions, maybe?!
If this all doesn't help try to use vanilla KSP for declaring the !array and use the $ with the constant.
HarryG
Hi again, I made it work ! Thank you, now I have a problem making the cursors persistent when I reload kontakt... In the rearrange fx dlc you make persistent (?last_cursor_val), (%cursor_index) and (?cursor_val). I tried that but it doesn't work, maybe it has changed with the V2 DD ? But how to make the new dd cursors persistent ? Thank you.YummyBeats
Hey, that's great to hear!
make_persistent only works when saving your whole nki patch or when saving/loading a snapshot. Since your users most likely won't overwrite the nki you should encourage them to use snapshots.
That being said in the yb_init_ddarea function simply add pers to all variable declarations including the dd_area. I will also update the script
Like so:
HarryG
I wanted the curors to recall the way they were left by the user after closing and reopening a project in a daw. The nki or snapshot isn't saved by the user but the project where kontakt is opened in would ! In this case the make persistent would work right ?YummyBeats
Yes true this case also should work with persistent vars. I have just updated the script can you try version 2.2?I have not tested it in a DAW though but it should work.