1 /*
2 This file is part of Kismet
3
4 Kismet is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 Kismet is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with Kismet; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19 #include "config.h"
20
21 #include <sys/types.h>
22 #include <dirent.h>
23 #include <sys/stat.h>
24 #include <unistd.h>
25
26 // Panel has to be here to pass configure, so just test these
27 #if (defined(HAVE_LIBNCURSES) || defined (HAVE_LIBCURSES))
28
29 #include "kis_panel_widgets.h"
30 #include "kis_panel_frontend.h"
31 #include "timetracker.h"
32 #include "messagebus.h"
33
34 #define WIN_CENTER(h, w) (LINES / 2) - ((h) / 2), (COLS / 2) - ((w) / 2), (h), (w)
35
Strlen(string str)36 unsigned int Kis_Panel_Specialtext::Strlen(string str) {
37 int npos = 0;
38 int escape = 0;
39
40 for (unsigned int pos = 0; pos < str.size(); pos++) {
41 if (str[pos] == '\004') {
42 escape = 1;
43 continue;
44 }
45
46 if (escape) {
47 escape = 0;
48
49 if (str[pos] == 'C') {
50 // Color escape code:
51 // \004Ccolorpref;text
52
53 // Catch malforms at the end
54 if (pos >= str.length()) {
55 continue;
56 }
57
58 size_t colorend = str.find(";", pos + 1);
59
60 if (colorend == string::npos)
61 continue;
62
63 pos = colorend;
64 }
65
66 continue;
67 }
68
69 npos++;
70 }
71
72 return npos;
73 }
74
Mvwaddnstr(WINDOW * win,int y,int x,string str,int n,Kis_Panel * panel,int colorpair)75 void Kis_Panel_Specialtext::Mvwaddnstr(WINDOW *win, int y, int x, string str, int n,
76 Kis_Panel *panel, int colorpair) {
77 int npos = 0;
78 int escape = 0;
79
80 for (unsigned int pos = 0; pos < str.size(); pos++) {
81 if (str[pos] == '\004') {
82 escape = 1;
83 continue;
84 }
85
86 // Handle the attributes
87 if (escape) {
88 if (str[pos] == 'u') {
89 wattron(win, WA_UNDERLINE);
90 } else if (str[pos] == 'U') {
91 wattroff(win, WA_UNDERLINE);
92 } else if (str[pos] == 's') {
93 wattron(win, WA_STANDOUT);
94 } else if (str[pos] == 'S') {
95 wattroff(win, WA_STANDOUT);
96 } else if (str[pos] == 'r') {
97 wattron(win, WA_REVERSE);
98 } else if (str[pos] == 'R') {
99 wattroff(win, WA_REVERSE);
100 } else if (str[pos] == 'b') {
101 if ((colorpair & A_BOLD) == 0)
102 wattron(win, WA_BOLD);
103 } else if (str[pos] == 'B') {
104 if ((colorpair & A_BOLD) == 0)
105 wattroff(win, WA_BOLD);
106 } else if (str[pos] == 'C') {
107 // Color escape code:
108 // \004Ccolorpref;text
109
110 // Catch malforms at the end
111 if (pos >= str.length()) {
112 continue;
113 }
114
115 size_t colorend = str.find(";", pos + 1);
116
117 if (colorend != string::npos) {
118 string cpref = str.substr(pos + 1, colorend - pos - 1);
119 int c = 0;
120
121
122 panel->ColorFromPref(c, cpref);
123 pos = colorend;
124
125 if (c > 0)
126 wattrset(win, c);
127 }
128 } else {
129 // fprintf(stderr, "invalid escape '%c'\n", str[pos]);
130 // Backfill the unescaped data
131 escape = 0;
132 if (npos <= n) {
133 mvwaddch(win, y, x + npos, '\\');
134 npos++;
135 }
136 if (npos <= n) {
137 mvwaddch(win, y, x + npos, str[npos]);
138 npos++;
139 }
140 }
141
142 escape = 0;
143 continue;
144 }
145
146 // Otherwise write the character, if we can. We DON'T abort here,
147 // because we need to process to the end of the string to turn off
148 // any attributes that were on
149 if (npos <= n) {
150 mvwaddch(win, y, x + npos, str[pos]);
151 npos++;
152 continue;
153 }
154 }
155 }
156
Kis_Panel_Color()157 Kis_Panel_Color::Kis_Panel_Color() {
158 // nextindex = COLORS + 1;
159 nextindex = 1;
160 }
161
AddColor(string color,string pref)162 int Kis_Panel_Color::AddColor(string color, string pref) {
163 map<string, Kis_Panel_Color::color_rec>::iterator cimi;
164 short nums[2] = {0, 0};
165 int bold = 0;
166 int pair;
167
168 if ((cimi = color_index_map.find(StrLower(color))) != color_index_map.end()) {
169 return cimi->second.colorindex;
170 }
171
172 if (nextindex == COLOR_PAIRS - 1) {
173 // fprintf(stderr, "debug - too many color pairs\n");
174 return COLOR_PAIR(0);
175 }
176
177 vector<string> colorpair = StrTokenize(color, ",");
178
179 if (colorpair.size() < 1)
180 colorpair.push_back("white");
181 if (colorpair.size() < 2)
182 colorpair.push_back("black");
183
184 colorpair[0] = StrLower(colorpair[0]);
185 colorpair[1] = StrLower(colorpair[1]);
186
187 for (unsigned int x = 0; x < 2; x++) {
188 string clr = colorpair[x];
189
190 if (clr == "grey" || clr == "gray")
191 clr = "hi-black";
192
193 // First, find if theres a hi-
194 if (clr.substr(0, 3) == "hi-") {
195 bold = 1;
196 clr = clr.substr(3, clr.length() - 3);
197 }
198
199 // Then match all the colors
200 if (clr == "default")
201 nums[x] = -1;
202 else if (clr == "black")
203 nums[x] = COLOR_BLACK;
204 else if (clr == "red")
205 nums[x] = COLOR_RED;
206 else if (clr == "green")
207 nums[x] = COLOR_GREEN;
208 else if (clr == "yellow")
209 nums[x] = COLOR_YELLOW;
210 else if (clr == "blue")
211 nums[x] = COLOR_BLUE;
212 else if (clr == "magenta")
213 nums[x] = COLOR_MAGENTA;
214 else if (clr == "cyan")
215 nums[x] = COLOR_CYAN;
216 else if (clr == "white")
217 nums[x] = COLOR_WHITE;
218 }
219
220 // fprintf(stderr, "debug - color init_pair %d vals %d, %d\n", nextindex, nums[0], nums[1]);
221 init_pair(nextindex, nums[0], nums[1]);
222
223 pair = COLOR_PAIR(nextindex);
224
225 if (bold) {
226 pair |= A_BOLD;
227 }
228
229 color_rec cr;
230 cr.pref = pref;
231 cr.color[0] = colorpair[0];
232 cr.color[1] = colorpair[1];
233 cr.colorindex = pair;
234
235 color_index_map[StrLower(color)] = cr;
236 nextindex++;
237
238 return pair;
239 }
240
RemapAllColors(string oldcolor,string newcolor,ConfigFile * conf)241 void Kis_Panel_Color::RemapAllColors(string oldcolor, string newcolor,
242 ConfigFile *conf) {
243 map<string, Kis_Panel_Color::color_rec>::iterator cri;
244 string o = StrLower(oldcolor), n = StrLower(newcolor);
245
246 for (cri = color_index_map.begin(); cri != color_index_map.end(); ++cri) {
247 int s = 0;
248
249 if (cri->second.pref == "")
250 continue;
251
252 if (cri->second.color[0] == o) {
253 cri->second.color[0] = n;
254 s = 1;
255 }
256
257 if (cri->second.color[1] == o) {
258 cri->second.color[1] = n;
259 s = 1;
260 }
261
262 if (s)
263 conf->SetOpt(cri->second.pref, cri->second.color[0] + string(",") +
264 cri->second.color[1], time(0));
265 }
266 }
267
panelint_draw_timer(TIMEEVENT_PARMS)268 int panelint_draw_timer(TIMEEVENT_PARMS) {
269 return ((PanelInterface *) parm)->DrawInterface();
270 }
271
272 // Pollable panel interface driver
PanelInterface()273 PanelInterface::PanelInterface() {
274 fprintf(stderr, "FATAL OOPS: PanelInterface() w/ no globalreg\n");
275 exit(1);
276 }
277
PanelInterface(GlobalRegistry * in_globalreg)278 PanelInterface::PanelInterface(GlobalRegistry *in_globalreg) {
279 globalreg = in_globalreg;
280
281 // Init curses
282 initscr();
283 raw();
284 cbreak();
285 noecho();
286 keypad(stdscr, 1);
287 meta(stdscr, 1);
288 mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, NULL);
289 start_color();
290 use_default_colors();
291
292 draweventid =
293 globalreg->timetracker->RegisterTimer(SERVER_TIMESLICES_SEC / 2,
294 NULL, 1, &panelint_draw_timer,
295 (void *) this);
296
297 globalreg->RegisterPollableSubsys(this);
298
299 getmaxyx(stdscr, hsize, vsize);
300 };
301
~PanelInterface()302 PanelInterface::~PanelInterface() {
303 for (unsigned int x = 0; x < live_panels.size(); x++)
304 delete live_panels[x];
305
306 globalreg->timetracker->RemoveTimer(draweventid);
307
308 globalreg->RemovePollableSubsys(this);
309
310 erase();
311
312 if (isendwin() == 0)
313 endwin();
314 }
315
MergeSet(int in_max_fd,fd_set * out_rset,fd_set * out_wset)316 int PanelInterface::MergeSet(int in_max_fd, fd_set *out_rset, fd_set *out_wset) {
317 if (globalreg->spindown)
318 return in_max_fd;
319
320 if (live_panels.size() == 0)
321 return in_max_fd;
322
323 // add stdin to the listen set
324 FD_SET(fileno(stdin), out_rset);
325
326 if (in_max_fd < fileno(stdin))
327 return fileno(stdin);
328
329 return in_max_fd;
330 }
331
Poll(fd_set & in_rset,fd_set & in_wset)332 int PanelInterface::Poll(fd_set& in_rset, fd_set& in_wset) {
333 if (live_panels.size() == 0)
334 return 0;
335
336 if (FD_ISSET(fileno(stdin), &in_rset)) {
337 // Poll via the top of the stack
338 int ret;
339
340 ret = live_panels[live_panels.size() - 1]->Poll();
341 DrawInterface();
342
343 if (ret < 0)
344 globalreg->fatal_condition = 1;
345 return ret;
346 }
347
348 return 0;
349 }
350
ResizeInterface()351 void PanelInterface::ResizeInterface() {
352 int nh, nv;
353
354 endwin();
355 refresh();
356 clear();
357
358 getmaxyx(stdscr, nh, nv);
359
360 if (hsize == nh && vsize == nv) {
361 return;
362 }
363
364 for (unsigned int x = 0; x < live_panels.size(); x++) {
365 // If it's full screen, keep it full screen, otherwise
366 // re-center it
367 if (live_panels[x]->FetchSzy() == hsize &&
368 live_panels[x]->FetchSzx() == vsize) {
369 live_panels[x]->Position(0, 0, nh, nv);
370 } else {
371 int rsy = live_panels[x]->FetchSzy(), rsx = live_panels[x]->FetchSzx();
372
373 if (rsy > nh)
374 rsy = nh;
375
376 if (rsx > nv)
377 rsx = nv;
378
379 live_panels[x]->Position(WIN_CENTER(rsy, rsx));
380 }
381 }
382
383 hsize = nh;
384 vsize = nv;
385 }
386
DrawInterface()387 int PanelInterface::DrawInterface() {
388 // Draw all the panels
389 for (unsigned int x = 0; x < live_panels.size(); x++) {
390 live_panels[x]->DrawPanel();
391 }
392
393 // Call the update
394 update_panels();
395 doupdate();
396
397 // Delete dead panels from before
398 for (unsigned int x = 0; x < dead_panels.size(); x++) {
399 delete(dead_panels[x]);
400 }
401 dead_panels.clear();
402
403 return 1;
404 }
405
AddPanel(Kis_Panel * in_panel)406 void PanelInterface::AddPanel(Kis_Panel *in_panel) {
407 live_panels.push_back(in_panel);
408 }
409
KillPanel(Kis_Panel * in_panel)410 void PanelInterface::KillPanel(Kis_Panel *in_panel) {
411 for (unsigned int x = 0; x < live_panels.size(); x++) {
412 if (live_panels[x] == in_panel) {
413 dead_panels.push_back(in_panel);
414 live_panels.erase(live_panels.begin() + x);
415 }
416 }
417 }
418
Kis_Panel_Component(GlobalRegistry * in_globalreg,Kis_Panel * in_panel)419 Kis_Panel_Component::Kis_Panel_Component(GlobalRegistry *in_globalreg,
420 Kis_Panel *in_panel) {
421 globalreg = in_globalreg;
422 parent_panel = in_panel;
423 window = in_panel->FetchDrawWindow();
424 visible = 0;
425 active = 0;
426
427 sx = sy = ex = ey = lx = ly = 0;
428 px = py = 0;
429 mx = my = 0;
430 layout_dirty = 0;
431
432 cb_switch = cb_activate = NULL;
433
434 color_active = color_inactive = 0;
435
436 color_active_pref = "panel_text_color";
437 color_inactive_pref = "panel_textdis_color";
438
439 name = "GENERIC_WIDGET";
440 }
441
SetCallback(int cbtype,int (* cb)(COMPONENT_CALLBACK_PARMS),void * aux)442 void Kis_Panel_Component::SetCallback(int cbtype, int (*cb)(COMPONENT_CALLBACK_PARMS),
443 void *aux) {
444 switch (cbtype) {
445 case COMPONENT_CBTYPE_SWITCH:
446 cb_switch = cb;
447 cb_switch_aux = aux;
448 break;
449 case COMPONENT_CBTYPE_ACTIVATED:
450 cb_activate = cb;
451 cb_activate_aux = aux;
452 break;
453 }
454 }
455
ClearCallback(int cbtype)456 void Kis_Panel_Component::ClearCallback(int cbtype) {
457 switch (cbtype) {
458 case COMPONENT_CBTYPE_SWITCH:
459 cb_switch = NULL;
460 break;
461 case COMPONENT_CBTYPE_ACTIVATED:
462 cb_activate = NULL;
463 break;
464 }
465 }
466
Kis_Panel_Packbox(GlobalRegistry * in_globalreg,Kis_Panel * in_panel)467 Kis_Panel_Packbox::Kis_Panel_Packbox(GlobalRegistry *in_globalreg,
468 Kis_Panel *in_panel) :
469 Kis_Panel_Component(in_globalreg, in_panel) {
470 homogenous = 0;
471 packing = 0;
472 spacing = 0;
473 center = 0;
474
475 name = "GENERIC_PACKBOX";
476 }
477
~Kis_Panel_Packbox()478 Kis_Panel_Packbox::~Kis_Panel_Packbox() {
479 // Nothing to do really
480 }
481
GetVisible()482 int Kis_Panel_Packbox::GetVisible() {
483 if (visible == 0)
484 return 0;
485
486 int any_vis = 0;
487
488 for (list<Kis_Panel_Packbox::packbox_details>::iterator x = packed_items.begin();
489 x != packed_items.end(); ++x) {
490 if ((*x).widget->GetVisible()) {
491 any_vis = 1;
492 break;
493 }
494 }
495
496 if (any_vis)
497 return 1;
498
499 return 0;
500 }
501
Pack_Start(Kis_Panel_Component * in_widget,int in_fill,int in_padding)502 void Kis_Panel_Packbox::Pack_Start(Kis_Panel_Component *in_widget, int in_fill,
503 int in_padding) {
504 packbox_details det;
505
506 det.widget = in_widget;
507 det.fill = in_fill;
508 det.padding = in_padding;
509
510 packed_items.push_front(det);
511
512 layout_dirty = 1;
513 }
514
Pack_End(Kis_Panel_Component * in_widget,int in_fill,int in_padding)515 void Kis_Panel_Packbox::Pack_End(Kis_Panel_Component *in_widget, int in_fill,
516 int in_padding) {
517 packbox_details det;
518
519 det.widget = in_widget;
520 det.fill = in_fill;
521 det.padding = in_padding;
522
523 packed_items.push_back(det);
524
525 layout_dirty = 1;
526 }
527
Pack_Before_Named(string in_name,Kis_Panel_Component * in_widget,int in_fill,int in_padding)528 void Kis_Panel_Packbox::Pack_Before_Named(string in_name,
529 Kis_Panel_Component *in_widget,
530 int in_fill, int in_padding) {
531 list<Kis_Panel_Packbox::packbox_details>::iterator i;
532 packbox_details det;
533
534 det.widget = in_widget;
535 det.fill = in_fill;
536 det.padding = in_padding;
537
538 layout_dirty = 1;
539
540 for (i = packed_items.begin(); i != packed_items.end(); ++i) {
541 if ((*i).widget->GetName() == in_name) {
542 packed_items.insert(i, det);
543 return;
544 }
545 }
546
547 packed_items.push_back(det);
548 return;
549 }
550
Pack_After_Named(string in_name,Kis_Panel_Component * in_widget,int in_fill,int in_padding)551 void Kis_Panel_Packbox::Pack_After_Named(string in_name,
552 Kis_Panel_Component *in_widget,
553 int in_fill, int in_padding) {
554 list<Kis_Panel_Packbox::packbox_details>::iterator i;
555 packbox_details det;
556
557 det.widget = in_widget;
558 det.fill = in_fill;
559 det.padding = in_padding;
560
561 layout_dirty = 1;
562
563 for (i = packed_items.begin(); i != packed_items.end(); ++i) {
564 if ((*i).widget->GetName() == in_name) {
565 packed_items.insert(++i, det);
566 return;
567 }
568 }
569
570 packed_items.push_back(det);
571 return;
572 }
573
Pack_Remove(Kis_Panel_Component * in_widget)574 void Kis_Panel_Packbox::Pack_Remove(Kis_Panel_Component *in_widget) {
575 list<Kis_Panel_Packbox::packbox_details>::iterator i;
576
577 for (i = packed_items.begin(); i != packed_items.end(); ++i) {
578 if ((*i).widget == in_widget) {
579 packed_items.erase(i);
580 layout_dirty = 1;
581 return;
582 }
583 }
584 }
585
Pack_Widgets()586 void Kis_Panel_Packbox::Pack_Widgets() {
587 int size, psize, msize, pos;
588 list<Kis_Panel_Packbox::packbox_details>::iterator i;
589
590 if (visible == 0)
591 return;
592
593 // Get the packing direction
594 if (packing == 0) {
595 size = lx;
596 } else {
597 size = ly;
598 }
599
600 // If we're homogenous, we divide by the # of widgets, find out if we're too
601 // small for any of them, and decrease until we can fit them
602 if (homogenous) {
603 int ndivs = packed_items.size();
604 int perbox = 0;
605
606 for (i = packed_items.begin(); i != packed_items.end(); ++i) {
607 if ((*i).widget->GetVisible() == 0) {
608 ndivs--;
609 continue;
610 }
611 }
612
613 for (i = packed_items.begin(); i != packed_items.end(); ++i) {
614 int wmsize;
615
616 if ((*i).widget->GetVisible() == 0) {
617 continue;
618 }
619
620 perbox = (int) ((float) (size - (spacing * (ndivs - 1))) / ndivs);
621
622 if (packing == 0) {
623 wmsize = (*i).widget->GetMinX();
624 } else {
625 wmsize = (*i).widget->GetMinY();
626 }
627
628 // If someone can't fit, decrease the number of divisions until we
629 // can, and we just don't draw those widgets. Yeah, it sucks,
630 // don't over-pack a small frame
631 if (wmsize > perbox) {
632 // If we simply can't fix the widget in, period, then bail on
633 // drawing.
634 if (ndivs <= 1) {
635 // fprintf(stderr, "we couldn't find, wah\n");
636 return;
637 }
638
639 ndivs -= 1;
640 i = packed_items.begin();
641 continue;
642 }
643 }
644
645 i = packed_items.begin();
646 for (int x = 0; x < ndivs && i != packed_items.end(); x++, ++i) {
647 if ((*i).widget->GetVisible() == 0) {
648 x--;
649 continue;
650 }
651
652 // Set the position of each widget
653 int ww = perbox - ((*i).padding * 2);
654 int co = 0;
655
656 // Get the preferred size (or best we can do) OR the fill
657 int psize = 0, op = 0;
658 if ((*i).fill == 0) {
659 if (packing == 0) {
660 psize = (*i).widget->GetPrefX() + ((*i).padding * 2);
661 op = ly;
662 } else {
663 psize = (*i).widget->GetPrefY() + ((*i).padding * 2);
664 op = lx;
665 }
666
667 if (psize > ww)
668 psize = ww;
669 } else {
670 psize = ww;
671 }
672
673 if (center && psize != ww) {
674 co = (ww - psize) / 2;
675 }
676
677 if (packing == 0) {
678 (*i).widget->SetPosition(
679 sx + (perbox * x) + (*i).padding + co, sy,
680 sx + (perbox * x) + (*i).padding + co + psize, sy + op);
681 } else {
682 (*i).widget->SetPosition(
683 sx, sy + (perbox * x) + (*i).padding + co, sx + op,
684 sy + (perbox * x) + (*i).padding + co + psize);
685 }
686
687 }
688
689 return;
690 // Done w/ homogenous spacing
691 }
692
693 // Non-homogenous spacing
694 // Pass 1: Can we fit everyone who has a preferred size in? If we can, then
695 // we can just start expanding them (or just plain draw them as is if we
696 // don't have any filler). Calculate preferred and minimum sizes simultaneously
697 // to save another iteration.
698 psize = 0;
699 msize = 0;
700 for (i = packed_items.begin(); i != packed_items.end(); ++i) {
701 if ((*i).widget->GetVisible() == 0)
702 continue;
703
704 if (packing == 0) {
705 psize += (*i).widget->GetPrefX() + ((*i).padding * 2);
706 msize += (*i).widget->GetMinX() + ((*i).padding * 2);
707 } else {
708 psize += (*i).widget->GetPrefY() + ((*i).padding * 2);
709 msize += (*i).widget->GetMinY() + ((*i).padding * 2);
710 }
711 }
712
713 // If we can't fit the preferred, can we fit the minimum?
714 if (psize > size) {
715 // fprintf(stderr, "debug - %p can't fit preferred\n", this);
716 if (msize <= size) {
717 // fprintf(stderr, "debug - %p can fit in size\n", this);
718 pos = 0;
719 // Fit them via minsize, giving them space from the free
720 // bucket so long as we have it
721 int bucket = size - msize;
722
723 // fprintf(stderr, "debug - %p has bucket %d for items, min %d\n", this, bucket, msize);
724
725 i = packed_items.begin();
726 for (int x = 0; i != packed_items.end(); ++i, x++) {
727 if ((*i).widget->GetVisible() == 0)
728 continue;
729
730 int mp, pp, op;
731
732 if (packing == 0) {
733 mp = (*i).widget->GetMinX();
734 pp = (*i).widget->GetPrefX();
735 /*
736 op = (*i).widget->GetPrefY();
737 if (op > ly || op == 0)
738 op = ly;
739 */
740 op = ly;
741 } else {
742 mp = (*i).widget->GetMinY();
743 pp = (*i).widget->GetPrefY();
744 /*
745 op = (*i).widget->GetPrefX();
746 if (op > lx || op == 0)
747 op = lx;
748 */
749 op = lx;
750 }
751
752 int ww;
753 ww = mp + ((*i).padding * 2);
754 // fprintf(stderr, "debug - %p item %d gets %d\n", this, x, ww);
755 if (bucket > 0 && mp < pp) {
756 int delta = pp - mp;
757 if (delta > bucket)
758 delta = bucket;
759 // fprintf(stderr, "debug - %p gave %d to item %d min %d wanted %d was %d now %d\n", this, delta, x, mp, pp - mp, ww, ww+delta);
760 bucket -= delta;
761 ww += delta;
762 }
763
764 if (packing == 0) {
765 (*i).widget->SetPosition(
766 sx + (spacing * x) + pos, sy,
767 sx + (spacing * x) + pos + ww, sy + op);
768 } else {
769 (*i).widget->SetPosition(
770 sx, sy + (spacing * x) + pos,
771 sx + op, sy + (spacing * x) + pos + ww);
772 }
773
774 pos += ww;
775 }
776 }
777
778 return;
779 }
780
781 /* Otherwise, we can more than fit our widgets...
782 * So the first order of business, find out how many are set to expand,
783 * and how much slush space we have to give them */
784 // fprintf(stderr, "debug - %p we can fit all preferred\n", this);
785 int bucket = 0;
786 int num_fill = 0;
787 for (i = packed_items.begin(); i != packed_items.end(); ++i) {
788 int pp;
789
790 if ((*i).widget->GetVisible() == 0)
791 continue;
792
793 if (packing == 0) {
794 pp = (*i).widget->GetPrefX();
795 } else {
796 pp = (*i).widget->GetPrefY();
797 }
798
799 /* Add up all the ones which aren't expanding to let us know
800 * how much we can give to the ones we can give more to */
801 if ((*i).fill == 0) {
802 bucket += pp;
803 } else {
804 num_fill++;
805 }
806 }
807
808 // Reclaim our variable - our free bucket is the remainder of unclaimed
809 // stuff
810 bucket = size - bucket - (spacing * (packed_items.size() - 1));
811 // fprintf(stderr, "debug - %p bucket %d fill %d\n", this, bucket, num_fill);
812
813 // Distribute the bucket over the expandable widgets, position, and draw
814 pos = 0;
815 i = packed_items.begin();
816 for (int x = 0; i != packed_items.end(); ++i, x++) {
817 int pp, op;
818
819 if ((*i).widget->GetVisible() == 0)
820 continue;
821
822 if (packing == 0) {
823 pp = (*i).widget->GetPrefX();
824 /*
825 op = (*i).widget->GetPrefY();
826 if (op > ly || op == 0)
827 op = ly;
828 */
829 op = ly;
830 } else {
831 pp = (*i).widget->GetPrefY();
832 /*
833 op = (*i).widget->GetPrefX();
834 if (op > lx || op == 0)
835 op = lx;
836 */
837 op = lx;
838 }
839
840 // Disperse the bucket over the items we have left
841 if ((*i).fill != 0 && num_fill != 0) {
842 pp = bucket / num_fill;
843 bucket = bucket - pp;
844 num_fill--;
845 }
846
847 if (packing == 0) {
848 (*i).widget->SetPosition(
849 sx + pos, sy,
850 sx + pos + pp, sy + op);
851 } else {
852 (*i).widget->SetPosition(
853 sx, sy + pos, sx + op, sy + pos + pp);
854 }
855
856 pos += pp + spacing;
857 }
858 }
859
DrawComponent()860 void Kis_Panel_Packbox::DrawComponent() {
861 list<Kis_Panel_Packbox::packbox_details>::iterator i;
862
863 if (visible == 0)
864 return;
865
866 for (i = packed_items.begin(); i != packed_items.end(); ++i) {
867 if ((*i).widget->GetLayoutDirty()) {
868 layout_dirty = 1;
869 break;
870 }
871 }
872
873 if (layout_dirty) {
874 Pack_Widgets();
875 layout_dirty = 0;
876 }
877
878 for (i = packed_items.begin(); i != packed_items.end(); ++i) {
879 (*i).widget->DrawComponent();
880 (*i).widget->SetLayoutDirty(0);
881 }
882 }
883
Kis_Menu(GlobalRegistry * in_globalreg,Kis_Panel * in_panel)884 Kis_Menu::Kis_Menu(GlobalRegistry *in_globalreg, Kis_Panel *in_panel) :
885 Kis_Panel_Component(in_globalreg, in_panel) {
886 globalreg = in_globalreg;
887 cur_menu = -1;
888 cur_item = -1;
889 sub_item = -1;
890 sub_menu = -1;
891 mouse_triggered = 0;
892 menuwin = NULL;
893 submenuwin = NULL;
894 text_color = border_color = disable_color = 0;
895
896 parent_panel->InitColorPref("menu_text_color", "white,blue");
897 parent_panel->InitColorPref("menu_border_color", "cyan,blue");
898 parent_panel->InitColorPref("menu_disable_color", "cyan,blue");
899 }
900
~Kis_Menu()901 Kis_Menu::~Kis_Menu() {
902 ClearMenus();
903
904 if (menuwin != NULL)
905 delwin(menuwin);
906 if (submenuwin != NULL)
907 delwin(submenuwin);
908 }
909
AddMenu(string in_text,int targ_char)910 int Kis_Menu::AddMenu(string in_text, int targ_char) {
911 _menu *menu = new _menu;
912
913 menu->text = in_text;
914 if (targ_char < 0 || targ_char > (int) in_text.length() - 1)
915 menu->targchar = -1;
916 else
917 menu->targchar = targ_char;
918
919 menu->width = 0;
920
921 menu->id = menubar.size();
922
923 menu->submenu = 0;
924 menu->visible = 1;
925 menu->checked = -1;
926
927 menubar.push_back(menu);
928
929 return menu->id;
930 }
931
SetMenuVis(int in_menu,int in_vis)932 void Kis_Menu::SetMenuVis(int in_menu, int in_vis) {
933 if (in_menu < 0 || in_menu > (int) menubar.size() - 1)
934 return;
935
936 menubar[in_menu]->visible = in_vis;
937 }
938
AddMenuItem(string in_text,int menuid,char extra)939 int Kis_Menu::AddMenuItem(string in_text, int menuid, char extra) {
940 if (menuid < 0 || menuid > (int) menubar.size() - 1)
941 return -1;
942
943 _menuitem *item = new _menuitem;
944
945 item->parentmenu = menuid;
946 item->text = in_text;
947 item->extrachar = extra;
948 item->id = menubar[menuid]->items.size();
949 item->visible = 1;
950 item->checked = -1;
951 item->colorpair = -1;
952 item->callback = NULL;
953 item->auxptr = NULL;
954 item->checksymbol = 'X';
955
956 if (extra != 0) {
957 for (vector<Kis_Menu::_menuitem *>::iterator p =
958 menubar[menuid]->items.begin(); p != menubar[menuid]->items.end(); p++) {
959 if ((*p)->extrachar == extra) {
960 _MSG("New menu item '" + in_text + "' shortcut '" + extra + "' "
961 "conflicts with existing item '" + (*p)->text + "'",
962 MSGFLAG_ERROR);
963 item->extrachar = 0;
964 }
965 }
966 }
967
968 // Auto-disable spacers
969 if (item->text[0] != '-')
970 item->enabled = 1;
971 else
972 item->enabled = 0;
973
974 item->submenu = -1;
975
976 menubar[menuid]->items.push_back(item);
977
978 if ((int) in_text.length() > menubar[menuid]->width)
979 menubar[menuid]->width = in_text.length();
980
981 return (menuid * 100) + item->id + 1;
982 }
983
SetMenuItemChecked(int in_item,int in_checked)984 void Kis_Menu::SetMenuItemChecked(int in_item, int in_checked) {
985 int mid = in_item / 100;
986 int iid = (in_item % 100) - 1;
987
988 if (mid < 0 || mid >= (int) menubar.size())
989 return;
990
991 if (iid < 0 || iid > (int) menubar[mid]->items.size())
992 return;
993
994 menubar[mid]->items[iid]->checked = in_checked;
995 menubar[mid]->checked = -1;
996
997 // Update the checked menu status
998 for (unsigned int x = 0; x < menubar[mid]->items.size(); x++) {
999 if (menubar[mid]->items[x]->checked > menubar[mid]->checked)
1000 menubar[mid]->checked = menubar[mid]->items[x]->checked;
1001 }
1002 }
1003
SetMenuItemColor(int in_item,string in_color)1004 void Kis_Menu::SetMenuItemColor(int in_item, string in_color) {
1005 int mid = in_item / 100;
1006 int iid = (in_item % 100) - 1;
1007
1008 if (mid < 0 || mid >= (int) menubar.size())
1009 return;
1010
1011 if (iid < 0 || iid > (int) menubar[mid]->items.size())
1012 return;
1013
1014 menubar[mid]->items[iid]->colorpair = parent_panel->AddColor(in_color);
1015 }
1016
AddSubMenuItem(string in_text,int menuid,char extra)1017 int Kis_Menu::AddSubMenuItem(string in_text, int menuid, char extra) {
1018 if (menuid < 0 || menuid > (int) menubar.size() - 1)
1019 return -1;
1020
1021 // Add a new menu to the menu handling system, which gives us
1022 // rational IDs and such.
1023 int smenuid = AddMenu(in_text, 0);
1024 // Mark the new menu record as a submenu so it doesn't get drawn
1025 // in the menubar
1026 menubar[smenuid]->submenu = 1;
1027
1028 // Add a menu item to the requested parent menu, and flag it as a submenu
1029 // pointing to our menuid so we can find it during drawing
1030 int sitem = AddMenuItem(in_text, menuid, extra);
1031
1032 menubar[menuid]->items[(sitem % 100) - 1]->submenu = smenuid;
1033
1034 // Return the id of the menu we made so we can add things to it
1035 return smenuid;
1036 }
1037
DisableMenuItem(int in_item)1038 void Kis_Menu::DisableMenuItem(int in_item) {
1039 int mid = in_item / 100;
1040 int iid = (in_item % 100) - 1;
1041
1042 if (mid < 0 || mid >= (int) menubar.size())
1043 return;
1044
1045 if (iid < 0 || iid > (int) menubar[mid]->items.size())
1046 return;
1047
1048 menubar[mid]->items[iid]->enabled = 0;
1049 }
1050
SetMenuItemCallback(int in_item,kis_menuitem_cb in_cb,void * in_aux)1051 void Kis_Menu::SetMenuItemCallback(int in_item, kis_menuitem_cb in_cb, void *in_aux) {
1052 int mid = in_item / 100;
1053 int iid = (in_item % 100) - 1;
1054
1055 if (mid < 0 || mid >= (int) menubar.size())
1056 return;
1057
1058 if (iid < 0 || iid > (int) menubar[mid]->items.size())
1059 return;
1060
1061 menubar[mid]->items[iid]->callback = in_cb;
1062 menubar[mid]->items[iid]->auxptr = in_aux;
1063 }
1064
ClearMenuItemCallback(int in_item)1065 void Kis_Menu::ClearMenuItemCallback(int in_item) {
1066 int mid = in_item / 100;
1067 int iid = (in_item % 100) - 1;
1068
1069 if (mid < 0 || mid >= (int) menubar.size())
1070 return;
1071
1072 if (iid < 0 || iid > (int) menubar[mid]->items.size())
1073 return;
1074
1075 menubar[mid]->items[iid]->callback = NULL;
1076 menubar[mid]->items[iid]->auxptr = NULL;
1077 }
1078
SetMenuItemCheckSymbol(int in_item,char in_sym)1079 void Kis_Menu::SetMenuItemCheckSymbol(int in_item, char in_sym) {
1080 int mid = in_item / 100;
1081 int iid = (in_item % 100) - 1;
1082
1083 if (mid < 0 || mid >= (int) menubar.size())
1084 return;
1085
1086 if (iid < 0 || iid > (int) menubar[mid]->items.size())
1087 return;
1088
1089 menubar[mid]->items[iid]->checksymbol = in_sym;
1090 }
1091
EnableMenuItem(int in_item)1092 void Kis_Menu::EnableMenuItem(int in_item) {
1093 int mid = in_item / 100;
1094 int iid = (in_item % 100) - 1;
1095
1096 if (mid < 0 || mid >= (int) menubar.size())
1097 return;
1098
1099 if (iid < 0 || iid > (int) menubar[mid]->items.size())
1100 return;
1101
1102 menubar[mid]->items[iid]->enabled = 1;
1103 }
1104
EnableAllItems(int in_menu)1105 void Kis_Menu::EnableAllItems(int in_menu) {
1106 if (in_menu < 0 || in_menu >= (int) menubar.size())
1107 return;
1108
1109 for (unsigned int x = 0; x < menubar[in_menu]->items.size(); x++)
1110 menubar[in_menu]->items[x]->enabled = 1;
1111 }
1112
DisableAllItems(int in_menu)1113 void Kis_Menu::DisableAllItems(int in_menu) {
1114 if (in_menu < 0 || in_menu >= (int) menubar.size())
1115 return;
1116
1117 for (unsigned int x = 0; x < menubar[in_menu]->items.size(); x++)
1118 menubar[in_menu]->items[x]->enabled = 0;
1119 }
1120
SetMenuItemVis(int in_item,int in_vis)1121 void Kis_Menu::SetMenuItemVis(int in_item, int in_vis) {
1122 int mid = in_item / 100;
1123 int iid = (in_item % 100) - 1;
1124
1125 if (mid < 0 || mid >= (int) menubar.size())
1126 return;
1127
1128 if (iid < 0 || iid > (int) menubar[mid]->items.size())
1129 return;
1130
1131 menubar[mid]->items[iid]->visible = in_vis;
1132 }
1133
ClearMenus()1134 void Kis_Menu::ClearMenus() {
1135 // Deconstruct the menubar
1136 for (unsigned int x = 0; x < menubar.size(); x++) {
1137 for (unsigned int y = 0; y < menubar[x]->items.size(); y++)
1138 delete menubar[x]->items[y];
1139 delete menubar[x];
1140 }
1141 }
1142
FindMenu(string in_menu)1143 int Kis_Menu::FindMenu(string in_menu) {
1144 for (unsigned int x = 0; x < menubar.size(); x++) {
1145 if (menubar[x]->text == in_menu)
1146 return menubar[x]->id;
1147 }
1148
1149 return -1;
1150 }
1151
Activate(int subcomponent)1152 void Kis_Menu::Activate(int subcomponent) {
1153 Kis_Panel_Component::Activate(subcomponent);
1154
1155 cur_menu = subcomponent - 1;
1156 cur_item = -1;
1157 sub_menu = -1;
1158 sub_item = -1;
1159 }
1160
Deactivate()1161 void Kis_Menu::Deactivate() {
1162 Kis_Panel_Component::Deactivate();
1163
1164 cur_menu = -1;
1165 cur_item = -1;
1166 sub_menu = -1;
1167 sub_item = -1;
1168 mouse_triggered = 0;
1169
1170 if (submenuwin) {
1171 delwin(submenuwin);
1172 submenuwin = NULL;
1173 }
1174
1175 if (menuwin) {
1176 delwin(menuwin);
1177 menuwin = NULL;
1178 }
1179 }
1180
DrawMenu(_menu * menu,WINDOW * win,int hpos,int vpos)1181 void Kis_Menu::DrawMenu(_menu *menu, WINDOW *win, int hpos, int vpos) {
1182 _menu *submenu = NULL;
1183 int subvpos = -1;
1184 int subhpos = -1;
1185 int dsz = 0;
1186 int width_add_check = 0, width_add_en = 0, mod_width = 0;
1187
1188 // Resize the menu window, taking invisible items into account, also
1189 // figure out the offset for any checked or disabled items
1190 for (unsigned int y = 0; y < menu->items.size(); y++) {
1191 if (menu->items[y]->visible) {
1192 dsz++;
1193
1194 if (menu->items[y]->checked > -1)
1195 width_add_check = 3;
1196
1197 if (menu->items[y]->enabled < 1)
1198 width_add_en = 2;
1199
1200 }
1201 }
1202
1203 mod_width = menu->width + 5 + width_add_check + width_add_en;
1204
1205 wresize(win, dsz + 2, mod_width);
1206
1207 // move it
1208 mvderwin(win, vpos, hpos);
1209
1210 // Draw the box
1211 wattrset(win, border_color);
1212 box(win, 0, 0);
1213
1214 // Use dsz as the position to draw into
1215 dsz = 0;
1216 for (unsigned int y = 0; y < menu->items.size(); y++) {
1217 string menuline;
1218
1219 if (menu->items[y]->visible == 0)
1220 continue;
1221
1222 // Shortcut out a spacer
1223 if (menu->items[y]->text[0] == '-') {
1224 wattrset(win, border_color);
1225 mvwhline(win, 1 + dsz, 1, ACS_HLINE, mod_width - 1);
1226 mvwaddch(win, 1 + dsz, 0, ACS_LTEE);
1227 mvwaddch(win, 1 + dsz, mod_width - 1, ACS_RTEE);
1228 dsz++;
1229 continue;
1230 }
1231
1232 wattrset(win, text_color);
1233
1234 if (menu->items[y]->colorpair != -1)
1235 wattrset(win, menu->items[y]->colorpair);
1236
1237 // Hilight the current item
1238 if (((int) menu->id == cur_menu && (int) y == cur_item) ||
1239 ((int) menu->id == sub_menu && (int) y == sub_item))
1240 wattron(win, WA_REVERSE);
1241
1242 // Draw the check
1243 if (menu->items[y]->checked == 1) {
1244 string cs = " ";
1245 cs[0] = menu->items[y]->checksymbol;
1246 menuline += cs;
1247 } else if (menu->items[y]->checked == 0 || menu->checked > -1) {
1248 menuline += " ";
1249 }
1250
1251 // Dim a disabled item
1252 if (menu->items[y]->enabled == 0) {
1253 wattrset(win, disable_color);
1254 }
1255
1256 // Format it with 'Foo F'
1257 if (menu->items[y]->enabled == 0)
1258 menuline += "(";
1259 menuline += menu->items[y]->text;
1260 if (menu->items[y]->enabled == 0)
1261 menuline += ")";
1262 menuline += " ";
1263 for (unsigned int z = menuline.length();
1264 (int) z <= mod_width - 5; z++) {
1265 menuline = menuline + string(" ");
1266 }
1267
1268 if (menu->items[y]->submenu != -1) {
1269 menuline = menuline + ">>";
1270
1271 // Draw again, using our submenu, if it's active
1272 if (menu->items[y]->submenu == cur_menu) {
1273 submenu = menubar[menu->items[y]->submenu];
1274 subvpos = vpos + dsz;
1275 subhpos = hpos + menu->width + 6;
1276 }
1277 } else if (menu->items[y]->extrachar != 0) {
1278 menuline = menuline + " " + menu->items[y]->extrachar;
1279 } else {
1280 menuline = menuline + " ";
1281 }
1282
1283 // Print it
1284 mvwaddstr(win, 1 + dsz, 1, menuline.c_str());
1285
1286 if (((int) menu->id == cur_menu && (int) y == cur_item) ||
1287 ((int) menu->id == sub_menu && (int) y == sub_item))
1288 wattroff(win, WA_REVERSE);
1289
1290 dsz++;
1291 }
1292
1293 // Draw the expanded submenu
1294 if (subvpos > 0 && subhpos > 0) {
1295 if (submenuwin == NULL)
1296 submenuwin = derwin(window, 1, 1, 0, 0);
1297
1298 DrawMenu(submenu, submenuwin, subhpos, subvpos);
1299 }
1300 }
1301
DrawComponent()1302 void Kis_Menu::DrawComponent() {
1303 if (visible == 0)
1304 return;
1305
1306 parent_panel->ColorFromPref(text_color, "menu_text_color");
1307 parent_panel->ColorFromPref(border_color, "menu_border_color");
1308 parent_panel->ColorFromPref(disable_color, "menu_disable_color");
1309
1310 int hpos = 3;
1311
1312 if (menuwin == NULL)
1313 menuwin = derwin(window, 1, 1, 0, 0);
1314
1315 wattron(window, border_color);
1316 mvwaddstr(window, sy, sx + 1, "~ ");
1317
1318 // Draw the menu bar itself
1319 for (unsigned int x = 0; x < menubar.size(); x++) {
1320 if (menubar[x]->submenu || menubar[x]->visible == 0)
1321 continue;
1322
1323 wattron(window, text_color);
1324
1325 // If the current menu is the selected one, hilight it
1326 if ((int) x == cur_menu || (int) x == sub_menu)
1327 wattron(window, WA_REVERSE);
1328
1329 // Draw the menu
1330 mvwaddstr(window, sy, sx + hpos, (menubar[x]->text).c_str());
1331 // Set the hilight
1332 if (menubar[x]->targchar >= 0) {
1333 wattron(window, WA_UNDERLINE);
1334 mvwaddch(window, sy, sx + hpos + menubar[x]->targchar,
1335 menubar[x]->text[menubar[x]->targchar]);
1336 wattroff(window, WA_UNDERLINE);
1337 }
1338
1339 wattroff(window, WA_REVERSE);
1340
1341 mvwaddstr(window, sy, sx + hpos + menubar[x]->text.length(), " ");
1342
1343 // Draw the menu itself, if we've got an item selected in it
1344 if (((int) x == cur_menu || (int) x == sub_menu) &&
1345 (sub_item >= 0 || cur_item >= 0 || mouse_triggered)) {
1346
1347 DrawMenu(menubar[x], menuwin, sx + hpos, sy + 1);
1348 }
1349
1350 hpos += menubar[x]->text.length() + 1;
1351 }
1352 wattroff(window, text_color);
1353 }
1354
FindNextEnabledItem()1355 void Kis_Menu::FindNextEnabledItem() {
1356 int looped = 0;
1357
1358 // Handle disabled and spacer items
1359 if (menubar[cur_menu]->items[cur_item]->enabled == 0) {
1360 // find the next enabled item
1361 for (int i = cur_item; i <= (int) menubar[cur_menu]->items.size(); i++) {
1362 // Loop
1363 if (i >= (int) menubar[cur_menu]->items.size()) {
1364 looped = 1;
1365 i = 0;
1366 }
1367
1368 if (looped && i == cur_item) {
1369 cur_item = 0;
1370 break;
1371 }
1372
1373 if (menubar[cur_menu]->items[i]->visible == 0)
1374 continue;
1375
1376 if (menubar[cur_menu]->items[i]->enabled) {
1377 cur_item = i;
1378 break;
1379 }
1380 }
1381 }
1382 }
1383
FindPrevEnabledItem()1384 void Kis_Menu::FindPrevEnabledItem() {
1385 int looped = 0;
1386
1387 // Handle disabled and spacer items
1388 if (menubar[cur_menu]->items[cur_item]->enabled == 0) {
1389 // find the next enabled item
1390 for (int i = cur_item; i >= -1; i--) {
1391 // Loop
1392 if (i < 0) {
1393 i = menubar[cur_menu]->items.size() - 1;
1394 looped = 1;
1395 }
1396
1397 if (looped && i == cur_item) {
1398 cur_item = 0;
1399 break;
1400 }
1401
1402 if (menubar[cur_menu]->items[i]->visible == 0)
1403 continue;
1404
1405 if (menubar[cur_menu]->items[i]->enabled) {
1406 cur_item = i;
1407 break;
1408 }
1409 }
1410 }
1411 }
1412
KeyPress(int in_key)1413 int Kis_Menu::KeyPress(int in_key) {
1414 if (visible == 0)
1415 return -1;
1416
1417 // Activate menu
1418 if (in_key == '~' || in_key == '`' || in_key == 0x1B) {
1419 if (cur_menu < 0) {
1420 Activate(1);
1421 } else {
1422 // Break out of submenus
1423 if (sub_menu != -1) {
1424 cur_menu = sub_menu;
1425 cur_item = sub_item;
1426 sub_menu = sub_item = -1;
1427
1428 if (submenuwin) {
1429 delwin(submenuwin);
1430 submenuwin = NULL;
1431 }
1432
1433 return 0;
1434 }
1435
1436 Deactivate();
1437 }
1438
1439 // We consume it but the framework doesn't get a state change
1440 return -1;
1441 }
1442
1443 // Menu movement
1444 if (in_key == KEY_RIGHT && cur_menu >= 0) {
1445
1446 // Break out of submenus on l/r
1447 if (sub_menu != -1) {
1448 cur_menu = sub_menu;
1449 cur_item = sub_item;
1450 sub_menu = sub_item = -1;
1451 return -1;
1452 }
1453
1454 for (unsigned int nm = cur_menu + 1; nm < menubar.size(); nm++) {
1455 if (menubar[nm]->submenu == 0) {
1456 cur_menu = nm;
1457 cur_item = 0;
1458 FindNextEnabledItem();
1459 break;
1460 }
1461 }
1462
1463 return -1;
1464 }
1465
1466 if (in_key == KEY_LEFT && cur_menu > 0) {
1467 // Break out of submenus on l/r
1468 if (sub_menu != -1) {
1469 cur_menu = sub_menu;
1470 cur_item = sub_item;
1471 sub_menu = sub_item = -1;
1472 return -1;
1473 }
1474
1475 for (int nm = cur_menu - 1; nm >= 0; nm--) {
1476 if (menubar[nm]->submenu == 0) {
1477 cur_menu = nm;
1478 cur_item = 0;
1479 FindNextEnabledItem();
1480 break;
1481 }
1482 }
1483
1484 return -1;
1485 }
1486
1487 if (in_key == KEY_DOWN && cur_menu >= 0 &&
1488 cur_item <= (int) menubar[cur_menu]->items.size() - 1) {
1489
1490 if (cur_item == (int) menubar[cur_menu]->items.size() - 1) {
1491 cur_item = 0;
1492 FindNextEnabledItem();
1493 return -1;
1494 }
1495
1496 cur_item++;
1497
1498 FindNextEnabledItem();
1499
1500 return -1;
1501 }
1502
1503 if (in_key == KEY_UP && cur_item >= 0) {
1504 if (cur_item == 0) {
1505 cur_item = menubar[cur_menu]->items.size() - 1;
1506 FindPrevEnabledItem();
1507 return -1;
1508 }
1509
1510 cur_item--;
1511
1512 FindPrevEnabledItem();
1513
1514 return -1;
1515 }
1516
1517 // Space or enter
1518 if ((in_key == ' ' || in_key == 0x0A || in_key == KEY_ENTER) && cur_menu >= 0) {
1519 if (cur_item == -1) {
1520 cur_item = 0;
1521 FindNextEnabledItem();
1522 return -1;
1523 }
1524
1525 // Are we entering a submenu?
1526 if (sub_menu == -1 && menubar[cur_menu]->items[cur_item]->submenu != -1) {
1527 // Remember where we were
1528 sub_menu = cur_menu;
1529 sub_item = cur_item;
1530 cur_menu = menubar[cur_menu]->items[cur_item]->submenu;
1531 cur_item = 0;
1532 return -1;
1533 }
1534
1535 if (menubar[cur_menu]->items[cur_item]->enabled == 0) {
1536 FindNextEnabledItem();
1537 return -1;
1538 }
1539
1540 int ret = (cur_menu * 100) + cur_item + 1;
1541
1542 // Per-menu callbacks
1543 if (menubar[cur_menu]->items[cur_item]->callback != NULL)
1544 (*(menubar[cur_menu]->items[cur_item]->callback))(globalreg, ret,
1545 menubar[cur_menu]->items[cur_item]->auxptr);
1546
1547 // Widget-wide callbacks
1548 if (cb_activate != NULL)
1549 (*cb_activate)(this, ret, cb_activate_aux, globalreg);
1550
1551 Deactivate();
1552
1553 // Generic fallthrough
1554 return ret;
1555 }
1556
1557 // Key shortcuts
1558 if (cur_menu >= 0) {
1559 if (cur_item < 0) {
1560 // Try w/ the proper case
1561 for (unsigned int x = 0; x < menubar.size(); x++) {
1562 if (in_key == menubar[x]->text[menubar[x]->targchar]) {
1563 cur_menu = x;
1564 cur_item = 0;
1565 FindNextEnabledItem();
1566 return -1;
1567 }
1568 }
1569 // Try with lowercase, if we didn't find one already
1570 for (unsigned int x = 0; x < menubar.size(); x++) {
1571 if (tolower(in_key) ==
1572 tolower(menubar[x]->text[menubar[x]->targchar])) {
1573 cur_menu = x;
1574 cur_item = 0;
1575 FindNextEnabledItem();
1576 return -1;
1577 }
1578 }
1579 return -1;
1580 } else {
1581 for (unsigned int x = 0; x < menubar[cur_menu]->items.size(); x++) {
1582 if (in_key == menubar[cur_menu]->items[x]->extrachar &&
1583 menubar[cur_menu]->items[x]->enabled == 1) {
1584 int ret = (cur_menu * 100) + x + 1;
1585
1586 // Per-menu callbacks
1587 if (menubar[cur_menu]->items[x]->callback != NULL) {
1588 (*(menubar[cur_menu]->items[x]->callback))
1589 (globalreg, ret, menubar[cur_menu]->items[x]->auxptr);
1590 }
1591
1592 // Widget-wide callbacks
1593 if (cb_activate != NULL)
1594 (*cb_activate)(this, ret, cb_activate_aux, globalreg);
1595
1596 Deactivate();
1597
1598 // Generic fallthrough
1599 return ret;
1600 }
1601 }
1602 return -1;
1603 }
1604 }
1605
1606 return 0;
1607 }
1608
MouseEvent(MEVENT * mevent)1609 int Kis_Menu::MouseEvent(MEVENT *mevent) {
1610 // Menu win/subwin coordinates
1611 int wbx, wby, wlx, wly;
1612 int match_any_win = 0;
1613
1614 if (mevent->bstate == 4 && mevent->y == sy) {
1615 // Click happened somewhere in the menubar
1616 int hpos = 3;
1617 for (unsigned int x = 0; x < menubar.size(); x++) {
1618 if (menubar[x]->submenu || menubar[x]->visible == 0)
1619 continue;
1620
1621 if (mevent->x < hpos)
1622 break;
1623
1624 if (mevent->x <= hpos + (int) menubar[x]->text.length()) {
1625 if ((int) x == cur_menu) {
1626 Deactivate();
1627 // Consume w/ no state change to caller
1628 return -1;
1629 } else {
1630 Activate(0);
1631 cur_menu = x;
1632 cur_item = 0;
1633
1634 FindNextEnabledItem();
1635
1636 sub_menu = -1;
1637 sub_item = -1;
1638
1639 if (submenuwin) {
1640 delwin(submenuwin);
1641 submenuwin = NULL;
1642 }
1643
1644 mouse_triggered = 1;
1645 // Consume w/ no state change to caller
1646 return -1;
1647 }
1648 }
1649
1650 hpos += menubar[x]->text.length() + 1;
1651 } /* menu list */
1652 } else if (mevent->bstate == 4 && mevent->y > sy && cur_menu >= 0) {
1653 // If we have a submenu
1654 if (submenuwin) {
1655 // See if we fall w/in it
1656 getparyx(submenuwin, wby, wbx);
1657 getmaxyx(submenuwin, wly, wlx);
1658
1659 // If we're anywhere in the window we don't close menus
1660 if (mevent->x >= wbx && mevent->x < wbx + wlx &&
1661 mevent->y >= wby && mevent->y < wby + wly)
1662 match_any_win = 1;
1663
1664 // Our range shouldn't include the borders
1665 if (mevent->x > wbx && mevent->x < wbx + wlx &&
1666 mevent->y > wby && mevent->y < wby + wly - 1) {
1667
1668 int mitem = mevent->y - wby - 1;
1669
1670 if (mitem >= 0 && mitem < (int) menubar[cur_menu]->items.size()) {
1671 if (menubar[cur_menu]->items[mitem]->enabled == 1) {
1672
1673 int ret = (cur_menu * 100) + mitem + 1;
1674
1675 // Per-menu callbacks
1676 if (menubar[cur_menu]->items[mitem]->callback != NULL)
1677 (*(menubar[cur_menu]->items[mitem]->callback))
1678 (globalreg, ret,
1679 menubar[cur_menu]->items[mitem]->auxptr);
1680
1681 // Widget-wide callbacks
1682 if (cb_activate != NULL)
1683 (*cb_activate)(this, ret, cb_activate_aux, globalreg);
1684
1685 Deactivate();
1686
1687 return ret;
1688 }
1689 }
1690 }
1691 }
1692
1693 if (menuwin) {
1694 // See if we fall w/in the main menu
1695 getparyx(menuwin, wby, wbx);
1696 getmaxyx(menuwin, wly, wlx);
1697
1698 // If we're anywhere in the window we don't close menus
1699 if (mevent->x >= wbx && mevent->x < wbx + wlx &&
1700 mevent->y >= wby && mevent->y < wby + wly)
1701 match_any_win = 1;
1702
1703 // Our range shouldn't include the borders
1704 if (mevent->x > wbx && mevent->x < wbx + wlx &&
1705 mevent->y > wby && mevent->y < wby + wly - 1) {
1706
1707 // If we had a sub menu, close it
1708 if (sub_menu >= 0) {
1709 cur_menu = sub_menu;
1710 cur_item = sub_item;
1711
1712 sub_menu = sub_item = -1;
1713
1714 if (submenuwin) {
1715 delwin(submenuwin);
1716 submenuwin = NULL;
1717 }
1718
1719 // And drop out of processing now, we don't want to select
1720 // the original menu item
1721 return -1;
1722 }
1723
1724 int mitem = mevent->y - wby - 1;
1725
1726 if (mitem >= 0 && mitem < (int) menubar[cur_menu]->items.size()) {
1727 if (menubar[cur_menu]->items[mitem]->enabled == 1) {
1728
1729 // Are we entering a submenu?
1730 if (menubar[cur_menu]->items[mitem]->submenu != -1) {
1731 // Remember where we were
1732 sub_menu = cur_menu;
1733 sub_item = cur_item;
1734 cur_menu = menubar[cur_menu]->items[mitem]->submenu;
1735 cur_item = 0;
1736 return -1;
1737 }
1738
1739 // Otherwise, trigger the menu item
1740 int ret = (cur_menu * 100) + mitem + 1;
1741
1742 // Per-menu callbacks
1743 if (menubar[cur_menu]->items[mitem]->callback != NULL)
1744 (*(menubar[cur_menu]->items[mitem]->callback))
1745 (globalreg, ret,
1746 menubar[cur_menu]->items[mitem]->auxptr);
1747
1748 // Widget-wide callbacks
1749 if (cb_activate != NULL)
1750 (*cb_activate)(this, ret, cb_activate_aux, globalreg);
1751
1752 Deactivate();
1753
1754 return ret;
1755 }
1756 }
1757 }
1758 }
1759
1760 // Close menus entirely if we're clicking somewhere else in the screen
1761 if (match_any_win == 0) {
1762 Deactivate();
1763 return -1;
1764 }
1765
1766 #if 0
1767 int hpos = 3;
1768 int ypos = sy + 2;
1769 for (unsigned int x = 0; x < (unsigned int) (cur_menu + 1); x++) {
1770 if (menubar[x]->submenu || menubar[x]->visible == 0)
1771 continue;
1772
1773 if (mevent->x < hpos)
1774 break;
1775
1776 hpos += menubar[x]->text.length() + 1;
1777
1778 if (mevent->x <= hpos + (int) menubar[x]->text.length()) {
1779 for (unsigned int y = 0; y < menubar[x]->items.size(); y++) {
1780 if (menubar[x]->items[y]->visible == 0)
1781 continue;
1782
1783 if (menubar[x]->items[y]->text[0] == '-') {
1784 ypos++;
1785 continue;
1786 }
1787
1788 if (ypos == mevent->y) {
1789 if (menubar[x]->items[y]->enabled == 0)
1790 return -1;
1791
1792 // Trigger the item
1793 if (cb_activate != NULL)
1794 (*cb_activate)(this, (cur_menu * 100) + y + 1,
1795 cb_activate_aux, globalreg);
1796
1797 Deactivate();
1798
1799 return (cur_menu * 100) + y + 1;
1800 }
1801
1802 ypos++;
1803 }
1804 }
1805 }
1806
1807 #endif
1808
1809 }
1810
1811 return 0;
1812 }
1813
Kis_Free_Text(GlobalRegistry * in_globalreg,Kis_Panel * in_panel)1814 Kis_Free_Text::Kis_Free_Text(GlobalRegistry *in_globalreg, Kis_Panel *in_panel) :
1815 Kis_Panel_Component(in_globalreg, in_panel) {
1816 globalreg = in_globalreg;
1817 scroll_pos = 0;
1818 SetMinSize(1, 1);
1819 alignment = 0;
1820 follow_tail = 0;
1821 max_text = -1;
1822 }
1823
~Kis_Free_Text()1824 Kis_Free_Text::~Kis_Free_Text() {
1825 // Nothing
1826 }
1827
DrawComponent()1828 void Kis_Free_Text::DrawComponent() {
1829 if (visible == 0)
1830 return;
1831
1832 int c;
1833
1834 parent_panel->ColorFromPref(color_active, color_active_pref);
1835 parent_panel->ColorFromPref(color_inactive, color_inactive_pref);
1836
1837 c = SetTransColor(color_active);
1838
1839 if (ly < (int) text_vec.size() && follow_tail && scroll_pos < 0)
1840 scroll_pos = text_vec.size() - ly + 1;
1841
1842 if (scroll_pos < 0 || scroll_pos > (int) text_vec.size())
1843 scroll_pos = 0;
1844
1845 int px = 0;
1846 for (unsigned int x = scroll_pos; x < text_vec.size() && px < ly; x++) {
1847 // Use the special formatter
1848 Kis_Panel_Specialtext::Mvwaddnstr(window, sy + px, sx,
1849 text_vec[x],
1850 lx - 1, parent_panel, c);
1851 px++;
1852 }
1853
1854 if ((int) text_vec.size() > ly) {
1855 // Draw the hash scroll bar
1856 mvwvline(window, sy, sx + lx - 1, ACS_VLINE, ly);
1857 // Figure out how far down our text we are
1858 // int perc = ey * (scroll_pos / text_vec.size());
1859 float perc = (float) ly * (float) ((float) (scroll_pos) /
1860 (float) (text_vec.size() - ly));
1861 wattron(window, WA_REVERSE);
1862 // Draw the solid position
1863 mvwaddch(window, sy + (int) perc, sx + lx - 1, ACS_BLOCK);
1864
1865 wattroff(window, WA_REVERSE);
1866 }
1867 }
1868
KeyPress(int in_key)1869 int Kis_Free_Text::KeyPress(int in_key) {
1870 if (visible == 0)
1871 return 0;
1872
1873 int scrollable = 1;
1874
1875 if ((int) text_vec.size() <= ly)
1876 scrollable = 0;
1877
1878 if (scrollable && in_key == KEY_UP && scroll_pos > 0) {
1879 scroll_pos--;
1880 return 0;
1881 }
1882
1883 if (scrollable && in_key == KEY_DOWN &&
1884 // Don't allow scrolling off the end
1885 scroll_pos < ((int) text_vec.size() - ly)) {
1886 scroll_pos++;
1887 return 0;
1888 }
1889
1890 if (scrollable && in_key == KEY_PPAGE && scroll_pos > 0) {
1891 scroll_pos -= (ly - 1);
1892 if (scroll_pos < 0)
1893 scroll_pos = 0;
1894 return 0;
1895 }
1896
1897 if (scrollable && in_key == KEY_NPAGE) {
1898 scroll_pos += (ly - 1);
1899 if (scroll_pos >= ((int) text_vec.size() - ly))
1900 scroll_pos = ((int) text_vec.size() - ly);
1901 return 0;
1902 }
1903
1904 return 1;
1905 }
1906
SetText(string in_text)1907 void Kis_Free_Text::SetText(string in_text) {
1908 text_vec = StrTokenize(in_text, "\n");
1909 SetPreferredSize(Kis_Panel_Specialtext::Strlen(in_text), 1);
1910 }
1911
SetText(vector<string> in_text)1912 void Kis_Free_Text::SetText(vector<string> in_text) {
1913 unsigned int ml = 0;
1914
1915 for (unsigned x = 0; x < in_text.size(); x++) {
1916 if (Kis_Panel_Specialtext::Strlen(in_text[x]) > ml)
1917 ml = Kis_Panel_Specialtext::Strlen(in_text[x]);
1918 }
1919
1920 text_vec = in_text;
1921
1922 SetPreferredSize(ml, in_text.size());
1923
1924 if (follow_tail)
1925 scroll_pos = -1;
1926 }
1927
AppendText(string in_text)1928 void Kis_Free_Text::AppendText(string in_text) {
1929 text_vec.push_back(in_text);
1930
1931 if (max_text > 0 && (int) text_vec.size() > max_text) {
1932 text_vec.erase(text_vec.begin(), text_vec.begin() + text_vec.size() - max_text);
1933 }
1934
1935 if (lx < (int) Kis_Panel_Specialtext::Strlen(in_text))
1936 SetPreferredSize(Kis_Panel_Specialtext::Strlen(in_text), text_vec.size());
1937
1938 // If we're following the tail then jump to the bottom when we add text
1939 if (ly < (int) text_vec.size() && follow_tail)
1940 scroll_pos = text_vec.size() - ly;
1941 }
1942
ProcessMessage(string in_msg,int in_flags)1943 void KisStatusText_Messageclient::ProcessMessage(string in_msg, int in_flags) {
1944 if ((in_flags & MSGFLAG_INFO)) {
1945 ((Kis_Status_Text *) auxptr)->AddLine("\004bINFO\004B: " + in_msg, 6);
1946 } else if ((in_flags & MSGFLAG_ERROR)) {
1947 ((Kis_Status_Text *) auxptr)->AddLine("\004rERROR\004R: " + in_msg, 7);
1948 } else if ((in_flags & MSGFLAG_FATAL)) {
1949 ((Kis_Status_Text *) auxptr)->AddLine("\004rFATAL\004R: " + in_msg, 7);
1950 } else {
1951 ((Kis_Status_Text *) auxptr)->AddLine(in_msg);
1952 }
1953 }
1954
Kis_Status_Text(GlobalRegistry * in_globalreg,Kis_Panel * in_panel)1955 Kis_Status_Text::Kis_Status_Text(GlobalRegistry *in_globalreg, Kis_Panel *in_panel) :
1956 Kis_Panel_Component(in_globalreg, in_panel) {
1957 globalreg = in_globalreg;
1958 scroll_pos = 0;
1959 status_color_normal = -1;
1960 parent_panel->InitColorPref("status_normal_color", "white,black");
1961 }
1962
~Kis_Status_Text()1963 Kis_Status_Text::~Kis_Status_Text() {
1964 // Nothing
1965 }
1966
DrawComponent()1967 void Kis_Status_Text::DrawComponent() {
1968 parent_panel->ColorFromPref(status_color_normal, "status_normal_color");
1969
1970 if (visible == 0)
1971 return;
1972
1973 wattrset(window, status_color_normal);
1974
1975 for (unsigned int x = 0; x < text_vec.size() && (int) x < ly; x++) {
1976 Kis_Panel_Specialtext::Mvwaddnstr(window, ey - x, sx,
1977 text_vec[text_vec.size() - x - 1],
1978 ex - 1, parent_panel, status_color_normal);
1979 }
1980 }
1981
KeyPress(int in_key)1982 int Kis_Status_Text::KeyPress(int in_key) {
1983 if (visible == 0)
1984 return 0;
1985
1986 return 1;
1987 }
1988
AddLine(string in_line,int headeroffset)1989 void Kis_Status_Text::AddLine(string in_line, int headeroffset) {
1990 vector<string> lw = LineWrap(in_line, headeroffset, ex - 1);
1991
1992 for (unsigned int x = 0; x < lw.size(); x++) {
1993 text_vec.push_back(lw[x]);
1994 }
1995
1996 if ((int) text_vec.size() > py) {
1997 text_vec.erase(text_vec.begin(), text_vec.begin() + text_vec.size() - py);
1998 }
1999 }
2000
Kis_Field_List(GlobalRegistry * in_globalreg,Kis_Panel * in_panel)2001 Kis_Field_List::Kis_Field_List(GlobalRegistry *in_globalreg, Kis_Panel *in_panel) :
2002 Kis_Panel_Component(in_globalreg, in_panel) {
2003 globalreg = in_globalreg;
2004 scroll_pos = 0;
2005 field_w = 0;
2006 }
2007
~Kis_Field_List()2008 Kis_Field_List::~Kis_Field_List() {
2009 // Nothing
2010 }
2011
DrawComponent()2012 void Kis_Field_List::DrawComponent() {
2013 if (visible == 0)
2014 return;
2015
2016 parent_panel->ColorFromPref(color_active, color_active_pref);
2017 parent_panel->ColorFromPref(color_inactive, color_inactive_pref);
2018
2019 SetTransColor(color_active);
2020
2021 for (unsigned int x = 0; x < field_vec.size() && (int) x < ey; x++) {
2022 // Set the field name to bold
2023 wattron(window, WA_UNDERLINE);
2024 mvwaddnstr(window, sy + x, sx, field_vec[x + scroll_pos].c_str(), field_w);
2025 mvwaddch(window, sy + x, sx + field_w, ':');
2026 wattroff(window, WA_UNDERLINE);
2027
2028 // Draw the data, leave room on the end for the scrollbar
2029 mvwaddnstr(window, sy + x, sx + field_w + 2, data_vec[x + scroll_pos].c_str(),
2030 sx - field_w - 3);
2031 }
2032
2033 if ((int) field_vec.size() > ey) {
2034 // Draw the hash scroll bar
2035 mvwvline(window, sy, sx + ex - 1, ACS_VLINE, ey);
2036 // Figure out how far down our text we are
2037 // int perc = ey * (scroll_pos / text_vec.size());
2038 float perc = (float) ey * (float) ((float) (scroll_pos) /
2039 (float) (field_vec.size() - ey));
2040 wattron(window, WA_REVERSE);
2041 // Draw the solid position
2042 mvwaddch(window, sy + (int) perc, sx + ex - 1, ACS_BLOCK);
2043
2044 wattroff(window, WA_REVERSE);
2045 }
2046 }
2047
KeyPress(int in_key)2048 int Kis_Field_List::KeyPress(int in_key) {
2049 if (visible == 0)
2050 return 0;
2051
2052 int scrollable = 1;
2053
2054 if ((int) field_vec.size() <= ey)
2055 scrollable = 0;
2056
2057 if (scrollable && in_key == KEY_UP && scroll_pos > 0) {
2058 scroll_pos--;
2059 return 0;
2060 }
2061
2062 if (scrollable && in_key == KEY_DOWN &&
2063 scroll_pos < ((int) field_vec.size() - ey)) {
2064 scroll_pos++;
2065 return 0;
2066 }
2067
2068 if (scrollable && in_key == KEY_PPAGE && scroll_pos > 0) {
2069 scroll_pos -= (ey - 1);
2070 if (scroll_pos < 0)
2071 scroll_pos = 0;
2072 return 0;
2073 }
2074
2075 if (scrollable && in_key == KEY_NPAGE) {
2076 scroll_pos += (ey - 1);
2077 if (scroll_pos >= ((int) field_vec.size() - ey))
2078 scroll_pos = ((int) field_vec.size() - ey);
2079 return 0;
2080 }
2081
2082 return 1;
2083 }
2084
AddData(string in_field,string in_data)2085 int Kis_Field_List::AddData(string in_field, string in_data) {
2086 int pos = field_vec.size();
2087 field_vec.push_back(in_field);
2088 data_vec.push_back(in_data);
2089
2090 if (in_field.length() > field_w)
2091 field_w = in_field.length();
2092
2093 return (int) pos;
2094 }
2095
ModData(unsigned int in_row,string in_field,string in_data)2096 int Kis_Field_List::ModData(unsigned int in_row, string in_field, string in_data) {
2097 if (in_row >= field_vec.size())
2098 return -1;
2099
2100 field_vec[in_row] = in_field;
2101 data_vec[in_row] = in_data;
2102
2103 return (int) in_row;
2104 }
2105
Kis_Scrollable_Table(GlobalRegistry * in_globalreg,Kis_Panel * in_panel)2106 Kis_Scrollable_Table::Kis_Scrollable_Table(GlobalRegistry *in_globalreg,
2107 Kis_Panel *in_panel) :
2108 Kis_Panel_Component(in_globalreg, in_panel) {
2109
2110 globalreg = in_globalreg;
2111
2112 scroll_pos = 0;
2113 hscroll_pos = 0;
2114 selected = -1;
2115
2116 SetMinSize(0, 3);
2117
2118 draw_lock_scroll_top = 0;
2119 draw_highlight_selected = 1;
2120 draw_titles = 1;
2121 }
2122
~Kis_Scrollable_Table()2123 Kis_Scrollable_Table::~Kis_Scrollable_Table() {
2124 for (unsigned int x = 0; x < data_vec.size(); x++) {
2125 delete data_vec[x];
2126 }
2127 }
2128
DrawComponent()2129 void Kis_Scrollable_Table::DrawComponent() {
2130 if (visible == 0)
2131 return;
2132
2133 parent_panel->ColorFromPref(color_active, color_active_pref);
2134 parent_panel->ColorFromPref(color_inactive, color_inactive_pref);
2135
2136 SetTransColor(color_active);
2137
2138 // Current character position x
2139 int xcur = 0;
2140 int ycur = 0;
2141 string ftxt;
2142
2143 // Assign widths to '0' sized things by dividing what's left
2144 // into them. We'll assume the caller doesn't generate a horizontally
2145 // scrollable table with variable width fields.
2146 int ndynf = 0, spare = lx;
2147
2148 if ((int) data_vec.size() > ly)
2149 spare -= 1;
2150
2151 for (unsigned int x = 0; x < title_vec.size(); x++) {
2152 title_vec[x].draw_width = title_vec[x].width;
2153
2154 if (title_vec[x].width < 0)
2155 continue;
2156
2157 if (title_vec[x].width == 0) {
2158 ndynf++;
2159 continue;
2160 }
2161
2162 spare -= (title_vec[x].draw_width + 1);
2163 }
2164 // Distribute the spare over the rest
2165 if (spare > 0) {
2166 for (unsigned int x = 0; x < title_vec.size() && ndynf > 0; x++) {
2167 if (title_vec[x].width == 0) {
2168 title_vec[x].draw_width = spare / ndynf;
2169 spare -= spare / ndynf--;
2170 }
2171 }
2172 }
2173
2174 // Print across the titles
2175 if (draw_titles) {
2176 wattron(window, WA_UNDERLINE);
2177 for (unsigned int x = hscroll_pos; x < title_vec.size() && xcur < lx; x++) {
2178
2179 int w = title_vec[x].draw_width;
2180
2181 if (xcur + w >= ex)
2182 w = lx - xcur;
2183
2184 // Align the field w/in the width
2185 ftxt = AlignString(title_vec[x].title, ' ', title_vec[x].alignment, w);
2186
2187 // Write it out
2188 mvwaddstr(window, sy, sx + xcur, ftxt.c_str());
2189
2190 // Advance by the width + 1
2191 xcur += w + 1;
2192 }
2193 wattroff(window, WA_UNDERLINE);
2194 ycur += 1;
2195 }
2196
2197 if ((int) data_vec.size() > ly) {
2198 // Draw the scroll bar
2199 mvwvline(window, sy, sx + lx - 1, ACS_VLINE, ly);
2200 float perc = (float) ly * (float) ((float) (scroll_pos) /
2201 (float) (data_vec.size() - ly));
2202 if (perc > ly - 1)
2203 perc = ly - 1;
2204 wattron(window, WA_REVERSE);
2205 mvwaddch(window, sy + (int) perc, sx + lx - 1, ACS_BLOCK);
2206 wattroff(window, WA_REVERSE);
2207 }
2208
2209 // Jump to the scroll location to start drawing rows
2210 for (unsigned int r = scroll_pos ? scroll_pos : 0;
2211 r < data_vec.size() && ycur < ly; r++) {
2212 // Print across
2213 xcur = 0;
2214
2215 if ((int) r == selected && draw_highlight_selected) {
2216 wattron(window, WA_REVERSE);
2217 mvwhline(window, sy + ycur, sx, ' ', lx);
2218 }
2219
2220 for (unsigned int x = hscroll_pos; x < data_vec[r]->data.size() &&
2221 xcur < lx && x < title_vec.size(); x++) {
2222 int w = title_vec[x].draw_width;
2223
2224 if (xcur + w >= lx)
2225 w = lx - xcur;
2226
2227 ftxt = AlignString(data_vec[r]->data[x], ' ', title_vec[x].alignment, w);
2228
2229 mvwaddstr(window, sy + ycur, sx + xcur, ftxt.c_str());
2230
2231 xcur += w + 1;
2232 }
2233
2234 if ((int) r == selected && draw_highlight_selected)
2235 wattroff(window, WA_REVERSE);
2236
2237 ycur += 1;
2238
2239 }
2240 }
2241
KeyPress(int in_key)2242 int Kis_Scrollable_Table::KeyPress(int in_key) {
2243 if (visible == 0)
2244 return 0;
2245
2246 int scrollable = 1;
2247 if ((int) data_vec.size() < ly)
2248 scrollable = 0;
2249
2250 // Selected up one, scroll up one if we need to
2251 if (in_key == KEY_UP) {
2252 if (draw_highlight_selected == 0 && scrollable) {
2253 // If we're not drawing the highlights then we don't mess
2254 // with the selected item at all, we just slide the scroll
2255 // pos up and down, and make sure we don't let them scroll
2256 // off the end of the world, keep as much of the tail in view
2257 // as possible
2258 if (scroll_pos > 0)
2259 scroll_pos--;
2260 } else if (selected > 0) {
2261 selected--;
2262 if (scrollable && scroll_pos > 0 && scroll_pos > selected) {
2263 scroll_pos--;
2264 }
2265 }
2266 }
2267
2268 if (in_key == KEY_DOWN && selected < (int) data_vec.size() - 1) {
2269 if (draw_highlight_selected == 0 && scrollable) {
2270 // If we're not drawing the highlights then we don't mess
2271 // with the selected item at all, we just slide the scroll
2272 // pos up and down, and make sure we don't let them scroll
2273 // off the end of the world, keep as much of the tail in view
2274 // as possible
2275 if (scroll_pos + ly <= (int) data_vec.size() - 1)
2276 scroll_pos++;
2277 } else if (draw_lock_scroll_top && scrollable &&
2278 scroll_pos + ly - 1 <= selected) {
2279 // If we're locked to always keep the list filled, we can only
2280 // scroll until the bottom is visible. This implies we don't
2281 // show the selected row, too
2282 selected++;
2283 scroll_pos++;
2284 } else {
2285 selected++;
2286 if (scrollable && scroll_pos + ly - 1 <= selected) {
2287 scroll_pos++;
2288 }
2289 }
2290 }
2291
2292 if (in_key == KEY_RIGHT && hscroll_pos < (int) title_vec.size() - 1) {
2293 hscroll_pos++;
2294 }
2295
2296 if (in_key == KEY_LEFT && hscroll_pos > 0) {
2297 hscroll_pos--;
2298 }
2299
2300 if (in_key == '\n' || in_key == '\r' || in_key == ' ') {
2301 if (cb_activate != NULL)
2302 (*cb_activate)(this, GetSelected(), cb_activate_aux, globalreg);
2303
2304 return GetSelected();
2305 }
2306
2307 return 0;
2308 }
2309
GetSelected()2310 int Kis_Scrollable_Table::GetSelected() {
2311 if (selected >= 0 && selected < (int) data_vec.size()) {
2312 return data_vec[selected]->key;
2313 }
2314
2315 return -1;
2316 }
2317
GetRow(int in_key)2318 vector<string> Kis_Scrollable_Table::GetRow(int in_key) {
2319 vector<string> ret;
2320
2321 if (in_key >= 0 && in_key < (int) data_vec.size()) {
2322 return data_vec[in_key]->data;
2323 }
2324
2325 return ret;
2326 }
2327
GetSelectedData()2328 vector<string> Kis_Scrollable_Table::GetSelectedData() {
2329 vector<string> ret;
2330
2331 if (selected >= 0 && selected < (int) data_vec.size()) {
2332 return data_vec[selected]->data;
2333 }
2334
2335 return ret;
2336 }
2337
SetSelected(int in_key)2338 int Kis_Scrollable_Table::SetSelected(int in_key) {
2339 for (unsigned int x = 0; x < data_vec.size(); x++) {
2340 if (data_vec[x]->key == in_key) {
2341 selected = x;
2342 return 1;
2343 }
2344 }
2345
2346 return 0;
2347 }
2348
AddTitles(vector<Kis_Scrollable_Table::title_data> in_titles)2349 int Kis_Scrollable_Table::AddTitles(vector<Kis_Scrollable_Table::title_data>
2350 in_titles) {
2351 title_vec = in_titles;
2352 return 1;
2353 }
2354
AddRow(int in_key,vector<string> in_fields)2355 int Kis_Scrollable_Table::AddRow(int in_key, vector<string> in_fields) {
2356 if (key_map.find(in_key) != key_map.end()) {
2357 _MSG("Scrollable_Table tried to add row already keyed", MSGFLAG_ERROR);
2358 return -1;
2359 }
2360
2361 if (in_fields.size() != title_vec.size()) {
2362 _MSG("Scrollable_Table added row with a different number of fields than "
2363 "the title", MSGFLAG_ERROR);
2364 }
2365
2366 row_data *r = new row_data;
2367 r->key = in_key;
2368 r->data = in_fields;
2369
2370 key_map[in_key] = 1;
2371
2372 data_vec.push_back(r);
2373
2374 SetPreferredSize(0, data_vec.size() + 2);
2375
2376 return 1;
2377 }
2378
DelRow(int in_key)2379 int Kis_Scrollable_Table::DelRow(int in_key) {
2380 if (key_map.find(in_key) == key_map.end()) {
2381 // _MSG("Scrollable_Table tried to del row that doesn't exist", MSGFLAG_ERROR);
2382 return -1;
2383 }
2384
2385 key_map.erase(key_map.find(in_key));
2386
2387 for (unsigned int x = 0; x < data_vec.size(); x++) {
2388 if (data_vec[x]->key == in_key) {
2389 delete data_vec[x];
2390 data_vec.erase(data_vec.begin() + x);
2391 break;
2392 }
2393 }
2394
2395 if (scroll_pos >= (int) data_vec.size()) {
2396 scroll_pos = data_vec.size() - 1;
2397 if (scroll_pos < 0)
2398 scroll_pos = 0;
2399 }
2400
2401 if (selected >= (int) data_vec.size()) {
2402 selected = data_vec.size() - 1;
2403 }
2404
2405 return 1;
2406 }
2407
ReplaceRow(int in_key,vector<string> in_fields)2408 int Kis_Scrollable_Table::ReplaceRow(int in_key, vector<string> in_fields) {
2409 if (key_map.find(in_key) == key_map.end()) {
2410 // Add a row instead
2411 return AddRow(in_key, in_fields);
2412
2413 #if 0
2414 _MSG("Scrollable_Table tried to replace row that doesn't exist",
2415 MSGFLAG_ERROR);
2416 return -1;
2417 #endif
2418 }
2419
2420 for (unsigned int x = 0; x < data_vec.size(); x++) {
2421 if (data_vec[x]->key == in_key) {
2422 data_vec[x]->data = in_fields;
2423 break;
2424 }
2425 }
2426
2427 return 1;
2428 }
2429
Clear()2430 void Kis_Scrollable_Table::Clear() {
2431 for (unsigned int x = 0; x < data_vec.size(); x++)
2432 delete data_vec[x];
2433
2434 data_vec.clear();
2435 key_map.clear();
2436
2437 return;
2438 }
2439
Kis_Single_Input(GlobalRegistry * in_globalreg,Kis_Panel * in_panel)2440 Kis_Single_Input::Kis_Single_Input(GlobalRegistry *in_globalreg,
2441 Kis_Panel *in_panel) :
2442 Kis_Panel_Component(in_globalreg, in_panel) {
2443 globalreg = in_globalreg;
2444 curs_pos = 0;
2445 inp_pos = 0;
2446 label_pos = LABEL_POS_NONE;
2447 max_len = 0;
2448 draw_len = 0;
2449 }
2450
~Kis_Single_Input()2451 Kis_Single_Input::~Kis_Single_Input() {
2452 // Nothing
2453 }
2454
DrawComponent()2455 void Kis_Single_Input::DrawComponent() {
2456 if (visible == 0)
2457 return;
2458
2459 parent_panel->ColorFromPref(color_active, color_active_pref);
2460 parent_panel->ColorFromPref(color_inactive, color_inactive_pref);
2461
2462 SetTransColor(color_active);
2463
2464 int xoff = 0;
2465 int yoff = 0;
2466
2467 // Draw the label if we can, in bold
2468 if (ly >= 2 && label_pos == LABEL_POS_TOP) {
2469 wattron(window, WA_BOLD);
2470 mvwaddnstr(window, sy, sx, label.c_str(), lx);
2471 wattroff(window, WA_BOLD);
2472 yoff = 1;
2473 } else if (label_pos == LABEL_POS_LEFT) {
2474 wattron(window, WA_BOLD);
2475 mvwaddnstr(window, sy, sx, label.c_str(), lx);
2476 wattroff(window, WA_BOLD);
2477 xoff += label.length() + 1;
2478 }
2479
2480 // set the drawing length
2481 draw_len = lx - xoff;
2482
2483 if (draw_len < 0)
2484 draw_len = 0;
2485
2486 // Don't let us fall behind start
2487 if (curs_pos < 0)
2488 curs_pos = 0;
2489
2490 // Clean up any silliness that might be present from initialization
2491 if (inp_pos - curs_pos >= draw_len)
2492 curs_pos = inp_pos - draw_len + 1;
2493
2494 // Reset the default color again since we messed with bold attributes
2495 SetTransColor(color_active);
2496
2497 // Invert for the text
2498 wattron(window, WA_REVERSE);
2499
2500 /* draw the inverted line */
2501 mvwhline(window, sy + yoff, sx + xoff, ' ', draw_len);
2502
2503 if (curs_pos >= (int) text.length())
2504 curs_pos = 0;
2505
2506 // fprintf(stderr, "debug - about to try to substr %d %d from len %d\n", curs_pos, draw_len, text.length());
2507
2508 /* draw the text from cur to what fits */
2509 mvwaddnstr(window, sy + yoff, sx + xoff,
2510 text.substr(curs_pos, draw_len).c_str(), draw_len);
2511
2512 /* Underline & unreverse the last character of the text (or space) */
2513 wattroff(window, WA_REVERSE);
2514
2515 if (active) {
2516 wattron(window, WA_UNDERLINE);
2517 char ch;
2518 if (inp_pos < (int) text.length())
2519 ch = text[inp_pos];
2520 else
2521 ch = ' ';
2522
2523 mvwaddch(window, sy + yoff, sx + xoff + (inp_pos - curs_pos), ch);
2524 wattroff(window, WA_UNDERLINE);
2525 }
2526 }
2527
KeyPress(int in_key)2528 int Kis_Single_Input::KeyPress(int in_key) {
2529 if (visible == 0 || draw_len == 0)
2530 return 0;
2531
2532 // scroll left, and move the viewing window if we have to
2533 if (in_key == KEY_LEFT && inp_pos > 0) {
2534 inp_pos--;
2535 if (inp_pos < curs_pos)
2536 curs_pos = inp_pos;
2537 return 0;
2538 }
2539
2540 // scroll right, and move the viewing window if we have to
2541 if (in_key == KEY_RIGHT && inp_pos < (int) text.length()) {
2542 inp_pos++;
2543
2544 if (inp_pos - curs_pos >= draw_len)
2545 curs_pos = inp_pos - draw_len + 1;
2546
2547 return 0;
2548 }
2549
2550 // Catch home/end (if we can)
2551 if (in_key == KEY_HOME) {
2552 inp_pos = 0;
2553 curs_pos = 0;
2554
2555 return 0;
2556 }
2557
2558 if (in_key == KEY_END) {
2559 inp_pos = text.length();
2560 curs_pos = inp_pos - draw_len + 1;
2561
2562 return 0;
2563 }
2564
2565 // Catch deletes
2566 if ((in_key == KEY_BACKSPACE || in_key == 0x7F) && text.length() > 0) {
2567 if (inp_pos == 0)
2568 inp_pos = 1;
2569
2570 text.erase(text.begin() + (inp_pos - 1));
2571
2572 if (inp_pos > 0)
2573 inp_pos--;
2574
2575 if (inp_pos < curs_pos)
2576 curs_pos = inp_pos;
2577
2578 return 0;
2579 }
2580
2581 // Lastly, if the character is in our filter of allowed characters for typing,
2582 // and if we have room, insert it and scroll to the right
2583 if ((int) text.length() < max_len &&
2584 filter_map.find(in_key) != filter_map.end()) {
2585 char ins[2] = { (char) in_key, (char) 0 };
2586 text.insert(inp_pos, ins);
2587 inp_pos++;
2588
2589 if (inp_pos - curs_pos >= draw_len)
2590 curs_pos = inp_pos - draw_len + 1;
2591
2592 return 0;
2593 }
2594
2595 return 0;
2596 }
2597
MouseEvent(MEVENT * mevent)2598 int Kis_Single_Input::MouseEvent(MEVENT *mevent) {
2599 int mwx, mwy;
2600 getbegyx(window, mwy, mwx);
2601
2602 mwx = mevent->x - mwx;
2603 mwy = mevent->y - mwy;
2604
2605 if (mevent->bstate == 4 && mwy == sy && mwx >= sx && mwx <= ex) {
2606 // Single input only does a focus switch on mouse events
2607 if (cb_switch != NULL)
2608 (*cb_switch)(this, 1, cb_switch_aux, globalreg);
2609
2610 return 1;
2611 }
2612
2613 return 0;
2614 }
2615
SetCharFilter(string in_charfilter)2616 void Kis_Single_Input::SetCharFilter(string in_charfilter) {
2617 filter_map.clear();
2618 for (unsigned int x = 0; x < in_charfilter.length(); x++) {
2619 filter_map[in_charfilter[x]] = 1;
2620 }
2621 }
2622
SetLabel(string in_label,KisWidget_LabelPos in_pos)2623 void Kis_Single_Input::SetLabel(string in_label, KisWidget_LabelPos in_pos) {
2624 label = in_label;
2625 label_pos = in_pos;
2626 SetPreferredSize(label.length() + max_len + 1, 1);
2627 SetMinSize(label.length() + 3, 1);
2628 }
2629
SetTextLen(int in_len)2630 void Kis_Single_Input::SetTextLen(int in_len) {
2631 max_len = in_len;
2632 SetPreferredSize(in_len + label.length() + 1, 1);
2633 SetMinSize(label.length() + 3, 1);
2634 }
2635
SetText(string in_text,int dpos,int ipos)2636 void Kis_Single_Input::SetText(string in_text, int dpos, int ipos) {
2637 text = in_text;
2638
2639 if (ipos < 0)
2640 inp_pos = in_text.length();
2641 else
2642 inp_pos = ipos;
2643
2644 if (dpos < 0)
2645 curs_pos = 0;
2646 else
2647 curs_pos = dpos;
2648 }
2649
GetText()2650 string Kis_Single_Input::GetText() {
2651 return text;
2652 }
2653
Kis_Button(GlobalRegistry * in_globalreg,Kis_Panel * in_panel)2654 Kis_Button::Kis_Button(GlobalRegistry *in_globalreg, Kis_Panel *in_panel) :
2655 Kis_Panel_Component(in_globalreg, in_panel) {
2656 globalreg = in_globalreg;
2657
2658 active = 0;
2659 SetMinSize(3, 1);
2660 }
2661
~Kis_Button()2662 Kis_Button::~Kis_Button() {
2663 // nada
2664 }
2665
DrawComponent()2666 void Kis_Button::DrawComponent() {
2667 if (visible == 0)
2668 return;
2669
2670 parent_panel->ColorFromPref(color_active, color_active_pref);
2671 parent_panel->ColorFromPref(color_inactive, color_inactive_pref);
2672
2673 SetTransColor(color_active);
2674
2675 // Draw the highlighted button area if we're active
2676 if (active)
2677 wattron(window, WA_REVERSE);
2678
2679 mvwhline(window, sy, sx, ' ', lx);
2680
2681 // Center the text
2682 int tx = (lx / 2) - (text.length() / 2);
2683 mvwaddnstr(window, sy, sx + tx, text.c_str(), lx - tx);
2684
2685 // Add the ticks
2686 mvwaddch(window, sy, sx, '[');
2687 mvwaddch(window, sy, sx + lx - 1, ']');
2688
2689 if (active)
2690 wattroff(window, WA_REVERSE);
2691 }
2692
KeyPress(int in_key)2693 int Kis_Button::KeyPress(int in_key) {
2694 if (visible == 0)
2695 return 0;
2696
2697 if (in_key == KEY_ENTER || in_key == '\n' || in_key == ' ') {
2698 if (cb_activate != NULL)
2699 (*cb_activate)(this, 1, cb_activate_aux, globalreg);
2700
2701 return 1;
2702 }
2703
2704 return 0;
2705 }
2706
MouseEvent(MEVENT * mevent)2707 int Kis_Button::MouseEvent(MEVENT *mevent) {
2708 int mwx, mwy;
2709 getbegyx(window, mwy, mwx);
2710
2711 mwx = mevent->x - mwx;
2712 mwy = mevent->y - mwy;
2713
2714 if (mevent->bstate == 4 && mwy == sy && mwx >= sx && mwx <= ex) {
2715 if (cb_activate != NULL)
2716 (*cb_activate)(this, 1, cb_activate_aux, globalreg);
2717
2718 return 1;
2719 }
2720
2721 return 0;
2722 }
2723
SetText(string in_text)2724 void Kis_Button::SetText(string in_text) {
2725 text = in_text;
2726 SetPreferredSize(text.length() + 4, 1);
2727 }
2728
Kis_Checkbox(GlobalRegistry * in_globalreg,Kis_Panel * in_panel)2729 Kis_Checkbox::Kis_Checkbox(GlobalRegistry *in_globalreg, Kis_Panel *in_panel) :
2730 Kis_Panel_Component(in_globalreg, in_panel) {
2731 globalreg = in_globalreg;
2732
2733 active = 0;
2734 checked = 0;
2735 }
2736
~Kis_Checkbox()2737 Kis_Checkbox::~Kis_Checkbox() {
2738 // nada
2739 }
2740
DrawComponent()2741 void Kis_Checkbox::DrawComponent() {
2742 if (visible == 0)
2743 return;
2744
2745 parent_panel->ColorFromPref(color_active, color_active_pref);
2746 parent_panel->ColorFromPref(color_inactive, color_inactive_pref);
2747
2748 SetTransColor(color_active);
2749
2750 // Draw the highlighted button area if we're active
2751 if (active)
2752 wattron(window, WA_REVERSE);
2753
2754 mvwhline(window, sy, sx, ' ', lx);
2755
2756 if (checked) {
2757 mvwaddnstr(window, sy, sx, "[X]", 3);
2758 } else {
2759 mvwaddnstr(window, sy, sx, "[ ]", 3);
2760 }
2761
2762 mvwaddnstr(window, sy, sx + 4, text.c_str(), lx - 4);
2763
2764 if (active)
2765 wattroff(window, WA_REVERSE);
2766 }
2767
Activate(int subcomponent)2768 void Kis_Checkbox::Activate(int subcomponent) {
2769 active = 1;
2770 }
2771
Deactivate()2772 void Kis_Checkbox::Deactivate() {
2773 active = 0;
2774 }
2775
KeyPress(int in_key)2776 int Kis_Checkbox::KeyPress(int in_key) {
2777 if (visible == 0)
2778 return 0;
2779
2780 if (in_key == KEY_ENTER || in_key == '\n' || in_key == ' ') {
2781 checked = !checked;
2782
2783 if (cb_activate != NULL)
2784 (*cb_activate)(this, 1, cb_activate_aux, globalreg);
2785
2786 return 0;
2787 }
2788
2789 return 0;
2790 }
2791
MouseEvent(MEVENT * mevent)2792 int Kis_Checkbox::MouseEvent(MEVENT *mevent) {
2793 int mwx, mwy;
2794 getbegyx(window, mwy, mwx);
2795
2796 mwx = mevent->x - mwx;
2797 mwy = mevent->y - mwy;
2798
2799 if (mevent->bstate == 4 && mwy == sy && mwx >= sx && mwx <= ex) {
2800 checked = !checked;
2801
2802 if (cb_activate != NULL)
2803 (*cb_activate)(this, 1, cb_activate_aux, globalreg);
2804
2805 return 1;
2806 }
2807
2808 return 0;
2809 }
2810
SetText(string in_text)2811 void Kis_Checkbox::SetText(string in_text) {
2812 text = in_text;
2813 SetPreferredSize(text.length() + 4, 1);
2814 }
2815
GetChecked()2816 int Kis_Checkbox::GetChecked() {
2817 return checked;
2818 }
2819
SetChecked(int in_check)2820 void Kis_Checkbox::SetChecked(int in_check) {
2821 checked = in_check;
2822 }
2823
Kis_Radiobutton(GlobalRegistry * in_globalreg,Kis_Panel * in_panel)2824 Kis_Radiobutton::Kis_Radiobutton(GlobalRegistry *in_globalreg, Kis_Panel *in_panel) :
2825 Kis_Panel_Component(in_globalreg, in_panel) {
2826 globalreg = in_globalreg;
2827
2828 active = 0;
2829 checked = 0;
2830 }
2831
~Kis_Radiobutton()2832 Kis_Radiobutton::~Kis_Radiobutton() {
2833 // nada
2834 }
2835
DrawComponent()2836 void Kis_Radiobutton::DrawComponent() {
2837 if (visible == 0)
2838 return;
2839
2840 parent_panel->ColorFromPref(color_active, color_active_pref);
2841 parent_panel->ColorFromPref(color_inactive, color_inactive_pref);
2842
2843 SetTransColor(color_active);
2844
2845 // Draw the highlighted button area if we're active
2846 if (active)
2847 wattron(window, WA_REVERSE);
2848
2849 mvwhline(window, sy, sx, ' ', lx);
2850
2851 if (checked) {
2852 mvwaddnstr(window, sy, sx, "(*)", 3);
2853 } else {
2854 mvwaddnstr(window, sy, sx, "( )", 3);
2855 }
2856
2857 mvwaddnstr(window, sy, sx + 4, text.c_str(), lx - 4);
2858
2859 if (active)
2860 wattroff(window, WA_REVERSE);
2861 }
2862
Activate(int subcomponent)2863 void Kis_Radiobutton::Activate(int subcomponent) {
2864 active = 1;
2865 }
2866
Deactivate()2867 void Kis_Radiobutton::Deactivate() {
2868 active = 0;
2869 }
2870
KeyPress(int in_key)2871 int Kis_Radiobutton::KeyPress(int in_key) {
2872 if (visible == 0)
2873 return 0;
2874
2875 if (in_key == KEY_ENTER || in_key == '\n' || in_key == ' ') {
2876 if (!checked)
2877 SetChecked(1);
2878
2879 if (cb_activate != NULL)
2880 (*cb_activate)(this, 1, cb_activate_aux, globalreg);
2881
2882 return 0;
2883 }
2884
2885 return 0;
2886 }
2887
MouseEvent(MEVENT * mevent)2888 int Kis_Radiobutton::MouseEvent(MEVENT *mevent) {
2889 int mwx, mwy;
2890 getbegyx(window, mwy, mwx);
2891
2892 mwx = mevent->x - mwx;
2893 mwy = mevent->y - mwy;
2894
2895 if (mevent->bstate == 4 && mwy == sy && mwx >= sx && mwx <= ex) {
2896 if (!checked)
2897 SetChecked(1);
2898
2899 if (cb_activate != NULL)
2900 (*cb_activate)(this, 1, cb_activate_aux, globalreg);
2901
2902 return 1;
2903 }
2904
2905 return 0;
2906 }
2907
SetText(string in_text)2908 void Kis_Radiobutton::SetText(string in_text) {
2909 text = in_text;
2910 SetPreferredSize(text.length() + 4, 1);
2911 }
2912
GetChecked()2913 int Kis_Radiobutton::GetChecked() {
2914 return checked;
2915 }
2916
SetChecked(int in_check)2917 void Kis_Radiobutton::SetChecked(int in_check) {
2918 checked = in_check;
2919
2920 for (unsigned int x = 0; x < linked_vec.size() && in_check; x++)
2921 linked_vec[x]->SetChecked(0);
2922
2923 }
2924
LinkRadiobutton(Kis_Radiobutton * in_button)2925 void Kis_Radiobutton::LinkRadiobutton(Kis_Radiobutton *in_button) {
2926 linked_vec.push_back(in_button);
2927 }
2928
AddExtDataVec(string name,int layer,string colorpref,string colordefault,char line,char fill,int overunder,vector<int> * in_dv)2929 void Kis_IntGraph::AddExtDataVec(string name, int layer, string colorpref,
2930 string colordefault, char line, char fill,
2931 int overunder, vector<int> *in_dv) {
2932 graph_source gs;
2933
2934 gs.layer = layer;
2935 gs.colorpref = colorpref;
2936 gs.colordefault = colordefault;
2937 gs.colorval = 0;
2938 snprintf(gs.line, 2, "%c", line);
2939 snprintf(gs.fill, 2, "%c", fill);
2940 gs.data = in_dv;
2941 gs.name = name;
2942 gs.overunder = overunder;
2943
2944 // Can't figure out how to do a sort template of a template class, so hell
2945 // with it, we'll do it sloppily here. Assembled least to greatest priority
2946 for (unsigned int x = 0; x < data_vec.size(); x++) {
2947 if (layer < data_vec[x].layer) {
2948 data_vec.insert(data_vec.begin() + x, gs);
2949 return;
2950 }
2951 }
2952
2953 if (name.length() > maxlabel)
2954 maxlabel = name.length();
2955
2956 // Add it to the end otherwise
2957 data_vec.push_back(gs);
2958 }
2959
KeyPress(int in_key)2960 int Kis_IntGraph::KeyPress(int in_key) {
2961 // Nothing to do for now
2962 return 1;
2963 }
2964
DrawComponent()2965 void Kis_IntGraph::DrawComponent() {
2966 if (visible == 0)
2967 return;
2968
2969 char backing[32];
2970
2971 parent_panel->ColorFromPref(color_fw, color_active_pref);
2972
2973 for (unsigned int x = 0; x < data_vec.size(); x++) {
2974 parent_panel->InitColorPref(data_vec[x].colorpref, data_vec[x].colordefault);
2975 parent_panel->ColorFromPref(data_vec[x].colorval, data_vec[x].colorpref);
2976 }
2977
2978 // We want the same scale for over/under, so we'll calculate the
2979 // height as h - 1 (label) (div 2 if o/u)
2980 int gh = (ly - 1) / (graph_mode == 1 ? 2 : 1) - xgraph_size;
2981 // Zero position on the graph is the bottom, or center, depending
2982 // on normal or over/under
2983 int gzero = ey - (graph_mode == 1 ? gh : 1) - xgraph_size;
2984 // Width - label
2985 int gw = lx;
2986 unsigned int gxofft;
2987
2988 // Set the drawing max and min
2989 int dmax_y = max_y;
2990 int dmin_y = min_y;
2991
2992 // Go through the list and get the max if we're auto-scaling
2993 if (max_y == 0 || min_y == 0) {
2994 for (unsigned int x = 0; x < data_vec.size(); x++) {
2995 for (unsigned int z = 0; z < data_vec[x].data->size(); z++) {
2996 if (max_y == 0 &&
2997 (((*(data_vec[x].data))[z] > 0 &&
2998 dmax_y < (*(data_vec[x].data))[z]) ||
2999 ((*(data_vec[x].data))[z] < 0 &&
3000 dmax_y > (*(data_vec[x].data))[z])))
3001 dmax_y = (*(data_vec[x].data))[z];
3002 }
3003 }
3004 }
3005
3006 // adjust the drawing size
3007 snprintf(backing, 32, " %d ", dmax_y);
3008 gxofft = strlen(backing);
3009 snprintf(backing, 32, " %d ", dmin_y);
3010 if (strlen(backing) > gxofft)
3011 gxofft = strlen(backing);
3012 gw -= gxofft;
3013
3014 // Go through from least to greatest priority so that the "high" priority
3015 // draws over the old
3016 for (unsigned int x = 0; x < data_vec.size(); x++) {
3017 int xmod = 0;
3018 int xgroup = 1;
3019 int dvsize = data_vec[x].data->size();
3020
3021 if (inter_x) {
3022 xmod = (int) ceilf((float) dvsize / (float) gw);
3023 xgroup = xmod * 2;
3024 }
3025
3026 for (int gx = 0; (gx < gw) && inter_x; gx++) {
3027 int r = 0, py, nuse = 0;
3028 // We make the assumption here that T is a numerical
3029 // type in some fashion, if this is ever not true we'll have
3030 // to do something else
3031 // int avg = 0;
3032 int max = 0;
3033
3034 // Interpolate down if we have too much data
3035 if (gw < dvsize) {
3036 // Center of the samples we look at
3037 r = (int) (((float) gx / (float) gw) * (float) dvsize);
3038
3039 // Determine the local max across our range
3040 for (int pos = -1 * (xgroup / 2); pos < (xgroup / 2); pos++) {
3041 if (r + pos >= dvsize || r + pos < 0) {
3042 continue;
3043 }
3044
3045 // Max depending on if we're neg or pos data
3046 if ((*(data_vec[x].data))[r + pos] >= 0 &&
3047 (*(data_vec[x].data))[r + pos] > max) {
3048 if ((*(data_vec[x].data))[r+pos] > dmax_y) {
3049 max = dmax_y;
3050 } else {
3051 max = (*(data_vec[x].data))[r + pos];
3052 }
3053 } else if ((*(data_vec[x].data))[r + pos] < 0 &&
3054 (*(data_vec[x].data))[r + pos] < max) {
3055 if ((*(data_vec[x].data))[r+pos] < dmin_y) {
3056 max = dmin_y;
3057 } else {
3058 max = (*(data_vec[x].data))[r + pos];
3059 }
3060 }
3061
3062 nuse++;
3063 }
3064 } else {
3065 nuse = 1;
3066 unsigned int pos = (unsigned int) (((float) gx/gw) * dvsize);
3067 if (pos >= (*(data_vec)[x].data).size() || pos < 0) {
3068 max = min_y;
3069 } else {
3070 max = (*(data_vec)[x].data)[pos];
3071 }
3072 }
3073
3074 if (nuse == 0) {
3075 continue;
3076 }
3077
3078 // If we're negative, do the math differently
3079 // Adapt the group max to our scale
3080 float adapted = 0;
3081
3082 if (max < 0) {
3083 adapted =
3084 (float) (abs(max) + dmin_y) /
3085 (float) (abs(dmax_y) + dmin_y);
3086 } else {
3087 adapted = (float) (max - min_y) / (float) (dmax_y - min_y);
3088 }
3089
3090 // Scale it to the height of the graph
3091 py = (int) ((float) gh * adapted);
3092
3093 // Set the color once
3094 wattrset(window, data_vec[x].colorval);
3095
3096 // If we're plotting over/normal, we do nothing
3097 // If we're plotting under, we invert and draw below
3098 int oumod = 1;
3099 if (data_vec[x].overunder < 0 && graph_mode == 1)
3100 oumod = -1;
3101
3102 for (int gy = gh; gy >= 0; gy--) {
3103 if (gy == py)
3104 mvwaddstr(window, gzero - (gy * oumod), sx + gx + gxofft,
3105 data_vec[x].line);
3106 else if (gy < py)
3107 mvwaddstr(window, gzero - (gy * oumod), sx + gx + gxofft,
3108 data_vec[x].fill);
3109 }
3110 }
3111
3112 int rwidth = (int) kismin(2, (1.0f / dvsize) * gw);
3113 for (int dvx = 0; dvx < dvsize && inter_x == 0; dvx++) {
3114 int py = 0;
3115 int max = (*(data_vec)[x].data)[dvx];
3116 int drawx = (int) (((float) dvx / dvsize) * gw);
3117
3118 // If we're negative, do the math differently
3119 // Adapt the group max to our scale
3120 float adapted = 0;
3121
3122 if (max < 0) {
3123 adapted =
3124 (float) (abs(max) + dmin_y) /
3125 (float) (abs(dmax_y) + dmin_y);
3126 } else {
3127 adapted = (float) (max - min_y) / (float) (dmax_y - min_y);
3128 }
3129
3130 // Scale it to the height of the graph
3131 py = (int) ((float) gh * adapted);
3132
3133 // Set the color once
3134 wattrset(window, data_vec[x].colorval);
3135
3136 for (int rdx = rwidth * -1; rdx < rwidth; rdx++) {
3137 // If we're plotting over/normal, we do nothing
3138 // If we're plotting under, we invert and draw below
3139 int oumod = 1;
3140 if (data_vec[x].overunder < 0 && graph_mode == 1)
3141 oumod = -1;
3142
3143 for (int gy = gh; gy >= 0; gy--) {
3144 if (gy == py)
3145 mvwaddstr(window, gzero - (gy * oumod),
3146 sx + drawx + rdx + gxofft,
3147 data_vec[x].line);
3148 else if (gy < py && data_vec[x].fill)
3149 mvwaddstr(window, gzero - (gy * oumod),
3150 sx + drawx + rdx + gxofft,
3151 data_vec[x].fill);
3152 }
3153
3154 }
3155 }
3156 }
3157
3158 if (draw_layers) {
3159 // Draw the labels (right-hand)
3160 int posmod = 0, negmod = 0;
3161 // Set the backing blank
3162 memset(backing, ' ', 32);
3163 if ((maxlabel + 4) >= 32)
3164 maxlabel = (32 - 4);
3165 backing[maxlabel + 4] = '\0';
3166 // Draw the component name labels
3167 for (unsigned int x = 0; x < data_vec.size(); x++) {
3168 // Position
3169 int lpos = 0;
3170 // Text color
3171 if (data_vec[x].overunder < 0 && graph_mode == 1) {
3172 lpos = ey - negmod++;
3173 } else {
3174 lpos = sy + posmod++;
3175 }
3176 // Fill in the blocking
3177 wattrset(window, color_fw);
3178 mvwaddstr(window, lpos, ex - (maxlabel + 4), backing);
3179 // Fill in the label
3180 mvwaddstr(window, lpos, ex - (maxlabel), data_vec[x].name.c_str());
3181
3182 // Fill in the colors
3183 wattrset(window, data_vec[x].colorval);
3184 mvwaddstr(window, lpos, ex - (maxlabel + 3), data_vec[x].line);
3185 mvwaddstr(window, lpos, ex - (maxlabel + 2), data_vec[x].fill);
3186 }
3187 }
3188
3189 // Draw the X marker labels
3190 wattrset(window, color_fw);
3191 for (unsigned int x = 0; x < label_x.size() && label_x_graphref >= 0; x++) {
3192 // GX within the # of samples on the graph
3193 int lgx = (int) (((float) gw / data_vec[label_x_graphref].data->size()) *
3194 label_x[x].position);
3195 for (unsigned int y = 0; y < label_x[x].label.size(); y++) {
3196 mvwaddch(window, gzero + y + 1, sx + lgx + gxofft, label_x[x].label[y]);
3197 }
3198 }
3199
3200 // Reuse the backing for the scale
3201 if (draw_scale) {
3202 snprintf(backing, 32, " %d ", dmax_y);
3203 wattrset(window, color_fw);
3204 mvwaddstr(window, sy, sx, backing);
3205
3206 wattrset(window, color_fw);
3207 mvwhline(window, gzero, sx, ACS_HLINE, lx);
3208
3209 snprintf(backing, 32, " %d ", min_y);
3210 mvwaddstr(window, gzero, sx, backing);
3211 }
3212 }
3213
3214 #if 0
3215 int Kis_PolarGraph::KeyPress(int in_key) {
3216 return 1;
3217 }
3218
3219 void Kis_PolarGraph::DrawComponent() {
3220 if (visible == 0)
3221 return;
3222
3223 // Square ourselves to the shortest dimension
3224 if (lx < ly)
3225 ly = lx;
3226 else
3227 lx = ly;
3228
3229 parent_panel->InitColorPref(color_active_pref, "white,black");
3230 parent_panel->ColorFromPref(color_fw, color_active_pref);
3231
3232 for (unsigned int x = 0; x < point_vec.size(); x++) {
3233 // Real position
3234 int px = (lx / 2) + point_vec[x].r * sin(point_vec[x].theta) * (lx / 2);
3235 int py = (ly / 2) - point_vec[x].r * cos(point_vec[x].theta) * (lx / 2);
3236
3237 // fprintf(stderr, "debug - graph %s pos %d %d\n", point_vec[x].name.c_str(), px, py);
3238
3239 // Plot the text at the position
3240 //wattrset(window, point_vec[x].colorval);
3241
3242 // Plot w/in boundaries
3243 mvwaddnstr(window, sy + py, sx + px, point_vec[x].name.c_str(),
3244 point_vec[x].name.length());
3245 }
3246
3247 }
3248
3249 void Kis_PolarGraph::AddPoint(int id, graph_point gp) {
3250 parent_panel->InitColorPref(gp.colorpref, gp.colordefault);
3251 parent_panel->ColorFromPref(gp.colorval, gp.colorpref);
3252
3253 gp.id = id;
3254
3255 if (fabs(gp.r) > maxr)
3256 maxr = fabs(gp.r);
3257
3258 for (unsigned int x = 0; x < point_vec.size(); x++) {
3259 if (point_vec[x].id == id) {
3260 point_vec[x] = gp;
3261 return;
3262 }
3263 }
3264
3265 point_vec.push_back(gp);
3266 }
3267
3268 void Kis_PolarGraph::DelPoint(int id) {
3269 maxr = 0;
3270
3271 for (unsigned int x = 0; x < point_vec.size(); x++) {
3272 if (point_vec[x].id == id) {
3273 point_vec.erase(point_vec.begin() + x);
3274 x--;
3275 continue;
3276 }
3277
3278 if (fabs(point_vec[x].r) > maxr)
3279 maxr = fabs(point_vec[x].r);
3280 }
3281 }
3282
3283 void Kis_PolarGraph::ClearPoints() {
3284 maxr = 0;
3285 point_vec.clear();
3286 }
3287
3288 Kis_Filepicker::Kis_Filepicker(GlobalRegistry *in_globalreg, Kis_Panel *in_panel) :
3289 Kis_Scrollable_Table(in_globalreg, in_panel) {
3290
3291 globalreg = in_globalreg;
3292 active = 0;
3293
3294 vector<Kis_Scrollable_Table::title_data> titles;
3295 Kis_Scrollable_Table::title_data t;
3296 t.width = 0;
3297 t.title = "File";
3298 t.alignment = 0;
3299 titles.push_back(t);
3300
3301 AddTitles(titles);
3302
3303 SetDrawTitles(0);
3304 SetLockScrollTop(1);
3305 }
3306
3307 Kis_Filepicker::~Kis_Filepicker() {
3308
3309 }
3310
3311 void Kis_Filepicker::SetDirectory(string in_dir) {
3312 DIR *dir;
3313 struct dirent *file;
3314 struct stat sbuf;
3315 vector<string> content;
3316
3317 if (in_dir == cur_directory)
3318 return;
3319
3320 if (in_dir[in_dir.length() - 1] != '/')
3321 in_dir += "/";
3322
3323 cur_directory = in_dir;
3324
3325 if ((dir = opendir(in_dir.c_str())) == NULL) {
3326 content.push_back("[ Invalid Directory:");
3327 content.push_back(string(" ") + in_dir + string(" ]"));
3328 return;
3329 }
3330
3331 while ((file = readdir(dir)) != NULL) {
3332 if (string(file->d_name) == ".")
3333 continue;
3334
3335 if (stat(file->d_name, &sbuf) < 0)
3336 continue;
3337
3338 if (S_ISDIR(sbuf.st_mode)) {
3339 string n = string(file->d_name);
3340 if (n != "..")
3341 n += "/";
3342
3343 content.push_back(n);
3344 }
3345 }
3346
3347 rewinddir(dir);
3348
3349 while ((file = readdir(dir)) != NULL) {
3350 if (stat(file->d_name, &sbuf) < 0)
3351 continue;
3352
3353 if (S_ISREG(sbuf.st_mode)) {
3354 content.push_back(string(file->d_name));
3355 }
3356 }
3357
3358 closedir(dir);
3359
3360 vector<string> td;
3361 td.push_back("");
3362
3363 for (unsigned int x = 0; x < content.size(); x++) {
3364 td[0] = content[x];
3365 ReplaceRow(x, td);
3366 }
3367
3368 SetFile(set_file);
3369 }
3370
3371 void Kis_Filepicker::SetFile(string in_file) {
3372 set_file = in_file;
3373
3374 if (set_file == "")
3375 return;
3376
3377 for (unsigned int x = 0; x < data_vec.size(); x++) {
3378 if (data_vec[x]->data[0] == set_file) {
3379 SetSelected(x);
3380 return;
3381 }
3382 }
3383 }
3384
3385 int Kis_Filepicker::KeyPress(int in_key) {
3386 struct stat sbuf;
3387
3388 if (visible == 0)
3389 return 0;
3390
3391 if (data_vec.size() > 0 && (in_key == '\n' || in_key == '\r' || in_key == ' ')) {
3392 vector<string> sel = GetSelectedData();
3393 if (sel.size() == 1) {
3394 if (stat(string(cur_directory + sel[0]).c_str(), &sbuf) == 0) {
3395 if (sel[0] == "..") {
3396 if (sel[0].rfind("/") != string::npos) {
3397 SetDirectory(sel[0].substr(0, sel[0].rfind("/")));
3398 }
3399 } else if (S_ISDIR(sbuf.st_mode)) {
3400 SetDirectory(cur_directory + sel[0]);
3401 return 0;
3402 }
3403 }
3404 }
3405 }
3406
3407 return Kis_Scrollable_Table::KeyPress(in_key);
3408 }
3409
3410 #endif
3411
Kis_Panel(GlobalRegistry * in_globalreg,KisPanelInterface * in_intf)3412 Kis_Panel::Kis_Panel(GlobalRegistry *in_globalreg, KisPanelInterface *in_intf) {
3413 globalreg = in_globalreg;
3414 kpinterface = in_intf;
3415 win = newwin(1, 1, 0, 0);
3416 pan = new_panel(win);
3417 hide_panel(pan);
3418 menu = NULL;
3419
3420 text_color = border_color = 0;
3421 InitColorPref("panel_text_color", "white,black");
3422 InitColorPref("panel_border_color", "blue,black");
3423 ColorFromPref(text_color, "panel_text_color");
3424 ColorFromPref(border_color, "panel_border_color");
3425
3426 sx = sy = sizex = sizey = 0;
3427
3428 active_component = NULL;
3429 main_component = NULL;
3430 tab_pos = -1;
3431
3432 last_key = 0;
3433 last_key_time.tv_sec = 0;
3434
3435 escape_timer = -1;
3436 }
3437
~Kis_Panel()3438 Kis_Panel::~Kis_Panel() {
3439 for (unsigned int x = 0; x < pan_comp_vec.size(); x++) {
3440 if (pan_comp_vec[x].comp_flags & KIS_PANEL_COMP_STATIC)
3441 continue;
3442
3443 delete pan_comp_vec[x].comp;
3444 }
3445
3446 if (pan != NULL)
3447 del_panel(pan);
3448 if (win != NULL)
3449 delwin(win);
3450 }
3451
AddComponentVec(Kis_Panel_Component * in_comp,int in_flags)3452 void Kis_Panel::AddComponentVec(Kis_Panel_Component *in_comp, int in_flags) {
3453 component_entry etr;
3454
3455 etr.comp_flags = in_flags;
3456 etr.comp = in_comp;
3457
3458 pan_comp_vec.push_back(etr);
3459 }
3460
DelComponentVec(Kis_Panel_Component * in_comp)3461 void Kis_Panel::DelComponentVec(Kis_Panel_Component *in_comp) {
3462 for (unsigned int x = 0; x < pan_comp_vec.size(); x++) {
3463 if (pan_comp_vec[x].comp == in_comp) {
3464 pan_comp_vec.erase(pan_comp_vec.begin() + x);
3465 return;
3466 }
3467 }
3468 }
3469
SetActiveComponent(Kis_Panel_Component * in_comp)3470 void Kis_Panel::SetActiveComponent(Kis_Panel_Component *in_comp) {
3471 for (unsigned int x = 0; x < pan_comp_vec.size(); x++) {
3472 if (pan_comp_vec[x].comp == in_comp) {
3473 active_component = in_comp;
3474 tab_pos = x;
3475 in_comp->Activate(0);
3476 } else {
3477 pan_comp_vec[x].comp->Deactivate();
3478 }
3479 }
3480 }
3481
KeyPress(int in_key)3482 int Kis_Panel::KeyPress(int in_key) {
3483 int ret;
3484
3485 if (menu) {
3486 ret = menu->KeyPress(in_key);
3487
3488 if (ret != 0)
3489 return 0;
3490 }
3491
3492 // figure out if we need to get to a visible item first and jump to it via the
3493 // tab function
3494 if (active_component != NULL && active_component->GetVisible() == 0 &&
3495 in_key != '\t')
3496 KeyPress('\t');
3497
3498 if (in_key == '\t' && tab_pos >= 0) {
3499 int set = -1;
3500
3501 // Find from current to end
3502 for (unsigned int x = tab_pos + 1; x < pan_comp_vec.size(); x++) {
3503 if ((pan_comp_vec[x].comp_flags & KIS_PANEL_COMP_TAB) == 0 ||
3504 (pan_comp_vec[x].comp->GetVisible() == 0))
3505 continue;
3506
3507 set = x;
3508 break;
3509 }
3510
3511 // No? Find from start
3512 if (set == -1) {
3513 for (unsigned int x = 0; x < pan_comp_vec.size(); x++) {
3514 if ((pan_comp_vec[x].comp_flags & KIS_PANEL_COMP_TAB) == 0 ||
3515 (pan_comp_vec[x].comp->GetVisible() == 0))
3516 continue;
3517
3518 set = x;
3519 break;
3520 }
3521 }
3522
3523 // No? Someone deleted the tabable components then, just stop
3524 if (set == -1) {
3525 tab_pos = -1;
3526 return 0;
3527 }
3528
3529 pan_comp_vec[tab_pos].comp->Deactivate();
3530 tab_pos = set;
3531
3532 pan_comp_vec[tab_pos].comp->Activate(1);
3533 active_component = pan_comp_vec[tab_pos].comp;
3534 }
3535
3536 if (active_component != NULL) {
3537 ret = active_component->KeyPress(in_key);
3538 return 0;
3539 }
3540
3541 return 0;
3542 }
3543
MouseEvent(MEVENT * mevent)3544 int Kis_Panel::MouseEvent(MEVENT *mevent) {
3545 int ret;
3546
3547 // We just process every component until we get a non-0
3548 for (unsigned int x = 0; x < pan_comp_vec.size(); x++) {
3549 if ((pan_comp_vec[x].comp_flags & KIS_PANEL_COMP_EVT) == 0)
3550 continue;
3551
3552 ret = pan_comp_vec[x].comp->MouseEvent(mevent);
3553
3554 if (ret != 0) {
3555 // Positive response means switch the focus
3556 if (ret >= 0) {
3557 if (active_component != NULL)
3558 active_component->Deactivate();
3559
3560 if ((pan_comp_vec[x].comp_flags & KIS_PANEL_COMP_TAB) &&
3561 tab_pos >= 0) {
3562 tab_pos = x;
3563 }
3564
3565 active_component = pan_comp_vec[x].comp;
3566 active_component->Activate(0);
3567 }
3568
3569 return 0;
3570 }
3571 }
3572
3573 return 0;
3574 }
3575
InitColorPref(string in_pref,string in_def)3576 void Kis_Panel::InitColorPref(string in_pref, string in_def) {
3577 if (kpinterface->prefs->FetchOpt(in_pref) == "")
3578 kpinterface->prefs->SetOpt(in_pref, in_def, 1);
3579 }
3580
ColorFromPref(int & clr,string in_pref)3581 void Kis_Panel::ColorFromPref(int &clr, string in_pref) {
3582 /*
3583 if (kpinterface->prefs->FetchOptDirty(in_pref) || clr == 0) {
3584 kpinterface->prefs->SetOptDirty(in_pref, 0);
3585 */
3586 clr = kpinterface->colors.AddColor(kpinterface->prefs->FetchOpt(in_pref),
3587 in_pref);
3588 /*
3589 }
3590 */
3591
3592 return;
3593 }
3594
RemapAllColors(string oldcolor,string newcolor)3595 void Kis_Panel::RemapAllColors(string oldcolor, string newcolor) {
3596 kpinterface->colors.RemapAllColors(oldcolor, newcolor, kpinterface->prefs);
3597 }
3598
AddColor(string in_color)3599 int Kis_Panel::AddColor(string in_color) {
3600 return kpinterface->colors.AddColor(in_color, "");
3601 }
3602
Position(int in_sy,int in_sx,int in_y,int in_x)3603 void Kis_Panel::Position(int in_sy, int in_sx, int in_y, int in_x) {
3604 sx = in_sx;
3605 sy = in_sy;
3606 sizex = in_x;
3607 sizey = in_y;
3608
3609 if (win == NULL) {
3610 win = newwin(sizey, sizex, sy, sx);
3611 }
3612
3613 if (pan == NULL) {
3614 pan = new_panel(win);
3615 } else {
3616 wresize(win, sizey, sizex);
3617 replace_panel(pan, win);
3618 move_panel(pan, sy, sx);
3619 ClearPanel();
3620 }
3621
3622 keypad(win, true);
3623 meta(win, true);
3624
3625 if (menu != NULL)
3626 menu->SetPosition(1, 0, 0, 0);
3627
3628 if (main_component != NULL)
3629 main_component->SetPosition(1, 1, in_x - 1, in_y - 2);
3630 }
3631
kp_escape_timer(TIMEEVENT_PARMS)3632 int kp_escape_timer(TIMEEVENT_PARMS) {
3633 // fprintf(stderr, "trigger escape timer %u %u\n", globalreg->timestamp.tv_sec, globalreg->timestamp.tv_usec);
3634 ungetch(0x00);
3635 ((Kis_Panel *) parm)->Poll();
3636
3637 return 0;
3638 }
3639
Poll()3640 int Kis_Panel::Poll() {
3641 if (globalreg->spindown)
3642 return 0;
3643
3644 int get = wgetch(win);
3645 MEVENT mevent;
3646 int ret;
3647 int escape_timer_possible = 1;
3648
3649 /*
3650 // Timeout on our internal escape handler
3651 struct timeval key_diff;
3652
3653 SubtractTimeval(&(globalreg->timestamp),
3654 &last_key_time,
3655 &key_diff);
3656
3657 if (key_diff.tv_sec > 1 ||
3658 key_diff.tv_usec > 500000) {
3659 last_key = 0;
3660 }
3661
3662 last_key_time.tv_sec = globalreg->timestamp.tv_sec;
3663 last_key_time.tv_usec = globalreg->timestamp.tv_usec;
3664 */
3665
3666 if (get == KEY_RESIZE) {
3667 globalreg->winch = 1;
3668 }
3669
3670 if (escape_timer > 0) {
3671 globalreg->timetracker->RemoveTimer(escape_timer);
3672 escape_timer = -1;
3673
3674 // Don't allow requeuing a second timer on a timered escape
3675 escape_timer_possible = 0;
3676 }
3677
3678 // If we're getting triggered from the timer callback
3679 if (get == 0x00) {
3680 get = 0x1b;
3681 }
3682
3683 if (get == 0x1b && last_key != 0x1b) {
3684 last_key = 0x1b;
3685 // fprintf(stderr, "schedule escape timer %u %u\n", globalreg->timestamp.tv_sec, globalreg->timestamp.tv_usec);
3686 if (escape_timer_possible) {
3687 escape_timer =
3688 globalreg->timetracker->RegisterTimer(2, NULL, 0,
3689 &kp_escape_timer, this);
3690 return 1;
3691 }
3692 } else if (last_key == 0x1b && get == 0x5b) {
3693 last_key = 0x5b;
3694 return 1;
3695 } else if (last_key == 0x5b) {
3696 switch (get) {
3697 case 0x41:
3698 get = KEY_UP;
3699 break;
3700 case 0x42:
3701 get = KEY_DOWN;
3702 break;
3703 case 0x43:
3704 get = KEY_RIGHT;
3705 break;
3706 case 0x44:
3707 get = KEY_LEFT;
3708 break;
3709 default:
3710 break;
3711 }
3712 } else {
3713 last_key = 0;
3714 }
3715
3716 if (get == KEY_MOUSE) {
3717 getmouse(&mevent);
3718 ret = MouseEvent(&mevent);
3719 } else {
3720 // fprintf(stderr, "debug - passing key %02x\n", get);
3721 ret = KeyPress(get);
3722 }
3723
3724 // If we can't trigger a timer, this means we came in from a timer,
3725 // which means we should force an extra interface redraw to handle what
3726 // it may have changed, we don't get our normal redraw since we didn't get
3727 // a real keypress
3728 if (escape_timer_possible == 0)
3729 kpinterface->DrawInterface();
3730
3731 if (ret < 0)
3732 return ret;
3733
3734 return 1;
3735 }
3736
SetTitle(string in_title)3737 void Kis_Panel::SetTitle(string in_title) {
3738 title = in_title;
3739 }
3740
DrawTitleBorder()3741 void Kis_Panel::DrawTitleBorder() {
3742 ColorFromPref(text_color, "panel_text_color");
3743 ColorFromPref(border_color, "panel_border_color");
3744
3745 wattrset(win, border_color);
3746 box(win, 0, 0);
3747 wattron(win, WA_UNDERLINE);
3748 mvwaddstr(win, 0, 3, title.c_str());
3749 wattroff(win, WA_UNDERLINE);
3750
3751 wattrset(win, text_color);
3752 }
3753
DrawComponentVec()3754 void Kis_Panel::DrawComponentVec() {
3755 wattrset(win, text_color);
3756 for (unsigned int x = 0; x < pan_comp_vec.size(); x++) {
3757 if ((pan_comp_vec[x].comp_flags & KIS_PANEL_COMP_DRAW) == 0)
3758 continue;
3759
3760 pan_comp_vec[x].comp->DrawComponent();
3761 }
3762
3763 if (menu != NULL)
3764 menu->DrawComponent();
3765 }
3766
3767 #endif
3768
3769