3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include "guiFormSpecMenu.h"
27 #include "constants.h"
31 #include <IGUICheckBox.h>
32 #include <IGUIEditBox.h>
33 #include <IGUIButton.h>
34 #include <IGUIStaticText.h>
36 #include <IGUIListBox.h>
37 #include <IGUITabControl.h>
38 #include <IGUIScrollBar.h>
39 #include <IGUIComboBox.h>
41 #include "tile.h" // ITextureSource
42 #include "util/string.h"
43 #include "util/numeric.h"
49 #define MY_CHECKPOS(a,b) \
50 if (v_pos.size() != 2) { \
51 errorstream<< "Invalid pos for element " << a << "specified: \"" \
52 << parts[b] << "\"" << std::endl; \
56 #define MY_CHECKGEOM(a,b) \
57 if (v_geom.size() != 2) { \
58 errorstream<< "Invalid pos for element " << a << "specified: \"" \
59 << parts[b] << "\"" << std::endl; \
64 void drawItemStack(video::IVideoDriver *driver,
66 const ItemStack &item,
67 const core::rect<s32> &rect,
68 const core::rect<s32> *clip,
74 const ItemDefinition &def = item.getDefinition(gamedef->idef());
75 video::ITexture *texture = gamedef->idef()->getInventoryTexture(def.name, gamedef);
77 // Draw the inventory texture
80 const video::SColor color(255,255,255,255);
81 const video::SColor colors[] = {color,color,color,color};
82 driver->draw2DImage(texture, rect,
83 core::rect<s32>(core::position2d<s32>(0,0),
84 core::dimension2di(texture->getOriginalSize())),
88 if(def.type == ITEM_TOOL && item.wear != 0)
91 float barheight = rect.getHeight()/16;
92 float barpad_x = rect.getWidth()/16;
93 float barpad_y = rect.getHeight()/16;
94 core::rect<s32> progressrect(
95 rect.UpperLeftCorner.X + barpad_x,
96 rect.LowerRightCorner.Y - barpad_y - barheight,
97 rect.LowerRightCorner.X - barpad_x,
98 rect.LowerRightCorner.Y - barpad_y);
100 // Shrink progressrect by amount of tool damage
101 float wear = item.wear / 65535.0;
103 wear * progressrect.UpperLeftCorner.X +
104 (1-wear) * progressrect.LowerRightCorner.X;
106 // Compute progressbar color
108 // wear = 0.5: yellow
110 video::SColor color(255,255,255,255);
111 int wear_i = MYMIN(floor(wear * 600), 511);
112 wear_i = MYMIN(wear_i + 10, 511);
114 color.set(255, wear_i, 255, 0);
116 color.set(255, 255, 511-wear_i, 0);
118 core::rect<s32> progressrect2 = progressrect;
119 progressrect2.LowerRightCorner.X = progressmid;
120 driver->draw2DRectangle(color, progressrect2, clip);
122 color = video::SColor(255,0,0,0);
123 progressrect2 = progressrect;
124 progressrect2.UpperLeftCorner.X = progressmid;
125 driver->draw2DRectangle(color, progressrect2, clip);
128 if(font != NULL && item.count >= 2)
130 // Get the item count as a string
131 std::string text = itos(item.count);
132 v2u32 dim = font->getDimension(narrow_to_wide(text).c_str());
133 v2s32 sdim(dim.X,dim.Y);
135 core::rect<s32> rect2(
136 /*rect.UpperLeftCorner,
137 core::dimension2d<u32>(rect.getWidth(), 15)*/
138 rect.LowerRightCorner - sdim,
142 video::SColor bgcolor(128,0,0,0);
143 driver->draw2DRectangle(bgcolor, rect2, clip);
145 video::SColor color(255,255,255,255);
146 font->draw(text.c_str(), rect2, color, false, false, clip);
154 GUIFormSpecMenu::GUIFormSpecMenu(irr::IrrlichtDevice* dev,
155 gui::IGUIElement* parent, s32 id,
156 IMenuManager *menumgr,
157 InventoryManager *invmgr,
160 GUIModalMenu(dev->getGUIEnvironment(), parent, id, menumgr),
166 m_selected_item(NULL),
167 m_selected_amount(0),
168 m_selected_dragging(false),
169 m_tooltip_element(NULL),
171 m_use_gettext(false),
176 GUIFormSpecMenu::~GUIFormSpecMenu()
180 delete m_selected_item;
185 void GUIFormSpecMenu::removeChildren()
187 const core::list<gui::IGUIElement*> &children = getChildren();
188 core::list<gui::IGUIElement*> children_copy;
189 for(core::list<gui::IGUIElement*>::ConstIterator
190 i = children.begin(); i != children.end(); i++)
192 children_copy.push_back(*i);
194 for(core::list<gui::IGUIElement*>::Iterator
195 i = children_copy.begin();
196 i != children_copy.end(); i++)
201 gui::IGUIElement *e = getElementFromId(256);
205 if(m_tooltip_element)
207 m_tooltip_element->remove();
208 m_tooltip_element = NULL;
212 int GUIFormSpecMenu::getListboxIndex(std::string listboxname) {
214 std::wstring wlistboxname = narrow_to_wide(listboxname.c_str());
216 for(unsigned int i=0; i < m_listboxes.size(); i++) {
218 std::wstring name(m_listboxes[i].first.fname.c_str());
219 if ( name == wlistboxname) {
220 return m_listboxes[i].second->getSelected();
226 std::vector<std::string> split(const std::string &s, char delim, bool escape=false) {
227 std::vector<std::string> tokens;
231 size_t nextpos = s.find(delim);
233 while(nextpos != std::string::npos) {
234 std::string toadd = s.substr(startpos,nextpos-startpos);
235 tokens.push_back(toadd);
236 startpos = nextpos+1;
237 nextpos = s.find(delim,nextpos+1);
241 tokens.push_back(s.substr(startpos));
244 std::string current = "";
245 current += s.c_str()[0];
246 bool last_was_delim = false;
247 for(unsigned int i=1; i < s.size(); i++) {
248 if (last_was_delim) {
249 if (s.c_str()[i] == delim) {
250 current += s.c_str()[i];
251 last_was_delim = false;
254 tokens.push_back(current);
257 current += s.c_str()[i];
258 last_was_delim = false;
262 if (s.c_str()[i] == delim) {
263 last_was_delim = true;
266 last_was_delim = false;
267 current += s.c_str()[i];
272 tokens.push_back(current);
278 void GUIFormSpecMenu::parseSize(parserData* data,std::string element) {
279 std::vector<std::string> parts = split(element,',');
281 if (parts.size() == 2) {
284 if (parts[1].find(';') != std::string::npos)
285 parts[1] = parts[1].substr(0,parts[1].find(';'));
287 invsize.X = stof(parts[0]);
288 invsize.Y = stof(parts[1]);
290 infostream<<"Form size ("<<invsize.X<<","<<invsize.Y<<")"<<std::endl;
293 v2u32 current_screensize = m_device->getVideoDriver()->getScreenSize();
294 v2u32 delta = current_screensize - m_lockscreensize;
296 if (current_screensize.Y > m_lockscreensize.Y)
301 if (current_screensize.X > m_lockscreensize.X)
306 offset = v2s32(delta.X,delta.Y);
308 data->screensize = m_lockscreensize;
314 padding = v2s32(data->screensize.Y/40, data->screensize.Y/40);
315 spacing = v2s32(data->screensize.Y/12, data->screensize.Y/13);
316 imgsize = v2s32(data->screensize.Y/15, data->screensize.Y/15);
318 padding.X*2+spacing.X*(invsize.X-1.0)+imgsize.X,
319 padding.Y*2+spacing.Y*(invsize.Y-1.0)+imgsize.Y + (data->helptext_h-5)
321 data->rect = core::rect<s32>(
322 data->screensize.X/2 - data->size.X/2 + offset.X,
323 data->screensize.Y/2 - data->size.Y/2 + offset.Y,
324 data->screensize.X/2 + data->size.X/2 + offset.X,
325 data->screensize.Y/2 + data->size.Y/2 + offset.Y
328 DesiredRect = data->rect;
329 recalculateAbsolutePosition(false);
330 data->basepos = getBasePos();
334 errorstream<< "Invalid size element (" << parts.size() << "): '" << element << "'" << std::endl;
337 void GUIFormSpecMenu::parseList(parserData* data,std::string element) {
339 if (m_gamedef == 0) {
340 errorstream<<"WARNING: invalid use of 'list' with m_gamedef==0"<<std::endl;
344 std::vector<std::string> parts = split(element,';');
346 if ((parts.size() == 4) || (parts.size() == 5)) {
347 std::string location = parts[0];
348 std::string listname = parts[1];
349 std::vector<std::string> v_pos = split(parts[2],',');
350 std::vector<std::string> v_geom = split(parts[3],',');
351 std::string startindex = "";
352 if (parts.size() == 5)
353 startindex = parts[4];
355 MY_CHECKPOS("list",2);
356 MY_CHECKGEOM("list",3);
358 InventoryLocation loc;
360 if(location == "context" || location == "current_name")
361 loc = m_current_inventory_location;
363 loc.deSerialize(location);
365 v2s32 pos = padding + AbsoluteRect.UpperLeftCorner;
366 pos.X += stof(v_pos[0]) * (float)spacing.X;
367 pos.Y += stof(v_pos[1]) * (float)spacing.Y;
370 geom.X = stoi(v_geom[0]);
371 geom.Y = stoi(v_geom[1]);
372 infostream<<"list inv="<<location<<", listname="<<listname
373 <<", pos=("<<pos.X<<","<<pos.Y<<")"
374 <<", geom=("<<geom.X<<","<<geom.Y<<")"
379 start_i = stoi(startindex);
380 if(data->bp_set != 2)
381 errorstream<<"WARNING: invalid use of list without a size[] element"<<std::endl;
382 m_inventorylists.push_back(ListDrawSpec(loc, listname, pos, geom, start_i));
385 errorstream<< "Invalid list element(" << parts.size() << "): '" << element << "'" << std::endl;
388 void GUIFormSpecMenu::parseCheckbox(parserData* data,std::string element) {
389 std::vector<std::string> parts = split(element,';');
391 if ((parts.size() == 3) || (parts.size() == 4)) {
392 std::vector<std::string> v_pos = split(parts[0],',');
393 std::string name = parts[1];
394 std::string label = parts[2];
395 std::string selected = "";
397 if (parts.size() == 4)
400 MY_CHECKPOS("checkbox",0);
403 pos.X += stof(v_pos[0]) * (float) spacing.X;
404 pos.Y += stof(v_pos[1]) * (float) spacing.Y;
406 core::rect<s32> rect = core::rect<s32>(pos.X, pos.Y+((imgsize.Y/2)-15), pos.X+300, pos.Y+((imgsize.Y/2)+15));
408 bool fselected = false;
410 if (selected == "true")
416 wlabel = wgettext(label.c_str());
418 wlabel = (wchar_t*) narrow_to_wide(label.c_str()).c_str();
420 FieldSpec spec = FieldSpec(
421 narrow_to_wide(name.c_str()),
427 spec.ftype = f_CheckBox;
429 gui::IGUICheckBox* e = Environment->addCheckBox(fselected, rect, this,
432 m_checkboxes.push_back(std::pair<FieldSpec,gui::IGUICheckBox*>(spec,e));
433 m_fields.push_back(spec);
438 errorstream<< "Invalid checkbox element(" << parts.size() << "): '" << element << "'" << std::endl;
441 void GUIFormSpecMenu::parseImage(parserData* data,std::string element) {
442 std::vector<std::string> parts = split(element,';');
444 if (parts.size() == 3) {
445 std::vector<std::string> v_pos = split(parts[0],',');
446 std::vector<std::string> v_geom = split(parts[1],',');
447 std::string name = parts[2];
449 MY_CHECKPOS("image",0);
450 MY_CHECKGEOM("image",1);
452 v2s32 pos = padding + AbsoluteRect.UpperLeftCorner;
453 pos.X += stof(v_pos[0]) * (float) spacing.X;
454 pos.Y += stof(v_pos[1]) * (float) spacing.Y;
457 geom.X = stoi(v_geom[0]) * (float)imgsize.X;
458 geom.Y = stoi(v_geom[1]) * (float)imgsize.Y;
460 infostream<<"image name="<<name
461 <<", pos=("<<pos.X<<","<<pos.Y<<")"
462 <<", geom=("<<geom.X<<","<<geom.Y<<")"
464 if(data->bp_set != 2)
465 errorstream<<"WARNING: invalid use of image without a size[] element"<<std::endl;
466 m_images.push_back(ImageDrawSpec(name, pos, geom));
470 if (parts.size() == 2) {
471 std::vector<std::string> v_pos = split(parts[0],',');
472 std::string name = parts[1];
474 MY_CHECKPOS("image",0);
476 v2s32 pos = padding + AbsoluteRect.UpperLeftCorner;
477 pos.X += stof(v_pos[0]) * (float) spacing.X;
478 pos.Y += stof(v_pos[1]) * (float) spacing.Y;
480 std::cout<<"image name="<<name
481 <<", pos=("<<pos.X<<","<<pos.Y<<")"
483 if(data->bp_set != 2)
484 errorstream<<"WARNING: invalid use of image without a size[] element"<<std::endl;
485 m_images.push_back(ImageDrawSpec(name, pos));
488 errorstream<< "Invalid image element(" << parts.size() << "): '" << element << "'" << std::endl;
491 void GUIFormSpecMenu::parseItemImage(parserData* data,std::string element) {
492 std::vector<std::string> parts = split(element,';');
494 if (parts.size() == 3) {
495 std::vector<std::string> v_pos = split(parts[0],',');
496 std::vector<std::string> v_geom = split(parts[1],',');
497 std::string name = parts[2];
499 MY_CHECKPOS("itemimage",0);
500 MY_CHECKGEOM("itemimage",1);
502 v2s32 pos = padding + AbsoluteRect.UpperLeftCorner;
503 pos.X += stof(v_pos[0]) * (float) spacing.X;
504 pos.Y += stof(v_pos[1]) * (float) spacing.Y;
507 geom.X = stoi(v_geom[0]) * (float)imgsize.X;
508 geom.Y = stoi(v_geom[1]) * (float)imgsize.Y;
510 infostream<<"item name="<<name
511 <<", pos=("<<pos.X<<","<<pos.Y<<")"
512 <<", geom=("<<geom.X<<","<<geom.Y<<")"
514 if(data->bp_set != 2)
515 errorstream<<"WARNING: invalid use of item_image without a size[] element"<<std::endl;
516 m_itemimages.push_back(ImageDrawSpec(name, pos, geom));
519 errorstream<< "Invalid ItemImage element(" << parts.size() << "): '" << element << "'" << std::endl;
522 void GUIFormSpecMenu::parseButton(parserData* data,std::string element,std::string type) {
523 std::vector<std::string> parts = split(element,';');
525 if (parts.size() == 4) {
526 std::vector<std::string> v_pos = split(parts[0],',');
527 std::vector<std::string> v_geom = split(parts[1],',');
528 std::string name = parts[2];
529 std::string label = parts[3];
531 MY_CHECKPOS("button",0);
532 MY_CHECKGEOM("button",1);
535 pos.X += stof(v_pos[0]) * (float)spacing.X;
536 pos.Y += stof(v_pos[1]) * (float)spacing.Y;
539 geom.X = (stof(v_geom[0]) * (float)spacing.X)-(spacing.X-imgsize.X);
540 pos.Y += (stof(v_geom[1]) * (float)imgsize.Y)/2;
542 core::rect<s32> rect = core::rect<s32>(pos.X, pos.Y-15, pos.X+geom.X, pos.Y+15);
544 if(data->bp_set != 2)
545 errorstream<<"WARNING: invalid use of button without a size[] element"<<std::endl;
547 label = unescape_string(label);
552 wlabel = wgettext(label.c_str());
554 wlabel = (wchar_t*) narrow_to_wide(label.c_str()).c_str();
556 FieldSpec spec = FieldSpec(
557 narrow_to_wide(name.c_str()),
562 spec.ftype = f_Button;
563 if(type == "button_exit")
566 Environment->addButton(rect, this, spec.fid, spec.flabel.c_str());
567 m_fields.push_back(spec);
572 errorstream<< "Invalid button element(" << parts.size() << "): '" << element << "'" << std::endl;
575 void GUIFormSpecMenu::parseBackground(parserData* data,std::string element) {
576 std::vector<std::string> parts = split(element,';');
578 if (parts.size() == 3) {
579 std::vector<std::string> v_pos = split(parts[0],',');
580 std::vector<std::string> v_geom = split(parts[1],',');
581 std::string name = parts[2];
583 MY_CHECKPOS("background",0);
584 MY_CHECKGEOM("background",1);
586 v2s32 pos = padding + AbsoluteRect.UpperLeftCorner;
587 pos.X += stof(v_pos[0]) * (float)spacing.X - ((float)spacing.X-(float)imgsize.X)/2;
588 pos.Y += stof(v_pos[1]) * (float)spacing.Y - ((float)spacing.Y-(float)imgsize.Y)/2;
591 geom.X = stof(v_geom[0]) * (float)spacing.X;
592 geom.Y = stof(v_geom[1]) * (float)spacing.Y;
594 infostream<<"image name="<<name
595 <<", pos=("<<pos.X<<","<<pos.Y<<")"
596 <<", geom=("<<geom.X<<","<<geom.Y<<")"
598 if(data->bp_set != 2)
599 errorstream<<"WARNING: invalid use of background without a size[] element"<<std::endl;
600 m_backgrounds.push_back(ImageDrawSpec(name, pos, geom));
603 errorstream<< "Invalid background element(" << parts.size() << "): '" << element << "'" << std::endl;
606 void GUIFormSpecMenu::parseTextList(parserData* data,std::string element) {
607 std::vector<std::string> parts = split(element,';');
609 if ((parts.size() == 5) || (parts.size() == 6)) {
610 std::vector<std::string> v_pos = split(parts[0],',');
611 std::vector<std::string> v_geom = split(parts[1],',');
612 std::string name = parts[2];
613 std::vector<std::string> items = split(parts[3],',');
614 std::string str_initial_selection = "";
615 std::string str_transparent = "false";
617 if (parts.size() >= 5)
618 str_initial_selection = parts[4];
620 if (parts.size() >= 6)
621 str_transparent = parts[5];
623 MY_CHECKPOS("textlist",0);
624 MY_CHECKGEOM("textlist",1);
627 pos.X += stof(v_pos[0]) * (float)spacing.X;
628 pos.Y += stof(v_pos[1]) * (float)spacing.Y;
631 geom.X = stof(v_geom[0]) * (float)spacing.X;
632 geom.Y = stof(v_geom[1]) * (float)spacing.Y;
635 core::rect<s32> rect = core::rect<s32>(pos.X, pos.Y, pos.X+geom.X, pos.Y+geom.Y);
637 std::wstring fname_w = narrow_to_wide(name.c_str());
639 FieldSpec spec = FieldSpec(
646 spec.ftype = f_ListBox;
648 //now really show list
649 gui::IGUIListBox *e = Environment->addListBox(rect, this,spec.fid);
651 //don't reset if we already have a user specified selection
652 if (data->listbox_selections.find(fname_w) == data->listbox_selections.end()) {
653 e->setAutoScrollEnabled(false);
656 if (str_transparent == "false")
657 e->setDrawBackground(true);
659 for (unsigned int i=0; i < items.size(); i++) {
660 if (items[i].c_str()[0] == '#') {
661 if (items[i].c_str()[1] == '#') {
662 e->addItem(narrow_to_wide(items[i]).c_str() +1);
665 std::wstring toadd = narrow_to_wide(items[i].c_str() + 7);
666 std::string color = items[i].substr(1,6);
668 e->addItem(toadd.c_str());
670 irr::video::SColor toset;
672 if (parseColor(color,toset))
673 e->setItemOverrideColor(i,toset);
677 e->addItem(narrow_to_wide(items[i]).c_str());
681 if (str_initial_selection != "")
682 e->setSelected(stoi(str_initial_selection.c_str())-1);
684 if (data->listbox_selections.find(fname_w) != data->listbox_selections.end()) {
685 e->setSelected(data->listbox_selections[fname_w]);
688 m_listboxes.push_back(std::pair<FieldSpec,gui::IGUIListBox*>(spec,e));
689 m_fields.push_back(spec);
692 errorstream<< "Invalid textlist element(" << parts.size() << "): '" << element << "'" << std::endl;
696 void GUIFormSpecMenu::parseDropDown(parserData* data,std::string element) {
697 std::vector<std::string> parts = split(element,';');
699 if (parts.size() == 5) {
700 std::vector<std::string> v_pos = split(parts[0],',');
701 std::string name = parts[2];
702 std::vector<std::string> items = split(parts[3],',');
703 std::string str_initial_selection = "";
704 str_initial_selection = parts[4];
706 MY_CHECKPOS("dropdown",0);
709 pos.X += stof(v_pos[0]) * (float)spacing.X;
710 pos.Y += stof(v_pos[1]) * (float)spacing.Y;
712 s32 width = stof(parts[1]) * (float)spacing.Y;
714 core::rect<s32> rect = core::rect<s32>(pos.X, pos.Y, pos.X+width, pos.Y+30);
716 std::wstring fname_w = narrow_to_wide(name.c_str());
718 FieldSpec spec = FieldSpec(
725 spec.ftype = f_DropDown;
728 //now really show list
729 gui::IGUIComboBox *e = Environment->addComboBox(rect, this,spec.fid);
731 //don't reset if we already have a user specified selection
732 //if (data->combobox_selections.find(fname_w) == data->listbox_selections.end()) {
733 // e->setAutoScrollEnabled(false);
736 for (unsigned int i=0; i < items.size(); i++) {
737 e->addItem(narrow_to_wide(items[i]).c_str());
740 if (str_initial_selection != "")
741 e->setSelected(stoi(str_initial_selection.c_str())-1);
743 //if (data->listbox_selections.find(fname_w) != data->listbox_selections.end()) {
744 // e->setSelected(data->listbox_selections[fname_w]);
747 //m_listboxes.push_back(std::pair<FieldSpec,gui::IGUIListBox*>(spec,e));
748 m_fields.push_back(spec);
751 errorstream << "Invalid dropdown element(" << parts.size() << "): '"
752 << element << "'" << std::endl;
755 void GUIFormSpecMenu::parsePwdField(parserData* data,std::string element) {
756 std::vector<std::string> parts = split(element,';');
758 if (parts.size() == 4) {
759 std::vector<std::string> v_pos = split(parts[0],',');
760 std::vector<std::string> v_geom = split(parts[1],',');
761 std::string name = parts[2];
762 std::string label = parts[3];
764 MY_CHECKPOS("pwdfield",0);
765 MY_CHECKGEOM("pwdfield",1);
768 pos.X += stof(v_pos[0]) * (float)spacing.X;
769 pos.Y += stof(v_pos[1]) * (float)spacing.Y;
772 geom.X = (stof(v_geom[0]) * (float)spacing.X)-(spacing.X-imgsize.X);
774 pos.Y += (stof(v_geom[1]) * (float)imgsize.Y)/2;
778 core::rect<s32> rect = core::rect<s32>(pos.X, pos.Y, pos.X+geom.X, pos.Y+geom.Y);
780 label = unescape_string(label);
785 if (label.length() > 1)
786 wlabel = wgettext(label.c_str());
788 wlabel = (wchar_t*) narrow_to_wide("").c_str();
791 wlabel = (wchar_t*) narrow_to_wide(label.c_str()).c_str();
793 FieldSpec spec = FieldSpec(
794 narrow_to_wide(name.c_str()),
801 gui::IGUIEditBox * e = Environment->addEditBox(0, rect, true, this, spec.fid);
802 Environment->setFocus(e);
804 if (label.length() > 1)
806 rect.UpperLeftCorner.Y -= 15;
807 rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + 15;
808 Environment->addStaticText(spec.flabel.c_str(), rect, false, true, this, 0);
811 e->setPasswordBox(true,L'*');
814 evt.KeyInput.Key = KEY_END;
815 evt.EventType = EET_KEY_INPUT_EVENT;
816 evt.KeyInput.PressedDown = true;
818 m_fields.push_back(spec);
819 if ((m_use_gettext) && (label.length() >1))
823 errorstream<< "Invalid pwdfield element(" << parts.size() << "): '" << element << "'" << std::endl;
826 void GUIFormSpecMenu::parseSimpleField(parserData* data,std::vector<std::string> &parts) {
827 std::string name = parts[0];
828 std::string label = parts[1];
829 std::string default_val = parts[2];
831 core::rect<s32> rect;
835 rect = core::rect<s32>(
836 data->screensize.X/2 - 580/2,
837 data->screensize.Y/2 - 300/2,
838 data->screensize.X/2 + 580/2,
839 data->screensize.Y/2 + 300/2
842 recalculateAbsolutePosition(false);
843 data->basepos = getBasePos();
846 else if(data->bp_set == 2)
847 errorstream<<"WARNING: invalid use of unpositioned \"field\" in inventory"<<std::endl;
849 v2s32 pos = padding + AbsoluteRect.UpperLeftCorner;
850 pos.Y = ((m_fields.size()+2)*60);
851 v2s32 size = DesiredRect.getSize();
853 rect = core::rect<s32>(size.X/2-150, pos.Y, (size.X/2-150)+300, pos.Y+30);
857 default_val = m_form_src->resolveText(default_val);
859 default_val = unescape_string(default_val);
860 label = unescape_string(label);
865 if (label.length() > 1)
866 wlabel = wgettext(label.c_str());
868 wlabel = (wchar_t*) narrow_to_wide("").c_str();
871 wlabel = (wchar_t*) narrow_to_wide(label.c_str()).c_str();
873 FieldSpec spec = FieldSpec(
874 narrow_to_wide(name.c_str()),
876 narrow_to_wide(default_val.c_str()),
882 // spec field id to 0, this stops submit searching for a value that isn't there
883 Environment->addStaticText(spec.flabel.c_str(), rect, false, true, this, spec.fid);
888 gui::IGUIEditBox *e = Environment->addEditBox(spec.fdefault.c_str(), rect, true, this, spec.fid);
889 Environment->setFocus(e);
892 evt.KeyInput.Key = KEY_END;
893 evt.EventType = EET_KEY_INPUT_EVENT;
894 evt.KeyInput.PressedDown = true;
897 if (label.length() > 1)
899 rect.UpperLeftCorner.Y -= 15;
900 rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + 15;
901 Environment->addStaticText(spec.flabel.c_str(), rect, false, true, this, 0);
904 if (m_use_gettext && (label.length() > 1))
907 m_fields.push_back(spec);
910 void GUIFormSpecMenu::parseTextArea(parserData* data,std::vector<std::string>& parts,std::string type) {
912 std::vector<std::string> v_pos = split(parts[0],',');
913 std::vector<std::string> v_geom = split(parts[1],',');
914 std::string name = parts[2];
915 std::string label = parts[3];
916 std::string default_val = parts[4];
919 MY_CHECKGEOM(type,1);
922 pos.X = stof(v_pos[0]) * (float) spacing.X;
923 pos.Y = stof(v_pos[1]) * (float) spacing.Y;
927 geom.X = (stof(v_geom[0]) * (float)spacing.X)-(spacing.X-imgsize.X);
929 if (type == "textarea")
931 geom.Y = (stof(v_geom[1]) * (float)imgsize.Y) - (spacing.Y-imgsize.Y);
936 pos.Y += (stof(v_geom[1]) * (float)imgsize.Y)/2;
941 core::rect<s32> rect = core::rect<s32>(pos.X, pos.Y, pos.X+geom.X, pos.Y+geom.Y);
943 if(data->bp_set != 2)
944 errorstream<<"WARNING: invalid use of positioned "<<type<<" without a size[] element"<<std::endl;
947 default_val = m_form_src->resolveText(default_val);
950 default_val = unescape_string(default_val);
951 label = unescape_string(label);
956 if (label.length() > 1)
957 wlabel = wgettext(label.c_str());
959 wlabel = (wchar_t*) narrow_to_wide("").c_str();
962 wlabel = (wchar_t*) narrow_to_wide(label.c_str()).c_str();
964 FieldSpec spec = FieldSpec(
965 narrow_to_wide(name.c_str()),
967 narrow_to_wide(default_val.c_str()),
973 // spec field id to 0, this stops submit searching for a value that isn't there
974 Environment->addStaticText(spec.flabel.c_str(), rect, false, true, this, spec.fid);
979 gui::IGUIEditBox *e = Environment->addEditBox(spec.fdefault.c_str(), rect, true, this, spec.fid);
980 Environment->setFocus(e);
982 if (type == "textarea")
984 e->setMultiLine(true);
985 e->setTextAlignment(gui::EGUIA_UPPERLEFT, gui::EGUIA_UPPERLEFT);
988 evt.EventType = EET_KEY_INPUT_EVENT;
989 evt.KeyInput.Key = KEY_END;
990 evt.KeyInput.Char = 0;
991 evt.KeyInput.Control = 0;
992 evt.KeyInput.Shift = 0;
993 evt.KeyInput.PressedDown = true;
997 if (label.length() > 1)
999 rect.UpperLeftCorner.Y -= 15;
1000 rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + 15;
1001 Environment->addStaticText(spec.flabel.c_str(), rect, false, true, this, 0);
1004 if (m_use_gettext && (label.length() > 1))
1006 m_fields.push_back(spec);
1009 void GUIFormSpecMenu::parseField(parserData* data,std::string element,std::string type) {
1010 std::vector<std::string> parts = split(element,';');
1012 if (parts.size() == 3) {
1013 parseSimpleField(data,parts);
1017 if (parts.size() == 5) {
1018 parseTextArea(data,parts,type);
1021 errorstream<< "Invalid field element(" << parts.size() << "): '" << element << "'" << std::endl;
1024 void GUIFormSpecMenu::parseLabel(parserData* data,std::string element) {
1025 std::vector<std::string> parts = split(element,';');
1027 if (parts.size() == 2) {
1028 std::vector<std::string> v_pos = split(parts[0],',');
1029 std::string text = parts[1];
1031 MY_CHECKPOS("label",0);
1033 v2s32 pos = padding;
1034 pos.X += stof(v_pos[0]) * (float)spacing.X;
1035 pos.Y += stof(v_pos[1]) * (float)spacing.Y;
1037 core::rect<s32> rect = core::rect<s32>(pos.X, pos.Y+((imgsize.Y/2)-15), pos.X+300, pos.Y+((imgsize.Y/2)+15));
1039 if(data->bp_set != 2)
1040 errorstream<<"WARNING: invalid use of label without a size[] element"<<std::endl;
1042 text = unescape_string(text);
1044 wchar_t* wlabel = 0;
1047 wlabel = wgettext(text.c_str());
1049 wlabel = (wchar_t*) narrow_to_wide(text.c_str()).c_str();
1051 FieldSpec spec = FieldSpec(
1057 Environment->addStaticText(spec.flabel.c_str(), rect, false, true, this, spec.fid);
1058 m_fields.push_back(spec);
1063 errorstream<< "Invalid label element(" << parts.size() << "): '" << element << "'" << std::endl;
1066 void GUIFormSpecMenu::parseVertLabel(parserData* data,std::string element) {
1067 std::vector<std::string> parts = split(element,';');
1069 if (parts.size() == 2) {
1070 std::vector<std::string> v_pos = split(parts[0],',');
1071 std::string text = parts[1];
1073 MY_CHECKPOS("vertlabel",1);
1075 v2s32 pos = padding;
1076 pos.X += stof(v_pos[0]) * (float)spacing.X;
1077 pos.Y += stof(v_pos[1]) * (float)spacing.Y;
1079 core::rect<s32> rect = core::rect<s32>(pos.X, pos.Y+((imgsize.Y/2)-15), pos.X+15, pos.Y+300);
1081 if(data->bp_set != 2)
1082 errorstream<<"WARNING: invalid use of label without a size[] element"<<std::endl;
1084 text = unescape_string(text);
1085 std::string label = "";
1087 if (m_use_gettext) {
1088 const char* toset = gettext(text.c_str());
1090 text = std::string(toset);
1093 for (unsigned int i=0; i < text.length(); i++) {
1094 label += text.c_str()[i];
1098 FieldSpec spec = FieldSpec(
1100 narrow_to_wide(label.c_str()),
1104 gui::IGUIStaticText *t =
1105 Environment->addStaticText(spec.flabel.c_str(), rect, false, true, this, spec.fid);
1106 t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
1107 m_fields.push_back(spec);
1110 errorstream<< "Invalid vertlabel element(" << parts.size() << "): '" << element << "'" << std::endl;
1113 void GUIFormSpecMenu::parseImageButton(parserData* data,std::string element,std::string type) {
1114 std::vector<std::string> parts = split(element,';');
1116 if ((parts.size() == 5) || (parts.size() == 7)) {
1117 std::vector<std::string> v_pos = split(parts[0],',');
1118 std::vector<std::string> v_geom = split(parts[1],',');
1119 std::string image_name = parts[2];
1120 std::string name = parts[3];
1121 std::string label = parts[4];
1123 MY_CHECKPOS("imagebutton",0);
1124 MY_CHECKGEOM("imagebutton",1);
1126 v2s32 pos = padding;
1127 pos.X += stof(v_pos[0]) * (float)spacing.X;
1128 pos.Y += stof(v_pos[1]) * (float)spacing.Y;
1130 geom.X = (stof(v_geom[0]) * (float)spacing.X)-(spacing.X-imgsize.X);
1131 geom.Y = (stof(v_geom[1]) * (float)spacing.Y)-(spacing.Y-imgsize.Y);
1133 bool noclip = false;
1134 bool drawborder = true;
1136 if ((parts.size() == 7)) {
1137 if (parts[5] == "true")
1140 if (parts[6] == "false")
1144 core::rect<s32> rect = core::rect<s32>(pos.X, pos.Y, pos.X+geom.X, pos.Y+geom.Y);
1146 if(data->bp_set != 2)
1147 errorstream<<"WARNING: invalid use of item_image_button without a size[] element"<<std::endl;
1149 label = unescape_string(label);
1151 FieldSpec spec = FieldSpec(
1152 narrow_to_wide(name.c_str()),
1153 narrow_to_wide(label.c_str()),
1154 narrow_to_wide(image_name.c_str()),
1157 spec.ftype = f_Button;
1158 if(type == "image_button_exit")
1159 spec.is_exit = true;
1161 video::ITexture *texture = 0;
1162 //if there's no gamedef specified try to get direct
1163 //TODO check for possible texture leak
1165 texture = m_gamedef->tsrc()->getTexture(image_name);
1167 if (fs::PathExists(image_name)) {
1168 texture = Environment->getVideoDriver()->getTexture(image_name.c_str());
1169 m_Textures.push_back(texture);
1173 gui::IGUIButton *e = Environment->addButton(rect, this, spec.fid, spec.flabel.c_str());
1174 e->setUseAlphaChannel(true);
1175 e->setImage(texture);
1176 e->setPressedImage(texture);
1177 e->setScaleImage(true);
1178 e->setNotClipped(noclip);
1179 e->setDrawBorder(drawborder);
1181 m_fields.push_back(spec);
1185 errorstream<< "Invalid imagebutton element(" << parts.size() << "): '" << element << "'" << std::endl;
1188 void GUIFormSpecMenu::parseTabHeader(parserData* data,std::string element) {
1189 std::vector<std::string> parts = split(element,';');
1191 if ((parts.size() == 4) || (parts.size() == 6)) {
1192 std::vector<std::string> v_pos = split(parts[0],',');
1193 std::string name = parts[1];
1194 std::vector<std::string> buttons = split(parts[2],',');
1195 std::string str_index = parts[3];
1196 bool show_background = true;
1197 bool show_border = true;
1198 int tab_index = stoi(str_index) -1;
1200 MY_CHECKPOS("tabheader",0);
1202 if (parts.size() == 6) {
1203 if (parts[4] == "true")
1204 show_background = false;
1205 if (parts[5] == "false")
1206 show_border = false;
1209 FieldSpec spec = FieldSpec(
1210 narrow_to_wide(name.c_str()),
1216 spec.ftype = f_TabHeader;
1218 v2s32 pos = padding;
1219 pos.X += stof(v_pos[0]) * (float)spacing.X;
1220 pos.Y += stof(v_pos[1]) * (float)spacing.Y;
1222 geom.X = data->screensize.Y;
1225 core::rect<s32> rect = core::rect<s32>(pos.X, pos.Y, pos.X+geom.X, pos.Y+geom.Y);
1227 gui::IGUITabControl *e = Environment->addTabControl(rect,this,show_background,show_border,spec.fid);
1229 e->setNotClipped(true);
1231 for (unsigned int i=0; i< buttons.size(); i++) {
1232 wchar_t* wbutton = 0;
1235 wbutton = wgettext(buttons[i].c_str());
1237 wbutton = (wchar_t*) narrow_to_wide(buttons[i].c_str()).c_str();
1239 e->addTab(wbutton,-1);
1245 if ((tab_index >= 0) &&
1246 (buttons.size() < INT_MAX) &&
1247 (tab_index < (int) buttons.size()))
1248 e->setActiveTab(tab_index);
1250 m_fields.push_back(spec);
1253 errorstream<< "Invalid TabHeader element(" << parts.size() << "): '" << element << "'" << std::endl;
1256 void GUIFormSpecMenu::parseItemImageButton(parserData* data,std::string element) {
1258 if (m_gamedef == 0) {
1259 errorstream<<"WARNING: invalid use of item_image_button with m_gamedef==0"<<std::endl;
1263 std::vector<std::string> parts = split(element,';');
1265 if (parts.size() == 5) {
1266 std::vector<std::string> v_pos = split(parts[0],',');
1267 std::vector<std::string> v_geom = split(parts[1],',');
1268 std::string item_name = parts[2];
1269 std::string name = parts[3];
1270 std::string label = parts[4];
1272 MY_CHECKPOS("itemimagebutton",0);
1273 MY_CHECKGEOM("itemimagebutton",1);
1275 v2s32 pos = padding;
1276 pos.X += stof(v_pos[0]) * (float)spacing.X;
1277 pos.Y += stof(v_pos[1]) * (float)spacing.Y;
1279 geom.X = (stof(v_geom[0]) * (float)spacing.X)-(spacing.X-imgsize.X);
1280 geom.Y = (stof(v_geom[1]) * (float)spacing.Y)-(spacing.Y-imgsize.Y);
1282 core::rect<s32> rect = core::rect<s32>(pos.X, pos.Y, pos.X+geom.X, pos.Y+geom.Y);
1284 if(data->bp_set != 2)
1285 errorstream<<"WARNING: invalid use of item_image_button without a size[] element"<<std::endl;
1287 IItemDefManager *idef = m_gamedef->idef();
1289 item.deSerialize(item_name, idef);
1290 video::ITexture *texture = idef->getInventoryTexture(item.getDefinition(idef).name, m_gamedef);
1291 std::string tooltip = item.getDefinition(idef).description;
1293 label = unescape_string(label);
1294 FieldSpec spec = FieldSpec(
1295 narrow_to_wide(name.c_str()),
1296 narrow_to_wide(label.c_str()),
1297 narrow_to_wide(item_name.c_str()),
1301 gui::IGUIButton *e = Environment->addButton(rect, this, spec.fid, spec.flabel.c_str());
1302 e->setUseAlphaChannel(true);
1303 e->setImage(texture);
1304 e->setPressedImage(texture);
1305 e->setScaleImage(true);
1306 spec.ftype = f_Button;
1307 rect+=data->basepos-padding;
1310 spec.tooltip=tooltip;
1311 m_fields.push_back(spec);
1314 errorstream<< "Invalid ItemImagebutton element(" << parts.size() << "): '" << element << "'" << std::endl;
1317 void GUIFormSpecMenu::parseBox(parserData* data,std::string element) {
1318 std::vector<std::string> parts = split(element,';');
1320 if (parts.size() == 3) {
1321 std::vector<std::string> v_pos = split(parts[0],',');
1322 std::vector<std::string> v_geom = split(parts[1],',');
1323 std::string color_str = parts[2];
1325 MY_CHECKPOS("box",0);
1326 MY_CHECKGEOM("box",1);
1328 v2s32 pos = padding + AbsoluteRect.UpperLeftCorner;
1329 pos.X += stof(v_pos[0]) * (float) spacing.X;
1330 pos.Y += stof(v_pos[1]) * (float) spacing.Y;
1333 geom.X = stof(v_geom[0]) * (float)spacing.X;
1334 geom.Y = stof(v_geom[1]) * (float)spacing.Y;
1336 irr::video::SColor color;
1338 if (parseColor(color_str,color)) {
1339 BoxDrawSpec spec(pos,geom,color);
1341 m_boxes.push_back(spec);
1344 errorstream<< "Invalid Box element(" << parts.size() << "): '" << element << "' INVALID COLOR" << std::endl;
1348 errorstream<< "Invalid Box element(" << parts.size() << "): '" << element << "'" << std::endl;
1351 void GUIFormSpecMenu::parseElement(parserData* data,std::string element) {
1356 std::vector<std::string> parts = split(element,'[', true);
1358 if (parts.size() != 2)
1361 std::string type = trim(parts[0]);
1362 std::string description = trim(parts[1]);
1364 if ((type == "size") || (type == "invsize")){
1365 parseSize(data,description);
1369 if (type == "list") {
1370 parseList(data,description);
1374 if (type == "checkbox") {
1375 parseCheckbox(data,description);
1379 if (type == "image") {
1380 parseImage(data,description);
1384 if (type == "item_image") {
1385 parseItemImage(data,description);
1389 if ((type == "button") || (type == "button_exit")) {
1390 parseButton(data,description,type);
1394 if (type == "background") {
1395 parseBackground(data,description);
1399 if (type == "textlist"){
1400 parseTextList(data,description);
1404 if (type == "dropdown"){
1405 parseDropDown(data,description);
1409 if (type == "pwdfield") {
1410 parsePwdField(data,description);
1414 if ((type == "field") || (type == "textarea")){
1415 parseField(data,description,type);
1419 if (type == "label") {
1420 parseLabel(data,description);
1424 if (type == "vertlabel") {
1425 parseVertLabel(data,description);
1429 if (type == "item_image_button") {
1430 parseItemImageButton(data,description);
1434 if ((type == "image_button") || (type == "image_button_exit")) {
1435 parseImageButton(data,description,type);
1439 if (type == "tabheader") {
1440 parseTabHeader(data,description);
1444 if (type == "box") {
1445 parseBox(data,description);
1451 << "Unknown DrawSpec: type="<<type<<", data=\""<<description<<"\""
1457 void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
1461 //preserve listboxes
1462 for (unsigned int i = 0; i < m_listboxes.size(); i++) {
1463 int selection = m_listboxes[i].second->getSelected();
1464 if (selection != -1) {
1465 std::wstring listboxname = m_listboxes[i].first.fname;
1466 mydata.listbox_selections[listboxname] = selection;
1473 mydata.size= v2s32(100,100);
1474 mydata.helptext_h = 15;
1475 mydata.screensize = screensize;
1477 // Base position of contents of form
1478 mydata.basepos = getBasePos();
1480 // State of basepos, 0 = not set, 1= set by formspec, 2 = set by size[] element
1481 // Used to adjust form size automatically if needed
1482 // A proceed button is added if there is no size[] element
1486 /* Convert m_init_draw_spec to m_inventorylists */
1488 m_inventorylists.clear();
1490 m_backgrounds.clear();
1491 m_itemimages.clear();
1492 m_listboxes.clear();
1493 m_checkboxes.clear();
1498 std::vector<std::string> elements = split(m_formspec_string,']',true);
1500 for (unsigned int i=0;i< elements.size();i++) {
1501 parseElement(&mydata,elements[i]);
1504 // If there's inventory, put the usage string at the bottom
1505 if (m_inventorylists.size())
1508 core::rect<s32> rect(0, 0, mydata.size.X-padding.X*2, mydata.helptext_h);
1509 rect = rect + v2s32((mydata.size.X/2 - mydata.rect.getWidth()/2) +5,
1510 mydata.size.Y-5-mydata.helptext_h);
1511 const wchar_t *text = wgettext("Left click: Move all items, Right click: Move single item");
1512 Environment->addStaticText(text, rect, false, true, this, 256);
1516 // If there's fields, add a Proceed button
1517 if (m_fields.size() && mydata.bp_set != 2)
1519 // if the size wasn't set by an invsize[] or size[] adjust it now to fit all the fields
1520 mydata.rect = core::rect<s32>(
1521 mydata.screensize.X/2 - 580/2,
1522 mydata.screensize.Y/2 - 300/2,
1523 mydata.screensize.X/2 + 580/2,
1524 mydata.screensize.Y/2 + 240/2+(m_fields.size()*60)
1526 DesiredRect = mydata.rect;
1527 recalculateAbsolutePosition(false);
1528 mydata.basepos = getBasePos();
1532 v2s32 pos = mydata.basepos;
1533 pos.Y = ((m_fields.size()+2)*60);
1535 v2s32 size = DesiredRect.getSize();
1536 mydata.rect = core::rect<s32>(size.X/2-70, pos.Y, (size.X/2-70)+140, pos.Y+30);
1537 wchar_t* text = wgettext("Proceed");
1538 Environment->addButton(mydata.rect, this, 257, text);
1545 // Note: parent != this so that the tooltip isn't clipped by the menu rectangle
1546 m_tooltip_element = Environment->addStaticText(L"",core::rect<s32>(0,0,110,18));
1547 m_tooltip_element->enableOverrideColor(true);
1548 m_tooltip_element->setBackgroundColor(video::SColor(255,110,130,60));
1549 m_tooltip_element->setDrawBackground(true);
1550 m_tooltip_element->setDrawBorder(true);
1551 m_tooltip_element->setOverrideColor(video::SColor(255,255,255,255));
1552 m_tooltip_element->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
1553 m_tooltip_element->setWordWrap(false);
1557 GUIFormSpecMenu::ItemSpec GUIFormSpecMenu::getItemAtPos(v2s32 p) const
1559 core::rect<s32> imgrect(0,0,imgsize.X,imgsize.Y);
1561 for(u32 i=0; i<m_inventorylists.size(); i++)
1563 const ListDrawSpec &s = m_inventorylists[i];
1565 for(s32 i=0; i<s.geom.X*s.geom.Y; i++)
1567 s32 item_i = i + s.start_item_i;
1568 s32 x = (i%s.geom.X) * spacing.X;
1569 s32 y = (i/s.geom.X) * spacing.Y;
1571 core::rect<s32> rect = imgrect + s.pos + p0;
1572 if(rect.isPointInside(p))
1574 return ItemSpec(s.inventoryloc, s.listname, item_i);
1579 return ItemSpec(InventoryLocation(), "", -1);
1582 void GUIFormSpecMenu::drawList(const ListDrawSpec &s, int phase)
1584 video::IVideoDriver* driver = Environment->getVideoDriver();
1587 gui::IGUIFont *font = NULL;
1588 gui::IGUISkin* skin = Environment->getSkin();
1590 font = skin->getFont();
1592 Inventory *inv = m_invmgr->getInventory(s.inventoryloc);
1594 infostream<<"GUIFormSpecMenu::drawList(): WARNING: "
1595 <<"The inventory location "
1596 <<"\""<<s.inventoryloc.dump()<<"\" doesn't exist"
1600 InventoryList *ilist = inv->getList(s.listname);
1602 infostream<<"GUIFormSpecMenu::drawList(): WARNING: "
1603 <<"The inventory list \""<<s.listname<<"\" @ \""
1604 <<s.inventoryloc.dump()<<"\" doesn't exist"
1609 core::rect<s32> imgrect(0,0,imgsize.X,imgsize.Y);
1611 for(s32 i=0; i<s.geom.X*s.geom.Y; i++)
1613 s32 item_i = i + s.start_item_i;
1614 if(item_i >= (s32) ilist->getSize())
1616 s32 x = (i%s.geom.X) * spacing.X;
1617 s32 y = (i/s.geom.X) * spacing.Y;
1619 core::rect<s32> rect = imgrect + s.pos + p;
1622 item = ilist->getItem(item_i);
1624 bool selected = m_selected_item
1625 && m_invmgr->getInventory(m_selected_item->inventoryloc) == inv
1626 && m_selected_item->listname == s.listname
1627 && m_selected_item->i == item_i;
1628 bool hovering = rect.isPointInside(m_pointer);
1632 if(hovering && m_selected_item)
1634 video::SColor bgcolor(255,192,192,192);
1635 driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
1639 video::SColor bgcolor(255,128,128,128);
1640 driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
1649 item.takeItem(m_selected_amount);
1653 drawItemStack(driver, font, item,
1654 rect, &AbsoluteClippingRect, m_gamedef);
1658 std::string tooltip_text = "";
1659 if(hovering && !m_selected_item)
1660 tooltip_text = item.getDefinition(m_gamedef->idef()).description;
1661 if(tooltip_text != "")
1663 m_tooltip_element->setVisible(true);
1664 this->bringToFront(m_tooltip_element);
1665 m_tooltip_element->setText(narrow_to_wide(tooltip_text).c_str());
1666 s32 tooltip_x = m_pointer.X + 15;
1667 s32 tooltip_y = m_pointer.Y + 15;
1668 s32 tooltip_width = m_tooltip_element->getTextWidth() + 15;
1669 s32 tooltip_height = m_tooltip_element->getTextHeight() + 5;
1670 m_tooltip_element->setRelativePosition(core::rect<s32>(
1671 core::position2d<s32>(tooltip_x, tooltip_y),
1672 core::dimension2d<s32>(tooltip_width, tooltip_height)));
1678 void GUIFormSpecMenu::drawSelectedItem()
1680 if(!m_selected_item)
1683 video::IVideoDriver* driver = Environment->getVideoDriver();
1686 gui::IGUIFont *font = NULL;
1687 gui::IGUISkin* skin = Environment->getSkin();
1689 font = skin->getFont();
1691 Inventory *inv = m_invmgr->getInventory(m_selected_item->inventoryloc);
1693 InventoryList *list = inv->getList(m_selected_item->listname);
1695 ItemStack stack = list->getItem(m_selected_item->i);
1696 stack.count = m_selected_amount;
1698 core::rect<s32> imgrect(0,0,imgsize.X,imgsize.Y);
1699 core::rect<s32> rect = imgrect + (m_pointer - imgrect.getCenter());
1700 drawItemStack(driver, font, stack, rect, NULL, m_gamedef);
1703 void GUIFormSpecMenu::drawMenu()
1706 std::string newform = m_form_src->getForm();
1707 if(newform != m_formspec_string){
1708 m_formspec_string = newform;
1709 regenerateGui(m_screensize_old);
1713 m_pointer = m_device->getCursorControl()->getPosition();
1715 updateSelectedItem();
1717 gui::IGUISkin* skin = Environment->getSkin();
1720 video::IVideoDriver* driver = Environment->getVideoDriver();
1722 video::SColor bgcolor(140,0,0,0);
1723 driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);
1725 m_tooltip_element->setVisible(false);
1730 for(u32 i=0; i<m_backgrounds.size(); i++)
1732 const ImageDrawSpec &spec = m_backgrounds[i];
1733 video::ITexture *texture = 0;
1736 texture = m_gamedef->tsrc()->getTexture(spec.name);
1739 texture = driver->getTexture(spec.name.c_str());
1740 m_Textures.push_back(texture);
1744 // Image size on screen
1745 core::rect<s32> imgrect(0, 0, spec.geom.X, spec.geom.Y);
1746 // Image rectangle on screen
1747 core::rect<s32> rect = imgrect + spec.pos;
1748 const video::SColor color(255,255,255,255);
1749 const video::SColor colors[] = {color,color,color,color};
1750 driver->draw2DImage(texture, rect,
1751 core::rect<s32>(core::position2d<s32>(0,0),
1752 core::dimension2di(texture->getOriginalSize())),
1753 NULL/*&AbsoluteClippingRect*/, colors, true);
1756 errorstream << "GUIFormSpecMenu::drawMenu() Draw backgrounds unable to load texture:" << std::endl;
1757 errorstream << "\t" << spec.name << std::endl;
1764 for(u32 i=0; i<m_boxes.size(); i++)
1766 const BoxDrawSpec &spec = m_boxes[i];
1768 irr::video::SColor todraw = spec.color;
1770 todraw.setAlpha(140);
1772 core::rect<s32> rect(spec.pos.X,spec.pos.Y,
1773 spec.pos.X + spec.geom.X,spec.pos.Y + spec.geom.Y);
1775 driver->draw2DRectangle(todraw, rect, 0);
1780 for(u32 i=0; i<m_images.size(); i++)
1782 const ImageDrawSpec &spec = m_images[i];
1783 video::ITexture *texture = 0;
1786 texture = m_gamedef->tsrc()->getTexture(spec.name);
1789 texture = driver->getTexture(spec.name.c_str());
1790 m_Textures.push_back(texture);
1793 const core::dimension2d<u32>& img_origsize = texture->getOriginalSize();
1794 // Image size on screen
1795 core::rect<s32> imgrect;
1798 imgrect = core::rect<s32>(0,0,spec.geom.X, spec.geom.Y);
1801 imgrect = core::rect<s32>(0,0,img_origsize.Width,img_origsize.Height);
1803 // Image rectangle on screen
1804 core::rect<s32> rect = imgrect + spec.pos;
1805 const video::SColor color(255,255,255,255);
1806 const video::SColor colors[] = {color,color,color,color};
1807 driver->draw2DImage(texture, rect,
1808 core::rect<s32>(core::position2d<s32>(0,0),img_origsize),
1809 NULL/*&AbsoluteClippingRect*/, colors, true);
1812 errorstream << "GUIFormSpecMenu::drawMenu() Draw images unable to load texture:" << std::endl;
1813 errorstream << "\t" << spec.name << std::endl;
1820 for(u32 i=0; i<m_itemimages.size(); i++)
1825 const ImageDrawSpec &spec = m_itemimages[i];
1826 IItemDefManager *idef = m_gamedef->idef();
1828 item.deSerialize(spec.name, idef);
1829 video::ITexture *texture = idef->getInventoryTexture(item.getDefinition(idef).name, m_gamedef);
1830 // Image size on screen
1831 core::rect<s32> imgrect(0, 0, spec.geom.X, spec.geom.Y);
1832 // Image rectangle on screen
1833 core::rect<s32> rect = imgrect + spec.pos;
1834 const video::SColor color(255,255,255,255);
1835 const video::SColor colors[] = {color,color,color,color};
1836 driver->draw2DImage(texture, rect,
1837 core::rect<s32>(core::position2d<s32>(0,0),
1838 core::dimension2di(texture->getOriginalSize())),
1839 NULL/*&AbsoluteClippingRect*/, colors, true);
1844 Phase 0: Item slot rectangles
1845 Phase 1: Item images; prepare tooltip
1846 If backgrounds used, do not draw Item slot rectangles
1849 if (m_backgrounds.size() > 0) start_phase=1;
1850 for(int phase=start_phase; phase<=1; phase++)
1851 for(u32 i=0; i<m_inventorylists.size(); i++)
1853 drawList(m_inventorylists[i], phase);
1859 gui::IGUIElement::draw();
1862 Draw fields/buttons tooltips
1864 for(u32 i=0; i<m_fields.size(); i++)
1866 const FieldSpec &spec = m_fields[i];
1867 if (spec.tooltip != "")
1869 core::rect<s32> rect = spec.rect;
1870 if (rect.isPointInside(m_pointer))
1872 m_tooltip_element->setVisible(true);
1873 this->bringToFront(m_tooltip_element);
1874 m_tooltip_element->setText(narrow_to_wide(spec.tooltip).c_str());
1875 s32 tooltip_x = m_pointer.X + 15;
1876 s32 tooltip_y = m_pointer.Y + 15;
1877 s32 tooltip_width = m_tooltip_element->getTextWidth() + 15;
1878 s32 tooltip_height = m_tooltip_element->getTextHeight() + 5;
1879 m_tooltip_element->setRelativePosition(core::rect<s32>(
1880 core::position2d<s32>(tooltip_x, tooltip_y),
1881 core::dimension2d<s32>(tooltip_width, tooltip_height)));
1887 Draw dragged item stack
1892 void GUIFormSpecMenu::updateSelectedItem()
1894 // If the selected stack has become empty for some reason, deselect it.
1895 // If the selected stack has become inaccessible, deselect it.
1896 // If the selected stack has become smaller, adjust m_selected_amount.
1897 ItemStack selected = verifySelectedItem();
1899 // WARNING: BLACK MAGIC
1900 // See if there is a stack suited for our current guess.
1901 // If such stack does not exist, clear the guess.
1902 if(m_selected_content_guess.name != "" &&
1903 selected.name == m_selected_content_guess.name &&
1904 selected.count == m_selected_content_guess.count){
1905 // Selected item fits the guess. Skip the black magic.
1907 else if(m_selected_content_guess.name != ""){
1909 for(u32 i=0; i<m_inventorylists.size() && !found; i++){
1910 const ListDrawSpec &s = m_inventorylists[i];
1911 Inventory *inv = m_invmgr->getInventory(s.inventoryloc);
1914 InventoryList *list = inv->getList(s.listname);
1917 for(s32 i=0; i<s.geom.X*s.geom.Y && !found; i++){
1918 u32 item_i = i + s.start_item_i;
1919 if(item_i >= list->getSize())
1921 ItemStack stack = list->getItem(item_i);
1922 if(stack.name == m_selected_content_guess.name &&
1923 stack.count == m_selected_content_guess.count){
1925 infostream<<"Client: Changing selected content guess to "
1926 <<s.inventoryloc.dump()<<" "<<s.listname
1927 <<" "<<item_i<<std::endl;
1928 delete m_selected_item;
1929 m_selected_item = new ItemSpec(s.inventoryloc, s.listname, item_i);
1930 m_selected_amount = stack.count;
1935 infostream<<"Client: Discarding selected content guess: "
1936 <<m_selected_content_guess.getItemString()<<std::endl;
1937 m_selected_content_guess.name = "";
1941 // If craftresult is nonempty and nothing else is selected, select it now.
1942 if(!m_selected_item)
1944 for(u32 i=0; i<m_inventorylists.size(); i++)
1946 const ListDrawSpec &s = m_inventorylists[i];
1947 if(s.listname == "craftpreview")
1949 Inventory *inv = m_invmgr->getInventory(s.inventoryloc);
1950 InventoryList *list = inv->getList("craftresult");
1951 if(list && list->getSize() >= 1 && !list->getItem(0).empty())
1953 m_selected_item = new ItemSpec;
1954 m_selected_item->inventoryloc = s.inventoryloc;
1955 m_selected_item->listname = "craftresult";
1956 m_selected_item->i = 0;
1957 m_selected_amount = 0;
1958 m_selected_dragging = false;
1965 // If craftresult is selected, keep the whole stack selected
1966 if(m_selected_item && m_selected_item->listname == "craftresult")
1968 m_selected_amount = verifySelectedItem().count;
1972 ItemStack GUIFormSpecMenu::verifySelectedItem()
1974 // If the selected stack has become empty for some reason, deselect it.
1975 // If the selected stack has become inaccessible, deselect it.
1976 // If the selected stack has become smaller, adjust m_selected_amount.
1977 // Return the selected stack.
1981 if(m_selected_item->isValid())
1983 Inventory *inv = m_invmgr->getInventory(m_selected_item->inventoryloc);
1986 InventoryList *list = inv->getList(m_selected_item->listname);
1987 if(list && (u32) m_selected_item->i < list->getSize())
1989 ItemStack stack = list->getItem(m_selected_item->i);
1990 if(m_selected_amount > stack.count)
1991 m_selected_amount = stack.count;
1998 // selection was not valid
1999 delete m_selected_item;
2000 m_selected_item = NULL;
2001 m_selected_amount = 0;
2002 m_selected_dragging = false;
2007 void GUIFormSpecMenu::acceptInput(int eventtype)
2011 std::map<std::string, std::string> fields;
2013 for(u32 i=0; i<m_fields.size(); i++)
2015 const FieldSpec &s = m_fields[i];
2018 if(s.ftype == f_Button)
2020 fields[wide_to_narrow(s.fname.c_str())] = wide_to_narrow(s.flabel.c_str());
2022 else if(s.ftype == f_ListBox) {
2023 std::stringstream ss;
2024 if (eventtype == gui::EGET_LISTBOX_CHANGED) {
2030 ss << (getListboxIndex(wide_to_narrow(s.fname.c_str()))+1);
2031 fields[wide_to_narrow(s.fname.c_str())] = ss.str();
2033 else if(s.ftype == f_DropDown) {
2034 // no dynamic cast possible due to some distributions shipped
2035 // without rtti support in irrlicht
2036 IGUIElement * element = getElementFromId(s.fid);
2037 gui::IGUIComboBox *e = NULL;
2038 if ((element) && (element->getType() == gui::EGUIET_COMBO_BOX)) {
2039 e = static_cast<gui::IGUIComboBox*>(element);
2041 fields[wide_to_narrow(s.fname.c_str())] =
2042 wide_to_narrow(e->getItem(e->getSelected()));
2044 else if (s.ftype == f_TabHeader) {
2045 // no dynamic cast possible due to some distributions shipped
2046 // without rtti support in irrlicht
2047 IGUIElement * element = getElementFromId(s.fid);
2048 gui::IGUITabControl *e = NULL;
2049 if ((element) && (element->getType() == gui::EGUIET_TAB_CONTROL)) {
2050 e = static_cast<gui::IGUITabControl*>(element);
2054 std::stringstream ss;
2055 ss << (e->getActiveTab() +1);
2056 fields[wide_to_narrow(s.fname.c_str())] = ss.str();
2059 else if (s.ftype == f_CheckBox) {
2060 // no dynamic cast possible due to some distributions shipped
2061 // without rtti support in irrlicht
2062 IGUIElement * element = getElementFromId(s.fid);
2063 gui::IGUICheckBox *e = NULL;
2064 if ((element) && (element->getType() == gui::EGUIET_CHECK_BOX)) {
2065 e = static_cast<gui::IGUICheckBox*>(element);
2070 fields[wide_to_narrow(s.fname.c_str())] = "true";
2072 fields[wide_to_narrow(s.fname.c_str())] = "false";
2077 IGUIElement* e = getElementFromId(s.fid);
2080 fields[wide_to_narrow(s.fname.c_str())] = wide_to_narrow(e->getText());
2086 m_text_dst->gotText(fields);
2090 bool GUIFormSpecMenu::OnEvent(const SEvent& event)
2092 if(event.EventType==EET_KEY_INPUT_EVENT)
2094 KeyPress kp(event.KeyInput);
2095 if (event.KeyInput.PressedDown && (kp == EscapeKey ||
2096 kp == getKeySetting("keymap_inventory")))
2101 m_text_dst->gotText(narrow_to_wide("MenuQuit"));
2104 if(event.KeyInput.Key==KEY_RETURN && event.KeyInput.PressedDown)
2111 m_text_dst->gotText(narrow_to_wide("KeyEnter"));
2115 if(event.EventType==EET_MOUSE_INPUT_EVENT
2116 && event.MouseInput.Event != EMIE_MOUSE_MOVED)
2118 // Mouse event other than movement
2120 // Get selected item and hovered/clicked item (s)
2122 updateSelectedItem();
2123 ItemSpec s = getItemAtPos(m_pointer);
2125 Inventory *inv_selected = NULL;
2126 Inventory *inv_s = NULL;
2130 inv_selected = m_invmgr->getInventory(m_selected_item->inventoryloc);
2131 assert(inv_selected);
2132 assert(inv_selected->getList(m_selected_item->listname) != NULL);
2139 inv_s = m_invmgr->getInventory(s.inventoryloc);
2142 errorstream<<"InventoryMenu: The selected inventory location "
2143 <<"\""<<s.inventoryloc.dump()<<"\" doesn't exist"
2145 s.i = -1; // make it invalid again
2149 InventoryList *list = inv_s->getList(s.listname);
2151 verbosestream<<"InventoryMenu: The selected inventory list \""
2152 <<s.listname<<"\" does not exist"<<std::endl;
2153 s.i = -1; // make it invalid again
2157 if((u32)s.i >= list->getSize()){
2158 infostream<<"InventoryMenu: The selected inventory list \""
2159 <<s.listname<<"\" is too small (i="<<s.i<<", size="
2160 <<list->getSize()<<")"<<std::endl;
2161 s.i = -1; // make it invalid again
2165 s_count = list->getItem(s.i).count;
2168 bool identical = (m_selected_item != NULL) && s.isValid() &&
2169 (inv_selected == inv_s) &&
2170 (m_selected_item->listname == s.listname) &&
2171 (m_selected_item->i == s.i);
2173 // buttons: 0 = left, 1 = right, 2 = middle
2174 // up/down: 0 = down (press), 1 = up (release), 2 = unknown event
2177 if(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)
2178 { button = 0; updown = 0; }
2179 else if(event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN)
2180 { button = 1; updown = 0; }
2181 else if(event.MouseInput.Event == EMIE_MMOUSE_PRESSED_DOWN)
2182 { button = 2; updown = 0; }
2183 else if(event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)
2184 { button = 0; updown = 1; }
2185 else if(event.MouseInput.Event == EMIE_RMOUSE_LEFT_UP)
2186 { button = 1; updown = 1; }
2187 else if(event.MouseInput.Event == EMIE_MMOUSE_LEFT_UP)
2188 { button = 2; updown = 1; }
2190 // Set this number to a positive value to generate a move action
2191 // from m_selected_item to s.
2192 u32 move_amount = 0;
2194 // Set this number to a positive value to generate a drop action
2195 // from m_selected_item.
2196 u32 drop_amount = 0;
2198 // Set this number to a positive value to generate a craft action at s.
2199 u32 craft_amount = 0;
2203 // Some mouse button has been pressed
2205 //infostream<<"Mouse button "<<button<<" pressed at p=("
2206 // <<p.X<<","<<p.Y<<")"<<std::endl;
2208 m_selected_dragging = false;
2210 if(s.isValid() && s.listname == "craftpreview")
2212 // Craft preview has been clicked: craft
2213 craft_amount = (button == 2 ? 10 : 1);
2215 else if(m_selected_item == NULL)
2219 // Non-empty stack has been clicked: select it
2220 m_selected_item = new ItemSpec(s);
2222 if(button == 1) // right
2223 m_selected_amount = (s_count + 1) / 2;
2224 else if(button == 2) // middle
2225 m_selected_amount = MYMIN(s_count, 10);
2227 m_selected_amount = s_count;
2229 m_selected_dragging = true;
2232 else // m_selected_item != NULL
2234 assert(m_selected_amount >= 1);
2238 // Clicked a slot: move
2239 if(button == 1) // right
2241 else if(button == 2) // middle
2242 move_amount = MYMIN(m_selected_amount, 10);
2244 move_amount = m_selected_amount;
2248 if(move_amount >= m_selected_amount)
2249 m_selected_amount = 0;
2251 m_selected_amount -= move_amount;
2255 else if(getAbsoluteClippingRect().isPointInside(m_pointer))
2257 // Clicked somewhere else: deselect
2258 m_selected_amount = 0;
2262 // Clicked outside of the window: drop
2263 if(button == 1) // right
2265 else if(button == 2) // middle
2266 drop_amount = MYMIN(m_selected_amount, 10);
2268 drop_amount = m_selected_amount;
2272 else if(updown == 1)
2274 // Some mouse button has been released
2276 //infostream<<"Mouse button "<<button<<" released at p=("
2277 // <<p.X<<","<<p.Y<<")"<<std::endl;
2279 if(m_selected_item != NULL && m_selected_dragging && s.isValid())
2283 // Dragged to different slot: move all selected
2284 move_amount = m_selected_amount;
2287 else if(m_selected_item != NULL && m_selected_dragging &&
2288 !(getAbsoluteClippingRect().isPointInside(m_pointer)))
2290 // Dragged outside of window: drop all selected
2291 drop_amount = m_selected_amount;
2294 m_selected_dragging = false;
2297 // Possibly send inventory action to server
2300 // Send IACTION_MOVE
2302 assert(m_selected_item && m_selected_item->isValid());
2303 assert(s.isValid());
2305 assert(inv_selected && inv_s);
2306 InventoryList *list_from = inv_selected->getList(m_selected_item->listname);
2307 InventoryList *list_to = inv_s->getList(s.listname);
2308 assert(list_from && list_to);
2309 ItemStack stack_from = list_from->getItem(m_selected_item->i);
2310 ItemStack stack_to = list_to->getItem(s.i);
2312 // Check how many items can be moved
2313 move_amount = stack_from.count = MYMIN(move_amount, stack_from.count);
2314 ItemStack leftover = stack_to.addItem(stack_from, m_gamedef->idef());
2315 // If source stack cannot be added to destination stack at all,
2317 if(leftover.count == stack_from.count && leftover.name == stack_from.name)
2319 m_selected_amount = stack_to.count;
2320 // In case the server doesn't directly swap them but instead
2321 // moves stack_to somewhere else, set this
2322 m_selected_content_guess = stack_to;
2323 m_selected_content_guess_inventory = s.inventoryloc;
2325 // Source stack goes fully into destination stack
2326 else if(leftover.empty())
2328 m_selected_amount -= move_amount;
2329 m_selected_content_guess = ItemStack(); // Clear
2331 // Source stack goes partly into destination stack
2334 move_amount -= leftover.count;
2335 m_selected_amount -= move_amount;
2336 m_selected_content_guess = ItemStack(); // Clear
2339 infostream<<"Handing IACTION_MOVE to manager"<<std::endl;
2340 IMoveAction *a = new IMoveAction();
2341 a->count = move_amount;
2342 a->from_inv = m_selected_item->inventoryloc;
2343 a->from_list = m_selected_item->listname;
2344 a->from_i = m_selected_item->i;
2345 a->to_inv = s.inventoryloc;
2346 a->to_list = s.listname;
2348 m_invmgr->inventoryAction(a);
2350 else if(drop_amount > 0)
2352 m_selected_content_guess = ItemStack(); // Clear
2354 // Send IACTION_DROP
2356 assert(m_selected_item && m_selected_item->isValid());
2357 assert(inv_selected);
2358 InventoryList *list_from = inv_selected->getList(m_selected_item->listname);
2360 ItemStack stack_from = list_from->getItem(m_selected_item->i);
2362 // Check how many items can be dropped
2363 drop_amount = stack_from.count = MYMIN(drop_amount, stack_from.count);
2364 assert(drop_amount > 0 && drop_amount <= m_selected_amount);
2365 m_selected_amount -= drop_amount;
2367 infostream<<"Handing IACTION_DROP to manager"<<std::endl;
2368 IDropAction *a = new IDropAction();
2369 a->count = drop_amount;
2370 a->from_inv = m_selected_item->inventoryloc;
2371 a->from_list = m_selected_item->listname;
2372 a->from_i = m_selected_item->i;
2373 m_invmgr->inventoryAction(a);
2375 else if(craft_amount > 0)
2377 m_selected_content_guess = ItemStack(); // Clear
2379 // Send IACTION_CRAFT
2381 assert(s.isValid());
2384 infostream<<"Handing IACTION_CRAFT to manager"<<std::endl;
2385 ICraftAction *a = new ICraftAction();
2386 a->count = craft_amount;
2387 a->craft_inv = s.inventoryloc;
2388 m_invmgr->inventoryAction(a);
2391 // If m_selected_amount has been decreased to zero, deselect
2392 if(m_selected_amount == 0)
2394 delete m_selected_item;
2395 m_selected_item = NULL;
2396 m_selected_amount = 0;
2397 m_selected_dragging = false;
2398 m_selected_content_guess = ItemStack();
2401 if(event.EventType==EET_GUI_EVENT)
2404 if(event.GUIEvent.EventType==gui::EGET_TAB_CHANGED
2407 // find the element that was clicked
2408 for(u32 i=0; i<m_fields.size(); i++)
2410 FieldSpec &s = m_fields[i];
2411 // if its a button, set the send field so
2412 // lua knows which button was pressed
2413 if ((s.ftype == f_TabHeader) && (s.fid == event.GUIEvent.Caller->getID()))
2418 // Restore focus to the full form
2419 Environment->setFocus(this);
2424 if(event.GUIEvent.EventType==gui::EGET_ELEMENT_FOCUS_LOST
2427 if(!canTakeFocus(event.GUIEvent.Element))
2429 infostream<<"GUIFormSpecMenu: Not allowing focus change."
2431 // Returning true disables focus change
2435 if((event.GUIEvent.EventType==gui::EGET_BUTTON_CLICKED) ||
2436 (event.GUIEvent.EventType==gui::EGET_CHECKBOX_CHANGED))
2438 unsigned int btn_id = event.GUIEvent.Caller->getID();
2440 if (btn_id == 257) {
2445 m_text_dst->gotText(narrow_to_wide("ExitButton"));
2446 // quitMenu deallocates menu
2450 // find the element that was clicked
2451 for(u32 i=0; i<m_fields.size(); i++)
2453 FieldSpec &s = m_fields[i];
2454 // if its a button, set the send field so
2455 // lua knows which button was pressed
2456 if (((s.ftype == f_Button) || (s.ftype == f_CheckBox)) &&
2457 (s.fid == event.GUIEvent.Caller->getID()))
2465 m_text_dst->gotText(narrow_to_wide("ExitButton"));
2469 // Restore focus to the full form
2470 Environment->setFocus(this);
2476 if(event.GUIEvent.EventType==gui::EGET_EDITBOX_ENTER)
2478 if(event.GUIEvent.Caller->getID() > 257)
2484 m_text_dst->gotText(narrow_to_wide("EditBoxEnter"));
2485 // quitMenu deallocates menu
2490 if((event.GUIEvent.EventType==gui::EGET_LISTBOX_SELECTED_AGAIN) ||
2491 (event.GUIEvent.EventType==gui::EGET_LISTBOX_CHANGED))
2493 int current_id = event.GUIEvent.Caller->getID();
2494 if(current_id > 257)
2496 // find the element that was clicked
2497 for(u32 i=0; i<m_fields.size(); i++)
2499 FieldSpec &s = m_fields[i];
2500 // if its a button, set the send field so
2501 // lua knows which button was pressed
2502 if ((s.ftype == f_ListBox) && (s.fid == current_id))
2505 acceptInput(event.GUIEvent.EventType);
2507 // Restore focus to the full form
2508 Environment->setFocus(this);
2516 return Parent ? Parent->OnEvent(event) : false;
2519 bool GUIFormSpecMenu::parseColor(std::string color, irr::video::SColor& outcolor) {
2520 outcolor = irr::video::SColor(0,0,0,0);
2522 if(!string_allowed(color, "0123456789abcdefABCDEF"))
2526 std::istringstream iss(color);
2527 iss >> std::hex >> color_value;
2528 outcolor = irr::video::SColor(color_value);
2530 outcolor.setAlpha(255);