LibreSprite / LibreSprite-proposals

Have a request? Let us know here!
6 stars 1 forks source link

Interactive scripts API #21

Open felipemanga opened 3 years ago

felipemanga commented 3 years ago
Is your feature request related to a problem? Please describe

Right now, scripts can execute a series of actions like altering a sprite or saving it, but they are limited as they can't request the user for input. As an example, if I wanted to make a script that blurs the image, the script can't show a dialog that asks how much (the blur radius).

Describe the solution you'd like

Here is my proposal for a scripting API that allows for more complex scripts to be made:

1- Allow scripts to listen for events. Clicking on a script in the menu triggers the "run" event. Clicking on a button in a dialog triggers that custom button's event. We can also have events for notifying the script that it has become selected as the current tool, mouse down/up/move in the sprite (allowing scripts to implement custom brushes), etc. As is the current behavior, the scripting engine will tear-down and clean up after an event is handled. We can avoid this as an optimization for mouse events, if it is necessary to prevent lag.

2- Addition of a new script object that serves as a key-value storage for scripts. This will allow scripts to maintain state information between executions or share data with other scripts. It will contain the following methods:

3- Addition of a new Dialog class that can be used to interact with the user.

Example script that opens a dialog and counts how many times a button was pressed:

createDialog();

function onEvent(event){
  if (event == "buttonOK-pressed") {
    let dialog = app.getDialog("test");
    let inputValue = dialog.getChild("value");
    let labelCaption = dialog.getChild("caption");
    let value = inputValue.value(); // get the number entered in the input field
    labelCaption.setLabel("You pressed OK " + count + " times. Value is " + value);
  }
}

function createDialog(){
  // opens a new dialog window
  let dialog = app.createDialog(); 

  // put a label inside the dialog. Last argument "caption" is an optional Id for retrieving the label later.
  dialog.addLabel("This is a label", "caption");

  // add number input with a label and an Id. Emits the "${id}-changed" event.
  dialog.addNumberInput("Enter a value:", "value");

  // create a button with an "OK" label and "buttonOK" id. Emits the "${id}-clicked" event.
  dialog.addButton("OK", "buttonOK"); 
}
felipemanga commented 2 years ago

Storage / HTTP APIs implemented with the following API:

Zughy commented 2 years ago

Overall idea is good, just a couple things:

felipemanga commented 2 years ago

I imagine being able to read/write would be useful for scripts to share data between each other, but didn't have anything specific in mind. A script is unlikely to accidentally break another one's data because namespaces are the full file path by default.

I'm also not sure if the data should be persistent. If you close and reopen libresprite, should all the data be lost? Preserving the data might be a problem if misbehaving scripts store too much stuff. Right now, with ephemeral storage, a shutdown will get you a clean slate in the next startup.

We're going to need an API for reading/writing files. Maybe that should be used to store any critical data and it wouldn't matter if scripts can write to any namespace.

Zughy commented 2 years ago

A script is unlikely to accidentally break another one's data because namespaces are the full file path by default

I fear some user might rename them and then wonder why it doesn't work

I'm also not sure if the data should be persistent

Mmm... I don't think it's a priority for now. But I guess we could use xml files, maybe in a storage folder inside the scripts folder

felipemanga commented 2 years ago

I fear some user might rename them and then wonder why it doesn't work

It would still work, though it would act like if it was freshly-installed.