forked from Mirrorlandia_minetest/minetest
Add scrollbaroptions FormSpec element (#8530)
This commit is contained in:
parent
9a5d43a4f5
commit
4f45bfd08b
@ -2351,16 +2351,40 @@ Elements
|
|||||||
|
|
||||||
### `scrollbar[<X>,<Y>;<W>,<H>;<orientation>;<name>;<value>]`
|
### `scrollbar[<X>,<Y>;<W>,<H>;<orientation>;<name>;<value>]`
|
||||||
|
|
||||||
* Show a scrollbar
|
* Show a scrollbar using options defined by the previous `scrollbaroptions[]`
|
||||||
* There are two ways to use it:
|
* There are two ways to use it:
|
||||||
1. handle the changed event (only changed scrollbar is available)
|
1. handle the changed event (only changed scrollbar is available)
|
||||||
2. read the value on pressing a button (all scrollbars are available)
|
2. read the value on pressing a button (all scrollbars are available)
|
||||||
* `orientation`: `vertical`/`horizontal`
|
* `orientation`: `vertical`/`horizontal`
|
||||||
* Fieldname data is transferred to Lua
|
* Fieldname data is transferred to Lua
|
||||||
* Value this trackbar is set to (`0`-`1000`)
|
* Value of this trackbar is set to (`0`-`1000`) by default
|
||||||
* See also `minetest.explode_scrollbar_event`
|
* See also `minetest.explode_scrollbar_event`
|
||||||
(main menu: `core.explode_scrollbar_event`).
|
(main menu: `core.explode_scrollbar_event`).
|
||||||
|
|
||||||
|
### `scrollbaroptions[opt1;opt2;...]`
|
||||||
|
* Sets options for all following `scrollbar[]` elements
|
||||||
|
* `min=<int>`
|
||||||
|
* Sets scrollbar minimum value, defaults to `0`.
|
||||||
|
* `max=<int>`
|
||||||
|
* Sets scrollbar maximum value, defaults to `1000`.
|
||||||
|
If the max is equal to the min, the scrollbar will be disabled.
|
||||||
|
* `smallstep=<int>`
|
||||||
|
* Sets scrollbar step value when the arrows are clicked or the mouse wheel is
|
||||||
|
scrolled.
|
||||||
|
* If this is set to a negative number, the value will be reset to `10`.
|
||||||
|
* `largestep=<int>`
|
||||||
|
* Sets scrollbar step value used by page up and page down.
|
||||||
|
* If this is set to a negative number, the value will be reset to `100`.
|
||||||
|
* `thumbsize=<int>`
|
||||||
|
* Sets size of the thumb on the scrollbar. Size is calculated in the number of
|
||||||
|
units the thumb spans out of the range of the scrollbar values.
|
||||||
|
* Example: If a scrollbar has a `min` of 1 and a `max` of 100, a thumbsize of 10
|
||||||
|
would span a tenth of the scrollbar space.
|
||||||
|
* If this is set to zero or less, the value will be reset to `1`.
|
||||||
|
* `arrows=<show/hide/default>`
|
||||||
|
* Whether to show the arrow buttons on the scrollbar. `default` hides the arrows
|
||||||
|
when the scrollbar gets too small, but shows them otherwise.
|
||||||
|
|
||||||
### `table[<X>,<Y>;<W>,<H>;<name>;<cell 1>,<cell 2>,...,<cell n>;<selected idx>]`
|
### `table[<X>,<Y>;<W>,<H>;<name>;<cell 1>,<cell 2>,...,<cell n>;<selected idx>]`
|
||||||
|
|
||||||
* Show scrollable table using options defined by the previous `tableoptions[]`
|
* Show scrollable table using options defined by the previous `tableoptions[]`
|
||||||
|
@ -24,6 +24,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include <limits>
|
#include <limits>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include "guiFormSpecMenu.h"
|
#include "guiFormSpecMenu.h"
|
||||||
|
#include "guiScrollBar.h"
|
||||||
|
#include "guiTable.h"
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
#include "gamedef.h"
|
#include "gamedef.h"
|
||||||
#include "client/keycode.h"
|
#include "client/keycode.h"
|
||||||
@ -123,24 +125,18 @@ GUIFormSpecMenu::~GUIFormSpecMenu()
|
|||||||
{
|
{
|
||||||
removeChildren();
|
removeChildren();
|
||||||
|
|
||||||
for (auto &table_it : m_tables) {
|
for (auto &table_it : m_tables)
|
||||||
table_it.second->drop();
|
table_it.second->drop();
|
||||||
}
|
for (auto &inventorylist_it : m_inventorylists)
|
||||||
for (auto &inventorylist_it : m_inventorylists) {
|
|
||||||
inventorylist_it.e->drop();
|
inventorylist_it.e->drop();
|
||||||
}
|
for (auto &checkbox_it : m_checkboxes)
|
||||||
for (auto &checkbox_it : m_checkboxes) {
|
|
||||||
checkbox_it.second->drop();
|
checkbox_it.second->drop();
|
||||||
}
|
for (auto &scrollbar_it : m_scrollbars)
|
||||||
for (auto &scrollbar_it : m_scrollbars) {
|
|
||||||
scrollbar_it.second->drop();
|
scrollbar_it.second->drop();
|
||||||
}
|
for (auto &background_it : m_backgrounds)
|
||||||
for (auto &background_it : m_backgrounds) {
|
|
||||||
background_it->drop();
|
background_it->drop();
|
||||||
}
|
for (auto &tooltip_rect_it : m_tooltip_rects)
|
||||||
for (auto &tooltip_rect_it : m_tooltip_rects) {
|
|
||||||
tooltip_rect_it.first->drop();
|
tooltip_rect_it.first->drop();
|
||||||
}
|
|
||||||
|
|
||||||
delete m_selected_item;
|
delete m_selected_item;
|
||||||
delete m_form_src;
|
delete m_form_src;
|
||||||
@ -614,22 +610,86 @@ void GUIFormSpecMenu::parseScrollBar(parserData* data, const std::string &elemen
|
|||||||
spec.ftype = f_ScrollBar;
|
spec.ftype = f_ScrollBar;
|
||||||
spec.send = true;
|
spec.send = true;
|
||||||
GUIScrollBar *e = new GUIScrollBar(Environment, this, spec.fid, rect,
|
GUIScrollBar *e = new GUIScrollBar(Environment, this, spec.fid, rect,
|
||||||
is_horizontal, false);
|
is_horizontal, true);
|
||||||
|
|
||||||
auto style = getStyleForElement("scrollbar", name);
|
auto style = getStyleForElement("scrollbar", name);
|
||||||
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
|
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
|
||||||
|
e->setArrowsVisible(data->scrollbar_options.arrow_visiblity);
|
||||||
|
|
||||||
|
s32 max = data->scrollbar_options.max;
|
||||||
|
s32 min = data->scrollbar_options.min;
|
||||||
|
|
||||||
|
e->setMax(max);
|
||||||
|
e->setMin(min);
|
||||||
|
|
||||||
e->setMax(1000);
|
|
||||||
e->setMin(0);
|
|
||||||
e->setPos(stoi(parts[4]));
|
e->setPos(stoi(parts[4]));
|
||||||
e->setSmallStep(10);
|
|
||||||
e->setLargeStep(100);
|
e->setSmallStep(data->scrollbar_options.small_step);
|
||||||
|
e->setLargeStep(data->scrollbar_options.large_step);
|
||||||
|
|
||||||
|
s32 scrollbar_size = is_horizontal ? dim.X : dim.Y;
|
||||||
|
|
||||||
|
e->setPageSize(scrollbar_size * (max - min + 1) / data->scrollbar_options.thumb_size);
|
||||||
|
|
||||||
m_scrollbars.emplace_back(spec,e);
|
m_scrollbars.emplace_back(spec,e);
|
||||||
m_fields.push_back(spec);
|
m_fields.push_back(spec);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
errorstream<< "Invalid scrollbar element(" << parts.size() << "): '" << element << "'" << std::endl;
|
errorstream << "Invalid scrollbar element(" << parts.size() << "): '" << element
|
||||||
|
<< "'" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GUIFormSpecMenu::parseScrollBarOptions(parserData* data, const std::string &element)
|
||||||
|
{
|
||||||
|
std::vector<std::string> parts = split(element, ';');
|
||||||
|
|
||||||
|
if (parts.size() == 0) {
|
||||||
|
warningstream << "Invalid scrollbaroptions element(" << parts.size() << "): '" <<
|
||||||
|
element << "'" << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const std::string &i : parts) {
|
||||||
|
std::vector<std::string> options = split(i, '=');
|
||||||
|
|
||||||
|
if (options.size() != 2) {
|
||||||
|
warningstream << "Invalid scrollbaroptions option syntax: '" <<
|
||||||
|
element << "'" << std::endl;
|
||||||
|
continue; // Go to next option
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options[0] == "max") {
|
||||||
|
data->scrollbar_options.max = stoi(options[1]);
|
||||||
|
continue;
|
||||||
|
} else if (options[0] == "min") {
|
||||||
|
data->scrollbar_options.min = stoi(options[1]);
|
||||||
|
continue;
|
||||||
|
} else if (options[0] == "smallstep") {
|
||||||
|
int value = stoi(options[1]);
|
||||||
|
data->scrollbar_options.small_step = value < 0 ? 10 : value;
|
||||||
|
continue;
|
||||||
|
} else if (options[0] == "largestep") {
|
||||||
|
int value = stoi(options[1]);
|
||||||
|
data->scrollbar_options.large_step = value < 0 ? 100 : value;
|
||||||
|
continue;
|
||||||
|
} else if (options[0] == "thumbsize") {
|
||||||
|
int value = stoi(options[1]);
|
||||||
|
data->scrollbar_options.thumb_size = value <= 0 ? 1 : value;
|
||||||
|
continue;
|
||||||
|
} else if (options[0] == "arrows") {
|
||||||
|
std::string value = trim(options[1]);
|
||||||
|
if (value == "hide")
|
||||||
|
data->scrollbar_options.arrow_visiblity = GUIScrollBar::HIDE;
|
||||||
|
else if (value == "show")
|
||||||
|
data->scrollbar_options.arrow_visiblity = GUIScrollBar::SHOW;
|
||||||
|
else // Auto hide/show
|
||||||
|
data->scrollbar_options.arrow_visiblity = GUIScrollBar::DEFAULT;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
warningstream << "Invalid scrollbaroptions option(" << options[0] <<
|
||||||
|
"): '" << element << "'" << std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUIFormSpecMenu::parseImage(parserData* data, const std::string &element)
|
void GUIFormSpecMenu::parseImage(parserData* data, const std::string &element)
|
||||||
@ -2591,6 +2651,11 @@ void GUIFormSpecMenu::parseElement(parserData* data, const std::string &element)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type == "scrollbaroptions") {
|
||||||
|
parseScrollBarOptions(data, description);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Ignore others
|
// Ignore others
|
||||||
infostream << "Unknown DrawSpec: type=" << type << ", data=\"" << description << "\""
|
infostream << "Unknown DrawSpec: type=" << type << ", data=\"" << description << "\""
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
@ -2633,24 +2698,18 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
|
|||||||
// Remove children
|
// Remove children
|
||||||
removeChildren();
|
removeChildren();
|
||||||
|
|
||||||
for (auto &table_it : m_tables) {
|
for (auto &table_it : m_tables)
|
||||||
table_it.second->drop();
|
table_it.second->drop();
|
||||||
}
|
for (auto &inventorylist_it : m_inventorylists)
|
||||||
for (auto &inventorylist_it : m_inventorylists) {
|
|
||||||
inventorylist_it.e->drop();
|
inventorylist_it.e->drop();
|
||||||
}
|
for (auto &checkbox_it : m_checkboxes)
|
||||||
for (auto &checkbox_it : m_checkboxes) {
|
|
||||||
checkbox_it.second->drop();
|
checkbox_it.second->drop();
|
||||||
}
|
for (auto &scrollbar_it : m_scrollbars)
|
||||||
for (auto &scrollbar_it : m_scrollbars) {
|
|
||||||
scrollbar_it.second->drop();
|
scrollbar_it.second->drop();
|
||||||
}
|
for (auto &background_it : m_backgrounds)
|
||||||
for (auto &background_it : m_backgrounds) {
|
|
||||||
background_it->drop();
|
background_it->drop();
|
||||||
}
|
for (auto &tooltip_rect_it : m_tooltip_rects)
|
||||||
for (auto &tooltip_rect_it : m_tooltip_rects) {
|
|
||||||
tooltip_rect_it.first->drop();
|
tooltip_rect_it.first->drop();
|
||||||
}
|
|
||||||
|
|
||||||
mydata.size= v2s32(100,100);
|
mydata.size= v2s32(100,100);
|
||||||
mydata.screensize = screensize;
|
mydata.screensize = screensize;
|
||||||
|
@ -379,7 +379,7 @@ protected:
|
|||||||
video::SColor m_default_tooltip_bgcolor;
|
video::SColor m_default_tooltip_bgcolor;
|
||||||
video::SColor m_default_tooltip_color;
|
video::SColor m_default_tooltip_color;
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IFormSource *m_form_src;
|
IFormSource *m_form_src;
|
||||||
TextDest *m_text_dst;
|
TextDest *m_text_dst;
|
||||||
@ -401,6 +401,16 @@ private:
|
|||||||
std::string focused_fieldname;
|
std::string focused_fieldname;
|
||||||
GUITable::TableOptions table_options;
|
GUITable::TableOptions table_options;
|
||||||
GUITable::TableColumns table_columns;
|
GUITable::TableColumns table_columns;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
s32 max = 1000;
|
||||||
|
s32 min = 0;
|
||||||
|
s32 small_step = 10;
|
||||||
|
s32 large_step = 100;
|
||||||
|
s32 thumb_size = 1;
|
||||||
|
GUIScrollBar::ArrowVisibility arrow_visiblity = GUIScrollBar::DEFAULT;
|
||||||
|
} scrollbar_options;
|
||||||
|
|
||||||
// used to restore table selection/scroll/treeview state
|
// used to restore table selection/scroll/treeview state
|
||||||
std::unordered_map<std::string, GUITable::DynamicData> table_dyndata;
|
std::unordered_map<std::string, GUITable::DynamicData> table_dyndata;
|
||||||
} parserData;
|
} parserData;
|
||||||
@ -455,6 +465,7 @@ private:
|
|||||||
bool parseVersionDirect(const std::string &data);
|
bool parseVersionDirect(const std::string &data);
|
||||||
bool parseSizeDirect(parserData* data, const std::string &element);
|
bool parseSizeDirect(parserData* data, const std::string &element);
|
||||||
void parseScrollBar(parserData* data, const std::string &element);
|
void parseScrollBar(parserData* data, const std::string &element);
|
||||||
|
void parseScrollBarOptions(parserData *data, const std::string &element);
|
||||||
bool parsePositionDirect(parserData *data, const std::string &element);
|
bool parsePositionDirect(parserData *data, const std::string &element);
|
||||||
void parsePosition(parserData *data, const std::string &element);
|
void parsePosition(parserData *data, const std::string &element);
|
||||||
bool parseAnchorDirect(parserData *data, const std::string &element);
|
bool parseAnchorDirect(parserData *data, const std::string &element);
|
||||||
|
@ -247,7 +247,7 @@ s32 GUIScrollBar::getPosFromMousePos(const core::position2di &pos) const
|
|||||||
w = RelativeRect.getHeight() - border_size * 2 - thumb_size;
|
w = RelativeRect.getHeight() - border_size * 2 - thumb_size;
|
||||||
p = pos.Y - AbsoluteRect.UpperLeftCorner.Y - border_size - offset;
|
p = pos.Y - AbsoluteRect.UpperLeftCorner.Y - border_size - offset;
|
||||||
}
|
}
|
||||||
return core::isnotzero(range()) ? s32(f32(p) / f32(w) * range()) + min_pos : 0;
|
return core::isnotzero(range()) ? s32(f32(p) / f32(w) * range() + 0.5f) + min_pos : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUIScrollBar::setPos(const s32 &pos)
|
void GUIScrollBar::setPos(const s32 &pos)
|
||||||
@ -272,7 +272,8 @@ void GUIScrollBar::setPos(const s32 &pos)
|
|||||||
|
|
||||||
f32 f = core::isnotzero(range()) ? (f32(thumb_area) - f32(thumb_size)) / range()
|
f32 f = core::isnotzero(range()) ? (f32(thumb_area) - f32(thumb_size)) / range()
|
||||||
: 1.0f;
|
: 1.0f;
|
||||||
draw_center = s32((f32(scroll_pos) * f) + (f32(thumb_size) * 0.5f)) + border_size;
|
draw_center = s32((f32(scroll_pos - min_pos) * f) + (f32(thumb_size) * 0.5f)) +
|
||||||
|
border_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUIScrollBar::setSmallStep(const s32 &step)
|
void GUIScrollBar::setSmallStep(const s32 &step)
|
||||||
@ -315,6 +316,12 @@ void GUIScrollBar::setPageSize(const s32 &size)
|
|||||||
setPos(scroll_pos);
|
setPos(scroll_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GUIScrollBar::setArrowsVisible(ArrowVisibility visible)
|
||||||
|
{
|
||||||
|
arrow_visibility = visible;
|
||||||
|
refreshControls();
|
||||||
|
}
|
||||||
|
|
||||||
s32 GUIScrollBar::getPos() const
|
s32 GUIScrollBar::getPos() const
|
||||||
{
|
{
|
||||||
return scroll_pos;
|
return scroll_pos;
|
||||||
@ -419,7 +426,21 @@ void GUIScrollBar::refreshControls()
|
|||||||
down_button->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT,
|
down_button->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT,
|
||||||
EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT);
|
EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT);
|
||||||
}
|
}
|
||||||
bool visible = (border_size != 0);
|
|
||||||
|
bool visible;
|
||||||
|
if (arrow_visibility == DEFAULT)
|
||||||
|
visible = (border_size != 0);
|
||||||
|
else if (arrow_visibility == HIDE) {
|
||||||
|
visible = false;
|
||||||
|
border_size = 0;
|
||||||
|
} else {
|
||||||
|
visible = true;
|
||||||
|
if (is_horizontal)
|
||||||
|
border_size = RelativeRect.getHeight();
|
||||||
|
else
|
||||||
|
border_size = RelativeRect.getWidth();
|
||||||
|
}
|
||||||
|
|
||||||
up_button->setVisible(visible);
|
up_button->setVisible(visible);
|
||||||
down_button->setVisible(visible);
|
down_button->setVisible(visible);
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,12 @@ public:
|
|||||||
GUIScrollBar(IGUIEnvironment *environment, IGUIElement *parent, s32 id,
|
GUIScrollBar(IGUIEnvironment *environment, IGUIElement *parent, s32 id,
|
||||||
core::rect<s32> rectangle, bool horizontal, bool auto_scale);
|
core::rect<s32> rectangle, bool horizontal, bool auto_scale);
|
||||||
|
|
||||||
|
enum ArrowVisibility {
|
||||||
|
HIDE,
|
||||||
|
SHOW,
|
||||||
|
DEFAULT
|
||||||
|
};
|
||||||
|
|
||||||
virtual void draw();
|
virtual void draw();
|
||||||
virtual void updateAbsolutePosition();
|
virtual void updateAbsolutePosition();
|
||||||
virtual bool OnEvent(const SEvent &event);
|
virtual bool OnEvent(const SEvent &event);
|
||||||
@ -39,6 +45,7 @@ public:
|
|||||||
void setLargeStep(const s32 &step);
|
void setLargeStep(const s32 &step);
|
||||||
void setPos(const s32 &pos);
|
void setPos(const s32 &pos);
|
||||||
void setPageSize(const s32 &size);
|
void setPageSize(const s32 &size);
|
||||||
|
void setArrowsVisible(ArrowVisibility visible);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void refreshControls();
|
void refreshControls();
|
||||||
@ -47,6 +54,7 @@ private:
|
|||||||
|
|
||||||
IGUIButton *up_button;
|
IGUIButton *up_button;
|
||||||
IGUIButton *down_button;
|
IGUIButton *down_button;
|
||||||
|
ArrowVisibility arrow_visibility = DEFAULT;
|
||||||
bool is_dragging;
|
bool is_dragging;
|
||||||
bool is_horizontal;
|
bool is_horizontal;
|
||||||
bool is_auto_scaling;
|
bool is_auto_scaling;
|
||||||
|
Loading…
Reference in New Issue
Block a user