Moved layout code out of Widget and Screen classes; not only is it cleaner this way, it also paves the way for eventually making Dialog classes also use the XML layout code

git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@5737 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
auria 2010-08-15 20:24:51 +00:00
parent e034082a2b
commit b1f7012cbd
11 changed files with 463 additions and 389 deletions

View File

@ -85,6 +85,8 @@ supertuxkart_SOURCES = \
guiengine/engine.hpp \
guiengine/event_handler.cpp \
guiengine/event_handler.hpp \
guiengine/layout_manager.cpp \
guiengine/layout_manager.hpp \
guiengine/modaldialog.cpp \
guiengine/modaldialog.hpp \
guiengine/scalable_font.cpp \

View File

@ -233,5 +233,3 @@ void AbstractStateManager::resetAndSetStack(Screen* screens[])
onTopMostScreenChanged();
} // resetAndSetStack

View File

@ -0,0 +1,380 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2010 Marianne Gagnon
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "graphics/irr_driver.hpp"
#include "guiengine/engine.hpp"
#include "guiengine/layout_manager.hpp"
#include "guiengine/scalable_font.hpp"
#include "guiengine/widget.hpp"
#include "io/file_manager.hpp"
#include "utils/ptr_vector.hpp"
#include <sstream>
using namespace GUIEngine;
#include "irrlicht.h"
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
// ----------------------------------------------------------------------------
bool LayoutManager::convertToCoord(std::string& x, int* absolute /* out */, int* percentage /* out */)
{
bool is_number;
int i;
std::istringstream myStream(x);
is_number = (myStream >> i)!=0;
if(!is_number) return false;
if( x[x.size()-1] == '%' ) // percentage
{
*percentage = i;
return true;
}
else // absolute number
{
*absolute = i;
return true;
}
}
// ----------------------------------------------------------------------------
void LayoutManager::readCoords(Widget* self, Widget* parent)
{
// determine widget position and size if not already done by sizers
std::string x = self->m_properties[PROP_X];
std::string y = self->m_properties[PROP_Y];
std::string width = self->m_properties[PROP_WIDTH];
std::string height = self->m_properties[PROP_HEIGHT];
// retrieve parent size (or screen size if none). Will be useful for layout
// and especially for percentages.
unsigned int parent_w, parent_h, parent_x, parent_y;
if(parent == NULL)
{
core::dimension2d<u32> frame_size = GUIEngine::getDriver()->getCurrentRenderTargetSize();
parent_w = frame_size.Width;
parent_h = frame_size.Height;
parent_x = 0;
parent_y = 0;
}
else
{
parent_w = parent->m_w;
parent_h = parent->m_h;
parent_x = parent->m_x;
parent_y = parent->m_y;
}
// ---- try converting to number
// x coord
{
int abs_x = -1, percent_x = -1;
if(convertToCoord(x, &abs_x, &percent_x ))
{
if (abs_x > -1) self->m_x = parent_x + abs_x;
else if (abs_x < -1) self->m_x = parent_x + (parent_w + abs_x);
else if (percent_x > -1) self->m_x = parent_x + parent_w*percent_x/100;
}
}
// y coord
{
int abs_y = -1, percent_y = -1;
if(convertToCoord(y, &abs_y, &percent_y ))
{
if (abs_y > -1) self->m_y = parent_y + abs_y;
else if (abs_y < -1) self->m_y = parent_y + (parent_h + abs_y);
else if (percent_y > -1) self->m_y = parent_y + parent_h*percent_y/100;
}
}
// ---- if this widget has an icon, get icon size. this can helpful determine its optimal size
int texture_w = -1, texture_h = -1;
if(self->m_properties[PROP_ICON].size() > 0)
{
ITexture* texture = irr_driver->getTexture((file_manager->getDataDir() + "/" +
self->m_properties[PROP_ICON]).c_str());
if(texture != NULL)
{
texture_w = texture->getSize().Width;
texture_h = texture->getSize().Height;
}
}
// ---- if this widget has a label, get text size. this can helpful determine its optimal size
int label_w = -1, label_h = -1;
if (self->m_text.size() > 0)
{
IGUIFont* font = (self->m_title_font ? GUIEngine::getTitleFont() : GUIEngine::getFont());
core::dimension2d< u32 > dim = font->getDimension( self->m_text.c_str() );
label_w = dim.Width + self->getWidthNeededAroundLabel();
// FIXME - won't work with multiline labels. thus, for now, when multiple
// lines are required, we need to specify a height explicitely
label_h = dim.Height + self->getHeightNeededAroundLabel();
}
// ---- read dimension
// width
{
int abs_w = -1, percent_w = -1;
if(convertToCoord(width, &abs_w, &percent_w ))
{
if (abs_w > -1) self->m_w = abs_w;
else if (percent_w > -1) self->m_w = (int)round(parent_w*percent_w/100.0);
}
else if(texture_w > -1) self->m_w = texture_w;
else if(label_w > -1) self->m_w = label_w;
}
// height
{
int abs_h = -1, percent_h = -1;
if (convertToCoord(height, &abs_h, &percent_h ))
{
if (abs_h > -1) self->m_h = abs_h;
else if (percent_h > -1) self->m_h = parent_h*percent_h/100;
}
else if (texture_h > -1 && label_h > -1) self->m_h = texture_h + label_h; // label + icon
else if (texture_h > -1) self->m_h = texture_h;
else if (label_h > -1) self->m_h = label_h;
}
// ---- can't make widget bigger than parent
if (self->m_h > (int)parent_h)
{
float ratio = (float)parent_h / self->m_h;
self->m_w = (int)(self->m_w*ratio);
self->m_h = (int)(self->m_h*ratio);
}
if (self->m_w > (int)parent_w)
{
// scale down while keeping aspect ratio (don't do this for text widgets though...)
float ratio = (float)parent_w / self->m_w;
self->m_w = (int)(self->m_w * ratio);
if (self->m_type != WTYPE_LABEL) self->m_h = (int)(self->m_h * ratio);
}
// ------ check for given max size
if (self->m_properties[PROP_MAX_WIDTH].size() > 0)
{
const int max_width = atoi( self->m_properties[PROP_MAX_WIDTH].c_str() );
if (self->m_w > max_width) self->m_w = max_width;
}
if (self->m_properties[PROP_MAX_HEIGHT].size() > 0)
{
const int max_height = atoi( self->m_properties[PROP_MAX_HEIGHT].c_str() );
if (self->m_h > max_height) self->m_h = max_height;
}
}
// ----------------------------------------------------------------------------
void LayoutManager::calculateLayout(ptr_vector<Widget>& widgets, Widget* parent)
{
const unsigned short widgets_amount = widgets.size();
// ----- read x/y/size parameters
for (unsigned short n=0; n<widgets_amount; n++)
{
readCoords(widgets.get(n), parent);
}//next widget
// ----- manage 'layout's if relevant
do // i'm using 'while false' here just to be able to 'break' ...
{
if(parent == NULL) break;
std::string layout_name = parent->m_properties[PROP_LAYOUT];
if(layout_name.size() < 1) break;
bool horizontal = false;
if (!strcmp("horizontal-row", layout_name.c_str()))
horizontal = true;
else if(!strcmp("vertical-row", layout_name.c_str()))
horizontal = false;
else
{
std::cerr << "Unknown layout name : " << layout_name.c_str() << std::endl;
break;
}
const int w = parent->m_w, h = parent->m_h;
// find space left after placing all absolutely-sized widgets in a row
// (the space left will be divided between remaining widgets later)
int left_space = (horizontal ? w : h);
unsigned short total_proportion = 0;
for(int n=0; n<widgets_amount; n++)
{
// relatively-sized widget
std::string prop = widgets[n].m_properties[ PROP_PROPORTION ];
if(prop.size() != 0)
{
total_proportion += atoi( prop.c_str() );
continue;
}
// absolutely-sized widgets
left_space -= (horizontal ? widgets[n].m_w : widgets[n].m_h);
} // next widget
// ---- lay widgets in row
int x = parent->m_x;
int y = parent->m_y;
for (int n=0; n<widgets_amount; n++)
{
std::string prop = widgets[n].m_properties[ PROP_PROPORTION ];
if(prop.size() != 0)
{
// proportional size
int proportion = 1;
std::istringstream myStream(prop);
if (!(myStream >> proportion))
std::cerr << "/!\\ Warning /!\\ : proportion '" << prop.c_str() << "' is not a number in widget " << widgets[n].m_properties[PROP_ID].c_str() << std::endl;
const float fraction = (float)proportion/(float)total_proportion;
if (horizontal)
{
widgets[n].m_x = x;
std::string align = widgets[n].m_properties[ PROP_ALIGN ];
if (align.size() < 1)
{
if (widgets[n].m_properties[ PROP_Y ].size() > 0)
widgets[n].m_y = atoi(widgets[n].m_properties[ PROP_Y ].c_str());
else
widgets[n].m_y = y;
}
else if (align == "top") widgets[n].m_y = y;
else if (align == "center") widgets[n].m_y = y + h/2 - widgets[n].m_h/2;
else if (align == "bottom") widgets[n].m_y = y + h - widgets[n].m_h;
else std::cerr << "/!\\ Warning /!\\ : alignment '" << align.c_str()
<< "' is unknown (widget '" << widgets[n].m_properties[PROP_ID].c_str()
<< "', in a horiozntal-row layout)\n";
widgets[n].m_w = (int)(left_space*fraction);
if (widgets[n].m_properties[PROP_MAX_WIDTH].size() > 0)
{
const int max_width = atoi( widgets[n].m_properties[PROP_MAX_WIDTH].c_str() );
if (widgets[n].m_w > max_width) widgets[n].m_w = max_width;
}
x += widgets[n].m_w;
}
else
{
widgets[n].m_h = (int)(left_space*fraction);
if (widgets[n].m_properties[PROP_MAX_HEIGHT].size() > 0)
{
const int max_height = atoi( widgets[n].m_properties[PROP_MAX_HEIGHT].c_str() );
if (widgets[n].m_h > max_height) widgets[n].m_h = max_height;
}
std::string align = widgets[n].m_properties[ PROP_ALIGN ];
if (align.size() < 1)
{
if (widgets[n].m_properties[ PROP_X ].size() > 0)
widgets[n].m_x = atoi(widgets[n].m_properties[ PROP_X ].c_str());
else
widgets[n].m_x = x;
}
else if (align == "left") widgets[n].m_x = x;
else if (align == "center") widgets[n].m_x = x + w/2 - widgets[n].m_w/2;
else if (align == "right") widgets[n].m_x = x + w - widgets[n].m_w;
else std::cerr << "/!\\ Warning /!\\ : alignment '" << align.c_str()
<< "' is unknown (widget '" << widgets[n].m_properties[PROP_ID].c_str()
<< "', in a vertical-row layout)\n";
widgets[n].m_y = y;
y += widgets[n].m_h;
}
}
else
{
// absolute size
if (horizontal)
{
widgets[n].m_x = x;
std::string align = widgets[n].m_properties[ PROP_ALIGN ];
if (align.size() < 1)
{
if (widgets[n].m_properties[ PROP_Y ].size() > 0)
widgets[n].m_y = atoi(widgets[n].m_properties[ PROP_Y ].c_str());
else
widgets[n].m_y = y;
}
else if (align == "top") widgets[n].m_y = y;
else if (align == "center") widgets[n].m_y = y + h/2 - widgets[n].m_h/2;
else if (align == "bottom") widgets[n].m_y = y + h - widgets[n].m_h;
else std::cerr << "/!\\ Warning /!\\ : alignment '" << align.c_str() << "' is unknown in widget " << widgets[n].m_properties[PROP_ID].c_str() << std::endl;
x += widgets[n].m_w;
}
else
{
//widgets[n].h = abs_var;
std::string align = widgets[n].m_properties[ PROP_ALIGN ];
if (align.size() < 1)
{
if (widgets[n].m_properties[ PROP_X ].size() > 0)
widgets[n].m_x = atoi(widgets[n].m_properties[ PROP_X ].c_str());
else
widgets[n].m_x = x;
}
else if (align == "left") widgets[n].m_x = x;
else if (align == "center") widgets[n].m_x = x + w/2 - widgets[n].m_w/2;
else if (align == "right") widgets[n].m_x = x + w - widgets[n].m_w;
else std::cerr << "/!\\ Warning /!\\ : alignment '" << align.c_str() << "' is unknown in widget " << widgets[n].m_properties[PROP_ID].c_str() << std::endl;
widgets[n].m_y = y;
y += widgets[n].m_h;
}
} // end if property or absolute size
} // next widget
} while(false);
// ----- also deal with containers' children
for(int n=0; n<widgets_amount; n++)
{
if(widgets[n].m_type == WTYPE_DIV) calculateLayout(widgets[n].m_children, &widgets[n]);
}
} // calculateLayout

