/*************************************************************************** * Copyright (C) 2004 by Christoph Freundl * * Christoph.Freundl@informatik.uni-erlangen.de * * * * 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 2 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 "layout.h" #include "widget.h" #ifdef GUI_DEBUG #include #endif namespace SDLwidgets { void VerticalLayout::add( Widget* widget ) { _contained_widgets.push_back( widget ); // arrangeAll(); _managed_widget->doLayout(); } void VerticalLayout::remove( Widget* widget ) { for ( std::vector::iterator it = _contained_widgets.begin(); it != _contained_widgets.end(); it++ ) { if ( *it == widget ) { _contained_widgets.erase( it ); std::map::iterator iter = _widget_stretch.find( widget ); if ( iter != _widget_stretch.end() ) { _widget_stretch.erase( iter ); } // arrangeAll(); _managed_widget->doLayout(); break; } } } void VerticalLayout::arrangeAll() { // initial layout of the widgets: // - put widgets in vertical order // - sum up the widget heights plus all spacings in _height // - the overall width _width is determined by the widest widget int current_height = _border_spacing; _width = 0; _height = _border_spacing; for ( std::vector::iterator it = _contained_widgets.begin(); it != _contained_widgets.end(); it++ ) { Widget* widget = *it; widget->setPosition( _border_spacing, current_height ); widget->setHeight( widget->getMinHeight() ); current_height += widget->getHeight() + _spacing; _height += widget->getHeight() + _spacing; if ( widget->getWidth() > _width ) { _width = widget->getWidth(); } } // finally compute overall width and height _width += 2 * _border_spacing; _height += _border_spacing - _spacing; if ( _width < _managed_widget->getMinWidth() ) _width = _managed_widget->getMinWidth(); // stretch widgets horizontally to container width // if horizontal stretch is FILL for ( std::vector::iterator it = _contained_widgets.begin(); it != _contained_widgets.end(); it++ ) { Widget* widget = *it; if ( widget->getWidth() < _width - 2 * _border_spacing && widget->getHorizontalStretch() == FILL ) widget->setWidth( _width - 2 * _border_spacing ); } // distribute remaining vertical space to all widgets with the // stretch attribute FILL if ( _managed_widget->getMinHeight() > _height ) { int remaining_space = _managed_widget->getMinHeight() - _height - _border_spacing; int additional_offset = 0; int number_fill = 0; std::map::iterator iter; for ( iter = _widget_stretch.begin(); iter != _widget_stretch.end(); iter++ ) { if ( iter->second == FILL ) number_fill++; } #ifdef GUI_DEBUG std::cout << "Remaining space is " << remaining_space << std::endl; std::cout << "Number of FILL widgets is " << number_fill << std::endl; #endif std::vector::iterator iter2; for ( iter2 = _contained_widgets.begin(); iter2 != _contained_widgets.end(); iter2++ ) { Widget* widget = *iter2; Sint16 x, y; widget->getPosition( x, y ); #ifdef GUI_DEBUG std::cout << "Moving by additional offset of " << additional_offset << std::endl; #endif widget->setPosition( x, y + additional_offset ); iter = _widget_stretch.find( widget ); if ( iter != _widget_stretch.end() && iter->second == FILL ) { int additional_space = remaining_space / number_fill--; #ifdef GUI_DEBUG std::cout << "Adding additional space of " << additional_space << std::endl; #endif widget->setHeight( widget->getHeight() + additional_space ); remaining_space -= additional_space; additional_offset += additional_space; _height += additional_space; } } } } void HorizontalLayout::add( Widget* widget ) { _contained_widgets.push_back( widget ); // arrangeAll(); _managed_widget->doLayout(); } void HorizontalLayout::remove( Widget* widget ) { for ( std::vector::iterator it = _contained_widgets.begin(); it != _contained_widgets.end(); it++ ) { if ( *it == widget ) { _contained_widgets.erase( it ); std::map::iterator iter = _widget_stretch.find( widget ); if ( iter != _widget_stretch.end() ) { _widget_stretch.erase( iter ); } // arrangeAll(); _managed_widget->doLayout(); break; } } } void HorizontalLayout::arrangeAll() { int current_width = 0; _width = 0; _height = 0; for ( std::vector::iterator it = _contained_widgets.begin(); it != _contained_widgets.end(); it++ ) { Widget* widget = *it; widget->setPosition( current_width, 0 ); widget->setWidth( widget->getMinWidth() ); current_width += widget->getWidth() + _spacing; _width += widget->getWidth() + _spacing; if ( widget->getHeight() > _height ) { _height = widget->getHeight(); } } _width -= _spacing; if ( _managed_widget->getMinWidth() > _width ) { int remaining_space = _managed_widget->getMinWidth() - _width; int additional_offset = 0; int number_fill = 0; std::map::iterator iter; for ( iter = _widget_stretch.begin(); iter != _widget_stretch.end(); iter++ ) { if ( iter->second == FILL ) number_fill++; } #ifdef GUI_DEBUG std::cout << "Remaining space is " << remaining_space << std::endl; std::cout << "Number of FILL widgets is " << number_fill << std::endl; #endif std::vector::iterator iter2; for ( iter2 = _contained_widgets.begin(); iter2 != _contained_widgets.end(); iter2++ ) { Widget* widget = *iter2; Sint16 x, y; widget->getPosition( x, y ); #ifdef GUI_DEBUG std::cout << "Moving by additional offset of " << additional_offset << std::endl; #endif widget->setPosition( x + additional_offset, y ); iter = _widget_stretch.find( widget ); if ( iter != _widget_stretch.end() && iter->second == FILL ) { int additional_space = remaining_space / number_fill--; #ifdef GUI_DEBUG std::cout << "Adding additional space of " << additional_space << std::endl; #endif widget->setWidth( widget->getWidth() + additional_space ); remaining_space -= additional_space; additional_offset += additional_space; _width += additional_space; } } } } void HorizontalLayout::arrangeToWidth( const Uint16 width ) { arrangeAll(); if ( width > _width ) { Uint16 space_left = width - _width; Uint16 widgets_left = _contained_widgets.size(); Uint16 pos_x = 0; for ( std::vector::iterator it = _contained_widgets.begin(); it != _contained_widgets.end(); it++ ) { Widget* widget = *it; Uint16 additional_space = space_left / widgets_left; widget->setMinWidth( widget->getWidth() + additional_space ); widget->setPosition( pos_x, 0 ); space_left -= additional_space; pos_x += widget->getWidth() + _spacing; widgets_left--; } _width = width; } } void FreeLayout::add( Widget* widget ) { _contained_widgets.push_back( widget ); Sint16 pos_x, pos_y; widget->getPosition( pos_x, pos_y ); if ( pos_x + widget->getWidth() > _width ) { _width = pos_x + widget->getWidth(); } if ( pos_y + widget->getHeight() > _height ) { _height = pos_x + widget->getHeight(); } _managed_widget->doLayout(); } void FreeLayout::remove( Widget* widget ) { for ( std::vector::iterator it = _contained_widgets.begin(); it != _contained_widgets.end(); it++ ) { if ( *it == widget ) { _contained_widgets.erase( it ); computeExtent(); _managed_widget->doLayout(); break; } } } void FreeLayout::computeExtent() { _width = 0; _height = 0; for ( std::vector::iterator it = _contained_widgets.begin(); it != _contained_widgets.end(); it++ ) { Widget* widget = *it; Sint16 pos_x, pos_y; widget->getPosition( pos_x, pos_y ); if ( pos_x + widget->getWidth() > _width ) { _width = pos_x + widget->getWidth(); } if ( pos_y + widget->getHeight() > _height ) { _height = pos_x + widget->getHeight(); } } } void TableLayout::add( Widget* widget ) { _contained_widgets.push_back( widget ); // arrangeAll(); _managed_widget->doLayout(); } void TableLayout::remove( Widget* widget ) { for ( std::vector::iterator it = _contained_widgets.begin(); it != _contained_widgets.end(); it++ ) { if ( *it == widget ) { _contained_widgets.erase( it ); // arrangeAll(); _managed_widget->doLayout(); break; } } } void TableLayout::arrangeAll() { // erase column widths and row heights _column_widths.assign( _number_columns, 0 ); _row_heights.clear(); // compute row heights and column widths int _column_index = 0; for ( std::vector::iterator it = _contained_widgets.begin(); it != _contained_widgets.end(); it++ ) { // set height to zero for a new row if ( _column_index == 0 ) { _row_heights.push_back( 0 ); } Uint16& current_height = _row_heights.back(); Widget* widget = *it; if ( widget->getHeight() > current_height ) { current_height = widget->getHeight(); } if ( widget->getWidth() > _column_widths[_column_index] ) { _column_widths[_column_index] = widget->getWidth(); } _column_index = ( _column_index + 1 ) % _number_columns; } // compute width and height _width = 0; for ( unsigned int i = 0; i < _number_columns; i++ ) { _width += _column_widths[i]; } _width += ( _number_columns - 1 ) * _horizontal_spacing; _height = 0; for ( unsigned int i = 0; i < _row_heights.size(); i++ ) { _height += _row_heights[i]; } _height += ( _row_heights.size() - 1 ) * _vertical_spacing; // stretch columns if necessary if ( _width < _managed_widget->getMinWidth() ) { int number_fill = 0; for ( unsigned int i = 0; i < _number_columns; i++ ) { if ( _column_stretch[i] == FILL ) number_fill++; } Uint16 remaining_space = _managed_widget->getMinWidth() - _width; for ( unsigned int i = 0; i < _number_columns; i++ ) { if ( _column_stretch[i] == FILL ) { Uint16 additional_space = remaining_space / number_fill;; _column_widths[i] += additional_space; _width += additional_space; remaining_space -= additional_space; number_fill--; } } } // arrange widgets _column_index = 0; int _row_index = 0; Uint16 x = 0, y = 0; for ( std::vector::iterator it = _contained_widgets.begin(); it != _contained_widgets.end(); it++ ) { // set height to zero for a new row if ( _column_index == 0 ) { x = 0; } Widget* widget = *it; widget->setPosition( x, y ); if ( _column_stretch[_column_index] == FILL ) widget->setWidth( _column_widths[_column_index] ); x += _column_widths[_column_index] + _horizontal_spacing; _column_index = ( _column_index + 1 ) % _number_columns; if ( _column_index == 0 ) { y += _row_heights[_row_index++] + _vertical_spacing; } } } }