Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UI Plugins #5872

Merged
merged 35 commits into from
Jun 3, 2023
Merged

UI Plugins #5872

merged 35 commits into from
Jun 3, 2023

Conversation

Noordfrees
Copy link
Member

@Noordfrees Noordfrees commented Apr 25, 2023

Type of change
New feature

Issue(s) closed
Fixes #4801 (at least partially, but more features can be added by and by)
Closes #2117 since there's no reason why it couldn't be used in scenario scripting as well

How it works
Plugins are a new type of add-on that allow creating arbitrary UI components as children of existing components. These work both in the editor and in-game.

Possible regressions
N/A

Screenshots
grafik

Additional context
This is a pretty small-ish baseplate. It supports a handful of basic UI widgets and callback events. That's quite enough to write, for example, the attached sample add-on which exchanges two hardcoded terrain types with each other. editor_swap_terrains.wad.zip

It does not support more advanced window components, such as Dropdowns, ListSelects, Editboxes, and, well, most sorts of components actually. So far we have only Windows, Boxes, Buttons, and single-line Textareas.

Note that there are quite some pitfalls when scripting such a plugin. Both in the windowing system – the frontend is actually quite nice to use compared to C++, except for the callbacks, but layouting a complex window properly is a headache no matter what the frontend looks like. And the callbacks – since the Lua context may be deleted during the lifetime of a toolbar button, we can't reuse custom variables or functions, everything has to be a raw string. Read the attached add-on to see what I mean.

The attached add-on is meant to be enabled only in the editor. Comment out the first line to get it in-game as well, but beware – it will desync in replays/MP the moment you use it.

@Noordfrees Noordfrees added enhancement New feature or request ui User interface addon Problems and requests related to add-ons labels Apr 25, 2023
@Noordfrees Noordfrees added this to the v1.2 milestone Apr 25, 2023
@Noordfrees Noordfrees self-assigned this Apr 25, 2023
@frankystone
Copy link
Contributor

Puuuhhh 😃 The example addon you gave looks a bit, hm, crazy? I understand the most but can you explain what this syntax means:

on_click = [=[
.....
		]=]

I mean the [ = [?

I will play around with this, but may take some time.

@Noordfrees
Copy link
Member Author

That's just a string literal, exactly like [[text]]. A [[...]] literal can contain any text except its matching closing string delimiter, so if you want to nest multiple levels of string literals you can place any number of = chars between the brackets to have an unlimited number of string delimiters for arbitrary nesting.

-- All of the following are equivalent:
[[Hello World]]
[=[Hello World]=]
[==[Hello World]==]
-- And this is not:
[===[Hello World]==]  -- this is not the correct closing string delimiter, so everything (including this comment) is still part of the string!  --- here's to finally close it: ]===]  -- This comment is not part of the string.

Another way to handle the situation that does not require writing entire functions as strings would be to put each callback into a separate file and simplify the callbacks as just

	on_click = [[ include("addons/addon_name.wad/toolbar_callback.lua") ]],

@frankystone
Copy link
Contributor

Thanks :-)

Another way to handle the situation that does not require writing entire functions as strings would be to put each callback into a separate file and simplify the callbacks as just

	on_click = [[ include("addons/addon_name.wad/toolbar_callback.lua") ]],

I can't get this to work, nothings happens if i try to make it like so. Here is my auto_mountains.wad (just adapted your addon and exchanged the main function): editor_auto_mountains.zip The contained file auto_height.lua does not work with your suggestion (don't be confused about the function get_all_map_fields(), this is not used). Probably i am doing something wrong…

I am also not able to create a window with a textbox and yes-no buttons 🥲 If i try that i get always an error

[string "           push_textdomain("yes_no.wad", true)..."]:34: ')' expected (to close '(' at line 2) near '}'

although i have tried to make it as simple as i can and check all parenthesis and commas i can't get rid of this error.
yes_no.zip

Another question about the value for orientation: In your example the value "vert" is used, but according to the documentation it should be "vertical"?

* ``"orientation"``: **Mandatory**. The box's layouting direction:
``"vertical"`` or ``"horizontal"``.