View File

@ -0,0 +1,59 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2009 Marianne Gagnon
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef __LAYOUT_MANAGER_HPP__
#define __LAYOUT_MANAGER_HPP__
#include <cstring> // for NULL
#include "utils/ptr_vector.hpp"
namespace GUIEngine
{
class Widget;
class LayoutManager
{
/**
* \brief Receives as string the raw property value retrieved from XML file.
* Will try to make sense of it, as an absolute value or a percentage.
*
* Return values :
* Will write to either absolute or percentage, depending on the case.
* Returns false if couldn't convert to either
*/
static bool convertToCoord(std::string& x, int* absolute /* out */, int* percentage /* out */);
public:
/**
* \brief Find a widget's x, y, w and h coords from what is specified in the XML properties.
* Most notably, expands coords relative to parent and percentages.
*/
static void readCoords(Widget* self, Widget* parent);
/**
* \brief Recursive call that lays out children widget within parent (or screen if none).
*
* Manages 'horizontal-row' and 'vertical-row' layouts, along with the proportions
* of the remaining children, as well as absolute sizes and locations.
*/
static void calculateLayout(ptr_vector<Widget>& widgets, Widget* parent=NULL);
};
}
#endif

View File

@ -1,5 +1,5 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2009 Marianne Gagnon
// Copyright (C) 2010 Marianne Gagnon
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@ -25,6 +25,7 @@
#include "input/input.hpp"
#include "io/file_manager.hpp"
#include "guiengine/engine.hpp"
#include "guiengine/layout_manager.hpp"
#include "guiengine/modaldialog.hpp"
#include "guiengine/screen.hpp"
#include "guiengine/widget.hpp"
@ -146,191 +147,7 @@ void Screen::calculateLayout()
{
assert(m_magic_number == 0xCAFEC001);
// build layout
calculateLayout( m_widgets );
} // calculateLayout
// -----------------------------------------------------------------------------
void Screen::calculateLayout(ptr_vector<Widget>& widgets, Widget* parent)
{
assert(m_magic_number == 0xCAFEC001);
const unsigned short widgets_amount = widgets.size();
// ----- read x/y/size parameters
for(unsigned short n=0; n<widgets_amount; n++)
{
widgets[n].readCoords(parent);
}//next widget
// ----- manage 'layout's if relevant
do // i'm using 'while false' here just to be able to 'break' ...
{
if(parent == NULL) break;
std::string layout_name = parent->m_properties[PROP_LAYOUT];
if(layout_name.size() < 1) break;
bool horizontal = false;
if (!strcmp("horizontal-row", layout_name.c_str()))
horizontal = true;
else if(!strcmp("vertical-row", layout_name.c_str()))
horizontal = false;
else
{
std::cerr << "Unknown layout name : " << layout_name.c_str() << std::endl;
break;
}
const int w = parent->m_w, h = parent->m_h;
// find space left after placing all absolutely-sized widgets in a row
// (the space left will be divided between remaining widgets later)
int left_space = (horizontal ? w : h);
unsigned short total_proportion = 0;
for(int n=0; n<widgets_amount; n++)
{
// relatively-sized widget
std::string prop = widgets[n].m_properties[ PROP_PROPORTION ];
if(prop.size() != 0)
{
total_proportion += atoi( prop.c_str() );
continue;
}
// absolutely-sized widgets
left_space -= (horizontal ? widgets[n].m_w : widgets[n].m_h);
} // next widget
// ---- lay widgets in row
int x = parent->m_x;
int y = parent->m_y;
for (int n=0; n<widgets_amount; n++)
{
std::string prop = widgets[n].m_properties[ PROP_PROPORTION ];
if(prop.size() != 0)
{
// proportional size
int proportion = 1;
std::istringstream myStream(prop);
if (!(myStream >> proportion))
std::cerr << "/!\\ Warning /!\\ : proportion '" << prop.c_str() << "' is not a number in widget " << widgets[n].m_properties[PROP_ID].c_str() << std::endl;
const float fraction = (float)proportion/(float)total_proportion;
if (horizontal)
{
widgets[n].m_x = x;
std::string align = widgets[n].m_properties[ PROP_ALIGN ];
if (align.size() < 1)
{
if (widgets[n].m_properties[ PROP_Y ].size() > 0)
widgets[n].m_y = atoi(widgets[n].m_properties[ PROP_Y ].c_str());
else
widgets[n].m_y = y;
}
else if (align == "top") widgets[n].m_y = y;
else if (align == "center") widgets[n].m_y = y + h/2 - widgets[n].m_h/2;
else if (align == "bottom") widgets[n].m_y = y + h - widgets[n].m_h;
else std::cerr << "/!\\ Warning /!\\ : alignment '" << align.c_str()
<< "' is unknown (widget '" << widgets[n].m_properties[PROP_ID].c_str()
<< "', in a horiozntal-row layout)\n";
widgets[n].m_w = (int)(left_space*fraction);
if (widgets[n].m_properties[PROP_MAX_WIDTH].size() > 0)
{
const int max_width = atoi( widgets[n].m_properties[PROP_MAX_WIDTH].c_str() );
if (widgets[n].m_w > max_width) widgets[n].m_w = max_width;
}
x += widgets[n].m_w;
}
else
{
widgets[n].m_h = (int)(left_space*fraction);
if (widgets[n].m_properties[PROP_MAX_HEIGHT].size() > 0)
{
const int max_height = atoi( widgets[n].m_properties[PROP_MAX_HEIGHT].c_str() );
if (widgets[n].m_h > max_height) widgets[n].m_h = max_height;
}
std::string align = widgets[n].m_properties[ PROP_ALIGN ];
if (align.size() < 1)
{
if (widgets[n].m_properties[ PROP_X ].size() > 0)
widgets[n].m_x = atoi(widgets[n].m_properties[ PROP_X ].c_str());
else
widgets[n].m_x = x;
}
else if (align == "left") widgets[n].m_x = x;
else if (align == "center") widgets[n].m_x = x + w/2 - widgets[n].m_w/2;
else if (align == "right") widgets[n].m_x = x + w - widgets[n].m_w;
else std::cerr << "/!\\ Warning /!\\ : alignment '" << align.c_str()
<< "' is unknown (widget '" << widgets[n].m_properties[PROP_ID].c_str()
<< "', in a vertical-row layout)\n";
widgets[n].m_y = y;
y += widgets[n].m_h;
}
}
else
{
// absolute size
if (horizontal)
{
widgets[n].m_x = x;
std::string align = widgets[n].m_properties[ PROP_ALIGN ];
if (align.size() < 1)
{
if (widgets[n].m_properties[ PROP_Y ].size() > 0)
widgets[n].m_y = atoi(widgets[n].m_properties[ PROP_Y ].c_str());
else
widgets[n].m_y = y;
}
else if (align == "top") widgets[n].m_y = y;
else if (align == "center") widgets[n].m_y = y + h/2 - widgets[n].m_h/2;
else if (align == "bottom") widgets[n].m_y = y + h - widgets[n].m_h;
else std::cerr << "/!\\ Warning /!\\ : alignment '" << align.c_str() << "' is unknown in widget " << widgets[n].m_properties[PROP_ID].c_str() << std::endl;
x += widgets[n].m_w;
}
else
{
//widgets[n].h = abs_var;
std::string align = widgets[n].m_properties[ PROP_ALIGN ];
if (align.size() < 1)
{
if (widgets[n].m_properties[ PROP_X ].size() > 0)
widgets[n].m_x = atoi(widgets[n].m_properties[ PROP_X ].c_str());
else
widgets[n].m_x = x;
}
else if (align == "left") widgets[n].m_x = x;
else if (align == "center") widgets[n].m_x = x + w/2 - widgets[n].m_w/2;
else if (align == "right") widgets[n].m_x = x + w - widgets[n].m_w;
else std::cerr << "/!\\ Warning /!\\ : alignment '" << align.c_str() << "' is unknown in widget " << widgets[n].m_properties[PROP_ID].c_str() << std::endl;
widgets[n].m_y = y;
y += widgets[n].m_h;
}
} // end if property or absolute size
} // next widget
} while(false);
// ----- also deal with containers' children
for(int n=0; n<widgets_amount; n++)
{
if(widgets[n].m_type == WTYPE_DIV) calculateLayout(widgets[n].m_children, &widgets[n]);
}
LayoutManager::calculateLayout( m_widgets );
} // calculateLayout
// -----------------------------------------------------------------------------

