Old 06-04-2016, 02:02 PM   #1
Lokasenna
Human being with feelings
 
Lokasenna's Avatar
 
Join Date: Sep 2008
Location: Calgary, AB, Canada
Posts: 6,551
Default Lokasenna's GUI library for Lua v2

V3 update, February 2020 - v3 is now available on ReaPack! I'll make a separate thread for it when time allows, but in the meantime you can have a look at https://jalovatt.github.io/scythe

GUIs. We all need them, and they're a bit of a pain to make in ReaScript. Why not let someone else do the hard work so you can get back to actually making your script do something cool?



Installation:

ReaPack
- Install the Lokasenna's GUI library v2 for Lua package
- In Reaper's action list, run Set Lokasenna_GUI v2 library path.lua

Any scripts requiring this library should now be able to find it.

Manual
- Download the files here (including any subfolders), making sure to keep the same folder structure wherever you put them on your hard drive
- Find and run the install script, Set Lokasenna_GUI v2 library path.lua

Developers
A second package, Lokasenna's GUI library v2 for Lua (developer tools), provides example scripts, templates, and documentation.


Development:
All of my work is done at Lokasenna_GUI on Github. Everything there is to be considered unstable, and probably not suitable for release, but any new feature updates or class additions will show up there. Contributions, bug reports, etc are all welcome.

Enjoy!


Reasons why you should use this sexy beast include:

- It comes with a GUI builder! (Experimental, see the Developer Tools package)


- Very little coding required on your part. A simple GUI might need only a dozen lines of code compared to the hundreds (or thousands, for some of my scripts) you'd have to write if you did it yourself.

- Global font and color settings, so you can change the overall look to suit your fancy.

- Layer visibility management, so you can have multiple sets of controls or dialog boxes come and go as needed.

- Graphics use blitting whenever possible, keeping the CPU usage low without any worry on your part.

- Hooks to run your own functions as part of the GUI's updating loop. You could relabel the options around a knob if you wanted, or have a slider and knob match the selected track's volume/pan... etc.

- Built-in crash reporting, providing more detailed error messages than Reaper does by itself.

- Can be told to exit from your own code, and to run a function when it does. For instance, "save all the current settings, run this action, and quit".

- Numerous helper functions in addition to the GUI code, simplifying a number of things that might be annoying to code on your own every time.

- Modular design, allowing you to use as much, or as little, of my own code as you want. You can also write your own classes if you'd prefer.


Changelog:

July 8/18: The "Lokasenna GUI v2.x.x" watermark now reads its version from ReaPack so I don't have to remember to update it.

June 27/18: First stable release, available on ReaPack. It will only be updated directly with bug fixes - any feature updates and new classes will live on the project repository until I feel like they're safe to move over.

June 6/18: Added support for creating elements with keyed tables rather than a series of function arguments, and an example script demonstrating it.

June 2/18: New class - Window. A number of under-the-hood improvements and new Core functions. Better crash reporting, and handling of Reaper's "restricted permissions" mode.

May 10/18: Fixed some weirdness with how Knob and Slider return their values. This update changes the parameters for both classes and will break any scripts that use them. My apologies.

April 29/18: Added Menubar class.

April 25/18: Added a basic crash reporter, moved the project to my own repository on Github.

April 22/18: Went through all of the classes/scripts and did some major tidying, as well as breaking most of the longer functions into smaller chunks.

April 8/18: Added Listbox and TextEditor classes. There were also a number of bug fixes and efficiency improvements back in... February? I forget.

September 26/17: Bug fix - the Knob class was ignoring min/max values when drawing values around the knob.

August 19/17: Bug fixes related to macOS using decimal values for the mousewheel, and scrolling the mousewheel on a Menubox with no options in it.

July 31/17: A few bug fixes.

June 9/17: First proper release. Classes are modular, tons of new features, code is much more efficient.

