Update list of wide characters
[centerim5.git] / cppconsui / ListBox.cpp
blobc66a0af05976caf7550447868234c49f595e564c
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 /// ListBox class implementation.
21 ///
22 /// @ingroup cppconsui
24 #include "ListBox.h"
26 #include <algorithm>
27 #include <cassert>
29 namespace CppConsUI {
31 ListBox::ListBox(int w, int h)
32 : AbstractListBox(w, h), children_height_(0), autosize_children_count_(0)
34 // Allow fast focus changing (paging) using PageUp/PageDown keys.
35 page_focus_ = true;
38 HorizontalLine *ListBox::insertSeparator(std::size_t pos)
40 auto l = new HorizontalLine(AUTOSIZE);
41 insertWidget(pos, *l);
42 return l;
45 HorizontalLine *ListBox::appendSeparator()
47 auto l = new HorizontalLine(AUTOSIZE);
48 appendWidget(*l);
49 return l;
52 void ListBox::insertWidget(std::size_t pos, Widget &widget)
54 Container::insertWidget(pos, widget, UNSETPOS, UNSETPOS);
56 if (!widget.isVisible())
57 return;
59 // Calculate the expected height by the widget.
60 int h = widget.getHeight();
61 int autosize_change = 0;
62 if (h == AUTOSIZE) {
63 h = widget.getWishHeight();
64 if (h == AUTOSIZE) {
65 h = 1;
66 autosize_change = 1;
70 updateChildren(h, autosize_change);
73 void ListBox::appendWidget(Widget &widget)
75 insertWidget(children_.size(), widget);
78 void ListBox::updateArea()
80 int autosize_height = 1;
81 int autosize_height_extra = 0;
82 if (autosize_children_count_ && children_height_ < real_height_) {
83 int space = real_height_ - (children_height_ - autosize_children_count_);
84 autosize_height = space / autosize_children_count_;
85 autosize_height_extra = space % autosize_children_count_;
88 int y = 0;
89 for (Widget *widget : children_) {
90 bool is_visible = widget->isVisible();
92 // Position the widget correctly.
93 widget->setRealPosition(0, y);
95 // Calculate the real width.
96 int w = widget->getWidth();
97 if (w == AUTOSIZE) {
98 w = widget->getWishWidth();
99 if (w == AUTOSIZE)
100 w = real_width_;
102 if (w > real_width_)
103 w = real_width_;
105 // Calculate the real height.
106 int h = widget->getHeight();
107 if (h == AUTOSIZE) {
108 h = widget->getWishHeight();
109 if (h == AUTOSIZE) {
110 h = autosize_height;
111 if (is_visible && autosize_height_extra > 0) {
112 --autosize_height_extra;
113 ++h;
118 widget->setRealSize(w, h);
120 if (is_visible)
121 y += h;
124 // Make sure that the currently focused widget is visible.
125 updateScroll();
128 void ListBox::onChildMoveResize(
129 Widget &activator, const Rect &oldsize, const Rect &newsize)
131 // Sanity check.
132 assert(newsize.getLeft() == UNSETPOS && newsize.getTop() == UNSETPOS);
134 if (!activator.isVisible())
135 return;
137 int old_height = oldsize.getHeight();
138 int new_height = newsize.getHeight();
140 if (old_height == new_height)
141 return;
143 int autosize_change = 0;
144 if (old_height == AUTOSIZE) {
145 old_height = activator.getWishHeight();
146 if (old_height == AUTOSIZE) {
147 old_height = 1;
148 --autosize_change;
151 if (new_height == AUTOSIZE) {
152 new_height = activator.getWishHeight();
153 if (new_height == AUTOSIZE) {
154 new_height = 1;
155 ++autosize_change;
159 updateChildren(new_height - old_height, autosize_change);
162 void ListBox::onChildWishSizeChange(
163 Widget &activator, const Size &oldsize, const Size &newsize)
165 if (!activator.isVisible() || activator.getHeight() != AUTOSIZE)
166 return;
168 // The widget is visible and is autosized.
169 int old_height = oldsize.getHeight();
170 int new_height = newsize.getHeight();
172 if (old_height == new_height)
173 return;
175 updateChildren(new_height - old_height, 0);
178 void ListBox::onChildVisible(Widget &activator, bool visible)
180 // The widget is being hidden or deleted.
181 int h = activator.getHeight();
182 int sign = visible ? 1 : -1;
183 int autosize_change = 0;
184 if (h == AUTOSIZE) {
185 h = activator.getWishHeight();
186 if (h == AUTOSIZE) {
187 h = 1;
188 autosize_change = sign;
191 updateChildren(sign * h, autosize_change);
194 void ListBox::moveWidget(Widget &widget, Widget &position, bool after)
196 Container::moveWidget(widget, position, after);
198 // Reposition all child widgets.
199 updateArea();
202 void ListBox::updateChildren(
203 int children_height_change, int autosize_children_count_change)
205 // Set new children data.
206 children_height_ += children_height_change;
207 assert(children_height_ >= 0);
208 autosize_children_count_ += autosize_children_count_change;
209 assert(autosize_children_count_ >= 0);
211 // Reposition all child widgets.
212 updateArea();
213 signal_children_height_change(*this, children_height_);
216 } // namespace CppConsUI
218 // vim: set tabstop=2 shiftwidth=2 textwidth=80 expandtab: