Logo
  • Main Page
  • Related Pages
  • Modules
  • Classes
  • Files

mmshboxwidget.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2005-2007 Stefan Schwarzer, Jens Schneider,             *
00003  *                           Matthias Hardt, Guido Madaus                  *
00004  *                                                                         *
00005  *   Copyright (C) 2007-2008 BerLinux Solutions GbR                        *
00006  *                           Stefan Schwarzer & Guido Madaus               *
00007  *                                                                         *
00008  *   Copyright (C) 2009-2013 BerLinux Solutions GmbH                       *
00009  *                                                                         *
00010  *   Authors:                                                              *
00011  *      Stefan Schwarzer   <stefan.schwarzer@diskohq.org>,                 *
00012  *      Matthias Hardt     <matthias.hardt@diskohq.org>,                   *
00013  *      Jens Schneider     <jens.schneider@diskohq.org>,                   *
00014  *      Guido Madaus       <guido.madaus@diskohq.org>,                     *
00015  *      Patrick Helterhoff <patrick.helterhoff@diskohq.org>,               *
00016  *      René Bählkow       <rene.baehlkow@diskohq.org>                     *
00017  *                                                                         *
00018  *   This library is free software; you can redistribute it and/or         *
00019  *   modify it under the terms of the GNU Lesser General Public            *
00020  *   License version 2.1 as published by the Free Software Foundation.     *
00021  *                                                                         *
00022  *   This library is distributed in the hope that it will be useful,       *
00023  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00024  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00025  *   Lesser General Public License for more details.                       *
00026  *                                                                         *
00027  *   You should have received a copy of the GNU Lesser General Public      *
00028  *   License along with this library; if not, write to the                 *
00029  *   Free Software Foundation, Inc.,                                       *
00030  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA            *
00031  **************************************************************************/
00032 
00033 #include "mmsgui/mmshboxwidget.h"
00034 
00035 MMSHBoxWidget::MMSHBoxWidget(MMSWindow *root) : MMSWidget::MMSWidget() {
00036     create(root);
00037 }
00038 
00039 bool MMSHBoxWidget::create(MMSWindow *root) {
00040     this->type = MMSWIDGETTYPE_HBOX;
00041     return MMSWidget::create(root, false, true, false, false, true, true, false);
00042 }
00043 
00044 MMSWidget *MMSHBoxWidget::copyWidget() {
00045     // create widget
00046     MMSHBoxWidget *newWidget = new MMSHBoxWidget(this->rootwindow);
00047 
00048     // copy base widget
00049     MMSWidget::copyWidget((MMSWidget*)newWidget);
00050 
00051     return newWidget;
00052 }
00053 
00054 void MMSHBoxWidget::add(MMSWidget *widget) {
00055     widget->setParent(this);
00056     this->children.push_back(widget);
00057     if (this->getRootWindow())
00058         this->getRootWindow()->add(widget);
00059     this->recalculateChildren();
00060 }
00061 
00062 
00063 void MMSHBoxWidget::calcSize(int *num_spacers, int *last_spacer,
00064                              int *required_pix, int *remain_pix, int *avail_pix, int *fixed_pix, int *dyn_pix, int *min_dyn_pix,
00065                              float dyn_reduce_factor) {
00066     *num_spacers  = 0;
00067     *last_spacer  = -1;
00068     *required_pix = 0;
00069     *remain_pix   = 0;
00070     *avail_pix    = 0;
00071     *fixed_pix    = 0;
00072     *dyn_pix      = 0;
00073     *min_dyn_pix  = 0;
00074 
00075     // through all my children
00076     for(unsigned int i = 0; i < this->children.size(); i++) {
00077         int content_width;
00078         int content_height;
00079         if (!children.at(i)->getContentSize(&content_width, &content_height)) {
00080             // size of content not set, use sizehint
00081             string sizehint = children.at(i)->getSizeHint();
00082 
00083             if (sizehint == "") {
00084                 // have no sizehint
00085                 (*num_spacers)++;
00086                 *last_spacer = i;
00087             }
00088             else {
00089                 // calculate length based on sizehint
00090                 int len;
00091                 getPixelFromSizeHint(&len, sizehint, this->geom.w, this->geom.h);
00092                 (*fixed_pix)+= len;
00093             }
00094         }
00095         else
00096         if (dyn_reduce_factor < 0.0001) {
00097             // use fixed min size
00098             (*fixed_pix)+= children.at(i)->getMinWidthPix();
00099         }
00100         else {
00101             // use content width
00102             content_width = (int)((float)content_width * dyn_reduce_factor + 0.5);
00103             if (content_width <= children.at(i)->getMinWidthPix()) {
00104                 // use fixed min size
00105                 (*fixed_pix)+= children.at(i)->getMinWidthPix();
00106             }
00107             else {
00108                 // use dynamic width
00109                 (*dyn_pix)+= content_width;
00110                 (*min_dyn_pix)+= children.at(i)->getMinWidthPix();
00111             }
00112         }
00113     }
00114 
00115     // minimal size needed
00116     *required_pix = *fixed_pix + *dyn_pix;
00117 
00118     // remaining pixels
00119     *remain_pix = this->geom.w - *required_pix;
00120 
00121     // available pixels
00122     *avail_pix = this->geom.w - *fixed_pix;
00123 }
00124 
00125 
00126 void MMSHBoxWidget::recalculateChildren() {
00127 
00128     // check something
00129     if(this->children.empty())
00130         return;
00131 
00132     if(this->geomset == false)
00133         return;
00134 
00135     // first pass: check if content fits into box, start with factor 1.0
00136     int num_spacers, last_spacer;
00137     int required_pix, remain_pix, avail_pix, fixed_pix, dyn_pix, min_dyn_pix;
00138     float dyn_reduce_factor = 1.0f;
00139     while (1) {
00140         // calculate content size of box
00141         calcSize(&num_spacers, &last_spacer,
00142                  &required_pix, &remain_pix, &avail_pix, &fixed_pix, &dyn_pix, &min_dyn_pix,
00143                  dyn_reduce_factor);
00144 
00145         if (remain_pix >= 0) {
00146             // fine, all widgets can be put into this box
00147             break;
00148         }
00149 
00150         // negative remaining pixels, so try to reduce something
00151         if (avail_pix > min_dyn_pix) {
00152             // available pixels for dynamic widget, so calculate reduce factor and recalc content size
00153             dyn_reduce_factor = (float)((float)avail_pix) / ((float)dyn_pix / dyn_reduce_factor);
00154             continue;
00155         }
00156         else
00157         if (avail_pix == min_dyn_pix) {
00158             // there are no free pixels for dynamic widgets, so set reduce factor to zero and recalc content size
00159             dyn_reduce_factor = 0.0f;
00160             continue;
00161         }
00162         else {
00163             // fixed content of box does not fit into it
00164             if (!this->getName().empty())
00165                 printf("HBOX (%s): cannot calculate geometry (not enough free pixels)\n", this->getName().c_str());
00166             else
00167                 printf("HBOX: cannot calculate geometry (not enough free pixels)\n");
00168             return;
00169             //do not throw exception as this will left surface locks behind
00170             //throw MMSWidgetError(0,"HBOX: cannot calculate geometry (not enough free pixels)");
00171         }
00172     }
00173 
00174 
00175     // second pass: calculate geometry of all children
00176     int next_pos = this->geom.x;
00177     int safe_len = (num_spacers) ? remain_pix / num_spacers : 0;
00178     for (unsigned int i = 0; i < this->children.size(); i++) {
00179         MMSFBRectangle rect;
00180         int content_width, content_height;
00181 
00182         if (!children.at(i)->getContentSize(&content_width, &content_height)) {
00183             // size of content not set, use sizehint
00184             string sizehint = children.at(i)->getSizeHint();
00185 
00186             if (sizehint == "") {
00187                 // calculate width based on remaining space
00188                 rect.w = safe_len;
00189                 if (i == last_spacer)
00190                     rect.w+= remain_pix % num_spacers;
00191             }
00192             else {
00193                 // calculate width based on sizehint
00194                 getPixelFromSizeHint(&rect.w, sizehint, this->geom.w, this->geom.h);
00195             }
00196         }
00197         else {
00198             // use content width
00199             rect.w = (int)((float)content_width * dyn_reduce_factor + 0.5);
00200             if (rect.w < children.at(i)->getMinWidthPix())
00201                 rect.w = children.at(i)->getMinWidthPix();
00202         }
00203 
00204         // set geometry of child widget
00205         rect.x = next_pos;
00206         rect.y = this->geom.y;
00207         rect.h = this->geom.h;
00208         this->children.at(i)->setGeometry(rect);
00209 
00210         // next position
00211         next_pos+= rect.w;
00212     }
00213 }
00214 
00215 void MMSHBoxWidget::setContentSizeFromChildren() {
00216     if (!this->minmax_set) {
00217         return;
00218     }
00219 
00220     if (!this->parent)
00221         return;
00222 
00223     // determine width and height of my content
00224     int mycw = 0;
00225     int mych = getMinHeightPix();
00226     for (unsigned int i = 0; i < this->children.size(); i++) {
00227         int content_width, content_height;
00228 
00229         if (!children.at(i)->getContentSize(&content_width, &content_height)) {
00230             // size of content not set, use sizehint
00231             string sizehint = children.at(i)->getSizeHint();
00232 
00233             if (sizehint == "") {
00234                 // have no sizehint, we assume lowest width of 0
00235                 content_width = 0;
00236             }
00237             else {
00238                 // calculate width based on sizehint
00239                 getPixelFromSizeHint(&content_width, sizehint, this->geom.w, this->geom.h);
00240             }
00241         }
00242         else {
00243             // content size of child set, so we can set lowest height of my content
00244             if (mych < content_height)
00245                 mych = content_height;
00246         }
00247 
00248         mycw+= content_width;
00249     }
00250 
00251     if (mycw > 0 && mych > 0) {
00252         // width and height of my content set, check min/max ranges
00253         if (mycw < getMinWidthPix())
00254             mycw = getMinWidthPix();
00255         if (getMaxHeightPix() > 0 && mych > getMaxHeightPix())
00256             mych = getMaxHeightPix();
00257         if (getMaxWidthPix() > 0 && mycw > getMaxWidthPix())
00258             mycw = getMaxWidthPix();
00259 
00260         // set my size
00261         this->content_width_child = mycw;
00262         this->content_height_child = mych;
00263         this->parent->setContentSizeFromChildren();
00264     }
00265 }
00266 

Generated by doxygen