June 13/16: Rewrote the library to be copy/paste-able rather than distributing the file separately.
__________________
I'm no longer using Reaper or working on scripts for it. Sorry. :(
Default 5.0 Nitpicky Edition / GUI library for Lua scripts / Theory Helper / Radial Menu / Donate

Last edited by Lokasenna; 02-09-2020 at 03:25 PM.
Lokasenna is offline   Reply With Quote
Old 06-04-2016, 06:13 PM   #2
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 9,872
Default

Thanks for your hard work on this, I'm sure it could be useful to a lot of scripters !!

Cheers !
X-Raym is offline   Reply With Quote
Old 06-04-2016, 10:19 PM   #3
michaeltonight
Human being with feelings
 
michaeltonight's Avatar
 
Join Date: Jun 2010
Location: Texas
Posts: 357
Default

This is amazing, Lokasenna.
michaeltonight is offline   Reply With Quote
Old 06-08-2016, 08:30 AM   #4
Ozman
Human being with feelings
 
Join Date: Feb 2015
Posts: 753
Default

This looks awesome!
Ozman is offline   Reply With Quote
Old 06-08-2016, 12:56 PM   #5
sfzgeek
Human being with feelings
 
sfzgeek's Avatar
 
Join Date: Feb 2009
Location: Dunedin, New Zealand
Posts: 205
Default

Bravo! Amazing work and excellent reference scripts!
__________________
My rawk band: The Hidden Venture.
sfzgeek is offline   Reply With Quote
Old 06-10-2016, 04:40 AM   #6
Brado231
Human being with feelings
 
Join Date: Sep 2012
Location: Oz
Posts: 196
Default

Great stuff! Thanks!!
Brado231 is offline   Reply With Quote
Old 02-20-2021, 09:43 PM   #7
noah1234j
Human being with feelings
 
Join Date: Jan 2021
Posts: 22
Default Issue in regard to getting GUI.Val, after setting it via a command

Hi Everyone, new to reaper, the forums, and programming in general and would be very grateful for any assistance.

After setting a listbox value via a command, I don't seem to be able to query the correct value.

I would like to add that I don't seem to have issues querying the value if I select the list item with my mouse cursor.

This is probably something really simple that I'm missing but I can't see it.

Thanks all

Code:
    local lib_path = reaper.GetExtState("Lokasenna_GUI", "lib_path_v2")
    if not lib_path or lib_path == "" then
        reaper.MB("Couldn't load the Lokasenna_GUI library. Please install 'Lokasenna's GUI library v2 for Lua', available on ReaPack, then run the 'Set Lokasenna_GUI v2 library path.lua' script in your Action List.", "Whoops!", 0)
        return
    end
    loadfile(lib_path .. "Core.lua")()
    
    GUI.req("Classes/Class - Listbox.lua")()
    GUI.req("Classes/Class - Button.lua")()

  function example_function()
    GUI.Val("Listbox", 1) --Sets the index to 1
    
    reaper.ShowConsoleMsg("Current index: " .. GUI.Val("Listbox")) --Lists 1 as the current index
    
    GUI.Val("Listbox", 4) --Sets the index to 4
    GUI.elms.Listbox.retval = {5}

    reaper.ShowConsoleMsg("Current index: " .. GUI.Val("Listbox")) --why does it list 1???? I would expect to get 4 in return
    
    GUI.Val("Listbox", 3) --Sets the index to 3
    reaper.ShowConsoleMsg("Current index: " .. GUI.Val("Listbox")) --still lists 1?
    end
  
  GUI.New("Listbox", "Listbox", {
      z = 11,
      x = 80,
      y = 32,
      w = 192,
      h = 96,
      list = {"item 1", "item 2", "item 4", "item 5", "item 6"},
      multi = false, -- For my purposes, I nee
      caption = "Scenes"
  })
  GUI.New("Button", "Button", {
      z = 12, 
      x = 80,
      y = 160,
      w = 70,
      h = 20,
      caption = "Push Me",
      func = example_function --Here is where I trigger the function on the button click
  })
  
