Go Back   Cockos Incorporated Forums > REAPER Forums > ReaScript, JSFX, REAPER Plug-in Extensions, Developer Forum

Reply
 
Thread Tools
Old 07-25-2021, 07:51 AM   #1
tack
Human being with feelings
 
tack's Avatar
 
Join Date: Jan 2014
Location: Ontario, Canada
Posts: 1,639
Default REAPER Toolkit - a GUI and utility library for Lua scripts

Hello REAPER scripters,

I'm happy to announce a new library called the REAPER Toolkit (rtk), a GUI and utility library for REAPER Lua scripts, which leverages REAPER's native GFX API without any external dependencies.

rtk is born out of the underlying GUI code that powers Reaticulate. I had invested so much time into it that I felt it deserved to be released as an independent library.

Visit the project website for documentation and download instructions:

https://reapertoolkit.dev


What does it look like?

rtk was originally written for Reaticulate, which is shown below to serve as a demonstration of rtk's capabilities.



This short screen capture demonstrates several of rtk's features, including:
  • Touch screen support
  • Adjustable global zoom level
  • Borderless windows
  • Widget animation subsystem
  • Drag-and-drop events
  • And of course various widgets (buttons, text inputs, option menus, checkboxes, etc.)

How does it differ from Scythe (Lokasenna GUI v3)?

I suspect this will be a FAQ, so I'll address it here.

The core of rtk was written for Reaticulate many years ago so I'm afraid I've not actually used Scythe before. But based on my perusal of Scythe's documentation, I see these key differences:
  • Scythe uses a fixed coordinate system, while rtk uses dynamic and scalable layouts via containers and a CSS-like box model
  • Due to the above, Scythe is smaller and probably performs better (as dynamically calculating layouts obviously brings some overhead)
  • Scythe has more widgets (rtk will develop more as the project matures, but Scythe is further ahead)
  • rtk has more core features, such as enhanced window management (via js_ReaScriptAPI), drag-and-drop, animation, and a rich widget API and event system
  • rtk has significantly better documentation
  • rtk supports both light and dark themes, and auto-selects based on REAPER's theme to provide a more integrated aesthetic
  • rtk supports both installation by ReaPack or integration and redistribution by script authors

Like Lokasenna, I wrote my own Lua API doc generation tool (clearly we both recognized how terrible the state of the union was ). LuaDox is available as a separate project.

What's Next

First and foremost, I am very interested to hear from you folks what you think. Your opinions will certainly help to influence rtk's direction.

As of 2022-02-18, the API is considered stable, and there is a documented process that allows for introducing breaking API changes while also not impacting existing scripts.

On the subject of widgets, these will be coming soon, mainly because I will need them for Reaticulate (and its infamous any-day-now-honest articulation map GUI editor):
  • ComboBox (text entry plus selection list)
  • Slider
  • RadioButton

If you have a feature request, feel free to ask here or open an issue on GitHub (or both).


So head on over to rtk's website, sift through the tutorial, take rtk out for a spin, and let me know what you think.

Happy hacking!

Last edited by tack; 02-28-2022 at 05:27 PM.
tack is offline   Reply With Quote
Old 07-25-2021, 10:35 AM   #2
Edgemeal
Human being with feelings
 
Edgemeal's Avatar
 
Join Date: Apr 2016
Location: ASU`ogacihC
Posts: 4,138
Default

I couldn't even get past the first line of the introduction example without errors LOL! I have no clue what 'pagage.path' is but after some searching I found an example, not sure if its correct way but the window with button now opens and seems to work. THANKS for sharing!

Code:
-- Test.lua (in same folder as rtk.lua)
--
local path = ({reaper.get_action_context()})[2]:match('^.+[\\//]')
package.path = path .. '/?.lua' 
local rtk = require('rtk')
...

Last edited by Edgemeal; 07-25-2021 at 10:45 AM. Reason: removed [[ ]] brackets from "/?.lua" still works
Edgemeal is offline   Reply With Quote
Old 07-25-2021, 10:43 AM   #3
tack
Human being with feelings
 
tack's Avatar
 
Join Date: Jan 2014
Location: Ontario, Canada
Posts: 1,639
Default

Quote:
Originally Posted by Edgemeal View Post
I couldn't even get past the first line of the introduction example without errors LOL! I have no clue what 'pagage.path' is but after some searching I found an example, not sure if its correct way but the window with button now opens and seems to work.
The tutorial covers this in more detail:

https://reapertoolkit.dev/manual/tut...ng_the_library

I will move that to the Hello World example on the front page too, to ensure it's copy-pastable.

Thanks for the feedback!
tack is offline   Reply With Quote
Old 07-25-2021, 01:56 PM   #4
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 11,131
Default

Looks like a very solid framework, and also a very solid documentation generator, well done and thanks for sharing !
Also, written all this doc for all this tools... that is kind of a hard passionate work !



One other major thing to add to your framework is that it si currently supported, which scythe is not anymore (lokasenna left the boat for an undetermined amount of time).


We have been spoiled with nice GUI framemork with cfillion ReaImGui extension these days, and now yours :P


I would say that focusing on what ReaImGui can't do would make sense. Scalable text is one of them as far as know. Your box approach CSS like system seems promising.


Anyway, I think the priority is to add screenshots to the doc. This would help us a lot to see what we can expect, what we can do etc.

Also, I think making the examples reapack compatible could make sense so we can try out of the box.


Though I'm curious about distribution model:



Quote:
Scythe is installed in a central location which all scripts use, while rtk is bundled as a single file and relies on script authors to distribute it with their scripts

So how do we keep up to date version of rtk ? Does this means than any fix you made have to been pushed by other scripters too ?
I think centralized distribution like scythe or reaimgui are quite interesting cause if the extension got a fixed, than all script depending on them will got one.
But I guess a scripter could have his own instance of rtk, used by all his script ?



Anyway, thanks for all. That is for sure a lot to explore!

PS: maybe even a scripting video from scratch could be nice at this point. :P
X-Raym is offline   Reply With Quote
Old 07-25-2021, 02:33 PM   #5
daniellumertz
Human being with feelings
 
daniellumertz's Avatar
 
Join Date: Dec 2017
Location: Brazil
Posts: 2,118
Default

Hey tack thanks for releasing this. I always liked the reaticulate GUI, nice we can use it now uhu!

Last edited by daniellumertz; 04-03-2023 at 10:08 AM.
daniellumertz is offline   Reply With Quote
Old 07-25-2021, 02:49 PM   #6
tack
Human being with feelings
 
tack's Avatar
 
Join Date: Jan 2014
Location: Ontario, Canada
Posts: 1,639
Default

Quote:
Originally Posted by X-Raym View Post
Looks like a very solid framework, and also a very solid documentation generator, well done and thanks for sharing ! Also, written all this doc for all this tools... that is kind of a hard passionate work !
Thanks! Yes, the documentation was a shocking amount of work. But it's always a good exercise as writing docs shakes out quite a lot of janky and half-baked stuff.


Quote:
Originally Posted by X-Raym View Post
I would say that focusing on what ReaImGui can't do would make sense. Scalable text is one of them as far as know. Your box approach CSS like system seems promising.
I think there will inevitably be a nontrivial amount of overlap just because they aim to accomplish similar things. But there are certainly enough differences to justify both projects. And at least to me ImGui aesthetically reminds me of Unix GUIs from the early 90s (and not in the nice nostalgic way). But I bet it's fast as balls.


Quote:
Originally Posted by X-Raym View Post
Anyway, I think the priority is to add screenshots to the doc. This would help us a lot to see what we can expect, what we can do etc.
Definitely. The docs do have screenshots for rtk.Button, rtk.OptionMenu, rtk.Application, and visualizations of some of the container types, but there are a few gaps to flesh out for sure.


Quote:
Originally Posted by X-Raym View Post
Also, I think making the examples reapack compatible could make sense so we can try out of the box.
That's a fine idea, but I first need to write some better, more comprehensive demos.


Quote:
Originally Posted by X-Raym View Post
So how do we keep up to date version of rtk ? Does this means than any fix you made have to been pushed by other scripters too? I think centralized distribution like scythe or reaimgui are quite interesting cause if the extension got a fixed, than all script depending on them will got one. But I guess a scripter could have his own instance of rtk, used by all his script ?
I have been and continue to be wrestling with this one.

Having a single installation that all scripts use imposes strict requirements on API stability. It simply won't do to have an rtk update break even a single script. I'm not at the stage yet where I can claim the API is stable. To be clear, I don't have any breaking changes planned, but it's only ever been my eyeballs on this thing, so I'd want to get a bunch more feedback before I make a commitment to not making breaking changes.

So having script authors distribute the version of rtk they have developed and tested against in their ReaPacks seems like a reasonable compromise. It mitigates the risk of changes (which could include bug fixes, if the buggy behavior was actually relied upon) made outside the script author's control negatively affecting their scripts. I've tried to make this process relatively simple by bundling the entirety of rtk into one file for distribution.

But I am receptive to arguments on this one. And as I gain more confidence with the API's stability I can see myself introducing a centralized distribution via ReaPack, giving script writers the option of whether to bundle their own copy or use the central one.


Quote:
Originally Posted by X-Raym View Post
PS: maybe even a scripting video from scratch could be nice at this point. :P
I'm definitely game for that. I think I'd wait and see what some of the initial questions, confusions, and pain points are with getting started so I'd have a better idea what to focus on. At this point I'm probably a little too disconnected from how other developers will approach it.

Thanks for your feedback X-Raym, I really appreciate it.
tack is offline   Reply With Quote
Old 07-25-2021, 03:46 PM   #7
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 11,131
Default

@tack
Thanks for your detailed feedback! And nice to see such responsiveness to feedbacks



For distribution, the good thing about having a centralized way is that it can be forked if necessary anyway , and use as if if not needed.


One other question: what have you done for accessibility? tab/maj tab navigation focus between items with enter key to validate a button for eg ?


@daniellumertz
To not go off topic on this thread too much, I have made a doc file with available library. You will be surprise by the first one (it is note the one you are thinking about!) :P
X-Raym is offline   Reply With Quote
Old 07-25-2021, 03:55 PM   #8
tack
Human being with feelings
 
tack's Avatar
 
Join Date: Jan 2014
Location: Ontario, Canada
Posts: 1,639
Default

Quote:
Originally Posted by X-Raym View Post
One other question: what have you done for accessibility? tab/maj tab navigation focus between items with enter key to validate a button for eg ?
Yeah, keyboard navigation is a weak spot. (Funny you mention it, I opened an issue last night to track that, as I gradually convert my internal to-list to GH issues.)

Reaticulate implements keyboard selection and activation of articulations at the application level, but keyboard navigation ought to be better supported in the core.

I don't think it would be too hard to implement but being able to allow the user to customize tab focus order needs some consideration.


Quote:
Originally Posted by X-Raym View Post
To not go off topic on this thread too much, I have made a doc file with available library.
Cool, thanks for putting that together. rtk's link goes to the wrong thread though.
tack is offline   Reply With Quote
Old 07-25-2021, 10:04 PM   #9
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 11,131
Default

@tack
Link fixed!


For Scythe, I managed to make a focus system with tab navigation and keyboard offset (and even ctrl+keyboard, relevant for sliders).

It is simply based on a ID number for the elements and didnt required to mod it.

Maybe it doesnt need to be built-in as long as the object property are flexible enough to be able to hook them like that. This would need to be tested in practice to be sure I guess


As extra precision I think the first thread should mentioned that this framework is GFX based and has not his own custom render engine (which would be a big diff against ReaImGui for eg). 😊
X-Raym is offline   Reply With Quote
Old 07-26-2021, 06:58 AM   #10
tack
Human being with feelings
 
tack's Avatar
 
Join Date: Jan 2014
Location: Ontario, Canada
Posts: 1,639
Default

Quote:
Originally Posted by X-Raym View Post
It is simply based on a ID number for the elements and didnt required to mod it.
For rtk I would just do a depth first traversal of the widget hierarchy, and that's probably good enough for 99% of use cases. Maybe I'll just do that and worry about allowing customization of the tab ordering later.

Quote:
Originally Posted by X-Raym View Post
Maybe it doesnt need to be built-in as long as the object property are flexible enough to be able to hook them like that.
While it could be implemented outside the library, I do feel this should be core OOTB functionality.


Quote:
Originally Posted by X-Raym View Post
As extra precision I think the first thread should mentioned that this framework is GFX based and has not his own custom render engine (which would be a big diff against ReaImGui for eg). 😊
Done. Thanks!
tack is offline   Reply With Quote
Old 07-31-2021, 04:30 PM   #11
storyteller
Human being with feelings
 
Join Date: Aug 2016
Posts: 232
Default

Congrats on the release Tack! Can't wait to take it on a test drive!
storyteller is offline   Reply With Quote
Old 09-03-2021, 03:32 AM   #12
Kabraxis
Human being with feelings
 
Kabraxis's Avatar
 
Join Date: Feb 2015
Location: Turkey
Posts: 263
Default

You have the best documentation ever. Great work!

Will there be a ReaPack version for RTK?
Edit: You've already answered that, sorry.

Last edited by Kabraxis; 09-03-2021 at 04:09 AM.
Kabraxis is offline   Reply With Quote
Old 09-03-2021, 07:53 AM   #13
Kabraxis
Human being with feelings
 
Kabraxis's Avatar
 
Join Date: Feb 2015
Location: Turkey
Posts: 263
Default

So I went ahead and tried it with my random digital instrument suggester. It's really easy to use, much like Kivy meets Web. I'm sure I'll be using this even more in the future. Thanks @Tack!

random_instr.gif
Kabraxis is offline   Reply With Quote
Old 09-06-2021, 08:52 AM   #14
tack
Human being with feelings
 
tack's Avatar
 
Join Date: Jan 2014
Location: Ontario, Canada
Posts: 1,639
Default

Quote:
Originally Posted by Kabraxis View Post
You have the best documentation ever. Great work!
Thanks!

Quote:
Originally Posted by Kabraxis View Post
It's really easy to use, much like Kivy meets Web. I'm sure I'll be using this even more in the future.
Very glad to hear.

I'd be curious to learn about any initial confusion and headscratchers you ran into while learning the basics (assuming there were any). Obviously as I've been staring at this code for the better part of 4 years, I lack any sort of perspective on this.
tack is offline   Reply With Quote
Old 09-06-2021, 02:26 PM   #15
gxray
Human being with feelings
 
Join Date: Dec 2020
Location: Miami, FL USA
Posts: 397
Default

This is amazing, quite a piece of work!

One design question I have -- had you considered a declarative format for the component definitions?
Something like S-expressions or XML/HTML?

My one hang-up with imperative UI is that it can get hard to follow the logic since there's no sort of hierarchical/determined visual flow for what gets rendered. And since side-effectful methods can add arbitrary components from anywhere in a codebase, as it grows in size maintainability can become difficult.

As an example, some pseudo-code based loosley on Vue.js and then same component translated to pseudo-code imperative function calls:

PHP Code:
<list background="gray" border="rounded">
  <
item for="input in state.inputs">
    <
text>{{ input.name }}: {{ input.value }}</text>
    <
button if="input.can_be_deleted" onclick="delete_input(input)">Delete Input</button>
  </
item>
</list> 
PHP Code:
let list = new List({ background"gray"border"rounded" })

for (
let i=0<= state.inputs.lengthi++) {
   
let input state.inputs[i]
   
let item = new Item()
   
let text = new Text(`${input.name}${input.value}`)
   
item.AddElement(text)
   if (
input.can_be_deleted) {
     const 
button = new Button()
     
button.onclick delete_input(input)
     
item.AddElement(button)
  }
  list.
AddElement(item)

Alternatively, there's the S-Expression way, would be like this (and this is what React etc convert JSX/HTML to anyways under the hood):

PHP Code:
h("list", { background "grey",  border="rounded" },
  
state.inputs.map(input => h("item", {}, [
    
h("text", {}, `${input.name}${input.value}`),
    
input.can_be_deleted &&
      
h("button", { onclick delete_input(input) }, "Delete Input")
  ]))

Where "h()" is the recursive rendering function that is something like the below:
PHP Code:
enum ELEMENT = {
  
BUTTON "button",
  
TEXT   "text",
}

function 
render(elementELEMENTpropertiesObject) { 
  
// code to render a single element, along with an object/table of properties
  // IE: "render("button", { onclick = delete_input(input) })
}

function 
h(elementELEMENTpropertiesObject, ...children) {
  
let thisElement render(elementproperties)
  for (
let child of children) {
    
thisElement.appendChild(h(children))
  }
  return 
thisElement

I've always wanted to write/port a declarative UI framework to REAPER.
Having that as an option in the REAPER GUI ecosystem would be awesome.

I started to look a while back at how to seriously do this, and the best I could come up with was to create ReaScript bindings to this:

It exposes roughly HTML + CSS and uses MVC + 2-way data binding, over C++:
PHP Code:
<h1>Simple data binding example</h1>
<
div data-model="my_model">
    <
h2>{{title}}</h2>
    <
p data-if="show_text">The quick brown fox jumps over the lazy {{animal}}.</p>
    <
input type="text" data-value="animal"/>
</
div
PHP Code:
using namespace Rml;

struct MyData {
    
String title "Hello World!";
    
String animal "dog";
    
bool show_text true;
my_data;

bool SetupDataBinding(ContextcontextDataModelHandlemy_model) {
    
DataModelConstructor constructor context->CreateDataModel("my_model");
    if (!
constructor) return false;

    
constructor.Bind("title", &my_data.title);
    
constructor.Bind("animal", &my_data.animal);
    
constructor.Bind("show_text", &my_data.show_text);

    
my_model constructor.GetModelHandle();
    return 
true;

Curious to hear your thoughts on this as you've been dealing with this REAPER UI thing for a while.
__________________
Seasoned codemonkey
Dunno a thing about making music (here to learn!)
gxray is offline   Reply With Quote
Old 09-06-2021, 03:42 PM   #16
tack
Human being with feelings
 
tack's Avatar
 
Join Date: Jan 2014
Location: Ontario, Canada
Posts: 1,639
Default

Quote:
Originally Posted by gxray View Post
One design question I have -- had you considered a declarative format for the component definitions? Something like S-expressions or XML/HTML?
I've always had S-expressions on my mind, actually. This is almost possible now -- the only thing that's missing is the ability to declare children on constructors of container widgets, but that's actually a trivial addition.

So something like this can be made possible quite easily:

Code:
local win = rtk.Window{
    title='My App',
    padding=10,
    rtk.VBox{
        spacing=10,
        rtk.HBox{
            spacing=5,
            valign='center',
            rtk.Text{'Magic Button:'},
            rtk.Button{
                'Click Me',
                onclick=function(self)
                    self:attr('label', 'I was clicked')
                    self:animate{'color', dst='red'}
                end
            }
        },
        rtk.CheckBox{
            'Enable borderless window',
            onchange=function(self)
                self.window:attr('borderless', self.value)
            end,
        },
    },
}
win:open()
But to be honest, for large and complex interfaces, I'm not convinced this approach is actually more readable than more conventional flat code. I think an XML-based approach would be more readable, but then I'm not super thrilled by the prospect of writing an XML parser in Lua. (Would be nice if Reaper's native XML parsing was exposed to Lua.)

And the main gap that would still need to be addressed is some way to reference declared widgets in event handler functions. This is almost a problem in the onchange() handler in the above example, except that the rtk.Window happens to be accessible as an attribute on every widget, so I get away with it in my example. But suppose the onclick() handler for the button wanted to modify the rtk.CheckBox below it, this wouldn't be possible currently. (At least not without manually doing a traversal of the widget hierarchy from the window, which is lame.)

So the obvious solution here is borrow more ideas from the DOM and allow a user-custom "id" attribute (which currently is just a monotonically increasing number per widget), and then offer a global function, say rtk.id(), to lookup widgets by their custom ids.

I'm not sure about the ergonomics of that approach, but the real concern is that by maintaining global references to all widgets we much more easily get into dangerous territory with memory leaks (inasmuch as the program has abandoned with the widget but there remains a global reference to it). I know Lua supports weak tables, and that'd definitely be required here, but I don't know if there be dragons with weak tables. (They can get tricky in other languages.)

And finally once you start building UIs that way, you're very quickly going to want something like CSS to manage the inevitable boilerplate.

I think I'll go ahead and add the code to support passing children on constructors like shown above (it's only like 5 extra lines). (Edit: this is committed now). The problem of how to reference widgets declared in this way warrants some more thought, so I'd be grateful to hear opinions on that.

Last edited by tack; 09-07-2021 at 04:39 PM.
tack is offline   Reply With Quote
Old 09-11-2021, 10:10 AM   #17
gxray
Human being with feelings
 
Join Date: Dec 2020
Location: Miami, FL USA
Posts: 397
Default

Quote:
Originally Posted by tack View Post
for large and complex interfaces, I'm not convinced this approach is actually more readable than more conventional flat code. I think an XML-based approach would be more readable
I do think it's a big improvement -- but agreed, XML/HTML based is my ideal too.
I've thought this same thing, and I do see one "easy"-ish implementation.

There are Lua templating engines which are self-contained and have no dependencies, the ones I could find were:

With "Liluat" looking the better of the two, since it supports import of other templates and arbitrary expression evaluation (whereas Mustache is logic-less)

Code:
local liluat = require("liluat")

local template = [[
  <body>
    <h1>Welcome to {{= title}}<h1>
    <h1>Vegetables</h1>
    <ul>
    {{ -- write regular lua code in the template}}
    {{for _,vegetable in ipairs(vegetables) do}}
      <li><b>{{= vegetable}}</b></li>
    {{end}}
    </ul>
  </body>
]]

-- values to render the template with
local values = {
	title = "A fine selection of vegetables.",
	vegetables = {
		"carrot",
		"cucumber",
		"broccoli",
		"tomato"
	}
}

-- compile the template into lua code
local compiled_template = liluat.compile(template)
local rendered_template = liluat.render(compiled_template, values)
io.write(rendered_template)
Output:
PHP Code:
<body>
  <
h1>Welcome to Vegetables</h1>
  <
h1>Vegetables</h1>
  <
ul>
    <
li><b>carrot</b></li>
    <
li><b>cucumber</b></li>
    <
li><b>broccoli</b></li>
    <
li><b>tomato</b></li>
  </
ul>
</
body
Now, imagine that is only step 1 of 2

The second step is to use a self-contained Lua XML parser to parse the generated XML into Lua tables. Then, programmatically render the components the XML describes. (This requires the S-Expression capable UI library)

So you could use https://github.com/manoelcampos/xml2lua
Quote:
XML Parser written entirely in Lua that works for Lua 5.1+. Convert XML to and from Lua Tables


So just imagine that the template was something like:
Code:
local template = [[
  <VBox>
    <Text>Welcome to {{= title}}</Text>
    <Text>Vegetables</Text>
    <List>
    {{ -- write regular lua code in the template}}
    {{for _,vegetable in ipairs(vegetables) do}}
      <ListItem><b>{{= vegetable}}</ListItem>
    {{end}}
    </List>
  </VBox>
]]
And then parse the template, use xml2lua to convert to a table, and render your GUI components from the table definition =D

---

I would probably write my "template" files for components separately, in like IE a ".lua.xml" file or something, and then read from it just for code cleanliness and organization
__________________
Seasoned codemonkey
Dunno a thing about making music (here to learn!)
gxray is offline   Reply With Quote
Old 09-11-2021, 10:52 AM   #18
tack
Human being with feelings
 
tack's Avatar
 
Join Date: Jan 2014
Location: Ontario, Canada
Posts: 1,639
Default

Quote:
Originally Posted by gxray View Post
There are Lua templating engines which are self-contained and have no dependencies, the ones I could find were:
So I actually ended up writing something from scratch. I took a look at xml2lua specifically, but I didn't want anything overly large. I decided while a fully compliant XML parser might be a bit much, implementing enough of a subset wasn't too difficult. So I'll call it RML, which is close enough to XML to be useful. Going from RML to a nested table structure was only about 120 lines of code. (Admittedly that code is not fully baked yet.)

I'm somewhat debating how I want variable scoping to work with expressions in the RML, though I think I have that sorted out. (At first I went with a dynamic scope approach but decided that's probably too clever, so will stick with lexical scoping, where the environment of executed code is determined at compile time, but can be explicitly overridden by passing a table at render time.)

The approach I'm taking around conditionals and loops is more inspired by Vue, which you mentioned in your earlier post, and which I myself am familiar with from other projects.

So my earlier example could be rewritten as:

Code:
function magic_click(self, event)
    self:attr('label', 'I was clicked')
    self:animate{'color', dst='red'}
end

local window = rml[[
  <window title='My App' padding=10>
    <vbox spacing=10>
      <hbox spacing=5 valign=center>
        <text>Magic Button:</text>
        <button onclick=magic_click>Click Me</button>
      </hbox>
      <checkbox if="rtk.has_js_reascript_api" onchange="self.window:attr('borderless', self.value)">
        Toggle borderless window
      </checkbox>
    </vbox>
  </window>
]]
window:open()
This shows:
  • Different types of handlers: inline expressions (with "self" being an injected magic variable like "this" is in javascript handlers) as well reference to externally defined functions
  • Conditional expression (checkbox only shows if js_ReaScriptAPI is available)
  • Single compile-and-render rml() convenience function (but template compiling and subsequent execution with custom variables injected into the function environment is also supported)

Mustache syntax is supported, both in attribute values as well as element content. But not for control flow -- that would be handled by the "if" and "for" attributes, a la Vue.

I still need to think about how for loops should work. Using a Lua expression is actually not straightforward to implement. I'll probably end up with a custom syntax that supports looping over tables, or iterating N times.

There is a risk here that with all this capability, reactivity will be assumed. But reactive updates are a whole other level of complexity entirely, and while it would undoubtedly be cool, it's hard to justify the effort at this stage.

Anyway, thanks for raising this to the foreground. I too wanted it early on, but it seemed a bit too ambitious, so I mainly just made sure to have a design to easily support S-expressions, knowing something XML-like would require it, so I could revisit this later. Now that I'm on the other side of rtk's design, implementing this doesn't seem like it will be too onerous. My code is still extremely experimental though, so who knows what dragons lurk around upcoming corners.

The question of how to access arbitrary widgets from event handlers still needs to be solved. There isn't (and almost certainly won't be) a CSS-like selector capability, so something like custom ids and rtk.id() is my best idea. Interested to hear your thoughts on that.

Last edited by tack; 09-11-2021 at 10:59 AM.
tack is offline   Reply With Quote
Old 09-11-2021, 02:52 PM   #19
gxray
Human being with feelings
 
Join Date: Dec 2020
Location: Miami, FL USA
Posts: 397
Default

Quote:
Originally Posted by tack View Post
The approach I'm taking around conditionals and loops is more inspired by Vue, which you mentioned in your earlier post, and which I myself am familiar with from other projects.

So my earlier example could be rewritten as: (...)

Mustache syntax is supported, both in attribute values as well as element content. But not for control flow -- that would be handled by the "if" and "for" attributes, a la Vue.

I still need to think about how for loops should work. Using a Lua expression is actually not straightforward to implement. I'll probably end up with a custom syntax that supports looping over tables, or iterating N times.
Oh my god, Vue for REAPER! Incredible!!

I've been writing Vue professionally since ~2016, right around the time Vue 2.0 was released, and I've written (nearly) everything.

From oldschool server-rendered templates -> jQuery -> old Angular.js -> React before Redux et all existed, whatnot.

Vue is simply the easiest/most productive and intuitive approach to modeling and building applications I've ever had the pleasure of working with. I used to speak frequently at Vue.js events.

Anyways, about this point:
Quote:
I still need to think about how for loops should work. Using a Lua expression is actually not straightforward to implement.
So one way I can think of off the top of my head, is to parse the "for" expression with a regex, and then call loadstring() on the "of" variable within the scope that contains the variable binding.
Then inject the dynamically evaluated result into the child template, aliased as the "for" variable in the closure

If you're like me, then trying to understand anything more complex than a potato described with words is impossible to follow, so here's roughly what I am trying to say:

(Note: Using EmmyLua annotations for type-safety https://emmylua.github.io/annotations/type.html)
Code:
---@alias ForOfExpression {for: string, of: string}

---@type fun(expr: string): ForOfExpression
function parse_for_of_expression(expr)

  -- Match "for=" content in EG: <text for="item in items">
  local pattern = "(%a+) [in|of] (%a+)"
  local _, _, alias, variable = string.find(expr, pattern)

  ---@type ForOfExpression
  local for_of_expression = { for = alias, of = variable }
  return for_of_expression
end

---@type fun(for_of_table: ForOfExpression): any
function get_for_of_variable_from_lexical_scope(for_of_expression)
  return loadstring(for_of_expression.of)
end

function render_for_of_template(template)
  local for_of_expression = parse_for_of_expression(fill_me_in)
  local value_bound_to_of = get_for_of_variable_from_lexical_scope(for_of_expression)

  return render_template(template)
            .with_value(value_bound_to_of)
            .as(for_of_expression.for)
end
And about this:

Quote:
Originally Posted by tack View Post
There is a risk here that with all this capability, reactivity will be assumed. But reactive updates are a whole other level of complexity entirely, and while it would undoubtedly be cool, it's hard to justify the effort at this stage.
I think you might be surprised how "easy" this is if you use the proper tooling so that the data in the templates is wrapped in a "reactive" type.

I wrote my own (shitty, just for fun) JS framework, including my own JSX rendering implementation and reactive data + rendering part, and managed to do it in about 60 lines by re-using Vue's low-level reactive() type.

In reaction to data being changed, I just re-called "render()" and passed in the updated state, check this out:

https://gist.github.com/GavinRay97/a...a89e9236994ca6

PHP Code:
// Fully type-safe JSX/TSX implementation in ~25 lines
function setAttributes(elHTMLElementattrsHTMLAttributes) {
  for (
let key in attrs) {
    
let val attrs[key]
    if (
key != 'style') return (el[key] = val)
    if (
typeof val == 'string') return (el.style.cssText val)
    return 
Object.assign(el.styleval)
  }
}

function 
assignProperty(elHTMLElementpropHTMLElement HTMLAttributes string) {
  if (Array.
isArray(prop)) return prop.map((it) => assignProperty(elit))

  if (
prop instanceof HTMLElement) return el.appendChild(prop)

  if (
typeof prop == 'string' || typeof prop == 'number')
    return (
el.textContent prop)

  if (
typeof prop == 'object') return setAttributes(elprop)
}

export function h(tag, ...props) {
  const 
el typeof tag == 'function' tag() : document.createElement(tag)
  
props.forEach((it) => assignProperty(elit))
  return 
el

PHP Code:
// Using the "h()" function as TSX pragma and writing your own Vue
// By re-using the reactivity primitives and using "morphdom" to efficiently update the DOM
import reactivecomputedwatchEffectwatch from 'vue'
import morphdom from 'morphdom'
import from './utils'

class App {
  private 
hostElElement
  
private _cachedHostElElement
  
public components = []

  
constructor(selectorstring) {
    
this.hostEl document.querySelector(selector)
    
this._cachedHostEl this.hostEl.cloneNode() as Element
  
}

  public 
run() {
    const 
nextEl this._cachedHostEl.cloneNode()
    
this.components.forEach((render) => nextEl.appendChild(render()))
    
morphdom(this.hostElnextEl)
  }

  public 
mount(component) {
    
watch(componentthis.run)
    
this.components.push(component)
  }
}

function 
myComponent() {
  const 
state reactive({ count1msg'changeme'numbers: [123] })
  return () => (
    <
div>
      <
p>Count: {state.count}</p>
      <
button onclick={() => state.count++}>Inc</button>
      <
p>Msg: {state.msg}</p>
      <
input onchange={(e) => (state.msg e.target.value)}></input>
    </
div>
  )
}

const 
app = new App('#app')
app.mount(myComponent())
app.run() 
It looks like there's an "RxLua" that's self-contained, maybe you could use this or some other event-emitter type library?

https://github.com/bjornbytes/RxLua

I'm sure it's not going to be this simple, but something roughly like:

Code:
local Rx = require('rx')

local state = {
  name = "Person",
  age = 25,
  list = { 1, 2, 3 }
}

local reactive_state = Rx.Observable.of(state)

render_template(some_template, reactive_state)

reactive_state:subscribe(function(updated_state)
   render_template(some_template, updated_state)
end)
If you wanted to go hardcore, I believe Vue uses a "scheduler", with a queue and eventing/messages + ticks, but fuckkk all of that haha.
__________________
Seasoned codemonkey
Dunno a thing about making music (here to learn!)

Last edited by gxray; 09-11-2021 at 03:04 PM.
gxray is offline   Reply With Quote
Old 09-11-2021, 03:08 PM   #20
gxray
Human being with feelings
 
Join Date: Dec 2020
Location: Miami, FL USA
Posts: 397
Default

Also about this:

Quote:
The question of how to access arbitrary widgets from event handlers still needs to be solved. There isn't (and almost certainly won't be) a CSS-like selector capability, so something like custom ids and rtk.id() is my best idea. Interested to hear your thoughts on that.
My vote goes to "Steal Vue's 'ref' system, like React eventually did." haha.

https://v3.vuejs.org/guide/compositi...late-refs.html

You're probably familiar with them, and you can call it whatever you like, but refs were created for exactly this purpose (need to reference a component programmatically that there's no means of getting a handle to).

PHP Code:
<vbox ref="main-screen">

</
vbox
Then something like self:refs or self.refs (my Lua is somewhat rusty, ha) I would think

---

Oh and a random neat thing I want to point out -- EmmyLua has support for "tagging" string template types as being another language, and then your IDE will use that language for syntax highlighting:

So my IDE would use proper XML highlighting inside of Lua files when writing your component templates. Amazing!

__________________
Seasoned codemonkey
Dunno a thing about making music (here to learn!)

Last edited by gxray; 09-11-2021 at 03:19 PM.
gxray is offline   Reply With Quote
Old 10-27-2021, 04:20 PM   #21
tack
Human being with feelings
 
tack's Avatar
 
Join Date: Jan 2014
Location: Ontario, Canada
Posts: 1,639
Default

Quote:
Originally Posted by gxray View Post
I think you might be surprised how "easy" this is if you use the proper tooling so that the data in the templates is wrapped in a "reactive" type.
That part is easy enough. I can imagine a relatively straightforward implementation for reactive values inside rtk widget attributes. But things get trickier when you get into virtual DOM territory. Consider this example:

Code:
local entries = rtk.reactive({{'Background', '#2f2f2f'}, {'Foreground', '#ffffff'}})

local window = rtk.rml[[
  <window>
    <vbox>
      <hbox for="(label, placeholder) in entries" spacing=5>
        <text>{{ label }}:</text>
        <entry :placeholder="placeholder"></entry>
      </hbox>
    </vbox>
  </window>
]]
window:open()

rtk.callafter(1, function()
  entries[#entries+1] = {'Accent', '#47abff'}
end)
It's pretty clear what this should do. And it's of course entirely possible with a bit of elbow grease. It's just crossing the elusive "easy" threshold.

I may have a go at it anyway, because obviously it's cool to have this level of reactivity. But my basic point is that once you dip your toes in the reactive pool, it ends up turning into a deeper lake before long.

Last edited by tack; 10-27-2021 at 04:25 PM.
tack is offline   Reply With Quote
Old 12-17-2021, 03:42 PM   #22
tack
Human being with feelings
 
tack's Avatar
 
Join Date: Jan 2014
Location: Ontario, Canada
Posts: 1,639
Default

Just wanted to give a heads up that I recently committed a breaking change for rtk.scale: instead of a scalar value controlling the overall UI scale, rtk.scale is now a table that reflects the various sources that influence UI scale -- namely the OS, REAPER's custom scale modifier (in the Advanced UI/system tweaks config), and the application's own custom scale factor.

What used to be rtk.scale is now rtk.scale.user, and an explicit rtk.Window:queue_reflow() is no longer needed after setting this value.

With this change, rtk apps will automatically respect the OS scale setting, at least for Windows and OS X. On Windows, system DPI changes are dynamically reflected.

I'll generally try to avoid breaking changes to the API, but as I'm not aware of a lot of rtk users, I figured it was worth striking while the iron was hot.
tack is offline   Reply With Quote
Old 12-22-2021, 09:33 AM   #23
MonkeyBars
Human being with feelings
 
MonkeyBars's Avatar
 
Join Date: Feb 2016
Location: Hollyweird
Posts: 2,796
Default

Thank you so much for rtk, tack! This is AMAZING. Love the detailed documentation.

I'm thinking I might be able to draw boxes around items pretty easily with rtk, like what I was trying to do when I started this thread.

Would it be possible to draw a box around some items, and allow the user to resize the box only horizontally? Obviously it would also need to follow the items' location and (zoom) size in the Arrange window...

Last edited by MonkeyBars; 12-22-2021 at 09:49 AM.
MonkeyBars is offline   Reply With Quote
Old 12-22-2021, 09:39 AM   #24
tack
Human being with feelings
 
tack's Avatar
 
Join Date: Jan 2014
Location: Ontario, Canada
Posts: 1,639
Default

Quote:
Originally Posted by MonkeyBars View Post
I'm thinking I might be able to draw boxes around items pretty easily with rtk, like what I was trying to do when I started this thread.

Would it be possible to draw a box around some items, and allow the user to resize the box only horizontally?
rtk can render a UI into a REAPER script gfx window, but can't draw arbitrarily over REAPER's own GUI elements. For that, I think your best bet is the js_ReaScriptAPI. Probably the best demonstration of this is Julian's MIDI Multi Tool.

This isn't something REAPER explicitly supports, but with some elbow grease it's possible.
tack is offline   Reply With Quote
Old 12-22-2021, 10:09 AM   #25
MonkeyBars
Human being with feelings
 
MonkeyBars's Avatar
 
Join Date: Feb 2016
Location: Hollyweird
Posts: 2,796
Default

Quote:
Originally Posted by tack View Post
rtk can render a UI into a REAPER script gfx window, but can't draw arbitrarily over REAPER's own GUI elements. For that, I think your best bet is the js_ReaScriptAPI. Probably the best demonstration of this is Julian's MIDI Multi Tool.

This isn't something REAPER explicitly supports, but with some elbow grease it's possible.
Thanks for your reply!

By elbow grease, I assume you mean things like detecting item area via its position + track height etc., and setting up defer to detect Arrange zoom/scroll changes and updating the location of the rtk.Box?

What about allowing only horizontal resize of a rtk.Box?
MonkeyBars is offline   Reply With Quote
Old 12-22-2021, 10:27 AM   #26
tack
Human being with feelings
 
tack's Avatar
 
Join Date: Jan 2014
Location: Ontario, Canada
Posts: 1,639
Default

Quote:
Originally Posted by MonkeyBars View Post
By elbow grease, I assume you mean things like detecting item area via its position + track height etc., and setting up defer to detect Arrange zoom/scroll changes and updating the location of the rtk.Box?
By elbow grease I mean wielding the js_ReaScriptAPI to use its low level functions to draw primitives over top REAPER's native GUI.

To be clear, this isn't something rtk can do. Unless there's a way to use js_ReaScriptAPI to take a ReaScript gfx window and somehow chroma-key and composite it over REAPER's hwnds -- and I'm not aware of this capability -- I don't think you can use rtk for your idea. Because rtk is meant for building GUIs within separate ReaScript gfx windows, not drawing arbitrarily over REAPER-native hwnds.

It's possible I've completely misunderstood what you're going for though. My reading is that you want to draw customizations over REAPER-native elements (in this case, items in the arrange view), not have a script GUI in a separate floating or docked window. If that's the case, I don't think rtk is right for this. The closest analog I could think of was Julian's multitool because it does this trick of drawing over REAPER-owned hwnds (not ReaScript gfx windows). But because of that, it's also had a history of being visually brittle, and making it work robustly has taken Julian some effort.

AFAICT you want to not only draw over the arrange view, but track scrolling/zooming as well and keep things synced. My sense is this is going to be much, much harder than you think. I recommend asking Julian in the js_ReaScriptAPI thread as he's probably most qualified to comment on what kind pain would await you.
tack is offline   Reply With Quote
Old 12-22-2021, 10:43 AM   #27
MonkeyBars
Human being with feelings
 
MonkeyBars's Avatar
 
Join Date: Feb 2016
Location: Hollyweird
Posts: 2,796
Default

Quote:
Originally Posted by tack View Post
My sense is this is going to be much, much harder than you think.
Yes not only in code labor time, but also the hit to performance by having to run a bunch of defer code to detect all that stuff... think I'll pass!

However I look forward to diving into rtk for my script's simple settings window with checkbox options
MonkeyBars is offline   Reply With Quote
Old 12-27-2021, 10:49 AM   #28
tack
Human being with feelings
 
tack's Avatar
 
Join Date: Jan 2014
Location: Ontario, Canada
Posts: 1,639
Default

A couple new classes added to rtk that improve support for scalable interfaces. rtk has always emphasized responsive design through resizable container classes, and now images can be responsive as well.
  • rtk.MultiImage: Encapsulates multiple underlying rtk.Image objects, representing different pixel density variants of the same image.
  • rtk.ImagePack: Manages a single image composed of a collection of smaller images, also known as an image sprite.
  • A new attribute called density has been added to rtk.Image which describes the pixel density of the image and dictates how it should behave with respect to the current UI scale.

The documentation is hopefully clear enough. Let me know if you have any questions. I've also added a new section to the tutorial.

Of course you still need to do the work to build image packs containing different resolutions (ImageMagick makes this much easier if you're comfortable on the CLI), but once that's in place, you can use a multi-DPI image (rtk.MultiImage) for any widget attribute that takes an image, and the appropriate DPI variant is automatically selected.

With this, and the recent changes to rtk.scale I mentioned a couple weeks ago, I'm pretty happy with how rtk-based applications behave on high-DPI systems.

Here's a demonstration with Reaticulate. In the upcoming release, all icons will contain 1x, 1.5x, and 2x variants.

tack is offline   Reply With Quote
Old 12-27-2021, 10:51 AM   #29
MonkeyBars
Human being with feelings
 
MonkeyBars's Avatar
 
Join Date: Feb 2016
Location: Hollyweird
Posts: 2,796
Default

Nice! Well done tack
MonkeyBars is offline   Reply With Quote
Old 01-08-2022, 12:44 PM   #30
tack
Human being with feelings
 
tack's Avatar
 
Join Date: Jan 2014
Location: Ontario, Canada
Posts: 1,639
Default

Quote:
Originally Posted by X-Raym View Post
I think centralized distribution like scythe or reaimgui are quite interesting cause if the extension got a fixed, than all script depending on them will got one.
I'm curious to hear other scripters' opinions on this.

rtk's current model is to have you distribute rtk with your script (either as a single bundled script file or separately, based on your preference). The main benefit of this is guaranteed compatibility.

Is this an obstacle to adoption, in your opinion? Is asking your script users to install a separate ReaPack for rtk so you don't need to distribute it your preference?

Thanks!
tack is offline   Reply With Quote
Old 01-08-2022, 01:42 PM   #31
MonkeyBars
Human being with feelings
 
MonkeyBars's Avatar
 
Join Date: Feb 2016
Location: Hollyweird
Posts: 2,796
Default

Quote:
Originally Posted by tack View Post
I'm curious to hear other scripters' opinions on this.

rtk's current model is to have you distribute rtk with your script (either as a single bundled script file or separately, based on your preference). The main benefit of this is guaranteed compatibility.

Is this an obstacle to adoption, in your opinion? Is asking your script users to install a separate ReaPack for rtk so you don't need to distribute it your preference?

Thanks!
There are various tradeoffs, aren't there... I guess one big question is how you plan to deal with breaking changes. How much do you emphasize backward compatibility in your dev roadmap?
MonkeyBars is offline   Reply With Quote
Old 01-08-2022, 02:15 PM   #32
tack
Human being with feelings
 
tack's Avatar
 
Join Date: Jan 2014
Location: Ontario, Canada
Posts: 1,639
Default

Quote:
Originally Posted by MonkeyBars View Post
There are various tradeoffs, aren't there... I guess one big question is how you plan to deal with breaking changes. How much do you emphasize backward compatibility in your dev roadmap?
Yeah, you hit the nail on the head exactly. This is the dilemma. A globally installed version must never break established APIs for existing scripts. That's the contract.

The reality is most things can be made backward compatible with some sacrifice to code maintenance or API ergonomics. The recent change I made to rtk.scale is an example where I broke the API by changing rtk.scale from a scalar value to a table with multiple fields. If I was desperate to avoid breaking anything, I'd have just put the new logic under rtk.scale2 or something similarly lame.

But ultimately if rtk's current distribution model is hindering adoption and moving to central ReaPack-managed deployment would improve, I'm quite willing to voluntarily wear those handcuffs.

I see a lot of activity on the Lokasenna GUI thread where people are raising bugs or struggling with things that are absolutely trivial with rtk, and curbing my desire to respond to each one of those posts with "well here's how you'd do it with rtk" is painful.

The ReaPack model I am contemplating would work like this:
  • Move rtk to semantic versioning (rather than the date-githash scheme like today, e.g. 20220108-1bf3494)
  • Rev the major version each time there's a breaking API change. Try to limit this to not more than 2 or 3 times a year.
  • Distribute the latest incarnation from each major version in the ReaPack. This could end up with potentially a dozen or two builds that get installed. (Currently the full bundle is about 225KB.)
  • When I rev a major version, shift all new development to that version, and encourage script-writers to migrate. Major fixes (like runtime errors) would get backported to applicable major versions released in the last year.
  • Scripts then import a specific major version.

For example, the ReaPack might contain:
  • v1.0.5: Scripts/rtk/1/rtk.lua
  • v2.2.13: Scripts/rtk/2/rtk.lua
  • v3.0.1: Scripts/rtk/3/rtk.lua

Scripters targeting the ReaPack deployment would import it this way:

Code:
package.path = reaper.GetResourcePath() .. '/Scripts/rtk/2/?.lua'
local rtk = require 'rtk'
That targets the latest build from the v2 API.

Lokasenna's approach of storing the library location via global state has the drawback in that it requires the end user to run an action first, and inflates the boilerplate for each script that uses the library. The only reason I can see for doing it this way is if install path for ReaPack content isn't guaranteed to be relative to reaper.GetResourcePath() .. '/Scripts' but I can't think of a scenario where this wouldn't be the case.

I have to imagine this would be nicer for consumers of the library. But as it's more constraining for me, I really only want to do it if rtk's (few AFAICT) current users, or its potential future users would prefer this approach.
tack is offline   Reply With Quote
Old 01-08-2022, 03:57 PM   #33
MonkeyBars
Human being with feelings
 
MonkeyBars's Avatar
 
Join Date: Feb 2016
Location: Hollyweird
Posts: 2,796
Default

Quote:
Originally Posted by tack View Post
For example, the ReaPack might contain:
  • v1.0.5: Scripts/rtk/1/rtk.lua
  • v2.2.13: Scripts/rtk/2/rtk.lua
  • v3.0.1: Scripts/rtk/3/rtk.lua
This seems like a very easy implementation method, and a good tradeoff balance between ease of dev for you and sufficient compatibility.

225kb is a bit large to have to include in one's script pack, imo.
MonkeyBars is offline   Reply With Quote
Old 01-20-2022, 08:18 AM   #34
MonkeyBars
Human being with feelings
 
MonkeyBars's Avatar
 
Join Date: Feb 2016
Location: Hollyweird
Posts: 2,796
Default

Hello tack,

Last nite I finally got to sit down and integrate rtk into my script... and it was SUCH a pleasure to use! Extremely easy and straightforward due to the architecture and superb documentation. (To be fair, a big reason I chose it was not only due to the docs but also my background as a pro web dev.) Thank you SO much!

Please DM me if you'd like to try out the beta. My usage of rtk is absolutely nothing sophisticated; I'm just happy I was able to implement my script options window in like 1 hour.

Last edited by MonkeyBars; 01-20-2022 at 08:26 AM.
MonkeyBars is offline   Reply With Quote
Old 01-20-2022, 10:47 AM   #35
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 11,131
Default

@monkey_bars
Can you show us a screenshots ? Or is it too soon ? :P
X-Raym is offline   Reply With Quote
Old 01-20-2022, 01:55 PM   #36
MonkeyBars
Human being with feelings
 
MonkeyBars's Avatar
 
Join Date: Feb 2016
Location: Hollyweird
Posts: 2,796
Default

Quote:
Originally Posted by X-Raym View Post
Can you show us a screenshots ? Or is it too soon ? :P
Too soon, as my script hasn't been released! But I recently opened the beta for limited testing. Feel free to DM me if you want the ReaPack link. I hope to release it next week.
MonkeyBars is offline   Reply With Quote
Old 01-20-2022, 02:48 PM   #37
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 11,131
Default

@Monkey_Bars
I'll wait for the full show then :P Thx !
X-Raym is offline   Reply With Quote
Old 01-20-2022, 07:00 PM   #38
tack
Human being with feelings
 
tack's Avatar
 
Join Date: Jan 2014
Location: Ontario, Canada
Posts: 1,639
Default

Quote:
Originally Posted by MonkeyBars View Post
Last nite I finally got to sit down and integrate rtk into my script... and it was SUCH a pleasure to use! Extremely easy and straightforward due to the architecture and superb documentation. (To be fair, a big reason I chose it was not only due to the docs but also my background as a pro web dev.) Thank you SO much!
That's really gratifying to hear, thanks!

Quote:
Originally Posted by MonkeyBars View Post
Please DM me if you'd like to try out the beta. My usage of rtk is absolutely nothing sophisticated; I'm just happy I was able to implement my script options window in like 1 hour.
I'll wait for you to fully bake it. I am admittedly interested to see how the code turned out.
tack is offline   Reply With Quote
Old 01-31-2022, 12:21 PM   #39
_Stevie_
Human being with feelings
 
_Stevie_'s Avatar
 
Join Date: Oct 2017
Location: Black Forest
Posts: 5,253
Default

I'm just doing my first baby steps with rtk on my mobile coding rig (MacBook Air M1) and every time I run the hello world example from here:
https://reapertoolkit.dev/index.html#hello_world

I get a huge window:

https://i.imgur.com/VNFfVpX.png

Yes, that window with the border is the actual scripting window.
I don't see any controls at all. It's just a grey window and when I try to resize it,
REAPER crashes immediately. Any ideas what could cause this?
__________________
My Reascripts forum thread | My Reascripts on GitHub
If you like or use my scripts, please support the Ukraine: Ukraine Crisis Relief Fund | DirectRelief | Save The Children | Razom

Last edited by _Stevie_; 02-19-2022 at 03:55 PM.
_Stevie_ is offline   Reply With Quote
Old 01-31-2022, 12:32 PM   #40
tack
Human being with feelings
 
tack's Avatar
 
Join Date: Jan 2014
Location: Ontario, Canada
Posts: 1,639
Default

Quote:
Originally Posted by _Stevie_ View Post
I'm just doing my first baby steps with rtk on my mobile coding rig (MacBook Air M1) and every time I run the hello world example from here:
https://reapertoolkit.dev/index.html#hello_world
Huh, weird. Because this is the same logic as what Reaticulate uses -- I assume Reaticulate is working for you on that system? I can't repro it on OS X over here, but it's also an older version running in a VM (and without a true retina display, as a result).

Stephan would you be ok opening an issue at https://github.com/jtackaberry/rtk/issues ? I anticipate some back-and-forth, if you're willing to help.

My immediate thought is to try explicitly specifying the window geometry and see if that does anything different:

Code:
local window = rtk.Window{x=0, y=0, w=800, h=600}
Also, is the behavior any different if you temporarily remove js_ReaScript_API? How about SWS?

Thanks!
tack is offline   Reply With Quote
Reply

Thread Tools

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 08:14 AM.


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