]> git.lizzy.rs Git - minetest.git/blob - src/guiInventoryMenu.cpp
Tuned polygon generation to sort the triangles for nicer gradients
[minetest.git] / src / guiInventoryMenu.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
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 General Public License for more details.
14
15 You should have received a copy of the GNU 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.
18 */
19
20
21 #include "guiInventoryMenu.h"
22 #include "constants.h"
23
24 void drawInventoryItem(video::IVideoDriver *driver,
25                 gui::IGUIFont *font,
26                 InventoryItem *item, core::rect<s32> rect,
27                 const core::rect<s32> *clip)
28 {
29         if(item == NULL)
30                 return;
31         
32         video::ITexture *texture = NULL;
33         texture = item->getImage();
34
35         if(texture != NULL)
36         {
37                 const video::SColor color(255,255,255,255);
38                 const video::SColor colors[] = {color,color,color,color};
39                 driver->draw2DImage(texture, rect,
40                         core::rect<s32>(core::position2d<s32>(0,0),
41                         core::dimension2di(texture->getOriginalSize())),
42                         clip, colors, false);
43         }
44         else
45         {
46                 video::SColor bgcolor(255,50,50,128);
47                 driver->draw2DRectangle(bgcolor, rect, clip);
48         }
49
50         if(font != NULL)
51         {
52                 std::string text = item->getText();
53                 if(font && text != "")
54                 {
55                         v2u32 dim = font->getDimension(narrow_to_wide(text).c_str());
56                         v2s32 sdim(dim.X,dim.Y);
57
58                         core::rect<s32> rect2(
59                                 /*rect.UpperLeftCorner,
60                                 core::dimension2d<u32>(rect.getWidth(), 15)*/
61                                 rect.LowerRightCorner - sdim,
62                                 sdim
63                         );
64
65                         video::SColor bgcolor(128,0,0,0);
66                         driver->draw2DRectangle(bgcolor, rect2, clip);
67                         
68                         font->draw(text.c_str(), rect2,
69                                         video::SColor(255,255,255,255), false, false,
70                                         clip);
71                 }
72         }
73 }
74
75 /*
76         GUIInventoryMenu
77 */
78
79 GUIInventoryMenu::GUIInventoryMenu(gui::IGUIEnvironment* env,
80                 gui::IGUIElement* parent, s32 id,
81                 IMenuManager *menumgr,
82                 v2s16 menu_size,
83                 InventoryContext *c,
84                 InventoryManager *invmgr
85                 ):
86         GUIModalMenu(env, parent, id, menumgr),
87         m_menu_size(menu_size),
88         m_c(c),
89         m_invmgr(invmgr)
90 {
91         m_selected_item = NULL;
92 }
93
94 GUIInventoryMenu::~GUIInventoryMenu()
95 {
96         removeChildren();
97
98         if(m_selected_item)
99                 delete m_selected_item;
100 }
101
102 void GUIInventoryMenu::removeChildren()
103 {
104         const core::list<gui::IGUIElement*> &children = getChildren();
105         core::list<gui::IGUIElement*> children_copy;
106         for(core::list<gui::IGUIElement*>::ConstIterator
107                         i = children.begin(); i != children.end(); i++)
108         {
109                 children_copy.push_back(*i);
110         }
111         for(core::list<gui::IGUIElement*>::Iterator
112                         i = children_copy.begin();
113                         i != children_copy.end(); i++)
114         {
115                 (*i)->remove();
116         }
117         /*{
118                 gui::IGUIElement *e = getElementFromId(256);
119                 if(e != NULL)
120                         e->remove();
121         }*/
122 }
123
124 void GUIInventoryMenu::regenerateGui(v2u32 screensize)
125 {
126         // Remove children
127         removeChildren();
128         
129         /*padding = v2s32(24,24);
130         spacing = v2s32(60,56);
131         imgsize = v2s32(48,48);*/
132
133         padding = v2s32(screensize.Y/40, screensize.Y/40);
134         spacing = v2s32(screensize.Y/12, screensize.Y/13);
135         imgsize = v2s32(screensize.Y/15, screensize.Y/15);
136
137         s32 helptext_h = 15;
138
139         v2s32 size(
140                 padding.X*2+spacing.X*(m_menu_size.X-1)+imgsize.X,
141                 padding.Y*2+spacing.Y*(m_menu_size.Y-1)+imgsize.Y + helptext_h
142         );
143
144         core::rect<s32> rect(
145                         screensize.X/2 - size.X/2,
146                         screensize.Y/2 - size.Y/2,
147                         screensize.X/2 + size.X/2,
148                         screensize.Y/2 + size.Y/2
149         );
150         
151         DesiredRect = rect;
152         recalculateAbsolutePosition(false);
153
154         v2s32 basepos = getBasePos();
155         
156         m_draw_spec.clear();
157         for(u16 i=0; i<m_init_draw_spec.size(); i++)
158         {
159                 DrawSpec &s = m_init_draw_spec[i];
160                 if(s.type == "list")
161                 {
162                         m_draw_spec.push_back(ListDrawSpec(s.name, s.subname,
163                                         basepos + v2s32(spacing.X*s.pos.X, spacing.Y*s.pos.Y),
164                                         s.geom));
165                 }
166         }
167
168         /*
169         m_draw_spec.clear();
170         m_draw_spec.push_back(ListDrawSpec("main",
171                         basepos + v2s32(spacing.X*0, spacing.Y*3), v2s32(8, 4)));
172         m_draw_spec.push_back(ListDrawSpec("craft",
173                         basepos + v2s32(spacing.X*3, spacing.Y*0), v2s32(3, 3)));
174         m_draw_spec.push_back(ListDrawSpec("craftresult",
175                         basepos + v2s32(spacing.X*7, spacing.Y*1), v2s32(1, 1)));
176         */
177         
178         // Add children
179         {
180                 core::rect<s32> rect(0, 0, size.X-padding.X*2, helptext_h);
181                 rect = rect + v2s32(size.X/2 - rect.getWidth()/2,
182                                 size.Y-rect.getHeight()-15);
183                 const wchar_t *text =
184                 L"Left click: Move all items, Right click: Move single item";
185                 Environment->addStaticText(text, rect, false, true, this, 256);
186         }
187 }
188
189 GUIInventoryMenu::ItemSpec GUIInventoryMenu::getItemAtPos(v2s32 p) const
190 {
191         core::rect<s32> imgrect(0,0,imgsize.X,imgsize.Y);
192         
193         for(u32 i=0; i<m_draw_spec.size(); i++)
194         {
195                 const ListDrawSpec &s = m_draw_spec[i];
196
197                 for(s32 i=0; i<s.geom.X*s.geom.Y; i++)
198                 {
199                         s32 x = (i%s.geom.X) * spacing.X;
200                         s32 y = (i/s.geom.X) * spacing.Y;
201                         v2s32 p0(x,y);
202                         core::rect<s32> rect = imgrect + s.pos + p0;
203                         if(rect.isPointInside(p))
204                         {
205                                 return ItemSpec(s.inventoryname, s.listname, i);
206                         }
207                 }
208         }
209
210         return ItemSpec("", "", -1);
211 }
212
213 void GUIInventoryMenu::drawList(const ListDrawSpec &s)
214 {
215         video::IVideoDriver* driver = Environment->getVideoDriver();
216
217         // Get font
218         gui::IGUIFont *font = NULL;
219         gui::IGUISkin* skin = Environment->getSkin();
220         if (skin)
221                 font = skin->getFont();
222         
223         Inventory *inv = m_invmgr->getInventory(m_c, s.inventoryname);
224         assert(inv);
225         InventoryList *ilist = inv->getList(s.listname);
226         
227         core::rect<s32> imgrect(0,0,imgsize.X,imgsize.Y);
228         
229         for(s32 i=0; i<s.geom.X*s.geom.Y; i++)
230         {
231                 s32 x = (i%s.geom.X) * spacing.X;
232                 s32 y = (i/s.geom.X) * spacing.Y;
233                 v2s32 p(x,y);
234                 core::rect<s32> rect = imgrect + s.pos + p;
235                 InventoryItem *item = NULL;
236                 if(ilist)
237                         item = ilist->getItem(i);
238
239                 if(m_selected_item != NULL && m_selected_item->listname == s.listname
240                                 && m_selected_item->i == i)
241                 {
242                         driver->draw2DRectangle(video::SColor(255,255,0,0),
243                                         core::rect<s32>(rect.UpperLeftCorner - v2s32(2,2),
244                                                         rect.LowerRightCorner + v2s32(2,2)),
245                                         &AbsoluteClippingRect);
246                 }
247
248                 if(item)
249                 {
250                         drawInventoryItem(driver, font, item,
251                                         rect, &AbsoluteClippingRect);
252                 }
253                 else
254                 {
255                         video::SColor bgcolor(255,128,128,128);
256                         driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
257                 }
258         }
259 }
260
261 void GUIInventoryMenu::drawMenu()
262 {
263         gui::IGUISkin* skin = Environment->getSkin();
264         if (!skin)
265                 return;
266         video::IVideoDriver* driver = Environment->getVideoDriver();
267         
268         video::SColor bgcolor(140,0,0,0);
269         driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);
270
271         /*
272                 Draw items
273         */
274         
275         for(u32 i=0; i<m_draw_spec.size(); i++)
276         {
277                 ListDrawSpec &s = m_draw_spec[i];
278                 drawList(s);
279         }
280
281         /*
282                 Call base class
283         */
284         gui::IGUIElement::draw();
285 }
286
287 bool GUIInventoryMenu::OnEvent(const SEvent& event)
288 {
289         if(event.EventType==EET_KEY_INPUT_EVENT)
290         {
291                 if(event.KeyInput.Key==KEY_ESCAPE && event.KeyInput.PressedDown)
292                 {
293                         quitMenu();
294                         return true;
295                 }
296                 if(event.KeyInput.Key==KEY_KEY_I && event.KeyInput.PressedDown)
297                 {
298                         quitMenu();
299                         return true;
300                 }
301         }
302         if(event.EventType==EET_MOUSE_INPUT_EVENT)
303         {
304                 if(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN
305                                 || event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN)
306                 {
307                         bool right = (event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN);
308                         v2s32 p(event.MouseInput.X, event.MouseInput.Y);
309                         //dstream<<"Mouse down at p=("<<p.X<<","<<p.Y<<")"<<std::endl;
310                         ItemSpec s = getItemAtPos(p);
311                         if(s.isValid())
312                         {
313                                 dstream<<"Mouse down on "<<s.inventoryname
314                                                 <<"/"<<s.listname<<" "<<s.i<<std::endl;
315                                 if(m_selected_item)
316                                 {
317                                         Inventory *inv_from = m_invmgr->getInventory(m_c,
318                                                         m_selected_item->inventoryname);
319                                         Inventory *inv_to = m_invmgr->getInventory(m_c,
320                                                         s.inventoryname);
321                                         assert(inv_from);
322                                         assert(inv_to);
323                                         InventoryList *list_from =
324                                                         inv_from->getList(m_selected_item->listname);
325                                         InventoryList *list_to =
326                                                         inv_to->getList(s.listname);
327                                         if(list_from == NULL)
328                                                 dstream<<"from list doesn't exist"<<std::endl;
329                                         if(list_to == NULL)
330                                                 dstream<<"to list doesn't exist"<<std::endl;
331                                         // Indicates whether source slot completely empties
332                                         bool source_empties = false;
333                                         if(list_from && list_to
334                                                         && list_from->getItem(m_selected_item->i) != NULL)
335                                         {
336                                                 dstream<<"Handing IACTION_MOVE to manager"<<std::endl;
337                                                 IMoveAction *a = new IMoveAction();
338                                                 a->count = right ? 1 : 0;
339                                                 a->from_inv = m_selected_item->inventoryname;
340                                                 a->from_list = m_selected_item->listname;
341                                                 a->from_i = m_selected_item->i;
342                                                 a->to_inv = s.inventoryname;
343                                                 a->to_list = s.listname;
344                                                 a->to_i = s.i;
345                                                 //ispec.actions->push_back(a);
346                                                 m_invmgr->inventoryAction(a);
347                                                 
348                                                 if(list_from->getItem(m_selected_item->i)->getCount()==1)
349                                                         source_empties = true;
350                                         }
351                                         // Remove selection if target was left-clicked or source
352                                         // slot was emptied
353                                         if(right == false || source_empties)
354                                         {
355                                                 delete m_selected_item;
356                                                 m_selected_item = NULL;
357                                         }
358                                 }
359                                 else
360                                 {
361                                         /*
362                                                 Select if non-NULL
363                                         */
364                                         Inventory *inv = m_invmgr->getInventory(m_c,
365                                                         s.inventoryname);
366                                         assert(inv);
367                                         InventoryList *list = inv->getList(s.listname);
368                                         if(list->getItem(s.i) != NULL)
369                                         {
370                                                 m_selected_item = new ItemSpec(s);
371                                         }
372                                 }
373                         }
374                         else
375                         {
376                                 if(m_selected_item)
377                                 {
378                                         delete m_selected_item;
379                                         m_selected_item = NULL;
380                                 }
381                         }
382                 }
383         }
384         if(event.EventType==EET_GUI_EVENT)
385         {
386                 if(event.GUIEvent.EventType==gui::EGET_ELEMENT_FOCUS_LOST
387                                 && isVisible())
388                 {
389                         if(!canTakeFocus(event.GUIEvent.Element))
390                         {
391                                 dstream<<"GUIInventoryMenu: Not allowing focus change."
392                                                 <<std::endl;
393                                 // Returning true disables focus change
394                                 return true;
395                         }
396                 }
397                 if(event.GUIEvent.EventType==gui::EGET_BUTTON_CLICKED)
398                 {
399                         /*switch(event.GUIEvent.Caller->getID())
400                         {
401                         case 256: // continue
402                                 setVisible(false);
403                                 break;
404                         case 257: // exit
405                                 dev->closeDevice();
406                                 break;
407                         }*/
408                 }
409         }
410
411         return Parent ? Parent->OnEvent(event) : false;
412 }
413
414
415