Fix build on systems that have a separate libintl library
[centerim5.git] / cppconsui / Widget.cpp
blobc1b3c22517990d64393c709fd799f78bca67404e
1 // Copyright (C) 2007 Mark Pustjens <pustjens@dds.nl>
2 // Copyright (C) 2010-2015 Petr Pavlu <setup@dagobah.cz>
3 //
4 // This file is part of CenterIM.
5 //
6 // CenterIM is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
11 // CenterIM is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with CenterIM. If not, see <http://www.gnu.org/licenses/>.
19 /// @file
20 /// Widget class implementation.
21 ///
22 /// @ingroup cppconsui
24 #include "Widget.h"
26 #include "ColorScheme.h"
27 #include "CoreManager.h"
29 #include <cassert>
30 #include <cstring>
32 namespace CppConsUI {
34 Widget::Widget(int w, int h)
35 : xpos_(UNSETPOS), ypos_(UNSETPOS), width_(w), height_(h),
36 wish_width_(AUTOSIZE), wish_height_(AUTOSIZE), real_xpos_(UNSETPOS),
37 real_ypos_(UNSETPOS), real_width_(0), real_height_(0), can_focus_(false),
38 has_focus_(false), visible_(true), parent_(nullptr), color_scheme_(0),
39 absolute_position_listeners_(0)
43 Widget::~Widget()
45 setVisibility(false);
47 if (parent_ != nullptr && absolute_position_listeners_.size() > 0)
48 parent_->unregisterAbsolutePositionListener(*this);
51 void Widget::moveResize(int newx, int newy, int neww, int newh)
53 if (newx == xpos_ && newy == ypos_ && neww == width_ && newh == height_)
54 return;
56 Rect oldsize(xpos_, ypos_, width_, height_);
57 Rect newsize(newx, newy, neww, newh);
59 xpos_ = newx;
60 ypos_ = newy;
61 width_ = neww;
62 height_ = newh;
64 signalMoveResize(oldsize, newsize);
67 Widget *Widget::getFocusWidget()
69 if (can_focus_)
70 return this;
71 return nullptr;
74 void Widget::cleanFocus()
76 if (!has_focus_)
77 return;
79 has_focus_ = false;
80 signal_focus(*this, false);
81 redraw();
84 bool Widget::restoreFocus()
86 return grabFocus();
89 void Widget::ungrabFocus()
91 if (parent_ == nullptr || !has_focus_)
92 return;
94 has_focus_ = false;
95 signal_focus(*this, false);
96 redraw();
99 bool Widget::grabFocus()
101 if (parent_ == nullptr || has_focus_)
102 return false;
104 if (can_focus_ && isVisibleRecursive()) {
105 if (parent_->setFocusChild(*this)) {
106 has_focus_ = true;
107 signal_focus(*this, true);
108 redraw();
110 return true;
113 return false;
116 void Widget::setVisibility(bool new_visible)
118 if (new_visible == visible_)
119 return;
121 visible_ = new_visible;
123 if (parent_ != nullptr) {
124 parent_->updateFocusChain();
126 Container *t = getTopContainer();
127 if (visible_) {
128 if (!t->getFocusWidget()) {
129 // There is no focused widget, try if this or a widget that was revealed
130 // can grab it.
131 t->moveFocus(Container::FOCUS_DOWN);
134 else {
135 Widget *focus = t->getFocusWidget();
136 if (focus && !focus->isVisibleRecursive()) {
137 // Focused widget was hidden, move the focus.
138 t->moveFocus(Container::FOCUS_DOWN);
142 signalVisible(visible_);
145 signal_visible(*this, visible_);
146 redraw();
149 bool Widget::isVisibleRecursive() const
151 if (parent_ == nullptr || !visible_)
152 return false;
154 return parent_->isWidgetVisible(*this);
157 void Widget::setParent(Container &new_parent)
159 // Changing parent widget is not supported.
160 assert(parent_ == nullptr);
162 parent_ = &new_parent;
164 // Register this widget as an absolute position listener to its parent in case
165 // some other widget is interested in a position of this widget.
166 if (absolute_position_listeners_.size() > 0)
167 parent_->registerAbsolutePositionListener(*this);
169 parent_->updateFocusChain();
171 Container *t = getTopContainer();
172 if (!t->getFocusWidget()) {
173 // There is no focused widget, try if this or a child widget (in case of
174 // Container) can grab it.
175 Widget *w = getFocusWidget();
176 if (w != nullptr)
177 w->grabFocus();
179 else {
180 // Clean focus if this widget/container was added to a container that
181 // already has a focused widget.
182 cleanFocus();
186 // All following moveResize() wrappers should always call member methods to get
187 // xpos_, ypos_, width_, height_ and never use member variables directly. See
188 // getLeft(), getTop(), getWidth(), getHeight() in the Window class.
189 void Widget::move(int newx, int newy)
191 moveResize(newx, newy, getWidth(), getHeight());
194 void Widget::resize(int neww, int newh)
196 moveResize(getLeft(), getTop(), neww, newh);
199 void Widget::setLeft(int newx)
201 moveResize(newx, getTop(), getWidth(), getHeight());
204 void Widget::setTop(int newy)
206 moveResize(getLeft(), newy, getWidth(), getHeight());
209 void Widget::setWidth(int neww)
211 moveResize(getLeft(), getTop(), neww, getHeight());
214 void Widget::setHeight(int newh)
216 moveResize(getLeft(), getTop(), getWidth(), newh);
219 Point Widget::getAbsolutePosition() const
221 if (parent_ == nullptr)
222 return Point(0, 0);
224 return parent_->getAbsolutePosition(*this);
227 Point Widget::getRelativePosition(const Container &ref) const
229 if (parent_ == nullptr)
230 return Point(0, 0);
232 return parent_->getRelativePosition(ref, *this);
235 void Widget::setRealPosition(int newx, int newy)
237 if (newx == real_xpos_ && newy == real_ypos_)
238 return;
240 real_xpos_ = newx;
241 real_ypos_ = newy;
243 signalAbsolutePositionChange();
246 void Widget::setRealSize(int neww, int newh)
248 if (neww == real_width_ && newh == real_height_)
249 return;
251 Size oldsize(real_width_, real_height_);
252 Size newsize(neww, newh);
254 real_width_ = neww;
255 real_height_ = newh;
257 updateAreaPostRealSizeChange(oldsize, newsize);
260 void Widget::setColorScheme(int new_color_scheme)
262 if (new_color_scheme == color_scheme_)
263 return;
265 color_scheme_ = new_color_scheme;
266 redraw();
269 int Widget::getColorScheme() const
271 if (color_scheme_ != 0)
272 return color_scheme_;
273 else if (parent_ != nullptr)
274 return parent_->getColorScheme();
276 return 0;
279 void Widget::registerAbsolutePositionListener(Widget &widget)
281 absolute_position_listeners_.push_back(&widget);
282 if (parent_ != nullptr && absolute_position_listeners_.size() == 1)
283 parent_->registerAbsolutePositionListener(*this);
286 void Widget::unregisterAbsolutePositionListener(Widget &widget)
288 Widgets::iterator i = std::find(absolute_position_listeners_.begin(),
289 absolute_position_listeners_.end(), &widget);
290 assert(i != absolute_position_listeners_.end());
292 absolute_position_listeners_.erase(i);
293 if (parent_ != nullptr && absolute_position_listeners_.size() == 0)
294 parent_->unregisterAbsolutePositionListener(*this);
297 void Widget::onAbsolutePositionChange(Widget & /*widget*/)
299 // Propagate the event to the listeners.
300 signalAbsolutePositionChange();
303 void Widget::signalMoveResize(const Rect &oldsize, const Rect &newsize)
305 if (parent_ == nullptr)
306 return;
308 // Tell the parent about the new size so it can position the widget correctly.
309 parent_->onChildMoveResize(*this, oldsize, newsize);
312 void Widget::signalWishSizeChange(const Size &oldsize, const Size &newsize)
314 if (parent_ == nullptr)
315 return;
317 // Tell the parent about the new wish size so it can position the widget
318 // correctly.
319 parent_->onChildWishSizeChange(*this, oldsize, newsize);
322 void Widget::signalVisible(bool visible)
324 if (parent_ == nullptr)
325 return;
327 // Tell the parent about the new visibility status so it can reposition its
328 // child widgets as appropriate.
329 parent_->onChildVisible(*this, visible);
332 void Widget::signalAbsolutePositionChange()
334 for (Widget *widget : absolute_position_listeners_)
335 widget->onAbsolutePositionChange(*this);
338 void Widget::updateArea()
340 // Empty for Widget.
343 void Widget::updateAreaPostRealSizeChange(
344 const Size & /*oldsize*/, const Size & /*newsize*/)
346 // Normal widgets only need to call updateArea().
347 updateArea();
350 void Widget::redraw()
352 if (parent_ == nullptr)
353 return;
355 parent_->redraw();
358 void Widget::setWishSize(int neww, int newh)
360 if (neww == wish_width_ && newh == wish_height_)
361 return;
363 Size oldsize(wish_width_, wish_height_);
364 Size newsize(neww, newh);
366 wish_width_ = neww;
367 wish_height_ = newh;
369 signalWishSizeChange(oldsize, newsize);
372 int Widget::getAttributes(int property, int *attrs, Error &error) const
374 return getAttributes(property, 0, attrs, error);
377 int Widget::getAttributes(
378 int property, int subproperty, int *attrs, Error &error) const
380 return COLORSCHEME->getAttributes(
381 getColorScheme(), property, subproperty, attrs, error);
384 Container *Widget::getTopContainer()
386 if (parent_ != nullptr)
387 return parent_->getTopContainer();
388 return dynamic_cast<Container *>(this);
391 } // namespace CppConsUI
393 // vim: set tabstop=2 shiftwidth=2 textwidth=80 expandtab: