1 /*
2 *
3 * kkconsui dialogbox class
4 * $Id: dialogbox.cc,v 1.14 2003/10/19 23:25:05 konst Exp $
5 *
6 * Copyright (C) 1999-2001 by Konstantin Klyagin <k@thekonst.net>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or (at
11 * your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 * USA
22 *
23 */
24 
25 #include "dialogbox.h"
26 
27 dialogbox *dialogbox::it;
28 
dialogbox()29 dialogbox::dialogbox(): first(true), menu(0), tree(0), window(0), bar(0), browser(0),
30 otherkeys(0), idle(0) {
31     freemenu = freetree = freewindow = freebar = freebrowser = false;
32 }
33 
~dialogbox()34 dialogbox::~dialogbox() {
35     if(menu && freemenu) delete menu;
36     if(tree && freetree) delete tree;
37     if(bar && freebar) delete bar;
38     if(window && freewindow) delete window;
39     if(browser && freebrowser) delete browser;
40 }
41 
setwindow(textwindow * neww,bool fw)42 void dialogbox::setwindow(textwindow *neww, bool fw) {
43     window = neww;
44     freewindow = fw;
45 }
46 
setbar(horizontalbar * newb,bool fb)47 void dialogbox::setbar(horizontalbar *newb, bool fb) {
48     bar = newb;
49     freebar = fb;
50 }
51 
setmenu(verticalmenu * newm,bool fm)52 void dialogbox::setmenu(verticalmenu *newm, bool fm) {
53     menu = newm;
54     freemenu = fm;
55 }
56 
settree(treeview * newt,bool ft)57 void dialogbox::settree(treeview *newt, bool ft) {
58     tree = newt;
59     freetree = ft;
60 }
61 
setbrowser(textbrowser * newbr,bool fbr)62 void dialogbox::setbrowser(textbrowser *newbr, bool fbr) {
63     browser = newbr;
64     freebrowser = fbr;
65 }
66 
getmenu()67 verticalmenu *dialogbox::getmenu() {
68     return menu;
69 }
70 
gettree()71 treeview *dialogbox::gettree() {
72     return tree;
73 }
74 
getwindow()75 textwindow *dialogbox::getwindow() {
76     return window;
77 }
78 
getbar()79 horizontalbar *dialogbox::getbar() {
80     return bar;
81 }
82 
getbrowser()83 textbrowser *dialogbox::getbrowser() {
84     return browser;
85 }
86 
open(int & menuitem,int & baritem,void ** ref)87 bool dialogbox::open(int &menuitem, int &baritem, void **ref) {
88     bool ret = false;
89     list<keybarassociation>::iterator i;
90 
91     it = this;
92     if(first) redraw();
93 
94     if(menu) {
95 	menuitem = menu->open();
96 	if(ref) *ref = menu->getref(menuitem-1);
97 	ret = menuitem || (menu->getlastkey() != KEY_ESC);
98     } else if(tree) {
99 	void *r;
100 	r = tree->open(&menuitem);
101 	if(ref) *ref = r;
102 	ret = menuitem || (tree->menu.getlastkey() != KEY_ESC) || r;
103     } else if(browser) {
104 	menuitem = browser->open();
105 	ret = menuitem;
106     } else if(bar) {
107 	bool fin, proceed;
108 	int k;
109 	menuitem = 0;
110 
111 	for(fin = false; !fin; ) {
112 	    proceed = idle ? keypressed() : true;
113 	    it = this;
114 
115 	    if(proceed)
116 	    switch(k = getkey()) {
117 		case KEY_LEFT:
118 		case KEY_RIGHT:
119 		    bar->movebar(k);
120 		    bar->redraw();
121 		    break;
122 		case '\r':
123 		    fin = ret = true;
124 		    break;
125 		case KEY_ESC:
126 		    fin = true; ret = false;
127 		    break;
128 		default:
129 		    i = find(it->kba.begin(), it->kba.end(), k);
130 
131 		    if(i != it->kba.end()) {
132 		      if(it->bar) {
133 			it->bar->item = i->baritem;
134 			it->bar->redraw();
135 			fin = ret = true;
136 		      }
137 		    }
138 		    else if(otherkeys)
139 		      if((k = otherkeys(*this, k)) != -1) {
140 			menuitem = k;
141 			fin = true;
142 		      }
143 		    break;
144 	    } else {
145 		if(idle) idle(*this);
146 	    }
147 	}
148     }
149 
150     if(bar) {
151 	baritem = bar->item;
152     } else {
153 	baritem = 0;
154     }
155 
156     return ret;
157 }
158 
open(int & menuitem)159 bool dialogbox::open(int &menuitem) {
160     int bi;
161     return open(menuitem, bi);
162 }
163 
open()164 bool dialogbox::open() {
165     int menuitem, bi;
166     return open(menuitem, bi);
167 }
168 
redraw()169 void dialogbox::redraw() {
170     if(window) {
171 	if(window->isopen()) window->redraw(); else window->open();
172 
173 	if(bar) {
174 	    if(window->isbordered()) {
175 		window->separatey(window->y2-window->y1-2);
176 	    }
177 
178 	    bar->setcoords(window->x2 - (window->isbordered() ? 1 : 2), window->y2-1);
179 	    bar->align(baleft);
180 	    bar->redraw();
181 	}
182 
183 	int x1 = window->x1 + (window->isbordered() ? 1 : 0);
184 
185 	if(menu) {
186 	    menu->setcoords(x1, window->y1+1, window->x2, bar ? window->y2-2 : window->y2);
187 	    menu->idle = &menuidle;
188 	    menu->otherkeys = &menukeys;
189 	} else if(tree) {
190 	    tree->setcoords(x1, window->y1+1, window->x2, bar ? window->y2-2 : window->y2);
191 	    tree->redraw();
192 	    tree->menu.idle = &menuidle;
193 	    tree->menu.otherkeys = &menukeys;
194 	} else if(browser) {
195 	    int x2 = window->x2 - (window->isbordered() ? 1 : 0);
196 
197 	    browser->setcoords(window->x1+1, window->y1+1, x2,
198 		bar ? window->y2-2 : window->y2);
199 
200 	    browser->redraw();
201 	    browser->idle = &browseridle;
202 	    browser->otherkeys = &browserkeys;
203 	}
204     }
205 
206     first = false;
207 }
208 
close()209 void dialogbox::close() {
210     if(window) window->close();
211 }
212 
clearkeys()213 void dialogbox::clearkeys() {
214     kba.clear();
215 }
216 
addkey(int key,int baritem)217 void dialogbox::addkey(int key, int baritem) {
218     kba.push_back(keybarassociation(key, baritem));
219 }
220 
addautokeys()221 void dialogbox::addautokeys() {
222     int key;
223     vector<string>::const_iterator i;
224     string::const_iterator c;
225 
226     if(bar) {
227 	for(i = bar->items.begin(); i != bar->items.end(); i++) {
228 	    for(c = i->begin(); (c != i->end()) && !isupper(*c); c++);
229 	    key = (c == i->end()) ? *i->begin() : *c;
230 	    addkey(tolower(key), i-bar->items.begin());
231 	    addkey(toupper(key), i-bar->items.begin());
232 	}
233     }
234 }
235 
menuidle(verticalmenu & caller)236 void dialogbox::menuidle(verticalmenu &caller) {
237     if(it->idle) {
238 	it->idle(*it);
239     } else {
240 	fd_set fds;
241 	FD_ZERO(&fds);
242 	FD_SET(0, &fds);
243 	select(1, &fds, 0, 0, 0);
244     }
245 }
246 
browseridle(textbrowser & caller)247 void dialogbox::browseridle(textbrowser &caller) {
248     if(it->idle) {
249 	it->idle(*it);
250     } else {
251 	fd_set fds;
252 	FD_ZERO(&fds);
253 	FD_SET(0, &fds);
254 	select(1, &fds, 0, 0, 0);
255     }
256 }
257 
menukeys(verticalmenu & caller,int k)258 int dialogbox::menukeys(verticalmenu &caller, int k) {
259     list<keybarassociation>::iterator i;
260     int ip;
261     dialogbox *sit;
262 
263     switch(k) {
264 	case KEY_LEFT:
265 	case KEY_RIGHT:
266 	    if(it->bar) {
267 		it->bar->movebar(k);
268 		it->bar->redraw();
269 	    }
270 	    break;
271 	case '-':
272 	case '+':
273 	    if(it->tree)
274 	    if(it->tree->collapsable) {
275 		int nid = it->tree->getid(it->tree->menu.getpos());
276 
277 		if(it->tree->isnode(nid)) {
278 		    if(it->tree->isnodeopen(nid)) it->tree->closenode(nid);
279 		    else it->tree->opennode(nid);
280 
281 		    it->tree->menu.redraw();
282 		}
283 	    }
284 
285 	default:
286 	    i = find(it->kba.begin(), it->kba.end(), k);
287 
288 	    if(i != it->kba.end()) {
289 		if(it->bar) {
290 		    it->bar->item = i->baritem;
291 		    it->bar->redraw();
292 		}
293 
294 		if(it->menu) {
295 		    return it->menu->getpos()+1;
296 		} else if(it->tree) {
297 		    return it->tree->menu.getpos()+1;
298 		}
299 	    } else {
300 		if(it->otherkeys) {
301 		    sit = it;
302 		    ip = it->otherkeys(*it, k);
303 		    it = sit;
304 		    return ip;
305 		}
306 	    }
307 	    break;
308     }
309 
310     return -1;
311 }
312 
browserkeys(textbrowser & caller,int k)313 int dialogbox::browserkeys(textbrowser &caller, int k) {
314     list<keybarassociation>::iterator i;
315     int ip;
316     dialogbox *sit;
317 
318     switch(k) {
319 	case KEY_LEFT:
320 	case KEY_RIGHT:
321 	    if(it->bar) {
322 		it->bar->movebar(k);
323 		it->bar->redraw();
324 	    }
325 	    break;
326 	case '\r':
327 	    return 1;
328 
329 	default:
330 	    i = find(it->kba.begin(), it->kba.end(), k);
331 
332 	    if(i != it->kba.end()) {
333 		if(it->bar) {
334 		    it->bar->item = i->baritem;
335 		    it->bar->redraw();
336 		}
337 
338 		return 1;
339 	    } else {
340 		if(it->otherkeys) {
341 		    sit = it;
342 		    ip = it->otherkeys(*it, k);
343 		    it = sit;
344 		    return ip;
345 		}
346 	    }
347 	    break;
348     }
349 
350     return -1;
351 }
352 
353 // ----------------------------------------------------------------------------
354 
keybarassociation(int nkey,int nbarit)355 dialogbox::keybarassociation::keybarassociation(int nkey, int nbarit) {
356     key = nkey;
357     baritem = nbarit;
358 }
359 
operator ==(const int akey)360 bool dialogbox::keybarassociation::operator == (const int akey) {
361     return key == akey;
362 }
363 
operator !=(const int akey)364 bool dialogbox::keybarassociation::operator != (const int akey) {
365     return !(*this == akey);
366 }
367