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() + 4);
666 std::string color = items[i].substr(1,3);
668 e->addItem(toadd.c_str());
670 bool valid_color = true;
672 irr::video::SColor toset = getColor(color,valid_color);
675 e->setItemOverrideColor(i,toset);
679 e->addItem(narrow_to_wide(items[i]).c_str());
683 if (str_initial_selection != "")
684 e->setSelected(stoi(str_initial_selection.c_str())-1);
686 if (data->listbox_selections.find(fname_w) != data->listbox_selections.end()) {
687 e->setSelected(data->listbox_selections[fname_w]);
690 m_listboxes.push_back(std::pair<FieldSpec,gui::IGUIListBox*>(spec,e));
691 m_fields.push_back(spec);
694 errorstream<< "Invalid textlist element(" << parts.size() << "): '" << element << "'" << std::endl;
698 void GUIFormSpecMenu::parseDropDown(parserData* data,std::string element) {
699 std::vector<std::string> parts = split(element,';');
701 if (parts.size() == 5) {
702 std::vector<std::string> v_pos = split(parts[0],',');
703 std::string name = parts[2];
704 std::vector<std::string> items = split(parts[3],',');
705 std::string str_initial_selection = "";
706 str_initial_selection = parts[4];
708 MY_CHECKPOS("dropdown",0);
711 pos.X += stof(v_pos[0]) * (float)spacing.X;
712 pos.Y += stof(v_pos[1]) * (float)spacing.Y;
714 s32 width = stof(parts[1]) * (float)spacing.Y;
716 core::rect<s32> rect = core::rect<s32>(pos.X, pos.Y, pos.X+width, pos.Y+30);
718 std::wstring fname_w = narrow_to_wide(name.c_str());
720 FieldSpec spec = FieldSpec(
727 spec.ftype = f_DropDown;
730 //now really show list
731 gui::IGUIComboBox *e = Environment->addComboBox(rect, this,spec.fid);
733 //don't reset if we already have a user specified selection
734 //if (data->combobox_selections.find(fname_w) == data->listbox_selections.end()) {
735 // e->setAutoScrollEnabled(false);
738 for (unsigned int i=0; i < items.size(); i++) {
739 e->addItem(narrow_to_wide(items[i]).c_str());
742 if (str_initial_selection != "")
743 e->setSelected(stoi(str_initial_selection.c_str())-1);
745 //if (data->listbox_selections.find(fname_w) != data->listbox_selections.end()) {
746 // e->setSelected(data->listbox_selections[fname_w]);
749 //m_listboxes.push_back(std::pair<FieldSpec,gui::IGUIListBox*>(spec,e));
750 m_fields.push_back(spec);
753 errorstream << "Invalid dropdown element(" << parts.size() << "): '"
754 << element << "'" << std::endl;
757 void GUIFormSpecMenu::parsePwdField(parserData* data,std::string element) {
758 std::vector<std::string> parts = split(element,';');
760 if (parts.size() == 4) {
761 std::vector<std::string> v_pos = split(parts[0],',');
762 std::vector<std::string> v_geom = split(parts[1],',');
763 std::string name = parts[2];
764 std::string label = parts[3];
766 MY_CHECKPOS("pwdfield",0);
767 MY_CHECKGEOM("pwdfield",1);
770 pos.X += stof(v_pos[0]) * (float)spacing.X;
771 pos.Y += stof(v_pos[1]) * (float)spacing.Y;
774 geom.X = (stof(v_geom[0]) * (float)spacing.X)-(spacing.X-imgsize.X);
776 pos.Y += (stof(v_geom[1]) * (float)imgsize.Y)/2;
780 core::rect<s32> rect = core::rect<s32>(pos.X, pos.Y, pos.X+geom.X, pos.Y+geom.Y);
782 label = unescape_string(label);
787 if (label.length() > 1)
788 wlabel = wgettext(label.c_str());
790 wlabel = (wchar_t*) narrow_to_wide("").c_str();
793 wlabel = (wchar_t*) narrow_to_wide(label.c_str()).c_str();
795 FieldSpec spec = FieldSpec(
796 narrow_to_wide(name.c_str()),
803 gui::IGUIEditBox * e = Environment->addEditBox(0, rect, true, this, spec.fid);
804 Environment->setFocus(e);
806 if (label.length() > 1)
808 rect.UpperLeftCorner.Y -= 15;
809 rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + 15;
810 Environment->addStaticText(spec.flabel.c_str(), rect, false, true, this, 0);
813 e->setPasswordBox(true,L'*');
816 evt.KeyInput.Key = KEY_END;
817 evt.EventType = EET_KEY_INPUT_EVENT;
818 evt.KeyInput.PressedDown = true;
820 m_fields.push_back(spec);
821 if ((m_use_gettext) && (label.length() >1))
825 errorstream<< "Invalid pwdfield element(" << parts.size() << "): '" << element << "'" << std::endl;
828 void GUIFormSpecMenu::parseSimpleField(parserData* data,std::vector<std::string> &parts) {
829 std::string name = parts[0];
830 std::string label = parts[1];
831 std::string default_val = parts[2];
833 core::rect<s32> rect;
837 rect = core::rect<s32>(
838 data->screensize.X/2 - 580/2,
839 data->screensize.Y/2 - 300/2,
840 data->screensize.X/2 + 580/2,
841 data->screensize.Y/2 + 300/2
844 recalculateAbsolutePosition(false);
845 data->basepos = getBasePos();
848 else if(data->bp_set == 2)
849 errorstream<<"WARNING: invalid use of unpositioned \"field\" in inventory"<<std::endl;
851 v2s32 pos = padding + AbsoluteRect.UpperLeftCorner;
852 pos.Y = ((m_fields.size()+2)*60);
853 v2s32 size = DesiredRect.getSize();
855 rect = core::rect<s32>(size.X/2-150, pos.Y, (size.X/2-150)+300, pos.Y+30);
859 default_val = m_form_src->resolveText(default_val);
861 default_val = unescape_string(default_val);
862 label = unescape_string(label);
867 if (label.length() > 1)
868 wlabel = wgettext(label.c_str());
870 wlabel = (wchar_t*) narrow_to_wide("").c_str();
873 wlabel = (wchar_t*) narrow_to_wide(label.c_str()).c_str();
875 FieldSpec spec = FieldSpec(
876 narrow_to_wide(name.c_str()),
878 narrow_to_wide(default_val.c_str()),
884 // spec field id to 0, this stops submit searching for a value that isn't there
885 Environment->addStaticText(spec.flabel.c_str(), rect, false, true, this, spec.fid);
890 gui::IGUIEditBox *e = Environment->addEditBox(spec.fdefault.c_str(), rect, true, this, spec.fid);
891 Environment->setFocus(e);
894 evt.KeyInput.Key = KEY_END;
895 evt.EventType = EET_KEY_INPUT_EVENT;
896 evt.KeyInput.PressedDown = true;
899 if (label.length() > 1)
901 rect.UpperLeftCorner.Y -= 15;
902 rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + 15;
903 Environment->addStaticText(spec.flabel.c_str(), rect, false, true, this, 0);
906 if (m_use_gettext && (label.length() > 1))
909 m_fields.push_back(spec);
912 void GUIFormSpecMenu::parseTextArea(parserData* data,std::vector<std::string>& parts,std::string type) {
914 std::vector<std::string> v_pos = split(parts[0],',');
915 std::vector<std::string> v_geom = split(parts[1],',');
916 std::string name = parts[2];
917 std::string label = parts[3];
918 std::string default_val = parts[4];
921 MY_CHECKGEOM(type,1);
924 pos.X = stof(v_pos[0]) * (float) spacing.X;
925 pos.Y = stof(v_pos[1]) * (float) spacing.Y;
929 geom.X = (stof(v_geom[0]) * (float)spacing.X)-(spacing.X-imgsize.X);
931 if (type == "textarea")
933 geom.Y = (stof(v_geom[1]) * (float)imgsize.Y) - (spacing.Y-imgsize.Y);
938 pos.Y += (stof(v_geom[1]) * (float)imgsize.Y)/2;
943 core::rect<s32> rect = core::rect<s32>(pos.X, pos.Y, pos.X+geom.X, pos.Y+geom.Y);
945 if(data->bp_set != 2)
946 errorstream<<"WARNING: invalid use of positioned "<<type<<" without a size[] element"<<std::endl;
949 default_val = m_form_src->resolveText(default_val);
952 default_val = unescape_string(default_val);
953 label = unescape_string(label);
958 if (label.length() > 1)
959 wlabel = wgettext(label.c_str());
961 wlabel = (wchar_t*) narrow_to_wide("").c_str();
964 wlabel = (wchar_t*) narrow_to_wide(label.c_str()).c_str();
966 FieldSpec spec = FieldSpec(
967 narrow_to_wide(name.c_str()),
969 narrow_to_wide(default_val.c_str()),
975 // spec field id to 0, this stops submit searching for a value that isn't there
976 Environment->addStaticText(spec.flabel.c_str(), rect, false, true, this, spec.fid);
981 gui::IGUIEditBox *e = Environment->addEditBox(spec.fdefault.c_str(), rect, true, this, spec.fid);
982 Environment->setFocus(e);
984 if (type == "textarea")
986 e->setMultiLine(true);
987 e->setTextAlignment(gui::EGUIA_UPPERLEFT, gui::EGUIA_UPPERLEFT);
990 evt.EventType = EET_KEY_INPUT_EVENT;
991 evt.KeyInput.Key = KEY_END;
992 evt.KeyInput.Char = 0;
993 evt.KeyInput.Control = 0;
994 evt.KeyInput.Shift = 0;
995 evt.KeyInput.PressedDown = true;
999 if (label.length() > 1)
1001 rect.UpperLeftCorner.Y -= 15;
1002 rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + 15;
1003 Environment->addStaticText(spec.flabel.c_str(), rect, false, true, this, 0);
1006 if (m_use_gettext && (label.length() > 1))
1008 m_fields.push_back(spec);
1011 void GUIFormSpecMenu::parseField(parserData* data,std::string element,std::string type) {
1012 std::vector<std::string> parts = split(element,';');
1014 if (parts.size() == 3) {
1015 parseSimpleField(data,parts);
1019 if (parts.size() == 5) {
1020 parseTextArea(data,parts,type);
1023 errorstream<< "Invalid field element(" << parts.size() << "): '" << element << "'" << std::endl;
1026 void GUIFormSpecMenu::parseLabel(parserData* data,std::string element) {
1027 std::vector<std::string> parts = split(element,';');
1029 if (parts.size() == 2) {
1030 std::vector<std::string> v_pos = split(parts[0],',');
1031 std::string text = parts[1];
1033 MY_CHECKPOS("label",0);
1035 v2s32 pos = padding;
1036 pos.X += stof(v_pos[0]) * (float)spacing.X;
1037 pos.Y += stof(v_pos[1]) * (float)spacing.Y;
1039 core::rect<s32> rect = core::rect<s32>(pos.X, pos.Y+((imgsize.Y/2)-15), pos.X+300, pos.Y+((imgsize.Y/2)+15));
1041 if(data->bp_set != 2)
1042 errorstream<<"WARNING: invalid use of label without a size[] element"<<std::endl;
1044 text = unescape_string(text);
1046 wchar_t* wlabel = 0;
1049 wlabel = wgettext(text.c_str());
1051 wlabel = (wchar_t*) narrow_to_wide(text.c_str()).c_str();
1053 FieldSpec spec = FieldSpec(
1059 Environment->addStaticText(spec.flabel.c_str(), rect, false, true, this, spec.fid);
1060 m_fields.push_back(spec);
1065 errorstream<< "Invalid label element(" << parts.size() << "): '" << element << "'" << std::endl;
1068 void GUIFormSpecMenu::parseVertLabel(parserData* data,std::string element) {
1069 std::vector<std::string> parts = split(element,';');
1071 if (parts.size() == 2) {
1072 std::vector<std::string> v_pos = split(parts[0],',');
1073 std::string text = parts[1];
1075 MY_CHECKPOS("vertlabel",1);
1077 v2s32 pos = padding;
1078 pos.X += stof(v_pos[0]) * (float)spacing.X;
1079 pos.Y += stof(v_pos[1]) * (float)spacing.Y;
1081 core::rect<s32> rect = core::rect<s32>(pos.X, pos.Y+((imgsize.Y/2)-15), pos.X+15, pos.Y+300);
1083 if(data->bp_set != 2)
1084 errorstream<<"WARNING: invalid use of label without a size[] element"<<std::endl;
1086 text = unescape_string(text);
1087 std::string label = "";
1089 if (m_use_gettext) {
1090 const char* toset = gettext(text.c_str());
1092 text = std::string(toset);
1095 for (unsigned int i=0; i < text.length(); i++) {
1096 label += text.c_str()[i];
1100 FieldSpec spec = FieldSpec(
1102 narrow_to_wide(label.c_str()),
1106 gui::IGUIStaticText *t =
1107 Environment->addStaticText(spec.flabel.c_str(), rect, false, true, this, spec.fid);
1108 t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
1109 m_fields.push_back(spec);
1112 errorstream<< "Invalid vertlabel element(" << parts.size() << "): '" << element << "'" << std::endl;
1115 void GUIFormSpecMenu::parseImageButton(parserData* data,std::string element,std::string type) {
1116 std::vector<std::string> parts = split(element,';');
1118 if ((parts.size() == 5) || (parts.size() == 7)) {
1119 std::vector<std::string> v_pos = split(parts[0],',');
1120 std::vector<std::string> v_geom = split(parts[1],',');
1121 std::string image_name = parts[2];
1122 std::string name = parts[3];
1123 std::string label = parts[4];
1125 MY_CHECKPOS("imagebutton",0);
1126 MY_CHECKGEOM("imagebutton",1);
1128 v2s32 pos = padding;
1129 pos.X += stof(v_pos[0]) * (float)spacing.X;
1130 pos.Y += stof(v_pos[1]) * (float)spacing.Y;
1132 geom.X = (stof(v_geom[0]) * (float)spacing.X)-(spacing.X-imgsize.X);
1133 geom.Y = (stof(v_geom[1]) * (float)spacing.Y)-(spacing.Y-imgsize.Y);
1135 bool noclip = false;
1136 bool drawborder = true;
1138 if ((parts.size() == 7)) {
1139 if (parts[5] == "true")
1142 if (parts[6] == "false")
1146 core::rect<s32> rect = core::rect<s32>(pos.X, pos.Y, pos.X+geom.X, pos.Y+geom.Y);
1148 if(data->bp_set != 2)
1149 errorstream<<"WARNING: invalid use of item_image_button without a size[] element"<<std::endl;
1151 label = unescape_string(label);
1153 FieldSpec spec = FieldSpec(
1154 narrow_to_wide(name.c_str()),
1155 narrow_to_wide(label.c_str()),
1156 narrow_to_wide(image_name.c_str()),
1159 spec.ftype = f_Button;
1160 if(type == "image_button_exit")
1161 spec.is_exit = true;
1163 video::ITexture *texture = 0;
1164 //if there's no gamedef specified try to get direct
1165 //TODO check for possible texture leak
1167 texture = m_gamedef->tsrc()->getTexture(image_name);
1169 if (fs::PathExists(image_name)) {
1170 texture = Environment->getVideoDriver()->getTexture(image_name.c_str());
1171 m_Textures.push_back(texture);
1175 gui::IGUIButton *e = Environment->addButton(rect, this, spec.fid, spec.flabel.c_str());
1176 e->setUseAlphaChannel(true);
1177 e->setImage(texture);
1178 e->setPressedImage(texture);
1179 e->setScaleImage(true);
1180 e->setNotClipped(noclip);
1181 e->setDrawBorder(drawborder);
1183 m_fields.push_back(spec);
1187 errorstream<< "Invalid imagebutton element(" << parts.size() << "): '" << element << "'" << std::endl;
1190 void GUIFormSpecMenu::parseTabHeader(parserData* data,std::string element) {
1191 std::vector<std::string> parts = split(element,';');
1193 if ((parts.size() == 4) || (parts.size() == 6)) {
1194 std::vector<std::string> v_pos = split(parts[0],',');
1195 std::string name = parts[1];
1196 std::vector<std::string> buttons = split(parts[2],',');
1197 std::string str_index = parts[3];
1198 bool show_background = true;
1199 bool show_border = true;
1200 int tab_index = stoi(str_index) -1;
1202 MY_CHECKPOS("tabheader",0);
1204 if (parts.size() == 6) {
1205 if (parts[4] == "true")
1206 show_background = false;
1207 if (parts[5] == "false")
1208 show_border = false;
1211 FieldSpec spec = FieldSpec(
1212 narrow_to_wide(name.c_str()),
1218 spec.ftype = f_TabHeader;
1220 v2s32 pos = padding;
1221 pos.X += stof(v_pos[0]) * (float)spacing.X;
1222 pos.Y += stof(v_pos[1]) * (float)spacing.Y;
1224 geom.X = data->screensize.Y;
1227 core::rect<s32> rect = core::rect<s32>(pos.X, pos.Y, pos.X+geom.X, pos.Y+geom.Y);
1229 gui::IGUITabControl *e = Environment->addTabControl(rect,this,show_background,show_border,spec.fid);
1231 e->setNotClipped(true);
1233 for (unsigned int i=0; i< buttons.size(); i++) {
1234 wchar_t* wbutton = 0;
1237 wbutton = wgettext(buttons[i].c_str());
1239 wbutton = (wchar_t*) narrow_to_wide(buttons[i].c_str()).c_str();
1241 e->addTab(wbutton,-1);
1247 if ((tab_index >= 0) &&
1248 (buttons.size() < INT_MAX) &&
1249 (tab_index < (int) buttons.size()))
1250 e->setActiveTab(tab_index);
1252 m_fields.push_back(spec);
1255 errorstream<< "Invalid TabHeader element(" << parts.size() << "): '" << element << "'" << std::endl;
1258 void GUIFormSpecMenu::parseItemImageButton(parserData* data,std::string element) {
1260 if (m_gamedef == 0) {
1261 errorstream<<"WARNING: invalid use of item_image_button with m_gamedef==0"<<std::endl;
1265 std::vector<std::string> parts = split(element,';');
1267 if (parts.size() == 5) {
1268 std::vector<std::string> v_pos = split(parts[0],',');
1269 std::vector<std::string> v_geom = split(parts[1],',');
1270 std::string item_name = parts[2];
1271 std::string name = parts[3];
1272 std::string label = parts[4];
1274 MY_CHECKPOS("itemimagebutton",0);
1275 MY_CHECKGEOM("itemimagebutton",1);
1277 v2s32 pos = padding;
1278 pos.X += stof(v_pos[0]) * (float)spacing.X;
1279 pos.Y += stof(v_pos[1]) * (float)spacing.Y;
1281 geom.X = (stof(v_geom[0]) * (float)spacing.X)-(spacing.X-imgsize.X);
1282 geom.Y = (stof(v_geom[1]) * (float)spacing.Y)-(spacing.Y-imgsize.Y);
1284 core::rect<s32> rect = core::rect<s32>(pos.X, pos.Y, pos.X+geom.X, pos.Y+geom.Y);
1286 if(data->bp_set != 2)
1287 errorstream<<"WARNING: invalid use of item_image_button without a size[] element"<<std::endl;
1289 IItemDefManager *idef = m_gamedef->idef();
1291 item.deSerialize(item_name, idef);
1292 video::ITexture *texture = idef->getInventoryTexture(item.getDefinition(idef).name, m_gamedef);
1293 std::string tooltip = item.getDefinition(idef).description;
1295 label = unescape_string(label);
1296 FieldSpec spec = FieldSpec(
1297 narrow_to_wide(name.c_str()),
1298 narrow_to_wide(label.c_str()),
1299 narrow_to_wide(item_name.c_str()),
1303 gui::IGUIButton *e = Environment->addButton(rect, this, spec.fid, spec.flabel.c_str());
1304 e->setUseAlphaChannel(true);
1305 e->setImage(texture);
1306 e->setPressedImage(texture);
1307 e->setScaleImage(true);
1308 spec.ftype = f_Button;
1309 rect+=data->basepos-padding;
1312 spec.tooltip=tooltip;
1313 m_fields.push_back(spec);
1316 errorstream<< "Invalid ItemImagebutton element(" << parts.size() << "): '" << element << "'" << std::endl;
1319 void GUIFormSpecMenu::parseBox(parserData* data,std::string element) {
1320 std::vector<std::string> parts = split(element,';');
1322 if (parts.size() == 3) {
1323 std::vector<std::string> v_pos = split(parts[0],',');
1324 std::vector<std::string> v_geom = split(parts[1],',');
1325 std::string color_str = parts[2];
1327 MY_CHECKPOS("box",0);
1328 MY_CHECKGEOM("box",1);
1330 v2s32 pos = padding + AbsoluteRect.UpperLeftCorner;
1331 pos.X += stof(v_pos[0]) * (float) spacing.X;
1332 pos.Y += stof(v_pos[1]) * (float) spacing.Y;
1335 geom.X = stof(v_geom[0]) * (float)spacing.X;
1336 geom.Y = stof(v_geom[1]) * (float)spacing.Y;
1338 bool valid_color = false;
1340 irr::video::SColor color = getColor(color_str,valid_color);
1343 BoxDrawSpec spec(pos,geom,color);
1345 m_boxes.push_back(spec);
1348 errorstream<< "Invalid Box element(" << parts.size() << "): '" << element << "' INVALID COLOR" << std::endl;
1352 errorstream<< "Invalid Box element(" << parts.size() << "): '" << element << "'" << std::endl;
1355 void GUIFormSpecMenu::parseElement(parserData* data,std::string element) {
1360 std::vector<std::string> parts = split(element,'[', true);
1362 if (parts.size() != 2)
1365 std::string type = trim(parts[0]);
1366 std::string description = trim(parts[1]);
1368 if ((type == "size") || (type == "invsize")){
1369 parseSize(data,description);
1373 if (type == "list") {
1374 parseList(data,description);
1378 if (type == "checkbox") {
1379 parseCheckbox(data,description);
1383 if (type == "image") {
1384 parseImage(data,description);
1388 if (type == "item_image") {
1389 parseItemImage(data,description);
1393 if ((type == "button") || (type == "button_exit")) {
1394 parseButton(data,description,type);
1398 if (type == "background") {
1399 parseBackground(data,description);
1403 if (type == "textlist"){
1404 parseTextList(data,description);
1408 if (type == "dropdown"){
1409 parseDropDown(data,description);
1413 if (type == "pwdfield") {
1414 parsePwdField(data,description);
1418 if ((type == "field") || (type == "textarea")){
1419 parseField(data,description,type);
1423 if (type == "label") {
1424 parseLabel(data,description);
1428 if (type == "vertlabel") {
1429 parseVertLabel(data,description);
1433 if (type == "item_image_button") {
1434 parseItemImageButton(data,description);
1438 if ((type == "image_button") || (type == "image_button_exit")) {
1439 parseImageButton(data,description,type);
1443 if (type == "tabheader") {
1444 parseTabHeader(data,description);
1448 if (type == "box") {
1449 parseBox(data,description);
1455 << "Unknown DrawSpec: type="<<type<<", data=\""<<description<<"\""
1461 void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
1465 //preserve listboxes
1466 for (unsigned int i = 0; i < m_listboxes.size(); i++) {
1467 int selection = m_listboxes[i].second->getSelected();
1468 if (selection != -1) {
1469 std::wstring listboxname = m_listboxes[i].first.fname;
1470 mydata.listbox_selections[listboxname] = selection;
1477 mydata.size= v2s32(100,100);
1478 mydata.helptext_h = 15;
1479 mydata.screensize = screensize;
1481 // Base position of contents of form
1482 mydata.basepos = getBasePos();
1484 // State of basepos, 0 = not set, 1= set by formspec, 2 = set by size[] element
1485 // Used to adjust form size automatically if needed
1486 // A proceed button is added if there is no size[] element
1490 /* Convert m_init_draw_spec to m_inventorylists */
1492 m_inventorylists.clear();
1494 m_backgrounds.clear();
1495 m_itemimages.clear();
1496 m_listboxes.clear();
1497 m_checkboxes.clear();
1502 std::vector<std::string> elements = split(m_formspec_string,']',true);
1504 for (unsigned int i=0;i< elements.size();i++) {
1505 parseElement(&mydata,elements[i]);
1508 // If there's inventory, put the usage string at the bottom
1509 if (m_inventorylists.size())
1512 core::rect<s32> rect(0, 0, mydata.size.X-padding.X*2, mydata.helptext_h);
1513 rect = rect + v2s32((mydata.size.X/2 - mydata.rect.getWidth()/2) +5,
1514 mydata.size.Y-5-mydata.helptext_h);
1515 const wchar_t *text = wgettext("Left click: Move all items, Right click: Move single item");
1516 Environment->addStaticText(text, rect, false, true, this, 256);
1520 // If there's fields, add a Proceed button
1521 if (m_fields.size() && mydata.bp_set != 2)
1523 // if the size wasn't set by an invsize[] or size[] adjust it now to fit all the fields
1524 mydata.rect = core::rect<s32>(
1525 mydata.screensize.X/2 - 580/2,
1526 mydata.screensize.Y/2 - 300/2,
1527 mydata.screensize.X/2 + 580/2,
1528 mydata.screensize.Y/2 + 240/2+(m_fields.size()*60)
1530 DesiredRect = mydata.rect;
1531 recalculateAbsolutePosition(false);
1532 mydata.basepos = getBasePos();
1536 v2s32 pos = mydata.basepos;
1537 pos.Y = ((m_fields.size()+2)*60);
1539 v2s32 size = DesiredRect.getSize();
1540 mydata.rect = core::rect<s32>(size.X/2-70, pos.Y, (size.X/2-70)+140, pos.Y+30);
1541 wchar_t* text = wgettext("Proceed");
1542 Environment->addButton(mydata.rect, this, 257, text);
1549 // Note: parent != this so that the tooltip isn't clipped by the menu rectangle
1550 m_tooltip_element = Environment->addStaticText(L"",core::rect<s32>(0,0,110,18));
1551 m_tooltip_element->enableOverrideColor(true);
1552 m_tooltip_element->setBackgroundColor(video::SColor(255,110,130,60));
1553 m_tooltip_element->setDrawBackground(true);
1554 m_tooltip_element->setDrawBorder(true);
1555 m_tooltip_element->setOverrideColor(video::SColor(255,255,255,255));
1556 m_tooltip_element->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER);
1557 m_tooltip_element->setWordWrap(false);
1561 GUIFormSpecMenu::ItemSpec GUIFormSpecMenu::getItemAtPos(v2s32 p) const
1563 core::rect<s32> imgrect(0,0,imgsize.X,imgsize.Y);
1565 for(u32 i=0; i<m_inventorylists.size(); i++)
1567 const ListDrawSpec &s = m_inventorylists[i];
1569 for(s32 i=0; i<s.geom.X*s.geom.Y; i++)
1571 s32 item_i = i + s.start_item_i;
1572 s32 x = (i%s.geom.X) * spacing.X;
1573 s32 y = (i/s.geom.X) * spacing.Y;
1575 core::rect<s32> rect = imgrect + s.pos + p0;
1576 if(rect.isPointInside(p))
1578 return ItemSpec(s.inventoryloc, s.listname, item_i);
1583 return ItemSpec(InventoryLocation(), "", -1);
1586 void GUIFormSpecMenu::drawList(const ListDrawSpec &s, int phase)
1588 video::IVideoDriver* driver = Environment->getVideoDriver();
1591 gui::IGUIFont *font = NULL;
1592 gui::IGUISkin* skin = Environment->getSkin();
1594 font = skin->getFont();
1596 Inventory *inv = m_invmgr->getInventory(s.inventoryloc);
1598 infostream<<"GUIFormSpecMenu::drawList(): WARNING: "
1599 <<"The inventory location "
1600 <<"\""<<s.inventoryloc.dump()<<"\" doesn't exist"
1604 InventoryList *ilist = inv->getList(s.listname);
1606 infostream<<"GUIFormSpecMenu::drawList(): WARNING: "
1607 <<"The inventory list \""<<s.listname<<"\" @ \""
1608 <<s.inventoryloc.dump()<<"\" doesn't exist"
1613 core::rect<s32> imgrect(0,0,imgsize.X,imgsize.Y);
1615 for(s32 i=0; i<s.geom.X*s.geom.Y; i++)
1617 s32 item_i = i + s.start_item_i;
1618 if(item_i >= (s32) ilist->getSize())
1620 s32 x = (i%s.geom.X) * spacing.X;
1621 s32 y = (i/s.geom.X) * spacing.Y;
1623 core::rect<s32> rect = imgrect + s.pos + p;
1626 item = ilist->getItem(item_i);
1628 bool selected = m_selected_item
1629 && m_invmgr->getInventory(m_selected_item->inventoryloc) == inv
1630 && m_selected_item->listname == s.listname
1631 && m_selected_item->i == item_i;
1632 bool hovering = rect.isPointInside(m_pointer);
1636 if(hovering && m_selected_item)
1638 video::SColor bgcolor(255,192,192,192);
1639 driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
1643 video::SColor bgcolor(255,128,128,128);
1644 driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
1653 item.takeItem(m_selected_amount);
1657 drawItemStack(driver, font, item,
1658 rect, &AbsoluteClippingRect, m_gamedef);
1662 std::string tooltip_text = "";
1663 if(hovering && !m_selected_item)
1664 tooltip_text = item.getDefinition(m_gamedef->idef()).description;
1665 if(tooltip_text != "")
1667 m_tooltip_element->setVisible(true);
1668 this->bringToFront(m_tooltip_element);
1669 m_tooltip_element->setText(narrow_to_wide(tooltip_text).c_str());
1670 s32 tooltip_x = m_pointer.X + 15;
1671 s32 tooltip_y = m_pointer.Y + 15;
1672 s32 tooltip_width = m_tooltip_element->getTextWidth() + 15;
1673 s32 tooltip_height = m_tooltip_element->getTextHeight() + 5;
1674 m_tooltip_element->setRelativePosition(core::rect<s32>(
1675 core::position2d<s32>(tooltip_x, tooltip_y),
1676 core::dimension2d<s32>(tooltip_width, tooltip_height)));
1682 void GUIFormSpecMenu::drawSelectedItem()
1684 if(!m_selected_item)
1687 video::IVideoDriver* driver = Environment->getVideoDriver();
1690 gui::IGUIFont *font = NULL;
1691 gui::IGUISkin* skin = Environment->getSkin();
1693 font = skin->getFont();
1695 Inventory *inv = m_invmgr->getInventory(m_selected_item->inventoryloc);
1697 InventoryList *list = inv->getList(m_selected_item->listname);
1699 ItemStack stack = list->getItem(m_selected_item->i);
1700 stack.count = m_selected_amount;
1702 core::rect<s32> imgrect(0,0,imgsize.X,imgsize.Y);
1703 core::rect<s32> rect = imgrect + (m_pointer - imgrect.getCenter());
1704 drawItemStack(driver, font, stack, rect, NULL, m_gamedef);
1707 void GUIFormSpecMenu::drawMenu()
1710 std::string newform = m_form_src->getForm();
1711 if(newform != m_formspec_string){
1712 m_formspec_string = newform;
1713 regenerateGui(m_screensize_old);
1717 m_pointer = m_device->getCursorControl()->getPosition();
1719 updateSelectedItem();
1721 gui::IGUISkin* skin = Environment->getSkin();
1724 video::IVideoDriver* driver = Environment->getVideoDriver();
1726 video::SColor bgcolor(140,0,0,0);
1727 driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);
1729 m_tooltip_element->setVisible(false);
1734 for(u32 i=0; i<m_backgrounds.size(); i++)
1736 const ImageDrawSpec &spec = m_backgrounds[i];
1737 video::ITexture *texture = 0;
1740 texture = m_gamedef->tsrc()->getTexture(spec.name);
1743 texture = driver->getTexture(spec.name.c_str());
1744 m_Textures.push_back(texture);
1748 // Image size on screen
1749 core::rect<s32> imgrect(0, 0, spec.geom.X, spec.geom.Y);
1750 // Image rectangle on screen
1751 core::rect<s32> rect = imgrect + spec.pos;
1752 const video::SColor color(255,255,255,255);
1753 const video::SColor colors[] = {color,color,color,color};
1754 driver->draw2DImage(texture, rect,
1755 core::rect<s32>(core::position2d<s32>(0,0),
1756 core::dimension2di(texture->getOriginalSize())),
1757 NULL/*&AbsoluteClippingRect*/, colors, true);
1760 errorstream << "GUIFormSpecMenu::drawMenu() Draw backgrounds unable to load texture:" << std::endl;
1761 errorstream << "\t" << spec.name << std::endl;
1768 for(u32 i=0; i<m_boxes.size(); i++)
1770 const BoxDrawSpec &spec = m_boxes[i];
1772 irr::video::SColor todraw = spec.color;
1774 todraw.setAlpha(140);
1776 core::rect<s32> rect(spec.pos.X,spec.pos.Y,
1777 spec.pos.X + spec.geom.X,spec.pos.Y + spec.geom.Y);
1779 driver->draw2DRectangle(todraw, rect, 0);
1784 for(u32 i=0; i<m_images.size(); i++)
1786 const ImageDrawSpec &spec = m_images[i];
1787 video::ITexture *texture = 0;
1790 texture = m_gamedef->tsrc()->getTexture(spec.name);
1793 texture = driver->getTexture(spec.name.c_str());
1794 m_Textures.push_back(texture);
1797 const core::dimension2d<u32>& img_origsize = texture->getOriginalSize();
1798 // Image size on screen
1799 core::rect<s32> imgrect;
1802 imgrect = core::rect<s32>(0,0,spec.geom.X, spec.geom.Y);
1805 imgrect = core::rect<s32>(0,0,img_origsize.Width,img_origsize.Height);
1807 // Image rectangle on screen
1808 core::rect<s32> rect = imgrect + spec.pos;
1809 const video::SColor color(255,255,255,255);
1810 const video::SColor colors[] = {color,color,color,color};
1811 driver->draw2DImage(texture, rect,
1812 core::rect<s32>(core::position2d<s32>(0,0),img_origsize),
1813 NULL/*&AbsoluteClippingRect*/, colors, true);
1816 errorstream << "GUIFormSpecMenu::drawMenu() Draw images unable to load texture:" << std::endl;
1817 errorstream << "\t" << spec.name << std::endl;
1824 for(u32 i=0; i<m_itemimages.size(); i++)
1829 const ImageDrawSpec &spec = m_itemimages[i];
1830 IItemDefManager *idef = m_gamedef->idef();
1832 item.deSerialize(spec.name, idef);
1833 video::ITexture *texture = idef->getInventoryTexture(item.getDefinition(idef).name, m_gamedef);
1834 // Image size on screen
1835 core::rect<s32> imgrect(0, 0, spec.geom.X, spec.geom.Y);
1836 // Image rectangle on screen
1837 core::rect<s32> rect = imgrect + spec.pos;
1838 const video::SColor color(255,255,255,255);
1839 const video::SColor colors[] = {color,color,color,color};
1840 driver->draw2DImage(texture, rect,
1841 core::rect<s32>(core::position2d<s32>(0,0),
1842 core::dimension2di(texture->getOriginalSize())),
1843 NULL/*&AbsoluteClippingRect*/, colors, true);
1848 Phase 0: Item slot rectangles
1849 Phase 1: Item images; prepare tooltip
1850 If backgrounds used, do not draw Item slot rectangles
1853 if (m_backgrounds.size() > 0) start_phase=1;
1854 for(int phase=start_phase; phase<=1; phase++)
1855 for(u32 i=0; i<m_inventorylists.size(); i++)
1857 drawList(m_inventorylists[i], phase);
1863 gui::IGUIElement::draw();
1866 Draw fields/buttons tooltips
1868 for(u32 i=0; i<m_fields.size(); i++)
1870 const FieldSpec &spec = m_fields[i];
1871 if (spec.tooltip != "")
1873 core::rect<s32> rect = spec.rect;
1874 if (rect.isPointInside(m_pointer))
1876 m_tooltip_element->setVisible(true);
1877 this->bringToFront(m_tooltip_element);
1878 m_tooltip_element->setText(narrow_to_wide(spec.tooltip).c_str());
1879 s32 tooltip_x = m_pointer.X + 15;
1880 s32 tooltip_y = m_pointer.Y + 15;
1881 s32 tooltip_width = m_tooltip_element->getTextWidth() + 15;
1882 s32 tooltip_height = m_tooltip_element->getTextHeight() + 5;
1883 m_tooltip_element->setRelativePosition(core::rect<s32>(
1884 core::position2d<s32>(tooltip_x, tooltip_y),
1885 core::dimension2d<s32>(tooltip_width, tooltip_height)));
1891 Draw dragged item stack
1896 void GUIFormSpecMenu::updateSelectedItem()
1898 // If the selected stack has become empty for some reason, deselect it.
1899 // If the selected stack has become inaccessible, deselect it.
1900 // If the selected stack has become smaller, adjust m_selected_amount.
1901 ItemStack selected = verifySelectedItem();
1903 // WARNING: BLACK MAGIC
1904 // See if there is a stack suited for our current guess.
1905 // If such stack does not exist, clear the guess.
1906 if(m_selected_content_guess.name != "" &&
1907 selected.name == m_selected_content_guess.name &&
1908 selected.count == m_selected_content_guess.count){
1909 // Selected item fits the guess. Skip the black magic.
1911 else if(m_selected_content_guess.name != ""){
1913 for(u32 i=0; i<m_inventorylists.size() && !found; i++){
1914 const ListDrawSpec &s = m_inventorylists[i];
1915 Inventory *inv = m_invmgr->getInventory(s.inventoryloc);
1918 InventoryList *list = inv->getList(s.listname);
1921 for(s32 i=0; i<s.geom.X*s.geom.Y && !found; i++){
1922 u32 item_i = i + s.start_item_i;
1923 if(item_i >= list->getSize())
1925 ItemStack stack = list->getItem(item_i);
1926 if(stack.name == m_selected_content_guess.name &&
1927 stack.count == m_selected_content_guess.count){
1929 infostream<<"Client: Changing selected content guess to "
1930 <<s.inventoryloc.dump()<<" "<<s.listname
1931 <<" "<<item_i<<std::endl;
1932 delete m_selected_item;
1933 m_selected_item = new ItemSpec(s.inventoryloc, s.listname, item_i);
1934 m_selected_amount = stack.count;
1939 infostream<<"Client: Discarding selected content guess: "
1940 <<m_selected_content_guess.getItemString()<<std::endl;
1941 m_selected_content_guess.name = "";
1945 // If craftresult is nonempty and nothing else is selected, select it now.
1946 if(!m_selected_item)
1948 for(u32 i=0; i<m_inventorylists.size(); i++)
1950 const ListDrawSpec &s = m_inventorylists[i];
1951 if(s.listname == "craftpreview")
1953 Inventory *inv = m_invmgr->getInventory(s.inventoryloc);
1954 InventoryList *list = inv->getList("craftresult");
1955 if(list && list->getSize() >= 1 && !list->getItem(0).empty())
1957 m_selected_item = new ItemSpec;
1958 m_selected_item->inventoryloc = s.inventoryloc;
1959 m_selected_item->listname = "craftresult";
1960 m_selected_item->i = 0;
1961 m_selected_amount = 0;
1962 m_selected_dragging = false;
1969 // If craftresult is selected, keep the whole stack selected
1970 if(m_selected_item && m_selected_item->listname == "craftresult")
1972 m_selected_amount = verifySelectedItem().count;
1976 ItemStack GUIFormSpecMenu::verifySelectedItem()
1978 // If the selected stack has become empty for some reason, deselect it.
1979 // If the selected stack has become inaccessible, deselect it.
1980 // If the selected stack has become smaller, adjust m_selected_amount.
1981 // Return the selected stack.
1985 if(m_selected_item->isValid())
1987 Inventory *inv = m_invmgr->getInventory(m_selected_item->inventoryloc);
1990 InventoryList *list = inv->getList(m_selected_item->listname);
1991 if(list && (u32) m_selected_item->i < list->getSize())
1993 ItemStack stack = list->getItem(m_selected_item->i);
1994 if(m_selected_amount > stack.count)
1995 m_selected_amount = stack.count;
2002 // selection was not valid
2003 delete m_selected_item;
2004 m_selected_item = NULL;
2005 m_selected_amount = 0;
2006 m_selected_dragging = false;
2011 void GUIFormSpecMenu::acceptInput(int eventtype)
2015 std::map<std::string, std::string> fields;
2017 for(u32 i=0; i<m_fields.size(); i++)
2019 const FieldSpec &s = m_fields[i];
2022 if(s.ftype == f_Button)
2024 fields[wide_to_narrow(s.fname.c_str())] = wide_to_narrow(s.flabel.c_str());
2026 else if(s.ftype == f_ListBox) {
2027 std::stringstream ss;
2028 if (eventtype == gui::EGET_LISTBOX_CHANGED) {
2034 ss << (getListboxIndex(wide_to_narrow(s.fname.c_str()))+1);
2035 fields[wide_to_narrow(s.fname.c_str())] = ss.str();
2037 else if(s.ftype == f_DropDown) {
2038 // no dynamic cast possible due to some distributions shipped
2039 // without rtti support in irrlicht
2040 IGUIElement * element = getElementFromId(s.fid);
2041 gui::IGUIComboBox *e = NULL;
2042 if ((element) && (element->getType() == gui::EGUIET_COMBO_BOX)) {
2043 e = static_cast<gui::IGUIComboBox*>(element);
2045 fields[wide_to_narrow(s.fname.c_str())] =
2046 wide_to_narrow(e->getItem(e->getSelected()));
2048 else if (s.ftype == f_TabHeader) {
2049 // no dynamic cast possible due to some distributions shipped
2050 // without rtti support in irrlicht
2051 IGUIElement * element = getElementFromId(s.fid);
2052 gui::IGUITabControl *e = NULL;
2053 if ((element) && (element->getType() == gui::EGUIET_TAB_CONTROL)) {
2054 e = static_cast<gui::IGUITabControl*>(element);
2058 std::stringstream ss;
2059 ss << (e->getActiveTab() +1);
2060 fields[wide_to_narrow(s.fname.c_str())] = ss.str();
2063 else if (s.ftype == f_CheckBox) {
2064 // no dynamic cast possible due to some distributions shipped
2065 // without rtti support in irrlicht
2066 IGUIElement * element = getElementFromId(s.fid);
2067 gui::IGUICheckBox *e = NULL;
2068 if ((element) && (element->getType() == gui::EGUIET_CHECK_BOX)) {
2069 e = static_cast<gui::IGUICheckBox*>(element);
2074 fields[wide_to_narrow(s.fname.c_str())] = "true";
2076 fields[wide_to_narrow(s.fname.c_str())] = "false";
2081 IGUIElement* e = getElementFromId(s.fid);
2084 fields[wide_to_narrow(s.fname.c_str())] = wide_to_narrow(e->getText());
2090 m_text_dst->gotText(fields);
2094 bool GUIFormSpecMenu::OnEvent(const SEvent& event)
2096 if(event.EventType==EET_KEY_INPUT_EVENT)
2098 KeyPress kp(event.KeyInput);
2099 if (event.KeyInput.PressedDown && (kp == EscapeKey ||
2100 kp == getKeySetting("keymap_inventory")))
2105 m_text_dst->gotText(narrow_to_wide("MenuQuit"));
2108 if(event.KeyInput.Key==KEY_RETURN && event.KeyInput.PressedDown)
2115 m_text_dst->gotText(narrow_to_wide("KeyEnter"));
2119 if(event.EventType==EET_MOUSE_INPUT_EVENT
2120 && event.MouseInput.Event != EMIE_MOUSE_MOVED)
2122 // Mouse event other than movement
2124 // Get selected item and hovered/clicked item (s)
2126 updateSelectedItem();
2127 ItemSpec s = getItemAtPos(m_pointer);
2129 Inventory *inv_selected = NULL;
2130 Inventory *inv_s = NULL;
2134 inv_selected = m_invmgr->getInventory(m_selected_item->inventoryloc);
2135 assert(inv_selected);
2136 assert(inv_selected->getList(m_selected_item->listname) != NULL);
2143 inv_s = m_invmgr->getInventory(s.inventoryloc);
2146 errorstream<<"InventoryMenu: The selected inventory location "
2147 <<"\""<<s.inventoryloc.dump()<<"\" doesn't exist"
2149 s.i = -1; // make it invalid again
2153 InventoryList *list = inv_s->getList(s.listname);
2155 verbosestream<<"InventoryMenu: The selected inventory list \""
2156 <<s.listname<<"\" does not exist"<<std::endl;
2157 s.i = -1; // make it invalid again
2161 if((u32)s.i >= list->getSize()){
2162 infostream<<"InventoryMenu: The selected inventory list \""
2163 <<s.listname<<"\" is too small (i="<<s.i<<", size="
2164 <<list->getSize()<<")"<<std::endl;
2165 s.i = -1; // make it invalid again
2169 s_count = list->getItem(s.i).count;
2172 bool identical = (m_selected_item != NULL) && s.isValid() &&
2173 (inv_selected == inv_s) &&
2174 (m_selected_item->listname == s.listname) &&
2175 (m_selected_item->i == s.i);
2177 // buttons: 0 = left, 1 = right, 2 = middle
2178 // up/down: 0 = down (press), 1 = up (release), 2 = unknown event
2181 if(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)
2182 { button = 0; updown = 0; }
2183 else if(event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN)
2184 { button = 1; updown = 0; }
2185 else if(event.MouseInput.Event == EMIE_MMOUSE_PRESSED_DOWN)
2186 { button = 2; updown = 0; }
2187 else if(event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)
2188 { button = 0; updown = 1; }
2189 else if(event.MouseInput.Event == EMIE_RMOUSE_LEFT_UP)
2190 { button = 1; updown = 1; }
2191 else if(event.MouseInput.Event == EMIE_MMOUSE_LEFT_UP)
2192 { button = 2; updown = 1; }
2194 // Set this number to a positive value to generate a move action
2195 // from m_selected_item to s.
2196 u32 move_amount = 0;
2198 // Set this number to a positive value to generate a drop action
2199 // from m_selected_item.
2200 u32 drop_amount = 0;
2202 // Set this number to a positive value to generate a craft action at s.
2203 u32 craft_amount = 0;
2207 // Some mouse button has been pressed
2209 //infostream<<"Mouse button "<<button<<" pressed at p=("
2210 // <<p.X<<","<<p.Y<<")"<<std::endl;
2212 m_selected_dragging = false;
2214 if(s.isValid() && s.listname == "craftpreview")
2216 // Craft preview has been clicked: craft
2217 craft_amount = (button == 2 ? 10 : 1);
2219 else if(m_selected_item == NULL)
2223 // Non-empty stack has been clicked: select it
2224 m_selected_item = new ItemSpec(s);
2226 if(button == 1) // right
2227 m_selected_amount = (s_count + 1) / 2;
2228 else if(button == 2) // middle
2229 m_selected_amount = MYMIN(s_count, 10);
2231 m_selected_amount = s_count;
2233 m_selected_dragging = true;
2236 else // m_selected_item != NULL
2238 assert(m_selected_amount >= 1);
2242 // Clicked a slot: move
2243 if(button == 1) // right
2245 else if(button == 2) // middle
2246 move_amount = MYMIN(m_selected_amount, 10);
2248 move_amount = m_selected_amount;
2252 if(move_amount >= m_selected_amount)
2253 m_selected_amount = 0;
2255 m_selected_amount -= move_amount;
2259 else if(getAbsoluteClippingRect().isPointInside(m_pointer))
2261 // Clicked somewhere else: deselect
2262 m_selected_amount = 0;
2266 // Clicked outside of the window: drop
2267 if(button == 1) // right
2269 else if(button == 2) // middle
2270 drop_amount = MYMIN(m_selected_amount, 10);
2272 drop_amount = m_selected_amount;
2276 else if(updown == 1)
2278 // Some mouse button has been released
2280 //infostream<<"Mouse button "<<button<<" released at p=("
2281 // <<p.X<<","<<p.Y<<")"<<std::endl;
2283 if(m_selected_item != NULL && m_selected_dragging && s.isValid())
2287 // Dragged to different slot: move all selected
2288 move_amount = m_selected_amount;
2291 else if(m_selected_item != NULL && m_selected_dragging &&
2292 !(getAbsoluteClippingRect().isPointInside(m_pointer)))
2294 // Dragged outside of window: drop all selected
2295 drop_amount = m_selected_amount;
2298 m_selected_dragging = false;
2301 // Possibly send inventory action to server
2304 // Send IACTION_MOVE
2306 assert(m_selected_item && m_selected_item->isValid());
2307 assert(s.isValid());
2309 assert(inv_selected && inv_s);
2310 InventoryList *list_from = inv_selected->getList(m_selected_item->listname);
2311 InventoryList *list_to = inv_s->getList(s.listname);
2312 assert(list_from && list_to);
2313 ItemStack stack_from = list_from->getItem(m_selected_item->i);
2314 ItemStack stack_to = list_to->getItem(s.i);
2316 // Check how many items can be moved
2317 move_amount = stack_from.count = MYMIN(move_amount, stack_from.count);
2318 ItemStack leftover = stack_to.addItem(stack_from, m_gamedef->idef());
2319 // If source stack cannot be added to destination stack at all,
2321 if(leftover.count == stack_from.count && leftover.name == stack_from.name)
2323 m_selected_amount = stack_to.count;
2324 // In case the server doesn't directly swap them but instead
2325 // moves stack_to somewhere else, set this
2326 m_selected_content_guess = stack_to;
2327 m_selected_content_guess_inventory = s.inventoryloc;
2329 // Source stack goes fully into destination stack
2330 else if(leftover.empty())
2332 m_selected_amount -= move_amount;
2333 m_selected_content_guess = ItemStack(); // Clear
2335 // Source stack goes partly into destination stack
2338 move_amount -= leftover.count;
2339 m_selected_amount -= move_amount;
2340 m_selected_content_guess = ItemStack(); // Clear
2343 infostream<<"Handing IACTION_MOVE to manager"<<std::endl;
2344 IMoveAction *a = new IMoveAction();
2345 a->count = move_amount;
2346 a->from_inv = m_selected_item->inventoryloc;
2347 a->from_list = m_selected_item->listname;
2348 a->from_i = m_selected_item->i;
2349 a->to_inv = s.inventoryloc;
2350 a->to_list = s.listname;
2352 m_invmgr->inventoryAction(a);
2354 else if(drop_amount > 0)
2356 m_selected_content_guess = ItemStack(); // Clear
2358 // Send IACTION_DROP
2360 assert(m_selected_item && m_selected_item->isValid());
2361 assert(inv_selected);
2362 InventoryList *list_from = inv_selected->getList(m_selected_item->listname);
2364 ItemStack stack_from = list_from->getItem(m_selected_item->i);
2366 // Check how many items can be dropped
2367 drop_amount = stack_from.count = MYMIN(drop_amount, stack_from.count);
2368 assert(drop_amount > 0 && drop_amount <= m_selected_amount);
2369 m_selected_amount -= drop_amount;
2371 infostream<<"Handing IACTION_DROP to manager"<<std::endl;
2372 IDropAction *a = new IDropAction();
2373 a->count = drop_amount;
2374 a->from_inv = m_selected_item->inventoryloc;
2375 a->from_list = m_selected_item->listname;
2376 a->from_i = m_selected_item->i;
2377 m_invmgr->inventoryAction(a);
2379 else if(craft_amount > 0)
2381 m_selected_content_guess = ItemStack(); // Clear
2383 // Send IACTION_CRAFT
2385 assert(s.isValid());
2388 infostream<<"Handing IACTION_CRAFT to manager"<<std::endl;
2389 ICraftAction *a = new ICraftAction();
2390 a->count = craft_amount;
2391 a->craft_inv = s.inventoryloc;
2392 m_invmgr->inventoryAction(a);
2395 // If m_selected_amount has been decreased to zero, deselect
2396 if(m_selected_amount == 0)
2398 delete m_selected_item;
2399 m_selected_item = NULL;
2400 m_selected_amount = 0;
2401 m_selected_dragging = false;
2402 m_selected_content_guess = ItemStack();
2405 if(event.EventType==EET_GUI_EVENT)
2408 if(event.GUIEvent.EventType==gui::EGET_TAB_CHANGED
2411 // find the element that was clicked
2412 for(u32 i=0; i<m_fields.size(); i++)
2414 FieldSpec &s = m_fields[i];
2415 // if its a button, set the send field so
2416 // lua knows which button was pressed
2417 if ((s.ftype == f_TabHeader) && (s.fid == event.GUIEvent.Caller->getID()))
2422 // Restore focus to the full form
2423 Environment->setFocus(this);
2428 if(event.GUIEvent.EventType==gui::EGET_ELEMENT_FOCUS_LOST
2431 if(!canTakeFocus(event.GUIEvent.Element))
2433 infostream<<"GUIFormSpecMenu: Not allowing focus change."
2435 // Returning true disables focus change
2439 if((event.GUIEvent.EventType==gui::EGET_BUTTON_CLICKED) ||
2440 (event.GUIEvent.EventType==gui::EGET_CHECKBOX_CHANGED))
2442 unsigned int btn_id = event.GUIEvent.Caller->getID();
2444 if (btn_id == 257) {
2449 m_text_dst->gotText(narrow_to_wide("ExitButton"));
2450 // quitMenu deallocates menu
2454 // find the element that was clicked
2455 for(u32 i=0; i<m_fields.size(); i++)
2457 FieldSpec &s = m_fields[i];
2458 // if its a button, set the send field so
2459 // lua knows which button was pressed
2460 if (((s.ftype == f_Button) || (s.ftype == f_CheckBox)) &&
2461 (s.fid == event.GUIEvent.Caller->getID()))
2469 m_text_dst->gotText(narrow_to_wide("ExitButton"));
2473 // Restore focus to the full form
2474 Environment->setFocus(this);
2480 if(event.GUIEvent.EventType==gui::EGET_EDITBOX_ENTER)
2482 if(event.GUIEvent.Caller->getID() > 257)
2488 m_text_dst->gotText(narrow_to_wide("EditBoxEnter"));
2489 // quitMenu deallocates menu
2494 if((event.GUIEvent.EventType==gui::EGET_LISTBOX_SELECTED_AGAIN) ||
2495 (event.GUIEvent.EventType==gui::EGET_LISTBOX_CHANGED))
2497 int current_id = event.GUIEvent.Caller->getID();
2498 if(current_id > 257)
2500 // find the element that was clicked
2501 for(u32 i=0; i<m_fields.size(); i++)
2503 FieldSpec &s = m_fields[i];
2504 // if its a button, set the send field so
2505 // lua knows which button was pressed
2506 if ((s.ftype == f_ListBox) && (s.fid == current_id))
2509 acceptInput(event.GUIEvent.EventType);
2511 // Restore focus to the full form
2512 Environment->setFocus(this);
2520 return Parent ? Parent->OnEvent(event) : false;
2523 irr::video::SColor GUIFormSpecMenu::getColor(std::string color,bool& valid_color) {
2525 if (color == "YLW") {
2527 return irr::video::SColor(255,255,255,0);
2530 if (color == "GRN") {
2532 return irr::video::SColor(255,34,249,34);
2535 if (color == "LIM") {
2537 return irr::video::SColor(255,50,205,50);
2540 if (color == "RED") {
2542 return irr::video::SColor(255,255,0,0);
2545 if (color == "ORN") {
2547 return irr::video::SColor(255,255,140,0);
2550 if (color == "BLU") {
2552 return irr::video::SColor(255,0,0,255);
2555 if (color == "CYN") {
2557 return irr::video::SColor(255,0,255,255);
2560 if (color == "BLK") {
2562 return irr::video::SColor(255,0,0,0);
2565 if (color == "BRN") {
2567 return irr::video::SColor(255,139,69,19);
2570 if (color == "WHT") {
2572 return irr::video::SColor(255,255,255,255);
2575 if (color == "GRY") {
2577 return irr::video::SColor(255,205,201,201);
2580 valid_color = false;
2582 return irr::video::SColor(0,0,0,0);