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)
DLC: reorder fx
(additional CONTENT)
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
v2.21 bug fixes
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_ddareafunction 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_widthpass the total width of your UI in pixels e.g. 800ui_heightpass the height of your UI in pixels e.g. 400dd_widthpass the width of the drag n drop areadd_heightpass the height of the drag n drop areadd_justifyjustify the dd_area along the x-axis … 0=left/start, 1=center, 2= right/enddd_alignalign the dd_area along the y-axis … 0=top; 1=center; 2=bottomdd_posxmove the dd_area across the x-axis depending on the justification (negatives values = left; positive values = right)dd_posymove the dd_area across the y-axis depending on the alignment (negatives values = up; positive values = down)dd_direction0=horizontal cursor movement; 1=vertical cursor movementdd_mouse_xdrag 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_ydrag 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_cursorimgused 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'm running across more problems here. I'm trying to have a functionnal bypass switch for each cursors /FXs. It's easy to set up but with the rearrange function, it just messes all things up. I can't find a logic in the problem, sometimes it'll doesn't recall the bypass value, sometimes it'll make another cursor bypassed....I tried adding another wait() in between the reapplybypass and the cursors reapply functions but it doesn't help...I tried to make a wait() in between each cursor reapply functions but it still messes things up (makes the bypass switch flash between on and off). The rearrange fx is also unstable, it can crash my kontakt, maybe i should increase the wait time, but it seems so much smoother on Melted Vibes. HarryYummyBeats
Hey,
I've just updated the code I've sent you via DM and declared a simple bypass button. I've then added a standard on ui_control calling the reapplypreamp function and also called it inside
yb_dd_rearrangebefore reapplying the knob's value. Like so:on init declare ui_button $bypass end on on ui_control($bypass) reapplypreamp($ENGINE_PAR_EFFECT_BYPASS,$bypass,$dd_cursor_pos,$NI_INSERT_BUS) end on function yb_dd_rearrange(index,pos,index_all) reorder_fx_slots($EFFECT_TYPE_EP_PREAMPS,$NI_INSERT_BUS) wait(100*1000) reapplypreamp($ENGINE_PAR_EFFECT_BYPASS,$bypass,$dd_cursor_pos,$NI_INSERT_BUS) reapplypreamp($ENGINE_PAR_EPP_DRIVE,$knobdrive,pos,$NI_INSERT_BUS) end functionEverything works without problems here. Can you give it a try and first only update the code I've sent you. Because maybe this time it is rather a performance issue?!
HarryG
Your code works, but it's only for one Fx, when I add all the other FXs, it messes up (i have a screen recording of everything bugging). I have a good pc so if there is a performance issue it's coming from Kontakt or my daw i think. If it's not stable enough, arrays could be a better solution don't you think ? + I could import FXs presets. The reoder fx slots function In the Draggables DLC is different from the code you've sent me, any particular reason ? Is it a better code ? Thanks ,HarryYummyBeats
Yes, actually I was referring to the Kontakt performance not your system's performance. Especially the use of many effects or voices can cause performance issues while your real CPU is running at 3% still. Doesn't necessarily mean that this will destroy your GUI functionality or affect your engine communication, but can cause audio glitches or lags with the GUI.
So when facing performance issues my method is to start low (no samples, little fx, not many voices but just simple code) and slowly build up until Kontakt reaches its limit. This way I hopefully can localize the issue. If everything works I then use an older machine with a slow cpu to make sure it is really not CPU related. Also the "Monitor -> Engine" tab can be helpful sometimes.
Anyway, I've now added the full 8 FX with multiple bypass buttons and went to 500 to 600ms which seems to work in my case.
I've also noticed if the drag&drop distance gets larger the more delay time you will need. For example moving a cursor from 0 to 7 and vise versa requires the largest delay time. But 600ms is ok overall and still pretty smooth, don't you think? You could tinker around and add some smaller waiting times within the reorder function's loops while moving the reapply functions into the reorder function's while loop as well. With some adjustments of course. Hope you know what I mean. I don't know if there's also a possibility to build a watchdog. That would be most reliable but unfortunately I've currently no idea how we could approach this.
Yes, for large amount of ui_controls and fx it might be better to use some cache arrays, since you probably already are using arrays for the control's ui_ids?! I'm not sure if this will solve the performance issue though but it's worth a try with a simple setup first.
Don't mind the different reorder function I was just building it quickly form scratch for one EFFECT_TYPE. The DLC function is using the index_all array which is needed for reordering multiple FX. You could add the
$EFFECT_TYPE_NONEloop though. Maybe this is smoothing out the performance a little bit?!HarryG
I've seen on a forum that the command wait_async() is very helpful for kontakt's performance, i'll look into that. I still can't manage to make the bypass switch work correctly...With one bypass switch, it works fine, but with two or more bypass switch, it doesn't work (it messes things up when two bypassed fx cross each other when rearranging them). I'm not using arrays for the switch ui IDs (I'm using a macro to declare them, and another macro to attach them to an engine par). I'm not familiar with arrays and how i would use them to create that cache system, but I think i'll try that because the reapply functions seems pretty unstable in my script. + i'm interested in letting the user save and load its FXs chain (if that's not too complicated)YummyBeats
Great you pointed that out. Thx for that!
wait_async() seems ideal for that purpose and exactly what you are looking for. I've never took a closer look on wait_async because I thought it only waits for async operations like loading external arrays .. well you never stop learning :)
I've just wrapped it around the set_engine_par like so
wait_async(set_engine_par($ENGINE_PAR_EFFECT_TYPE, fx_array[idx_array[$i]], -1, $i, generic))and removed ALL wait() commands. It works great but it seems a little slower than a 600ms delay with the larger drag distances but on the other hand quicker on shorter drag distances. But most important - it is way more reliable! Actually it is the same behavior as with melted vibes so I assume they are using wait_async() as well.If things are still getting messed up with your code I think something else must be wrong?! I'll send you a DM with my code example. Let me know how that goes.
Arrays - especially arrays which are holding the ui_ids - are still useful. Since you are already working with macros, it is just a few more lines of code.
Simply update your macros like this:
HarryG
I've read that having the wait_async() commands in an array makes kontakt process them in parallel resulting in a even better performance. The bypasses are working ! The bypass are position related though, like you bypass position 3 so any fx in position 3 would be bypassed. Is there a way to make each bypass tied to a particular fx ? Like a preamp bypass switch that will make the fx bypassed wherever the user rearrange the preamp fx to ? I think Melted Vibes work like that (+ their bypass button are on the cursor, i wonder how they've done that). Anyway now I'm going to implement the reapplyFX to each knob to see how kontakt handles it.YummyBeats
Great that it's working now. Assigning each bypass to a certain FX doesn't make any difference in performance I was just too lazy to do the whole thing :)
There are many ways to achieve that. But the first question is what you wanna use as reference. You could either use the cursor indices or the cursor positions whereas working with the cursor positions should be easier because they represent the slots at the same time whereas the the indices can be linked to a certain EFFECT_TYPE (never tried that, though, so don't count on it working). Either way I think you need to work with arrays and search() to cache and fetch positions/slots.
From then on everything is up to you. I prefer storing the FX types directly to a cache array to be able to directly fetch the position related $EFFECT_TYPE when needed. It's too complicated to explain in detail here, I will send you a DM with the updated code again. Let me know if you made any progress.
HarryG
Hi ! I've set my draggables and everything that makes the cursor rearrange the FX and it works great but I have a problem. I have a bunch of knobs that controls the FXs parameters but everytime I drag the FX to a new position, it resets all the FXs controls (including the type (like vintage, modern etc) and all its controls values. How do I prevent the fx from resetting itself to its init state ? I want the fx to keep its type and all its values from the knobs. I'm sure it has to do with persistence etc but i can't make it work. FYI, I attached the knobs to the FX controls with this command : set_engine_par($ENGINE_PAR_#enginepar#,$knob#name#, -1, $dd_cursor_pos,$NI_INSERT_BUS) (it's part of a macro). Maybe i've done something wrong with the set engine par command, or maybe it's just a persistence i need to include somewhere anyway how do i fix this ? Many thanks ! HarryYummyBeats
Hey,
each time you reposition the fx (changing slots), the whole fx gets initiated again which means it is set to its default values again as if you load a fresh FX to a slot. Your ui_control's values or settings should not change though, unless you are updating them from the fx settings via
get_engine_par.Anyway so if you are using individual ui controls for each FX setting (engine) you should be able to recall the last fx settings via
set_engine_pareg. from your knob positions or current menu selection etc.Additionally you should make each ui_control persistent. I'd recommend this solution if your code is not too bloated already (because there is - or maybe was - a lines of code limit for the on init. Learn more
If you are only using one set of ui_controls for multiple FX controls (engine) you could create a database via arrays and cache each individual FX setting (engine parameters) whenever you reposition your fx. Use these arrays again to update all your ui controls once a fx has been dragged to a new position (yb_dd_rearrange function) or each time when you select a another cursor (yb_dd_onclick function). With this solution it's only necessary to make the cache array(s) persistent and use it to recall all ui_control settings within your on init
There may be more elegant solutions, but this is what comes to my mind right now.
HarryG
Hi thanks! I'm using a macro for creating knobs and they are all persistent. Then, i have a macro for attaching them to an engine par : So each knob is controlling only one engine par at a time. Each time I drag a FX cursor to a new position the knobs are left at the same position they were left. How do i recall the FX's menu/knobs position with set_engine_par ? I could fix it with arrays as you mentionned but won't it be overkill and too complicated ? Thanks, harryYummyBeats
Well, I always keep saying if it works then it works. But apart from that, if you already went with the array solution, I would stick with it, as it opens up a number of other possibilities, such as saving all FX settings in an external array and reimporting them in later sessions – aka user presets.
If you still want to go with the set_engine_par solution, just create a function or macro (for each fx or ui_control type) and as usual use the ui_control's value for the set_engine_par value and call the whole function / macro inside the yb_dd_onclick function like so:
example - for the instrument buses
on init declare ui_knob $knob_delay_time (0, 1000000, 1) end on function yb_dd_onclick(index,pos,index_all) reapply($ENGINE_PAR_DL_TIME,$knob_delay_time,0) end function function reapply(par,val,bus) set_engine_par(par, val, -1, $dd_cursor_pos, $NI_BUS_OFFSET+bus) end functionHarryG
Hi again I tried the set engine par solution but i can't make it work. The function works great but i need to click on the cursor again after sliding it to a new position in order to recall the correct values. How could i change the code in order to make it recall the correct values automatically right after the user rearrange a cursor to a new position ? I tried calling the set engine par function into the yb_dd_rearrange but it does the same thing as yb_bb_onclick (i need to click on the cursor again in order to recall the right values). I did not tried the Array solution since I'm not familiar with arrays but i could give it a try. Do you have an idea how i could fix the problem ? Btw, I know the Kontakt Play Series "Melted Vibes" has a perfect drag and drop fx section that i would like to copy, but i think I'm not ready to code like NI's developpers haha Thanks, HarryYummyBeats
That's weird I tried with Kontakt 8 and it worked as soon as the cursor was dragged to the new position. I even didn't have to release the mouse. Older Kontakt versions don't visually update whats going on with the FX slots inside the edit window but engine wise its definitely working. So if you are on an older version either hit the panic button (!) after dragging & reapplying any fx setting to visualize if the fx settings have been updated or try a very remarkable fx setting like delay feedback and use extreme settings (0 and max) to see - I mean to hear - if it's working.
Putting the reapply function into
yb_dd_rearrangeshould definitely work though, since this function is called on every mouse release event. You could add a message with an increasing counter after calling the reapply function to see ifyb_dd_rearrangeis really fired each time. Let me know if notOne further vague guess - if nothing helps: maybe there are too many set_engine_par calls going on at the same time?! In this case try to add some wait commands in between some set_engine_par calls - only a few micro seconds.
But yeah KSP can be tricky & frustrating. First it seems to work then it doesn't anymore or suddenly Kontakt throws errors out of nowhere.
HarryG
Hi again, I tried both kontakt 7 and 8 and i can't make it work...I think i did something wrong but i can't find why. I added a message inside the yb_dd_rearrange and it shows the message everytime i rearrange the FX so no problem here. I only tried with one control for now (the Preamp Drive) so it's light and easy to hear. Here's what i'm working with : function yb_dd_rearrange(index,pos,index_all) reorder_fx_slots reapplypreamp($ENGINE_PAR_EPP_DRIVE,$knobdrive,$NI_INSERT_BUS) message("it works") wait($UIWaitTime) message("") end function function reapplypreamp(par,val,insertbus) set_engine_par(par, val, -1, $dd_cursor_pos, insertbus) end function If you have an Idea what I did wrong here. I tried inside the onclick function too without success.YummyBeats
I've now tried your code and got it to work. Just leave both functions in yb_dd_rearrange and add a pretty long wait(), between reorder_fx_slots() and reapplypreamp(). Maybe 100ms to 1s long .. just play around and test with slower systems.
I've also sent you a DM with the full code for testing.
HarryG
Hi again ! I'm looking for a way to make the draggables look like a serie 500 rack, with each little 500 effect a rearrangable fx. In order to do that, I want each cursor to be its own little rack fx. Is it doable ? With your script I'm able to have cursors that displays panels when the user clicks on it, but with my idea, the cursors would actually need to contain their own panels with the rack ui and knobs etc...I'm trying to do something like T-Racks Mixbox. Thanks !YummyBeats
Hey,unfortunately that is not possible with KSP because we can't add any controls to the cursor. Basically we can only customize it with a custom picture.
That being said, it may probably work with a sketchy workaround. Like you could use a placeholder image while dragging. And when dropping the cursor or releasing the mouse you could overlay the cursor with the full rack panel at the exact position where the cursor was dropped (additionally you can also swap the cursor placeholder with a transparent image). However this is not as easy as it sounds because the cursor values are not given in pixel positions but in percentages of the total width & height of the drag and drop area. Well there is a chance that it works precisely without any displacements because the percentage position is at least a floating number but I think it rather gets messed up and there will be no chance to get it accurate, but maybe accurately enough for the eyes though?!
Unfortunately this method is also not covered here but if you like the trial & error approach, you could tinker around with some simple images like simple rectangles first.
HarryG
Thank you very much, I don't think I'm ready to try this out yet though haha ! I'll stick to the common version of this. I would love as a next tutorial, to see how to let the user save and load their custom FX chains presets ! I know it's possible as I've seen many librairies with that feature, but i've always wondered how to achieve that ! Thank you for answering quickly ! HarryDaniel Lautersztain
Can you confirm what compile settings you're using for Sublime for this? I'm using the settings recommended in your Sublime article but no matter what I do, I get very unusually behavior with cursors (swapping places and shifting up and down erratically) when I use the Sublime v2 version. I'm copying your code exactly, not making any changes, and I don't think I'm doing anything else in my script that would be interfering. Just to test, I put the vanilla version into my script and it works perfectly, no issues whatsoever. I'm not sure if it's a compiler error or what. But just curious what you're settings for SublimeKSP are.YummyBeats
Actually just the default settings: Extra Syntax Checks, Add Compilation Date & Sanitize Behavior... I doubt this is causing the issue?!
I have not been able to find any bugs so far, in fact all clicks next to the cursors should be completely ignored. Did you test this v2 vanilla version? Because if so it's even more confusing because all the logics between vanilla & sublime should be exactly the same just packed into a function. The only changes that have been made since version 2.00 are to make all variables persistent and to add the onclick function without executing any code in it. I also doubt that these changes can cause this. If so I really don't know why. But as said I was also able to reproduces this behavior but only with a blank instrument. When adding custom cursor images I wasn't able to reproduce it so far. So I still believe that this is some kind of a "Lag-Induced Glitch"?!
But I could be wrong of course. If you find something let me know.
Daniel Lautersztain
Gotcha ya I'm not sure either. When I use the vanilla version though it works perfectly so I may just stick with that. There must be some issue when doing it with functions (though I have dozens of other functions that seem to be okay). But vanilla works fine so i'll stick with it, I'm not really missing any functionality by using (I can make the variables persistent). Though the Sublime version is definitely easier to read haha.Daniel Lautersztain
How are you able to use $NI_MOUSE_EVENT_TYPE in a function? I'm getting a compiler error that "$NI_MOUSE_EVENT_TYPE can only be used in ui callbacks" even though i'm copying everything directly from the Sublime 2.2 script (i'm also running Sublime KSP). Oddly enough if I open your KSP script for sublime 2.2 version and compile, I get no errors.YummyBeats
There is actually no restriction, just use it as you would do outside a function. However, you may only call the function inside the on ui_control of the dd_area then.Also, do not use the "call" expression when you call the function (learn more). It is best not to use "call" at all simply to keep a clear code structure e.g. in case a function should be extended later which would then no longer work
Daniel Lautersztain
I had no idea! Time to refresh the Sublime KSP wiki hehe thanks! Also your Sublime article is soooo helpful! Another little quirk I'm running into is that when I adjust dd_posx or dd_posy, my dd_area isn't moving. I've tried when using different justify/align values. I think if I set align to 0 and justify to 0, can get dd_posx to move along the x axis, but the y values won't change at all. Are you able to move the dd_area using these values? Not sure if I'm missing something.YummyBeats
Yeah the wiki is pretty insightful :)
Thx for pointing that out I think these were some debugging leftovers where I used fixed positions. Can you try the updated version 2.21?
If you don't want to replace the whole function just replace these lines
With these lines:
Daniel Lautersztain
This worked perfectly! I actually saw that 0 and was curious why it was hard coded hah, thanks! Okay last question I swear. I'm using this v2 version for rearranging fx slots and I've added code to show corresponding controls for each fx depending on $dd_this_cursor. My issue is I need to set the position for the controls and I'm using 2 areas in my instrument to show controls instead of just 1 set. So that means I can't use $dd_cursor_pos to set the position of the control when doing set_engine_par. That works when you need to control one FX at a time. So if I have a compressor and do "set_engine_par($ENGINE_PAR_FCOMP_RATIO, $my_slider, -1, ***current position***, $NI_BUS_OFFSET) the current position needs to update if I drag the compressor to position 4 instead of position 0. I already have an %FX[$DD_CURSOR_COUNT] array that stores all the constants for the FX types. I guess what I need is a way to check which position each FX is in at any given time so that in the UICB I can make sure the position value matches where it gets moved to. Normally $dd_cursor_pos works fine for this if you only need to see/control one FX module at a time but in my instrument you can control 2 modules at a time so I need the position value to be a bit more dynamic.Daniel Lautersztain
Actually disregard my last question, I fixed it. Turns out I had removed persistence on $dd_this_cursor and $dd_cursor_pos and that's why my values were inconsistent!Daniel Lautersztain
So awesome to see this update! A bunch of extra functionality too, I love the mouse time function. I'm noticing some weird behavior though, in the 2.2 sublime version (havent tested the others) if you click on an area just to the right of the image box, it will shift one of the other buttons to the right. Clicking on the shifted box will reset it. I tried narrowing the dd_width to like 20 pixels (basically the size of the box) but it will still happen on occasion. I suspect clicking off the image but still in the dd_area will force a change the in the x value position. Is there any way to prevent *any* x position value, in the case of using a vertical draggable. Basically to prevent any of the cursor images from being able to move at all on the x axis and only on the y, no matter where in the dd_area you click.YummyBeats
That's good to hear, also thx again for initiating this.
That's weird actually all clicks other than on the cursor itself should be ignored already, since MOUSE_BEHAVIOR is set to 0. I also couldn't reproduce this behavior with the vertical drag & drop nki from the supplied file. I just clicked along outside the cursors / list items but everything works as it should. I've tested it with Kontakt 6 and Kontakt 7. Can you verify if the supplied "ksp_draggables_v2-2_xy (compiled).nki" has that strange behavior on your system as well?
Daniel Lautersztain
Interesting, in the compiled .nki I don't experience it but if I take the ksp script version 2.2 and open it in Sublime, compile it then add to it a fresh instrument that's where it happens. I also bring it up because in my own instrument I'm working on where I implemented this in, the same thing happens there. Here's an image upload to show what's happening. I wonder, if you take the ksp_draggables_v2-2_xy (sublime).ksp and add it to sublime, compile, then just add it to a blank instrument, do you notice the same thing (sometimes you have to click around for a minute before it happens) https://ibb.co/whL6cp5RYummyBeats
Well that sounds maximum confusing now. Because yes, I did the exact same thing. I just compiled the "ksp_draggables_v2-2_xy (sublime).ksp" as is to create the ksp_draggables_v2-2_xy (compiled).nki.I even just copied the compiled code to a blank new instrument and even with 228px width and the small blank cursors (like in your screenshot) I didn't get that behavior.
Did you activate anything with the ksp plugin like compact variables or optimize compiled code? Or did you accidentally set $DD_MOUSE_X to > 0?
YummyBeats
Hey, I just did another testing. This time I was very persistent and able to reproduce it. According to my observation it happens if you drag an item and quickly click on another item or anywhere around, during the release event so to say. I'm not sure if it's an issue with the code and if so I really don't know which part.I currently rather believe it's some engine latency issues?! So my assumption right now is that on release it does track all coordinates maybe due to latency or a too long release phase. So that the engine still believes the cursor is clicked/active after release. But that's just speculation. I need to investigate this further.
On the other hand it never happened to me with real world scenarios so far (when using normal sized items with custom images etc and not clicking around like crazy).
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:
function hideAll declare i for i := 0 to num_elements(%fxPanel_uID)-1 %fxPanel_uID[i] -> hide := $HIDE_WHOLE_CONTROL end for end functionThen 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_controlcallback or inside the onclick function or anywhere you wantfunction openPanel(idx) hideAll %fxPanel_uID[idx] -> hide := $HIDE_PART_NOTHING end functionHarryG
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:function yb_dd_onclick(index,pos,index_all) openPanel(index) end functionBut 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.