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
27 verticalmenu::verticalmenu(int px1
, int py1
, int px2
, int py2
, int pncolor
, int pscolor
)
28 : abstractuicontrol() {
30 setcolor(pncolor
, pscolor
);
31 setcoords(px1
, py1
, px2
, py2
);
34 verticalmenu::verticalmenu(int pncolor
, int pscolor
)
35 : abstractuicontrol() {
37 setcolor(pncolor
, pscolor
);
40 void verticalmenu::initmembers() {
41 firstdisp
= curelem
= 0;
44 clearonfocuslost
= cycled
= exitonedges
= false;
47 void verticalmenu::setcolor(int pncolor
, int pscolor
) {
48 ncolor
= pncolor
, scolor
= pscolor
;
51 void verticalmenu::clear() {
55 bool verticalmenu::empty() {
59 void verticalmenu::setcoords(int nx1
, int ny1
, int nx2
, int ny2
) {
66 void verticalmenu::additemf(const char *fmt
, ...) {
72 void verticalmenu::additem(const string
&text
) {
73 additem(ncolor
, 0, text
);
76 void verticalmenu::additem(int color
, void *ref
, const string
&text
) {
79 i
.color
= color
? color
: ncolor
;
85 void verticalmenu::additemf(int color
, void *ref
, const char *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
, ...) {
98 additem(color
, (void *) ref
, buf
);
101 void verticalmenu::addline() {
105 void verticalmenu::addline(int color
, const char *fmt
, ...) {
112 vsprintf(buf
, fmt
, ap
);
124 bool verticalmenu::shownelem(int n
, int selected
) {
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
]) {
148 attrset(selected
&& (item
.kind
== ITEM_NORM
) ?
149 scolor
: item
.color
);
150 else attrset(ncolor
);
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;
174 return item
.kind
== ITEM_NORM
;
177 void verticalmenu::showall() {
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) {
198 for(p
= firstdisp
; (p
< firstdisp
+y2
-y1
) && (p
< items
.size()); p
++) {
199 kgotoxy(x1
, y1
+p
-firstdisp
);
203 for(; p
< firstdisp
+y2
-y1
; p
++) {
204 mvhline(y1
+p
-firstdisp
, x1
, ' ', x2
-x1
);
208 void verticalmenu::redraw() {
210 kgotoxy(x1
, y1
+curelem
-firstdisp
);
212 if(!clearonfocuslost
)
214 shownelem(curelem
, 1);
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() {
227 if(!window
.empty()) window
.open();
231 kgotoxy(x1
, y1
+curelem
-firstdisp
);
232 if(clearonfocuslost
&& curelem
>= 0)
233 shownelem(curelem
, 1);
235 finished
= aborted
= false;
238 if(idle
) go
= keypressed(); else go
= 1;
241 if(emacs
) k
= emacsbind(k
);
257 shownelem(curelem
, 0);
258 if(--curelem
< firstdisp
) {
259 firstdisp
= curelem
- y2
+ y1
+ 1;
262 int savecurelem
= curelem
+1;
265 if(!shownelem(curelem
, 1)) {
272 shownelem(curelem
= savecurelem
, 1);
276 } else if(exitonedges
) {
279 curelem
= items
.size()-1;
280 if((firstdisp
= curelem
-y2
+y1
+1) < 0) firstdisp
= 0;
287 if(curelem
< items
.size()-1) {
288 shownelem(curelem
++, 0);
290 if(curelem
> firstdisp
+y2
-y1
-1) {
291 firstdisp
+= y2
- y1
;
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);
305 } else if(exitonedges
) {
308 curelem
= firstdisp
= 0;
315 if((curelem
-= y2
-y1
) < 0) {
316 if(finished
= exitonedges
) continue;
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;
338 curelem
= firstdisp
= 0;
340 finished
= finished
|| exitonedges
;
344 curelem
= items
.size()-1;
345 if((firstdisp
= curelem
-y2
+y1
+1) < 0) firstdisp
= 0;
347 finished
= finished
|| exitonedges
;
352 if((go
= (*otherkeys
)(*this, k
)) != -1) {
360 if(idle
) (*idle
)(*this);
367 int verticalmenu::getcount() {
371 int verticalmenu::getlastkey() {
375 void *verticalmenu::getref(int n
) {
376 return (n
>= 0) && (n
< items
.size()) ? items
[n
].ref
: 0;
379 int verticalmenu::getpos() {
383 void verticalmenu::getpos(int &cur
, int &first
) {
388 void verticalmenu::setpos(int cur
, int first
) {
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
) {
401 setcoords(window
.x1
+1, window
.y1
+1, window
.x2
, window
.y2
);
404 void verticalmenu::remove(int pos
) {
405 vector
<verticalmenuitem
>::iterator ii
;
408 if((pos
>= 0) && (pos
< items
.size())) {
409 for(i
= 0, ii
= items
.begin(); ii
!= items
.end() && i
< pos
; i
++, ii
++);
414 void verticalmenu::close() {
418 void verticalmenu::checkclear() {
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();
437 for(ii
= items
.begin()+curelem
; ii
!= items
.begin(); ii
--) {
438 if(ii
->kind
== ITEM_NORM
) {
439 curelem
= ii
-items
.begin();
445 clearonfocuslost
= false;
447 clearonfocuslost
= scf
;
450 verticalmenu::~verticalmenu() {
453 // --------------------------------------------------------------------------
455 horizontalmenu
*currenthmenu
;
457 horizontalmenu::horizontalmenu(int x
, int y
, int normcolor
, int selcolor
, int framecolor
) {
466 horizontalmenu::horizontalmenu() {
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
) {
479 case KEY_RIGHT
: return HM_RIGHT
;
480 case KEY_LEFT
: return HM_LEFT
;
481 case KEY_F(10) : return HM_CLOSE
;
483 if(currenthmenu
->otherkeys
) {
484 currenthmenu
->finished
= currenthmenu
->otherkeys(*currenthmenu
, k
);
485 return currenthmenu
->finished
? 0 : -1;
492 void horizontalmenu::additem(int color
, const string
&text
) {
493 horizontalmenuitem i
;
495 i
.color
= color
? color
: ncolor
;
499 void horizontalmenu::additem(const string
&text
) {
503 void horizontalmenu::additemf(int color
, const char *fmt
, ...) {
507 vsprintf(buf
, fmt
, ap
);
512 void horizontalmenu::additemf(const char *fmt
, ...) {
516 vsprintf(buf
, fmt
, ap
);
521 int horizontalmenu::getx(int n
) {
523 for(i
= 0; i
< n
; i
++) l
+= menus
[i
].text
.size();
528 int horizontalmenu::menulen(int n
) {
529 verticalmenu m
= menus
[n
].menu
;
530 vector
<verticalmenu::verticalmenuitem
>::iterator i
;
533 for(i
= m
.items
.begin(); i
!= m
.items
.end(); i
++) {
534 if(!i
->text
.empty() && (i
->text
.size() > l
)) l
= i
->text
.size();
540 void horizontalmenu::redraw() {
547 void horizontalmenu::draw() {
548 vector
<horizontalmenuitem
>::iterator i
;
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
);
563 void horizontalmenu::moveelem(int old
) {
564 attrset(menus
[old
].color
);
565 kgotoxy(getx(old
), coordy
);
566 printstring(menus
[old
].text
);
569 kgotoxy(getx(selected
), coordy
);
570 printstring(menus
[selected
].text
);
573 bool horizontalmenu::open(int *hor
, int *pulld
) {
575 int ch
, osel
, oact
= 0;
578 if((selected
< 0) || (selected
>= menus
.size())) selected
= 0;
582 for(finished
= false; !finished
; ) {
585 if(emacs
) ch
= emacsbind(ch
);
594 if(++selected
>= menus
.size()) selected
= 0;
599 if(--selected
< 0) selected
= menus
.size()-1;
605 m
= pulldown(selected
);
607 if(!m
->items
.empty()) {
609 m
->x2
= m
->x1
+ menulen(selected
) + 1;
610 m
->window
.x2
= m
->x2
;
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;
621 if(pulld
) *pulld
= r
;
622 if(hor
) *hor
= selected
+1;
623 done
= finished
= true;
628 if(r
== HM_RIGHT
|| r
== HM_LEFT
) continue;
630 if(pulld
) *pulld
= 0;
631 if(hor
) *hor
= selected
+1;
632 done
= finished
= true;
643 done
= finished
= (*otherkeys
)(*this, ch
);
648 if(oact
== KEY_RIGHT
|| oact
== KEY_LEFT
) oact
= '\r'; else oact
= 0;
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
;
678 // --------------------------------------------------------------------------
680 #ifdef __KTOOL_USE_NAMESPACES
682 using ktool::horizontalmenuitem
;
686 horizontalmenuitem::horizontalmenuitem() {
689 horizontalmenuitem::horizontalmenuitem(const horizontalmenuitem
&a
) {
695 horizontalmenuitem::~horizontalmenuitem() {