]> git.lizzy.rs Git - minetest.git/blobdiff - src/guiFormSpecMenu.cpp
Update ContentFeatures serialization format now as PROTOCOL_VERSION was changed
[minetest.git] / src / guiFormSpecMenu.cpp
index 7ded2b37eea2d2c7dcb8c0ff3e6747406685f44c..4db020c11fd88ebfc53148edf90e8b4b6d73ac34 100644 (file)
@@ -199,6 +199,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
        
        m_inventorylists.clear();
        m_images.clear();
+       m_backgrounds.clear();
        m_fields.clear();
 
        Strfnd f(m_formspec_string);
@@ -278,9 +279,26 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
                                        <<", geom=("<<geom.X<<","<<geom.Y<<")"
                                        <<std::endl;
                        if(bp_set != 2)
-                               errorstream<<"WARNING: invalid use of button without a size[] element"<<std::endl;
+                               errorstream<<"WARNING: invalid use of image without a size[] element"<<std::endl;
                        m_images.push_back(ImageDrawSpec(name, pos, geom));
                }
+               else if(type == "background")
+               {
+                       v2s32 pos = basepos;
+                       pos.X += stof(f.next(",")) * (float)spacing.X - ((float)spacing.X-(float)imgsize.X)/2;
+                       pos.Y += stof(f.next(";")) * (float)spacing.Y - ((float)spacing.Y-(float)imgsize.Y)/2;
+                       v2s32 geom;
+                       geom.X = stof(f.next(",")) * (float)spacing.X;
+                       geom.Y = stof(f.next(";")) * (float)spacing.Y;
+                       std::string name = f.next("]");
+                       infostream<<"image name="<<name
+                                       <<", pos=("<<pos.X<<","<<pos.Y<<")"
+                                       <<", geom=("<<geom.X<<","<<geom.Y<<")"
+                                       <<std::endl;
+                       if(bp_set != 2)
+                               errorstream<<"WARNING: invalid use of background without a size[] element"<<std::endl;
+                       m_backgrounds.push_back(ImageDrawSpec(name, pos, geom));
+               }
                else if(type == "field")
                {
                        std::string fname = f.next(";");
@@ -382,9 +400,9 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
                }
                else if(type == "label")
                {
-                       v2s32 pos;
-                       pos.X = stof(f.next(",")) * (float)spacing.X;
-                       pos.Y = stof(f.next(";")) * (float)spacing.Y;
+                       v2s32 pos = padding;
+                       pos.X += stof(f.next(",")) * (float)spacing.X;
+                       pos.Y += stof(f.next(";")) * (float)spacing.Y;
 
                        rect = core::rect<s32>(pos.X, pos.Y+((imgsize.Y/2)-15), pos.X+300, pos.Y+((imgsize.Y/2)+15));
                        
@@ -403,9 +421,9 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
                }
                else if(type == "button" || type == "button_exit")
                {
-                       v2s32 pos;
-                       pos.X = stof(f.next(",")) * (float)spacing.X;
-                       pos.Y = stof(f.next(";")) * (float)spacing.Y;
+                       v2s32 pos = padding;
+                       pos.X += stof(f.next(",")) * (float)spacing.X;
+                       pos.Y += stof(f.next(";")) * (float)spacing.Y;
                        v2s32 geom;
                        geom.X = (stof(f.next(",")) * (float)spacing.X)-(spacing.X-imgsize.X);
                        pos.Y += (stof(f.next(";")) * (float)imgsize.Y)/2;
@@ -431,9 +449,9 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
                }
                else if(type == "image_button" || type == "image_button_exit")
                {
-                       v2s32 pos;
-                       pos.X = stof(f.next(",")) * (float)spacing.X;
-                       pos.Y = stof(f.next(";")) * (float)spacing.Y;
+                       v2s32 pos = padding;
+                       pos.X += stof(f.next(",")) * (float)spacing.X;
+                       pos.Y += stof(f.next(";")) * (float)spacing.Y;
                        v2s32 geom;
                        geom.X = (stof(f.next(",")) * (float)spacing.X)-(spacing.X-imgsize.X);
                        geom.Y = (stof(f.next(";")) * (float)spacing.Y)-(spacing.Y-imgsize.Y);
@@ -458,6 +476,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
                        
                        video::ITexture *texture = m_gamedef->tsrc()->getTextureRaw(fimage);
                        gui::IGUIButton *e = Environment->addButton(rect, this, spec.fid, spec.flabel.c_str());
+                       e->setUseAlphaChannel(true);
                        e->setImage(texture);
                        e->setPressedImage(texture);
                        e->setScaleImage(true);
@@ -692,17 +711,28 @@ void GUIFormSpecMenu::drawMenu()
        m_tooltip_element->setVisible(false);
 
        /*
-               Draw items
-               Phase 0: Item slot rectangles
-               Phase 1: Item images; prepare tooltip
+               Draw backgrounds
        */
-       
-       for(int phase=0; phase<=1; phase++)
-       for(u32 i=0; i<m_inventorylists.size(); i++)
+       for(u32 i=0; i<m_backgrounds.size(); i++)
        {
-               drawList(m_inventorylists[i], phase);
+               const ImageDrawSpec &spec = m_backgrounds[i];
+               video::ITexture *texture =
+                               m_gamedef->tsrc()->getTextureRaw(spec.name);
+               // Image size on screen
+               core::rect<s32> imgrect(0, 0, spec.geom.X, spec.geom.Y);
+               // Image rectangle on screen
+               core::rect<s32> rect = imgrect + spec.pos;
+               const video::SColor color(255,255,255,255);
+               const video::SColor colors[] = {color,color,color,color};
+               driver->draw2DImage(texture, rect,
+                       core::rect<s32>(core::position2d<s32>(0,0),
+                                       core::dimension2di(texture->getOriginalSize())),
+                       NULL/*&AbsoluteClippingRect*/, colors, true);
        }
-
+       
+       /*
+               Draw images
+       */
        for(u32 i=0; i<m_images.size(); i++)
        {
                const ImageDrawSpec &spec = m_images[i];
@@ -720,6 +750,20 @@ void GUIFormSpecMenu::drawMenu()
                        NULL/*&AbsoluteClippingRect*/, colors, true);
        }
 
