|
|
|
03-06-2021, 08:02 AM
|
#1
|
Human being with feelings
Join Date: May 2015
Location: Québec, Canada
Posts: 4,937
|
ReaImGui: ReaScript binding for Dear ImGui
REAPER Immediate-Mode Graphical User Interface
ReaImGui is a ReaScript binding and REAPER backend for the Dear ImGui toolkit. It adds over 380 API functions (more than 800 including constants!) for creating GPU-rendered GUI interfaces.
This REAPER extension plugin can be installed using ReaPack (through the default ReaTeam Extensions repository).
About Dear ImGui
Dear ImGui is an implementation of the immediate-mode GUI paradigm. Applications using this paradigm create their GUI on the fly without retaining and managing the UI toolkit's state themselves.
This is particularly well suited to ReaScripts by making use of the global 33Hz timer to describe each UI frames.
See Dear ImGui's FAQ.
Example code #1
This example shows the bare-minimum code needed to display a window using ReaImGui.
Code:
local ctx = reaper.ImGui_CreateContext('My script')
local function loop()
local visible, open = reaper.ImGui_Begin(ctx, 'My window', true)
if visible then
reaper.ImGui_Text(ctx, 'Hello World!')
reaper.ImGui_End(ctx)
end
if open then
reaper.defer(loop)
end
end
reaper.defer(loop)
Example code #2
This example loads a font and receives user input.
Code:
dofile(reaper.GetResourcePath() ..
'/Scripts/ReaTeam Extensions/API/imgui.lua')('0.8')
local ctx = reaper.ImGui_CreateContext('My script')
local sans_serif = reaper.ImGui_CreateFont('sans-serif', 13)
reaper.ImGui_Attach(ctx, sans_serif)
click_count, text = 0, 'The quick brown fox jumps over the lazy dog'
local function myWindow()
local rv
if reaper.ImGui_Button(ctx, 'Click me!') then
click_count = click_count + 1
end
if click_count % 2 == 1 then
reaper.ImGui_SameLine(ctx)
reaper.ImGui_Text(ctx, [[hello dear imgui! \o/]])
end
rv, text = reaper.ImGui_InputText(ctx, 'text field', text)
end
local function loop()
reaper.ImGui_PushFont(ctx, sans_serif)
reaper.ImGui_SetNextWindowSize(ctx, 400, 80, reaper.ImGui_Cond_FirstUseEver())
local visible, open = reaper.ImGui_Begin(ctx, 'My window', true)
if visible then
myWindow()
reaper.ImGui_End(ctx)
end
reaper.ImGui_PopFont(ctx)
if open then
reaper.defer(loop)
end
end
reaper.defer(loop)
An EEL2 example is provided as ReaImGui_Hello World.eel along with the extension. Python and C++ examples are available on GitHub.
Example code #3
Dear ImGui comes with a comprehensive demo application showcasing most features. A partial ReaScript port of it is provided along with the extension as ReaImGui_Demo.lua.
Documentation
A custom HTML documentation is accessible via the Documentation button in the demo script (or by opening <resource path>/Data/reaper_imgui_doc.html).
It is also available online: reaper_imgui_doc.html.
Additional tools for Lua scripts
Backward-compatibility shims
Lua scripts may request a specific version of ReaImGui's API:
Code:
dofile(reaper.GetResourcePath() ..
'/Scripts/ReaTeam Extensions/API/imgui.lua')
('X.Y.Z') -- current version at the time of writing the script
gfx to ReaImGui translation
Lua scripts can use a translation layer to re-implement most gfx functions using ReaImGui ( discussion thread):
Code:
gfx = dofile(reaper.GetResourcePath() ..
'/Scripts/ReaTeam Extensions/API/gfx2imgui.lua')
Minimum system requirements
REAPER v5.979 (v6.58 or newer recommended)
Linux, macOS 10.9 or Windows Vista
Required system libraries on Linux: GDK3 3.22, freetype, libepoxy, libpng, libstdc++ for GCC 5.1
Workarounds for REAPER API limitations
- Writable arguments are listed before optional arguments in order to be returned first. Example: ImGui_GetMouseDragDelta [t=266396]
- Extensions may only register functions, so constant values and flags are exposed as functions
- Extension functions cannot have callback parameters. ReaImGui provides a way to create EEL function objects to work around this.
Contributing
The source code is available under LGPLv3 on GitHub. Patches (including documentation edits) can be submitted as pull requests. Send bug reports on the issue tracker.
Last edited by cfillion; 01-20-2024 at 07:56 PM.
Reason: ReaImGui != RealmGui
|
|
|
03-06-2021, 08:24 AM
|
#2
|
Human being with feelings
Join Date: Dec 2020
Location: Miami, FL USA
Posts: 396
|
HUGE MOMENT
__________________
Seasoned codemonkey
Dunno a thing about making music (here to learn!)
|
|
|
03-06-2021, 09:07 AM
|
#3
|
Human being with feelings
Join Date: Oct 2017
Location: Larisa, Greece
Posts: 3,799
|
Awesome! I just wish to see in future scripts a universal size of the GUI for the docked scripts. This would be very useful and way more clean to work with.
An example is Ableton or Bitwig devices, where they have the same height in the docker and you can navigate and choose easier the parameters.
|
|
|
03-06-2021, 10:07 AM
|
#4
|
Human being with feelings
Join Date: Oct 2017
Location: Black Forest
Posts: 5,054
|
Quote:
Originally Posted by gxray
HUGE MOMENT
|
YES, this is HUGE. Thanks cfillion, you rock!
|
|
|
03-06-2021, 12:22 PM
|
#5
|
Human being with feelings
Join Date: Jan 2007
Location: mcr:uk
Posts: 3,889
|
Awww man, not another thing to look into! LOL!
|
|
|
03-06-2021, 12:55 PM
|
#6
|
Human being with feelings
Join Date: Dec 2020
Location: Miami, FL USA
Posts: 396
|
For those who might not be familiar, brief examples of the kinds of UI's which have been built using ImGUI:
__________________
Seasoned codemonkey
Dunno a thing about making music (here to learn!)
|
|
|
03-06-2021, 01:15 PM
|
#7
|
Human being with feelings
Join Date: Dec 2017
Location: Brazil
Posts: 1,992
|
woooooow this exemples are neat!
Thanks a lot for bringing this to reaper !
:O
Can't wait to see more GUI Exemples using this, will try probably this week to do one!
|
|
|
03-06-2021, 02:17 PM
|
#8
|
Human being with feelings
Join Date: Apr 2014
Posts: 398
|
If I understand well, this is really, REALLY cool!
Your contributions to the community are so impactful!
THANK YOU!
|
|
|
03-06-2021, 07:26 PM
|
#9
|
Human being with feelings
Join Date: Dec 2017
Location: Brazil
Posts: 1,992
|
cfillion do you know if there is a place I can look/search the functions/methods?
I am looking at their git but a little confused as the info is sparsed in pages, wondering if there is a list that I just didn't found.
Also I can import images with your version?
Looking at the code in the big example nice work!
Thanks a lot again!
|
|
|
03-06-2021, 07:43 PM
|
#10
|
Human being with feelings
Join Date: May 2015
Location: Québec, Canada
Posts: 4,937
|
REAPER's built-in ReaScript documentation (Help menu) is the best way to find all functions (and descriptions). All functions start with "ImGui_".
No images (or custom font) support at this time, but it's something I'd like to add.
Last edited by cfillion; 03-06-2021 at 08:01 PM.
|
|
|
03-06-2021, 08:01 PM
|
#11
|
Human being with feelings
Join Date: Dec 2017
Location: Brazil
Posts: 1,992
|
ohh, I didn't know they would start to appear there that is coooolll! Thanks, will continue here! Images and fonts will would be a great add!
|
|
|
03-06-2021, 08:30 PM
|
#12
|
Human being with feelings
Join Date: Sep 2018
Location: China
Posts: 565
|
Is there any document about how to use it?
EDIT:Found it! Thanks!
Last edited by dsyrock; 03-06-2021 at 09:39 PM.
|
|
|
03-06-2021, 10:30 PM
|
#13
|
Human being with feelings
Join Date: Dec 2017
Location: Brazil
Posts: 1,992
|
Hey this is amazing !
I really would like to see more examples as people do, I will share mine that did for study the lib.
Also having a hard time creating a menu if someone have a simple example...
Code:
r = reaper
local click_count, text = 0, ''
local ctx = reaper.ImGui_CreateContext('Not Midi Transfer', 300, 325)
layer = 1
function print(a)
reaper.ShowConsoleMsg('\n'..tostring(a))
end
function HelpMarker(desc) -- Function to show a ?
reaper.ImGui_TextDisabled(ctx, '(?)')
if reaper.ImGui_IsItemHovered(ctx) then
reaper.ImGui_BeginTooltip(ctx)
reaper.ImGui_PushTextWrapPos(ctx, reaper.ImGui_GetFontSize(ctx) * 35.0)
reaper.ImGui_Text(ctx, desc)
reaper.ImGui_PopTextWrapPos(ctx)
reaper.ImGui_EndTooltip(ctx)
end
end
function ToolTip(text)
if reaper.ImGui_IsItemHovered(ctx) then
reaper.ImGui_BeginTooltip(ctx)
reaper.ImGui_PushTextWrapPos(ctx, reaper.ImGui_GetFontSize(ctx) * 35.0)
reaper.ImGui_Text(ctx, text)
reaper.ImGui_PopTextWrapPos(ctx)
reaper.ImGui_EndTooltip(ctx)
end
end
function loop()
local rv
if reaper.ImGui_IsCloseRequested(ctx) then
reaper.ImGui_DestroyContext(ctx)
return
end
local window_flags = reaper.ImGui_WindowFlags_MenuBar() |
reaper.ImGui_WindowFlags_NoDecoration()
reaper.ImGui_SetNextWindowPos(ctx, 0, 0)
reaper.ImGui_SetNextWindowSize(ctx, reaper.ImGui_GetDisplaySize(ctx))
reaper.ImGui_Begin(ctx, 'Window', nil, window_flags)
----------------------------------------
---------------------------------------²
-----------------------------------------
---- GUI
if reaper.ImGui_BeginMenuBar(ctx) then
if reaper.ImGui_BeginMenu(ctx, 'File') then
if reaper.ImGui_MenuItem(ctx, 'Open') then
reaper.ShowConsoleMsg('opening...\n')
end
if reaper.ImGui_MenuItem(ctx, 'Save') then
reaper.ShowConsoleMsg('saving...\n')
end
reaper.ImGui_EndMenu(ctx)
end
reaper.ImGui_EndMenuBar(ctx)
end
if reaper.ImGui_Button(ctx, 'Click me!') then
click_count = click_count + 1
reaper.ShowConsoleMsg("aaa")
end
reaper.ImGui_SameLine(ctx)
reaper.ImGui_Text(ctx, [[\o/]])
reaper.ImGui_SameLine(ctx)
HelpMarker('Need a help friend?\nI once took an arrow in the kneww')
------------
rv, text = reaper.ImGui_InputText(ctx, 'text input', 'thanks cfillion '..tostring(click_count))
------------- Slider
if not v then v = 5 end
retval, v = reaper.ImGui_SliderDouble(ctx, 'Log', v, 10, 30, v, reaper.ImGui_SliderFlags_Logarithmic()) -- Window, Name, Value, Min, Max, opt string in the middle, flags for log or stuff
-------------- Checkbox
if not type(bol) then bol = true end
rc, bol = r.ImGui_Checkbox(ctx, 'What do you want from me', bol)
-------------- Radio
if not val then val = 1 end
rv, val = r.ImGui_RadioButtonEx(ctx, 'radio a', val, 0); r.ImGui_SameLine(ctx)
rv, val = r.ImGui_RadioButtonEx(ctx, 'radio b', val, 1); r.ImGui_SameLine(ctx)
rv, val = r.ImGui_RadioButtonEx(ctx, 'radio c', val, 2)
-------------- Many Butto funny
for i = 0, 4 do
if i > 0 then
r.ImGui_SameLine(ctx)
end
r.ImGui_PushID(ctx, i)
local buttonColor = reaper.ImGui_ColorConvertHSVtoRGB(i / 7.0, 0.6, 0.6, 1.0)
local hoveredColor = reaper.ImGui_ColorConvertHSVtoRGB(i / 7.0, 0.7, 0.7, 1.0)
local activeColor = reaper.ImGui_ColorConvertHSVtoRGB(i / 7.0, 0.8, 0.8, 1.0)
r.ImGui_PushStyleColor(ctx, r.ImGui_Col_Button(), buttonColor)
r.ImGui_PushStyleColor(ctx, r.ImGui_Col_ButtonHovered(), hoveredColor)
r.ImGui_PushStyleColor(ctx, r.ImGui_Col_ButtonActive(), activeColor)
r.ImGui_Button(ctx, 'Click')
r.ImGui_PopStyleColor(ctx, 3)
r.ImGui_PopID(ctx)
ToolTip('Can you eat buttons?')
if reaper.ImGui_IsItemClicked( ctx) then
print("You Can! But Just "..i+1)
end
end
------------------------------------ Above again
r.ImGui_PushID(ctx, 0)
if not vari then vari = 0.01 end
if not hues then hues = 0 end
hues = hues + vari
local buttonColor = reaper.ImGui_ColorConvertHSVtoRGB( 0.1+hues, 0.6, 0.6, 1.0)
local hoveredColor = reaper.ImGui_ColorConvertHSVtoRGB( 7.0, 0.7, 0.7, 1.0)
local activeColor = reaper.ImGui_ColorConvertHSVtoRGB( 7.0, 0.8, 0.8, 1.0)
r.ImGui_PushStyleColor(ctx, r.ImGui_Col_Button(), buttonColor)
r.ImGui_PushStyleColor(ctx, r.ImGui_Col_ButtonHovered(), hoveredColor)
r.ImGui_PushStyleColor(ctx, r.ImGui_Col_ButtonActive(), activeColor)
r.ImGui_Button(ctx, 'Danger', 250, 100)
retval, vari = reaper.ImGui_SliderDouble(ctx, 'H', vari, 0, 0.2) -- Window, Name, Value, Min, Max, opt string in the middle, flags for log or stuff
r.ImGui_PopStyleColor(ctx, 3)
r.ImGui_PopID(ctx)
--------------------------------------
---------------------------------------
--------------------------------------
reaper.ImGui_End(ctx)
reaper.defer(loop)
end
loop()
Here another one that might help someone It is the simplest I could get, like a blank GUI, with nothing in it just open the screen (there is two options lines).
Code:
function GuiInit()
ctx = reaper.ImGui_CreateContext('Item Sequencer') -- Add VERSION TODO
FONT = reaper.ImGui_CreateFont('sans-serif', 15) -- Create the fonts you need
reaper.ImGui_AttachFont(ctx, FONT)-- Attach the fonts you need
end
function loop()
local window_flags = reaper.ImGui_WindowFlags_MenuBar()
reaper.ImGui_SetNextWindowSize(ctx, 250, 300, reaper.ImGui_Cond_Once())-- Set the size of the windows. Use in the 4th argument reaper.ImGui_Cond_FirstUseEver() to just apply at the first user run, so ImGUI remembers user resize s2
reaper.ImGui_PushFont(ctx, FONT) -- Says you want to start using a specific font
local visible, open = reaper.ImGui_Begin(ctx, 'Robert Green Blue ', true, window_flags)
if visible then
--------
--YOUR GUI HERE
--------
reaper.ImGui_End(ctx)
end
reaper.ImGui_PopFont(ctx) -- Pop Font
if open then
reaper.defer(loop)
else
reaper.ImGui_DestroyContext(ctx)
end
end
GuiInit()
loop()
Last edited by daniellumertz; 08-26-2021 at 10:08 PM.
|
|
|
03-06-2021, 10:39 PM
|
#14
|
Human being with feelings
Join Date: May 2015
Location: Québec, Canada
Posts: 4,937
|
Quote:
Originally Posted by daniellumertz
Also having a hard time creating a menu if someone have a simple example...
|
Code:
local window_flags = reaper.ImGui_WindowFlags_MenuBar() |
reaper.ImGui_WindowFlags_NoDecoration()
reaper.ImGui_SetNextWindowPos(ctx, 0, 0)
reaper.ImGui_SetNextWindowSize(ctx, reaper.ImGui_GetDisplaySize(ctx))
reaper.ImGui_Begin(ctx, 'Window', nil, window_flags)
if reaper.ImGui_BeginMenuBar(ctx) then
if reaper.ImGui_BeginMenu(ctx, 'File') then
if reaper.ImGui_MenuItem(ctx, 'Open') then
reaper.ShowConsoleMsg('opening...\n')
end
if reaper.ImGui_MenuItem(ctx, 'Save') then
reaper.ShowConsoleMsg('saving...\n')
end
reaper.ImGui_EndMenu(ctx)
end
reaper.ImGui_EndMenuBar(ctx)
end
reaper.ImGui_End(ctx)
|
|
|
03-06-2021, 11:32 PM
|
#15
|
Human being with feelings
Join Date: Dec 2017
Location: Brazil
Posts: 1,992
|
Thanks Cfillion!
I was forgetting the flags! I update my example with yours here on the forum! Looking neat!
Other question, if you don't mind, how would you make layers? EDIT? I said layers but meant tabs, like changing the objects you see
I was thinking in putting the objects between if conditions but if it don't happen it might change objects place around, so it might need to be counted but not draw, or with 0 alpha. Thanks for the responses!
Last edited by daniellumertz; 03-07-2021 at 01:12 PM.
|
|
|
03-08-2021, 02:31 AM
|
#16
|
Human being with feelings
Join Date: May 2015
Location: Québec, Canada
Posts: 4,937
|
Quote:
Originally Posted by daniellumertz
Other question, if you don't mind, how would you make layers? EDIT? I said layers but meant tabs, like changing the objects you see
I was thinking in putting the objects between if conditions but if it don't happen it might change objects place around, so it might need to be counted but not draw, or with 0 alpha. Thanks for the responses!
|
I'm not sure I understand what you mean exactly. If you mean actual tabs, ImGui has those, see Widgets > Tabs in the demo script. If you mean to have some kind of "placeholder widget" that takes room in the layout but is not drawn, this can be done with ImGui_Dummy (or ImGui_InvisibleButton).
|
|
|
03-08-2021, 03:29 AM
|
#17
|
Human being with feelings
Join Date: May 2015
Location: Québec, Canada
Posts: 4,937
|
Released version 0.1.1:
Code:
• Add EEL2 example using the legacy < 6.24 syntax [#1]
• Fix first frame having twice the contents in the example scripts
• macOS: process the first click over an unfocused window
• Remove focus from ImGui input controls when the context window itself loses focus
Docking bugfixes:
• Fix keyboard input going to REAPER when docked
• Skip rendering when docked and another docker tab is active
• Linux & Windows: fix mousewheel events leaking to REAPER
• Linux: fix crashes, flickering and incomplete rendering
• macOS: update viewport size if it changed while another docker tab was active
• Windows: don't lose focus when Tab is pressed
Last edited by cfillion; 03-08-2021 at 05:54 AM.
Reason: s/5.24/6.24
|
|
|
03-08-2021, 01:30 PM
|
#18
|
Human being with feelings
Join Date: Apr 2016
Posts: 143
|
This was bound to happen, but huge thanks to cfillion for making the inevitable happen sooner rather than later.
How long till someone codes a wasm interpreter so we could finally run Windows inside Reaper?
|
|
|
03-08-2021, 04:48 PM
|
#19
|
Human being with feelings
Join Date: Sep 2016
Location: Toronto
Posts: 744
|
Thank you so much for this cfillon, what an incredible toolkit! It's inspired me to finally learn scripting and I've started on something I've wanted for a long time: an item arpeggiator script. Here's a preview: https://youtu.be/BtE5hqbbdos . I need to figure out a lot of things before it's ready like presets and smarter controls.
Somethings I'm still struggling to understand, could someone post an example of a vertical slider that has these attributes?
-it starts up with a definable default value
-double click on the control returns it to the default value
-after clicking it and releasing the mouse, it runs a function immediately
-it responds to mousewheel (and shift-mousewheel for finer adjustement if possible)
|
|
|
03-09-2021, 12:24 AM
|
#20
|
Human being with feelings
Join Date: Apr 2014
Posts: 398
|
Nice to see the first real applications! Good job Arthur!
|
|
|
03-09-2021, 01:37 AM
|
#21
|
Human being with feelings
Join Date: Dec 2017
Location: Brazil
Posts: 1,992
|
Quote:
Originally Posted by cfillion
I'm not sure I understand what you mean exactly. If you mean actual tabs, ImGui has those, see Widgets > Tabs in the demo script. If you mean to have some kind of "placeholder widget" that takes room in the layout but is not drawn, this can be done with ImGui_Dummy (or ImGui_InvisibleButton).
|
Thanks a lot for the info! Will give a look at this week.
One thing. If my script calls a message box (that needs input) the ImGui breaks I think... You might already know just wanna report, just in case...
|
|
|
03-09-2021, 05:49 AM
|
#22
|
Human being with feelings
Join Date: May 2015
Location: Québec, Canada
Posts: 4,937
|
Quote:
Originally Posted by Arthur McArthur
could someone post an example of a vertical slider that has these attributes?
-it starts up with a definable default value
-double click on the control returns it to the default value
-after clicking it and releasing the mouse, it runs a function immediately
-it responds to mousewheel (and shift-mousewheel for finer adjustement if possible)
|
Code:
local default_value = 42
local value = default_value
local reset = {}
function resetOnDoubleClick(id, value, default)
if reaper.ImGui_IsItemDeactivated(ctx) and reset[id] then
reset[id] = nil
return default
elseif reaper.ImGui_IsItemHovered(ctx) and reaper.ImGui_IsMouseDoubleClicked(ctx, 0) then
reset[id] = true
end
return value
end
function applyMousewheel(value, min, max)
local shift = reaper.ImGui_GetKeyMods(ctx) & reaper.ImGui_KeyModFlags_Shift() ~= 0
local wheel, hwheel = reaper.ImGui_GetMouseWheel(ctx)
if shift and wheel == 0 then wheel = hwheel end
if wheel ~= 0 then
speed = shift and 1 or 4
value = value + math.ceil(wheel * speed)
return math.max(min, math.min(value, max))
end
return value
end
function myVSliderInt(id, width, height, value, min, max, default_value)
local rv
rv,value = reaper.ImGui_VSliderInt(ctx, id, width, height, value, min, max)
value = resetOnDoubleClick(id, value, default_value)
if reaper.ImGui_IsItemHovered(ctx) then
value = applyMousewheel(value, min, max)
end
-- or ImGui_IsItemDeactivatedAfterEdit to only do something if the value changed
return reaper.ImGui_IsItemDeactivated(ctx), value
end
function loop()
local rv
-- ...
rv,value = myVSliderInt('##v', 40, 160, value, 0, 100, default_value)
if rv then
doSomething()
end
-- ...
end
Quote:
Originally Posted by daniellumertz
One thing. If my script calls a message box (that needs input) the ImGui breaks I think... You might already know just wanna report, just in case...
|
I wasn't aware of that issue, thanks! Seems like calling ShowMessageBox/GetUserInputs on Windows and Linux pauses all scripts but not the extension, which proceeds to delete the contextes thinking the are no longer in use. I'll look into possible solutions...
An alternative would be to use ImGui's own modal dialog feature. See Demo > Popups & Modal windows > Modals.
Last edited by cfillion; 03-09-2021 at 06:48 AM.
|
|
|
03-09-2021, 10:17 AM
|
#23
|
Human being with feelings
Join Date: Sep 2016
Location: Toronto
Posts: 744
|
Thanks so much cfillon!
Here's a bit of code testing it out, it seems like the mousewheel is lagging behind one step and displaying the last value instead of the current one, is there a way to fix that?
Also, is there a better way to do multiple sliders than how I've tried it here? I just copied the code you provided and added 1 to all the values.
Code:
local ctx = reaper.ImGui_CreateContext('Slider Test', 300, 600)
local default_value = 0
local value = default_value
local default_value2 = 0
local value2 = default_value2
local reset = {}
function loop()
if reaper.ImGui_IsCloseRequested(ctx) then
reaper.ImGui_DestroyContext(ctx)
return
end
reaper.ImGui_SetNextWindowPos(ctx, 0, 0)-- Don't really need but it makes it at 0 0 "Lock it"
reaper.ImGui_SetNextWindowSize(ctx, reaper.ImGui_GetDisplaySize(ctx))-- Don't really need but it makes it the size of the screen
reaper.ImGui_Begin(ctx, 'wnd', nil, reaper.ImGui_WindowFlags_NoDecoration())
--- GUI HERE
local rv
local rv2
-- ...
rv,value = myVSliderInt('##v1', 40, 160, value, -24, 24, default_value)
if rv then
dosomething()
end
rv2,value2 = myVSliderInt2('##v2', 40, 160, value2, -24, 24, default_value2)
if rv2 then
dosomething()
end
-- ...
reaper.ImGui_End(ctx)
reaper.defer(loop)
end
function dosomething()
reaper.ShowConsoleMsg(value)
end
function resetOnDoubleClick(id, value, default)
if reaper.ImGui_IsItemDeactivated(ctx) and reset[id] then
reset[id] = nil
return default
elseif reaper.ImGui_IsItemHovered(ctx) and reaper.ImGui_IsMouseDoubleClicked(ctx, 0) then
reset[id] = true
end
return value
end
function applyMousewheel(value, min, max)
local shift = reaper.ImGui_GetKeyMods(ctx) & reaper.ImGui_KeyModFlags_Shift() ~= 0
local wheel, hwheel = reaper.ImGui_GetMouseWheel(ctx)
if shift and wheel == 0 then wheel = hwheel end
if wheel ~= 0 then
speed = shift and 1 or 1
value = value + math.ceil(wheel * speed)
dosomething()
return math.max(min, math.min(value, max))
end
return value
end
function myVSliderInt(id, width, height, value, min, max, default_value)
local rv
rv,value = reaper.ImGui_VSliderInt(ctx, id, width, height, value, min, max)
value = resetOnDoubleClick(id, value, default_value)
if reaper.ImGui_IsItemHovered(ctx) then
value = applyMousewheel(value, min, max)
end
-- or ImGui_IsItemDeactivatedAfterEdit to only do something if the value changed
return reaper.ImGui_IsItemDeactivated(ctx), value
end
function myVSliderInt2(id, width, height, value2, min, max, default_value)
local rv2
rv2,value2 = reaper.ImGui_VSliderInt(ctx, id, width, height, value2, min, max)
value2 = resetOnDoubleClick(id, value2, default_value)
if reaper.ImGui_IsItemHovered(ctx) then
value2 = applyMousewheel(value2, min, max)
end
-- or ImGui_IsItemDeactivatedAfterEdit to only do something if the value changed
return reaper.ImGui_IsItemDeactivated(ctx), value2
end
loop()
|
|
|
03-10-2021, 12:18 AM
|
#24
|
Human being with feelings
Join Date: May 2015
Location: Québec, Canada
Posts: 4,937
|
Quote:
Originally Posted by Arthur McArthur
Here's a bit of code testing it out, it seems like the mousewheel is lagging behind one step and displaying the last value instead of the current one, is there a way to fix that?
|
That is because the dosomething() inside applyMousewheel happens before the global value variable is modified.
You could do something like this:
Code:
function applyMousewheel(value, min, max)
-- ...
return true, math.max(min, math.min(value, max))
end
return false, value
end
function myVSliderInt(id, width, height, value, min, max, default_value)
local rv
rv,value = reaper.ImGui_VSliderInt(ctx, id, width, height, value, min, max)
value = resetOnDoubleClick(id, value, default_value)
local changed
if reaper.ImGui_IsItemHovered(ctx) then
changed,value = applyMousewheel(value, min, max)
end
if not changed then changed = reaper.ImGui_IsItemDeactivated(ctx) end
-- or ImGui_IsItemDeactivatedAfterEdit to only do something if the value changed
return changed, value
end
Quote:
Originally Posted by Arthur McArthur
Also, is there a better way to do multiple sliders than how I've tried it here? I just copied the code you provided and added 1 to all the values.
|
There's no need to add another myVSliderInt* function for each slider. It can be reused:
Code:
rv,value = myVSliderInt('##v1', 40, 160, value, -24, 24, default_value)
if rv then
dosomething()
end
rv,value2 = myVSliderInt('##v2', 40, 160, value2, -24, 24, default_value2)
if rv then
dosomething()
end
|
|
|
03-10-2021, 05:49 AM
|
#25
|
Human being with feelings
Join Date: Jun 2013
Location: Krefeld, Germany
Posts: 14,690
|
Any chance for this in JSFX -> @gfx ?
-Michael
|
|
|
03-10-2021, 07:23 AM
|
#26
|
Human being with feelings
Join Date: May 2015
Location: Québec, Canada
Posts: 4,937
|
Quote:
Originally Posted by mschnell
Any chance for this in JSFX -> @gfx ?
|
That's not possible with the current REAPER extension API.
|
|
|
03-10-2021, 07:33 AM
|
#27
|
Human being with feelings
Join Date: Sep 2016
Location: Toronto
Posts: 744
|
Great, thank you!!
Here's some test slider example code based on what cfillon provided for those interested, it has:
-Integer and double sliders in horizontal and vertical
-Default values (double-click to reset)
-Mousewheel (shift-mousewheel for fine adjustments)
-Different mousewheel sensitivity variables for integer and double
Code:
local ctx = reaper.ImGui_CreateContext('Slider Test', 250, 250)
int_mousewheel_sensitivity = 1
int_mousewheel_sensitivity_fine = 1
double_mousewheel_sensitivity = .1
double_mousewheel_sensitivity_fine = .01
local default_value = 0
local value = default_value
local default_value2 = 1
local value2 = default_value2
local default_value3 = 2
local value3 = default_value3
local default_value4 = 3
local value4 = default_value4
local reset = {}
----------------------------- TEST FUNCTION ----------------------
function dosomething()
reaper.ShowConsoleMsg(test_input .. '\n')
end
-------------------------------------------------------------------
------------------------- GUI ------------------------------------
-------------------------------------------------------------------
function loop()
if reaper.ImGui_IsCloseRequested(ctx) then
reaper.ImGui_DestroyContext(ctx)
return
end
reaper.ImGui_SetNextWindowPos(ctx, 0, 0)-- Don't really need but it makes it at 0 0 "Lock it"
reaper.ImGui_SetNextWindowSize(ctx, reaper.ImGui_GetDisplaySize(ctx))-- Don't really need but it makes it the size of the screen
reaper.ImGui_Begin(ctx, 'wnd', nil, reaper.ImGui_WindowFlags_NoDecoration())
local rv
---Vertical Slider
rv,value = myVSliderInt('##v1', 40, 160, value, -10, 10, default_value)
if rv then
test_input = value
dosomething()
end
reaper.ImGui_SameLine(ctx)
---Vertical Slider Double
rv,value2 = myVSliderDouble('##v2', 40, 160, value2, -10, 10, default_value2)
if rv then
test_input = value2
dosomething()
end
---Horizontal Slider
rv,value3 = mySliderInt('##v3', value3, -10, 10, default_value3)
if rv then
test_input = value3
dosomething()
end
---Horizontal Slider Double
rv,value4 = mySliderDouble('##v4', value4, -10, 10, default_value4)
if rv then
test_input = value4
dosomething()
end
reaper.ImGui_End(ctx)
reaper.defer(loop)
end
--------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------
---------------------------- DOUBLE CLICK AND MOUSEWHEEL FUNCTIONS --------------------------------
function resetOnDoubleClick(id, value, default)
if reaper.ImGui_IsItemDeactivated(ctx) and reset[id] then
reset[id] = nil
return default
elseif reaper.ImGui_IsItemHovered(ctx) and reaper.ImGui_IsMouseDoubleClicked(ctx, 0) then
reset[id] = true
end
return value
end
function applyMousewheel(value, min, max)
local shift = reaper.ImGui_GetKeyMods(ctx) & reaper.ImGui_KeyModFlags_Shift() ~= 0
local wheel, hwheel = reaper.ImGui_GetMouseWheel(ctx)
if shift and wheel == 0 then wheel = hwheel end
if wheel ~= 0 then
speed = shift and int_mousewheel_sensitivity_fine or int_mousewheel_sensitivity
value = value + math.ceil(wheel * speed)
return true, math.max(min, math.min(value, max))
end
rv=true
return false, value
end
function applyMousewheelDouble(value, min, max)
local shift = reaper.ImGui_GetKeyMods(ctx) & reaper.ImGui_KeyModFlags_Shift() ~= 0
local wheel, hwheel = reaper.ImGui_GetMouseWheel(ctx)
if shift and wheel == 0 then wheel = hwheel end
if wheel ~= 0 then
speed = shift and double_mousewheel_sensitivity_fine or double_mousewheel_sensitivity
value = value + (wheel * speed)
return true, math.max(min, math.min(value, max))
end
rv=true
return false, value
end
------------------------------------ VERTICAL SLIDER ---------------------------------
function myVSliderInt(id, width, height, value, min, max, default_value)
local rv
rv,value = reaper.ImGui_VSliderInt(ctx, id, width, height, value, min, max)
value = resetOnDoubleClick(id, value, default_value)
local changed
if reaper.ImGui_IsItemHovered(ctx) then
changed,value = applyMousewheel(value, min, max)
end
if not changed then changed = reaper.ImGui_IsItemDeactivatedAfterEdit(ctx) end
return changed, value
end
------------------------------------ VERTICAL SLIDER DOUBLE ---------------------------------
function myVSliderDouble(id, width, height, value, min, max, default_value)
local rv
rv,value = reaper.ImGui_VSliderDouble(ctx, id, width, height, value, min, max)
value = resetOnDoubleClick(id, value, default_value)
local changed
if reaper.ImGui_IsItemHovered(ctx) then
changed,value = applyMousewheelDouble(value, min, max)
end
if not changed then changed = reaper.ImGui_IsItemDeactivatedAfterEdit(ctx) end
return changed, value
end
----------------------------------------- HORIZONTAL SLIDER ---------------------------
function mySliderInt(id, value, min, max, default_value)
local rv
rv,value = reaper.ImGui_SliderInt(ctx, id, value, min, max)
value = resetOnDoubleClick(id, value, default_value)
local changed
if reaper.ImGui_IsItemHovered(ctx) then
changed, value = applyMousewheel(value, min, max)
end
if not changed then changed = reaper.ImGui_IsItemDeactivatedAfterEdit(ctx) end
return changed, value
end
----------------------------------------- HORIZONTAL SLIDER DOUBLE ---------------------------
function mySliderDouble(id, value, min, max, default_value)
local rv
rv,value = reaper.ImGui_SliderDouble(ctx, id, value, min, max)
value = resetOnDoubleClick(id, value, default_value)
local changed
if reaper.ImGui_IsItemHovered(ctx) then
changed, value = applyMousewheelDouble(value, min, max)
end
if not changed then changed = reaper.ImGui_IsItemDeactivatedAfterEdit(ctx) end
return changed, value
end
----------------------------------------------------------------------------
-----------------------------------------------------------------------------
--------------------------------------------------------------------------
loop()
|
|
|
03-10-2021, 10:26 AM
|
#28
|
Human being with feelings
Join Date: Apr 2016
Location: ASU`ogacihC
Posts: 3,913
|
Interesting!
|
|
|
03-10-2021, 02:33 PM
|
#29
|
Human being with feelings
Join Date: Apr 2014
Posts: 95
|
Awesome !
Did some testing with the full demo and multiple selectables: it seems the ImGui_KeyModFlags are not working: when i disable it, i am able to select multiple lines.
line 1112
Code:
if r.ImGui_TreeNode(ctx, 'Selection State: Multiple Selection') then
demo.HelpMarker('Hold CTRL and click to select multiple items.')
for i,sel in ipairs(widgets.selectables.multiple) do
if r.ImGui_Selectable(ctx, ('Object %d'):format(i-1), sel) then
-- if not (r.ImGui_GetKeyMods(ctx) & r.ImGui_KeyModFlags_Ctrl()) ~= 0 then -- Clear selection when CTRL is not held
-- for j = 1, #widgets.selectables.multiple do
-- widgets.selectables.multiple[j] = false
-- end
-- end
widgets.selectables.multiple[i] = not sel
end
end
r.ImGui_TreePop(ctx)
end
|
|
|
03-10-2021, 09:17 PM
|
#30
|
Human being with feelings
Join Date: Dec 2020
Location: Miami, FL USA
Posts: 396
|
Have been studying basic C++ the past two days to try to integrate some of these third party prebuilt ImGui components with ReaImGui.
It's been entirely thanks to @cfillion
Today was first success!
Accomplished the following: - Learned more basic C++ (aka bothered cfillion all day)
- Ported 36 ImGui styles/skins to ReaImgui
- Ported a style-inherited "toggle" button
- Ported two curve editor components
- The top one works but I'm unsure how useful it will be
- The bottom one where you see nothing, is much more useful, but I'm too stupid to figure out how to get it working right. Something for tomorrow I guess.
Tomorrow, I will try to port: - A visual node-based editor for DSP/FX graphs or routing stuff
- A sequencer/arranger timeline component
- Also need to write some docs on how folks can help port these and integrate other ones
Demo of today's fruits:
__________________
Seasoned codemonkey
Dunno a thing about making music (here to learn!)
|
|
|
03-11-2021, 06:17 AM
|
#31
|
Human being with feelings
Join Date: May 2015
Location: Québec, Canada
Posts: 4,937
|
Quote:
Originally Posted by aurelien
Awesome !
Did some testing with the full demo and multiple selectables: it seems the ImGui_KeyModFlags are not working: when i disable it, i am able to select multiple lines.
line 1112
|
The commented out lines are responsible for disabling multi-selection when Ctrl is not down. However the condition is incorrect, it should have been:
Code:
if (r.ImGui_GetKeyMods(ctx) & r.ImGui_KeyModFlags_Ctrl()) == 0 then -- Clear selection when CTRL is not held"
(Fixed for the next release)
|
|
|
03-11-2021, 06:39 AM
|
#32
|
Human being with feelings
Join Date: Apr 2014
Posts: 95
|
Thanks cfillion !
I commented out the lines to test multi-selection in the example i posted.
With your fix, everything is working as expected!
I'm really grateful for your work.
|
|
|
03-11-2021, 09:16 AM
|
#33
|
Human being with feelings
Join Date: Dec 2017
Location: Brazil
Posts: 1,992
|
Quote:
Originally Posted by gxray
Have been studying basic C++ the past two days to try to integrate some of these third party prebuilt ImGui components with ReaImGui.
It's been entirely thanks to @cfillion
Today was first success!
Accomplished the following: - Learned more basic C++ (aka bothered cfillion all day)
- Ported 36 ImGui styles/skins to ReaImgui
- Ported a style-inherited "toggle" button
- Ported two curve editor components
- The top one works but I'm unsure how useful it will be
- The bottom one where you see nothing, is much more useful, but I'm too stupid to figure out how to get it working right. Something for tomorrow I guess.
Tomorrow, I will try to port: - A visual node-based editor for DSP/FX graphs or routing stuff
- A sequencer/arranger timeline component
- Also need to write some docs on how folks can help port these and integrate other ones
Demo of today's fruits:
|
Wow! This will end up being even bigger than what already is ! Danke! a lot mr.gxray!
Even a timeline and a node based !!!
This is other level GUI for scripters now
|
|
|
03-14-2021, 04:56 PM
|
#34
|
Human being with feelings
Join Date: Sep 2016
Location: Toronto
Posts: 744
|
Is there any way to suppress the error:
Loading presetImGui assertion failed: (g.CurrentWindowStack.Size == 1) && "Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?"
When a ReaScript error pops up?
|
|
|
03-16-2021, 05:21 AM
|
#35
|
Human being with feelings
Join Date: May 2015
Location: Québec, Canada
Posts: 4,937
|
Quote:
Originally Posted by Arthur McArthur
Is there any way to suppress the error:
Loading presetImGui assertion failed: (g.CurrentWindowStack.Size == 1) && "Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?"
When a ReaScript error pops up?
|
No, because those messages are meant to inform that a fatal ImGui error occured and the context has been destroyed.
If preventing Lua errors from happening during the script's normal operation is not possible, you could use Lua's protected mode (pcall/xpcall functions) to catch them without crashing the script mid-frame.
https://www.lua.org/pil/8.4.html
|
|
|
03-16-2021, 04:34 PM
|
#36
|
Human being with feelings
Join Date: Apr 2013
Location: France
Posts: 9,875
|
Such things could be huge game changer for theming!
Default windows popup is doesn't real time preview...
also making copy color from other element could be done way more easily...
This could be a good framework to remake the theme tweaker!
|
|
|
03-16-2021, 04:59 PM
|
#37
|
Human being with feelings
Join Date: Oct 2017
Location: Black Forest
Posts: 5,054
|
Goodness X-Raym, such a great idea!
|
|
|
03-16-2021, 05:20 PM
|
#38
|
Human being with feelings
Join Date: Apr 2013
Location: France
Posts: 9,875
|
@Stevie
And it is getting better such quickly !!
Copy paste of colors for theme tweaker, at last!
|
|
|
03-16-2021, 06:27 PM
|
#39
|
Human being with feelings
Join Date: Dec 2017
Location: Brazil
Posts: 1,992
|
ahhhh great idea indeed! copy and paste will save a lot of time hahaha
|
|
|
03-17-2021, 02:47 AM
|
#40
|
Human being with feelings
Join Date: Oct 2017
Location: Black Forest
Posts: 5,054
|
Waaaah, do you plan to release that script?
|
|
|
Thread Tools |
|
Display Modes |
Linear Mode
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
All times are GMT -7. The time now is 08:58 AM.
|