Important Dates

Latest Posts

Topic: UI questions

kaputtnik
Avatar
Topic Opener
Joined: 2013-02-18, 20:48
Posts: 2514
OS: Archlinux
Version: current master
Ranking
One Elder of Players
Location: Germany
Posted at: 2024-01-15, 19:19

Probably a topic gathering UI-related questions regarding the new ui widgets available in version 1.2

In the screenshot below the windows have a layout of one horizontal box containing two vertical boxes (2 columns). The 'left' box has a textarea as child, the 'right' one has a mutlilinetextarea as child. Each vertical box should have a width of 200 pixels. For comparison a screen ruler showing pixels is also in this screenshot.

Fighting with width's

  • The above window displays the result when applying w = 200 to the textarea. As you can see at the screenruler the width isn't 200. Confusing
  • The next window below shows the result if i apply a spinbox with the mandatory property unit_w = 200 . Oh, suddenly the left column has the wanted width of 200 pixels. And the width of the textarea doesn't matter, i can set w = 2000 to the textarea and nothing changes. Confusing
  • The bottom window shows the result with removed spinbox but applying fixed_width = 200 to the textarea. Yeah this is what i would expect when using w = 200 for the textarea.

Why need the textarea an extra property fixed_width? Or vice versa: What purpose has the w property for textareas?

The Problem for me is that i build such a menu part by part: 1. create the boxes with one child for each, probably i want to show a header for each column so i put textareas in each column box and test this. The result is not what i want (the width's are not applied), because i didn't remember the fixed_width property. After remembering this property the result looks ok. Then i place the next children to the columns, all of them with the needed width, 200 pixels in this case. But, hm for the spinbox i need another property than w to apply the width, namely unit_w. So i have now three properties defining the width, w, unit_w and fixed_w and also have to remember which property belongs to which widget. This is also part of confusion...

Just wanted to write from a users perspective and hopefully my confusion is understandable.

Multilinetextarea and richtext

The textarea in the left column uses wui_info_panel_paragraph as value for the font. Applying this font to the multilinetextarea doesn't work as you can see in the screenshot. Code:

{
      widget = "multilinetextarea",
      name   = "editbox_header", 
      resizing = "expandboth",
      w      = 200,
      scroll_mode = "none",                     -- very useful, without this one has to define also the height
      font   = "wui_info_panel_paragraph",
      text   = _("Enter coordinates, e.g.: 20,23"),
},

I know i can do something like `rt(p(_("Enter coordinates, e.g.: 20,23"))) for the text, but then the font is totally different.
To cite Nordfriese:

In simplified mode (without <rt>), the mltextarea applies its own richtext wrapping around that and this wrapping uses the font style attribute.

Probably i didn't understand this, because if i try to use something like p(_("Enter coordinates, e.g.: 20,23")) for the text (so it get wrapped in an rt-tag, as in understoud) i get prompted with the richtext source code and no richtext rendering is done. So what is needed get the look of text in the multilinetextarea the same as in the textarea? Or: What does "applies its own richtext wrapping" mean in detail?

So i am a bit lost here, maybe too dumb to understand all these things. And a bit frustrated. On the other side i think the new UI stuff is just new, and the documentation only lacks some important information for beginners. Nevertheless this is a great enhancement to the game and i am glad to have it face-smile.png


Attachment:
ui_width_1.png

Top Quote
Nordfriese
Avatar
Joined: 2017-01-17, 18:07
Posts: 2029
OS: Debian Testing
Version: Latest master
Ranking
One Elder of Players
Location: 0x55555d3a34c0
Posted at: 2024-01-15, 19:58

Single line textareas

They can be either layouted or fixed. In layouted mode, the default width is always equal to the text width, and your custom width is ignored completely. If you specify a fixed_width, then the textarea is forced to that width, regardless of the text's size. In both cases, the Box may add extra width if applicable.

The w property doesn't really make sense for the regular single line textarea. It is there only for cornercases, since it affects the very first time a textarea is layouted (before it computes its required size). In a few very exotic situations setting this to a high or low value can make a difference.

Spinbox

How regular width and unit_w interact, and how to get the buttons part and the label part to show up as intended, is forever confusing to me in C++ as well face-wink.png

This widget is an absolute nightmare to layout properly. Play around with many combinations of w and unit_w until it looks sort of good. That's how every spinbox I ever added to the Widelands UI is layouted face-tongue.png

Multiline textarea and richtext

If you use any richtext markup (the <rt> tag), then the font property is completely ignored. The richtext defines its own style. If you do not use a <font ...> tag then a default style is applied.

The ML text area's style only applies if you don't use any richtext markup at all.

If you use p() without rt(), then you do not get WLRichtext, p() only adds a <p> tag but no <rt> tag, so it is not valid richtext and the text is rendered verbatim.

Examples:

-- Valid richtext, renders "Hello World" with a default font
text = [[ <rt><p>Hello World</p></rt> ]]  

-- Valid richtext, renders "Hello World" with a custom font
text = [[ <rt><p><font face="serif" color=007fbf bold=1 italic=1>Hello World</font></p></rt> ]]  

-- Not richtext, renders "Hello World" in the mltextarea's font
text = [[ Hello World ]]  

-- Not richtext, renders verbatim "<p>Hello World</p>" in the textarea's font
text = [[ <p>Hello World</p> ]]  

However, by comparing your examples (which actually should work but here don't) with my own sample code (which does work), I noticed that in the current state of the branch the style was only applied if the text was afterwards set via widget.text = "..." but not applied to the initial text due to some intransparent implementation detail of MultilineEditbox. I pushed a commit with a fix for this bug, please check again.

Edited: 2024-01-15, 19:59

Top Quote
matthiakl
Avatar
Joined: 2020-10-30, 09:17
Posts: 13
OS: Arch Linux
Ranking
Pry about Widelands
Posted at: 2024-01-15, 20:59

Spinbox

A spinbox consists of two components: a label and the "unit" which is the button group and the value indicator in between. So the unit_w sets the fixed width of the button group. Choose it, so that the value is readable.

If we name the width of the label label_w, we get the relation "w = unit_w + label_w". So with having unit_w a fixed value, w behaves very similar (and strange) to single textareas wrt the label.


(In C++ there are even more widths to add to the confusion ;): width, desired_width, max_width)


Top Quote
kaputtnik
Avatar
Topic Opener
Joined: 2013-02-18, 20:48
Posts: 2514
OS: Archlinux
Version: current master
Ranking
One Elder of Players
Location: Germany
Posted at: 2024-01-16, 11:49

Ok, thank you very much!

Spinbox

Funnily i have no problems so far with this widget, except the label. But this can be circumvented by applying just no label and make an extra textarea widget which act as a label.

Multilinetextarea and richtext

The explanation of Nordfriese was exactly how i understood this. So my issue was just a bug, leading to confusion. Thanks for fixing!


Another thing i am fighting with:

Fighting with width's, aka positioning of widgets

Normally all widgets should be shown centered. But in a two columns layout this doesn't work if one widget's width is smaller than the wanted columns width. In the screenshot the row with the editbox (value 10,25) consist of a multilinetextarea (column1, width 200) and an editbox (column2, width 200) both wrapped in an horizontal box. All fine here. But for my taste the editbox is too wide.

The row below of this consists also of multilientextarea (column1, width 200) but the editbox has a width of 100. As a result the sum of both widgets width's is used for centering the whole row.

Now my idea was to put the multilientextarea and the editbox each in it's own box with orientation vertical and give the boxes the wanted width of 200 to make them shown centered. But the result is the same.

The only solution i found is to add some space widgets around the edit box, so that the overall width of column2 is 200 (space 50 + widget width 100 + space 50). Is there another way to have widgets centered in a two columns layout?


Attachment:
ui_width_2.png

Top Quote
Nordfriese
Avatar
Joined: 2017-01-17, 18:07
Posts: 2029
OS: Debian Testing
Version: Latest master
Ranking
One Elder of Players
Location: 0x55555d3a34c0
Posted at: 2024-01-16, 12:26

I am not sure what exactly you want to accomplish. A mockup annotating the desired dimensions of all widgets and the spacing between them would be helpful.

If I understand correctly, you want the right column entry to consist of a fixed-width editbox with empty padding of 50px each to the left and right, in which case two space widgets would indeed be the correct way to go.

Giving a box a nominal width may or may not have a visible effect if the box itself is layouted by a parent box, since the box will calculate its desired size based on its content and the parent box will resize the child box based on that. Thus, a box with only one element is nearly always useless.

P.S. The text in your example has some ugly linebreaks, consider using &nbsp; for spaces where no line wrapping should take place.

Edited: 2024-01-16, 12:27

Top Quote
kaputtnik
Avatar
Topic Opener
Joined: 2013-02-18, 20:48
Posts: 2514
OS: Archlinux
Version: current master
Ranking
One Elder of Players
Location: Germany
Posted at: 2024-01-16, 17:46

Nordfriese wrote:

If I understand correctly, you want the right column entry to consist of a fixed-width editbox with empty padding of 50px each to the left and right, in which case two space widgets would indeed be the correct way to go.

Yes, that's the answer i want to hear.

P.S. The text in your example has some ugly linebreaks, consider using &nbsp; for spaces where no line wrapping should take place.

Yes, the next thing i want to fix, thanks for the hint!


Top Quote
kaputtnik
Avatar
Topic Opener
Joined: 2013-02-18, 20:48
Posts: 2514
OS: Archlinux
Version: current master
Ranking
One Elder of Players
Location: Germany
Posted at: 2024-01-16, 18:21

P.S. The text in your example has some ugly linebreaks, consider using   for spaces where no line wrapping should take place.

Don't know if this a bug or normal: This does only work if i wrap the text within richtext, eg. rt(p(" Text with no&nbsp;space")). Without richtext ` is shown instead of a space.


Top Quote
Nordfriese
Avatar
Joined: 2017-01-17, 18:07
Posts: 2029
OS: Debian Testing
Version: Latest master
Ranking
One Elder of Players
Location: 0x55555d3a34c0
Posted at: 2024-01-16, 18:39

kaputtnik wrote:

P.S. The text in your example has some ugly linebreaks, consider using   for spaces where no line wrapping should take place.

Don't know if this a bug or normal: This does only work if i wrap the text within richtext, eg. rt(p(" Text with no&nbsp;space")). Without richtext ` is shown instead of a space.

That's normal. As I said above, without an <rt> tag everything is rendered verbatim, and &nbsp; is only interpreted as a non-breaking space when used within richtext.

Btw, the website is having a bit of trouble with &nbsp; even when put in markdown code styling face-wink.png


Top Quote
kaputtnik
Avatar
Topic Opener
Joined: 2013-02-18, 20:48
Posts: 2514
OS: Archlinux
Version: current master
Ranking
One Elder of Players
Location: Germany
Posted at: 2024-01-20, 12:54

Another question:

I want to stop code execution and want to show a window with an Ok and a Cancel button. Pseudo code:

local fields = {}
gather fields

if #fields > 5000 then
   show_warning_window(fields)    -- show warning window with text: _("%1$d are a lot of fields. Click OK if you are sure"):bformat(#fields)
end

function callback_ok(fields)      -- user clicked OK, but how to pass the 'fields'?
   execute_function(fields)
end

Does the variable 'fields' needs to be global in such a case? Or is there another solution?


Top Quote
Nordfriese
Avatar
Joined: 2017-01-17, 18:07
Posts: 2029
OS: Debian Testing
Version: Latest master
Ranking
One Elder of Players
Location: 0x55555d3a34c0
Posted at: 2024-01-20, 15:09

If you have single-threaded execution you might want to use wl.ui.show_messagebox which does not require callbacks at all:

function action()
    local fields = gather_fields()
    if #fields > 5000 and not wl.ui.show_messagebox(_("Warning"), _("Are you sure?"), true) then return end
    for i,f in ipairs(fields) do
        print("Processing field " .. f.x .. "," .. f.y)
    end
end

If you don't want to use show_messagebox (e.g. because you want a custom window), then you have two options. Either make fields global. But be sure to choose a good, unique name in this case, global variables are bad style. Or, more work but cleaner and safer, stringify it and pass it as a function parameter that you then decode (or just as a parameter pack):

local fields_as_str = ""
for i,f in ipairs(fields) do fields_as_str = fields_as_str .. ",{x=" .. f.x .. ",y=" .. f.y .. "}" end
on_clicked = "do_something(" .. fields_as_str:sub(2) .. ")"
function do_something(...)
    for i,c in ipairs({...}) do
        print("Processing coordinates " .. c.x .. "," .. c.y)
    end
end

Top Quote