1 // Copyright (C) 2007 Mark Pustjens <pustjens@dds.nl>
2 // Copyright (C) 2010-2015 Petr Pavlu <setup@dagobah.cz>
4 // This file is part of CenterIM.
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/>.
20 /// Widget class implementation.
22 /// @ingroup cppconsui
26 #include "ColorScheme.h"
27 #include "CoreManager.h"
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)
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_
)
56 Rect
oldsize(xpos_
, ypos_
, width_
, height_
);
57 Rect
newsize(newx
, newy
, neww
, newh
);
64 signalMoveResize(oldsize
, newsize
);
67 Widget
*Widget::getFocusWidget()
74 void Widget::cleanFocus()
80 signal_focus(*this, false);
84 bool Widget::restoreFocus()
89 void Widget::ungrabFocus()
91 if (parent_
== nullptr || !has_focus_
)
95 signal_focus(*this, false);
99 bool Widget::grabFocus()
101 if (parent_
== nullptr || has_focus_
)
104 if (can_focus_
&& isVisibleRecursive()) {
105 if (parent_
->setFocusChild(*this)) {
107 signal_focus(*this, true);
116 void Widget::setVisibility(bool new_visible
)
118 if (new_visible
== visible_
)
121 visible_
= new_visible
;
123 if (parent_
!= nullptr) {
124 parent_
->updateFocusChain();
126 Container
*t
= getTopContainer();
128 if (!t
->getFocusWidget()) {
129 // There is no focused widget, try if this or a widget that was revealed
131 t
->moveFocus(Container::FOCUS_DOWN
);
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_
);
149 bool Widget::isVisibleRecursive() const
151 if (parent_
== nullptr || !visible_
)
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();
180 // Clean focus if this widget/container was added to a container that
181 // already has a focused widget.
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)
224 return parent_
->getAbsolutePosition(*this);
227 Point
Widget::getRelativePosition(const Container
&ref
) const
229 if (parent_
== nullptr)
232 return parent_
->getRelativePosition(ref
, *this);
235 void Widget::setRealPosition(int newx
, int newy
)
237 if (newx
== real_xpos_
&& newy
== real_ypos_
)
243 signalAbsolutePositionChange();
246 void Widget::setRealSize(int neww
, int newh
)
248 if (neww
== real_width_
&& newh
== real_height_
)
251 Size
oldsize(real_width_
, real_height_
);
252 Size
newsize(neww
, newh
);
257 updateAreaPostRealSizeChange(oldsize
, newsize
);
260 void Widget::setColorScheme(int new_color_scheme
)
262 if (new_color_scheme
== color_scheme_
)
265 color_scheme_
= new_color_scheme
;
269 int Widget::getColorScheme() const
271 if (color_scheme_
!= 0)
272 return color_scheme_
;
273 else if (parent_
!= nullptr)
274 return parent_
->getColorScheme();
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)
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)
317 // Tell the parent about the new wish size so it can position the widget
319 parent_
->onChildWishSizeChange(*this, oldsize
, newsize
);
322 void Widget::signalVisible(bool visible
)
324 if (parent_
== nullptr)
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()
343 void Widget::updateAreaPostRealSizeChange(
344 const Size
& /*oldsize*/, const Size
& /*newsize*/)
346 // Normal widgets only need to call updateArea().
350 void Widget::redraw()
352 if (parent_
== nullptr)
358 void Widget::setWishSize(int neww
, int newh
)
360 if (neww
== wish_width_
&& newh
== wish_height_
)
363 Size
oldsize(wish_width_
, wish_height_
);
364 Size
newsize(neww
, 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: