Skip to content

Commit 4f45bfd

Browse files
v-robrubenwardy
authored andcommittedDec 6, 2019
Add scrollbaroptions FormSpec element (#8530)
1 parent 9a5d43a commit 4f45bfd

File tree

5 files changed

+159
-36
lines changed

5 files changed

+159
-36
lines changed
 

‎doc/lua_api.txt

+26-2
Original file line numberDiff line numberDiff line change
@@ -2351,16 +2351,40 @@ Elements
23512351

23522352
### `scrollbar[<X>,<Y>;<W>,<H>;<orientation>;<name>;<value>]`
23532353

2354-
* Show a scrollbar
2354+
* Show a scrollbar using options defined by the previous `scrollbaroptions[]`
23552355
* There are two ways to use it:
23562356
1. handle the changed event (only changed scrollbar is available)
23572357
2. read the value on pressing a button (all scrollbars are available)
23582358
* `orientation`: `vertical`/`horizontal`
23592359
* Fieldname data is transferred to Lua
2360-
* Value this trackbar is set to (`0`-`1000`)
2360+
* Value of this trackbar is set to (`0`-`1000`) by default
23612361
* See also `minetest.explode_scrollbar_event`
23622362
(main menu: `core.explode_scrollbar_event`).
23632363

2364+
### `scrollbaroptions[opt1;opt2;...]`
2365+
* Sets options for all following `scrollbar[]` elements
2366+
* `min=<int>`
2367+
* Sets scrollbar minimum value, defaults to `0`.
2368+
* `max=<int>`
2369+
* Sets scrollbar maximum value, defaults to `1000`.
2370+
If the max is equal to the min, the scrollbar will be disabled.
2371+
* `smallstep=<int>`
2372+
* Sets scrollbar step value when the arrows are clicked or the mouse wheel is
2373+
scrolled.
2374+
* If this is set to a negative number, the value will be reset to `10`.
2375+
* `largestep=<int>`
2376+
* Sets scrollbar step value used by page up and page down.
2377+
* If this is set to a negative number, the value will be reset to `100`.
2378+
* `thumbsize=<int>`
2379+
* Sets size of the thumb on the scrollbar. Size is calculated in the number of
2380+
units the thumb spans out of the range of the scrollbar values.
2381+
* Example: If a scrollbar has a `min` of 1 and a `max` of 100, a thumbsize of 10
2382+
would span a tenth of the scrollbar space.
2383+
* If this is set to zero or less, the value will be reset to `1`.
2384+
* `arrows=<show/hide/default>`
2385+
* Whether to show the arrow buttons on the scrollbar. `default` hides the arrows
2386+
when the scrollbar gets too small, but shows them otherwise.
2387+
23642388
### `table[<X>,<Y>;<W>,<H>;<name>;<cell 1>,<cell 2>,...,<cell n>;<selected idx>]`
23652389

23662390
* Show scrollable table using options defined by the previous `tableoptions[]`

‎src/gui/guiFormSpecMenu.cpp

+89-30
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
2424
#include <limits>
2525
#include <sstream>
2626
#include "guiFormSpecMenu.h"
27+
#include "guiScrollBar.h"
28+
#include "guiTable.h"
2729
#include "constants.h"
2830
#include "gamedef.h"
2931
#include "client/keycode.h"
@@ -123,24 +125,18 @@ GUIFormSpecMenu::~GUIFormSpecMenu()
123125
{
124126
removeChildren();
125127

126-
for (auto &table_it : m_tables) {
128+
for (auto &table_it : m_tables)
127129
table_it.second->drop();
128-
}
129-
for (auto &inventorylist_it : m_inventorylists) {
130+
for (auto &inventorylist_it : m_inventorylists)
130131
inventorylist_it.e->drop();
131-
}
132-
for (auto &checkbox_it : m_checkboxes) {
132+
for (auto &checkbox_it : m_checkboxes)
133133
checkbox_it.second->drop();
134-
}
135-
for (auto &scrollbar_it : m_scrollbars) {
134+
for (auto &scrollbar_it : m_scrollbars)
136135
scrollbar_it.second->drop();
137-
}
138-
for (auto &background_it : m_backgrounds) {
136+
for (auto &background_it : m_backgrounds)
139137
background_it->drop();
140-
}
141-
for (auto &tooltip_rect_it : m_tooltip_rects) {
138+
for (auto &tooltip_rect_it : m_tooltip_rects)
142139
tooltip_rect_it.first->drop();
143-
}
144140

145141
delete m_selected_item;
146142
delete m_form_src;
@@ -614,22 +610,86 @@ void GUIFormSpecMenu::parseScrollBar(parserData* data, const std::string &elemen
614610
spec.ftype = f_ScrollBar;
615611
spec.send = true;
616612
GUIScrollBar *e = new GUIScrollBar(Environment, this, spec.fid, rect,
617-
is_horizontal, false);
613+
is_horizontal, true);
618614

619615
auto style = getStyleForElement("scrollbar", name);
620616
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
617+
e->setArrowsVisible(data->scrollbar_options.arrow_visiblity);
618+
619+
s32 max = data->scrollbar_options.max;
620+
s32 min = data->scrollbar_options.min;
621+
622+
e->setMax(max);
623+
e->setMin(min);
621624

622-
e->setMax(1000);
623-
e->setMin(0);
624625
e->setPos(stoi(parts[4]));
625-
e->setSmallStep(10);
626-
e->setLargeStep(100);
626+
627+
e->setSmallStep(data->scrollbar_options.small_step);
628+
e->setLargeStep(data->scrollbar_options.large_step);
629+
630+
s32 scrollbar_size = is_horizontal ? dim.X : dim.Y;
631+
632+
e->setPageSize(scrollbar_size * (max - min + 1) / data->scrollbar_options.thumb_size);
627633

628634
m_scrollbars.emplace_back(spec,e);
629635
m_fields.push_back(spec);
630636
return;
631637
}
632-
errorstream<< "Invalid scrollbar element(" << parts.size() << "): '" << element << "'" << std::endl;
638+
errorstream << "Invalid scrollbar element(" << parts.size() << "): '" << element
639+
<< "'" << std::endl;
640+
}
641+
642+
void GUIFormSpecMenu::parseScrollBarOptions(parserData* data, const std::string &element)
643+
{
644+
std::vector<std::string> parts = split(element, ';');
645+
646+
if (parts.size() == 0) {
647+
warningstream << "Invalid scrollbaroptions element(" << parts.size() << "): '" <<
648+
element << "'" << std::endl;
649+
return;
650+
}
651+
652+
for (const std::string &i : parts) {
653+
std::vector<std::string> options = split(i, '=');
654+
655+
if (options.size() != 2) {
656+
warningstream << "Invalid scrollbaroptions option syntax: '" <<
657+
element << "'" << std::endl;
658+
continue; // Go to next option
659+
}
660+
661+
if (options[0] == "max") {
662+
data->scrollbar_options.max = stoi(options[1]);
663+
continue;
664+
} else if (options[0] == "min") {
665+
data->scrollbar_options.min = stoi(options[1]);
666+
continue;
667+
} else if (options[0] == "smallstep") {
668+
int value = stoi(options[1]);
669+
data->scrollbar_options.small_step = value < 0 ? 10 : value;
670+
continue;
671+
} else if (options[0] == "largestep") {
672+
int value = stoi(options[1]);
673+
data->scrollbar_options.large_step = value < 0 ? 100 : value;
674+
continue;
675+
} else if (options[0] == "thumbsize") {
676+
int value = stoi(options[1]);
677+
data->scrollbar_options.thumb_size = value <= 0 ? 1 : value;
678+
continue;
679+
} else if (options[0] == "arrows") {
680+
std::string value = trim(options[1]);
681+
if (value == "hide")
682+
data->scrollbar_options.arrow_visiblity = GUIScrollBar::HIDE;
683+
else if (value == "show")
684+
data->scrollbar_options.arrow_visiblity = GUIScrollBar::SHOW;
685+
else // Auto hide/show
686+
data->scrollbar_options.arrow_visiblity = GUIScrollBar::DEFAULT;
687+
continue;
688+
}
689+
690+
warningstream << "Invalid scrollbaroptions option(" << options[0] <<
691+
"): '" << element << "'" << std::endl;
692+
}
633693
}
634694

635695
void GUIFormSpecMenu::parseImage(parserData* data, const std::string &element)
@@ -2591,6 +2651,11 @@ void GUIFormSpecMenu::parseElement(parserData* data, const std::string &element)
25912651
return;
25922652
}
25932653

2654+
if (type == "scrollbaroptions") {
2655+
parseScrollBarOptions(data, description);
2656+
return;
2657+
}
2658+
25942659
// Ignore others
25952660
infostream << "Unknown DrawSpec: type=" << type << ", data=\"" << description << "\""
25962661
<< std::endl;
@@ -2633,24 +2698,18 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
26332698
// Remove children
26342699
removeChildren();
26352700

2636-
for (auto &table_it : m_tables) {
2701+
for (auto &table_it : m_tables)
26372702
table_it.second->drop();
2638-
}
2639-
for (auto &inventorylist_it : m_inventorylists) {
2703+
for (auto &inventorylist_it : m_inventorylists)
26402704
inventorylist_it.e->drop();
2641-
}
2642-
for (auto &checkbox_it : m_checkboxes) {
2705+
for (auto &checkbox_it : m_checkboxes)
26432706
checkbox_it.second->drop();
2644-
}
2645-
for (auto &scrollbar_it : m_scrollbars) {
2707+
for (auto &scrollbar_it : m_scrollbars)
26462708
scrollbar_it.second->drop();
2647-
}
2648-
for (auto &background_it : m_backgrounds) {
2709+
for (auto &background_it : m_backgrounds)
26492710
background_it->drop();
2650-
}
2651-
for (auto &tooltip_rect_it : m_tooltip_rects) {
2711+
for (auto &tooltip_rect_it : m_tooltip_rects)
26522712
tooltip_rect_it.first->drop();
2653-
}
26542713

