Esempio n. 1
0
// ----------------------------------------------------------------------------
void RibbonWidget::add()
{
    assert(m_magic_number == 0xCAFEC001);
    assert(m_x > -10.0f);
    assert(m_y > -10.0f);
    assert(m_w > 0.0f);
    assert(m_h > 0.0f);


    m_labels.clearWithoutDeleting();

    rect<s32> widget_size = rect<s32>(m_x, m_y, m_x + m_w, m_y + m_h);

    int id = (m_reserved_id == -1 ? getNewID() : m_reserved_id);

    IGUIButton * btn = GUIEngine::getGUIEnv()->addButton(widget_size,
                                                         m_parent, id, L"");
    m_element = btn;

    m_active_children.clearWithoutDeleting(); // Is just a copy of m_children without the deactivated children. m_children takes care of memory.
    for (unsigned int i=0; i<m_children.size(); i++)
    {
        if (m_children[i].isVisible())
        {
            m_active_children.push_back(m_children.get(i));
        }
    }
    const int subbuttons_amount = m_active_children.size();

    // For some ribbon types, we can have unequal sizes depending on whether
    // items have labels or not
    int with_label = 0;
    int without_label = 0;

    // ---- check how much space each child button will take and fit
    // them within available space
    int total_needed_space = 0;
    for (int i=0; i<subbuttons_amount; i++)
    {
        // FIXME: why do I manually invoke the Layout Manager here?
        LayoutManager::readCoords(m_active_children.get(i));
        LayoutManager::applyCoords(m_active_children.get(i), NULL, this);

        if (m_active_children[i].m_type != WTYPE_ICON_BUTTON &&
            m_active_children[i].m_type != WTYPE_BUTTON)
        {
            Log::warn("RiggonWidget", "Ribbon widgets can only have "
                            "(icon)button widgets as children");
            continue;
        }

        // ribbon children must not be keyboard navigatable, the parent
        // ribbon takes care of that
        if (m_active_children[i].m_type == WTYPE_ICON_BUTTON)
        {
            IconButtonWidget* icon = ((IconButtonWidget*)m_active_children.get(i));
            icon->m_tab_stop = false;
        }


        bool has_label_underneath = m_active_children[i].m_text.size() > 0;
        if (m_active_children[i].m_properties[PROP_LABELS_LOCATION].size() > 0)
        {
            has_label_underneath = false;
        }

        if (has_label_underneath) with_label++;
        else                      without_label++;

        total_needed_space += m_active_children[i].m_w;
    }

    //int biggest_y = 0;
    const int button_y = 10;

    const int one_button_space =
        int(roundf((float)m_w / (float)subbuttons_amount));

    int widget_x = -1;

    // ---- add children
    for (int i=0; i<subbuttons_amount; i++)
    {
        // ---- tab ribbons
        if (getRibbonType() == RIBBON_TABS)
        {
            const int large_tab = (int)((with_label + without_label)
                                        *one_button_space
                                        / (with_label + without_label/2.0f));
            const int small_tab = large_tab/2;

            stringw& message = m_active_children[i].m_text;


            if (message.size() == 0)
            {
                if (widget_x == -1) widget_x = small_tab/2;
                else widget_x += small_tab/2;
            }
            else
            {
                if (widget_x == -1) widget_x = large_tab/2;
                else widget_x += large_tab/2;
            }

            IGUIButton * subbtn = NULL;
            rect<s32> subsize = rect<s32>(widget_x - large_tab/2+2,  0,
                                          widget_x + large_tab/2-2,  m_h);

            if (message.size() == 0)
            {
                subsize = rect<s32>(widget_x - small_tab/2+2,  0,
                                    widget_x + small_tab/2-2,  m_h);
            }

            if (m_active_children[i].m_type == WTYPE_BUTTON)
            {
                subbtn = GUIEngine::getGUIEnv()
                       ->addButton(subsize, btn, getNewNoFocusID(),
                                   message.c_str(), L"");
                subbtn->setTabStop(false);
                subbtn->setTabGroup(false);

                if ((int)GUIEngine::getFont()->getDimension(message.c_str())
                                              .Width > subsize.getWidth()  &&
                    message.findFirst(L' ') == -1                          &&
                    message.findFirst(L'\u00AD') == -1                        )
                {
                    // if message too long and contains no space and no soft
                    // hyphen, make the font smaller
                    subbtn->setOverrideFont(GUIEngine::getSmallFont());
                }
            }
            else if (m_active_children[i].m_type == WTYPE_ICON_BUTTON)
            {
                rect<s32> icon_part = rect<s32>(15,
                                                0,
                                                subsize.getHeight()+15,
                                                subsize.getHeight());

                if (message.size() == 0)
                {
                    const int x = subsize.getWidth()/2 - subsize.getHeight()/2;
                    // no label, only icon, so center the icon
                    icon_part = rect<s32>(x,
                                          0,
                                          x + subsize.getHeight(),
                                          subsize.getHeight());
                }

                // label at the *right* of the icon (for tabs)
                rect<s32> label_part = rect<s32>(subsize.getHeight()+15,
                                                 0,
                                                 subsize.getWidth()-15,
                                                 subsize.getHeight());

                // use the same ID for all subcomponents; since event handling
                // is done per-ID, no matter which one your hover, this
                // widget will get it
                int same_id = getNewNoFocusID();
                subbtn = GUIEngine::getGUIEnv()->addButton(subsize, btn,
                                                           same_id, L"", L"");

                IGUIButton* icon =
                    GUIEngine::getGUIEnv()->addButton(icon_part, subbtn,
                                                      same_id, L"");
                icon->setScaleImage(true);
                std::string filename = file_manager->getAsset(
                                     m_active_children[i].m_properties[PROP_ICON]);
                icon->setImage( irr_driver->getTexture(filename.c_str()) );
                icon->setUseAlphaChannel(true);
                icon->setDrawBorder(false);
                icon->setTabStop(false);

                IGUIStaticText* label =
                    GUIEngine::getGUIEnv()->addStaticText(message.c_str(),
                                                          label_part,
                                                          false /* border */,
                                                          true /* word wrap */,
                                                          subbtn, same_id);

                if ((int)GUIEngine::getFont()->getDimension(message.c_str())
                                              .Width > label_part.getWidth()&&
                    message.findFirst(L' ') == -1                           &&
                    message.findFirst(L'\u00AD') == -1                        )
                {
                    // if message too long and contains no space and no soft
                    // hyphen, make the font smaller
                    label->setOverrideFont(GUIEngine::getSmallFont());
                }
                label->setTextAlignment(EGUIA_CENTER, EGUIA_CENTER);
                label->setTabStop(false);
                label->setNotClipped(true);
                label->setRightToLeft(translations->isRTLText(message));
                m_labels.push_back(label);

                subbtn->setTabStop(false);
                subbtn->setTabGroup(false);
            }
            else
            {
                Log::error("RibbonWidget", "Invalid tab bar contents");
            }

            m_active_children[i].m_element = subbtn;

            if (message.size() == 0) widget_x += small_tab/2;
            else                     widget_x += large_tab/2;
        }
        // ---- icon ribbons
        else if (m_active_children[i].m_type == WTYPE_ICON_BUTTON)
        {
            if (widget_x == -1) widget_x = one_button_space/2;

            // find how much space to keep for the label under the button.
            // consider font size, whether the label is multiline, etc...
            bool has_label = m_active_children[i].m_text.size() > 0;

            if (m_active_children[i].m_properties[PROP_LABELS_LOCATION].size() > 0)
            {
                has_label = false;
            }

            const int needed_space_under_button = has_label
                                                ? GUIEngine::getFontHeight()
                                                : 10;

            float imageRatio =
                (float)m_active_children[i].m_w / (float)m_active_children[i].m_h;

            // calculate the size of the image
            std::string filename =
                file_manager->getAsset(m_active_children[i].m_properties[PROP_ICON]);
            video::ITexture* image =
                irr_driver->getTexture((filename).c_str());
            if(!image)
            {
                std::string file = file_manager->getAsset(FileManager::GUI,"main_help.png");
                image = irr_driver->getTexture(file);
                if(!image)
                    Log::fatal("RibbonWidget",
                        "Can't find fallback texture 'gui/main_help.png, aborting.");
            }

            float image_h = (float)image->getSize().Height;
            float image_w = image_h*imageRatio;
            float zoom = (float) (m_h - button_y - needed_space_under_button) / image_h;
            float zoom_x = (float) one_button_space / image_w;
            if(zoom_x < zoom)
                zoom = zoom_x;

            // ---- add bitmap button part
            // backup and restore position in case the same object is added
            // multiple times (FIXME: unclean)
            int old_x = m_active_children[i].m_x;
            int old_y = m_active_children[i].m_y;
            int old_w = m_active_children[i].m_w;
            int old_h = m_active_children[i].m_h;

            m_active_children[i].m_x = widget_x - int(image_w*zoom/2.0f);
            m_active_children[i].m_y = button_y;
            m_active_children[i].m_w = int(image_w*zoom);
            m_active_children[i].m_h = int(image_h*zoom);

            IconButtonWidget* icon = ((IconButtonWidget*)m_active_children.get(i));

            if (icon->m_properties[PROP_EXTEND_LABEL].size() == 0)
            {
                icon->m_properties[PROP_EXTEND_LABEL] =
                    StringUtils::toString(one_button_space - icon->m_w);
            }

            m_active_children.get(i)->m_parent = btn;
            m_active_children.get(i)->add();

            // restore backuped size and location (see above for more info)
            m_active_children[i].m_x = old_x;
            m_active_children[i].m_y = old_y;
            m_active_children[i].m_w = old_w;
            m_active_children[i].m_h = old_h;

            // the label itself will be added by the icon widget. since it
            // adds the label outside of the widget area it is assigned to,
            // the label will appear in the area we want at the bottom

            widget_x += one_button_space;
        }
        else
        {
            Log::warn("RiggonWidget", "Invalid contents type in ribbon");
        }


        //m_children[i].id = subbtn->getID();
        m_active_children[i].m_event_handler = this;
    }// next sub-button

    id = m_element->getID();
    m_element->setTabOrder(id);
    m_element->setTabGroup(false);
    updateSelection();

    if (!m_is_visible)
        setVisible(false);
}   // add
Esempio n. 2
0
void RibbonWidget::add()
{
    m_labels.clearWithoutDeleting();
    
    
    rect<s32> widget_size = rect<s32>(m_x, m_y, m_x + m_w, m_y + m_h);
    
    int id = (m_reserved_id == -1 ? getNewID() : m_reserved_id);
    
    IGUIButton * btn = GUIEngine::getGUIEnv()->addButton(widget_size, m_parent, id, L"");
    m_element = btn;
    
    const int subbuttons_amount = m_children.size();
    
    // ---- check how much space each child button will take and fit them within available space
    int total_needed_space = 0;
    for (int i=0; i<subbuttons_amount; i++)
    {
        // FIXME: a little unclean to invoke layout code here?
        LayoutManager::readCoords(m_children.get(i), NULL, this);
        
        if (m_children[i].m_type != WTYPE_ICON_BUTTON && m_children[i].m_type != WTYPE_BUTTON)
        {
            std::cerr << "/!\\ Warning /!\\ : ribbon widgets can only have (icon)button widgets as children "
                      << std::endl;
            continue;
        }
        
        // ribbon children must not be keyboard navigatable, the parent ribbon takes care of that
        if (m_children[i].m_type == WTYPE_ICON_BUTTON)
        {
            IconButtonWidget* icon = ((IconButtonWidget*)m_children.get(i));
            icon->m_tab_stop = false;
        }
        
        total_needed_space += m_children[i].m_w;
    }
    
    int free_w_space = m_w - total_needed_space;
    
    //int biggest_y = 0;
    const int button_y = 10;
    float global_zoom = 1;
    
    const int min_free_space = 50;
    global_zoom = (float)m_w / (float)( m_w - free_w_space + min_free_space );
    //free_w_space = (int)(m_w - total_needed_space*global_zoom);
    
    const int one_button_space = (int)round((float)m_w / (float)subbuttons_amount);
    
    // ---- add children
    for (int i=0; i<subbuttons_amount; i++)
    {
        
        const int widget_x = one_button_space*(i+1) - one_button_space/2;
        
        // ---- tab ribbons
        if (getRibbonType() == RIBBON_TABS)
        {
            IGUIButton * subbtn = NULL;
            rect<s32> subsize = rect<s32>(widget_x - one_button_space/2+2,  0,
                                          widget_x + one_button_space/2-2,  m_h);
            
            stringw& message = m_children[i].m_text;
            
            if (m_children[i].m_type == WTYPE_BUTTON)
            {
                subbtn = GUIEngine::getGUIEnv()->addButton(subsize, btn, getNewNoFocusID(), message.c_str(), L"");
                subbtn->setTabStop(false);
                subbtn->setTabGroup(false);
            }
            else if (m_children[i].m_type == WTYPE_ICON_BUTTON)
            {
                rect<s32> icon_part = rect<s32>(15,
                                                0,
                                                subsize.getHeight()+15,
                                                subsize.getHeight());
                // label at the *right* of the icon (for tabs)
                rect<s32> label_part = rect<s32>(subsize.getHeight()+15,
                                                 0,
                                                 subsize.getWidth()-15,
                                                 subsize.getHeight());
                
                // use the same ID for all subcomponents; since event handling is done per-ID, no matter
                // which one your hover, this widget will get it
                int same_id = getNewNoFocusID();
                subbtn = GUIEngine::getGUIEnv()->addButton(subsize, btn, same_id, L"", L"");
                
                //MyGUIButton* icon = new MyGUIButton(GUIEngine::getGUIEnv(), subbtn, same_id, icon_part, true);
                IGUIButton* icon = GUIEngine::getGUIEnv()->addButton(icon_part, subbtn, same_id, L"");
                icon->setScaleImage(true);
                icon->setImage( irr_driver->getTexture((file_manager->getDataDir() + "/" + m_children[i].m_properties[PROP_ICON]).c_str()) );
                icon->setUseAlphaChannel(true);
                icon->setDrawBorder(false);
                icon->setTabStop(false);
                
                IGUIStaticText* label = GUIEngine::getGUIEnv()->addStaticText(message.c_str(), label_part,
                                                                              false /* border */,
                                                                              true /* word wrap */,
                                                                              subbtn, same_id);
                label->setTextAlignment(EGUIA_CENTER, EGUIA_CENTER);
                label->setTabStop(false);
                label->setNotClipped(true);
                m_labels.push_back(label);
                
                subbtn->setTabStop(false);
                subbtn->setTabGroup(false);
                
            }
            else
            {
                std::cerr << "Invalid tab bar contents\n";
            }
            
            m_children[i].m_element = subbtn;
        }
        // ---- icon ribbons
        else if (m_children[i].m_type == WTYPE_ICON_BUTTON)
        {
            // find how much space to keep for the label under the button.
            // consider font size, whether the label is multiline, etc...
            const bool has_label = m_children[i].m_text.size() > 0;
            
            const int needed_space_under_button = has_label ? GUIEngine::getFontHeight() : 10;
            
            float imageRatio = (float)m_children[i].m_w / (float)m_children[i].m_h;
            
            // calculate the size of the image
            video::ITexture* image = irr_driver->getTexture((file_manager->getDataDir() + "/" + m_children[i].m_properties[PROP_ICON]).c_str());
            float image_h = (float)image->getSize().Height;
            float image_w = image_h*imageRatio;

            // scale to fit (FIXME: calculate the right value directly...)
            float zoom = global_zoom;
            
            if (button_y + image_h*zoom + needed_space_under_button > m_h)
            {
                // scale down
                while (button_y + image_h*zoom + needed_space_under_button > m_h) zoom -= 0.01f;
            }
            else
            {
                // scale up
                while (button_y + image_h*zoom + needed_space_under_button < m_h) zoom += 0.01f;
            }
            
            // ---- add bitmap button part
            // backup and restore position in case the same object is added multiple times (FIXME: unclean)
            int old_x = m_children[i].m_x;
            int old_y = m_children[i].m_y;
            int old_w = m_children[i].m_w;
            int old_h = m_children[i].m_h;
            
            m_children[i].m_x = widget_x - (int)(image_w*zoom/2.0f);
            m_children[i].m_y = button_y;
            m_children[i].m_w = (int)(image_w*zoom);
            m_children[i].m_h = (int)(image_h*zoom);
            
            IconButtonWidget* icon = ((IconButtonWidget*)m_children.get(i));
            icon->m_properties[PROP_EXTEND_LABEL] = StringUtils::toString(one_button_space - icon->m_w);

            m_children.get(i)->m_parent = btn;
            m_children.get(i)->add();

            // restore backuped size and location (see above for more info)
            m_children[i].m_x = old_x;
            m_children[i].m_y = old_y;
            m_children[i].m_w = old_w;
            m_children[i].m_h = old_h;
            
            // the label itself will be added by the icon widget. since it adds the label outside of the
            // widget area it is assigned to, the label will appear in the area we want at the bottom
        }
        else
        {
            std::cerr << "/!\\ Warning /!\\ : Invalid contents type in ribbon" << std::endl;
        }
        
        
        //m_children[i].id = subbtn->getID();
        m_children[i].m_event_handler = this;
    }// next sub-button
    
    id = m_element->getID();
    m_element->setTabOrder(id);
    m_element->setTabGroup(false);
    updateSelection();
}