Lumiera 0.pre.04~rc.1
»edit your freedom«
Loading...
Searching...
No Matches
element-box-widget.cpp
Go to the documentation of this file.
1/*
2 ElementBoxWidget - fundamental UI building block to represent a placed element
3
4 Copyright (C)
5 2016, Hermann Vosseler <Ichthyostega@web.de>
6
7  **Lumiera** is free software; you can redistribute it and/or modify it
8  under the terms of the GNU General Public License as published by the
9  Free Software Foundation; either version 2 of the License, or (at your
10  option) any later version. See the file COPYING for further details.
11
12* *****************************************************************/
13
14
44#include "stage/gtk-base.hpp"
47
48#include "lib/util.hpp"
49
50
51
52namespace stage {
53namespace widget {
54
55
56 namespace {//Implementation helpers...
69 inline void
70 queryNaturalSize (Gtk::Widget const& widget, Gtk::Requisition& natSize)
71 {
72 Gtk::Requisition minDummy;
73 widget.get_preferred_size (minDummy, natSize);
74 }
75
76 inline int
77 queryNaturalHeight (Gtk::Widget const& widget)
78 {
79 int minDummy{0}, natHeight{0};
80 widget.get_preferred_height(minDummy, natHeight);
81 return natHeight;
82 }
83
84 inline int
85 queryNaturalWidth (Gtk::Widget const& widget)
86 {
87 int minDummy{0}, natWidth{0};
88 widget.get_preferred_width(minDummy, natWidth);
89 return natWidth;
90 }
91
93 Gtk::Requisition ICON_SIZ{};
94
98 const double HYSTERESIS = 1.6;
99
100 inline void
101 initIconSizeHeuristic (Gtk::Widget const& icon)
102 {
103 if (ICON_SIZ.width > 0) return;
105 }
106
107 }//(End)helpers
108
109
110
111
114
115
116 Literal
122
123 Literal
129
130 Gtk::IconSize
132 {
134 return Gtk::ICON_SIZE_MENU;
135 }
136
137
140 {
141 Strategy strategy;
142 if (widthConstraint_)
143 strategy.getWidth = move(widthConstraint_);
144 if (heightConstraint_)
145 strategy.getHeight = move(heightConstraint_);
146 return strategy;
147 }
148
149
150 IDLabel::IDLabel (Literal iconID, Literal menuSymb, Gtk::IconSize siz)
151 : Gtk::Box{Gtk::ORIENTATION_HORIZONTAL}
152 , imgIcon_{Gtk::StockID{iconID}, siz}
153 , imgMenu_{Gtk::StockID{menuSymb}, siz}
154 {
155 icon_.set_image(imgIcon_);
156 menu_.set_image(imgMenu_);
157 this->add(icon_);
158 this->add(menu_);
159 this->add(name_);
160 this->set_name(ID_idlabel);
161 this->get_style_context()->add_class(CLASS_background);
162 this->get_style_context()->add_class(CLASS_idlabel);
163 icon_.get_style_context()->add_class(CLASS_idlabel_icon);
164 menu_.get_style_context()->add_class(CLASS_idlabel_menu);
165 name_.get_style_context()->add_class(CLASS_idlabel_name);
166 name_.set_hexpand(true);
167
168 this->show_all();
169 initIconSizeHeuristic (icon_);
170 }
171
172
173 void
175 {
176 name_.set_text(idCaption);
177 // can not retrieve size information from hidden widgets...
178 this->show_all(); // Note: size constraint handling will trigger again
179 // cache required full display size (for size constrained layout)
180 queryNaturalSize (*this, labelFullSize_);
181 }
182
185 {
186 return name_.get_text();
187 }
188
189
190
192 : EventBox{}
193 , strategy_{config.buildLayoutStrategy(*this)}
194 , label_{config.getIconID()
195 ,config.getMenuSymb()
196 ,config.getIconSize()}
197 , frame_{}
198 {
199 set_name (ID_element);
200 get_style_context()->add_class (CLASS_background); // Style to ensure an opaque backdrop
201 get_style_context()->add_class (CLASS_elementbox);
202 label_.get_style_context()->add_class (CLASS_elementbox_idlabel);
203
204 frame_.set_label_align (0.0, 0.0);
205 frame_.set_label_widget(label_);
206 this->add (frame_);
207
208 this->show_all();
209 label_.setCaption (config.getName());
210 }
211
212
213 void
215 {
216 label_.setCaption (nameID);
217 }
218
221 {
222 return label_.getCaption();
223 }
224
231 Gtk::SizeRequestMode
233 {
234 return Gtk::SizeRequestMode::SIZE_REQUEST_HEIGHT_FOR_WIDTH;
235 }
236
259 void
260 ElementBoxWidget::get_preferred_width_vfunc (int& minimum_width, int& natural_width) const
261 {
263 minimum_width = natural_width = strategy_.getWidth();
264 else
265 _Base::get_preferred_width_vfunc (minimum_width,natural_width);
266 }
267
272 void
273 ElementBoxWidget::get_preferred_height_vfunc (int& minimum_height, int& natural_height) const
274 {
276 minimum_height = natural_height = strategy_.getHeight();
277 else
278 _Base::get_preferred_height_vfunc (minimum_height,natural_height);
279 }
280
281 void
282 ElementBoxWidget::get_preferred_height_for_width_vfunc (int width, int& minimum_height, int& natural_height) const
283 {
285 minimum_height = natural_height = strategy_.getHeight();
286 else
287 _Base::get_preferred_height_for_width_vfunc (width, minimum_height,natural_height);
288 }
289
301 void
302 ElementBoxWidget::on_size_allocate (Gtk::Allocation& availableSize)
303 {
305 imposeSizeConstraint (availableSize.get_width(), availableSize.get_height());
306 _Base::on_size_allocate(availableSize);
307 }
308
309
318 void
320 {
321 label_.imposeSizeConstraint (widthC, heightC);
322 }
323
330 void
331 IDLabel::imposeSizeConstraint (int widthC, int heightC)
332 {
333 // short circuit: need to perform precise checks?
334 if ( labelFullSize_.width > widthC
335 or labelFullSize_.height > heightC
336 )
337 this->adaptSize(widthC, heightC);
338 }
339
340
341 namespace {//IDLabel layout management internals....
342
346 inline int
347 reduce(Gtk::Button& icon)
348 {
349 int widthReduction{0};
350 if (icon.get_visible())
351 {
352 widthReduction = queryNaturalWidth (icon);
353 icon.hide();
354 }
355 return widthReduction;
356 }
357
359 inline int
360 reduce(Gtk::Label& label, int goal)
361 {
362 ASSERT (goal >=0);
363 int reduction{0};
364 if (label.get_visible())
365 {
366 int width = queryNaturalWidth (label);
370 if (reduction < goal)
371 {//shortening alone does not suffice
372 label.hide();
373 reduction = width;
374 }
375 }
376 return reduction;
377 }
378
386 template<class FUN>
387 inline bool
388 maybeShow(Gtk::Button& icon, int w, int h, FUN& reCheck)
389 {
390 if (icon.is_visible()) return true; // nothing can be done here
391 bool success{false};
392 if (w >= ICON_SIZ.width * HYSTERESIS and h >= ICON_SIZ.height)
393 {
394 icon.show();
395 if (not (success=reCheck()))
396 icon.hide();
397 }
398 return success;
399 }
400
401 template<class FUN>
402 inline bool
403 maybeShow(Gtk::Label& label, int w, int h, FUN& reCheck)
404 {
405 bool success{false};
406 // use icon dimensions as as heuristics to determine
407 // if attempting to show the label is worth trying...
408 if (w >= ICON_SIZ.width * HYSTERESIS and h >= ICON_SIZ.height)
409 {
410 label.show();
411 int width = queryNaturalWidth (label);
412 int goal = width - w;
413 if (goal > 0) // too large, yet might fit if shortened
414 reduce (label, goal);
415 if (not (success=reCheck()))
416 label.hide();
417 }
418 return success;
419 }
420
421
422 }//(End)Layout helpers
423
424
435 void
436 IDLabel::adaptSize (int widthC, int heightC)
437 {
438 // first determine if vertical extension is problematic
439 int currH = queryNaturalHeight (*this);
440 if (currH > heightC)
441 {//hide all child widgets,
442 // not much options left...
443 name_.hide();
444 menu_.hide();
445 icon_.hide();
446 return;
447 }
448
449 // now test if we need to reduce or can expand
450 int currW = queryNaturalWidth (*this);
451 if (currW > widthC)
452 {//reduce to comply
453 int goal = currW - widthC;
454 ASSERT (goal > 0);
455 if ((goal -= reduce(name_, goal)) <= 0) return;
456 if ((goal -= reduce(menu_) ) <= 0) return;
457 if ((goal -= reduce(icon_) ) <= 0) return;
458 currW = queryNaturalWidth(*this);
459 goal = currW - widthC;
460 ENSURE (goal <= 0, "IDLabel layout management floundered. "
461 "Removed all content, yet remaining width %d > %d"
462 , currW, widthC);
463 }
464 else
465 {//maybe some headroom left to show more?
466 int headroom = widthC - currW;
467 auto reCheck = [&]() -> bool
468 {// WARNING: side effect assignment
469 currW = queryNaturalWidth (*this);
470 currH = queryNaturalHeight(*this);
471 headroom = widthC - currW;
472 return currH <= heightC
473 and currW <= widthC;
474 };
475
476 if (not maybeShow (icon_, headroom, heightC, reCheck)) return;
477 if (not maybeShow (menu_, headroom, heightC, reCheck)) return;
478 if (not maybeShow (name_, headroom, heightC, reCheck)) return;
479 }
480 }
481
482
483
484}}// namespace stage::widget
Inline string literal.
Definition symbol.hpp:78
Strategy buildLayoutStrategy(ElementBoxWidget &)
decide upon the presentation strategy
A basic building block of the Lumiera UI.
void get_preferred_height_for_width_vfunc(int, int &, int &) const override
void get_preferred_width_vfunc(int &, int &) const override
Layout preferences are delegated through the Strategy.
void on_size_allocate(Gtk::Allocation &) override
Tap into the notification of screen space allocation to possibly enforce size constraints.
ElementBoxWidget(Kind kind, Type type, QS ...qualifiers)
setup an ElementBoxWidget with suitable presentation style.
void imposeSizeConstraint(int, int)
Ensure the child widgets can be represented and possibly adjust or hide content, in case the extensio...
Strategy strategy_
actual layout strategy binding for this widget
Gtk::SizeRequestMode get_request_mode_vfunc() const final
Layout trend for ElementBoxWidget is nailed down (final) to "height-for-width".
void get_preferred_height_vfunc(int &, int &) const override
IDLabel(Literal iconID, Literal menuSymb, Gtk::IconSize)
void adaptSize(int, int)
Multi-step procedure to keep this IDLabel widget within the given screen size constraints.
void imposeSizeConstraint(int, int)
Ensure the IDLabel stays within a given size constraint.
Widget to render an ID label with associated icon.
A set of basic GTK includes for the UI.
Gtk::Requisition ICON_SIZ
point of reference for layout computations
const double HYSTERESIS
excess factor used to prevent "layout flickering"
void queryNaturalSize(Gtk::Widget const &widget, Gtk::Requisition &natSize)
Helper to retrieve what GTK effectively uses as minimal extension of a widget.
int reduce(Gtk::Button &icon)
attempt to reduce space consumption
bool maybeShow(Gtk::Button &icon, int w, int h, FUN &reCheck)
attempt to use available space to show more content
Lumiera GTK UI implementation root.
Definition guifacade.cpp:37
cuString CLASS_idlabel
cuString CLASS_idlabel_menu
cuString ID_idlabel
Literal ICON_arrow_hand_menu
cuString CLASS_background
opaque backdrop
const uString cuString
Definition gtk-base.hpp:93
Literal ICON_placement
cuString CLASS_elementbox
cuString CLASS_idlabel_name
cuString CLASS_elementbox_idlabel
only present on IDLabel widget within ElementBoxWidget
cuString CLASS_idlabel_icon
cuString ID_element
Definition of access keys for uniform UI styling.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...