1 /**
2 * Copyright Mikael H�gdahl - triyana@users.sourceforge.net
3 *
4 * This source is distributed under the terms of the Q Public License version 1.0,
5 * created by Trolltech (www.trolltech.com).
6 */
7
8 #include "Fl_Table.h"
9 #include "Fl_Table_Data.h"
10 #include "Fl_Select.h"
11 #include "Fl_Find.h"
12 #include "Fl_Defines.h"
13 #include <FL/Fl.H>
14 #include <FL/fl_ask.H>
15 #include <FL/fl_draw.H>
16 #include <FL/Fl_Choice.H>
17 #include <FL/Fl_Check_Button.H>
18 #include <FL/Fl_File_Chooser.H>
19 #include <FL/Fl_Input.H>
20 #include <FL/Fl_Scrollbar.H>
21 #include <FL/fl_show_colormap.H>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <ctype.h>
26
27
28
29 /**
30 * Callback for vertical scrollbar
31 */
cb_ver(Fl_Widget * w,void * o)32 void Fl_Table::cb_ver (Fl_Widget* w, void* o) {
33 ((Fl_Table*)o)->cb_ver();
34 }
35
36
37
38 /**
39 * Callback for horizontal scrollbar
40 */
cb_hor(Fl_Widget * w,void * o)41 void Fl_Table::cb_hor (Fl_Widget* w, void* o) {
42 ((Fl_Table*)o)->cb_hor();
43 }
44
45
46
47 /**
48 * Create table widget
49 * @param Fl_Table_Data - Data object
50 * @param int - X pos
51 * @param int - Y pos
52 * @param int - Width
53 * @param int - Height
54 */
Fl_Table(Fl_Window * dlgParent,Fl_Table_Data * data,int x,int y,int w,int h)55 Fl_Table::Fl_Table (Fl_Window* dlgParent, Fl_Table_Data* data, int x, int y, int w, int h) :
56 Fl_Group (x, y, w, h, 0) {
57 aData = data;
58 aDlgParent = dlgParent;
59 aCurrCol = 0;
60 aCurrRow = 0;
61 aStartCol = 0;
62 aStartRow = 0;
63 aWidth = 0;
64 aVisibleRows = 0;
65 aMaxVisibleRows = 0;
66 aVisibleCols = 0;
67 aWidth = 0;
68 aClipped = 0;
69 *aSearchWord = '\0';
70 aCase = false;
71 aEditWidget = 0;
72 aDragState = DRAG_NONE;
73 aEventHandler = 0;
74 aFind = new Fl_Find ();
75
76 begin();
77 aDummy = new Fl_Input (0, 0, 0, 0);
78 aScrollbarVer = new Fl_Scrollbar (x + w - SCROLL_SIZE, y, SCROLL_SIZE, h - SCROLL_SIZE);
79 aScrollbarHor = new Fl_Scrollbar (x, y + h - SCROLL_SIZE, w - SCROLL_SIZE, SCROLL_SIZE);
80 end();
81
82 box (FL_DOWN_BOX);
83 color (FL_WHITE);
84 aScrollbarVer->callback (cb_ver, this);
85 aScrollbarHor->callback (cb_hor, this);
86 aScrollbarHor->type (FL_HORIZONTAL);
87 aScrollbarVer->slider_size (0.08);
88 aScrollbarHor->slider_size (0.08);
89
90 set_data_size ();
91 Fl::focus (this);
92 remove (aDummy);
93 }
94
95
96
97 /**
98 * Delete table object
99 */
~Fl_Table()100 Fl_Table::~Fl_Table () {
101 quit_edit_mode (false);
102 delete aData;
103 delete []aWidth;
104 delete aDummy;
105 delete aFind;
106 }
107
108
109
110 /**
111 * Add new row at the end of table
112 */
add()113 void Fl_Table::add () {
114 aData->add ();
115 aCurrRow = aData->rows() - 1;
116 if (aData->rows() >= aMaxVisibleRows) {
117 aStartRow = aData->rows() - aMaxVisibleRows + 1;
118 if (aStartRow < 0) aStartRow = 0;
119 }
120 set_data_size();
121 if (aEventHandler) aEventHandler->handle (FL_DATA_CHANGE);
122 redraw();
123 }
124
125
126
127 /**
128 * Scrollbar has changed it position
129 */
cb_hor()130 void Fl_Table::cb_hor () {
131 aStartCol = aScrollbarHor->value ();
132 quit_edit_mode (true);
133 redraw ();
134 }
135
136
137
138 /**
139 * Scrollbar has changed it position
140 */
cb_ver()141 void Fl_Table::cb_ver () {
142 aStartRow = aScrollbarVer->value ();
143 quit_edit_mode (true);
144 redraw ();
145 }
146
147
148
149 /**
150 * Create a clip rectangle.
151 * You must call fl_pop_clip after
152 * @return int - CLIP_COL | CLIP_ROW if width or height has shrinked/changed
153 */
clip(int xpos,int ypos,int width,int height,int row)154 int Fl_Table::clip (int xpos, int ypos, int width, int height, int row) {
155 int retVal = 0;
156 int win_width = x() + w() - ((row == FL_LABEL_ROW) ? 0 : (SCROLL_SIZE));
157 int win_height = y() + h() - ((row == FL_LABEL_ROW) ? 0 : (SCROLL_SIZE));
158
159 if ((xpos + width) >= win_width) {
160 width = win_width - xpos;
161 retVal |= CLIP_COL;
162 }
163
164 if ((ypos + height) > win_height) {
165 height = win_height - ypos;
166 retVal |= CLIP_ROW;
167 }
168
169 fl_clip (xpos, ypos, width, height);
170 return retVal;
171 }
172
173
174
175 /**
176 * Set new data source
177 */
data(Fl_Table_Data * data)178 void Fl_Table::data (Fl_Table_Data* data) {
179 delete aData;
180 aData = data;
181
182 set_data_size();
183
184 aCurrRow = aData->rows () - 1;
185 aCurrCol = 0;
186 aStartCol = 0;
187 aStartRow = aCurrRow - (h() / aData->height(aCurrRow)) + 4;
188 if (aStartRow < 0) aStartRow = 0;
189 if (aStartCol < 0) aStartCol = 0;
190 ((Fl_Valuator*)aScrollbarVer)->value (aStartRow);
191 aScrollbarHor->slider_size (0.25);
192 aScrollbarVer->slider_size (0.25);
193 }
194
195
196
197 /**
198 * Draw lable, header and all cells.
199 */
draw()200 void Fl_Table::draw () {
201 int xpos = x() + 1;
202 int ypos = y() + 1;
203 int foo = 1;
204
205 Fl_Group::draw ();
206
207 if (!aData) return;
208
209 if (aData->show_label()) {
210 draw_label (xpos + 1, ypos + foo);
211 ypos += aData->height(FL_LABEL_ROW);
212 foo = 0;
213 }
214
215 aVisibleCols = 0;
216 if (aData->show_header()) {
217 draw_header (xpos + 1, ypos + foo);
218 ypos += aData->height (FL_HEADER_ROW);
219 foo = 0;
220 }
221
222 aVisibleRows = aMaxVisibleRows = 0;
223 aClipped = 1;
224 aActiveX = aActiveY = aActiveW = aActiveH = aActiveR = aActiveC = -1;
225
226 int clipped = 0;
227 int lastHeight = 20;
228 for (int f = aStartRow; f < aData->rows(); f++) {
229 clipped = draw_row (f, xpos + 1, ypos + foo);
230
231 if (clipped == CLIP_COL || clipped == CLIP_NONE) {
232 aVisibleRows++;
233 aMaxVisibleRows++;
234 aClipped = 0;
235 lastHeight = aData->height (f);
236 ypos += lastHeight;
237 }
238 else
239 break;
240 }
241 if (clipped != CLIP_ROW)
242 aMaxVisibleRows += (y() + h() - ypos) / lastHeight;
243
244 if (aEditWidget) {
245 aEditWidget->redraw ();
246 aEditWidget->draw ();
247 Fl::focus (aEditWidget);
248 }
249 else if (aActiveH > -1) {
250 clip (aActiveX, aActiveY, aActiveW, aActiveH);
251 draw_cell (aActiveR, aActiveC, aActiveX, aActiveY, aActiveW, aActiveH);
252 fl_pop_clip();
253 }
254 }
255
256
257
258 /**
259 * Draw cell
260 */
draw_cell(int row,int col,int xpos,int ypos,int width,int height)261 void Fl_Table::draw_cell (int row, int col, int xpos, int ypos, int width, int height) {
262 int arow = row;
263
264 if (row == aActiveR && col == aActiveC) arow = FL_ACTIVE_ROW;
265
266 if (aData->editor_type(row, col, false) == FL_BOOL_EDITOR) {
267 int addx = 2;
268 int addy = (height / 2) - (aData->textsize (row, col) / 2) - 2;
269 int size = aData->textsize (row, col) + 4;
270
271 if (aData->align (row, col) == FL_ALIGN_RIGHT)
272 addx = width - 4 - size;
273 else if (aData->align (row, col) == FL_ALIGN_CENTER)
274 addx = (width / 2) - (aData->textsize (row, col) / 2);
275
276 draw_cell (xpos, ypos, width, height, aData->box_color (arow, col), aData->border_color (arow, col));
277 fl_draw_box (FL_DOWN_BOX, xpos + addx, ypos + addy, size, size, FL_WHITE);
278
279 if (*aData->value (row, col) != '\0' && *aData->value (row, col) != '0') {
280 fl_color (FL_BLACK);
281 fl_line (xpos + addx + 3, ypos + addy + 3, xpos + addx + size - 4, ypos + addy + size - 4);
282 fl_line (xpos + addx + size - 4, ypos + addy + 3, xpos + addx + 3, ypos + addy + size - 4);
283 }
284 }
285 else if (aData->editor_type(row, col, false) == FL_SECRET_EDITOR) {
286 draw_cell (xpos, ypos, width, height, aData->box_color (arow, col), aData->border_color (arow, col));
287 fl_font (aData->textfont (arow, col), aData->textsize (arow, col));
288 fl_color (aData->textcolor (arow, col));
289 fl_draw ("******", xpos + 2, ypos, width - 4, height, aData->align (arow, col));
290 }
291 else {
292 draw_cell (xpos, ypos, width, height, aData->box_color (arow, col), aData->border_color (arow, col));
293 fl_font (aData->textfont (arow, col), aData->textsize (arow, col));
294 fl_color (aData->textcolor (arow, col));
295 fl_draw (aData->value (row, col), xpos + 2, ypos, width - 4, height, aData->align (arow, col));
296 }
297 }
298
299
300
301 /**
302 * Draw cell background area
303 */
draw_cell(int x,int y,int w,int h,Fl_Color bg,Fl_Color fg)304 void Fl_Table::draw_cell (int x, int y, int w, int h, Fl_Color bg, Fl_Color fg) {
305 fl_color (bg);
306 fl_rectf (x, y, w, h);
307 fl_color (fg);
308 fl_rect (x, y, w, h);
309 }
310
311
312
313 /**
314 * Draw table title
315 */
draw_label(int xpos,int ypos)316 void Fl_Table::draw_label (int xpos, int ypos) {
317 int height = aData->height(FL_LABEL_ROW);
318 int width = w() - 1;
319
320 height--;
321 clip (xpos, ypos, width, height, FL_LABEL_ROW);
322 fl_draw_box (FL_UP_BOX, xpos, ypos, width - 1, height, aData->box_color (FL_LABEL_ROW, 0));
323 fl_font (aData->textfont (FL_LABEL_ROW, 0), aData->textsize (FL_LABEL_ROW, 0));
324 fl_color (aData->textcolor (FL_LABEL_ROW, 0));
325 fl_draw (aData->value(FL_LABEL_ROW, 0), xpos + 2, ypos, width - 4, height, FL_ALIGN_CENTER);
326 fl_pop_clip ();
327 }
328
329
330
331 /**
332 * Draw table header
333 */
draw_header(int xpos,int ypos)334 void Fl_Table::draw_header (int xpos, int ypos) {
335 int height = aData->height(FL_HEADER_ROW);
336 int width;
337 int clipped;
338
339 for (int f = aStartCol; f < aData->cols(); f++) {
340 width = aWidth[f];
341 clipped = clip (xpos, ypos, width, height, FL_HEADER_ROW);
342
343 fl_draw_box (FL_UP_BOX, xpos, ypos, width, height, aData->box_color (FL_HEADER_ROW, 0));
344 fl_font (aData->textfont (FL_HEADER_ROW, f), aData->textsize (FL_HEADER_ROW, f));
345 fl_color (aData->textcolor (FL_HEADER_ROW, f));
346 fl_draw (aData->value (FL_HEADER_ROW, f), xpos + 2, ypos, width - 4, height, aData->align (FL_HEADER_ROW, f));
347 fl_pop_clip ();
348
349 if (clipped == CLIP_COL || clipped == CLIP_BOTH)
350 return;
351 else
352 aVisibleCols++;
353
354 xpos += aWidth[f];
355 }
356 }
357
358
359
360 /**
361 * Draw table row, return true if row is clipped
362 */
draw_row(int row,int xpos,int ypos)363 int Fl_Table::draw_row (int row, int xpos, int ypos) {
364 int height;
365 int width;
366 int clipped = 0;
367
368 for (int f = aStartCol; f < aData->cols(); f++) {
369 height = aData->height(f);
370 width = aWidth[f];
371 clipped = clip (xpos, ypos, width, height);
372
373 height++;
374 if (f < (aData->cols() - 1)) width++;
375 if (row == (aData->rows() - 1)) height--;
376
377 if (aEditWidget && row == aCurrRow && f == aCurrCol)
378 aEditWidget->resize (xpos, ypos, width, height);
379 else if (row == aCurrRow && f == aCurrCol) {
380 // Save size and pos for drawing active box last, after all rows gave been drawn
381 aActiveX = xpos; aActiveY = ypos; aActiveW = width; aActiveH = height;
382 aActiveC = f; aActiveR = row;
383 }
384 else
385 draw_cell (row, f, xpos, ypos, width, height);
386
387 xpos += aWidth[f];
388 fl_pop_clip ();
389
390 if (clipped == CLIP_COL) break;
391 }
392 return clipped;
393 }
394
395
396
397 /**
398 * Start editing current row
399 * @param bool - true to force use of the custom editor (FL_DLG_CUSTOM_EDITOR) flag
400 */
edit(bool force_custom)401 void Fl_Table::edit (bool force_custom) {
402 if (aEditWidget) {
403 if (aData && aData->rows() > 0 && aCurrRow >= 0 && quit_edit_mode (true) == true)
404 start_edit_mode (force_custom);
405 }
406 else
407 start_edit_mode (force_custom);
408 }
409
410
411
412 /**
413 * Erase current row
414 */
erase()415 void Fl_Table::erase () {
416 aData->erase (aCurrRow);
417 set_data_size();
418 set_cursor(aCurrRow, aCurrCol);
419 if (aEventHandler) aEventHandler->handle (FL_DATA_CHANGE);
420 redraw();
421 }
422
423
424
425 /**
426 * Mouse is dragged, change column size if right position
427 */
ev_drag()428 void Fl_Table::ev_drag () {
429 int xpos = Fl::event_x();
430
431 if (aDragState == DRAG_HOR) {
432 int currx = x();
433 for (int f = aStartCol; f < aDragCol; f++)
434 currx += aWidth[f];
435 if (xpos - currx > 10)
436 aWidth[aDragCol] = xpos - currx;
437 redraw ();
438 }
439 }
440
441
442
443 /**
444 * Keys are pressed down
445 */
ev_keyboard_down()446 bool Fl_Table::ev_keyboard_down () {
447 switch (Fl::event_key()) {
448 case FL_Down:
449 move_cursor (1, 0);
450 break;
451
452 case FL_Left:
453 move_cursor (0, -1);
454 break;
455
456 case FL_Page_Down:
457 if (Fl::event_state() == FL_CTRL)
458 move_cursor (1999999999, 0);
459 else
460 move_cursor (SCROLL_JUMP, 0);
461 break;
462
463 case FL_Page_Up:
464 if (Fl::event_state() == FL_CTRL)
465 move_cursor (-1999999999, 0);
466 else
467 move_cursor (-SCROLL_JUMP, 0);
468 break;
469
470 case FL_Right:
471 move_cursor (0, 1);
472 break;
473
474 case FL_Up:
475 move_cursor (-1, 0);
476 break;
477
478 case FL_Escape:
479 if (aEditWidget) quit_edit_mode (false);
480 break;
481
482 case FL_Enter:
483 if (aEditWidget == 0)
484 start_edit_mode ();
485 else
486 quit_edit_mode (true);
487 break;
488
489 default:
490 if (Fl::event_state() == FL_ALT)
491 return false;
492 else if (Fl::event_state() == FL_CTRL) {
493 //printf ("2 - %d\n", Fl::event_key());
494
495 switch (Fl::event_key()) {
496 case 'a':
497 case 'n':
498 add ();
499 break;
500
501 case 'c':
502 Fl::copy (aData->value (aCurrRow, aCurrCol), strlen (aData->value (aCurrRow, aCurrCol)), 1);
503 break;
504
505 case 'd':
506 erase ();
507 break;
508
509 case 'f':
510 find (false);
511 break;
512
513 case 'g':
514 find (true);
515 break;
516
517 case 'i':
518 insert ();
519 break;
520
521 case 's':
522 if (dirty())
523 save ();
524 break;
525
526 case 'x':
527 Fl::copy (aData->value (aCurrRow, aCurrCol), strlen (aData->value (aCurrRow, aCurrCol)), 1);
528 aData->value ("", aCurrRow, aCurrCol);
529 break;
530
531 case 'v':
532 aDummy->value ("");
533 Fl::paste (*aDummy, 1);
534 if (aData->value (aDummy->value(), aCurrRow, aCurrCol) == false && aEventHandler) aEventHandler->handle (FL_DATA_ERROR);
535 break;
536
537 case FL_Escape:
538 break;
539 }
540 Fl::focus (this);
541 redraw ();
542 }
543 break;
544 }
545
546 if (aCurrRow < 0) aCurrRow = 0;
547 if (aCurrCol < 0) aCurrCol = 0;
548 if (aCurrRow < aStartRow) aStartRow = aCurrRow;
549 if (aCurrCol < aStartCol) aStartCol = aCurrCol;
550 return true;
551 }
552
553
554
555 /**
556 * Mouse is moved, check if user are above header. If so change mouse cursor if between cells.
557 */
ev_move()558 void Fl_Table::ev_move () {
559 if (!aData) return;
560 int xpos = Fl::event_x();
561 int ypos = Fl::event_y();
562 int currx = x();
563 int curry = y();
564
565 if (aData->show_label())
566 curry += (aData->textsize (FL_LABEL_ROW, 0) + ( aData->textsize (FL_LABEL_ROW, 0) / 2));
567 if (ypos > curry) {
568 if (aData->show_header())
569 curry += aData->height (FL_HEADER_ROW);
570
571 if (ypos < curry) {
572 // Cursor is inside header
573 for (int f = aStartCol; f < aData->cols(); f++) {
574 currx += aWidth[f];
575 if (xpos > (currx - 3) && xpos < (currx + 4)) {
576 aDragState = DRAG_HOR;
577 aDragCol = f;
578 fl_cursor (FL_CURSOR_WE);
579 return;
580 }
581 }
582 }
583 }
584
585 // Set cursor to standar one only if it was set to another cursor before
586 if (aDragState != DRAG_NONE) {
587 fl_cursor (FL_CURSOR_DEFAULT);
588 aDragState = DRAG_NONE;
589 }
590 }
591
592
593
594 /**
595 * Mouse is pushed.
596 * Select new current cell
597 */
ev_push()598 void Fl_Table::ev_push () {
599 int xpos = Fl::event_x();
600 int ypos = Fl::event_y();
601 int row;
602 int col;
603 int c, d;
604
605 get_cell_pos (row, col, xpos, ypos, c, d);
606
607 if (aEditWidget) {
608 if (row != aCurrRow || col != aCurrCol) {
609 quit_edit_mode (true);
610 Fl::focus (this);
611 }
612 else {
613 aEditWidget->handle (FL_PUSH);
614 aEditWidget->draw();
615 Fl::focus (aEditWidget);
616 return;
617 }
618 }
619 else
620 Fl::focus (this);
621
622 if (row <= FL_NO_ROW || col < 0)
623 return;
624 else if (row == FL_HEADER_ROW && col >= 0) {
625 if (Fl::event_button() == FL_LEFT_MOUSE)
626 aData->sort (col, true);
627 else if (Fl::event_button() == FL_RIGHT_MOUSE)
628 aData->sort (col, false);
629 redraw ();
630 }
631 else if (row >= 0 && col >= 0 && (row != aCurrRow || col != aCurrCol)) {
632 if (quit_edit_mode (true)) {
633 aCurrRow = row;
634 aCurrCol = col;
635 redraw ();
636 }
637 }
638 else {
639 if (Fl::event_clicks() == 1) {
640 if (aEditWidget == 0)
641 start_edit_mode ();
642 else
643 quit_edit_mode (true);
644 }
645 }
646 }
647
648
649
650 /**
651 * Search for text in cell.
652 * Display a search dialog or continue to serach for next word
653 */
find(bool nextword)654 void Fl_Table::find (bool nextword) {
655 if (!aData) return;
656
657 const char* searchWord = 0;
658 const char* replaceWord = 0;
659 bool found = false;
660 char tmp[200];
661 int ret;
662 int case_sense;
663 int begin = 0;
664
665 if (nextword == false || *aSearchWord == '\0') {
666 ret = aFind->show_modal (aDlgParent);
667 searchWord = aFind->text ();
668 replaceWord = aFind->text ();
669 case_sense = aFind->case_sensitive ();
670 begin = aFind->beginning ();
671
672 if (ret == 0) return;
673
674 aCase = (case_sense == 1) ? true : false;
675
676 if (searchWord && *searchWord) {
677 strncpy (aSearchWord, searchWord, 199);
678
679 if (aCase == false) {
680 #ifdef WIN32
681 _strlwr (aSearchWord);
682 #else
683 char* f = aSearchWord;
684 while (*f) {
685 *f = tolower (*f);
686 f++;
687 }
688 #endif
689 }
690 }
691 else
692 return;
693 }
694
695
696 for (int row = (begin == 0 ? aCurrRow : 0); row < aData->rows(); row++) {
697 for (int col = (begin == 0 ? (row == aCurrRow ? aCurrCol + 1: 0) : 0); col < aData->cols(); col++) {
698 if (aCase == false) {
699 strncpy (tmp, aData->value (row, col), 199);
700 #ifdef WIN32
701 _strlwr (tmp);
702 #else
703 char* f = tmp;
704 while (*f) {
705 *f = tolower (*f);
706 f++;
707 }
708 #endif
709
710 if (strstr (tmp, aSearchWord))
711 found = true;
712 }
713 else if (strstr (aData->value (row, col), aSearchWord))
714 found = true;
715
716 if (found) {
717 set_cursor (row, col);
718 return;
719 }
720 }
721 }
722 fl_beep (FL_BEEP_ERROR);
723 }
724
725
726
727 /**
728 * Get cell size and position
729 */
get_cell_pos(int & row,int & col,int & xpos,int & ypos,int & width,int & height)730 void Fl_Table::get_cell_pos (int& row, int& col, int& xpos, int& ypos, int& width, int& height) {
731 row = col = FL_NO_ROW;
732 if (!aData) return;
733
734 int currx = x();
735 int curry = y();
736
737 if (aData->show_label()) curry += (aData->height (FL_LABEL_ROW));
738 if (ypos < curry) {
739 row = FL_LABEL_ROW;
740 return;
741 }
742 if (aData->show_header()) curry += aData->height (FL_HEADER_ROW);
743 if (ypos < curry) row = FL_HEADER_ROW;
744
745 for (int c = aStartCol; c < aData->cols(); c++) {
746 if (xpos > currx && xpos <= (currx + aWidth[c])) {
747 col = c;
748 xpos = currx;
749 width = aWidth[c];
750 break;
751 }
752 else if (xpos > (x() + w() - aScrollbarVer->w()))
753 break;
754
755 currx += aWidth[c];
756 }
757
758 if (row == FL_HEADER_ROW) return;
759
760 for (int r = aStartRow; r < aData->rows(); r++) {
761 if (ypos >= curry && ypos < (curry + aData->height(r))) {
762 row = r;
763 ypos = curry;
764 height = aData->height(r);
765 break;
766 }
767 else if (ypos > (y() + h() - aScrollbarHor->h()))
768 break;
769
770 curry += aData->height(r);
771 }
772 }
773
774
775
776 /**
777 * All events goes here
778 * @param int - Event
779 */
handle(int event)780 int Fl_Table::handle (int event) {
781 if (!aData) return Fl_Group::handle (event);
782
783 switch (event) {
784 case FL_DRAG:
785 ev_drag ();
786 return 1;
787
788 case FL_KEYDOWN:
789 if (ev_keyboard_down ())
790 return 1;
791 else
792 break;
793
794 case FL_KEYUP:
795 if (aEditWidget) aEditWidget->redraw();
796 return 0;
797
798 case FL_LEAVE:
799 if (aDragState != DRAG_NONE) {
800 fl_cursor (FL_CURSOR_DEFAULT);
801 aDragState = DRAG_NONE;
802 }
803 return 0;
804
805 case FL_MOVE:
806 ev_move ();
807 return 0;
808
809 case FL_PUSH:
810 ev_push ();
811 Fl_Group::handle (event);
812 return 1;
813
814 default:
815 break;
816 }
817
818 return Fl_Group::handle (event);
819 }
820
821
822
823 /**
824 * Insert row at current position
825 */
insert()826 void Fl_Table::insert () {
827 aData->insert (aCurrRow);
828 set_data_size();
829 set_cursor(aCurrRow, aCurrCol);
830 if (aEventHandler) aEventHandler->handle (FL_DATA_CHANGE);
831 redraw();
832 }
833
834
835
836 /**
837 * Move cursor from current position
838 * @param int - Number of rows to move cursor
839 * @param int - Number of columns to move cursor
840 */
move_cursor(int rows,int cols)841 void Fl_Table::move_cursor (int rows, int cols) {
842 if (aEditWidget) return;
843 if (!aData || aData->rows() == 0 || aData->cols() == 0) return;
844
845 aCurrRow += rows;
846 if (aVisibleRows > 1) {
847 if (aCurrRow < aStartRow) aStartRow = aCurrRow;
848 if (aCurrRow > (aStartRow + aVisibleRows - 1)) aStartRow = aCurrRow - aVisibleRows + 1;
849 }
850 else
851 aStartRow = aCurrRow;
852
853 if (aCurrRow >= aData->rows()) aCurrRow = aData->rows() - 1;
854 if (aCurrRow < 0) aCurrRow = 0;
855 if (aStartRow >= aData->rows() || aStartRow < 0) aStartRow = aCurrRow;
856
857 aCurrCol += cols;
858 if (aVisibleCols > 1) {
859 if (aCurrCol < aStartCol) aStartCol = aCurrCol;
860 if (aCurrCol > (aStartCol + aVisibleCols - 1)) aStartCol = aCurrCol - aVisibleCols + 1;
861 }
862 else
863 aStartCol = aCurrCol;
864
865 if (aCurrCol >= aData->cols()) aCurrCol = aData->cols() - 1;
866 if (aCurrCol < 0) aCurrCol = 0;
867 if (aStartCol >= aData->cols() || aStartCol < 0) aStartCol = aCurrCol;
868
869 ((Fl_Valuator*)aScrollbarVer)->value ((double)aStartRow);
870 ((Fl_Valuator*)aScrollbarHor)->value ((double)aStartCol);
871 redraw ();
872 }
873
874
875
quit_edit_mode(bool save)876 bool Fl_Table::quit_edit_mode (bool save) {
877 if (aEditWidget) {
878 const char** list;
879 int row;
880 int a, b;
881 bool stop = true;
882 char label[100];
883
884 if (save) {
885 switch (aData->editor_type(aCurrRow, aCurrCol, false)) {
886 case FL_BOOL_EDITOR:
887 if (((Fl_Check_Button*)aEditWidget)->value() == 0)
888 stop = aData->value ("\0", aCurrRow, aCurrCol);
889 else
890 stop = aData->value ("\1", aCurrRow, aCurrCol);
891 break;
892
893 case FL_LIST_EDITOR:
894 row = ((Fl_Choice*)aEditWidget)->value ();
895 list = aData->choice (aCurrRow, aCurrCol, a, b, label);
896 stop = aData->value (list[row], aCurrRow, aCurrCol);
897 break;
898
899 default:
900 stop = aData->value (((Fl_Input*)aEditWidget)->value(), aCurrRow, aCurrCol);
901 break;
902 }
903 }
904
905 if (stop == true) {
906 remove (aEditWidget);
907 delete aEditWidget;
908 aEditWidget = 0;
909 if (aEventHandler) aEventHandler->handle (FL_DATA_CHANGE);
910 }
911 else {
912 fl_beep (FL_BEEP_ERROR);
913 if (aEventHandler) aEventHandler->handle (FL_DATA_ERROR);
914 aEditWidget->redraw ();
915 Fl::focus (aEditWidget);
916 return false;
917 }
918 }
919 Fl::focus (this);
920 redraw ();
921 return true;
922 }
923
924
925
926 /**
927 * Resize table and scrollbars.
928 * @param int - X pos
929 * @param int - Y pos
930 * @param int - Width
931 * @param int - Height
932 */
resize(int x,int y,int w,int h)933 void Fl_Table::resize (int x, int y, int w, int h) {
934 Fl_Group::resize (x, y, w, h);
935
936 int hfix = (aData && aData->show_label()) ? aData->height(FL_LABEL_ROW) : 0;
937 int yfix = (aData && aData->show_label()) ? 0 : 2;
938
939 aScrollbarVer->resize (x + w - SCROLL_SIZE, y + hfix + yfix, SCROLL_SIZE, h - hfix - yfix);
940 aScrollbarHor->resize (x, y + h - SCROLL_SIZE, w - SCROLL_SIZE, SCROLL_SIZE);
941 }
942
943
944
945 /**
946 * Let data save itself
947 */
save()948 bool Fl_Table::save () {
949 int row = aData->save ();
950
951 if (row < 0) {
952 if (aEventHandler) aEventHandler->handle (FL_DATA_SAVE);
953 set_data_size();
954 redraw ();
955 return true;
956 }
957 else {
958 if (aEventHandler) aEventHandler->handle (FL_DATA_SAVE_ERROR);
959 set_cursor (row, 0);
960 redraw ();
961 return false;
962 }
963 }
964
965 /**
966 * Callback for file chooser
967 */
tab_fc_callback(Fl_File_Chooser * fc,void * data)968 void tab_fc_callback(Fl_File_Chooser *fc, void *data)
969 {
970 Fl_Table *t = static_cast<Fl_Table *>(data);
971 t->aData->value (fc->value(), t->aCurrRow, t->aCurrCol);
972 }
973
974 /**
975 * Start to edit a cell
976 */
start_edit_mode(bool force_custom)977 void Fl_Table::start_edit_mode (bool force_custom) {
978 if (aData->editor_type (aCurrRow, aCurrCol, false) == FL_DLG_COLOR_EDITOR) {
979 int col = atoi (aData->value(aCurrRow, aCurrCol));
980 if (col < 0 || col > 255) col = 0;
981 int newcol = fl_show_colormap ((Fl_Color) col);
982 char buff [31];
983 SNPRINTF (buff, 30, "%d", newcol);
984 aData->value (buff, aCurrRow, aCurrCol);
985
986 }
987 else if (aData->editor_type (aCurrRow, aCurrCol, false) == FL_DLG_DIR_EDITOR) {
988 char* dir = fl_dir_chooser("Select Directory", aData->value(aCurrRow, aCurrCol));
989 aData->value (dir, aCurrRow, aCurrCol);
990
991 }
992 else if (aData->editor_type (aCurrRow, aCurrCol, false) == FL_DLG_FILE_EDITOR) {
993
994 Fl_File_Chooser *fc = new Fl_File_Chooser("Select File", "*", Fl_File_Chooser::SINGLE, aData->value(aCurrRow, aCurrCol));
995 fc->callback(tab_fc_callback, this);
996 delete fc;
997 }
998 else {
999 aEditWidget = aData->editor (aCurrRow, aCurrCol, force_custom);
1000 if (!aEditWidget) return;
1001
1002 switch (aData->editor_type(aCurrRow, aCurrCol, force_custom)) {
1003 case FL_DLG_LIST_EDITOR: {
1004 if (aEditWidget) {
1005 // This is a dialog popup mode and when dialog close the editing also stops
1006
1007 Fl_Select* dlg = (Fl_Select*) aEditWidget;
1008 bool ok = false;
1009
1010 Fl::event_clicks (0);
1011 if (dlg && dlg->show_modal (aDlgParent) == 1 && dlg->row () > 0) {
1012 int a, b;
1013 char label[100];
1014 const char** list = aData->choice (aCurrRow, aCurrCol, a, b, label);
1015 ok = aData->value (list[dlg->row () - 1], aCurrRow, aCurrCol);
1016 }
1017 delete dlg;
1018 aEditWidget = 0;
1019 if (aEventHandler && ok)
1020 aEventHandler->handle (FL_DATA_CHANGE);
1021 }
1022 Fl::focus (this);
1023 break;
1024 }
1025
1026 case FL_DLG_CUSTOM_EDITOR: {
1027 Fl_Dialog* dlg = (Fl_Dialog*) aEditWidget;
1028 bool ok = false;
1029
1030 Fl::event_clicks (0);
1031 if (dlg) {
1032 if (dlg->show_modal (aDlgParent) == 1) {
1033 ok = true;
1034 // Dialog has changed data, make sure current data object nows that
1035 aData->dirty (true);
1036 }
1037 }
1038 delete dlg;
1039 aEditWidget = 0;
1040 if (aEventHandler && ok)
1041 aEventHandler->handle (FL_DATA_CHANGE);
1042 Fl::focus (this);
1043 break;
1044 }
1045
1046 default:
1047 Fl_Group::add (aEditWidget);
1048 Fl::focus (aEditWidget);
1049 aEditWidget->draw ();
1050 break;
1051 }
1052 }
1053 redraw ();
1054 }
1055
1056
1057
1058 /**
1059 * Set size of columns and scrollbar values
1060 */
set_data_size()1061 void Fl_Table::set_data_size () {
1062 if (!aData) return;
1063
1064 aScrollbarVer->range (0, aData->rows());
1065 aScrollbarHor->range (0, aData->cols());
1066 delete []aWidth;
1067 aWidth = new int[aData->cols() + 1];
1068 for (int f = 0; f < aData->cols(); f++)
1069 aWidth[f] = aData->width (f);
1070
1071 redraw();
1072 }
1073