aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--builtin/mm_menubar.lua4
-rw-r--r--builtin/modstore.lua6
-rw-r--r--doc/lua_api.txt45
-rw-r--r--src/guiFormSpecMenu.cpp261
-rw-r--r--src/guiFormSpecMenu.h12
5 files changed, 259 insertions, 69 deletions
diff --git a/builtin/mm_menubar.lua b/builtin/mm_menubar.lua
index c3ddbb289..a60ea7ae5 100644
--- a/builtin/mm_menubar.lua
+++ b/builtin/mm_menubar.lua
@@ -30,8 +30,8 @@ end
--------------------------------------------------------------------------------
function menubar.refresh()
- menubar.formspec = "box[-0.3,5.625;12.4,1.3;000000]" ..
- "box[-0.3,5.6;12.4,0.05;FFFFFF]"
+ menubar.formspec = "box[-0.3,5.625;12.4,1.3;#000000]" ..
+ "box[-0.3,5.6;12.4,0.05;#FFFFFF]"
menubar.buttons = {}
local button_base = -0.25
diff --git a/builtin/modstore.lua b/builtin/modstore.lua
index 43f7759ad..b364ce6bd 100644
--- a/builtin/modstore.lua
+++ b/builtin/modstore.lua
@@ -183,9 +183,9 @@ function modstore.getmodlist(list)
retval = retval .. "label[10,-0.4;" .. fgettext("Page $1 of $2", list.page+1, list.pagecount) .. "]"
retval = retval .. "button[11.6,-0.1;0.5,0.5;btn_modstore_page_up;^]"
- retval = retval .. "box[11.6,0.35;0.28,8.6;000000]"
+ retval = retval .. "box[11.6,0.35;0.28,8.6;#000000]"
local scrollbarpos = 0.35 + (8.1/(list.pagecount-1)) * list.page
- retval = retval .. "box[11.6," ..scrollbarpos .. ";0.28,0.5;32CD32]"
+ retval = retval .. "box[11.6," ..scrollbarpos .. ";0.28,0.5;#32CD32]"
retval = retval .. "button[11.6,9.0;0.5,0.5;btn_modstore_page_down;v]"
@@ -206,7 +206,7 @@ function modstore.getmodlist(list)
if details ~= nil then
local screenshot_ypos = (i-1 - (list.page * modstore.modsperpage))*1.9 +0.2
- retval = retval .. "box[0," .. screenshot_ypos .. ";11.4,1.75;FFFFFF]"
+ retval = retval .. "box[0," .. screenshot_ypos .. ";11.4,1.75;#FFFFFF]"
--screenshot
if details.screenshot_url ~= nil and
diff --git a/doc/lua_api.txt b/doc/lua_api.txt
index 933050224..689496e22 100644
--- a/doc/lua_api.txt
+++ b/doc/lua_api.txt
@@ -873,6 +873,22 @@ list[<inventory location>;<list name>;<X>,<Y>;<W>,<H>;]
list[<inventory location>;<list name>;<X>,<Y>;<W>,<H>;<starting item index>]
^ Show an inventory list
+listcolors[<slot_bg_normal>;<slot_bg_hover>]
+^ Sets background color of slots in HEX-Color format
+^ Sets background color of slots on mouse hovering
+
+listcolors[<slot_bg_normal>;<slot_bg_hover>;<slot_border>]
+^ Sets background color of slots in HEX-Color format
+^ Sets background color of slots on mouse hovering
+^ Sets color of slots border
+
+listcolors[<slot_bg_normal>;<slot_bg_hover>;<slot_border>;<tooltip_bgcolor>;<tooltip_fontcolor>]
+^ Sets background color of slots in HEX-Color format
+^ Sets background color of slots on mouse hovering
+^ Sets color of slots border
+^ Sets background color of tooltips
+^ Sets font color of tooltips
+
image[<X>,<Y>;<W>,<H>;<texture name>]
^ Show an image
^ Position and size units are inventory slots
@@ -881,11 +897,21 @@ item_image[<X>,<Y>;<W>,<H>;<item name>]
^ Show an inventory image of registered item/node
^ Position and size units are inventory slots
+bgcolor[<color>;<fullscreen>]
+^ Sets background color of formspec in HEX-Color format
+^ If true the background color is drawn fullscreen (does not effect the size of the formspec)
+
background[<X>,<Y>;<W>,<H>;<texture name>]
^ Use a background. Inventory rectangles are not drawn then.
^ Position and size units are inventory slots
^ Example for formspec 8x4 in 16x resolution: image shall be sized 8*16px x 4*16px
+background[<X>,<Y>;<W>,<H>;<texture name>;<auto_clip>]
+^ Use a background. Inventory rectangles are not drawn then.
+^ Position and size units are inventory slots
+^ Example for formspec 8x4 in 16x resolution: image shall be sized 8*16px x 4*16px
+^ If true the background is clipped to formspec size (x and y are used as offset values, w and h are ignored)
+
pwdfield[<X>,<Y>;<W>,<H>;<name>;<label>]
^ Textual password style field; will be sent to server when a button is clicked
^ x and y position the field relative to the top left of the menu
@@ -972,7 +998,7 @@ textlist[<X>,<Y>;<W>,<H>;<name>;<listelem 1>,<listelem 2>,...,<listelem n>]
^ x and y position the itemlist relative to the top left of the menu
^ w and h are the size of the itemlist
^ name fieldname sent to server on doubleclick value is current selected element
-^ listelements can be prepended by #color in hexadecimal format RRGGBB,
+^ listelements can be prepended by #color in hexadecimal format RRGGBB (only),
^ if you want a listelement to start with # write ##
textlist[<X>,<Y>;<W>,<H>;<name>;<listelem 1>,<listelem 2>,...,<listelem n>;<selected idx>;<transparent>]
@@ -980,7 +1006,7 @@ textlist[<X>,<Y>;<W>,<H>;<name>;<listelem 1>,<listelem 2>,...,<listelem n>;<sele
^ x and y position the itemlist relative to the top left of the menu
^ w and h are the size of the itemlist
^ name fieldname sent to server on doubleclick value is current selected element
-^ listelements can be prepended by #RRGGBB in hexadecimal format
+^ listelements can be prepended by #RRGGBB (only) in hexadecimal format
^ if you want a listelement to start with # write ##
^ index to be selected within textlist
^ true/false draw transparent background
@@ -998,7 +1024,7 @@ box[<X>,<Y>;<W>,<H>;<color>]
^ simple colored semitransparent box
^ x and y position the box relative to the top left of the menu
^ w and h are the size of box
-^ color in hexadecimal format RRGGBB
+^ color in HEX-Color format
dropdown[<X>,<Y>;<W>;<name>;<item 1>,<item 2>, ...,<item n>;<selected idx>]
^ show a dropdown field
@@ -1007,7 +1033,7 @@ dropdown[<X>,<Y>;<W>;<name>;<item 1>,<item 2>, ...,<item n>;<selected idx>]
^ fieldname data is transfered to lua
^ items to be shown in dropdown
^ index of currently selected dropdown item
-^ color in hexadecimal format RRGGBB
+^ color in hexadecimal format RRGGBB (only)
checkbox[<X>,<Y>;<name>;<label>;<selected>]
^ show a checkbox
@@ -1027,6 +1053,17 @@ Inventory location:
- "nodemeta:<X>,<Y>,<Z>": Any node metadata
- "detached:<name>": A detached inventory
+HEX-Color
+---------
+#RGB
+^ defines a color in hexadecimal format
+#RGBA
+^ defines a color in hexadecimal format and alpha channel
+#RRGGBB
+^ defines a color in hexadecimal format
+#RRGGBBAA
+^ defines a color in hexadecimal format and alpha channel
+
Vector helpers
---------------
vector.new([x[, y, z]]) -> vector
diff --git a/src/guiFormSpecMenu.cpp b/src/guiFormSpecMenu.cpp
index f3d4568ef..111e17d6c 100644
--- a/src/guiFormSpecMenu.cpp
+++ b/src/guiFormSpecMenu.cpp
@@ -604,7 +604,7 @@ void GUIFormSpecMenu::parseButton(parserData* data,std::string element,std::stri
void GUIFormSpecMenu::parseBackground(parserData* data,std::string element) {
std::vector<std::string> parts = split(element,';');
- if (parts.size() == 3) {
+ if ((parts.size() == 3) || (parts.size() == 4)) {
std::vector<std::string> v_pos = split(parts[0],',');
std::vector<std::string> v_geom = split(parts[1],',');
std::string name = unescape_string(parts[2]);
@@ -620,6 +620,14 @@ void GUIFormSpecMenu::parseBackground(parserData* data,std::string element) {
geom.X = stof(v_geom[0]) * (float)spacing.X;
geom.Y = stof(v_geom[1]) * (float)spacing.Y;
+ if (parts.size() == 4) {
+ m_clipbackground = is_yes(parts[3]);
+ if (m_clipbackground) {
+ pos.X = stoi(v_pos[0]); //acts as offset
+ pos.Y = stoi(v_pos[1]); //acts as offset
+ }
+ }
+
if(data->bp_set != 2)
errorstream<<"WARNING: invalid use of background without a size[] element"<<std::endl;
m_backgrounds.push_back(ImageDrawSpec(name, pos, geom));
@@ -686,16 +694,16 @@ void GUIFormSpecMenu::parseTextList(parserData* data,std::string element) {
e->addItem(narrow_to_wide(unescape_string(items[i])).c_str() +1);
}
else {
- std::string color = items[i].substr(1,6);
+ std::string color = items[i].substr(0,7);
std::wstring toadd =
narrow_to_wide(unescape_string(items[i]).c_str() + 7);
e->addItem(toadd.c_str());
- irr::video::SColor toset;
+ video::SColor tmp_color;
- if (parseColor(color, toset))
- e->setItemOverrideColor(i,toset);
+ if (parseColor(color, tmp_color, false))
+ e->setItemOverrideColor(i,tmp_color);
}
}
else {
@@ -1329,7 +1337,6 @@ void GUIFormSpecMenu::parseBox(parserData* data,std::string element) {
if (parts.size() == 3) {
std::vector<std::string> v_pos = split(parts[0],',');
std::vector<std::string> v_geom = split(parts[1],',');
- std::string color_str = parts[2];
MY_CHECKPOS("box",0);
MY_CHECKGEOM("box",1);
@@ -1342,10 +1349,10 @@ void GUIFormSpecMenu::parseBox(parserData* data,std::string element) {
geom.X = stof(v_geom[0]) * (float)spacing.X;
geom.Y = stof(v_geom[1]) * (float)spacing.Y;
- irr::video::SColor color;
+ video::SColor tmp_color;
- if (parseColor(color_str, color)) {
- BoxDrawSpec spec(pos,geom,color);
+ if (parseColor(parts[2], tmp_color, false)) {
+ BoxDrawSpec spec(pos, geom, tmp_color);
m_boxes.push_back(spec);
}
@@ -1357,6 +1364,46 @@ void GUIFormSpecMenu::parseBox(parserData* data,std::string element) {
errorstream<< "Invalid Box element(" << parts.size() << "): '" << element << "'" << std::endl;
}
+void GUIFormSpecMenu::parseBackgroundColor(parserData* data,std::string element) {
+ std::vector<std::string> parts = split(element,';');
+
+ if ((parts.size() == 1) || (parts.size() == 2)) {
+ parseColor(parts[0],m_bgcolor,false);
+
+ if (parts.size() == 2) {
+ std::string fullscreen = parts[1];
+ m_bgfullscreen = is_yes(fullscreen);
+ }
+ return;
+ }
+ errorstream<< "Invalid bgcolor element(" << parts.size() << "): '" << element << "'" << std::endl;
+}
+
+void GUIFormSpecMenu::parseListColors(parserData* data,std::string element) {
+ std::vector<std::string> parts = split(element,';');
+
+ if (parts.size() == 2) || (parts.size() == 3) || (parts.size() == 5)) {
+ parseColor(parts[0], m_slotbg_n, false);
+ parseColor(parts[1], m_slotbg_h, false);
+
+ if (parts.size() >= 3) {
+ if (parseColor(parts[2], m_slotbordercolor, false)) {
+ m_slotborder = true;
+ }
+ }
+ if (parts.size() == 5) {
+ video::SColor tmp_color;
+
+ if (parseColor(parts[3], tmp_color, false))
+ m_tooltip_element->setBackgroundColor(tmp_color);
+ if (parseColor(parts[4], tmp_color, false))
+ m_tooltip_element->setOverrideColor(tmp_color);
+ }
+ return;
+ }
+ errorstream<< "Invalid listcolors element(" << parts.size() << "): '" << element << "'" << std::endl;
+}
+
void GUIFormSpecMenu::parseElement(parserData* data,std::string element) {
//some prechecks
@@ -1467,6 +1514,16 @@ void GUIFormSpecMenu::parseElement(parserData* data,std::string element) {
return;
}
+ if (type == "bgcolor") {
+ parseBackgroundColor(data,description);
+ return;
+ }
+
+ if (type == "listcolors") {
+ parseListColors(data,description);
+ return;
+ }
+
// Ignore others
infostream
<< "Unknown DrawSpec: type="<<type<<", data=\""<<description<<"\""
@@ -1537,6 +1594,32 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
m_fields.clear();
m_boxes.clear();
+ // Set default values (fits old formspec values)
+ m_bgcolor = video::SColor(140,0,0,0);
+ m_bgfullscreen = false;
+
+ m_slotbg_n = video::SColor(255,128,128,128);
+ m_slotbg_h = video::SColor(255,192,192,192);
+
+ m_slotbordercolor = video::SColor(200,0,0,0);
+ m_slotborder = false;
+
+ m_clipbackground = false;
+ // Add tooltip
+ {
+ // Note: parent != this so that the tooltip isn't clipped by the menu rectangle
+ m_tooltip_element = Environment->addStaticText(L"",core::rect<s32>(0,0,110,18));
+ m_tooltip_element->enableOverrideColor(true);
+ m_tooltip_element->setBackgroundColor(video::SColor(255,110,130,60));
+ m_tooltip_element->setDrawBackground(true);
+ m_tooltip_element->setDrawBorder(true);
+ m_tooltip_element->setOverrideColor(video::SColor(255,255,255,255));
+ m_tooltip_element->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
+ m_tooltip_element->setWordWrap(false);
+ //we're not parent so no autograb for this one!
+ m_tooltip_element->grab();
+ }
+
std::vector<std::string> elements = split(m_formspec_string,']');
@@ -1544,18 +1627,6 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
parseElement(&mydata,elements[i]);
}
- // If there's inventory, put the usage string at the bottom
- if (m_inventorylists.size())
- {
- changeCtype("");
- core::rect<s32> rect(0, 0, mydata.size.X-padding.X*2, mydata.helptext_h);
- rect = rect + v2s32((mydata.size.X/2 - mydata.rect.getWidth()/2) +5,
- mydata.size.Y-5-mydata.helptext_h);
- const wchar_t *text = wgettext("Left click: Move all items, Right click: Move single item");
- Environment->addStaticText(text, rect, false, true, this, 256);
- delete[] text;
- changeCtype("C");
- }
// If there's fields, add a Proceed button
if (m_fields.size() && mydata.bp_set != 2)
{
@@ -1583,20 +1654,6 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
}
changeCtype("C");
}
- // Add tooltip
- {
- // Note: parent != this so that the tooltip isn't clipped by the menu rectangle
- m_tooltip_element = Environment->addStaticText(L"",core::rect<s32>(0,0,110,18));
- m_tooltip_element->enableOverrideColor(true);
- m_tooltip_element->setBackgroundColor(video::SColor(255,110,130,60));
- m_tooltip_element->setDrawBackground(true);
- m_tooltip_element->setDrawBorder(true);
- m_tooltip_element->setOverrideColor(video::SColor(255,255,255,255));
- m_tooltip_element->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
- m_tooltip_element->setWordWrap(false);
- //we're not parent so no autograb for this one!
- m_tooltip_element->grab();
- }
//set initial focus if parser didn't set it
focused_element = Environment->getFocus();
@@ -1681,16 +1738,31 @@ void GUIFormSpecMenu::drawList(const ListDrawSpec &s, int phase)
if(phase == 0)
{
- if(hovering && m_selected_item)
- {
- video::SColor bgcolor(255,192,192,192);
- driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
- }
+ if(hovering)
+ driver->draw2DRectangle(m_slotbg_h, rect, &AbsoluteClippingRect);
else
- {
- video::SColor bgcolor(255,128,128,128);
- driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
- }
+ driver->draw2DRectangle(m_slotbg_n, rect, &AbsoluteClippingRect);
+ }
+
+ //Draw inv slot borders
+ if (m_slotborder) {
+ s32 x1 = rect.UpperLeftCorner.X;
+ s32 y1 = rect.UpperLeftCorner.Y;
+ s32 x2 = rect.LowerRightCorner.X;
+ s32 y2 = rect.LowerRightCorner.Y;
+ s32 border = 1;
+ driver->draw2DRectangle(m_slotbordercolor,
+ core::rect<s32>(v2s32(x1 - border, y1 - border),
+ v2s32(x2 + border, y1)), NULL);
+ driver->draw2DRectangle(m_slotbordercolor,
+ core::rect<s32>(v2s32(x1 - border, y2),
+ v2s32(x2 + border, y2 + border)), NULL);
+ driver->draw2DRectangle(m_slotbordercolor,
+ core::rect<s32>(v2s32(x1 - border, y1),
+ v2s32(x1, y2)), NULL);
+ driver->draw2DRectangle(m_slotbordercolor,
+ core::rect<s32>(v2s32(x2, y1),
+ v2s32(x2 + border, y2)), NULL);
}
if(phase == 1)
@@ -1771,8 +1843,12 @@ void GUIFormSpecMenu::drawMenu()
return;
video::IVideoDriver* driver = Environment->getVideoDriver();
- video::SColor bgcolor(140,0,0,0);
- driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);
+ v2u32 screenSize = driver->getScreenSize();
+ core::rect<s32> allbg(0, 0, screenSize.X , screenSize.Y);
+ if (m_bgfullscreen)
+ driver->draw2DRectangle(m_bgcolor, allbg, &allbg);
+ else
+ driver->draw2DRectangle(m_bgcolor, AbsoluteRect, &AbsoluteClippingRect);
m_tooltip_element->setVisible(false);
@@ -1789,6 +1865,15 @@ void GUIFormSpecMenu::drawMenu()
core::rect<s32> imgrect(0, 0, spec.geom.X, spec.geom.Y);
// Image rectangle on screen
core::rect<s32> rect = imgrect + spec.pos;
+
+ if (m_clipbackground) {
+ core::dimension2d<s32> absrec_size = AbsoluteRect.getSize();
+ rect = core::rect<s32>(AbsoluteRect.UpperLeftCorner.X - spec.pos.X,
+ AbsoluteRect.UpperLeftCorner.Y - spec.pos.Y,
+ AbsoluteRect.UpperLeftCorner.X + absrec_size.Width + spec.pos.X*2,
+ AbsoluteRect.UpperLeftCorner.Y + absrec_size.Height + spec.pos.Y*2);
+ }
+
const video::SColor color(255,255,255,255);
const video::SColor colors[] = {color,color,color,color};
driver->draw2DImage(texture, rect,
@@ -1880,10 +1965,8 @@ void GUIFormSpecMenu::drawMenu()
Draw items
Phase 0: Item slot rectangles
Phase 1: Item images; prepare tooltip
- If backgrounds used, do not draw Item slot rectangles
*/
int start_phase=0;
- if (m_backgrounds.size() > 0) start_phase=1;
for(int phase=start_phase; phase<=1; phase++)
for(u32 i=0; i<m_inventorylists.size(); i++)
{
@@ -2643,18 +2726,78 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
return Parent ? Parent->OnEvent(event) : false;
}
-bool GUIFormSpecMenu::parseColor(std::string color, irr::video::SColor& outcolor) {
- outcolor = irr::video::SColor(0,0,0,0);
-
- if (!string_allowed(color, "0123456789abcdefABCDEF"))
+static inline bool hex_digit_decode(char hexdigit, unsigned char &value)
+{
+ if(hexdigit >= '0' && hexdigit <= '9')
+ value = hexdigit - '0';
+ else if(hexdigit >= 'A' && hexdigit <= 'F')
+ value = hexdigit - 'A' + 10;
+ else if(hexdigit >= 'a' && hexdigit <= 'f')
+ value = hexdigit - 'a' + 10;
+ else
return false;
+ return true;
+}
- u32 color_value;
- std::istringstream iss(color);
- iss >> std::hex >> color_value;
-
- outcolor = irr::video::SColor(color_value);
+bool GUIFormSpecMenu::parseColor(std::string &value, video::SColor &color, bool quiet)
+{
+ const char *hexpattern = NULL;
+ if (value[0] == '#') {
+ if (value.size() == 9)
+ hexpattern = "#RRGGBBAA";
+ else if (value.size() == 7)
+ hexpattern = "#RRGGBB";
+ else if (value.size() == 5)
+ hexpattern = "#RGBA";
+ else if (value.size() == 4)
+ hexpattern = "#RGB";
+ }
+
+ if (hexpattern) {
+ assert(strlen(hexpattern) == value.size());
+ video::SColor outcolor(255, 255, 255, 255);
+ for (size_t pos = 0; pos < value.size(); ++pos) {
+ // '#' in the pattern means skip that character
+ if (hexpattern[pos] == '#')
+ continue;
- outcolor.setAlpha(255);
- return true;
+ // Else assume hexpattern[pos] is one of 'R' 'G' 'B' 'A'
+ // Read one or two digits, depending on hexpattern
+ unsigned char c1, c2;
+ if (hexpattern[pos+1] == hexpattern[pos]) {
+ // Two digits, e.g. hexpattern == "#RRGGBB"
+ if (!hex_digit_decode(value[pos], c1) ||
+ !hex_digit_decode(value[pos+1], c2))
+ goto fail;
+ ++pos;
+ }
+ else {
+ // One digit, e.g. hexpattern == "#RGB"
+ if (!hex_digit_decode(value[pos], c1))
+ goto fail;
+ c2 = c1;
+ }
+ u32 colorpart = ((c1 & 0x0f) << 4) | (c2 & 0x0f);
+
+ // Update outcolor with newly read color part
+ if (hexpattern[pos] == 'R')
+ outcolor.setRed(colorpart);
+ else if (hexpattern[pos] == 'G')
+ outcolor.setGreen(colorpart);
+ else if (hexpattern[pos] == 'B')
+ outcolor.setBlue(colorpart);
+ else if (hexpattern[pos] == 'A')
+ outcolor.setAlpha(colorpart);
+ }
+
+ color = outcolor;
+ return true;
+ }
+
+ // Optionally, named colors could be implemented here
+
+fail:
+ if (!quiet)
+ errorstream<<"Invalid color: \""<<value<<"\""<<std::endl;
+ return false;
}
diff --git a/src/guiFormSpecMenu.h b/src/guiFormSpecMenu.h
index 20ab52e8b..8b0e50379 100644
--- a/src/guiFormSpecMenu.h
+++ b/src/guiFormSpecMenu.h
@@ -285,6 +285,14 @@ protected:
bool m_allowclose;
bool m_lock;
v2u32 m_lockscreensize;
+
+ bool m_bgfullscreen;
+ bool m_slotborder;
+ bool m_clipbackground;
+ video::SColor m_bgcolor;
+ video::SColor m_slotbg_n;
+ video::SColor m_slotbg_h;
+ video::SColor m_slotbordercolor;
private:
typedef struct {
v2s32 size;
@@ -334,8 +342,10 @@ private:
void parseItemImageButton(parserData* data,std::string element);
void parseTabHeader(parserData* data,std::string element);
void parseBox(parserData* data,std::string element);
+ void parseBackgroundColor(parserData* data,std::string element);
+ void parseListColors(parserData* data,std::string element);
- bool parseColor(std::string color, irr::video::SColor& outcolor);
+ bool parseColor(std::string &value, video::SColor &color, bool quiet);
};
class FormspecFormSource: public IFormSource