GUI.Init()
GUI.Main()
noah1234j is offline   Reply With Quote
Old 02-21-2021, 12:47 AM   #8
MusoBob
Human being with feelings
 
MusoBob's Avatar
 
Join Date: Sep 2014
Posts: 2,642
Default

See what this does:

Code:
    local lib_path = reaper.GetExtState("Lokasenna_GUI", "lib_path_v2")
    if not lib_path or lib_path == "" then
        reaper.MB("Couldn't load the Lokasenna_GUI library. Please install 'Lokasenna's GUI library v2 for Lua', available on ReaPack, then run the 'Set Lokasenna_GUI v2 library path.lua' script in your Action List.", "Whoops!", 0)
        return
    end
    loadfile(lib_path .. "Core.lua")()
    
    GUI.req("Classes/Class - Listbox.lua")()
    GUI.req("Classes/Class - Button.lua")()

  function example_function()
    GUI.Val("Listbox", 1) --Sets the index to 1
    
    reaper.ShowConsoleMsg("Current index: " .. listbox_val .."\n") --Lists 1 as the current index
    
    GUI.Val("Listbox", 4) --Sets the index to 4
    GUI.elms.Listbox.retval = {5}

    reaper.ShowConsoleMsg("Current index: " .. listbox_val .."\n") --why does it list 1???? I would expect to get 4 in return
    
    GUI.Val("Listbox", 3) --Sets the index to 3
    reaper.ShowConsoleMsg("Current index: " .. listbox_val .."\n") --still lists 1?
    end
  
  GUI.New("Listbox", "Listbox", {
      z = 11,
      x = 80,
      y = 32,
      w = 192,
      h = 96,
      list = {"item 1", "item 2", "item 4", "item 5", "item 6"},
      multi = false, -- For my purposes, I nee
      caption = "Scenes"
  })
  GUI.New("Button", "Button", {
      z = 12, 
      x = 80,
      y = 160,
      w = 70,
      h = 20,
      caption = "Push Me",
      func = example_function --Here is where I trigger the function on the button click
  })
  
  function GUI.elms.Listbox:onmouseup()
      GUI.Listbox.onmouseup(self)
      listbox_val = GUI.Val("Listbox") 
      reaper.ShowConsoleMsg("Current index: " .. GUI.Val("Listbox") .."\n")
      
  end
  
GUI.Init()
GUI.Main()
__________________
ReaTrakStudio Chord Track for Reaper forum
www.reatrak.com
STASH Downloads https://stash.reaper.fm/u/ReaTrak
MusoBob is offline   Reply With Quote
Old 02-21-2021, 02:15 AM   #9
MusoBob
Human being with feelings
 
MusoBob's Avatar
 
Join Date: Sep 2014
Posts: 2,642
Default

I had a look at it, this should set it:

Code:
   GUI.Val("Listbox", 2) --Sets the index to 2. Accepts a table of boolean values for items to be selected or not selected.
   GUI.elms.Listbox:init()
   reaper.ShowConsoleMsg("Current index: " .. GUI.Val("Listbox") .."\n") --Lists 2 as the current index
EDIT: and this will set 1 4 6 selected
Code:
GUI.Val("Listbox", {true,false,true,false,true}) --Sets the index to 1 4 6. Accepts a table of boolean values for items to be selected or not selected.
or
Code:
preset1={true,false,true,false,true}
GUI.Val("Listbox", preset1) --Sets the index to 1 4 6. Accepts a table of boolean values for items to be selected or not selected.
https://github.com/jalovatt/Lokasenn...i/2.00-Listbox
Example Lokasenna GUI included > Script: Example - Menubar, Listbox, and TextEditor.lua
\REAPER\Scripts\ReaTeam Scripts\Development\Lokasenna_GUI v2\Developer Tools\Examples and Templates

__________________
ReaTrakStudio Chord Track for Reaper forum
www.reatrak.com
STASH Downloads https://stash.reaper.fm/u/ReaTrak

Last edited by MusoBob; 02-21-2021 at 04:50 AM.
MusoBob is offline   Reply With Quote
Old 02-22-2021, 01:04 PM   #10
noah1234j
Human being with feelings
 
Join Date: Jan 2021
Posts: 22
Default

Thanks for your help MusoBob.

When I'm running this I'm still getting 1 returned to me?
Perhaps I'm running it the wrong place? or I am on the wrong version of Lokasenna?

Code:
    local lib_path = reaper.GetExtState("Lokasenna_GUI", "lib_path_v2")
    if not lib_path or lib_path == "" then
        reaper.MB("Couldn't load the Lokasenna_GUI library. Please install 'Lokasenna's GUI library v2 for Lua', available on ReaPack, then run the 'Set Lokasenna_GUI v2 library path.lua' script in your Action List.", "Whoops!", 0)
        return
    end
    loadfile(lib_path .. "Core.lua")()
    
    GUI.req("Classes/Class - Listbox.lua")()
    GUI.req("Classes/Class - Button.lua")()

  function example_function()
   GUI.Val("Listbox", 2) --Sets the index to 2.
   GUI.elms.Listbox:init()
   reaper.ShowConsoleMsg("Current index: " .. GUI.Val("Listbox") .."\n") --Still listing 1 for me?
  end
  
  GUI.New("Listbox", "Listbox", {
      z = 11,
      x = 80,
      y = 32,
      w = 192,
      h = 96,
      list = {"item 1", "item 2", "item 4", "item 5", "item 6"},
      multi = false,
      caption = "Scenes"
  })
  GUI.New("Button", "Button", {
      z = 12, 
      x = 80,
      y = 160,
      w = 70,
      h = 20,
      caption = "Push Me",
      func = example_function --Here is where I trigger the function on the button click
  })
  
GUI.Init()
GUI.Main()
noah1234j is offline   Reply With Quote
Old 02-22-2021, 02:18 PM   #11
MusoBob
Human being with feelings
 
MusoBob's Avatar
 
Join Date: Sep 2014
Posts: 2,642
Default

I will have another look at it, but if you are setting the value you should already know that ?
Code:
  function example_function()
   set_val = 2 --Sets the index to 2
   GUI.Val("Listbox", set_val) .
   GUI.elms.Listbox:init()
   
   reaper.ShowConsoleMsg("Current index: " .. set_val .."\n") 
  
  end
__________________
ReaTrakStudio Chord Track for Reaper forum
www.reatrak.com
STASH Downloads https://stash.reaper.fm/u/ReaTrak
MusoBob is offline   Reply With Quote
Old 02-23-2021, 12:16 PM   #12
solger
Human being with feelings
 
solger's Avatar
 
Join Date: Mar 2013
Posts: 5,844
Default

I had a quick look at the core code of the Listbox class and it seems that the Listbox also expects a table when using multi = false (for returning the correct value **). So try this:

Code:
function example_function()
    GUI.Val("Listbox", {[4] = true}) -- set index 4 to true
    reaper.ShowConsoleMsg("Current index: " .. GUI.Val("Listbox") .."\n") 
end

Or as MusoBob showed with the example above in post #831: another way would be to use the value directly from the variable (set_val in the example) for further usage.



** EDIT: Not quite sure yet (I need to take a closer look at the core code again), but getting '1' as return value when using multi = false and a number (instead of a table) for setting the index might perhaps be a bug.
__________________
ReaLauncher

Last edited by solger; 02-23-2021 at 01:12 PM.
solger is offline   Reply With Quote
Old 04-12-2021, 08:54 AM   #13
J Reverb
Human being with feelings
 
Join Date: Jul 2009
Posts: 1,071
Default

Hi all,
Couple of questions

Is there a best practice for creating a row of buttons ?
I would like to have a different function on each button which I have but at the moment I have to create each one individually like so .. and the code gets long and I'm looking at creating quite a few of them.
Code:
local layer = GUI.createLayer({name = "Layer1"})
layer:addElements( GUI.createElements(
{
  name = "1",
  type = "Button",
  x = 8,
  y = 10,
  w = 60,
  h = 30,
  caption = "b1",
  func = func1,
},
{
  name = "2",
  type = "Button",
  x = 8,
  y = 90,
  w = 60,
  h = 30,
  caption = "b2",
  func = func2,
 },
etc. etc.

Also second question,
Is there a way to change the color of the last clicked button ? So I know that is the current function ?

Thanks v much
J Reverb is offline   Reply With Quote
Old 04-12-2021, 11:32 AM   #14
woodslanding
Human being with feelings
 
woodslanding's Avatar
 
Join Date: Mar 2007
Location: Denver, CO
Posts: 633
Default

There are a lot of ways to do that. I created a grid layout method for a bunch of identically sized elements:

Code:
function GetLayoutXandY(i,x,y,w,h,rows)
    ----MSG("layout: x = "..x)
    local xadj = math.floor((i - 1)/rows)
    local yadj = (i-1) % rows
    local xpos = x + (xadj * w)
    local ypos = y + (yadj * h)
    return xpos,ypos
end
then I have a method like this:
Code:
mybuttons = {
   x = 0, y = 0, w = 96, h = 36
}
for i,s in ipairs(mybuttons) do
    local xpos, ypos = GetLayoutXandY(i,mybuttons.x,mybuttons.y, mybuttons.w,mybuttons.h, 1)
    local button = GUI.createElement({
           name = 'button'..i,
           x = xpos,
           y = ypos,  
          --etc.
    })
    myLayer:addElements(button)
end
Hope this helps.
__________________
eric moon
Very Stable Genius
https://gogolab.com/
woodslanding is offline   Reply With Quote
Old 04-12-2021, 02:45 PM   #15
J Reverb
Human being with feelings
 
Join Date: Jul 2009
Posts: 1,071
Default

@woodslanding

Yeah that looks like the sort of thing I might need I was sure there had to be a way of drawing stuff automatically, I am using scythe v3 and can't seem to get your code working though. How would this integrate into the basic framework ?
Cheers for your help.
J Reverb is offline   Reply With Quote
Old 04-13-2021, 07:16 AM   #16
woodslanding
Human being with feelings
 
woodslanding's Avatar
 
Join Date: Mar 2007
Location: Denver, CO
Posts: 633
Default

that's kind of pseudo-code, yeah. I'm sure it won't work as is... it's just to give you the idea.

Read up on lua tables, and study the methods he uses to create the various widgets himself, you'll see how the constructors are just tables. Once you learn to create and alter tables various ways, it will all fall into place.
__________________
eric moon
Very Stable Genius
https://gogolab.com/
woodslanding is offline   Reply With Quote
Old 10-18-2021, 08:37 AM   #17
noah1234j
Human being with feelings
 
Join Date: Jan 2021
Posts: 22
Default Help with element deletion

Hi Everyone, I'm trying to have a button that removes itself after a certain amount of time. It seems to remove its self property when it is clicked, but when triggered by the timer function it doesn't seem to update the UI. I believe I somehow need to trigger a UI redraw but am not sure of how ( I also might be looking in the wrong place). Any help would be greatly appreciated.

Code:
Code:
function remove_popup()
GUI.elms.popup:delete()
end

GUI.New("popup", "Button", {
    z = 1,
    x = 5.0,
    y = 260.0,
    w = 330,
    h = 40,
    caption = msg,
    font = 3,
    col_txt = "white",
    col_fill = "blue",
    func = remove_popup
})

time_start = reaper.time_precise()
reaper.ShowConsoleMsg("Starting a timer for 2 seconds...")

local function Main()
    local elapsed = reaper.time_precise() - time_start
    if elapsed >= 3 then
      remove_popup()
      reaper.ShowConsoleMsg("2 seconds have elapsed")
        return
    else
        reaper.defer(Main)
    end
end

Main()
noah1234j is offline   Reply With Quote
Old 10-18-2021, 10:31 AM   #18
solger
Human being with feelings
 
solger's Avatar
 
Join Date: Mar 2013
Posts: 5,844
Default

Adding this line should do the trick:
Code:
function remove_popup()
  GUI.elms.popup:delete()
  GUI.redraw_z[0] = true
end
Using redraw_z[0] (with value 'zero') redraws everything. It's also possible to redraw only specific z layers. More info here: https://github.com/jalovatt/Lokasenn.../4.02-Z-layers

EDIT:

Since the button in your example is on z layer 1 (z = 1), redrawing only z layer 1 should also work:
Code:
function remove_popup()
  GUI.elms.popup:delete()
  GUI.redraw_z[1] = true
end
__________________
ReaLauncher

Last edited by solger; 10-18-2021 at 10:38 AM.
solger is offline   Reply With Quote
Old 10-18-2021, 05:22 PM   #19
noah1234j
Human being with feelings
 
Join Date: Jan 2021
Posts: 22
Default

That's the ticket, thanks so much Solger. Very helpful as always.

Quote:
Originally Posted by solger View Post
Adding this line should do the trick:
Code:
function remove_popup()
  GUI.elms.popup:delete()
  GUI.redraw_z[0] = true
end
Using redraw_z[0] (with value 'zero') redraws everything. It's also possible to redraw only specific z layers. More info here: https://github.com/jalovatt/Lokasenn.../4.02-Z-layers

EDIT:

Since the button in your example is on z layer 1 (z = 1), redrawing only z layer 1 should also work:
Code:
function remove_popup()
  GUI.elms.popup:delete()
  GUI.redraw_z[1] = true
end
noah1234j is offline   Reply With Quote
Old 11-28-2021, 11:59 AM   #20
DrFrankencopter
Human being with feelings
 
Join Date: Jan 2011
Location: Ottawa, Canada
Posts: 293
Default Easy Q: How do I close the main window?

Hey Folks, just getting started with this cool GUI script and Lua scripting in general.

I've written my script and hooked it into a couple sliders and buttons. But for some reason I'm stuck on what I figured would be the easiest things:
1. I would like the Ok button to Close the GUI main window (as changes have already been applied)
2. I would like the main window "X" button to call a 'restore()' function and close the window

I have my various functions working. I can modify the Midi, and restore it. But I can't figure out how to interact with the main window.

I've tried setting 'GUI.quit = true' and it doesn't appear to do anything to the window.

I've been looking at the wiki and I see guidance on how to start the Gui, but not how to shut it down: https://github.com/jalovatt/Lokasenn...a-basic-script

Any help here would be much appreciated...
__________________
RME TotalMixFX Actions for Reaper here: https://stash.reaper.fm/v/29339/reape...MixOSC_x64.dll
DrFrankencopter is offline   Reply With Quote
Old 11-28-2021, 12:21 PM   #21
solger
Human being with feelings
 
solger's Avatar
 
Join Date: Mar 2013
Posts: 5,844
Default

Quote:
Originally Posted by DrFrankencopter View Post
1. I would like the Ok button to Close the GUI main window (as changes have already been applied)
...
I've tried setting 'GUI.quit = true' and it doesn't appear to do anything to the window.
Calling 'gfx.quit' afterwards should do the trick:
Code:
GUI.quit = true
gfx.quit()
Quote:
Originally Posted by DrFrankencopter View Post
2. I would like the main window "X" button to call a 'restore()' function and close the window
Try using the reaper.atexit function (https://www.extremraym.com/cloud/rea...oc/#lua_atexit):
Code:
reaper.atexit(function ()
 -- call your code or function(s) here
end)
__________________
ReaLauncher
solger is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 09:57 PM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.