removed duplicate "bmp"
[oweals/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                 Inventory *inventory,
82                 Queue<InventoryAction*> *actions,
83                 IMenuManager *menumgr):
84         GUIModalMenu(env, parent, id, menumgr)
85 {
86         m_inventory = inventory;
87         m_selected_item = NULL;
88         m_actions = actions;
89
90         /*m_selected_item = new ItemSpec;
91         m_selected_item->listname = "main";
92         m_selected_item->i = 3;*/
93 }
94
95 GUIInventoryMenu::~GUIInventoryMenu()
96 {
97         removeChildren();
98
99         if(m_selected_item)
100                 delete m_selected_item;
101 }
102
103 void GUIInventoryMenu::removeChildren()
104 {
105         {
106                 gui::IGUIElement *e = getElementFromId(256);
107                 if(e != NULL)
108                         e->remove();
109         }
110 }
111
112 void GUIInventoryMenu::regenerateGui(v2u32 screensize)
113 {
114         // Remove children
115         removeChildren();
116         
117         padding = v2s32(24,24);
118         spacing = v2s32(60,56);
119         imgsize = v2s32(48,48);
120
121         s32 helptext_h = 15;
122
123         v2s32 size(
124                 padding.X*2+spacing.X*(8-1)+imgsize.X,
125                 padding.Y*2+spacing.Y*(7-1)+imgsize.Y + helptext_h
126         );
127
128         core::rect<s32> rect(
129                         screensize.X/2 - size.X/2,
130                         screensize.Y/2 - size.Y/2,
131                         screensize.X/2 + size.X/2,
132                         screensize.Y/2 + size.Y/2
133         );
134         
135         DesiredRect = rect;
136         recalculateAbsolutePosition(false);
137
138         v2s32 basepos = getBasePos();
139         
140         m_draw_positions.clear();
141         m_draw_positions.push_back(ListDrawSpec("main",
142                         basepos + v2s32(spacing.X*0, spacing.Y*3), v2s32(8, 4)));
143         m_draw_positions.push_back(ListDrawSpec("craft",
144                         basepos + v2s32(spacing.X*3, spacing.Y*0), v2s32(3, 3)));
145         m_draw_positions.push_back(ListDrawSpec("craftresult",
146                         basepos + v2s32(spacing.X*7, spacing.Y*1), v2s32(1, 1)));
147         
148         // Add children
149         {
150                 core::rect<s32> rect(0, 0, size.X-padding.X*2, helptext_h);
151                 rect = rect + v2s32(size.X/2 - rect.getWidth()/2,
152                                 size.Y-rect.getHeight()-15);
153                 const wchar_t *text =
154                 L"Left click: Move all items, Right click: Move single item";
155                 Environment->addStaticText(text, rect, false, true, this, 256);
156         }
157 }
158
159 GUIInventoryMenu::ItemSpec GUIInventoryMenu::getItemAtPos(v2s32 p) const
160 {
161         core::rect<s32> imgrect(0,0,imgsize.X,imgsize.Y);
162         
163         for(u32 i=0; i<m_draw_positions.size(); i++)
164         {
165                 const ListDrawSpec &s = m_draw_positions[i];
166
167                 for(s32 i=0; i<s.geom.X*s.geom.Y; i++)
168                 {
169                         s32 x = (i%s.geom.X) * spacing.X;
170                         s32 y = (i/s.geom.X) * spacing.Y;
171                         v2s32 p0(x,y);
172                         core::rect<s32> rect = imgrect + s.pos + p0;
173                         if(rect.isPointInside(p))
174                         {
175                                 return ItemSpec(s.listname, i);
176                         }
177                 }
178         }
179
180         return ItemSpec("", -1);
181 }
182
183 //void GUIInventoryMenu::drawList(const std::string &name, v2s32 pos, v2s32 geom)
184 void GUIInventoryMenu::drawList(const ListDrawSpec &s)
185 {
186         video::IVideoDriver* driver = Environment->getVideoDriver();
187
188         // Get font
189         gui::IGUIFont *font = NULL;
190         gui::IGUISkin* skin = Environment->getSkin();
191         if (skin)
192                 font = skin->getFont();
193         
194         InventoryList *ilist = m_inventory->getList(s.listname);
195         
196         core::rect<s32> imgrect(0,0,imgsize.X,imgsize.Y);
197         
198         for(s32 i=0; i<s.geom.X*s.geom.Y; i++)
199         {
200                 s32 x = (i%s.geom.X) * spacing.X;
201                 s32 y = (i/s.geom.X) * spacing.Y;
202                 v2s32 p(x,y);
203                 core::rect<s32> rect = imgrect + s.pos + p;
204                 InventoryItem *item = NULL;
205                 if(ilist)
206                         item = ilist->getItem(i);
207
208                 if(m_selected_item != NULL && m_selected_item->listname == s.listname
209                                 && m_selected_item->i == i)
210                 {
211                         driver->draw2DRectangle(video::SColor(255,255,0,0),
212                                         core::rect<s32>(rect.UpperLeftCorner - v2s32(2,2),
213                                                         rect.LowerRightCorner + v2s32(2,2)),
214                                         &AbsoluteClippingRect);
215                 }
216
217                 if(item)
218                 {
219                         drawInventoryItem(driver, font, item,
220                                         rect, &AbsoluteClippingRect);
221                 }
222                 else
223                 {
224                         video::SColor bgcolor(255,128,128,128);
225                         driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
226                 }
227         }
228 }
229
230 void GUIInventoryMenu::drawMenu()
231 {
232         gui::IGUISkin* skin = Environment->getSkin();
233         if (!skin)
234                 return;
235         video::IVideoDriver* driver = Environment->getVideoDriver();
236         
237         video::SColor bgcolor(140,0,0,0);
238         driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);
239
240         /*
241                 Draw items
242         */
243         
244         for(u32 i=0; i<m_draw_positions.size(); i++)
245         {
246                 ListDrawSpec &s = m_draw_positions[i];
247                 drawList(s);
248         }
249
250         /*
251                 Call base class
252         */
253         gui::IGUIElement::draw();
254 }
255
256 bool GUIInventoryMenu::OnEvent(const SEvent& event)
257 {
258         if(event.EventType==EET_KEY_INPUT_EVENT)
259         {
260                 if(event.KeyInput.Key==KEY_ESCAPE && event.KeyInput.PressedDown)
261                 {
262                         quitMenu();
263                         return true;
264                 }
265                 if(event.KeyInput.Key==KEY_KEY_I && event.KeyInput.PressedDown)
266                 {
267                         quitMenu();
268                         return true;
269                 }
270         }
271         if(event.EventType==EET_MOUSE_INPUT_EVENT)
272         {
273                 if(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN
274                                 || event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN)
275                 {
276                         bool right = (event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN);
277                         v2s32 p(event.MouseInput.X, event.MouseInput.Y);
278                         //dstream<<"Mouse down at p=("<<p.X<<","<<p.Y<<")"<<std::endl;
279                         ItemSpec s = getItemAtPos(p);
280                         if(s.isValid())
281                         {
282                                 //dstream<<"Mouse down on "<<s.listname<<" "<<s.i<<std::endl;
283                                 if(m_selected_item)
284                                 {
285                                         InventoryList *list_from =
286                                                         m_inventory->getList(m_selected_item->listname);
287                                         InventoryList *list_to =
288                                                         m_inventory->getList(s.listname);
289                                         // Indicates whether source slot completely empties
290                                         bool source_empties = false;
291                                         if(list_from && list_to
292                                                         && list_from->getItem(m_selected_item->i) != NULL)
293                                         {
294                                                 dstream<<"Queueing IACTION_MOVE"<<std::endl;
295                                                 IMoveAction *a = new IMoveAction();
296                                                 a->count = right ? 1 : 0;
297                                                 a->from_name = m_selected_item->listname;
298                                                 a->from_i = m_selected_item->i;
299                                                 a->to_name = s.listname;
300                                                 a->to_i = s.i;
301                                                 m_actions->push_back(a);
302                                                 
303                                                 if(list_from->getItem(m_selected_item->i)->getCount()==1)
304                                                         source_empties = true;
305                                         }
306                                         // Remove selection if target was left-clicked or source
307                                         // slot was emptied
308                                         if(right == false || source_empties)
309                                         {
310                                                 delete m_selected_item;
311                                                 m_selected_item = NULL;
312                                         }
313                                 }
314                                 else
315                                 {
316                                         /*
317                                                 Select if non-NULL
318                                         */
319                                         InventoryList *list = m_inventory->getList(s.listname);
320                                         if(list->getItem(s.i) != NULL)
321                                         {
322                                                 m_selected_item = new ItemSpec(s);
323                                         }
324                                 }
325                         }
326                         else
327                         {
328                                 if(m_selected_item)
329                                 {
330                                         delete m_selected_item;
331                                         m_selected_item = NULL;
332                                 }
333                         }
334                 }
335         }
336         if(event.EventType==EET_GUI_EVENT)
337         {
338                 if(event.GUIEvent.EventType==gui::EGET_ELEMENT_FOCUS_LOST
339                                 && isVisible())
340                 {
341                         if(!canTakeFocus(event.GUIEvent.Element))
342                         {
343                                 dstream<<"GUIInventoryMenu: Not allowing focus change."
344                                                 <<std::endl;
345                                 // Returning true disables focus change
346                                 return true;
347                         }
348                 }
349                 if(event.GUIEvent.EventType==gui::EGET_BUTTON_CLICKED)
350                 {
351                         /*switch(event.GUIEvent.Caller->getID())
352                         {
353                         case 256: // continue
354                                 setVisible(false);
355                                 break;
356                         case 257: // exit
357                                 dev->closeDevice();
358                                 break;
359                         }*/
360                 }
361         }
362
363         return Parent ? Parent->OnEvent(event) : false;
364 }
365
366
367