View File

@ -96,14 +96,6 @@ namespace GUIEngine
static void addWidgetsRecursively(ptr_vector<Widget>& widgets, Widget* parent=NULL);
/**
* @brief Recursive call that lays out children widget within parent (or screen if none).
*
* Manages 'horizontal-row' and 'vertical-row' layouts, along with the proportions
* of the remaining children, as well as absolute sizes and locations.
*/
void calculateLayout(ptr_vector<Widget>& widgets, Widget* parent=NULL);
/** Will be called to determine if the 3D scene must be rendered when at this screen. */
bool m_render_3d;

View File

@ -258,37 +258,6 @@ bool Widget::isFocusedForPlayer(const int playerID)
return m_player_focus[playerID];
}
// -----------------------------------------------------------------------------
/**
* Receives as string the raw property value retrieved from XML file.
* Will try to make sense of it, as an absolute value or a percentage.
*
* Return values :
* Will write to either absolute or percentage, depending on the case.
* Returns false if couldn't convert to either
*/
bool Widget::convertToCoord(std::string& x, int* absolute /* out */, int* percentage /* out */)
{
bool is_number;
int i;
std::istringstream myStream(x);
is_number = (myStream >> i)!=0;
if(!is_number) return false;
if( x[x.size()-1] == '%' ) // percentage
{
*percentage = i;
return true;
}
else // absolute number
{
*absolute = i;
return true;
}
}
// -----------------------------------------------------------------------------
@ -304,147 +273,6 @@ void Widget::move(const int x, const int y, const int w, const int h)
m_element->setRelativePosition( core::rect < s32 > (x, y, x+w, y+h) );
}
// -----------------------------------------------------------------------------
/**
* Finds its x, y, w and h coords from what is specified in the XML properties.
* Most notably, expands coords relative to parent and percentages.
*/
void Widget::readCoords(Widget* parent)
{
assert(m_magic_number == 0xCAFEC001);
/* determine widget position and size if not already done by sizers */
std::string x = m_properties[PROP_X];
std::string y = m_properties[PROP_Y];
std::string width = m_properties[PROP_WIDTH];
std::string height = m_properties[PROP_HEIGHT];
/* retrieve parent size (or screen size if none). Will be useful for layout
and especially for percentages. */
unsigned int parent_w, parent_h, parent_x, parent_y;
if(parent == NULL)
{
core::dimension2d<u32> frame_size = GUIEngine::getDriver()->getCurrentRenderTargetSize();
parent_w = frame_size.Width;
parent_h = frame_size.Height;
parent_x = 0;
parent_y = 0;
}
else
{
parent_w = parent->m_w;
parent_h = parent->m_h;
parent_x = parent->m_x;
parent_y = parent->m_y;
}
// ---- try converting to number
// x coord
{
int abs_x = -1, percent_x = -1;
if(convertToCoord(x, &abs_x, &percent_x ))
{
if (abs_x > -1) m_x = parent_x + abs_x;
else if (abs_x < -1) m_x = parent_x + (parent_w + abs_x);
else if (percent_x > -1) m_x = parent_x + parent_w*percent_x/100;
}
}
// y coord
{
int abs_y = -1, percent_y = -1;
if(convertToCoord(y, &abs_y, &percent_y ))
{
if (abs_y > -1) m_y = parent_y + abs_y;
else if (abs_y < -1) m_y = parent_y + (parent_h + abs_y);
else if (percent_y > -1) m_y = parent_y + parent_h*percent_y/100;
}
}
// ---- if this widget has an icon, get icon size. this can helpful determine its optimal size
int texture_w = -1, texture_h = -1;
if(m_properties[PROP_ICON].size() > 0)
{
ITexture* texture = irr_driver->getTexture(
(file_manager->getDataDir() + "/" + m_properties[PROP_ICON]).c_str());
if(texture != NULL)
{
texture_w = texture->getSize().Width;
texture_h = texture->getSize().Height;
}
}
// ---- if this widget has a label, get text size. this can helpful determine its optimal size
int label_w = -1, label_h = -1;
if (m_text.size() > 0)
{
IGUIFont* font = (m_title_font ? GUIEngine::getTitleFont() : GUIEngine::getFont());
core::dimension2d< u32 > dim = font->getDimension( m_text.c_str() );
label_w = dim.Width + getWidthNeededAroundLabel();
// FIXME - won't work with multiline labels. thus, for now, when multiple
// lines are required, we need to specify a height explicitely
label_h = dim.Height + getHeightNeededAroundLabel();
}
// ---- read dimension
// width
{
int abs_w = -1, percent_w = -1;
if(convertToCoord(width, &abs_w, &percent_w ))
{
if (abs_w > -1) m_w = abs_w;
else if (percent_w > -1) m_w = (int)round(parent_w*percent_w/100.0);
}
else if(texture_w > -1) m_w = texture_w;
else if(label_w > -1) m_w = label_w;
}
// height
{
int abs_h = -1, percent_h = -1;
if (convertToCoord(height, &abs_h, &percent_h ))
{
if (abs_h > -1) m_h = abs_h;
else if (percent_h > -1) m_h = parent_h*percent_h/100;
}
else if (texture_h > -1 && label_h > -1) m_h = texture_h + label_h; // label + icon
else if (texture_h > -1) m_h = texture_h;
else if (label_h > -1) m_h = label_h;
}
// ---- can't make widget bigger than parent
if (m_h > (int)parent_h)
{
float ratio = (float)parent_h / m_h;
m_w = (int)(m_w*ratio);
m_h = (int)(m_h*ratio);
}
if (m_w > (int)parent_w)
{
// scale down while keeping aspect ratio (don't do this for text widgets though...)
float ratio = (float)parent_w/m_w;
m_w = (int)(m_w*ratio);
if (m_type != WTYPE_LABEL) m_h = (int)(m_h*ratio);
}
// ------ check for given max size
if (m_properties[PROP_MAX_WIDTH].size() > 0)
{
const int max_width = atoi( m_properties[PROP_MAX_WIDTH].c_str() );
if (m_w > max_width) m_w = max_width;
}
if (m_properties[PROP_MAX_HEIGHT].size() > 0)
{
const int max_height = atoi( m_properties[PROP_MAX_HEIGHT].c_str() );
if (m_h > max_height) m_h = max_height;
}
}
// -----------------------------------------------------------------------------
void Widget::setParent(IGUIElement* parent)

View File

@ -115,6 +115,7 @@ namespace GUIEngine
protected:
unsigned int m_magic_number;
// FIXME: find better ways than hackish "friend"?
friend class EventHandler;
friend class Screen;
friend class Skin;
@ -122,6 +123,7 @@ namespace GUIEngine
friend class SpinnerWidget;
friend class ProgressBarWidget;
friend class DynamicRibbonWidget;
friend class LayoutManager;
/** When true, this widget shall use a bigger and more colourful font */
bool m_title_font;
@ -167,28 +169,11 @@ namespace GUIEngine
/** override in children if you need to know when the widget is unfocused. */
virtual void unfocused(const int playerID) { }
/**
* The XML loader stored coords in their raw string form inside this widget.
* This method parses the strings. Most notably, expands coords relative to parent
* and calculates percentages.
*/
void readCoords(Widget* parent=NULL);
/**
* An irrlicht parent (most often used to put widgets in dialogs)
*/
irr::gui::IGUIElement* m_parent;
/**
* Receives as string the raw property value retrieved from XML file.
* Will try to make sense of it, as an absolute value or a percentage.
*
* Return values :
* Will write to either absolute or percentage, depending on the case.
* Returns false if couldn't convert to either
*/
static bool convertToCoord(std::string& x, int* absolute, int* percentage);
/**
* IrrLicht widget created to represent this object.
*/

View File

@ -21,6 +21,7 @@
#include "graphics/irr_driver.hpp"
#include "guiengine/engine.hpp"
#include "guiengine/layout_manager.hpp"
#include "guiengine/scalable_font.hpp"
#include "guiengine/widgets/button_widget.hpp"
#include "input/input_manager.hpp"
@ -58,7 +59,9 @@ RibbonWidget::RibbonWidget(const RibbonType type) : Widget(WTYPE_RIBBON)
updateSelection();
}
// -----------------------------------------------------------------------------
void RibbonWidget::add()
{
m_labels.clearWithoutDeleting();
@ -77,11 +80,13 @@ void RibbonWidget::add()
int total_needed_space = 0;
for (int i=0; i<subbuttons_amount; i++)
{
m_children[i].readCoords(this);
// FIXME: a little unclean to invoke layout code here?
LayoutManager::readCoords(m_children.get(i), 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;
std::cerr << "/!\\ Warning /!\\ : ribbon widgets can only have (icon)button widgets as children "
<< std::endl;
continue;
}

View File

@ -239,6 +239,7 @@
9556A881119EF976009C558F /* options_screen_video.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9556A87E119EF976009C558F /* options_screen_video.cpp */; };
955DE88310042701006A4F3C /* check_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 955DE88110042701006A4F3C /* check_manager.cpp */; };
955DE88C1004273B006A4F3C /* check_structure.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 955DE8871004273B006A4F3C /* check_structure.cpp */; };
9560368C12187EFB00EB96C4 /* layout_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9560368A12187EFB00EB96C4 /* layout_manager.cpp */; };
95634EF21126272C009C145D /* gp_info_dialog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 95634EF01126272C009C145D /* gp_info_dialog.cpp */; };
956541BB10DD5F0A00C83E99 /* arenas_screen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 956541B910DD5F0A00C83E99 /* arenas_screen.cpp */; };
956541E110DD628C00C83E99 /* add_device_dialog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 956541DF10DD628C00C83E99 /* add_device_dialog.cpp */; };
@ -448,6 +449,8 @@
955DE88210042701006A4F3C /* check_manager.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = check_manager.hpp; path = ../../tracks/check_manager.hpp; sourceTree = SOURCE_ROOT; };
955DE8871004273B006A4F3C /* check_structure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = check_structure.cpp; path = ../../tracks/check_structure.cpp; sourceTree = SOURCE_ROOT; };
955DE8881004273B006A4F3C /* check_structure.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = check_structure.hpp; path = ../../tracks/check_structure.hpp; sourceTree = SOURCE_ROOT; };
9560368A12187EFB00EB96C4 /* layout_manager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = layout_manager.cpp; path = ../../guiengine/layout_manager.cpp; sourceTree = SOURCE_ROOT; };
9560368B12187EFB00EB96C4 /* layout_manager.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = layout_manager.hpp; path = ../../guiengine/layout_manager.hpp; sourceTree = SOURCE_ROOT; };
95634EF01126272C009C145D /* gp_info_dialog.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = gp_info_dialog.cpp; path = ../../states_screens/dialogs/gp_info_dialog.cpp; sourceTree = SOURCE_ROOT; };
95634EF11126272C009C145D /* gp_info_dialog.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = gp_info_dialog.hpp; path = ../../states_screens/dialogs/gp_info_dialog.hpp; sourceTree = SOURCE_ROOT; };
956541B910DD5F0A00C83E99 /* arenas_screen.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = arenas_screen.cpp; path = ../../states_screens/arenas_screen.cpp; sourceTree = SOURCE_ROOT; };
@ -1288,6 +1291,8 @@
958330B310122B4A00C5137E /* engine.hpp */,
958330B410122B4A00C5137E /* event_handler.cpp */,
958330B510122B4A00C5137E /* event_handler.hpp */,
9560368A12187EFB00EB96C4 /* layout_manager.cpp */,
9560368B12187EFB00EB96C4 /* layout_manager.hpp */,
958330B610122B4A00C5137E /* modaldialog.cpp */,
958330B710122B4A00C5137E /* modaldialog.hpp */,
953F8B1F11F7C13C00205E66 /* scalable_font.cpp */,
@ -2626,6 +2631,7 @@
9545ABCA11E3E38300D3C37A /* progress_bar_widget.cpp in Sources */,
9554C4A611F1188000906416 /* race_result_gui.cpp in Sources */,
953F8B2111F7C13C00205E66 /* scalable_font.cpp in Sources */,
9560368C12187EFB00EB96C4 /* layout_manager.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -83,7 +83,9 @@ class FeatureUnlockedCutScene : public GUIEngine::Screen, public GUIEngine::Scre
/** The scene node for the light. */
irr::scene::ILightSceneNode* m_light;
#define USE_IRRLICHT_BUG_WORKAROUND
//#define USE_IRRLICHT_BUG_WORKAROUND
#ifdef USE_IRRLICHT_BUG_WORKAROUND
scene::IMeshSceneNode *m_avoid_irrlicht_bug;
#endif