Instead of having each tool as a button in the main menu of the editor i think it would be better to have an extra dropdown for add-on tools. Ideally not shown, or disabled, if no add-on tools are installed.

If you click several times of an addon entry in the main menu, on each click a new window is created covering the previously opened window. This should be prevented.

@Noordfrees
Copy link
Member Author

Noordfrees commented May 1, 2023

  • Re Yes/No: You have a Lua syntax error, a { is missing after line 39. Then it works.
    grafik
    Note that errors in stringified Lua code snippets always give their line number relative to the code snippet's start, so if the snippet starts at e.g. line 30 then an error in line 10 is actually near the source file line 40.
  • Re "vert" : It is annoying to always spell out h-o-r-i-z-o-n-t-a-l and v-e-r-t-i-c-a-l, especially since any complex window has lots of boxes. So I added some shorthands for their Lua equivalents. Will add them to the documentation as well.
  • Re dropdowns: Dropdowns (along with tables and listselects) are actually the hardest UI elements to handle in the Lua interface. I will definitely add those features, but that's for a separate branch to keep the PR reviewable.
  • Re windows: I will also add Unique Windows. Again, in a separate branch for reviewability.
  • Re AutoHeight: The following works for me:
      					on_click = [=[
      						include("addons/editor_auto_mountains.wad/auto_height.lua")
      						auto_mountains()
      					]=]

@frankystone
Copy link
Contributor

  • Re Yes/No: You have a Lua syntax error, a { is missing after line 39. Then it works.

Oh, stupid me :-) That's the reason why i always need some time.

How can i determine which button a user has clicked on? Or is this also for a later branch?

Note that errors in stringified Lua code snippets always give their line number relative to the code snippet's start, so if the snippet starts at e.g. line 30 then an error in line 10 is actually near the source file line 40.

Good to know, thanks.

  • Re dropdowns: Dropdowns (along with tables and listselects) are actually the hardest UI elements to handle in the Lua interface. I will definitely add those features, but that's for a separate branch to keep the PR reviewable.

Maybe a misunderstanding: I don't meant to add dropdowns for add-on windows, i meant a dropdown for the editors main menu which contains all add-on ui-plugins. Similar to the Tools menu.

  • Re AutoHeight: The following works for me:
      					on_click = [=[
      						include("addons/editor_auto_mountains.wad/auto_height.lua")
      						auto_mountains()
      					]=]

Ah, thanks again.

@Noordfrees
Copy link
Member Author

How can i determine which button a user has clicked on? Or is this also for a later branch?

Each button has its own on_click callback code. If you want to use the multiple-files approach, you can use a different file for each button, or set a global variable before including the file (ACTION="yes"; include("filename.lua")), or use only exported functions (like in automountains – include("filename.lua"); callback_function_3()).

Re dropdowns: Dropdowns (along with tables and listselects) are actually the hardest UI elements to handle in the Lua interface. I will definitely add those features, but that's for a separate branch to keep the PR reviewable.

Maybe a misunderstanding: I don't meant to add dropdowns for add-on windows, i meant a dropdown for the editors main menu which contains all add-on ui-plugins. Similar to the Tools menu.

No that's the same case. Adding new entries to an existing dropdown is equally hard. Also, UI plugins have a lot of flexibility since they can edit arbitrary aspects of the GUI; I don't want to restrict the functionality to allow only a handful of dropdown entries and nothing else as plugin entry points.
So yes I will add such a dropdown when implementing scripting support for dropdowns and make it the recommended place for plugins' starting points, but right now that would be a lot of code… unless of course someone who wants to do the code review tells me it's fine, in which case I would add a lot more functionality here :)

@frankystone
Copy link
Contributor

Will it be possible to have some sort of templates for ui-plugins? E.g. a yes_no template which contains a textbox and two buttons and one can do something like:

mv.toolbar:create_child({
	widget = "button",
	name   = "auto_mountains_plugin_toolbar_button",
	w      = styles.get_size("toolbar_button_size"),
	h      = styles.get_size("toolbar_button_size"),
	tooltip  = _("Set height of mountains automatically"),
	icon     = "images/wui/editor/tools/height.png",
	on_click = [[  template("yes_no", "_(This is the text for the textbox)", 
                                include("addons/editor_auto_mountains.wad/auto_height.lua")
  				auto_mountains() )  ]],
})

Something along that would make the handling much easier. And i think such templates can cover most of the use cases.

@Noordfrees
Copy link
Member Author

Will it be possible to have some sort of templates for ui-plugins?

Hm… we have one such C++ UI element, the WLMessageBox – a simple modal window with a multiline textarea and an OK button and optionally a Cancel button. Would exposing this to Lua be sufficient for most such cases I think?

If we really need more complicated templates that will actually be used by many add-ons, that can be done too, but I'd consider this lower priority than getting all the basic UI widget types createable and – very important, and currently only rudimentarily supported – allowing scripts to access them and change their properties later. What sort of templates would you need?

@frankystone
Copy link
Contributor

Think of the fourth empire campaign where the player has to decide to attack Vesta or to deliver some wine. Here a simple yes/no template would be fine. A Yes/No template would be one of the most used, i guess, because simple decisions can be made as a question which only can be answered with yes or no.

And in general like described in #2117 , e.g. a mutiline optionbox to make it possible to make some sort of conversation with different possible answers:

Protagonist: "Hey, nice to meet you!"
Possible answers from the player

  • I am fine, thank you (leaving)
  • Who are you?
  • Hey, nice to meet you also. May i ask you some thing?
  • I don't have the time to speak to you

Depending on the players choice, a scenario can act different. Either start a conversation with the protagonist or not.

For the editor i think having just a OK-template is enough. More difficult things can be implemented later, or if (ever) needed.

Copy link
Contributor

@frankystone frankystone left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One question and suggestions to improve the example with comments.

src/scripting/lua_ui.cc Outdated Show resolved Hide resolved
src/scripting/lua_ui.cc Outdated Show resolved Hide resolved
src/scripting/lua_ui.cc Show resolved Hide resolved
src/scripting/lua_ui.cc Show resolved Hide resolved
src/scripting/lua_ui.cc Show resolved Hide resolved
src/scripting/lua_ui.cc Show resolved Hide resolved
src/scripting/lua_ui.cc Show resolved Hide resolved
src/scripting/lua_ui.cc Show resolved Hide resolved
src/scripting/lua_ui.cc Outdated Show resolved Hide resolved
@frankystone
Copy link
Contributor

From my side this is good to go now :-)

@frankystone
Copy link
Contributor

frankystone commented May 7, 2023

Instead of of using checkboxes one can also create a window with buttons to achieve a multi-answer approach. I have tried that, but it fails with

expected a userdata, but got something else.

Any advice?

The scenario: test_UI-Plugin.zip

@Noordfrees
Copy link
Member Author

Noordfrees commented May 7, 2023

Lua function call syntax: mv.create_child(mv:create_child(

@frankystone
Copy link
Contributor

Always the same stupid mistakes, thanks a lot!

@Noordfrees Noordfrees dismissed frankystone’s stale review May 31, 2023 21:33

all comments were resolved

@Noordfrees Noordfrees requested a review from a team May 31, 2023 21:33
Copy link
Member

@tothxa tothxa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've gone through lua_ui.cc once, and it looks OK, but I want to double-check against the docs.

Meanwhile some minor comments.

src/graphic/style_manager.h Outdated Show resolved Hide resolved
src/logic/addons.cc Outdated Show resolved Hide resolved
Copy link
Member

@tothxa tothxa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you. I only tested with your attached add-on, otherwise I rely on @frankystone's earlier testing.

The generic get_table_{string,int,boolean} functions could be moved to lua.{cc,h}.

Copy link
Member

@tothxa tothxa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I didn't realise they needed another header.

@Noordfrees Noordfrees merged commit 924e255 into widelands:master Jun 3, 2023
29 of 33 checks passed
@Noordfrees Noordfrees deleted the uiplugins branch June 3, 2023 07:31
@Noordfrees
Copy link
Member Author

Thanks for the review :)

@Noordfrees Noordfrees mentioned this pull request Jun 4, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
addon Problems and requests related to add-ons enhancement New feature or request ui User interface
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Editor addons; create windows? Multiple-options campaign message boxes
3 participants