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:
parent
e034082a2b
commit
b1f7012cbd
@ -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 \
|
||||
|
@ -233,5 +233,3 @@ void AbstractStateManager::resetAndSetStack(Screen* screens[])
|
||||
onTopMostScreenChanged();
|
||||
} // resetAndSetStack
|
||||
|
||||
|
||||
|
380
src/guiengine/layout_manager.cpp
Normal file
380
src/guiengine/layout_manager.cpp
Normal 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
|
||||
|
59
src/guiengine/layout_manager.hpp
Normal file
59
src/guiengine/layout_manager.hpp
Normal 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
|
@ -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
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user