connwrap - initialize gnutls session in cw_connect
[centerim.git] / kkconsui / src / cmenus.cc
blob85f8d1ec00baccb518a7f2dcb8e09d63bfb35019
1 /*
3 * kkconsui various textmode menus classes
4 * $Id: cmenus.cc,v 1.20 2004/03/28 11:38:35 konst Exp $
6 * Copyright (C) 1999-2001 by Konstantin Klyagin <k@thekonst.net>
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.
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.
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
25 #include "cmenus.h"
27 verticalmenu::verticalmenu(int px1, int py1, int px2, int py2, int pncolor, int pscolor)
28 : abstractuicontrol() {
29 initmembers();
30 setcolor(pncolor, pscolor);
31 setcoords(px1, py1, px2, py2);
34 verticalmenu::verticalmenu(int pncolor, int pscolor)
35 : abstractuicontrol() {
36 initmembers();
37 setcolor(pncolor, pscolor);
40 void verticalmenu::initmembers() {
41 firstdisp = curelem = 0;
42 idle = 0;
43 otherkeys = 0;
44 clearonfocuslost = cycled = exitonedges = false;
47 void verticalmenu::setcolor(int pncolor, int pscolor) {
48 ncolor = pncolor, scolor = pscolor;
51 void verticalmenu::clear() {
52 items.clear();
55 bool verticalmenu::empty() {
56 return items.empty();
59 void verticalmenu::setcoords(int nx1, int ny1, int nx2, int ny2) {
60 x1 = nx1;
61 x2 = nx2;
62 y1 = ny1;
63 y2 = ny2;
66 void verticalmenu::additemf(const char *fmt, ...) {
67 string buf;
68 VGETSTRING(buf, fmt);
69 additem(buf);
72 void verticalmenu::additem(const string &text) {
73 additem(ncolor, 0, text);
76 void verticalmenu::additem(int color, void *ref, const string &text) {
77 verticalmenuitem i;
78 i.text = text;
79 i.color = color ? color : ncolor;
80 i.kind = ITEM_NORM;
81 i.ref = ref;
82 items.push_back(i);
85 void verticalmenu::additemf(int color, void *ref, const char *fmt, ...) {
86 string buf;
87 VGETSTRING(buf, fmt);
88 additem(color, ref, buf);
91 void verticalmenu::additem(int color, int ref, const string &text) {
92 additem(color, (void *) ref, text);
95 void verticalmenu::additemf(int color, int ref, const char *fmt, ...) {
96 string buf;
97 VGETSTRING(buf, fmt);
98 additem(color, (void *) ref, buf);
101 void verticalmenu::addline() {
102 addline(ncolor, 0);
105 void verticalmenu::addline(int color, const char *fmt, ...) {
106 verticalmenuitem i;
107 char buf[10240];
108 va_list ap;
110 if(fmt) {
111 va_start(ap, fmt);
112 vsprintf(buf, fmt, ap);
113 va_end(ap);
114 i.text = buf;
115 i.kind = ITEM_SEP;
116 } else {
117 i.kind = ITEM_LINE;
120 i.color = color;
121 items.push_back(i);
124 bool verticalmenu::shownelem(int n, int selected) {
125 bool hlight = true;
126 int extra = 0;
127 unsigned char c;
128 string buf;
130 if((n < 0) || (n >= items.size())) return false;
131 verticalmenuitem &item = items[n];
133 if(!(selected && item.kind != ITEM_NORM)) {
134 attrset(selected && (item.kind == ITEM_NORM) ? scolor : item.color);
136 if(item.kind == ITEM_LINE) {
137 if(!selected) mvhline(y1+n-firstdisp, x1, HLINE, x2-x1);
138 } else if(!item.text.empty()) {
139 mvprintw(y1+n-firstdisp, x1, "");
141 buf = item.text; //makebidi(item.text, x2-x1);
143 for(int i = x1; i < x2+extra; i++) {
144 if(i-x1 < buf.size()) {
145 switch(c = buf[i-x1]) {
146 case 1:
147 if(hlight = !hlight)
148 attrset(selected && (item.kind == ITEM_NORM) ?
149 scolor : item.color);
150 else attrset(ncolor);
152 extra++;
153 break;
154 case 2: addch(HLINE); break;
155 case 3: addch(VLINE); break;
156 case 4: addch(RTEE); break;
157 case 5: addch(LTEE); break;
158 case 6: addch(ULCORNER); break;
159 case 7: addch(LLCORNER); break;
160 case 8: addch(LRCORNER); break;
161 case 9: addch(URCORNER); break;
162 default:
163 printchar(c);
164 break;
166 } else {
167 printw(" ");
174 return item.kind == ITEM_NORM;
177 void verticalmenu::showall() {
178 unsigned int p;
180 if(curelem < 0) {
181 curelem = 0;
182 } else if(curelem > items.size()-1) {
183 curelem = items.size()-1;
186 if((firstdisp+y2-y1 <= curelem) || (curelem < firstdisp)) {
187 firstdisp = curelem-y2+y1+1;
190 if((firstdisp+y2-y1 > items.size()) && (y2-y1 < items.size())) {
191 firstdisp = items.size()-y2+y1;
192 } else if(firstdisp < 0) {
193 firstdisp = 0;
196 attrset(ncolor);
198 for(p = firstdisp; (p < firstdisp+y2-y1) && (p < items.size()); p++) {
199 kgotoxy(x1, y1+p-firstdisp);
200 shownelem(p, 0);
203 for(; p < firstdisp+y2-y1; p++) {
204 mvhline(y1+p-firstdisp, x1, ' ', x2-x1);
208 void verticalmenu::redraw() {
209 showall();
210 kgotoxy(x1, y1+curelem-firstdisp);
212 if(!clearonfocuslost)
213 if(curelem >= 0)
214 shownelem(curelem, 1);
216 refresh();
219 void verticalmenu::scale() {
220 if((y2 = y1+items.size()) > LINES-2) y2 = LINES-2;
221 if(!window.empty()) window.y2 = y2;
224 int verticalmenu::open() {
225 int go, k;
227 if(!window.empty()) window.open();
229 intredraw();
231 kgotoxy(x1, y1+curelem-firstdisp);
232 if(clearonfocuslost && curelem >= 0)
233 shownelem(curelem, 1);
235 finished = aborted = false;
237 while(!finished) {
238 if(idle) go = keypressed(); else go = 1;
239 if(go) {
240 k = getkey();
241 if(emacs) k = emacsbind(k);
242 lastkey = k;
244 switch(k) {
245 case '\r':
246 finished = true;
247 checkclear();
248 break;
250 case 27:
251 checkclear();
252 return 0;
253 break;
255 case KEY_UP:
256 if(curelem > 0) {
257 shownelem(curelem, 0);
258 if(--curelem < firstdisp) {
259 firstdisp = curelem - y2 + y1 + 1;
260 intredraw();
261 } else {
262 int savecurelem = curelem+1;
264 while(curelem >= 0)
265 if(!shownelem(curelem, 1)) {
266 curelem--;
267 } else {
268 break;
271 if(curelem < 0)
272 shownelem(curelem = savecurelem, 1);
274 refresh();
276 } else if(exitonedges) {
277 finished = true;
278 } else if(cycled) {
279 curelem = items.size()-1;
280 if((firstdisp = curelem-y2+y1+1) < 0) firstdisp = 0;
281 intredraw();
283 break;
285 case KEY_DOWN:
286 if(!items.empty()) {
287 if(curelem < items.size()-1) {
288 shownelem(curelem++, 0);
290 if(curelem > firstdisp+y2-y1-1) {
291 firstdisp += y2 - y1;
292 intredraw();
293 } else {
294 bool lastone;
295 int savecur = curelem-1;
297 while(curelem < items.size()) {
298 if(!(lastone = shownelem(curelem, 1)))
299 curelem++; else break;
302 if(!lastone) shownelem(curelem = savecur, 1);
303 refresh();
305 } else if(exitonedges) {
306 finished = true;
307 } else if(cycled) {
308 curelem = firstdisp = 0;
309 intredraw();
312 break;
314 case KEY_PPAGE:
315 if((curelem -= y2-y1) < 0) {
316 if(finished = exitonedges) continue;
317 curelem = 0;
320 firstdisp = curelem;
321 intredraw();
322 break;
324 case KEY_NPAGE:
325 if(!items.empty()) {
326 if((curelem += y2-y1) > items.size()-1) {
327 if(finished = exitonedges) continue;
328 curelem = items.size()-1;
331 if((firstdisp = curelem-y2+y1+1) < 0) firstdisp = 0;
334 intredraw();
335 break;
337 case KEY_HOME:
338 curelem = firstdisp = 0;
339 intredraw();
340 finished = finished || exitonedges;
341 break;
343 case KEY_END:
344 curelem = items.size()-1;
345 if((firstdisp = curelem-y2+y1+1) < 0) firstdisp = 0;
346 intredraw();
347 finished = finished || exitonedges;
348 break;
350 default:
351 if(otherkeys) {
352 if((go = (*otherkeys)(*this, k)) != -1) {
353 checkclear();
354 return go;
357 break;
359 } else {
360 if(idle) (*idle)(*this);
364 return curelem+1;
367 int verticalmenu::getcount() {
368 return items.size();
371 int verticalmenu::getlastkey() {
372 return lastkey;
375 void *verticalmenu::getref(int n) {
376 return (n >= 0) && (n < items.size()) ? items[n].ref : 0;
379 int verticalmenu::getpos() {
380 return curelem;
383 void verticalmenu::getpos(int &cur, int &first) {
384 cur = curelem;
385 first = firstdisp;
388 void verticalmenu::setpos(int cur, int first) {
389 curelem = cur;
390 if(first != -1) firstdisp = first;
393 void verticalmenu::setitemcolor(int pos, int color) {
394 if((pos >= 0) && (pos < items.size())) {
395 items[pos].color = color;
399 void verticalmenu::setwindow(textwindow nwindow) {
400 window = nwindow;
401 setcoords(window.x1+1, window.y1+1, window.x2, window.y2);
404 void verticalmenu::remove(int pos) {
405 vector<verticalmenuitem>::iterator ii;
406 int i;
408 if((pos >= 0) && (pos < items.size())) {
409 for(i = 0, ii = items.begin(); ii != items.end() && i < pos; i++, ii++);
410 items.erase(ii);
414 void verticalmenu::close() {
415 window.close();
418 void verticalmenu::checkclear() {
419 if(window.isopen())
420 if(clearonfocuslost)
421 shownelem(curelem, 0);
424 void verticalmenu::intredraw() {
425 bool scf = clearonfocuslost;
427 if(curelem >= 0 && curelem < items.size()) {
428 vector<verticalmenuitem>::iterator ii;
430 for(ii = items.begin()+curelem; ii != items.end(); ii++) {
431 if(ii->kind == ITEM_NORM) {
432 curelem = ii-items.begin();
433 break;
437 for(ii = items.begin()+curelem; ii != items.begin(); ii--) {
438 if(ii->kind == ITEM_NORM) {
439 curelem = ii-items.begin();
440 break;
445 clearonfocuslost = false;
446 redraw();
447 clearonfocuslost = scf;
450 verticalmenu::~verticalmenu() {
453 // --------------------------------------------------------------------------
455 horizontalmenu *currenthmenu;
457 horizontalmenu::horizontalmenu(int x, int y, int normcolor, int selcolor, int framecolor) {
458 ncolor = normcolor;
459 scolor = selcolor;
460 fcolor = framecolor;
461 coordy = y;
462 coordx = x;
463 otherkeys = 0;
466 horizontalmenu::horizontalmenu() {
467 coordy = coordx = 0;
470 horizontalmenu::~horizontalmenu() {
473 #define HM_RIGHT 50001
474 #define HM_LEFT 50002
475 #define HM_CLOSE 50003
477 int horizontalmenu::menu_otherkeys(verticalmenu &ref, int k) {
478 switch(k) {
479 case KEY_RIGHT : return HM_RIGHT;
480 case KEY_LEFT : return HM_LEFT;
481 case KEY_F(10) : return HM_CLOSE;
482 default:
483 if(currenthmenu->otherkeys) {
484 currenthmenu->finished = currenthmenu->otherkeys(*currenthmenu, k);
485 return currenthmenu->finished ? 0 : -1;
489 return -1;
492 void horizontalmenu::additem(int color, const string &text) {
493 horizontalmenuitem i;
494 i.text = text;
495 i.color = color ? color : ncolor;
496 menus.push_back(i);
499 void horizontalmenu::additem(const string &text) {
500 additem(0, text);
503 void horizontalmenu::additemf(int color, const char *fmt, ...) {
504 va_list ap;
505 char buf[1024];
506 va_start(ap, fmt);
507 vsprintf(buf, fmt, ap);
508 va_end(ap);
509 additem(color, buf);
512 void horizontalmenu::additemf(const char *fmt, ...) {
513 va_list ap;
514 char buf[1024];
515 va_start(ap, fmt);
516 vsprintf(buf, fmt, ap);
517 va_end(ap);
518 additem(0, buf);
521 int horizontalmenu::getx(int n) {
522 int i, l = 0;
523 for(i = 0; i < n; i++) l += menus[i].text.size();
524 if(n > 0) l += n*2;
525 return l+coordx;
528 int horizontalmenu::menulen(int n) {
529 verticalmenu m = menus[n].menu;
530 vector<verticalmenu::verticalmenuitem>::iterator i;
531 int l = 0;
533 for(i = m.items.begin(); i != m.items.end(); i++) {
534 if(!i->text.empty() && (i->text.size() > l)) l = i->text.size();
537 return l;
540 void horizontalmenu::redraw() {
541 int sv = selected;
542 selected = -1;
543 draw();
544 selected = sv;
547 void horizontalmenu::draw() {
548 vector<horizontalmenuitem>::iterator i;
549 int n;
551 attrset(ncolor);
552 mvhline(coordy, 0, ' ', COLS);
554 for(n = 0, i = menus.begin(); i != menus.end(); i++, n++) {
555 kgotoxy(getx(n), coordy);
556 if(n == selected) attrset(scolor); else attrset(ncolor);
557 printstring(i->text);
560 refresh();
563 void horizontalmenu::moveelem(int old) {
564 attrset(menus[old].color);
565 kgotoxy(getx(old), coordy);
566 printstring(menus[old].text);
568 attrset(scolor);
569 kgotoxy(getx(selected), coordy);
570 printstring(menus[selected].text);
573 bool horizontalmenu::open(int *hor, int *pulld) {
574 bool done = false;
575 int ch, osel, oact = 0;
576 verticalmenu *m;
578 if((selected < 0) || (selected >= menus.size())) selected = 0;
579 saveline();
580 draw();
582 for(finished = false; !finished; ) {
583 if(!oact) {
584 ch = getkey();
585 if(emacs) ch = emacsbind(ch);
586 } else {
587 ch = oact;
590 osel = selected;
592 switch(ch) {
593 case KEY_RIGHT:
594 if(++selected >= menus.size()) selected = 0;
595 moveelem(osel);
596 break;
598 case KEY_LEFT:
599 if(--selected < 0) selected = menus.size()-1;
600 moveelem(osel);
601 break;
603 case '\r':
604 case KEY_DOWN:
605 m = pulldown(selected);
607 if(!m->items.empty()) {
608 m->scale();
609 m->x2 = m->x1 + menulen(selected) + 1;
610 m->window.x2 = m->x2;
611 currenthmenu = this;
613 int r = m->open();
615 switch(r) {
616 case HM_RIGHT: oact = KEY_RIGHT; break;
617 case HM_LEFT: oact = KEY_LEFT; break;
618 case HM_CLOSE: oact = KEY_F(10); break;
619 default:
620 if(r) {
621 if(pulld) *pulld = r;
622 if(hor) *hor = selected+1;
623 done = finished = true;
627 m->close();
628 if(r == HM_RIGHT || r == HM_LEFT) continue;
629 } else if(!oact) {
630 if(pulld) *pulld = 0;
631 if(hor) *hor = selected+1;
632 done = finished = true;
634 break;
636 case KEY_F(10):
637 case 27:
638 finished = true;
639 break;
641 default:
642 if(otherkeys) {
643 done = finished = (*otherkeys)(*this, ch);
645 break;
648 if(oact == KEY_RIGHT || oact == KEY_LEFT) oact = '\r'; else oact = 0;
651 restoreline();
652 return done;
655 void horizontalmenu::close() {
658 void horizontalmenu::saveline() {
659 screenbuffer.save(0, coordy, COLS, coordy);
662 void horizontalmenu::restoreline() {
663 screenbuffer.restore();
666 verticalmenu *horizontalmenu::pulldown(int n) {
667 if((n >= 0) && (n < menus.size())) {
668 menus[n].menu.setcolor(ncolor, scolor);
669 menus[n].menu.otherkeys = &menu_otherkeys;
670 menus[n].menu.cycled = true;
671 menus[n].menu.setwindow(textwindow(getx(n)-1, coordy+1, getx(n)+2, coordy+6, fcolor));
672 return &menus[n].menu;
673 } else {
674 return 0;
678 // --------------------------------------------------------------------------
680 #ifdef __KTOOL_USE_NAMESPACES
682 using ktool::horizontalmenuitem;
684 #endif
686 horizontalmenuitem::horizontalmenuitem() {
689 horizontalmenuitem::horizontalmenuitem(const horizontalmenuitem &a) {
690 text = a.text;
691 color = a.color;
692 menu = a.menu;
695 horizontalmenuitem::~horizontalmenuitem() {