26552714
mydata.size= v2s32(100,100);
26562715
mydata.screensize = screensize;

‎src/gui/guiFormSpecMenu.h

+12-1
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ class GUIFormSpecMenu : public GUIModalMenu
379379
video::SColor m_default_tooltip_bgcolor;
380380
video::SColor m_default_tooltip_color;
381381

382-
382+
383383
private:
384384
IFormSource *m_form_src;
385385
TextDest *m_text_dst;
@@ -401,6 +401,16 @@ class GUIFormSpecMenu : public GUIModalMenu
401401
std::string focused_fieldname;
402402
GUITable::TableOptions table_options;
403403
GUITable::TableColumns table_columns;
404+
405+
struct {
406+
s32 max = 1000;
407+
s32 min = 0;
408+
s32 small_step = 10;
409+
s32 large_step = 100;
410+
s32 thumb_size = 1;
411+
GUIScrollBar::ArrowVisibility arrow_visiblity = GUIScrollBar::DEFAULT;
412+
} scrollbar_options;
413+
404414
// used to restore table selection/scroll/treeview state
405415
std::unordered_map<std::string, GUITable::DynamicData> table_dyndata;
406416
} parserData;
@@ -455,6 +465,7 @@ class GUIFormSpecMenu : public GUIModalMenu
455465
bool parseVersionDirect(const std::string &data);
456466
bool parseSizeDirect(parserData* data, const std::string &element);
457467
void parseScrollBar(parserData* data, const std::string &element);
468+
void parseScrollBarOptions(parserData *data, const std::string &element);
458469
bool parsePositionDirect(parserData *data, const std::string &element);
459470
void parsePosition(parserData *data, const std::string &element);
460471
bool parseAnchorDirect(parserData *data, const std::string &element);

‎src/gui/guiScrollBar.cpp

+24-3
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ s32 GUIScrollBar::getPosFromMousePos(const core::position2di &pos) const
247247
w = RelativeRect.getHeight() - border_size * 2 - thumb_size;
248248
p = pos.Y - AbsoluteRect.UpperLeftCorner.Y - border_size - offset;
249249
}
250-
return core::isnotzero(range()) ? s32(f32(p) / f32(w) * range()) + min_pos : 0;
250+
return core::isnotzero(range()) ? s32(f32(p) / f32(w) * range() + 0.5f) + min_pos : 0;
251251
}
252252

253253
void GUIScrollBar::setPos(const s32 &pos)
@@ -272,7 +272,8 @@ void GUIScrollBar::setPos(const s32 &pos)
272272

273273
f32 f = core::isnotzero(range()) ? (f32(thumb_area) - f32(thumb_size)) / range()
274274
: 1.0f;
275-
draw_center = s32((f32(scroll_pos) * f) + (f32(thumb_size) * 0.5f)) + border_size;
275+
draw_center = s32((f32(scroll_pos - min_pos) * f) + (f32(thumb_size) * 0.5f)) +
276+
border_size;
276277
}
277278

278279
void GUIScrollBar::setSmallStep(const s32 &step)
@@ -315,6 +316,12 @@ void GUIScrollBar::setPageSize(const s32 &size)
315316
setPos(scroll_pos);
316317
}
317318

319+
void GUIScrollBar::setArrowsVisible(ArrowVisibility visible)
320+
{
321+
arrow_visibility = visible;
322+
refreshControls();
323+
}
324+
318325
s32 GUIScrollBar::getPos() const
319326
{
320327
return scroll_pos;
@@ -419,7 +426,21 @@ void GUIScrollBar::refreshControls()
419426
down_button->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT,
420427
EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT);
421428
}
422-
bool visible = (border_size != 0);
429+
430+
bool visible;
431+
if (arrow_visibility == DEFAULT)
432+
visible = (border_size != 0);
433+
else if (arrow_visibility == HIDE) {
434+
visible = false;
435+
border_size = 0;
436+
} else {
437+
visible = true;
438+
if (is_horizontal)
439+
border_size = RelativeRect.getHeight();
440+
else
441+
border_size = RelativeRect.getWidth();
442+
}
443+
423444
up_button->setVisible(visible);
424445
down_button->setVisible(visible);
425446
}

‎src/gui/guiScrollBar.h

+8
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ class GUIScrollBar : public IGUIElement
2323
GUIScrollBar(IGUIEnvironment *environment, IGUIElement *parent, s32 id,
2424
core::rect<s32> rectangle, bool horizontal, bool auto_scale);
2525

26+
enum ArrowVisibility {
27+
HIDE,
28+
SHOW,
29+
DEFAULT
30+
};
31+
2632
virtual void draw();
2733
virtual void updateAbsolutePosition();
2834
virtual bool OnEvent(const SEvent &event);
@@ -39,6 +45,7 @@ class GUIScrollBar : public IGUIElement
3945
void setLargeStep(const s32 &step);
4046
void setPos(const s32 &pos);
4147
void setPageSize(const s32 &size);
48+
void setArrowsVisible(ArrowVisibility visible);
4249

4350
private:
4451
void refreshControls();
@@ -47,6 +54,7 @@ class GUIScrollBar : public IGUIElement
4754

4855
IGUIButton *up_button;
4956
IGUIButton *down_button;
57+
ArrowVisibility arrow_visibility = DEFAULT;
5058
bool is_dragging;
5159
bool is_horizontal;
5260
bool is_auto_scaling;

0 commit comments

Comments
 (0)
Please sign in to comment.