1 //
2 // This file is part of libyacurs.
3 // Copyright (C) 2013 Rafael Ostertag
4 //
5 // This program is free software: you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License as
7 // published by the Free Software Foundation, either version 3 of the
8 // License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful, but
11 // WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program. If not, see
17 // <http://www.gnu.org/licenses/>.
18 //
19 //
20 // $Id$
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <gettext.h>
27
28 #include <cassert>
29 #include <cstdlib>
30
31 #include "dialog.h"
32 #include "eventqueue.h"
33 #include "hotkey.h"
34 #include "yacursex.h"
35
36 namespace YACURS {
37 namespace INTERNAL {
38 /**
39 * HotKey for cancelling Dialog.
40 */
41 class HotKeyEsc : public HotKey {
42 private:
43 Dialog& _dialog;
44
45 public:
HotKeyEsc(Dialog & d)46 HotKeyEsc(Dialog& d) : HotKey(27), _dialog(d) {}
47
HotKeyEsc(const HotKeyEsc & hk)48 HotKeyEsc(const HotKeyEsc& hk) : HotKey(hk), _dialog(hk._dialog) {}
49
action()50 void action() {
51 _dialog._dstate = DIALOG_CANCEL;
52 _dialog.close();
53 }
54
clone() const55 HotKey* clone() const { return new HotKeyEsc(*this); }
56 };
57 } // namespace INTERNAL
58 } // namespace YACURS
59
60 using namespace YACURS;
61
62 //
63 // Private
64 //
65
66 //
67 // Protected
68 //
ok_button() const69 const Button* const Dialog::ok_button() const { return _bok; }
70
cancel_button() const71 const Button* const Dialog::cancel_button() const { return _bcancel; }
72
yes_button() const73 const Button* const Dialog::yes_button() const { return _byes; }
74
no_button() const75 const Button* const Dialog::no_button() const { return _bno; }
76
dialog_state(DIALOG_STATE st)77 void Dialog::dialog_state(DIALOG_STATE st) { _dstate = st; }
78
add_button(Button * b)79 void Dialog::add_button(Button* b) { _hpack->add_back(b); }
80
add_button(Spacer * s)81 void Dialog::add_button(Spacer* s) { _hpack->add_back(s); }
82
button_press_handler(Event & e)83 void Dialog::button_press_handler(Event& e) {
84 if (realization() != REALIZED) return;
85
86 assert(e == EVT_BUTTON_PRESS);
87 EventEx<Button*>& evt = dynamic_cast<EventEx<Button*>&>(e);
88
89 if (evt.data() == _bok) {
90 _dstate = DIALOG_OK;
91 on_ok_button();
92 close();
93 }
94
95 if (evt.data() == _bcancel) {
96 _dstate = DIALOG_CANCEL;
97 on_cancel_button();
98 close();
99 }
100
101 if (evt.data() == _byes) {
102 _dstate = DIALOG_YES;
103 on_yes_button();
104 close();
105 }
106
107 if (evt.data() == _bno) {
108 _dstate = DIALOG_NO;
109 on_no_button();
110 close();
111 }
112 }
113
on_ok_button()114 void Dialog::on_ok_button() { /* Intentionally empty */
115 }
116
on_cancel_button()117 void Dialog::on_cancel_button() { /* Intentionally empty */
118 }
119
on_yes_button()120 void Dialog::on_yes_button() { /* Intentionally empty */
121 }
122
on_no_button()123 void Dialog::on_no_button() { /* Intentionally empty */
124 }
125
126 //
127 // Public
128 //
129
Dialog(const std::string & title,DIALOG_TYPE dialogType,DIALOG_SIZE dialogSize)130 Dialog::Dialog(const std::string& title, DIALOG_TYPE dialogType,
131 DIALOG_SIZE dialogSize)
132 : _vpack(new VPack),
133 _hpack(new HPack),
134 _byes(0),
135 _bok(0),
136 _ok_spacer(new Spacer),
137 _bcancel(0),
138 _bno(0),
139 _hrule(new HRule),
140 _dstate(DIALOG_CANCEL),
141 _dialog_type(dialogType),
142 _dialog_size(dialogSize),
143 _title(title) {
144 _hrule->color(DIALOG);
145
146 _vpack->add_back(_hrule);
147 _vpack->add_back(_hpack);
148
149 switch (_dialog_type) {
150 case OKCANCEL:
151 _bcancel = new Button(_("Cancel"));
152 _hpack->add_back(_bcancel);
153 _hpack->add_front(_ok_spacer);
154 // Fall thru
155
156 case OK_ONLY:
157 _bok = new Button(_("OK"));
158 _hpack->add_front(_bok);
159 break;
160
161 case YESNO:
162 _bno = new Button(_("No"));
163 _hpack->add_front(_bno);
164 _hpack->add_front(_ok_spacer);
165 // Fall thru
166
167 case YES_ONLY:
168 _byes = new Button(_("Yes"));
169 _hpack->add_front(_byes);
170 break;
171
172 // handled separately
173 case YESNOCANCEL:
174 _bcancel = new Button(_("Cancel"));
175 _hpack->add_back(_bcancel);
176 _hpack->add_front(_ok_spacer);
177 _bno = new Button(_("No"));
178 _hpack->add_front(_bno);
179 _hpack->add_front(_ok_spacer);
180 _byes = new Button(_("Yes"));
181 _hpack->add_front(_byes);
182 break;
183
184 default:
185 throw EXCEPTIONS::InvalidDialogType();
186 break;
187 }
188
189 // from Window
190 Window::widget(_vpack);
191 frame(true);
192 color(DIALOG);
193 }
194
~Dialog()195 Dialog::~Dialog() {
196 assert(_vpack != 0);
197 assert(_hpack != 0);
198 assert(_hrule != 0);
199 assert(_ok_spacer != 0);
200
201 delete _vpack;
202 delete _hpack;
203 delete _hrule;
204 delete _ok_spacer;
205
206 if (_bok) delete _bok;
207 if (_byes) delete _byes;
208 if (_bcancel) delete _bcancel;
209 if (_bno) delete _bno;
210
211 EventQueue::disconnect_event(EventConnectorMethod1<Dialog>(
212 EVT_BUTTON_PRESS, this, &Dialog::button_press_handler));
213 }
214
widget(WidgetBase * _w)215 void Dialog::widget(WidgetBase* _w) {
216 assert(_vpack != 0);
217 _vpack->add_front(_w);
218 }
219
220 DIALOG_STATE
dialog_state() const221 Dialog::dialog_state() const { return _dstate; }
222
223 DIALOG_TYPE
dialog_type() const224 Dialog::dialog_type() const { return _dialog_type; }
225
title(const std::string & title)226 void Dialog::title(const std::string& title) {
227 _title = title;
228
229 if (realization() == REALIZED) {
230 // Ugly hack, reset box, so that it will be adjusted to new
231 // title...
232 if (frame()) curses_window()->box();
233
234 refresh(true);
235 }
236 }
237
title() const238 std::string Dialog::title() const { return _title; }
239
refresh(bool immediate)240 void Dialog::refresh(bool immediate) {
241 if (realization() != REALIZED && realization() != REALIZING) return;
242
243 CurStr tmp(_title, Coordinates(1, 0), DIALOG_TITLE);
244 curses_window()->addstrx(tmp);
245
246 Window::refresh(immediate);
247 }
248
realize()249 void Dialog::realize() {
250 REALIZE_ENTER;
251
252 // Reset the dialog state
253 _dstate = DIALOG_CANCEL;
254
255 EventQueue::connect_event(EventConnectorMethod1<Dialog>(
256 EVT_BUTTON_PRESS, this, &Dialog::button_press_handler));
257
258 Margin _margin(2, 2, 2, 2);
259 _vpack->hinting(false);
260
261 if (_dialog_size == AUTOMATIC) {
262 _vpack->hinting(true);
263 // Compute the margin. We try to vertically center the dialog.
264 int hinted_rows = Window::widget()->size_hint().rows();
265 if (hinted_rows > 0 && hinted_rows < area().rows() - 2) {
266 int vert_margin = (area().rows() - hinted_rows) / 2 - 1;
267 _margin = Margin(vert_margin, 2, vert_margin, 2);
268 }
269 }
270
271 margin(_margin);
272 Window::realize();
273
274 add_hotkey(INTERNAL::HotKeyEsc(*this));
275
276 REALIZE_LEAVE;
277 }
278
unrealize()279 void Dialog::unrealize() {
280 UNREALIZE_ENTER;
281
282 EventQueue::disconnect_event(EventConnectorMethod1<Dialog>(
283 EVT_BUTTON_PRESS, this, &Dialog::button_press_handler));
284
285 Window::unrealize();
286
287 UNREALIZE_LEAVE;
288 }
289