Update list of wide characters
[centerim5.git] / cppconsui / MenuWindow.cpp
blobc94dad07a0e2eb7a641171ffade52b1f8a18f279
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 /// MenuWindow class implementation.
21 ///
22 /// @ingroup cppconsui
24 #include "MenuWindow.h"
26 #include <algorithm>
27 #include <cassert>
29 namespace CppConsUI {
31 MenuWindow::MenuWindow(int x, int y, int w, int h, const char *title)
32 : Window(x, y, w, h, title, TYPE_TOP), wish_height_(3), ref_(nullptr),
33 xshift_(0), yshift_(0), hide_on_close_(false)
35 wish_width_ = MENU_WINDOW_WISH_WIDTH;
37 listbox_ = new ListBox(AUTOSIZE, AUTOSIZE);
38 listbox_->signal_children_height_change.connect(
39 sigc::mem_fun(this, &MenuWindow::onChildrenHeightChange));
40 Window::addWidget(*listbox_, 1, 1);
43 MenuWindow::MenuWindow(Widget &ref, int w, int h, const char *title)
44 : Window(0, 0, w, h, title, TYPE_TOP), wish_height_(3), ref_(nullptr),
45 xshift_(0), yshift_(0), hide_on_close_(false)
47 wish_width_ = MENU_WINDOW_WISH_WIDTH;
49 listbox_ = new ListBox(AUTOSIZE, AUTOSIZE);
50 listbox_->signal_children_height_change.connect(
51 sigc::mem_fun(this, &MenuWindow::onChildrenHeightChange));
52 Window::addWidget(*listbox_, 1, 1);
54 setReferenceWidget(ref);
57 MenuWindow::~MenuWindow()
59 cleanReferenceWidget();
62 void MenuWindow::onAbsolutePositionChange(Widget &widget)
64 if (&widget == ref_)
65 updatePositionAndSize();
66 Window::onAbsolutePositionChange(widget);
69 void MenuWindow::show()
71 if (ref_ != nullptr) {
72 assert(!ref_visible_conn_.connected());
74 ref_visible_conn_ = ref_->signal_visible.connect(
75 sigc::mem_fun(this, &MenuWindow::onReferenceWidgetVisible));
78 if (hide_on_close_) {
79 // Make sure that the first widget in the focus chain is always focused.
80 listbox_->cleanFocus();
81 listbox_->moveFocus(Container::FOCUS_DOWN);
84 Window::show();
87 void MenuWindow::hide()
89 if (ref_ != nullptr)
90 ref_visible_conn_.disconnect();
92 Window::hide();
95 void MenuWindow::close()
97 if (hide_on_close_)
98 hide();
99 else
100 Window::close();
103 void MenuWindow::onScreenResized()
105 updatePositionAndSize();
108 Button *MenuWindow::insertSubMenu(
109 std::size_t pos, const char *title, MenuWindow &submenu)
111 Button *button = prepareSubMenu(title, submenu);
112 listbox_->insertWidget(pos, *button);
113 return button;
116 Button *MenuWindow::appendSubMenu(const char *title, MenuWindow &submenu)
118 Button *button = prepareSubMenu(title, submenu);
119 listbox_->appendWidget(*button);
120 return button;
123 void MenuWindow::setHideOnClose(bool new_hide_on_close)
125 if (hide_on_close_ == new_hide_on_close)
126 return;
128 hide_on_close_ = new_hide_on_close;
131 void MenuWindow::setReferenceWidget(Widget &new_ref)
133 if (ref_ == &new_ref)
134 return;
136 // Clean the current reference.
137 cleanReferenceWidget();
139 ref_ = &new_ref;
140 ref_->add_destroy_notify_callback(this, onReferenceWidgetDestroy_);
141 ref_->registerAbsolutePositionListener(*this);
142 updatePositionAndSize();
145 void MenuWindow::cleanReferenceWidget()
147 if (ref_ == nullptr)
148 return;
150 ref_->remove_destroy_notify_callback(this);
151 ref_->unregisterAbsolutePositionListener(*this);
152 ref_ = nullptr;
155 void MenuWindow::setLeftShift(int x)
157 if (xshift_ == x)
158 return;
160 xshift_ = x;
161 updatePositionAndSize();
164 void MenuWindow::setTopShift(int y)
166 if (yshift_ == y)
167 return;
169 yshift_ = y;
170 updatePositionAndSize();
173 void MenuWindow::addWidget(Widget &widget, int x, int y)
175 Window::addWidget(widget, x, y);
178 Button *MenuWindow::prepareSubMenu(const char *title, MenuWindow &submenu)
180 // Setup submenu correctly.
181 submenu.hide();
182 submenu.setHideOnClose(true);
183 signal_hide.connect(sigc::hide(sigc::mem_fun(submenu, &MenuWindow::hide)));
185 // Create an opening button.
186 auto button = new Button(title);
187 button->signal_activate.connect(
188 sigc::hide(sigc::mem_fun(submenu, &MenuWindow::show)));
190 submenu.setReferenceWidget(*button);
192 return button;
195 void MenuWindow::updatePositionAndSize()
197 // This code is called when a position or size of this window should be
198 // updated.
200 // This can happen when:
201 // - the screen is resized,
202 // - the listbox wish height changed,
203 // - reference widget changed its position on the screen.
205 if (ref_ == nullptr) {
206 // Absolute screen position.
207 int h = listbox_->getChildrenHeight() + 2;
208 int max = Curses::getHeight() - ypos_;
209 if (h > max)
210 setWishHeight(std::max(max, 3));
211 else
212 setWishHeight(h);
213 return;
216 // Relative position to another widget.
217 Point p = ref_->getAbsolutePosition();
218 if (p.getX() == UNSETPOS || p.getY() == UNSETPOS)
219 p = Point(0, 0);
221 int x = p.getX() + xshift_;
222 int y = p.getY() + yshift_;
224 int above = y;
225 int below = Curses::getHeight() - y - 1;
226 int req_h;
227 if (height_ == AUTOSIZE)
228 req_h = listbox_->getChildrenHeight() + 2;
229 else
230 req_h = height_;
232 if (below > req_h) {
233 // Draw the window under the combobox.
234 move(x, y + 1);
235 setWishHeight(req_h);
237 else if (above > req_h) {
238 // Draw the window above the combobox.
239 move(x, y - req_h);
240 setWishHeight(req_h);
242 else if (height_ == AUTOSIZE) {
243 if (below >= above) {
244 move(x, y + 1);
245 setWishHeight(below);
247 else {
248 move(x, 0);
249 setWishHeight(above);
254 void MenuWindow::onChildrenHeightChange(
255 ListBox & /*activator*/, int /*new_height*/)
257 if (height_ != AUTOSIZE)
258 return;
260 updatePositionAndSize();
263 void MenuWindow::onReferenceWidgetVisible(Widget & /*activator*/, bool visible)
265 if (visible)
266 return;
268 // Close this window if the reference widget is no longer visible.
269 close();
272 void MenuWindow::onReferenceWidgetDestroy()
274 // Ref widget is about to die right now, this window should be destroyed too.
275 assert(ref_ != nullptr);
276 ref_ = nullptr;
277 delete this;
280 } // namespace CppConsUI
282 // vim: set tabstop=2 shiftwidth=2 textwidth=80 expandtab: