Old 11-09-2019, 10:12 AM   #601
woodslanding
Human being with feelings
 
woodslanding's Avatar
 
Join Date: Mar 2007
Location: Denver, CO
Posts: 416
Default

Quote:
Originally Posted by Lokasenna View Post
The previous versions were all double quotes as well. As for why:
- IMO doubles make slightly more sense since single quotes/apostrophes are more likely to appear in a UI's text.
I think this is the best argument... sold.

Looks like there may be enough image support here for me to port my IControl class over to V3 without having to edit the base classes (which I did before). I'll submit it for your inspection when I get something working.
__________________
eric moon
Very Stable Genius
https://gogolab.com/
woodslanding is offline   Reply With Quote
Old 11-09-2019, 11:45 PM   #602
woodslanding
Human being with feelings
 
woodslanding's Avatar
 
Join Date: Mar 2007
Location: Denver, CO
Posts: 416
Default

I'm trying to figure out what the (...) syntax does in LUA. I'm searching on google, and it doesn't seem to be 'searchable'! Google turns nothing up for it.

Do you know where I might be able to read up on it?
__________________
eric moon
Very Stable Genius
https://gogolab.com/
woodslanding is offline   Reply With Quote
Old 11-10-2019, 12:24 AM   #603
cfillion
Human being with feelings
 
cfillion's Avatar
 
Join Date: May 2015
Location: Québec, Canada
Posts: 2,892
Default

They're called vararg functions: https://www.lua.org/manual/5.3/manual.html#3.4.11. The vararg expression ... (three dots) stores all extra parameters that were given to the function (it's not a table, more like functions with multiple return values).

Last edited by cfillion; 11-10-2019 at 12:46 AM.
cfillion is offline   Reply With Quote
Old 11-10-2019, 10:18 PM   #604
woodslanding
Human being with feelings
 
woodslanding's Avatar
 
Join Date: Mar 2007
Location: Denver, CO
Posts: 416
Default

Quote:
Originally Posted by cfillion View Post
They're called vararg functions: https://www.lua.org/manual/5.3/manual.html#3.4.11. The vararg expression ... (three dots) stores all extra parameters that were given to the function (it's not a table, more like functions with multiple return values).
Thanks! A lot of good information there about how arguments work.

I'm going to have to get my head around passing functions around. It's all new to me and makes my head spin a bit....

As an example, in 'working with images' I find:

Code:
if self:containsPoint(state.mouse.x, state.mouse.y) then

		self.func(table.unpack(self.params))
self.params here refers to func's self, is that right? Am I right in thinking that func as an argument to the control should be the function we want it to execute when the button is pressed?

I'm trying to imagine what syntax I would use to have the func parameter call an action that required the value of self.state as an argument... I've figured other ways to do that without func, (basically overriding the control's mouse methods with direct calls) but it seems like I'm missing the point. There is an easier way, correct?

Okay, searched in Knob.lua, and it looks like the func argument is not being used in this way there, so maybe I was mistaken. Is what I'm talking about above possible? or desirable?
__________________
eric moon
Very Stable Genius
https://gogolab.com/

Last edited by woodslanding; 11-10-2019 at 10:55 PM.
woodslanding is offline   Reply With Quote
Old 11-11-2019, 07:35 AM   #605
Lokasenna
Human being with feelings
 
Lokasenna's Avatar
 
Join Date: Sep 2008
Location: Calgary, AB, Canada
Posts: 6,475
Default

Quote:
Originally Posted by woodslanding View Post
Thanks! A lot of good information there about how arguments work.

I'm going to have to get my head around passing functions around. It's all new to me and makes my head spin a bit....

As an example, in 'working with images' I find:

Code:
if self:containsPoint(state.mouse.x, state.mouse.y) then

		self.func(table.unpack(self.params))
self.params here refers to func's self, is that right? Am I right in thinking that func as an argument to the control should be the function we want it to execute when the button is pressed?
self is just an argument; in this case self is the IButton. If you're used to something like Javascript's this, self isn't passed around the same way.

Quote:
I'm trying to imagine what syntax I would use to have the func parameter call an action that required the value of self.state as an argument... I've figured other ways to do that without func, (basically overriding the control's mouse methods with direct calls) but it seems like I'm missing the point. There is an easier way, correct?
I've just pushed an update for you. . User functions for Button, Menubar, and the IButton example in the image script all receive self as their first argument. i.e. when creating them you would use:
Code:
func = function(self, a, b, c) Msg(self.name, a, b, c) end,
params = {"a", "b", "c"}
Lokasenna is online now   Reply With Quote
Old 11-11-2019, 10:31 AM   #606
woodslanding
Human being with feelings
 
woodslanding's Avatar
 
Join Date: Mar 2007
Location: Denver, CO
Posts: 416
Default

oh, sweet, thanks!
__________________
eric moon
Very Stable Genius
https://gogolab.com/
woodslanding is offline   Reply With Quote
Old 11-13-2019, 10:36 AM   #607
reapero
Human being with feelings
 
Join Date: Aug 2011
Posts: 250
Default

Is it possible to set the inc paramter of the Slider class to something smaller than 1? I´d like to keep the range at 1 top at the beginning and inc something like 0,01, cause then i wouldnt need to do any math, should the user change the range of the fader.
reapero is offline   Reply With Quote
Old 11-13-2019, 10:38 AM   #608
Lokasenna
Human being with feelings
 
Lokasenna's Avatar
 
Join Date: Sep 2008
Location: Calgary, AB, Canada
Posts: 6,475
Default

Quote:
Originally Posted by reapero View Post
Is it possible to set the inc paramter of the Slider class to something smaller than 1? I´d like to keep the range at 1 top at the beginning and inc something like 0,01, cause then i wouldnt need to do any math, should the user change the range of the fader.
Yup. One of the sliders in the General Demonstration example has increments of 0.25:
Code:
GUI.New("my_sldr", 	"Slider",		4, 128, 256, 128, "Slider", 0, 10, 20, 0.25, "v")
Lokasenna is online now   Reply With Quote
Old 11-14-2019, 02:00 AM   #609
reapero
Human being with feelings
 
Join Date: Aug 2011
Posts: 250
Default

So how come this doesnt work? I kept the formatting that your GUI builder puked:

Code:
GUI.New("Offset", "Slider", {
    z = 11,
    x = 64.0,
    y = 340,
    w = 96,
    caption = "Offset",
    min = offset_min,
    max = offset_max,
    defaults = {0,0},
    inc = 0.1,
    dir = "h",
    font_a = 2,
    font_b = 4,
    col_txt = "txt",
    col_fill = "elm_fill",
    bg = "wnd_bg",
    show_handles = true,
    show_values = true,
    cap_x = 0,
    cap_y = 0
    
})
Offset_min is 0 and offset_max is 1. The slider goes straight from 0 to 1, no steps allowed.

Last edited by reapero; 11-14-2019 at 03:37 AM.
reapero is offline   Reply With Quote
Old 11-14-2019, 07:17 AM   #610
Lokasenna
Human being with feelings
 
Lokasenna's Avatar
 
Join Date: Sep 2008
Location: Calgary, AB, Canada
Posts: 6,475
Default

My bad; it wasn't picking up the inc parameter for elements created as a table. Pushing a fix up now.
Lokasenna is online now   Reply With Quote
Old 11-14-2019, 01:05 PM   #611
reapero
Human being with feelings
 
Join Date: Aug 2011
Posts: 250
Default

Thanks Loka. Working nicely now!
reapero is offline   Reply With Quote
Old 11-16-2019, 09:11 AM   #612
reapero
Human being with feelings
 
Join Date: Aug 2011
Posts: 250
Default

Ok, please bear with me. This is more like a SetExtState quetion but related to the usage of this GUI library somehow.

So i have set up this script with 10 sliders, most of them are double (table output). I want to create presets for the script, so i´d like to use ExtStates to store these settings. Now looking at the API:

Code:
reaper.SetExtState( section, key, value, persist )
Correct me if i am wrong but for this case this will turn out to be something like this:

reaper.SetExtState( "MY_PLUGIN", "PRESET_NUMBER_X", data, true)

That means i have to store A LOT of values in the "data" string. A lot like meaning every fader has its own max and min, its couple values if its a table, etc. That will probably become an ugly long string like "0,10,01,07,0,100,0,0,2,20,0...." separated by comma or space.

Is that the way to go here? Its going to be very hard for me to navigate thru this string to locate problems, cause i´ll probably forget what is what. I can create a function that separates this values and sends them into the right variables but even so, i wonder if i am just making things more complicated than they should.

thank you
reapero is offline   Reply With Quote
Old 11-16-2019, 02:25 PM   #613
Lokasenna
Human being with feelings
 
Lokasenna's Avatar
 
Join Date: Sep 2008
Location: Calgary, AB, Canada
Posts: 6,475
Default

Quote:
Originally Posted by reapero View Post
i wonder if i am just making things more complicated than they should.
Putting a bunch of values into one string and splitting them back out again is actually the most common way to do this.

If your presets are flat - that is, they don't have any nested tables - it's really easy:

Code:
-- Make sure the characters you use aren't in the data, or you'll have to add
-- some logic to hande them
local keyValueSeparator = "="
local fieldSeparator = "&"

local function hashToExtString(hash)
  local out = {}
  for k, v in pairs(hash) do
    out[#out + 1] = k .. keyValueSeparator .. v
  end
  return out.concat(fieldSeparator)
end

local function hashFromExtString(ext)
  local out = {}
  for pair in ext:gmatch("[^" .. fieldSeparator .. "]+") do
    local k, v = pair:match("(.+)=(.+)")

    if tonumber(v) then
      v = tonumber(v)
    elseif v == "true" then
      v = true
    elseif v == "false" then
      v = false
    end

    out[k] = v
  end

  return out
end


--------------------
-- To save:

local presets = {
  {
    name = "apple",
    min = 5,
    max = 10,
  },
  {
    name = "banana",
    min = 0,
    max = 3,
  },
  {
    name = "cherry",
    min = 2,
    max = 9,
  }
}

for i, preset in pairs(presets) do
  local extString = hashToExtString(preset)
  reaper.SetExtState("MY_PLUGIN", "PRESET_NUMBER_" .. i, extString, true)
end

--------------------
-- To load:

local presets = {}

for i = 1, NUMBER_OF_PRESETS do
  local extString = reaper.GetExtState("MY_PLUGIN", "PRESET_NUMBER_"..i)

  presets[i] = hashFromExtString(extString)
end
(Note: Don't have a chance to test this)

If you do have nested tables, it's a bit more work. Radial Menu stores its settings in a text file, and I found a function that writes all of the table contents as Lua code: https://github.com/ReaTeam/ReaScript...Menu.lua#L5000 . Loading them again is just a matter of reading in the file and telling Lua to execute it.
Lokasenna is online now   Reply With Quote
Old 11-23-2019, 08:29 AM   #614
Lokasenna
Human being with feelings
 
Lokasenna's Avatar
 
Join Date: Sep 2008
Location: Calgary, AB, Canada
Posts: 6,475
Default

Small update for v2:

- Fix: Checklists with only a single item couldn't be set to false via GUI.Val("MyChecklist", false)

- Added documentation about Checklists' alternate behaviour with only one element

- Removed the HTML documentation from the Developer Tools package; I don't have the script that generates it from the wiki installed, and it's just one more thing I have to remember to do any time I want to update the docs.

The project wiki is now the sole source of documentation.
Lokasenna is online now   Reply With Quote
Old 11-29-2019, 08:24 AM   #615
reapero
Human being with feelings
 
Join Date: Aug 2011
Posts: 250
Default

I am trying to populate a menubox with presets that are actually keys on a given section of a the exts-state.ini file. So the latest options of the opts parameter need to be given programtically.

After getting the keynames from Extsate i end up with a string like this:

Code:
preset_list = '"preset1","preset2","preset3"'

GUI.New("Preset_menubox", "Menubox", {
    z = 11,
    x = 500,
    y = 128,
    w = 128,
    h = 20,
    caption = "",
    optarray = {"PRESETS...","Save","Delete",">Load", preset_list },

This doesnt create 3 options at the end but just a long one with all the quotes. I guess this was a very dirty approach...

Is there anything i can do?
reapero is offline   Reply With Quote
Old 11-29-2019, 09:23 AM   #616
Lokasenna
Human being with feelings
 
Lokasenna's Avatar
 
Join Date: Sep 2008
Location: Calgary, AB, Canada
Posts: 6,475
Default

Try this:
Code:
optarray = table.pack("PRESETS...","Save","Delete",">Load", table.unpack(preset_list)),
table.unpack dumps the contents of a table out as multiple return values, and table.pack takes all of its arguments and puts them into a new table.

By unpacking a table in a function call, all of the table elements are passed as separate function arguments.
Lokasenna is online now   Reply With Quote
Old 11-29-2019, 10:37 AM   #617
reapero
Human being with feelings
 
Join Date: Aug 2011
Posts: 250
Default

Nice! Thanks

EDIT: Allright now i need to rebuid the menubox during the main loop, so that it reflects the newly created presets. I tried with the :redraw method but the GUI doesn't update.

Can this be done? Cheers

Last edited by reapero; 11-29-2019 at 11:01 AM.
reapero is offline   Reply With Quote
Old 11-29-2019, 02:39 PM   #618
babag
Human being with feelings
 
Join Date: Nov 2009
Posts: 1,704
Default

Quote:
Originally Posted by Lokasenna View Post
Have a look at the Menubar class - it has to do the same thing for drawing the green hover indicator.

onmouseover turns the indicator on: https://github.com/jalovatt/Lokasenn...nubar.lua#L275
onupdate checks if it should be turned off: https://github.com/jalovatt/Lokasenn...nubar.lua#L232
i just tried copying these two functions into my toolbar code, just above the local 'function btn_click(command)' line, and loading the menubar class. the toolbar does run but nothing happens on hovering over the various buttons. i'm guessing something needs to be added into the functions to tell them to change color? not sure how or where to do that.

thanks,
babag

Last edited by babag; 11-29-2019 at 02:48 PM.
babag is offline   Reply With Quote
Old 11-29-2019, 03:53 PM   #619
Lokasenna
Human being with feelings
 
Lokasenna's Avatar
 
Join Date: Sep 2008
Location: Calgary, AB, Canada
Posts: 6,475
Default

Post the whole script (or put it on Dropbox and post a link)?
Lokasenna is online now   Reply With Quote
Old 11-29-2019, 03:56 PM   #620
Lokasenna
Human being with feelings
 
Lokasenna's Avatar
 
Join Date: Sep 2008
Location: Calgary, AB, Canada
Posts: 6,475
Default

Quote:
Originally Posted by reapero View Post
Nice! Thanks

EDIT: Allright now i need to rebuid the menubox during the main loop, so that it reflects the newly created presets. I tried with the :redraw method but the GUI doesn't update.

Can this be done? Cheers
Can't test right now, but I believe this should work:
Code:
GUI.elms.myMenubox.optarray = aNewArray
GUI.elms.myMenubox:redraw()
No?
Lokasenna is online now   Reply With Quote
Old 11-29-2019, 07:23 PM   #621
D Rocks
Human being with feelings
 
Join Date: Dec 2017
Location: Quebec, Canada
Posts: 544
Default

I'd warmly welcome ReaPlugs to look like this!
__________________
Alex | www.drocksrecords.com | Thanks for REAPER
D Rocks is online now   Reply With Quote
Old 11-30-2019, 11:06 AM   #622
babag
Human being with feelings
 
Join Date: Nov 2009
Posts: 1,704
Default

thanks, lokasenna. the code below throws an error at line 237:

Code:
-- NoIndex: true

-- Makes an 8 x 8 grid of buttons user can put actions into.
-- Grid can be modified by editing User Options section to get the desired grid size.
-- Script was made to solve problem of Reaper floating toolbar rearranging buttons if window was resized by accident or otherwise.

-- The Core library must be loaded prior to anything else

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 run 'Script: Set Lokasenna_GUI v2 library path.lua' in your Action List.", "Whoops!", 0)
    return
end
loadfile(lib_path .. "Core.lua")()


GUI.req("Classes/Class - Button.lua")()
GUI.req("Classes/Class - Menubar.lua")()


-- If any of the requested libraries weren't found, abort the script.
if missing_lib then return 0 end


------------------------------------
-------- USER OPTIONS --------------
------------------------------------

local button_width      = 58    -- Set your button width  here
local button_height     = 28    -- Set your button height here
local buttons_per_row   = 8     -- Set how many buttons you want in each row here 
local button_h_spacer   = 3     -- Set how much horizontal space between buttons here
local button_v_spacer   = 2     -- Set how much vertical   space between buttons here


------------------------------------
-------- Functions  ----------------
------------------------------------

function GUI.Menubar:onmouseover()

    local opt = self.mousemnu

    local x = GUI.mouse.x - self.x

    if  self.mousemnu_x and x > self:measuretitles(nil, true) then

        self.mousemnu = nil
        self.mousemnu_x = nil
        self:redraw()

        return

    end


    -- Iterate through the titles by overall width until we
    -- find which one the mouse is in.
    for i = 1, #self.menus do

        if x <= self:measuretitles(i, true) then

            self.mousemnu = i
            self.mousemnu_x = self:measuretitles(i - 1, true)

            if self.mousemnu ~= opt then self:redraw() end

            return
        end

    end

end

function GUI.Menubar:onupdate()

    if self.mousemnu and not GUI.IsInside(self, GUI.mouse.x, GUI.mouse.y) then
        self.mousemnu = nil
        self.mousemnu_x = nil
        self:redraw()

        -- Skip the rest of the update loop for this elm
        return true
    end

end

local function btn_click(command)
	
	-- Be nice, give the user an Undo point
	reaper.Undo_BeginBlock()
	
    reaper.Main_OnCommand(reaper.NamedCommandLookup(command), 0)
    
	reaper.Undo_EndBlock("Toolbar Grid Template", 0)	
    
    -- Exit the script on the next update
	GUI.quit = false
	
end


------------------------------------
-------- GUI Elements --------------
------------------------------------

local elms = {}

-- Define your buttons below.

-- Copy, delete, or comment out label/command lines below to get the number of buttons you want.
        
-- Label field is for text that will be displayed on the the button.
-- Example: label = "PLAY\n130%",
-- Note that the \n causes a line break and will display the text on two lines.

-- Command field is for the command ID from the actions list.
-- Example 1: command = 65535
-- Example 2: command = "_eed3041ab48a593fcd3909218c058b46"
-- Note that example 1 has no quotes as it is a native Reaper action.
-- Note that example 2 has quotes as it is a custom action.
-- Note that command = 65535 can be used as a spacer. It is a "no-op" action.
-- Text can still be displayed even if the button is a "no-op" action.

local toolbar_buttons = {
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
}


------------------------------------
-------- Window settings -----------
------------------------------------

for k in ipairs(toolbar_buttons) do

    total_buttons = k
    
end    
    
local button_rows = (total_buttons / buttons_per_row)
local gui_w       = (button_width * buttons_per_row) + ((buttons_per_row - 1) * button_h_spacer)
local gui_h       = (button_height * button_rows) + ((button_rows - 1) * button_v_spacer)

GUI.name = "TOOLBAR GRID TEMPLATE"
--GUI.x, GUI.y, GUI.w, GUI.h = 0, 0, 972, 240
GUI.x, GUI.y, GUI.w, GUI.h = 0, 0, gui_w, gui_h
--GUI.x, GUI.y, GUI.w, GUI.h = 0, 0, gui_w, 208
GUI.anchor, GUI.corner = "mouse", "C"


------------------------------------
-------- GUI Elements cont. --------
------------------------------------

local buttons_count     = -1    -- Leave this one alone or screwy things will happen

for k, v in ipairs(toolbar_buttons) do
  if row_buttons   == (buttons_per_row - 1) then    -- Set conditions for switching to a new row
      row_buttons   = 0
  else
      buttons_count = (buttons_count + 1)
  end

  elms["button_"..k] = {
    type = "Button",
    col_fill = {.2,.2,.2},
    z = (#toolbar_buttons - k) + 1,
    x = ((k - 1) % buttons_per_row) * (button_width + button_h_spacer),
    y = math.floor((k - 1) / buttons_per_row) *  (button_height + button_v_spacer),
    w = button_width,
    h = button_height,
    caption = v.label,
    func = GUI.Menubar.onmouseover,
    func = GUI.Menubar:onupdate(col_fill = {.2,.8,.2}),
    func = btn_click,
    params = {v.command},       -- Send command parameter to the btn_click function so that it will accept a variable.
    tooltip = "I'm a button"
  }

end

GUI.CreateElms(elms)


GUI.Init()
GUI.Main()
all i've done is to add the two menubar functions in the 'functions' section near the top and then to add calls for them in the gui elements section near the end, the second with a color option. that's the line that throws the error.

edit:
oh, yeah, at the beginning added the menubar class.

thanks for looking at this,
babag
babag is offline   Reply With Quote
Old 11-30-2019, 03:42 PM   #623
Lokasenna
Human being with feelings
 
Lokasenna's Avatar
 
Join Date: Sep 2008
Location: Calgary, AB, Canada
Posts: 6,475
Default

- You can't use the Menubar code as-is because it's specifically written for the Menubar class - it references other properties and methods that the Button class won't have, and does things you don't need a Button to do.

- It's throwing an error because you can't pass a statement (col_fill = {.2,.8,.2}) as a function argument.

- You can't have more than one func = ___ - Lua will just overwrite the previous ones.

- func is also specifically for handling Button clicks; you have to specifically override the button's other methods.

This should do the trick. I've added a table, ToolbarButton, with the replacement button methods, and then assigned them to each button as it gets created.

Code:
-- NoIndex: true

-- Makes an 8 x 8 grid of buttons user can put actions into.
-- Grid can be modified by editing User Options section to get the desired grid size.
-- Script was made to solve problem of Reaper floating toolbar rearranging buttons if window was resized by accident or otherwise.

-- The Core library must be loaded prior to anything else

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 run 'Script: Set Lokasenna_GUI v2 library path.lua' in your Action List.", "Whoops!", 0)
    return
end
loadfile(lib_path .. "Core.lua")()

GUI.req("Classes/Class - Button.lua")()

-- If any of the requested libraries weren't found, abort the script.
if missing_lib then return 0 end


------------------------------------
-------- USER OPTIONS --------------
------------------------------------

local button_width      = 58    -- Set your button width  here
local button_height     = 28    -- Set your button height here
local buttons_per_row   = 8     -- Set how many buttons you want in each row here
local button_h_spacer   = 3     -- Set how much horizontal space between buttons here
local button_v_spacer   = 2     -- Set how much vertical   space between buttons here


------------------------------------
-------- Functions  ----------------
------------------------------------


local function btn_click(command)

	-- Be nice, give the user an Undo point
	reaper.Undo_BeginBlock()

    reaper.Main_OnCommand(reaper.NamedCommandLookup(command), 0)

	reaper.Undo_EndBlock("Toolbar Grid Template", 0)

    -- Exit the script on the next update
	GUI.quit = false

end


------------------------------------
-------- GUI Elements --------------
------------------------------------

local elms = {}

-- Define your buttons below.

-- Copy, delete, or comment out label/command lines below to get the number of buttons you want.

-- Label field is for text that will be displayed on the the button.
-- Example: label = "PLAY\n130%",
-- Note that the \n causes a line break and will display the text on two lines.

-- Command field is for the command ID from the actions list.
-- Example 1: command = 65535
-- Example 2: command = "_eed3041ab48a593fcd3909218c058b46"
-- Note that example 1 has no quotes as it is a native Reaper action.
-- Note that example 2 has quotes as it is a custom action.
-- Note that command = 65535 can be used as a spacer. It is a "no-op" action.
-- Text can still be displayed even if the button is a "no-op" action.

local toolbar_buttons = {
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
  { label = "",                   command = 65535 },
}


------------------------------------
-------- Window settings -----------
------------------------------------

for k in ipairs(toolbar_buttons) do

    total_buttons = k

end

local button_rows = (total_buttons / buttons_per_row)
local gui_w       = (button_width * buttons_per_row) + ((buttons_per_row - 1) * button_h_spacer)
local gui_h       = (button_height * button_rows) + ((button_rows - 1) * button_v_spacer)

GUI.name = "TOOLBAR GRID TEMPLATE"
--GUI.x, GUI.y, GUI.w, GUI.h = 0, 0, 972, 240
GUI.x, GUI.y, GUI.w, GUI.h = 0, 0, gui_w, gui_h
--GUI.x, GUI.y, GUI.w, GUI.h = 0, 0, gui_w, 208
GUI.anchor, GUI.corner = "mouse", "C"


------------------------------------
-------- GUI Elements cont. --------
------------------------------------


local ToolbarButton = {}

function ToolbarButton:onupdate()
  if self.hovered and not GUI.IsInside(self, GUI.mouse.x, GUI.mouse.y) then
    self.hovered = false
    self:redraw()

    -- Skip the rest of the update loop for this elm
    return true
  end
end

function ToolbarButton:onmouseover()
  if not self.hovered then
    self.hovered = true
    self:redraw()
  end
end

function ToolbarButton:draw()
  GUI.Button.draw(self)

  if self.hovered then
    GUI.color({1, 1, 1, 0.1})
    gfx.rect(self.x + 1 + 2 * self.state, self.y + 1 + 2 * self.state, self.w - 2, self.h - 2)
    gfx.a = 1
  end
end


local buttons_count     = -1    -- Leave this one alone or screwy things will happen

for k, v in ipairs(toolbar_buttons) do
  if row_buttons   == (buttons_per_row - 1) then    -- Set conditions for switching to a new row
      row_buttons   = 0
  else
      buttons_count = (buttons_count + 1)
  end

  elms["button_"..k] = {
    type = "Button",
    col_fill = {.2,.2,.2},
    z = (#toolbar_buttons - k) + 1,
    x = ((k - 1) % buttons_per_row) * (button_width + button_h_spacer),
    y = math.floor((k - 1) / buttons_per_row) *  (button_height + button_v_spacer),
    w = button_width,
    h = button_height,
    caption = v.label,
    func = btn_click,
    params = {v.command},       -- Send command parameter to the btn_click function so that it will accept a variable.
    tooltip = "I'm a button",
    onupdate = ToolbarButton.onupdate,
    onmouseover = ToolbarButton.onmouseover,
    draw = ToolbarButton.draw,
  }

end

GUI.CreateElms(elms)


GUI.Init()
GUI.Main()
This is one of the many things that will be easier to do in v3 - each event can have a before___ or after___ function attached to it rather than having to override the event method itself.
Lokasenna is online now   Reply With Quote
Old 11-30-2019, 04:03 PM   #624
babag
Human being with feelings
 
Join Date: Nov 2009
Posts: 1,704
Default

hey, thanks! i'd have never figured that out. :-P

looks like in the 'function ToolbarButton:draw()' there is a line:
Code:
GUI.color({1, 1, 1, 0.1})
that seems to control the mouseover brightness. i tried changing .1 to .5 and it gets much lighter. is there a way to apply color, maybe something like giving rgb values in parentheses or something? or does that asdd a whole new complication?

thanks again,
babag
babag is offline   Reply With Quote
Old 11-30-2019, 04:20 PM   #625
Lokasenna
Human being with feelings
 
Lokasenna's Avatar
 
Join Date: Sep 2008
Location: Calgary, AB, Canada
Posts: 6,475
Default

Quote:
Originally Posted by babag View Post
hey, thanks! i'd have never figured that out. :-P

looks like in the 'function ToolbarButton:draw()' there is a line:
Code:
GUI.color({1, 1, 1, 0.1})
that seems to control the mouseover brightness. i tried changing .1 to .5 and it gets much lighter. is there a way to apply color, maybe something like giving rgb values in parentheses or something? or does that asdd a whole new complication?

thanks again,
babag
Those values are Red, Green, Blue, Alpha - just from 0 to 1 instead of 0 to 255.

Note that we do have to reset the alpha to 1 afterward (gfx.a = 1) or it will mess up drawing subsequent buttons.
Lokasenna is online now   Reply With Quote
Old 11-30-2019, 04:30 PM   #626
babag
Human being with feelings
 
Join Date: Nov 2009
Posts: 1,704
Default

cool! thanks!
babag is offline   Reply With Quote
Old 12-02-2019, 09:01 AM   #627
reapero
Human being with feelings
 
Join Date: Aug 2011
Posts: 250
Default

Quote:
Originally Posted by Lokasenna View Post
Can't test right now, but I believe this should work:
Code:
GUI.elms.myMenubox.optarray = aNewArray
GUI.elms.myMenubox:redraw()
No?
YES! Thx
reapero is offline   Reply With Quote
Old 12-09-2019, 08:36 AM   #628
deeb
Human being with feelings
 
deeb's Avatar
 
Join Date: Feb 2017
Posts: 2,497
Default

Lokasenna! any idea when V3 will be released?
deeb is offline   Reply With Quote
Old 12-09-2019, 09:14 AM   #629
Lokasenna
Human being with feelings
 
Lokasenna's Avatar
 
Join Date: Sep 2008
Location: Calgary, AB, Canada
Posts: 6,475
Default

Quote:
Originally Posted by deeb View Post
Lokasenna! any idea when V3 will be released?
When the items on my to-do list are either done or I decide they aren't important: https://github.com/jalovatt/scythe/i...223.0+Alpha%22

Documentation is the big one, but I'm struggling to stay motivated on it. I've got a system set up to automatically generate documentation (Preview here) for the new modules but I can't come up with an effective way to do the same for the element classes.

Between that, and Christmas, and Advent of Code... not sure. Maybe early January?
Lokasenna is online now   Reply With Quote
Old 12-09-2019, 09:29 AM   #630
deeb
Human being with feelings
 
deeb's Avatar
 
Join Date: Feb 2017
Posts: 2,497
Default

Quote:
Originally Posted by Lokasenna View Post
When the items on my to-do list are either done or I decide they aren't important: https://github.com/jalovatt/scythe/i...223.0+Alpha%22

Documentation is the big one, but I'm struggling to stay motivated on it. I've got a system set up to automatically generate documentation (Preview here) for the new modules but I can't come up with an effective way to do the same for the element classes.

Between that, and Christmas, and Advent of Code... not sure. Maybe early January?
so it will be named "scythe"?

"but I'm struggling to stay motivated on it"
UP UP but you always first !

"but I can't come up with an effective way to do the same for the element classes."

Maybe mesopotine or someone else could give an insight?


I think i will start doing a new thing on V2.. and eventually port to v3 later.

Not wanting to push or anything at all, but i wonder if you plan to Plan more then 1 column for ListView?
example:
Title | Author | Age | Action | Slider | Button | ^ScrollBar^

Last edited by deeb; 12-09-2019 at 09:46 AM.
deeb is offline   Reply With Quote
Old 12-09-2019, 09:53 AM   #631
Lokasenna
Human being with feelings
 
Lokasenna's Avatar
 
Join Date: Sep 2008
Location: Calgary, AB, Canada
Posts: 6,475
Default

Quote:
Originally Posted by deeb View Post
so it will be named "scythe"?
Yup. With the additional non-GUI modules it includes I felt a name change was appropriate, and it's a good opportunity to make a Reaper pun.

Quote:
I think i will start doing a new thing on V2.. and eventually port to v3 later.
Fair enough. I would suggest using the table syntax for creating your elements though, since v3 only uses that. i.e.
Code:
GUI.New("thing", "Button", {
  x = 1,
  y = 2,
  ...
})
Quote:
Not wanting to push or anything at all, but i wonder if you plan to Plan more then 1 column for ListView?
example:
Title | Author | Age | Action | Slider | Button | ^ScrollBar^
I hadn't thought of it, but I'll add that to my list of ideas.
Lokasenna is online now   Reply With Quote
Old 12-09-2019, 09:54 AM   #632
deeb
Human being with feelings
 
deeb's Avatar
 
Join Date: Feb 2017
Posts: 2,497
Default

Just experienced this and reminder to just say: Would be nice if "lokasenna" or "FrameworkName" would be in examples files names so that when searching in actions they gets easily found.

deeb is offline   Reply With Quote
Old 12-09-2019, 10:42 AM   #633
Lokasenna
Human being with feelings
 
Lokasenna's Avatar
 
Join Date: Sep 2008
Location: Calgary, AB, Canada
Posts: 6,475
Default

I'll think about it.
Lokasenna is online now   Reply With Quote
Old 12-11-2019, 04:35 PM   #634
woodslanding
Human being with feelings
 
woodslanding's Avatar
 
Join Date: Mar 2007
Location: Denver, CO
Posts: 416
Default

your tiny tip of the 'searching for actions' iceberg....

We need a google search type algorithm for finding actions.... or the ability to assign them a bunch of search key words!
__________________
eric moon
Very Stable Genius
https://gogolab.com/
woodslanding is offline   Reply With Quote
Old 12-11-2019, 07:49 PM   #635
MusoBob
Human being with feelings
 
MusoBob's Avatar
 
Join Date: Sep 2014
Posts: 1,177
Default

Is there a way of scaling up the GUI and Radial Menu for HiDPI-Screens ?
__________________
ReaTrakStudio Chord Track for Reaper forum
www.reatrak.com
MusoBob is online now   Reply With Quote
Old 12-11-2019, 09:23 PM   #636
Lokasenna
Human being with feelings
 
Lokasenna's Avatar
 
Join Date: Sep 2008
Location: Calgary, AB, Canada
Posts: 6,475
Default

Quote:
Originally Posted by MusoBob View Post
Is there a way of scaling up the GUI and Radial Menu for HiDPI-Screens ?
Not at the moment, but definitely worth looking into.

- It looks like I can use retval, name = reaper.ThemeLayout_GetLayout("mcp", -3) to get the DPI context (256 on a regular monitor, 512 on Retina).

- I... think?... it would just require intercepting any references to screen coordinates or pixel sizes and doubling them. Does that make sense? A lot of work and refactoring, but at least straightforward if that's the case.
Lokasenna is online now   Reply With Quote
Old 12-12-2019, 01:34 AM   #637
MusoBob
Human being with feelings
 
MusoBob's Avatar
 
Join Date: Sep 2014
Posts: 1,177
Default

Yes that's what I thought would be a way to do it.
I was going to try it with a slider to add/subtract from the size and co-ordinates but then you have to do a ondelete() and init() to refresh the elements ????
__________________
ReaTrakStudio Chord Track for Reaper forum
www.reatrak.com
MusoBob is online now   Reply With Quote
Old 12-12-2019, 07:28 AM   #638
Lokasenna
Human being with feelings
 
Lokasenna's Avatar
 
Join Date: Sep 2008
Location: Calgary, AB, Canada
Posts: 6,475
Default

For dynamic scaling, yeah. If you only needed to support either regular or HiDPI and nothing in between that becomes much easier because it can be a global wrapper for init that tells all of the elements to do it.

At any rate, v3 is probably a better place to test stuff like this since it's been refactored and tidied so much. If and when we figure out a good solution, I can look at back-porting it to v2.
Lokasenna is online now   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 03:12 PM.


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