+       /*
+               Draw items
+               Phase 0: Item slot rectangles
+               Phase 1: Item images; prepare tooltip
+               If backgrounds used, do not draw Item slot rectangles
+       */
+       int start_phase=0;
+       if (m_backgrounds.size() > 0) start_phase=1;
+       for(int phase=start_phase; phase<=1; phase++)
+       for(u32 i=0; i<m_inventorylists.size(); i++)
+       {
+               drawList(m_inventorylists[i], phase);
+       }
+
        /*
                Draw dragged item stack
        */
@@ -733,6 +777,54 @@ void GUIFormSpecMenu::drawMenu()
 
 void GUIFormSpecMenu::updateSelectedItem()
 {
+       // WARNING: BLACK MAGIC
+       // See if there is a stack suited for our current guess.
+       // If such stack does not exist, clear the guess.
+       if(m_selected_content_guess.name != "")
+       {
+               bool found = false;
+               for(u32 i=0; i<m_inventorylists.size() && !found; i++){
+                       const ListDrawSpec &s = m_inventorylists[i];
+                       Inventory *inv = m_invmgr->getInventory(s.inventoryloc);
+                       if(!inv)
+                               continue;
+                       InventoryList *list = inv->getList(s.listname);
+                       if(!list)
+                               continue;
+                       for(s32 i=0; i<s.geom.X*s.geom.Y && !found; i++){
+                               u32 item_i = i + s.start_item_i;
+                               if(item_i >= list->getSize())
+                                       continue;
+                               ItemStack stack = list->getItem(item_i);
+                               if(stack.name == m_selected_content_guess.name &&
+                                               stack.count == m_selected_content_guess.count){
+                                       found = true;
+                                       if(m_selected_item){
+                                               // If guessed stack is already selected, all is fine
+                                               if(m_selected_item->inventoryloc == s.inventoryloc &&
+                                                               m_selected_item->listname == s.listname &&
+                                                               m_selected_item->i == (s32)item_i &&
+                                                               m_selected_amount == stack.count){
+                                                       break;
+                                               }
+                                               delete m_selected_item;
+                                               m_selected_item = NULL;
+                                       }
+                                       infostream<<"Client: Changing selected content guess to "
+                                                       <<s.inventoryloc.dump()<<" "<<s.listname
+                                                       <<" "<<item_i<<std::endl;
+                                       m_selected_item = new ItemSpec(s.inventoryloc, s.listname, item_i);
+                                       m_selected_amount = stack.count;
+                                       break;
+                               }
+                       }
+               }
+               if(!found){
+                       infostream<<"Client: Discarding selected content guess: "
+                                       <<m_selected_content_guess.getItemString()<<std::endl;
+                       m_selected_content_guess.name = "";
+               }
+       }
        // If the selected stack has become empty for some reason, deselect it.
        // If the selected stack has become smaller, adjust m_selected_amount.
        if(m_selected_item)
@@ -890,14 +982,14 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
 
                        InventoryList *list = inv_s->getList(s.listname);
                        if(list == NULL){
-                               errorstream<<"InventoryMenu: The selected inventory list \""
+                               verbosestream<<"InventoryMenu: The selected inventory list \""
                                                <<s.listname<<"\" does not exist"<<std::endl;
                                s.i = -1;  // make it invalid again
                                break;
                        }
 
                        if((u32)s.i >= list->getSize()){
-                               errorstream<<"InventoryMenu: The selected inventory list \""
+                               infostream<<"InventoryMenu: The selected inventory list \""
                                                <<s.listname<<"\" is too small (i="<<s.i<<", size="
                                                <<list->getSize()<<")"<<std::endl;
                                s.i = -1;  // make it invalid again
@@ -1054,21 +1146,28 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
                        // Check how many items can be moved
                        move_amount = stack_from.count = MYMIN(move_amount, stack_from.count);
                        ItemStack leftover = stack_to.addItem(stack_from, m_gamedef->idef());
-                       if(leftover.count == stack_from.count)
+                       // If source stack cannot be added to destination stack at all,
+                       // they are swapped
+                       if(leftover.count == stack_from.count && leftover.name == stack_from.name)
                        {
-                               // Swap the stacks
-                               m_selected_amount -= stack_to.count;
+                               m_selected_amount = stack_to.count;
+                               // In case the server doesn't directly swap them but instead
+                               // moves stack_to somewhere else, set this
+                               m_selected_content_guess = stack_to;
+                               m_selected_content_guess_inventory = s.inventoryloc;
                        }
+                       // Source stack goes fully into destination stack
                        else if(leftover.empty())
                        {
-                               // Item fits
                                m_selected_amount -= move_amount;
+                               m_selected_content_guess = ItemStack(); // Clear
                        }
+                       // Source stack goes partly into destination stack
                        else
                        {
-                               // Item only fits partially
                                move_amount -= leftover.count;
                                m_selected_amount -= move_amount;
+                               m_selected_content_guess = ItemStack(); // Clear
                        }
 
                        infostream<<"Handing IACTION_MOVE to manager"<<std::endl;
@@ -1084,6 +1183,8 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
                }
                else if(drop_amount > 0)
                {
+                       m_selected_content_guess = ItemStack(); // Clear
+
                        // Send IACTION_DROP
 
                        assert(m_selected_item && m_selected_item->isValid());
@@ -1107,6 +1208,8 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
                }
                else if(craft_amount > 0)
                {
+                       m_selected_content_guess = ItemStack(); // Clear
+
                        // Send IACTION_CRAFT
 
                        assert(s.isValid());
@@ -1126,6 +1229,7 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
                        m_selected_item = NULL;
                        m_selected_amount = 0;
                        m_selected_dragging = false;
+                       m_selected_content_guess = ItemStack();
                }
        }
        if(event.EventType==EET_GUI_EVENT)
@@ -1166,6 +1270,8 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
                                                return true;
                                        }else{
                                                s.send = false;
+                                               // Restore focus to the full form
+                                               Environment->setFocus(this);
                                                return true;
                                        }
                                }