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 /// MenuWindow class implementation.
22 /// @ingroup cppconsui
24 #include "MenuWindow.h"
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
)
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
));
79 // Make sure that the first widget in the focus chain is always focused.
80 listbox_
->cleanFocus();
81 listbox_
->moveFocus(Container::FOCUS_DOWN
);
87 void MenuWindow::hide()
90 ref_visible_conn_
.disconnect();
95 void MenuWindow::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
);
116 Button
*MenuWindow::appendSubMenu(const char *title
, MenuWindow
&submenu
)
118 Button
*button
= prepareSubMenu(title
, submenu
);
119 listbox_
->appendWidget(*button
);
123 void MenuWindow::setHideOnClose(bool new_hide_on_close
)
125 if (hide_on_close_
== new_hide_on_close
)
128 hide_on_close_
= new_hide_on_close
;
131 void MenuWindow::setReferenceWidget(Widget
&new_ref
)
133 if (ref_
== &new_ref
)
136 // Clean the current reference.
137 cleanReferenceWidget();
140 ref_
->add_destroy_notify_callback(this, onReferenceWidgetDestroy_
);
141 ref_
->registerAbsolutePositionListener(*this);
142 updatePositionAndSize();
145 void MenuWindow::cleanReferenceWidget()
150 ref_
->remove_destroy_notify_callback(this);
151 ref_
->unregisterAbsolutePositionListener(*this);
155 void MenuWindow::setLeftShift(int x
)
161 updatePositionAndSize();
164 void MenuWindow::setTopShift(int 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.
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
);
195 void MenuWindow::updatePositionAndSize()
197 // This code is called when a position or size of this window should be
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_
;
210 setWishHeight(std::max(max
, 3));
216 // Relative position to another widget.
217 Point p
= ref_
->getAbsolutePosition();
218 if (p
.getX() == UNSETPOS
|| p
.getY() == UNSETPOS
)
221 int x
= p
.getX() + xshift_
;
222 int y
= p
.getY() + yshift_
;
225 int below
= Curses::getHeight() - y
- 1;
227 if (height_
== AUTOSIZE
)
228 req_h
= listbox_
->getChildrenHeight() + 2;
233 // Draw the window under the combobox.
235 setWishHeight(req_h
);
237 else if (above
> req_h
) {
238 // Draw the window above the combobox.
240 setWishHeight(req_h
);
242 else if (height_
== AUTOSIZE
) {
243 if (below
>= above
) {
245 setWishHeight(below
);
249 setWishHeight(above
);
254 void MenuWindow::onChildrenHeightChange(
255 ListBox
& /*activator*/, int /*new_height*/)
257 if (height_
!= AUTOSIZE
)
260 updatePositionAndSize();
263 void MenuWindow::onReferenceWidgetVisible(Widget
& /*activator*/, bool visible
)
268 // Close this window if the reference widget is no longer visible.
272 void MenuWindow::onReferenceWidgetDestroy()
274 // Ref widget is about to die right now, this window should be destroyed too.
275 assert(ref_
!= nullptr);
280 } // namespace CppConsUI
282 // vim: set tabstop=2 shiftwidth=2 textwidth=80 expandtab: