void grid::request_reduce_height(const unsigned maximum_height) { point size = get_best_size(); if(size.y <= static_cast<int>(maximum_height)) { /** @todo this point shouldn't be reached, find out why it does. */ return; } const unsigned too_high = size.y - maximum_height; unsigned reduced = 0; for(size_t row = 0; row < rows_; ++row) { unsigned wanted_height = row_height_[row] - (too_high - reduced); /** * @todo Improve this code. * * Now we try every item to be reduced, maybe items need a flag whether * or not to try to reduce and also evaluate whether the force * reduction is still needed. */ if(too_high - reduced >= row_height_[row]) { DBG_GUI_L << LOG_HEADER << " row " << row << " height " << row_height_[row] << " want to reduce " << too_high << " is too small to be reduced fully try 1 pixel.\n"; wanted_height = 1; } /* Reducing the height of a widget causes the widget to save its new size in widget::layout_size_. After that, get_best_size() will return that size and not the originally calculated optimal size. Thus, it's perfectly correct that grid::calculate_best_size() that we call later calls get_best_size() for child widgets as if size reduction had never happened. */ const unsigned height = grid_implementation::row_request_reduce_height( *this, row, wanted_height); if(height < row_height_[row]) { unsigned reduction = row_height_[row] - height; DBG_GUI_L << LOG_HEADER << " row " << row << " height " << row_height_[row] << " want to reduce " << too_high << " reduced " << reduction << " pixels.\n"; size.y -= reduction; reduced += reduction; } if(size.y <= static_cast<int>(maximum_height)) { break; } } size = calculate_best_size(); DBG_GUI_L << LOG_HEADER << " Requested maximum " << maximum_height << " resulting height " << size.y << ".\n"; set_layout_size(size); }
void tgrid::request_reduce_height(const unsigned maximum_height) { tpoint size = get_best_size(); if(size.y <= static_cast<int>(maximum_height)) { /** @todo this point shouldn't be reached, find out why it does. */ return; } const unsigned too_high = size.y - maximum_height; unsigned reduced = 0; for(size_t row = 0; row < rows_; ++row) { unsigned wanted_height = row_height_[row] - (too_high - reduced); /** * @todo Improve this code. * * Now we try every item to be reduced, maybe items need a flag whether * or not to try to reduce and also evaluate whether the force * reduction is still needed. */ if(too_high - reduced >= row_height_[row]) { DBG_GUI_L << LOG_HEADER << " row " << row << " height " << row_height_[row] << " want to reduce " << too_high << " is too small to be reduced fully try 1 pixel.\n"; wanted_height = 1; } const unsigned height = tgrid_implementation::row_request_reduce_height( *this, row, wanted_height); if(height < row_height_[row]) { DBG_GUI_L << LOG_HEADER << " row " << row << " height " << row_height_[row] << " want to reduce " << too_high << " reduced " << row_height_[row] - height << " pixels.\n"; size.y -= row_height_[row] - height; row_height_[row] = height; } if(size.y <= static_cast<int>(maximum_height)) { break; } } size = calculate_best_size(); DBG_GUI_L << LOG_HEADER << " Requested maximum " << maximum_height << " resulting height " << size.y << ".\n"; set_layout_size(size); }
tpoint twidget::get_best_size() const { if (is_empty_rect(fix_rect_)) { tpoint result = layout_size_; if (result == tpoint(0, 0)) { result = calculate_best_size(); } return result; } else { return tpoint(fix_rect_.w, fix_rect_.h); } }
tpoint twidget::get_best_size() const { assert(visible_ != INVISIBLE); tpoint result = layout_size_; if(result == tpoint(0, 0)) { result = calculate_best_size(); } #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS last_best_size_ = result; #endif return result; }
void grid::request_placement(dispatcher&, const event::ui_event, bool& handled, bool&) { if (get_window()->invalidate_layout_blocked()) { handled = true; return; } point size = get_size(); point best_size = calculate_best_size(); if(size.x >= best_size.x && size.y >= best_size.y) { place(get_origin(), size); handled = true; return; } recalculate_best_size(); if(size.y >= best_size.y) { // We have enough space in the Y direction, but not in the X direction. // Try wrapping the content. request_reduce_width(size.x); best_size = get_best_size(); if(size.x >= best_size.x && size.y >= best_size.y) { // Wrapping succeeded, we still fit vertically. place(get_origin(), size); handled = true; return; } else { // Wrapping failed, we no longer fit. // Reset the sizes of child widgets. layout_initialize(true); } } /* Not enough space. Let the event flow higher up. This is a pre-event handler, so the event flows upwards. */ }
point widget::get_best_size() const { assert(visible_ != visibility::invisible); point result = layout_size_; if(result == point()) { result = calculate_best_size(); //Adjust to linked widget size if linked widget size was already calculated. if(!get_window()->get_need_layout() && !linked_group_.empty()) { point linked_size = get_window()->get_linked_size(linked_group_); result.x = std::max(result.x, linked_size.x); result.y = std::max(result.y, linked_size.y); } } #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS last_best_size_ = result; #endif return result; }
void grid::request_reduce_width(const unsigned maximum_width) { point size = get_best_size(); if(size.x <= static_cast<int>(maximum_width)) { /** @todo this point shouldn't be reached, find out why it does. */ return; } const unsigned too_wide = size.x - maximum_width; unsigned reduced = 0; for(size_t col = 0; col < cols_; ++col) { if(too_wide - reduced >= col_width_[col]) { DBG_GUI_L << LOG_HEADER << " column " << col << " is too small to be reduced.\n"; continue; } const unsigned wanted_width = col_width_[col] - (too_wide - reduced); const unsigned width = grid_implementation::column_request_reduce_width( *this, col, wanted_width); if(width < col_width_[col]) { unsigned reduction = col_width_[col] - width; DBG_GUI_L << LOG_HEADER << " reduced " << reduction << " pixels for column " << col << ".\n"; size.x -= reduction; reduced += reduction; } if(size.x <= static_cast<int>(maximum_width)) { break; } } set_layout_size(calculate_best_size()); }
void tgrid::place(const tpoint& origin, const tpoint& size) { log_scope2(log_gui_layout, LOG_SCOPE_HEADER); /***** INIT *****/ twidget::place(origin, size); if(!rows_ || !cols_) { return; } // call the calculate so the size cache gets updated. const tpoint best_size = calculate_best_size(); assert(row_height_.size() == rows_); assert(col_width_.size() == cols_); assert(row_grow_factor_.size() == rows_); assert(col_grow_factor_.size() == cols_); DBG_GUI_L << LOG_HEADER << " best size " << best_size << " available size " << size << ".\n"; /***** BEST_SIZE *****/ if(best_size == size) { layout(origin); return; } if(best_size.x > size.x || best_size.y > size.y) { // The assertion below fails quite often so try to give as much information as possible. std::stringstream out; out << " Failed to place a grid, we have " << size << " space but we need " << best_size << " space."; out << " This happened at a grid with the id '" << id() << "'"; twidget* pw = parent(); while(pw != nullptr) { out << " in a '" << typeid(*pw).name() << "' with the id '" << pw->id() << "'"; pw = pw->parent(); } ERR_GUI_L << LOG_HEADER << out.str() << ".\n"; return; } /***** GROW *****/ // expand it. if(size.x > best_size.x) { const unsigned w = size.x - best_size.x; unsigned w_size = std::accumulate( col_grow_factor_.begin(), col_grow_factor_.end(), 0); DBG_GUI_L << LOG_HEADER << " extra width " << w << " will be divided amount " << w_size << " units in " << cols_ << " columns.\n"; if(w_size == 0) { // If all sizes are 0 reset them to 1 for(auto & val : col_grow_factor_) { val = 1; } w_size = cols_; } // We might have a bit 'extra' if the division doesn't fix exactly // but we ignore that part for now. const unsigned w_normal = w / w_size; for(unsigned i = 0; i < cols_; ++i) { col_width_[i] += w_normal * col_grow_factor_[i]; DBG_GUI_L << LOG_HEADER << " column " << i << " with grow factor " << col_grow_factor_[i] << " set width to " << col_width_[i] << ".\n"; } } if(size.y > best_size.y) { const unsigned h = size.y - best_size.y; unsigned h_size = std::accumulate( row_grow_factor_.begin(), row_grow_factor_.end(), 0); DBG_GUI_L << LOG_HEADER << " extra height " << h << " will be divided amount " << h_size << " units in " << rows_ << " rows.\n"; if(h_size == 0) { // If all sizes are 0 reset them to 1 for(auto & val : row_grow_factor_) { val = 1; } h_size = rows_; } // We might have a bit 'extra' if the division doesn't fix exactly // but we ignore that part for now. const unsigned h_normal = h / h_size; for(unsigned i = 0; i < rows_; ++i) { row_height_[i] += h_normal * row_grow_factor_[i]; DBG_GUI_L << LOG_HEADER << " row " << i << " with grow factor " << row_grow_factor_[i] << " set height to " << row_height_[i] << ".\n"; } } layout(origin); return; }
tpoint tgrid::recalculate_best_size() { tpoint best_size = calculate_best_size(); set_layout_size(best_size); return best_size; }