1 #include <GridCtrl/GridCtrl.h>
2
3 namespace Upp {
4
5 #ifdef COMPILER_MSC
6 #pragma warning(disable: 4355)
7 #endif
8
9 #define TFILE <GridCtrl/GridCtrl.t>
10 #include <Core/t.h>
11
12 bool GridCtrl::index_as_column = false;
13 bool GridCtrl::reverse_sort_icon = false;
14
GridCtrl()15 GridCtrl::GridCtrl() : holder(*this)
16 {
17 sortCol = -1;
18 hcol = -1;
19 hrow = -1;
20
21 fixed_click = false;
22 fixed_top_click = false;
23 fixed_left_click = false;
24 size_changed = true;
25
26 resize_panel_open = false;
27
28 synced = false;
29 sc_fr = -1;
30 sc_lr = -1;
31
32 resizeCol = false;
33 resizeRow = false;
34
35 ready = false;
36 doscroll = true;
37 firstRow = lastRow = -1;
38 firstCol = lastCol = -1;
39
40 firstVisCol = -1;
41 lastVisCol = -1;
42 firstVisRow = -1;
43 lastVisRow = -1;
44
45 colidx = -1;
46 rowidx = -1;
47 rowfnd = -1;
48
49 GD_COL_WIDTH = 50;
50 GD_ROW_HEIGHT = Draw::GetStdFontCy() + 5;
51 GD_HDR_HEIGHT = GD_ROW_HEIGHT + 2;
52 GD_IND_WIDTH = 9;
53
54 display = new GridDisplay();
55 display->SetTextAlign(GD::VCENTER);
56 orgdisp = display;
57
58 sbx.Horz();
59 sby.Vert();
60 sbx.WhenScroll = THISBACK(Scroll);
61 sby.WhenScroll = THISBACK(Scroll);
62 sbx.SetLine(5);
63 sby.SetLine(GridCtrl::GD_ROW_HEIGHT);
64
65 fixed_cols = 1;
66 fixed_rows = 1;
67
68 total_cols = 0;
69 total_rows = 0;
70
71 minRowSelected = -1;
72 maxRowSelected = -1;
73
74 bains = 0;
75 coluid = 0;
76 rowuid = 0;
77
78 close.SetLabel(t_("Close"));
79 close <<= THISBACK(CloseGrid);
80
81 oldpos.Clear();
82
83 indicator = false;
84 resizing_cols = true;
85 resizing_rows = true;
86 resizing_fixed_cols = true;
87 resizing_fixed_rows = false;
88 resize_paint_mode = 2;
89 resize_col_mode = 1;
90 resize_row_mode = 0;
91 multi_select = false;
92 select_row = true;
93 moving_cols = false;
94 moving_rows = false;
95 dragging = false;
96 horz_grid = true;
97 vert_grid = true;
98 draw_last_horz_line = true;
99 draw_last_vert_line = true;
100 sorting = false;
101 live_cursor = false;
102 row_changing = true;
103 edit_mode = GE_ROW;
104 one_click_edit = false;
105 goto_first_edit = true;
106 coloring_mode = 0;
107 isedit = false;
108 genr_ctrls = 0;
109 edit_ctrls = false;
110 sorting = true;
111 sorting_multicol = true;
112 header = true;
113
114 cancel_update_cell = false;
115 cancel_update = false;
116 cancel_insert = false;
117 cancel_remove = false;
118 cancel_accept = false;
119 cancel_duplicate = false;
120 cancel_cursor = false;
121 cancel_move = false;
122
123 inserting = false;
124 appending = false;
125 duplicating = false;
126 removing = false;
127 accepting = false;
128 canceling = false;
129 moving = false;
130 navigating = false;
131 searching = false;
132 editing = false;
133 edits_in_new_row = true;
134 closing = false;
135 hiding = false;
136 clipboard = false;
137 extra_paste = true;
138 fixed_paste = false;
139 copy_allowed = true;
140 cut_allowed = true;
141 paste_allowed = true;
142 copy_column_names = false;
143 draw_focus = false;
144 ask_remove = false;
145
146 search_hide = true;
147 search_highlight = true;
148 search_highlight_first = false;
149 search_immediate = true;
150 search_case = false;
151 search_move_cursor = true;
152 search_display = true;
153
154 row_order = false;
155 row_data = false;
156
157 reject_null_row = true;
158 tab_changes_row = true;
159 tab_adds_row = false;
160 enter_like_tab = false;
161 keep_last_row = false;
162 remove_hides = false;
163 full_col_resizing = true;
164 full_row_resizing = false;
165 chameleon = false;
166 summary_row = false;
167 update_summary = true;
168 popups = true;
169 focus_lost_accepting = false;
170
171 mouse_move = false;
172 row_modified = 0;
173
174 valid_cursor = false;
175
176 curpos.x = curpos.y = -1;
177 oldcur.x = oldcur.y = -1;
178 curid.x = curid.y = -1;
179 ctrlid.x = ctrlid.y = -1;
180 ctrlpos.x = ctrlpos.y = -1;
181 osz.cx = osz.cy = -1;
182 livecur.x = livecur.y = -1;
183 leftpnt.x = leftpnt.y = -1;
184 shiftpos.x = shiftpos.y = -1;
185
186 fixed_width = 0;
187 fixed_height = 0;
188 total_width = 0;
189 total_height = 0;
190 summary_height = 0;
191
192 ItemRect &ir = vitems.Add();
193 ir.parent = this;
194 ir.edits = &edits;
195 items.Add();
196
197 /* add indicator, total_cols = 1 */
198 AddColumn("", 0);
199
200 shiftmode = false;
201 recalc_cols = false;
202 recalc_rows = false;
203 selected_rows = 0;
204 selected_items = 0;
205
206 WhenMenuBar = THISBACK(StdMenuBar);
207 WhenToolBar = THISBACK(StdToolBar);
208
209 find <<= THISBACK(DoFind);
210
211 StdAppend = THISBACK(DoAppend);
212 StdRemove = THISBACK(DoRemove);
213 StdInsert = THISBACK(DoInsertBefore);
214 StdDuplicate = THISBACK(DoDuplicate);
215 StdEdit = THISBACK(DoEdit);
216
217 newrow_inserted = false;
218 newrow_appended = false;
219 row_removed = false;
220 just_clicked = false;
221
222 call_whenchangecol = true;
223 call_whenchangerow = true;
224 call_whenremoverow = true;
225 call_whenupdaterow = true;
226 call_wheninsertrow = true;
227
228 sel_begin = false;
229 sel_end = false;
230
231 moving_header = false;
232 moving_body = false;
233 moving_allowed = false;
234
235 join_group = 0;
236
237 curSplitCol = oldSplitCol = -1;
238 curSplitRow = oldSplitRow = -1;
239
240 moveCol = moveRow = -1;
241 find_offset = 0;
242
243 scrollLeftRight = false;
244
245 fg_focus = SColorHighlightText;
246 bg_focus = SColorHighlight;
247 fg_select = Black;
248 bg_select = Color(217, 198, 251);
249 fg_live = SColorText;
250 bg_live = IsDarkColorFace() ? Blend(SColorHighlight, Black, 132) : Blend(SColorHighlight, White, 132);
251 fg_found = Color(0, 0, 0);
252 bg_found = Blend(SColorHighlight, Color(189,231,237), 200);
253 fg_even = SColorText;
254 fg_odd = SColorText;
255 bg_even = SColorPaper;
256 bg_odd = SColorPaper;
257 fg_grid = SColorShadow;
258
259 focused_ctrl = NULL;
260 focused_ctrl_id = -1;
261 focused_col = -1;
262
263 find.NullText(t_("Search"));
264 find.WhenBar = THISBACK(FindOptsBar);
265
266 /* frames added at the very end, otherwise there will be strange crash in optimal mode... */
267 sbx.AutoHide();
268 sby.AutoHide();
269 SetFrame(ViewFrame());
270 AddFrame(sbx);
271 AddFrame(sby);
272 Ctrl::Add(holder);
273
274 resize_panel_open = false;
275 resize_panel.WhenClose = Proxy(WhenClose);
276
277 resizing = false;
278 selecting = false;
279 is_clipboard = false;
280 enabled = true;
281 sync_flag = 0;
282 paint_flag = 0;
283 }
284
~GridCtrl()285 GridCtrl::~GridCtrl()
286 {
287 delete orgdisp;
288 }
289
StdToolBar(Bar & bar)290 void GridCtrl::StdToolBar(Bar &bar)
291 {
292 bool e = IsEnabled();
293 bool c = e && IsCursor();
294 bool d = c && IsRowEditable();
295
296 if(appending)
297 bar.Add(e, t_("Append"), GridImg::Append(), StdAppend);
298
299 if(inserting)
300 bar.Add(c, t_("Insert "), GridImg::Insert(), StdInsert);
301
302 if(duplicating)
303 bar.Add(d && !isedit, t_("Duplicate"), GridImg::Duplicate(), StdDuplicate);
304
305 if(removing)
306 bar.Add(d && (keep_last_row ? GetCount() > 1 : true), t_("Delete "), GridImg::Delete(), StdRemove);
307
308 if(editing)
309 {
310 bar.Add(!isedit && d, t_("Edit"), GridImg::Modify(), StdEdit);
311 if(accepting)
312 bar.Add(isedit, t_("Accept"), GridImg::Commit(), THISBACK(DoEndEdit));
313 if(canceling)
314 bar.Add(isedit, t_("Cancel"), GridImg::Cancel(), THISBACK(DoCancelEdit));
315 }
316
317 if(searching)
318 {
319 if(inserting || appending || removing)
320 bar.Separator();
321 FindBar(bar, 150);
322 }
323
324 if(moving)
325 {
326 if(searching)
327 bar.Separator();
328
329 bar.Add(c, t_("Move up"), GridImg::MoveUp(), THISBACK(DoSwapUp));
330 bar.Add(c, t_("Move down"), GridImg::MoveDn(), THISBACK(DoSwapDown));
331 }
332
333 if(navigating)
334 {
335 if(!closing)
336 bar.GapRight();
337 else
338 bar.Separator();
339
340 NavigatingBar(bar);
341 }
342
343 if(closing)
344 {
345 bar.GapRight();
346 bar.Add(close, 76, 24);
347 }
348 }
349
FindBar(Bar & bar,int cx)350 void GridCtrl::FindBar(Bar &bar, int cx)
351 {
352 bar.Add(find, cx);
353 }
354
InfoBar(Bar & bar,int cx)355 void GridCtrl::InfoBar(Bar &bar, int cx)
356 {
357 bar.Add(info, cx);
358 }
359
SetToolBarInfo(String inf)360 void GridCtrl::SetToolBarInfo(String inf)
361 {
362 info.SetLabel(inf);
363 }
364
NavigatingBar(Bar & bar)365 void GridCtrl::NavigatingBar(Bar &bar)
366 {
367 bar.Add(RowFormat(t_("First %s")), GridImg::FirstRec(), THISBACK(DoGoBegin));
368 bar.Add(RowFormat(t_("Previous %s")), GridImg::PrevRec(), THISBACK(DoGoPrev));
369 bar.Add(RowFormat(t_("Next %s")), GridImg::NextRec(), THISBACK(DoGoNext));
370 bar.Add(RowFormat(t_("Last %s")), GridImg::LastRec(), THISBACK(DoGoEnd));
371 }
372
SetToolBar(bool b,int align,int frame)373 GridCtrl& GridCtrl::SetToolBar(bool b, int align, int frame)
374 {
375 RemoveFrame(bar);
376
377 if(!b)
378 return *this;
379
380 InsertFrame(frame, bar.Align(align));
381 bar.SetStyle(ToolBar::StyleDefault());
382
383 if(frame == 1)
384 switch(align)
385 {
386 case BarCtrl::BAR_TOP:
387 RemoveFrame(TopSeparatorFrame());
388 InsertFrame(2, TopSeparatorFrame());
389 break;
390 case BarCtrl::BAR_BOTTOM:
391 RemoveFrame(BottomSeparatorFrame());
392 InsertFrame(2, BottomSeparatorFrame());
393 break;
394 case BarCtrl::BAR_LEFT:
395 RemoveFrame(LeftSeparatorFrame());
396 InsertFrame(2, LeftSeparatorFrame());
397 break;
398 case BarCtrl::BAR_RIGHT:
399 RemoveFrame(RightSeparatorFrame());
400 InsertFrame(2, RightSeparatorFrame());
401 break;
402 }
403 WhenToolBar(bar);
404 return *this;
405 }
406
ResizePanel(bool b)407 GridCtrl& GridCtrl::ResizePanel(bool b)
408 {
409 resize_panel_open = b;
410 RemoveFrame(resize_panel);
411 RemoveFrame(BottomSeparatorFrame());
412 if(!b)
413 return *this;
414 InsertFrame(1, resize_panel);
415 InsertFrame(2, BottomSeparatorFrame());
416 return *this;
417 }
418
FindOptsBar(Bar & bar)419 void GridCtrl::FindOptsBar(Bar &bar)
420 {
421 bar.Add(t_("Immediate search"), THISBACK1(SetFindOpts, 0)).Check(search_immediate);
422 bar.Add(t_("Hide rows"), THISBACK1(SetFindOpts, 1)).Check(search_hide);
423 bar.Add(t_("Highlight found cells"), THISBACK1(SetFindOpts, 2)).Check(search_highlight);
424 bar.Add(t_("Case sensitive"), THISBACK1(SetFindOpts, 3)).Check(search_case);
425 }
426
SetFindOpts(int n)427 void GridCtrl::SetFindOpts(int n)
428 {
429 switch(n)
430 {
431 case 0:
432 search_immediate = !search_immediate;
433 if(!search_immediate)
434 {
435 find <<= THISBACK(Nothing);
436 find.WhenEnter = THISBACK(DoFind);
437 }
438 else
439 {
440 find <<= THISBACK(DoFind);
441 find.WhenEnter = THISBACK(Nothing);
442 }
443 break;
444 case 1:
445 search_hide = !search_hide;
446 if(!String(~find).IsEmpty())
447 {
448 if(!search_hide)
449 ShowRows();
450 else
451 DoFind();
452 }
453 break;
454 case 2:
455 search_highlight = !search_highlight;
456 if(!search_highlight)
457 {
458 ClearFound(false);
459 Refresh();
460 }
461 else
462 DoFind();
463 break;
464 case 3:
465 search_case = !search_case;
466 DoFind();
467 break;
468 }
469 }
470
RowFormat(const char * s)471 String GridCtrl::RowFormat(const char *s)
472 {
473 String row = t_("row");
474 return Sprintf(s, ~row);
475 }
476
StdMenuBar(Bar & bar)477 void GridCtrl::StdMenuBar(Bar &bar)
478 {
479 bool c = IsCursor();
480 bool e = c && IsRowEditable();
481 bool isitem = false;
482
483 if(inserting)
484 {
485 if(bains == 0)
486 {
487 bar.Add(c, t_("Insert "), StdInsert)
488 .Image(GridImg::Insert())
489 .Help(RowFormat(t_("Insert a new %s into the table.")))
490 .Key(K_INSERT);
491 }
492 else if(bains == 1)
493 {
494 bar.Add(c, t_("Insert before"), THISBACK(DoInsertBefore))
495 .Image(GridImg::InsertBefore())
496 .Help(RowFormat(t_("Insert a new %s into the table before current")))
497 .Key(K_INSERT);
498 bar.Add(c, t_("Insert after"), THISBACK(DoInsertAfter))
499 .Image(GridImg::InsertAfter())
500 .Help(RowFormat(t_("Insert a new %s into the table after current")))
501 .Key(K_ALT_INSERT);
502 }
503 else if(bains == 2)
504 {
505 bar.Add(c, t_("Insert after"), THISBACK(DoInsertAfter))
506 .Image(GridImg::InsertAfter())
507 .Help(RowFormat(t_("Insert a new %s into the table after current")))
508 .Key(K_INSERT);
509 bar.Add(c, t_("Insert before"), THISBACK(DoInsertBefore))
510 .Image(GridImg::InsertBefore())
511 .Help(RowFormat(t_("Insert a new %s into the table before current")))
512 .Key(K_ALT_INSERT);
513 }
514 isitem = true;
515 }
516
517 if(appending)
518 {
519 bar.Add(t_("Append"), StdAppend)
520 .Image(GridImg::Append())
521 .Help(RowFormat(t_("Append a new %s at the end of the table.")))
522 .Key(inserting ? (dword) K_CTRL_INSERT : (dword) K_INSERT);
523
524 isitem = true;
525 }
526
527 if(duplicating)
528 {
529 bar.Add(c, t_("Duplicate"), THISBACK(DoDuplicate))
530 .Image(GridImg::Duplicate())
531 .Help(RowFormat(t_("Duplicate current table %s.")))
532 .Key(K_CTRL_D);
533
534 isitem = true;
535 }
536
537 if(editing)
538 {
539 bar.Add(!isedit && e, t_("Edit"), StdEdit)
540 .Image(GridImg::Modify())
541 .Help(RowFormat(t_("Edit active %s.")))
542 .Key(K_ENTER);
543
544 isitem = true;
545 }
546
547 if(removing)
548 {
549 RemovingMenu(bar);
550 isitem = true;
551 }
552
553 if(moving)
554 {
555 MovingMenu(bar);
556 isitem = true;
557 }
558
559 if(multi_select || !select_row)
560 {
561 SelectMenu(bar);
562 isitem = true;
563 }
564
565 if(clipboard)
566 {
567 if(isitem)
568 bar.Separator();
569 ClipboardMenu(bar);
570 isitem = true;
571 }
572
573 if(hiding)
574 {
575 if(isitem)
576 bar.Separator();
577 ColumnsMenu(bar);
578 }
579 }
580
RemovingMenu(Bar & bar)581 void GridCtrl::RemovingMenu(Bar &bar)
582 {
583 bool c = IsCursor() && IsRowEditable();
584 bar.Add(c && (keep_last_row ? GetCount() > 1 : true), t_("Delete "), StdRemove)
585 .Image(GridImg::Delete())
586 .Help(RowFormat(t_("Delete active %s.")))
587 .Key(K_DELETE);
588 }
589
MovingMenu(Bar & bar)590 void GridCtrl::MovingMenu(Bar &bar)
591 {
592 bool c = IsCursor();
593 bar.Add(c && curpos.y > fixed_rows, t_("Move up"), THISBACK(DoSwapUp))
594 .Image(GridImg::MoveUp())
595 .Key(K_CTRL_UP);
596 bar.Add(c && curpos.y >= fixed_rows && curpos.y < total_rows - 1, t_("Move down"), THISBACK(DoSwapDown))
597 .Image(GridImg::MoveDn())
598 .Key(K_CTRL_DOWN);
599 }
600
SelectMenu(Bar & bar)601 void GridCtrl::SelectMenu(Bar &bar)
602 {
603 bar.Add(total_rows > fixed_rows, RowFormat(t_("Select all")), THISBACK(DoSelectAll))
604 .Image(GridImg::SelectAll())
605 .Help(t_("Select all table rows"))
606 .Key(K_CTRL_A);
607 }
608
ColumnsMenu(Bar & bar)609 void GridCtrl::ColumnsMenu(Bar &bar)
610 {
611 bar.Add(t_("Columns"), THISBACK(ColumnList));
612 }
613
ColumnList(Bar & bar)614 void GridCtrl::ColumnList(Bar &bar)
615 {
616 int cnt = 0;
617 for(int i = fixed_cols; i < total_cols; i++)
618 if(!hitems[i].index && !hitems[i].hidden)
619 cnt++;
620
621 for(int i = fixed_cols; i < total_cols; i++)
622 {
623 if(!hitems[i].index)
624 bar.Add((String) items[0][hitems[i].id].val, THISBACK1(MenuHideColumn, i))
625 .Check(!hitems[i].hidden)
626 .Enable(cnt > 1 || (cnt == 1 && hitems[i].hidden));
627 }
628 }
629
ClipboardMenu(Bar & bar)630 void GridCtrl::ClipboardMenu(Bar &bar)
631 {
632 bool c = IsCursor();
633 bool s = c || IsSelection();
634 bar.Add(t_("Copy"), THISBACK(DoCopy)).Image(CtrlImg::copy()).Key(K_CTRL_C).Enable(s && copy_allowed);
635 bar.Add(t_("Cut"), THISBACK(Nothing)).Image(CtrlImg::cut()).Key(K_CTRL_X).Enable(s && cut_allowed);
636 bar.Add(t_("Paste"), THISBACK(DoPaste)).Image(CtrlImg::paste()).Key(K_CTRL_V).Enable(c && paste_allowed && IsClipboardAvailable());
637 if(extra_paste)
638 bar.Add(t_("Paste as"), THISBACK(PasteAsMenu));
639 }
640
PasteAsMenu(Bar & bar)641 void GridCtrl::PasteAsMenu(Bar &bar)
642 {
643 bool c = IsCursor();
644 bool s = IsClipboardAvailable() && !fixed_paste;
645 bar.Add(t_("appended"), THISBACK(DoPasteAppendedRows)).Key(K_CTRL_E).Enable(s && paste_allowed);
646 bar.Add(t_("inserted"), THISBACK(DoPasteInsertedRows)).Key(K_CTRL_I).Enable(c && paste_allowed && s);
647 }
648
IsClipboardAvailable()649 bool GridCtrl::IsClipboardAvailable()
650 {
651 return IsClipboardFormatAvailable<GridClipboard>() ||
652 IsClipboardAvailableText();
653 }
654
GetClipboard()655 GridClipboard GridCtrl::GetClipboard()
656 {
657 GridClipboard gc = ReadClipboardFormat<GridClipboard>();
658 return gc;
659 }
660
SetClipboard(bool all,bool silent)661 void GridCtrl::SetClipboard(bool all, bool silent)
662 {
663 if(!clipboard)
664 return;
665
666 GridClipboard gc;
667
668 Point minpos(total_cols, total_rows);
669 Point maxpos(fixed_cols, fixed_rows);
670
671 String body;
672 Vector<int> sc;
673 sc.Set(0, -1, total_cols);
674
675 int prev_row = -1;
676
677 for(int i = fixed_rows; i < total_rows; i++)
678 {
679 bool row_selected = select_row && IsSelected(i, false);
680
681 for(int j = fixed_cols; j < total_cols; j++)
682 {
683 if(all || row_selected || IsSelected(i, j, false))
684 {
685 if(prev_row < 0)
686 prev_row = i;
687
688 GridClipboard::ClipboardData &d = gc.data.Add();
689 d.col = j;
690 d.row = i;
691 d.v = Get0(i, j);
692
693 if(i < minpos.y) minpos.y = i;
694 else if(i > maxpos.y) maxpos.y = i;
695 if(j < minpos.x) minpos.x = j;
696 else if(j > maxpos.x) maxpos.x = j;
697
698 if(i != prev_row)
699 {
700 body += "\r\n";
701 prev_row = i;
702 }
703 body += GetStdConvertedColumn(j, d.v).ToString() + '\t';
704
705 sc[j] = 1;
706 }
707 }
708
709 int cnt = body.GetCount();
710 if(cnt > 0 && body[cnt - 1] == '\t')
711 body.Remove(cnt - 1);
712 }
713
714 String header;
715
716 if(copy_column_names)
717 {
718 for(int i = 0; i < sc.GetCount(); i++)
719 if(sc[i] >= 0)
720 header += hitems[i].GetName() + '\t';
721
722 int cnt = header.GetCount();
723 if(cnt > 0 && header[cnt - 1] == '\t')
724 header.Remove(cnt - 1);
725 header += "\r\n";
726 }
727
728 gc.minpos = minpos;
729 gc.maxpos = maxpos;
730
731 bool row_selected = select_row && IsSelected(curpos.y, false);
732 gc.shiftmode = row_selected ? true : shiftmode;
733
734 WriteClipboardFormat(gc);
735 AppendClipboardText(header + body);
736
737 if(!silent)
738 {
739 Color c0 = bg_select;
740 Color c1 = White;
741 Color c2 = bg_focus;
742
743 for(int i = 0; i < 256; i += 64)
744 {
745 bg_select = Blend(c0, c1, i);
746 bg_focus = Blend(c2, c1, i);
747 Refresh(); Sync();
748 Sleep(1);
749 }
750
751 for(int i = 0; i < 256; i += 32)
752 {
753 bg_select = Blend(c1, c0, i);
754 bg_focus = Blend(c1, c2, i);
755 Refresh(); Sync();
756 Sleep(1);
757 }
758 }
759 }
760
PasteCallbacks(bool new_row)761 void GridCtrl::PasteCallbacks(bool new_row)
762 {
763 if(new_row)
764 {
765 LOG("WhenInsertRow() - paste");
766 #ifdef LOG_CALLBACKS
767 LGR(2, "WhenInsertRow() - paste");
768 #endif
769 WhenInsertRow();
770 }
771 else
772 {
773 #ifdef LOG_CALLBACKS
774 LGR(2, "WhenUpdateRow() - paste");
775 #endif
776 WhenUpdateRow();
777 }
778 }
779
Paste(int mode)780 void GridCtrl::Paste(int mode)
781 {
782 if(!clipboard)
783 return;
784
785 GridClipboard gc = GetClipboard();
786
787 bool is_gc = !gc.data.IsEmpty();
788 bool is_tc = IsClipboardAvailableText();
789
790 if(!is_gc && !is_tc)
791 return;
792
793 if(is_gc && select_row && !gc.shiftmode)
794 return;
795
796 Point cp(curpos);
797
798 if(cp.x < 0 || select_row)
799 cp.x = fixed_cols;
800 if(cp.y < 0)
801 cp.y = fixed_rows;
802
803 Vector<String> lines;
804
805 if(is_tc && !is_gc)
806 lines = Upp::Split(FromUnicode(ReadClipboardUnicodeText()), '\n');
807
808 if(mode == 1)
809 {
810 int dy = is_gc ? gc.maxpos.y - gc.minpos.y + 1
811 : lines.GetCount();
812 Insert0(curpos.y, dy);
813 curpos.y += dy;
814 }
815 else if(mode == 2)
816 cp.y = total_rows;
817
818 int lc = -1, lr = -1;
819
820 int tr = total_rows;
821
822 if(!is_gc)
823 {
824 if(is_tc)
825 {
826 int pr = 0;
827 bool new_row = false;
828
829 for(int i = 0; i < lines.GetCount(); i++)
830 {
831 String line = TrimRight(lines[i]);
832 Vector<String> cells = Upp::Split(line, '\t', false);
833 for(int j = 0; j < cells.GetCount(); j++)
834 {
835 int r = i;
836 int c = j;
837
838 if(r > pr)
839 {
840 PasteCallbacks(new_row);
841 pr = r;
842 }
843
844 if(cp.x + c < total_cols)
845 {
846 lc = cp.x + c;
847 lr = cp.y + r;
848
849 rowidx = lr;
850
851 new_row = lr >= tr || mode > 0;
852
853 if(fixed_paste && new_row)
854 break;
855
856 Value v(cells[j]);
857 WhenPasteCell(lr - fixed_rows, lc - fixed_cols, v);
858 Set0(lr, lc, v, true);
859 }
860
861 if(i == lines.GetCount() - 1 && j == cells.GetCount() - 1)
862 PasteCallbacks(new_row);
863 }
864 }
865 }
866 }
867 else if(!select_row && gc.shiftmode)
868 {
869 lc = cp.x;
870 lr = cp.y;
871
872 for(int i = 0; i < gc.data.GetCount(); i++)
873 {
874 Set0(lr, lc, gc.data[i].v, true);
875
876 bool data_end = i == gc.data.GetCount() - 1;
877 bool new_row = ++lc > total_cols - 1;
878 if(new_row || data_end)
879 {
880 bool nr = lr + 1 >= tr;
881 if(new_row && nr && fixed_paste)
882 break;
883
884 PasteCallbacks(new_row && (nr || mode > 0));
885
886 if(!data_end)
887 {
888 lc = fixed_cols;
889 ++lr;
890 rowidx = lr;
891 }
892 }
893 }
894 }
895 else
896 {
897 int pr = gc.data[0].row - gc.minpos.y;
898 bool new_row = false;
899
900 for(int i = 0; i < gc.data.GetCount(); i++)
901 {
902 int r = gc.data[i].row - gc.minpos.y;
903 int c = gc.data[i].col - gc.minpos.x;
904
905 if(r > pr)
906 {
907 PasteCallbacks(new_row);
908 pr = r;
909 }
910
911 if(cp.x + c < total_cols)
912 {
913 lc = cp.x + c;
914 lr = cp.y + r;
915
916 rowidx = lr;
917
918 new_row = lr >= tr || mode > 0;
919
920 if(fixed_paste && new_row)
921 break;
922 Set0(lr, lc, gc.data[i].v, true);
923 }
924
925 if(i == gc.data.GetCount() - 1)
926 PasteCallbacks(new_row);
927 }
928 }
929
930 if(lc >= 0 && lr >= 0)
931 {
932 SetCursor0(lc, lr);
933 sby.Set(vitems[curpos.y].nBottom() - GetSize().cy);
934 }
935 WhenPaste();
936 ClearSelection();
937 }
938
DoCopy()939 void GridCtrl::DoCopy()
940 {
941 SetClipboard();
942 }
943
DoPaste()944 void GridCtrl::DoPaste()
945 {
946 Paste(0);
947 }
948
DoPasteInsertedRows()949 void GridCtrl::DoPasteInsertedRows()
950 {
951 Paste(1);
952 }
953
DoPasteAppendedRows()954 void GridCtrl::DoPasteAppendedRows()
955 {
956 Paste(2);
957 }
958
SetOrder()959 void GridCtrl::SetOrder()
960 {
961 row_order = true;
962 WhenChangeOrder();
963 }
964
Nothing()965 void GridCtrl::Nothing()
966 {
967 }
968
DrawLine(bool iniLine,bool delLine)969 void GridCtrl::DrawLine(bool iniLine, bool delLine)
970 {
971 if((resizeCol || resizeRow) && resize_paint_mode < 2)
972 {
973 int sx = resize_paint_mode == 1 ? fixed_width : 0;
974 int sy = resize_paint_mode == 1 ? fixed_height : 0;
975 ViewDraw w(this);
976 Size sz = GetSize();
977
978 Point curPnt;
979 static Point oldPnt = curPnt;
980
981 if(resizeCol)
982 {
983 curPnt.x = hitems[splitCol].nRight(sbx) - 1;
984 if(delLine) w.DrawRect(oldPnt.x, sy, 1, sz.cy, InvertColor());
985 if(iniLine) w.DrawRect(curPnt.x, sy, 1, sz.cy, InvertColor());
986 }
987 if(resizeRow)
988 {
989 curPnt.y = vitems[splitRow].nBottom(sby) - 1;
990 if(delLine) w.DrawRect(sx, oldPnt.y, sz.cx, 1, InvertColor());
991 if(iniLine) w.DrawRect(sx, curPnt.y, sz.cx, 1, InvertColor());
992 }
993
994 oldPnt = curPnt;
995 }
996 }
997
GetItemValue(const Item & it,int id,const ItemRect & hi,const ItemRect & vi)998 Value GridCtrl::GetItemValue(const Item& it, int id, const ItemRect& hi, const ItemRect& vi)
999 {
1000 Value val = hi.IsConvertion() && vi.IsConvertion()
1001 ? GetConvertedColumn(id, it.val)
1002 : it.val;
1003
1004 return val;
1005 }
1006
GetAttrTextVal(const Value & val)1007 Value GridCtrl::GetAttrTextVal(const Value& val)
1008 {
1009 if(IsType<AttrText>(val))
1010 {
1011 const AttrText& t = ValueTo<AttrText>(val);
1012 return t.text;
1013 }
1014 return val;
1015 }
1016
GetItemAttrs(const Item & it,const Value & value,int r,int c,const ItemRect & vi,const ItemRect & hi,dword & style,GridDisplay * & gd,Color & fg,Color & bg,Font & fnt)1017 void GridCtrl::GetItemAttrs(const Item& it, const Value& value, int r, int c, const ItemRect& vi, const ItemRect& hi, dword& style, GridDisplay*& gd, Color& fg, Color& bg, Font& fnt)
1018 {
1019 if(!IsNull(vi.fg))
1020 fg = vi.fg;
1021 else if(!IsNull(hi.fg))
1022 fg = hi.fg;
1023
1024 if(!IsNull(vi.bg))
1025 bg = vi.bg;
1026 else if(!IsNull(hi.bg))
1027 bg = hi.bg;
1028
1029 fnt = StdFont();
1030
1031 if(r < fixed_rows && !IsNull(hi.hfnt))
1032 fnt = hi.hfnt;
1033 else if(c < fixed_cols && !IsNull(vi.hfnt))
1034 fnt = vi.hfnt;
1035 else if(!IsNull(vi.fnt))
1036 fnt = vi.fnt;
1037 else if(!IsNull(hi.fnt))
1038 fnt = hi.fnt;
1039
1040 GridDisplay * hd = hi.display;
1041 GridDisplay * vd = vi.display;
1042 gd = display;
1043 if(!hi.ignore_display && !vi.ignore_display)
1044 gd = vd ? vd : (hd ? hd : (it.display ? it.display : display));
1045
1046 gd->SetLeftImage(Null);
1047
1048 const Value& val = IsNull(value) ? it.val : value;
1049
1050 if(IsType<AttrText>(val))
1051 {
1052 const AttrText& t = ValueTo<AttrText>(val);
1053
1054 if(!IsNull(t.paper)) bg = t.paper;
1055 if(!IsNull(t.ink)) fg = t.ink;
1056 if(!IsNull(t.font)) fnt = t.font;
1057 dword s = 0;
1058 if(!IsNull(t.align))
1059 {
1060 if(t.align == ALIGN_LEFT)
1061 s = GD::LEFT;
1062 else if(t.align == ALIGN_RIGHT)
1063 s = GD::RIGHT;
1064 else if(t.align == ALIGN_CENTER)
1065 s = GD::HCENTER;
1066 style &= ~GD::HALIGN;
1067 style |= s;
1068 }
1069 if(!IsNull(t.img))
1070 gd->SetLeftImage(t.img);
1071 }
1072
1073 }
1074
GetItemSize(int & r,int & c,int & x,int & y,int & cx,int & cy,bool & skip,bool relx,bool rely)1075 GridCtrl::Item& GridCtrl::GetItemSize(int &r, int &c, int &x, int &y, int &cx, int &cy, bool &skip, bool relx, bool rely)
1076 {
1077 int idx = hitems[c].id;
1078 int idy = vitems[r].id;
1079
1080 int dx = 0;
1081 int dy = 0;
1082
1083 Item *it = &items[idy][idx];
1084
1085 if(it->isjoined)
1086 {
1087 int group = it->group;
1088 it = &items[it->idy][it->idx];
1089 skip = it->paint_flag == paint_flag;
1090 it->paint_flag = paint_flag;
1091 if(skip)
1092 return *it;
1093
1094 while(c >= 0 && items[idy][hitems[c].id].group == group) --c;
1095 ++c;
1096 while(r >= 0 && items[vitems[r].id][idx].group == group) --r;
1097 ++r;
1098
1099 dx = it->cx;
1100 dy = it->cy;
1101 }
1102 else
1103 skip = false;
1104
1105 x = hitems[c].nLeft();
1106 y = vitems[r].nTop();
1107 cx = hitems[c + dx].nRight() - x;
1108 cy = vitems[r + dy].nBottom() - y;
1109
1110 if(!draw_last_vert_line && c == total_cols - 1 && r >= fixed_rows) cx += 1;
1111 if(!draw_last_horz_line && r == total_rows - 1 && c >= fixed_cols) cy += 1;
1112
1113 if(relx) x -= sbx;
1114 if(rely) y -= sby;
1115
1116 return *it;
1117 }
1118
Paint(Draw & w)1119 void GridCtrl::Paint(Draw &w)
1120 {
1121 static int paintcnt = 0;
1122
1123 Font stdfont(StdFont());
1124
1125 Size sz = GetSize();
1126 Rect rc = Rect(sz); //w.GetClip() - it always returns view rect now. bug??
1127
1128 if(!ready)
1129 {
1130 w.DrawRect(rc, SColorPaper);
1131 return;
1132 }
1133
1134 int i, j, cx, cy, x, y;
1135 bool skip;
1136 Rect r;
1137
1138 LG(0, "---- Paint(%d)", ++paintcnt);
1139
1140 if(total_cols <= 1 || total_rows == 0)
1141 {
1142 LG(0, "---- Paint(%d) Empty.", paintcnt);
1143 w.DrawRect(sz, SColorPaper);
1144 return;
1145 }
1146
1147 if(UpdateCols() || UpdateRows())
1148 UpdateSizes();
1149
1150 if(firstCol < 0) firstCol = GetFirstVisCol(fixed_width);
1151 if(firstRow < 0) firstRow = GetFirstVisRow(fixed_height);
1152
1153 LG(0, "firstCol %d", firstCol);
1154 LG(0, "firstRow %d", firstRow);
1155
1156 int en = IsShowEnabled() ? 0 : GD::READONLY;
1157
1158 //---------------------------------------------------------------------------------------
1159
1160 if(fixed_width > 0 && fixed_height > 0)
1161 {
1162 w.Clip(0, 0, fixed_width, fixed_height);
1163 dword style = chameleon ? GD::CHAMELEON : 0;
1164
1165 display->PaintFixed(w, 1, 1, 0, 0, fixed_width, fixed_height,
1166 Value(""),
1167 style, stdfont, false, false,
1168 0, -1, 0,
1169 true);
1170 w.End();
1171 }
1172
1173 r.Set(fixed_width, 0, sz.cx, summary_row ? sz.cy : fixed_height);
1174
1175 if(w.IsPainting(r) && total_cols > 1)
1176 {
1177 LG(0, "Top header");
1178 w.Clip(r);
1179
1180 x = hitems[total_cols - 1].nRight(sbx);
1181 int rx = x;
1182
1183 int firstcol = indicator ? 0 : (fixed_cols > 1 ? 1 : firstVisCol);
1184 if(firstCol < 0) firstCol = 0;
1185 int jfc = chameleon ? 0 : firstCol;
1186
1187 for(i = 0; i < fixed_rows; i++)
1188 {
1189 for(j = jfc; j < total_cols; j++)
1190 {
1191 ItemRect& hi = hitems[j];
1192
1193 if(hi.hidden)
1194 continue;
1195
1196 int jj = j;
1197 Item &it = GetItemSize(i, j, x, y, cx, cy, skip, true, false);
1198 if(skip)
1199 continue;
1200
1201 if(x >= rc.right)
1202 break;
1203
1204 if(w.IsPainting(x, y, cx, cy))
1205 {
1206 GridDisplay * gd = it.display ? it.display : display;
1207
1208 dword style = hi.style | hi.halign;
1209 if(i > 0) style &= ~GD::HIGHLIGHT;
1210 if(chameleon)
1211 style |= GD::CHAMELEON;
1212
1213 Font fnt(stdfont);
1214 gd->SetLeftImage(hi.img);
1215 gd->ReverseSortIcon(reverse_sort_icon);
1216 gd->PaintFixed(w, jj == firstcol, i == 0, x, y, cx, cy,
1217 i == 0 ? it.val : GetConvertedColumn(hi.id, it.val),
1218 style | en, IsNull(hi.hfnt) ? fnt : hi.hfnt, false, false,
1219 i == 0 ? hi.sortmode : 0,
1220 hi.sortcol,
1221 sortOrder.GetCount(),
1222 true);
1223
1224 it.rcx = gd->real_size.cx;
1225 it.rcy = gd->real_size.cy;
1226 }
1227
1228 if(summary_row && i == 0)
1229 {
1230 cy = GD_HDR_HEIGHT;
1231 y = sz.cy - cy;
1232
1233 if(w.IsPainting(x, y, cx, cy))
1234 {
1235 Item &it = summary[hi.id];
1236 GridDisplay * gd = it.display ? it.display : display;
1237
1238 dword style = en | hi.halign;
1239 if(chameleon)
1240 style |= GD::CHAMELEON;
1241
1242 String s;
1243 if(hi.sop != SOP_NONE && !hi.sopfrm.IsEmpty() && !IsNull(it.val))
1244 s = Format(hi.sopfrm, it.val);
1245 else
1246 s = IsString(it.val) ? it.val : StdConvert().Format(it.val);
1247 gd->SetLeftImage(Null);
1248 //gd->PaintFixed(w, jj == firstcol, i == 0, x, y, cx, cy, s,
1249 // style | en, stdfont, false, false, 0, -1, 0, true);
1250 Color fg = Black;
1251 Color bg = Blend(Blue, White, 240);
1252 w.DrawRect(x, y, cx, 1, Gray);
1253 Font fnt(stdfont);
1254
1255 if(style & GD::READONLY)
1256 {
1257 bg = Blend(bg, SGray(), 40);
1258 fg = Blend(fg, SGray(), 200);
1259 }
1260
1261 gd->Paint(w, x, y + 1, cx, cy - 1, s, style, fg, bg, fnt.Bold(), false, 0, 0);
1262
1263 it.rcx = gd->real_size.cx;
1264 it.rcy = gd->real_size.cy;
1265 }
1266 }
1267 }
1268 }
1269 if(rx < sz.cx || chameleon)
1270 {
1271 int cx = sz.cx - rx + 1;
1272 dword style = 0;
1273 if(chameleon)
1274 {
1275 cx = max(10, cx);
1276 style = GD::CHAMELEON;
1277 }
1278 display->PaintFixed(w, 0, 1, rx, 0, cx, fixed_height,
1279 Value(""),
1280 style, stdfont, false, false,
1281 0, -1, 0,
1282 true);
1283 if(summary_row)
1284 {
1285 Color fg = Black;
1286 Color bg = Blend(Blue, White, 240);
1287 w.DrawRect(rx, y, cx, 1, Gray);
1288
1289 if(style & GD::READONLY)
1290 {
1291 bg = Blend(bg, SGray(), 40);
1292 fg = Blend(fg, SGray(), 200);
1293 }
1294 display->Paint(w, rx, y + 1, cx, GD_HDR_HEIGHT - 1, Value(""), style, fg, bg, stdfont, false, 0, 0);
1295 }
1296 }
1297
1298 w.End();
1299 }
1300 //---------------------------------------------------------------------------------------
1301
1302 bool can_paint = firstCol >= 0 && firstRow >= 0;
1303 r.Set(0, fixed_height, fixed_width, sz.cy);
1304
1305 if(can_paint && w.IsPainting(r))
1306 {
1307 LG(0, "Left header");
1308 w.Clip(r);
1309 y = vitems[total_rows - 1].nBottom(sby);
1310
1311 if(y < sz.cy)
1312 w.DrawRect(Rect(0, y, fixed_width, sz.cy - summary_height), SColorPaper);
1313
1314 for(i = 0; i < fixed_cols; i++)
1315 {
1316 bool firstx = (i == !indicator);
1317 bool indicator = (i == 0);
1318 int id = hitems[i].id;
1319
1320 for(j = firstRow; j < total_rows; j++)
1321 {
1322 ItemRect& vi = vitems[j];
1323
1324 if(vi.hidden)
1325 continue;
1326
1327 Item &it = GetItemSize(j, i, x, y, cx, cy, skip, false, true);
1328
1329 if(skip)
1330 continue;
1331
1332 if(y >= rc.bottom)
1333 break;
1334
1335 if(w.IsPainting(x, y, cx, cy))
1336 {
1337 GridDisplay * gd = it.display ? it.display : display;
1338
1339 dword style = vi.style;
1340 if(i > 0) style &= ~GD::HIGHLIGHT;
1341 if(chameleon)
1342 style |= GD::CHAMELEON;
1343
1344 Font fnt(stdfont);
1345 gd->PaintFixed(w, firstx, j == 0, x, y, cx, cy,
1346 GetConvertedColumn(id, it.val),
1347 style | en, IsNull(vi.hfnt) ? fnt : vi.hfnt,
1348 indicator, false, 0, -1, 0, false);
1349
1350 it.rcx = gd->real_size.cx;
1351 it.rcy = gd->real_size.cy;
1352 }
1353 }
1354
1355 if(summary_row)
1356 {
1357 j = 0;
1358 cy = GD_HDR_HEIGHT;
1359 y = sz.cy - cy;
1360 if(w.IsPainting(x, y, cx, cy))
1361 {
1362 Item& it = summary[hitems[i].id];
1363 GridDisplay * gd = it.display ? it.display : display;
1364
1365 dword style = vitems[j].style;
1366 if(chameleon)
1367 style |= GD::CHAMELEON;
1368
1369 // gd->PaintFixed(w, firstx, true, x, y, cx, cy,
1370 // GetConvertedColumn(id, it.val),
1371 // style | en, stdfont,
1372 // false, false, 0, -1, 0, false);
1373 //
1374 Color fg = Black;
1375 Color bg = Blend(Blue, White, 240);
1376 w.DrawRect(x, y, cx, 1, Gray);
1377 Font fnt(stdfont);
1378 gd->Paint(w, x, y + 1, cx, cy - 1, GetConvertedColumn(id, it.val), style | en, fg, bg, fnt.Bold(), false, 0, 0);
1379
1380 }
1381 }
1382 }
1383
1384 w.End();
1385 }
1386
1387 //---------------------------------------------------------------------------------------
1388
1389 r.Set(fixed_width, fixed_height, sz.cx, sz.cy - summary_height);
1390
1391 if(can_paint && w.IsPainting(r))
1392 {
1393 LG(0, "Body");
1394 w.Clip(r);
1395
1396 x = hitems[total_cols - 1].nRight(sbx);
1397 y = vitems[total_rows - 1].nBottom(sby);
1398
1399 if(x < sz.cx) w.DrawRect(Rect(max(x, rc.left), max(fixed_height, rc.top), sz.cx, sz.cy), SColorPaper);
1400 if(y < sz.cy) w.DrawRect(Rect(max(fixed_width, rc.left), max(y, rc.top), sz.cx, sz.cy), SColorPaper);
1401
1402 bool hasfocus = HasFocus() || holder.HasFocusDeep();
1403
1404 for(i = max(firstRow, fixed_rows); i < total_rows; i++)
1405 {
1406 ItemRect& vi = vitems[i];
1407 if(vi.hidden) continue;
1408
1409 bool even = coloring_mode == 2 ? (i - vi.n - fixed_rows) & 1 : false;
1410
1411 for(j = max(firstCol, fixed_cols); j < total_cols; j++)
1412 {
1413 const ItemRect& hi = hitems[j];
1414
1415 if(hi.hidden)
1416 continue;
1417
1418 Item &it = GetItemSize(i, j, x, y, cx, cy, skip);
1419 if(skip)
1420 continue;
1421
1422 if(y >= rc.bottom)
1423 goto end_paint;
1424
1425 if(x >= rc.right)
1426 break;
1427
1428 if(!w.IsPainting(0, y, sz.cx, cy))
1429 break;
1430
1431 if(w.IsPainting(x, y, cx, cy))
1432 {
1433 bool iscur = draw_focus ? (i == curpos.y && j == curpos.x) : false;
1434
1435 if(coloring_mode == 1)
1436 even = (j - hi.n - fixed_cols) & 1;
1437
1438 int id = hi.id;
1439
1440 dword style = en | (select_row ? vi.style : it.style) | hi.balign;
1441 dword istyle = it.style;
1442
1443 if(hitems[j].wrap)
1444 style |= GD::WRAP;
1445 if(ctrlpos.y == i && edits[id].ctrl && edits[id].ctrl->IsShown())
1446 style |= GD::NOTEXT;
1447 if(it.ctrl)
1448 style |= GD::NOTEXT;
1449
1450 if(coloring_mode > 0)
1451 style |= (even ? GD::EVEN : GD::ODD);
1452 if(hasfocus)
1453 style |= GD::FOCUS;
1454
1455 Color cfg;
1456 Color cbg;
1457
1458 Font fnt = StdFont();
1459 GridDisplay* gd;
1460 Value val = GetItemValue(it, id, hi, vi);
1461 GetItemAttrs(it, val, i, j, vi, hi, style, gd, cfg, cbg, fnt);
1462
1463 Color fg = SColorText;
1464 Color bg = SColorPaper;
1465
1466 bool custom = true;
1467
1468 if(style & GD::CURSOR)
1469 {
1470 if(style & GD::FOCUS)
1471 {
1472 fg = iscur ? Blend(bg_focus, Black, 230) : fg_focus;
1473 bg = iscur ? Blend(bg_focus, White, 230) : bg_focus;
1474 }
1475 else
1476 {
1477 bg = Blend(SColorDisabled, bg);
1478 }
1479 custom = false;
1480 }
1481 else if(style & GD::LIVE)
1482 {
1483 fg = fg_live;
1484 bg = bg_live;
1485 custom = false;
1486 }
1487 else if(istyle & GD::FOUND)
1488 {
1489 fg = fg_found;
1490 bg = bg_found;
1491 custom = false;
1492 }
1493 else if(style & GD::SELECT)
1494 {
1495 fg = fg_select;
1496 bg = bg_select;
1497 custom = false;
1498 }
1499 else if(style & GD::EVEN)
1500 {
1501 fg = fg_even;
1502 bg = bg_even;
1503 }
1504 else if(style & GD::ODD)
1505 {
1506 fg = fg_odd;
1507 bg = bg_odd;
1508 }
1509
1510 if(custom)
1511 {
1512 if(!IsNull(cfg)) fg = cfg;
1513 if(!IsNull(cbg)) bg = cbg;
1514 }
1515
1516 if(style & GD::READONLY)
1517 {
1518 bg = Blend(bg, SGray(), 40);
1519 fg = Blend(fg, SGray(), 200);
1520 }
1521
1522 gd->SetBgImage(vi.img);
1523 gd->col = j - fixed_rows;
1524 gd->row = i - fixed_cols;
1525 gd->parent = this;
1526
1527 val = GetAttrTextVal(val);
1528
1529 gd->Paint(w, x, y, cx, cy,
1530 val, style,
1531 fg, bg, fnt, it.style & GD::FOUND, it.fs, it.fe);
1532
1533 it.rcx = gd->real_size.cx;
1534 it.rcy = gd->real_size.cy;
1535
1536 if(vert_grid)
1537 {
1538 bool skip = false;
1539 if(!draw_last_vert_line && j == total_cols - 1)
1540 skip = true;
1541
1542 if(!skip)
1543 w.DrawRect(x + cx - 1, y, 1, cy, fg_grid);
1544 }
1545 if(horz_grid)
1546 {
1547 bool skip = false;
1548 if(!draw_last_horz_line && i == total_rows - 1)
1549 skip = true;
1550
1551 if(!skip)
1552 w.DrawRect(x, y + cy - 1, cx, 1, fg_grid);
1553 }
1554
1555 if(iscur && draw_focus)
1556 Upp::DrawFocus(w, x, y, cx, cy);
1557 }
1558 //if(curpos.y == i)
1559 // DrawFocus(w, hitems[fixed_cols].nLeft(), y, hitems[total_cols - 1].nRight() - 1, cy - 1);
1560 }
1561 }
1562
1563 end_paint:
1564
1565 w.End();
1566
1567 lastCol = j - 1;
1568 lastRow = i - 1;
1569 }
1570
1571
1572 if(moving_header && fixed_top_click && curSplitCol >= 0)
1573 {
1574 r.Set(fixed_width, 0, sz.cx, fixed_height);
1575 w.Clip(r);
1576 bool lastcol = curSplitCol == lastVisCol;
1577
1578 int cp = curSplitCol;
1579 if(!lastcol)
1580 while(++cp < total_cols && hitems[cp].hidden);
1581
1582 int cx = hitems[cp].nWidth() / 2;
1583 int x = lastcol ? hitems[curSplitCol].nLeft(sbx) + cx
1584 : hitems[curSplitCol].nRight(sbx) - 1;
1585 DrawFatFrame(w, x, 0, cx, vitems[fixed_rows - 1].nBottom(), moving_allowed ? LtBlue : Red, 2);
1586 w.End();
1587 }
1588
1589 if(moving_header && fixed_left_click)
1590 {
1591 int dy = curSplitRow == lastVisRow ? -2 : -1;
1592 int y = curSplitRow >= 0 ? vitems[curSplitRow].nBottom(sby) + dy : 0;
1593 if(y >= fixed_height - 1)
1594 DrawVertDragLine(w, y, hitems[fixed_cols - 1].nRight(), 0, moving_allowed ? LtBlue : Red);
1595 }
1596
1597 if(moving_body)
1598 {
1599 int dy = curSplitRow == lastVisRow ? -2 : -1;
1600 int y = curSplitRow >= 0 ? vitems[curSplitRow].nBottom(sby) + dy : 0;
1601 if(y >= fixed_height - 1)
1602 DrawVertDragLine(w, y, sz.cx, fixed_width - 1, LtBlue);
1603 }
1604
1605 if(search_display && !search_string.IsEmpty())
1606 {
1607 Size tsz = GetTextSize(search_string, StdFont());
1608 w.DrawRect(Rect(0, sz.cy - tsz.cy - 4, tsz.cx + 4, sz.cy), SRed);
1609 w.DrawText(2, sz.cy - tsz.cy - 2, search_string, StdFont(), SYellow);
1610 }
1611
1612 if(!can_paint)
1613 w.DrawRect(Rect(0, total_cols > 1 ? fixed_height : 0, sz.cx, sz.cy), SColorPaper);
1614 if(++paint_flag > 100)
1615 paint_flag = 0;
1616
1617 LG(0, "---- Paint(%d).", paintcnt);
1618 }
1619
DrawHorzDragLine(Draw & w,int pos,int cx,int size,Color c)1620 void GridCtrl::DrawHorzDragLine(Draw &w, int pos, int cx, int size, Color c)
1621 {
1622 //w.DrawRect(pos, 0, cx / 2, size - 1, Color(100, 100, 100, 100);
1623 DrawFrame(w, pos + 1, 1, cx / 2 - 2, size - 2, c);
1624 DrawFrame(w, pos, 0, cx / 2, size, c);
1625 // DrawFatFrame(w, x, 0,ďż˝ int cxďż˝ int cyďż˝ Color colorďż˝ int n)
1626 }
1627
DrawVertDragLine(Draw & w,int pos,int size,int dx,Color c)1628 void GridCtrl::DrawVertDragLine(Draw &w, int pos, int size, int dx, Color c)
1629 {
1630 w.DrawRect(1 + dx, pos, size - dx - 1, 2, c);
1631 }
1632
GetStdConvertedValue(const Value & v) const1633 Value GridCtrl::GetStdConvertedValue(const Value& v) const
1634 {
1635 if(IsString(v))
1636 {
1637 return v;
1638 }
1639 else if(IsType<AttrText>(v))
1640 {
1641 const AttrText& t = ValueTo<AttrText>(v);
1642 return t.text;
1643 }
1644 else
1645 return StdConvert().Format(v);
1646 }
1647
GetConvertedColumn(int col,const Value & v) const1648 Value GridCtrl::GetConvertedColumn(int col, const Value &v) const
1649 {
1650 Convert *conv = edits[col].convert;
1651 return conv ? conv->Format(v) : v;
1652 }
1653
GetStdConvertedColumn(int col,const Value & v) const1654 Value GridCtrl::GetStdConvertedColumn(int col, const Value &v) const
1655 {
1656 Value val = GetConvertedColumn(col, v);
1657 return GetStdConvertedValue(val);
1658 }
1659
GetString(Id id) const1660 String GridCtrl::GetString(Id id) const
1661 {
1662 int c = aliases.Get(id);
1663 return GetStdConvertedColumn(c, Get0(rowidx, c));
1664 }
1665
InsertColumn(int col,const char * name,int size,bool idx)1666 GridCtrl::ItemRect& GridCtrl::InsertColumn(int col, const char *name, int size, bool idx)
1667 {
1668 int id;
1669
1670 if(size < 0)
1671 size = GD_COL_WIDTH;
1672
1673 if(col < total_cols)
1674 {
1675 id = hitems[col].id;
1676 for(int i = 0; i < total_cols; i++)
1677 {
1678 if(hitems[i].id >= id)
1679 hitems[i].id += 1;
1680 }
1681 }
1682 else
1683 id = total_cols;
1684
1685 ItemRect& ir = hitems.Insert(col);
1686 ir.parent = this;
1687 ir.items = &items;
1688 ir.edits = &edits;
1689 ir.prop = size;
1690 ir.id = id;
1691 ir.uid = coluid++;
1692 ir.index = idx;
1693
1694 if(index_as_column && idx)
1695 {
1696 size = 70;
1697 ir.prop = size;
1698 ir.Fixed(size);
1699 }
1700
1701 ir.Size(size);
1702 aliases.Add(ToLower(name), id);
1703 rowbkp.Insert(id);
1704 edits.Insert(id);
1705 summary.Insert(id);
1706
1707 for(int i = 0; i < total_rows; i++)
1708 items[i].Insert(id);
1709
1710 items[0][id].val = name;
1711
1712 colidx = col;
1713 total_cols++;
1714
1715 UpdateJoins(-1, col, 1);
1716
1717 firstCol = -1;
1718
1719 if(ready)
1720 {
1721 RecalcCols();
1722 UpdateSizes();
1723 UpdateSb();
1724 SyncSummary();
1725 SyncCtrls();
1726 Refresh(); //RefreshFromCol??
1727 }
1728 else
1729 recalc_cols = true;
1730
1731 SetModify();
1732
1733 return hitems[col];
1734 }
1735
AddColumn(const char * name,int size,bool idx)1736 GridCtrl::ItemRect& GridCtrl::AddColumn(const char *name, int size, bool idx)
1737 {
1738 ItemRect::aliases = &aliases;
1739
1740 if(size < 0)
1741 size = GD_COL_WIDTH;
1742
1743 if(total_rows > 1)
1744 for(int i = 1; i < total_rows; ++i)
1745 items[i].Add();
1746 else
1747 total_rows = 1;
1748
1749 Item &it = items[0].Add();
1750 it.val = name;
1751
1752 ItemRect &ib = hitems.Add();
1753
1754 ib.parent = this;
1755 ib.items = &items;
1756 ib.edits = &edits;
1757 ib.prop = size;
1758 ib.id = total_cols;
1759 ib.uid = coluid++;
1760 ib.index = idx;
1761
1762 if(index_as_column && idx)
1763 {
1764 size = 70;
1765 ib.prop = size;
1766 ib.Fixed(size);
1767 }
1768
1769 ib.Size(size);
1770 if(!ib.hidden)
1771 {
1772 lastVisCol = total_cols;
1773 if(firstVisCol < 0)
1774 firstVisCol = lastVisCol;
1775 }
1776
1777 if(header && vitems[0].nsize == 0)
1778 {
1779 vitems[0].size = vitems[0].nsize = GD_HDR_HEIGHT;
1780 vitems[0].hidden = false;
1781 }
1782 if(!header)
1783 {
1784 vitems[0].size = vitems[0].nsize = 0;
1785 vitems[0].hidden = true;
1786 }
1787
1788 edits.Add();
1789 summary.Add();
1790 rowbkp.Add();
1791 aliases.Add(ToLower(name), ib.id);
1792 total_cols++;
1793
1794 if(ready && IsOpen())
1795 {
1796 recalc_cols = true;
1797 RefreshLayout();
1798 }
1799
1800 return ib;
1801 }
1802
AddColumn(const Id id,const char * name,int size,bool idx)1803 GridCtrl::ItemRect& GridCtrl::AddColumn(const Id id, const char *name, int size, bool idx)
1804 {
1805 return AddColumn(name ? name : (const char *) ~id, size, idx).Alias(id);
1806 }
1807
AddColumn(const String & name,int size,bool idx)1808 GridCtrl::ItemRect& GridCtrl::AddColumn(const String& name, int size, bool idx)
1809 {
1810 return AddColumn((const char *) name, size, idx);
1811 }
1812
RemoveColumn(int n,int count)1813 void GridCtrl::RemoveColumn(int n, int count)
1814 {
1815 n += fixed_cols;
1816 if(count < 0)
1817 count = total_cols - n;
1818 if(n < fixed_cols || n + count > total_cols)
1819 return;
1820 for(int i = 0; i < total_rows; i++)
1821 items[i].Remove(n, count);
1822
1823 Vector<int> r;
1824 for(int i = 0; i < count; i++)
1825 {
1826 if(edits[hitems[n + i].id].factory)
1827 --genr_ctrls;
1828 r.Add(hitems[n + i].id);
1829 }
1830
1831 int id = hitems[n].id;
1832
1833 Upp::Sort(r);
1834
1835 hitems.Remove(n, count);
1836
1837 rowbkp.Remove(r);
1838 summary.Remove(r);
1839 edits.Remove(r);
1840 total_cols -= count;
1841 recalc_cols = true;
1842
1843 for(int i = 0; i < total_cols; i++)
1844 if(hitems[i].id >= id)
1845 hitems[i].id -= count;
1846
1847 valid_cursor = SetCursor0(min(curpos.x, total_cols - 1), curpos.y).IsValid();
1848 Repaint(true);
1849 }
1850
AddRow(int n,int size)1851 GridCtrl::ItemRect& GridCtrl::AddRow(int n, int size)
1852 {
1853 Append0(n, size);
1854 return GetRow();
1855 }
1856
AddSeparator(Color c)1857 GridCtrl& GridCtrl::AddSeparator(Color c)
1858 {
1859 Append0(1, 3);
1860 ItemRect& ir = GetRow();
1861 ir.Bg(c);
1862 ir.Editable(false);
1863 ir.Clickable(false);
1864 ir.Skip(true);
1865 return *this;
1866 }
1867
SetRowCount(int n,int size)1868 void GridCtrl::SetRowCount(int n, int size)
1869 {
1870 Clear();
1871 Append0(n, size);
1872 }
1873
SetColCount(int n,int size)1874 void GridCtrl::SetColCount(int n, int size)
1875 {
1876 Reset();
1877 for(int i = 0; i < n; i++)
1878 AddColumn("", size, false);
1879 }
1880
MouseMove(Point p,dword keyflags)1881 void GridCtrl::MouseMove(Point p, dword keyflags)
1882 {
1883 mouse_move = true;
1884
1885 if(resizing)
1886 {
1887 int si, lp, mp, off;
1888 RectItems *its;
1889 static int sub = 0;
1890
1891 if(resizeCol)
1892 {
1893 mp = p.x;
1894 lp = leftpnt.x;
1895 si = splitCol;
1896 its = &hitems;
1897 bool top = fixed_top_click || (!fixed_left_click && full_col_resizing);
1898 off = top ? sbx : 0;
1899 }
1900 else
1901 {
1902 mp = p.y;
1903 lp = leftpnt.y;
1904 si = splitRow;
1905 its = &vitems;
1906 bool left = fixed_left_click || (!fixed_top_click && full_row_resizing);
1907 off = left ? sby : 0;
1908 }
1909
1910 int right = (*its)[si].nRight(off);
1911
1912 if(just_clicked)
1913 {
1914 sub = right - lp;
1915 just_clicked = false;
1916 }
1917
1918 if(SetDiffItemSize(resizeCol, *its, si, mp - right + sub))
1919 {
1920 Split(GS_MOVE);
1921 }
1922
1923 return;
1924 }
1925 else if(fixed_click)
1926 {
1927 if((fixed_top_click && !moving_cols) ||
1928 (fixed_left_click && !moving_rows) ||
1929 moveCol < 0 || moveRow < 0)
1930 return;
1931
1932 if(!moving_header)
1933 {
1934 int diffx = p.x - leftpnt.x;
1935 int diffy = p.y - leftpnt.y;
1936 if(abs(diffx) < 5 && abs(diffy) < 5)
1937 return;
1938
1939 p -= Point(diffx, diffy);
1940
1941 moving_header = true;
1942 int idx = hitems[moveCol].id;
1943 int idy = vitems[moveRow].id;
1944 pophdr.val = idy > 0 ? GetConvertedColumn(moveCol, items[idy][idx].val) : items[idy][idx].val;
1945
1946 if(fixed_top_click)
1947 {
1948 pophdr.sortmode = hitems[moveCol].sortmode;
1949 pophdr.sortcol = hitems[moveCol].sortcol;
1950 pophdr.sortcnt = sortOrder.GetCount();
1951
1952 UpdateHighlighting(GS_POPUP, p);
1953 }
1954 else
1955 {
1956 pophdr.sortmode = 0;
1957 pophdr.sortcol = -1;
1958 pophdr.sortcnt = 0;
1959 }
1960
1961 dx = hitems[moveCol].nLeft(fixed_top_click ? sbx : 0) - p.x;
1962 dy = vitems[moveRow].nTop(fixed_left_click ? sby : 0) - p.y;
1963 }
1964
1965
1966 Point pt = p + GetScreenRect().TopLeft() + GetBarOffset();
1967
1968 pophdr.display = display;
1969 pophdr.chameleon = chameleon;
1970 pophdr.PopUp(this, pt.x + dx, pt.y + dy, hitems[moveCol].nWidth(), vitems[moveRow].nHeight());
1971
1972 if(fixed_top_click && curSplitCol != oldMoveCol)
1973 {
1974 moving_allowed = CanMoveCol(moveCol, curSplitCol);
1975 RefreshTop();
1976 //Refresh(oldMoveCol >= 0 ? hitems[oldMoveCol].nRight(sbx) : 0, 0, hitems[curSplitCol].nRight(sbx), fixed_height);
1977 oldMoveCol = curSplitCol;
1978 }
1979
1980 if(fixed_left_click && curSplitRow != oldMoveRow)
1981 {
1982 Refresh(0, 0, fixed_width, fixed_height);
1983 RefreshLeft();
1984 oldMoveRow = curSplitRow;
1985 }
1986 return;
1987 }
1988
1989 if(leftpnt != p && p.y < fixed_height)
1990 {
1991 UpdateHighlighting(GS_MOVE, p);
1992 }
1993
1994 if(live_cursor && popup.IsOpen())
1995 {
1996 LG(2, "MouseMove:LiveCursor");
1997 if(IsMouseBody(p))
1998 SetCursor0(p, CU_MOUSE | CU_HIGHLIGHT);
1999 else
2000 SetCursor0(-1, -1, CU_HIGHLIGHT);
2001 }
2002
2003 if(HasCapture())
2004 {
2005 if(!moving_body)
2006 {
2007 if(keyflags & K_SHIFT)
2008 {
2009 if(SetCursor0(p, CU_MOUSE))
2010 {
2011 DoShiftSelect();
2012 selecting = true;
2013 }
2014 return;
2015 }
2016
2017 bool select = true;
2018 if(select_row && !multi_select)
2019 select = false;
2020
2021 if(select && (keyflags & K_CTRL))
2022 {
2023 if(SetCursor0(p, CU_MOUSE))
2024 {
2025 DoCtrlSelect();
2026 selecting = true;
2027 }
2028 return;
2029 }
2030 }
2031
2032 if(moveCol < 0 || moveRow < 0)
2033 return;
2034
2035 if(!dragging)
2036 return;
2037
2038 if(!moving_body)
2039 {
2040 popup.Close();
2041
2042 if(!top_click && valid_cursor &&
2043 p.x < total_width &&
2044 p.y < total_height &&
2045 (abs(p.y - leftpnt.y) > 5 ||
2046 abs(p.x - leftpnt.x) > 5))
2047 moving_body = true;
2048
2049 oldMoveRow = -1;
2050 }
2051 else
2052 {
2053 Point pt = p + GetScreenRect().TopLeft();
2054
2055 int row = curSplitRow - fixed_rows + 2;
2056 if(select_row)
2057 {
2058 int count = max(1, selected_rows);
2059
2060 if(vitems[curpos.y].IsSelect())
2061 popup.val = Format(t_("Moving selection (%d %s) before row %d"), count, count == 1 ? t_("row") : t_("rows"), row);
2062 else
2063 popup.val = Format(t_("Moving row %d before row %d"), curpos.y - fixed_rows + 1, row);
2064 }
2065 else
2066 {
2067 int count = max(1, selected_items);
2068 popup.val = Format(t_("Moving %d %s before row %d"), count, count == 1 ? t_("cell") : t_("cells"), row);
2069 }
2070
2071 int px = pt.x + 15;
2072 int py = pt.y + GD_ROW_HEIGHT;
2073
2074 popup.gd = display;
2075 popup.gd->row = 0;
2076 popup.gd->col = 0;
2077 popup.fg = SColorText;
2078 popup.bg = SColorPaper;
2079 popup.fnt = StdFont();
2080 popup.style = 0;
2081 popup.PopUp(this, px, py, GetTextSize((String) popup.val, StdFont()).cx + 10, GD_ROW_HEIGHT);
2082 SetFocus();
2083
2084 if(curSplitRow != oldMoveRow || scrollLeftRight)
2085 {
2086 int dy = sby;
2087 if(oldMoveRow >= 0)
2088 Refresh(Rect(0, vitems[oldMoveRow].nBottom(dy) - 5, GetSize().cx, vitems[oldMoveRow].nBottom(dy) + 5));
2089 else
2090 Refresh(Rect(0, 0, GetSize().cx, 5));
2091 if(curSplitRow >= 0)
2092 Refresh(Rect(0, vitems[curSplitRow].nBottom(dy) - 5, GetSize().cx, vitems[curSplitRow].nBottom(dy) + 5));
2093 else
2094 Refresh(Rect(0, 0, GetSize().cx, 5));
2095
2096 oldMoveRow = curSplitRow;
2097 popup.Refresh();
2098
2099 scrollLeftRight = false;
2100 }
2101 }
2102 }
2103 else
2104 SyncPopup();
2105 }
2106
SyncPopup()2107 void GridCtrl::SyncPopup()
2108 {
2109 if(!IsPopUp() && popups)
2110 {
2111 Point p = GetMouseViewPos();
2112
2113 bool fc = p.x < fixed_width;
2114 bool fr = p.y < fixed_height;
2115
2116 int c = GetMouseCol(p, !fc, fc);
2117 int r = GetMouseRow(p, !fr, fr);
2118
2119 bool new_cell = false;
2120
2121 if(r != oldSplitRow)
2122 {
2123 oldSplitRow = r;
2124 new_cell = true;
2125 }
2126 if(c != oldSplitCol)
2127 {
2128 oldSplitCol = c;
2129 new_cell = true;
2130 }
2131
2132 bool valid_pos = c >= 0 && r >= 0;
2133
2134 Ctrl* ctrl = valid_pos ? GetCtrl(r, c, true, false, false, false) : NULL;
2135
2136 bool close = popup.IsOpen();
2137
2138 if(valid_pos && !ctrl)
2139 {
2140 Item& it = GetItem(r, c);
2141 ItemRect& hi = hitems[c];
2142 ItemRect& vi = vitems[r];
2143
2144 if(it.rcx > 0 || it.rcy > 0)
2145 {
2146 close = false;
2147
2148 Value val = GetStdConvertedValue(r == 0 ? it.val : GetItemValue(it, hi.id, hi, vi));
2149
2150 if(new_cell)
2151 {
2152 popup.fg = SColorText;
2153 popup.bg = SColorPaper;
2154 popup.fnt = StdFont();
2155 popup.style = 0;
2156 popup.val = val;
2157
2158 Point p0 = GetMousePos();
2159 int x = hi.npos + p0.x - p.x - 1 - sbx.Get() * int(!fc);
2160 int y = vi.npos + p0.y - p.y - 1 - sby.Get() * int(!fr);
2161
2162 GetItemAttrs(it, Null, r, c, vi, hi, popup.style, popup.gd, popup.fg, popup.bg, popup.fnt);
2163 popup.gd->row = r < fixed_rows ? -1 : r - fixed_rows;
2164 popup.gd->col = c < fixed_cols ? -1 : c - fixed_cols;
2165 Rect scr = GetWorkArea();
2166 int margin = popup.gd->lm + popup.gd->rm;
2167 int cx = min(600, min((int) (scr.right * 0.4), max(it.rcx + margin + 2, hi.nsize + 1)));
2168 int lines = popup.gd->GetLinesCount(cx - margin - 2, WString(val), popup.fnt, true);
2169 int cy = max(lines * Draw::GetStdFontCy() + popup.gd->tm + popup.gd->bm + 2, vi.nsize + 1);
2170 if(fr && r == 0)
2171 {
2172 y++;
2173 cy--;
2174 }
2175 popup.PopUp(this, x, y, cx, cy);
2176 if(!close)
2177 popup.Refresh();
2178 UpdateHighlighting(GS_BORDER, Point(0, 0));
2179 }
2180 else if(val != popup.val)
2181 {
2182 popup.val = val;
2183 popup.Refresh();
2184 }
2185 }
2186 }
2187
2188 if(close)
2189 {
2190 popup.Close();
2191 oldSplitCol = -1;
2192 oldSplitRow = -1;
2193 UpdateHighlighting(GS_BORDER, Point(0, 0));
2194 }
2195 }
2196 }
2197
LeftDown(Point p,dword keyflags)2198 void GridCtrl::LeftDown(Point p, dword keyflags)
2199 {
2200 //popup.Close();
2201 SetCapture();
2202 leftpnt = p;
2203 just_clicked = true;
2204 selecting = false;
2205
2206 fixed_top_click = p.x >= fixed_width && p.y < fixed_height;
2207 fixed_left_click = p.x < fixed_width && p.y >= fixed_height;
2208 fixed_click = fixed_top_click || fixed_left_click;
2209 top_click = p.y < fixed_height;
2210
2211 resizing = curResizeCol || curResizeRow;
2212
2213 if(resizing)
2214 {
2215 popup.Close();
2216
2217 splitCol = curSplitCol;
2218 splitRow = curSplitRow;
2219 resizeCol = curResizeCol;
2220 resizeRow = curResizeRow;
2221
2222 Split(GS_DOWN);
2223 return;
2224 }
2225 else if(fixed_click)
2226 {
2227 moveCol = oldMoveCol = GetMouseCol(p, fixed_top_click, 1);
2228 moveRow = oldMoveRow = GetMouseRow(p, fixed_left_click, 1);
2229 return;
2230 }
2231
2232 SetFocus();
2233
2234 if(IsEmpty() || IsReadOnly())
2235 return;
2236
2237 bool is_shift = keyflags & K_SHIFT;
2238 bool is_ctrl = keyflags & K_CTRL;
2239
2240 CurState cs = SetCursor0(p, CU_MOUSE | CU_HIDECTRLS);
2241 bool state_change = cs.IsValid() && !cs.IsNew() && (is_ctrl || is_shift);
2242
2243 if(!cs.IsAccepted() && !state_change)
2244 return;
2245
2246 if(cs || state_change)
2247 {
2248 moveCol = curpos.x;
2249 moveRow = curpos.y;
2250
2251 if(keyflags & K_CTRL)
2252 {
2253 bool select = true;
2254 if(!select_row)
2255 ClearSelection();
2256 else if(!multi_select)
2257 select = false;
2258
2259 if(select)
2260 {
2261 if(IsValidCursor(oldcur) && selected_items == 0 && cs.IsNew())
2262 {
2263 shiftpos = oldcur;
2264
2265 if(select_row)
2266 {
2267 SelectRange(oldcur, oldcur, true, true);
2268 SelectRange(curpos, curpos, true, true);
2269 }
2270 else
2271 {
2272 SelectRange(oldcur, curpos, true, false);
2273 }
2274 }
2275 else
2276 {
2277 shiftpos = curpos;
2278 bool rowsel = vitems[curpos.y].IsSelect();
2279 SelectRange(curpos, curpos, !rowsel, select_row);
2280 }
2281 selecting = true;
2282 }
2283 }
2284 else if(keyflags & K_SHIFT)
2285 {
2286 DoShiftSelect();
2287 selecting = true;
2288 }
2289 }
2290
2291 #ifdef LOG_CALLBACKS
2292 //LGR(2, "WhenLeftClick()");
2293 #endif
2294
2295 WhenLeftClick();
2296
2297 if(editing && one_click_edit && cs.IsValid() ) //&& IsRowEditable() ?
2298 StartEdit();
2299 else
2300 RebuildToolBar();
2301 }
2302
LeftUp(Point p,dword keyflags)2303 void GridCtrl::LeftUp(Point p, dword keyflags)
2304 {
2305 LG(0, "LeftUp");
2306
2307 ReleaseCapture();
2308 fixed_click = false;
2309
2310 UpdateHighlighting(resizing ? GS_MOVE : GS_UP, p);
2311
2312 if(moving_header)
2313 {
2314 LG(0, "moving_header");
2315 pophdr.Close();
2316
2317 moving_header = false;
2318 if(fixed_top_click)
2319 MoveCol(moveCol, curSplitCol);
2320 else
2321 MoveRow(moveRow, curSplitRow);
2322
2323 if(focused_ctrl)
2324 focused_ctrl->SetFocus();
2325
2326 fixed_top_click = false;
2327 fixed_left_click = false;
2328
2329 return;
2330 }
2331
2332 if(resizing)
2333 {
2334 Split(GS_UP);
2335 resizeCol = resizeRow = resizing = false;
2336 return;
2337 }
2338
2339 if(fixed_top_click && sorting && Distance(leftpnt, p) < 3)
2340 {
2341 int i = GetMouseRow(leftpnt, false, true);
2342 int j = GetMouseCol(leftpnt, true, false);
2343
2344 if(j >= fixed_cols && i == 0 && hitems[i].sortable)
2345 {
2346 int newSortCol = hitems[j].id;
2347
2348 if(sorting_multicol && (keyflags & K_CTRL))
2349 {
2350 int colidx = InMultisort(newSortCol);
2351
2352 if(colidx < 0)
2353 sortOrder.Add(newSortCol);
2354
2355 int cnt = sortOrder.GetCount();
2356
2357 hitems[j].ChangeSortMode(newSortCol == sortOrder[cnt - 1]);
2358
2359 if(colidx >= 0)
2360 {
2361 if(hitems[j].sortmode == 0)
2362 {
2363 sortOrder.Remove(colidx);
2364 cnt--;
2365 }
2366
2367 if(WhenSort)
2368 WhenSort();
2369 else
2370 {
2371 if(hitems[j].sortmode > 0 && colidx == cnt - 1)
2372 GSort();
2373 else
2374 Multisort();
2375 }
2376 }
2377 else
2378 {
2379 hitems[j].sortcol = cnt;
2380 if(WhenSort)
2381 WhenSort();
2382 else
2383 GSort();
2384 }
2385 }
2386 else
2387 {
2388 if(sortCol >= 0 && sortCol != newSortCol)
2389 {
2390 int idx = GetIdCol(sortCol, true);
2391 hitems[idx].sortmode = 0;
2392 }
2393
2394 ClearMultisort(1);
2395 hitems[j].ChangeSortMode();
2396 hitems[j].sortcol = 1;
2397
2398 if(hitems[j].sortmode == 0)
2399 sortCol = -1;
2400 else
2401 sortCol = newSortCol;
2402
2403 sortOrder.Add(newSortCol);
2404
2405 if(WhenSort)
2406 WhenSort();
2407 else
2408 GSort(newSortCol, hitems[j].sortmode, fixed_rows);
2409 }
2410
2411 UpdateCursor();
2412 Repaint(false, true);
2413
2414 if(WhenSorted)
2415 WhenSorted();
2416 }
2417 }
2418
2419 if(moving_body)
2420 {
2421 popup.Close();
2422 moving_body = false;
2423 MoveRows(curSplitRow + 1, !vitems[curpos.y].IsSelect());
2424 return;
2425 }
2426
2427 if(selected_rows > 0 && !selecting)
2428 ClearSelection();
2429 }
2430
LeftDouble(Point p,dword keyflags)2431 void GridCtrl::LeftDouble(Point p, dword keyflags)
2432 {
2433 LG(0, "LeftDouble");
2434
2435 if(full_col_resizing && curSplitCol >= 0)
2436 return;
2437
2438 if(full_row_resizing && curSplitRow >= 0)
2439 return;
2440
2441 if(IsEmpty() || !IsMouseBody(p) || IsReadOnly())
2442 return;
2443
2444 if(keyflags & K_SHIFT || keyflags & K_CTRL)
2445 return;
2446
2447 if(!valid_cursor)
2448 return;
2449
2450 if(editing)
2451 StartEdit();
2452
2453 if(!IsCtrl(curpos))
2454 {
2455 popup.Close();
2456 #ifdef LOG_CALLBACKS
2457 LGR(2, "WhenLeftDouble()");
2458 #endif
2459 WhenLeftDouble();
2460 }
2461 }
2462
LeftRepeat(Point p,dword keyflags)2463 void GridCtrl::LeftRepeat(Point p, dword keyflags)
2464 {
2465 if(!moving_header && !resizeCol && !resizeRow)
2466 MouseAccel(p, resize_col_mode == 0, resize_row_mode == 0, keyflags);
2467 }
2468
RightDown(Point p,dword keyflags)2469 void GridCtrl::RightDown(Point p, dword keyflags)
2470 {
2471 if(IsReadOnly())
2472 return;
2473
2474 if(total_rows > fixed_rows)
2475 {
2476 if(!EndEdit())
2477 return;
2478
2479 SetCursor0(p, CU_MOUSE);
2480 }
2481
2482 RebuildToolBar();
2483 SetFocus(); //jak nie bedzie menu to fokous zostanie na danym wierszu
2484 MenuBar::Execute(WhenMenuBar);
2485 }
2486
Init()2487 void GridCtrl::Init()
2488 {
2489 bar.Set(WhenToolBar);
2490 UpdateCols(true);
2491 /* recalc_rows bo przed otworzeniem grida moglo zostac wywolane setrowheight */
2492 UpdateRows(resize_row_mode > 0 || recalc_rows);
2493
2494 UpdateSizes();
2495 UpdateSb();
2496 UpdateHolder(true);
2497 SyncSummary();
2498 SyncCtrls();
2499 }
2500
State(int reason)2501 void GridCtrl::State(int reason)
2502 {
2503 if(reason == OPEN)
2504 {
2505 Init();
2506 ready = true;
2507 //ready po init - updatesb wola layout() a ten syncctrl
2508 //(ktory w sumie wola sie 3 razy zanim grid sie wyswietli - niepotrzebnie)
2509 }
2510 else if(reason == CLOSE)
2511 {
2512 if(live_cursor)
2513 SetCursor0(-1, -1, CU_HIGHLIGHT);
2514 }
2515 else if(reason == ENABLE)
2516 {
2517 bool e = IsEnabled();
2518 if(e != enabled)
2519 {
2520 RebuildToolBar();
2521 enabled = e;
2522 }
2523 }
2524 }
2525
Layout()2526 void GridCtrl::Layout()
2527 {
2528 if(!ready)
2529 return;
2530
2531 UpdateCols();
2532 UpdateRows();
2533 UpdateSizes();
2534 UpdateSb();
2535 UpdateHolder();
2536 UpdateCtrls(UC_CHECK_VIS | UC_SHOW);
2537 SyncCtrls();
2538 }
2539
ChildAction(Ctrl * child,int event)2540 void GridCtrl::ChildAction(Ctrl *child, int event)
2541 {
2542 if(child != &holder && child->IsShown())
2543 popup.Close();
2544
2545 if(child != focused_ctrl)
2546 {
2547 if(event == LEFTDOWN || event == RIGHTDOWN || event == MOUSEWHEEL)
2548 {
2549 //LG(2, "got event :%x child: %x", event, child);
2550 Point cp = GetCtrlPos(child);
2551 if(cp.x < 0 || cp.y < 0)
2552 return;
2553
2554 SetCursor0(cp);
2555 UpdateCtrls(UC_SHOW);
2556 WhenCtrlAction();
2557 }
2558 }
2559
2560 if(event == MOUSEMOVE)
2561 {
2562 if(live_cursor)
2563 {
2564 LG(2, "Child:LiveCursor");
2565 Point p = GetMouseViewPos();
2566 if(IsMouseBody(p))
2567 SetCursor0(p, CU_MOUSE | CU_HIGHLIGHT);
2568 else
2569 SetCursor0(-1, -1, CU_HIGHLIGHT);
2570 }
2571 }
2572
2573 }
2574
ChildMouseEvent(Ctrl * child,int event,Point p,int zdelta,dword keyflags)2575 void GridCtrl::ChildMouseEvent(Ctrl *child, int event, Point p, int zdelta, dword keyflags)
2576 {
2577 ChildAction(child, event);
2578 Ctrl::ChildMouseEvent(child, event, p, zdelta, keyflags);
2579 }
2580
ChildFrameMouseEvent(Ctrl * child,int event,Point p,int zdelta,dword keyflags)2581 void GridCtrl::ChildFrameMouseEvent(Ctrl *child, int event, Point p, int zdelta, dword keyflags)
2582 {
2583 ChildAction(child, event);
2584 Ctrl::ChildFrameMouseEvent(child, event, p, zdelta, keyflags);
2585 }
2586
DragAndDrop(Point p,PasteClip & d)2587 void GridCtrl::DragAndDrop(Point p, PasteClip& d)
2588 {
2589 /*
2590 moving_body = true;
2591 if(curSplitRow != oldMoveRow || scrollLeftRight)
2592 {
2593 int dy = sby;
2594 if(oldMoveRow >= 0)
2595 Refresh(Rect(0, vitems[oldMoveRow].nBottom(dy) - 5, GetSize().cx, vitems[oldMoveRow].nBottom(dy) + 5));
2596 else
2597 Refresh(Rect(0, 0, GetSize().cx, 5));
2598 if(curSplitRow >= 0)
2599 Refresh(Rect(0, vitems[curSplitRow].nBottom(dy) - 5, GetSize().cx, vitems[curSplitRow].nBottom(dy) + 5));
2600 else
2601 Refresh(Rect(0, 0, GetSize().cx, 5));
2602
2603 oldMoveRow = curSplitRow;
2604 popup.Refresh();
2605
2606 scrollLeftRight = false;
2607 }
2608 */
2609 }
2610
GetItemRect(int r,int c,bool hgrid,bool vgrid,bool hrel,bool vrel)2611 Rect GridCtrl::GetItemRect(int r, int c, bool hgrid, bool vgrid, bool hrel, bool vrel)
2612 {
2613 int dx = sbx + (hrel ? fixed_width : 0);
2614 int dy = sby + (vrel ? fixed_height : 0);
2615
2616 int idx = hitems[c].id;
2617 int idy = vitems[r].id;
2618
2619 Item &it = items[idy][idx];
2620
2621 int left, top, right, bottom;
2622
2623 if(it.isjoined)
2624 {
2625 int group = it.group;
2626
2627 while(r > fixed_rows && items[vitems[r].id][idx].group == group) --r;
2628 ++r;
2629
2630 top = vitems[r].nTop(dy);
2631 bottom = vitems[r + it.cy].nBottom(dy);
2632
2633 while(c > fixed_cols && items[idy][hitems[c].id].group == group) --c;
2634 ++c;
2635
2636 left = hitems[c].nLeft(dx);
2637 right = hitems[c + it.cx].nRight(dx);
2638 }
2639 else
2640 {
2641 left = hitems[c].nLeft(dx);
2642 top = vitems[r].nTop(dy);
2643 right = hitems[c].nRight(dx);
2644 bottom = vitems[r].nBottom(dy);
2645 }
2646
2647 return Rect(left, top, right - (int) vgrid, bottom - (int) hgrid);
2648 }
2649
AlignRect(Rect & r,int i)2650 Rect& GridCtrl::AlignRect(Rect &r, int i)
2651 {
2652 Rect c(r);
2653 int align = hitems[i].calign;
2654 int sx = hitems[i].sx;
2655 int sy = hitems[i].sy;
2656
2657 if(sx > 0)
2658 {
2659 if(align & GD::HCENTER)
2660 {
2661 int d = (r.Width() - sx - 1) / 2;
2662 r.left += d;
2663 r.right -= d;
2664 }
2665 else if(align & GD::LEFT)
2666 {
2667 r.left += hitems[i].sl;
2668 r.right = r.left + sx;
2669 }
2670 else if(align & GD::RIGHT)
2671 {
2672 r.right -= hitems[i].sr;
2673 r.left = r.right - sx;
2674 }
2675 else if(align & GD::HPOS)
2676 {
2677 r.left += hitems[i].sl;
2678 r.right -= hitems[i].sr;
2679 }
2680 }
2681
2682 if(sy > 0)
2683 {
2684 if(align & GD::VCENTER)
2685 {
2686 int d = (r.Height() - sy - 1) / 2;
2687 r.top += d;
2688 r.bottom -= d;
2689 }
2690 else if(align & GD::TOP)
2691 {
2692 r.top += hitems[i].st;
2693 r.bottom = r.top + sy;
2694 }
2695 else if(align & GD::RIGHT)
2696 {
2697 r.bottom -= hitems[i].sb;
2698 r.top = r.bottom - sy;
2699 }
2700 else if(align & GD::VPOS)
2701 {
2702 r.top += hitems[i].st;
2703 r.bottom -= hitems[i].sb;
2704 }
2705 }
2706
2707 if(r.left < c.left) r.left = c.left;
2708 if(r.right > c.right) r.right = c.right;
2709 if(r.top < c.top) r.top = c.top;
2710 if(r.bottom > c.bottom) r.bottom = c.bottom;
2711
2712 return r;
2713 }
2714
2715
Scroll()2716 void GridCtrl::Scroll()
2717 {
2718 Point newpos(sbx, sby);
2719 Size delta = oldpos - newpos;
2720 oldpos = newpos;
2721
2722 if(delta.cx != 0) firstCol = -1;
2723 if(delta.cy != 0) firstRow = -1;
2724
2725 if(!doscroll)
2726 return;
2727
2728 LG(0, "Scroll (%d, %d)", delta.cx, delta.cy);
2729
2730 SyncCtrls();
2731 UpdateCtrls(UC_CHECK_VIS | UC_SHOW | UC_SCROLL);
2732
2733 if(resizeCol || resizeRow)
2734 return;
2735
2736 if(!IsFullRefresh())
2737 {
2738 Size sz = GetSize();
2739 holder.ScrollView(delta);
2740 if(delta.cx != 0)
2741 {
2742 ScrollView(Rect(fixed_width, 0, sz.cx, fixed_height), delta.cx, 0);
2743 ScrollView(Rect(fixed_width, sz.cy - summary_height, sz.cx, sz.cy), delta.cx, 0);
2744 scrollLeftRight = true;
2745 }
2746 if(delta.cy != 0)
2747 {
2748 ScrollView(Rect(0, fixed_height, fixed_width, sz.cy - summary_height), 0, delta.cy);
2749 }
2750 }
2751
2752 if(live_cursor)
2753 SetCursor0(GetMousePos() - GetScreenRect().TopLeft(), CU_MOUSE | CU_HIGHLIGHT);
2754
2755 SyncPopup();
2756 }
2757
SetFixedRows(int n)2758 void GridCtrl::SetFixedRows(int n)
2759 {
2760 if(n >= 0 && n <= total_rows)
2761 {
2762 LG(0, "SetFixedRows");
2763 fixed_rows = n;
2764 firstRow = -1;
2765 UpdateSizes();
2766 UpdateHolder();
2767 UpdateVisColRow(false);
2768 if(ready)
2769 SyncCtrls();
2770 Refresh();
2771 }
2772 }
2773
SetFixedCols(int n)2774 void GridCtrl::SetFixedCols(int n)
2775 {
2776 if(n >= 0 && n < total_cols)
2777 {
2778 LG(0, "SetFixedCols");
2779 fixed_cols = n + 1; /* +1 - indicator! */
2780 firstCol = -1;
2781 UpdateSizes();
2782 UpdateHolder();
2783 UpdateVisColRow(true);
2784 if(ready)
2785 SyncCtrls();
2786 Refresh();
2787 }
2788 }
2789
Set0(int r,int c,const Value & val_,bool paste)2790 void GridCtrl::Set0(int r, int c, const Value &val_, bool paste)
2791 {
2792 Value val = val_;
2793 if(c > total_cols - 1)
2794 return;
2795 if(r > total_rows - 1)
2796 AddRow(r - total_rows + 1);
2797
2798 vitems[r].operation = GridOperation::UPDATE;
2799
2800 int ri = vitems[r].id;
2801 Item &it = items[ri][c];
2802
2803 if(it.isjoined) {
2804 ri = it.idy;
2805 c = it.idx;
2806 }
2807
2808 Ctrl *ctrl = items[ri][c].ctrl;
2809 bool setctrl = true;
2810 if(!ctrl) {
2811 ctrl = edits[c].ctrl;
2812 setctrl = ctrlid.y == ri;
2813 }
2814
2815 if(ctrl) {
2816 if(paste && IsString(val)) {
2817 Convert *cv = dynamic_cast<Convert *>(ctrl);
2818 if(cv)
2819 val = cv->Scan(val);
2820 }
2821 if(setctrl)
2822 ctrl->SetData(val);
2823 }
2824
2825 items[ri][c].val = val;
2826 RefreshItem(r, c, false);
2827
2828 if(paste)
2829 WhenUpdateCell();
2830
2831 SyncSummary();
2832 }
2833
Set(int r,int c,const Value & val)2834 void GridCtrl::Set(int r, int c, const Value &val)
2835 {
2836 Set0(r + fixed_rows, c + fixed_cols, val);
2837 }
2838
Set(int r,Id id,const Value & val)2839 void GridCtrl::Set(int r, Id id, const Value &val)
2840 {
2841 Set0(r + fixed_rows, aliases.Get(id), val);
2842 }
2843
Set(int r,const char * s,const Value & val)2844 void GridCtrl::Set(int r, const char *s, const Value &val)
2845 {
2846 Set0(r + fixed_rows, aliases.Get(s), val);
2847 }
2848
Set(int c,const Value & val)2849 void GridCtrl::Set(int c, const Value &val)
2850 {
2851 Set0(rowidx, c + fixed_cols, val);
2852 }
2853
Set(Id id,const Value & val)2854 void GridCtrl::Set(Id id, const Value &val)
2855 {
2856 Set0(rowidx, aliases.Get(id), val);
2857 }
2858
Set(int r,const Vector<Value> & v,int data_offset,int column_offset)2859 void GridCtrl::Set(int r, const Vector<Value> &v, int data_offset /* = 0*/, int column_offset /* = 0*/)
2860 {
2861 r += fixed_rows;
2862 vitems[r].operation = GridOperation::UPDATE;
2863 int cnt = min(v.GetCount(), total_cols - fixed_cols);
2864 int r0 = vitems[r].id;
2865 int c = fixed_cols + column_offset;
2866 for(int i = data_offset; i < cnt; i++)
2867 items[r0][c++].val = v[i];
2868
2869 RefreshRow(r, false, 0);
2870 }
2871
Set(const Vector<Value> & v,int data_offset,int column_offset)2872 void GridCtrl::Set(const Vector<Value> &v, int data_offset /* = 0*/, int column_offset /* = 0*/)
2873 {
2874 int r = rowidx - fixed_rows;
2875 Set(r, v, data_offset, column_offset);
2876 }
2877
SetAny(int r,int c,const Value & val)2878 void GridCtrl::SetAny(int r, int c, const Value &val)
2879 {
2880 Set0(r, c, val);
2881 }
2882
SetRaw(int r,int c,const Value & val)2883 void GridCtrl::SetRaw(int r, int c, const Value &val)
2884 {
2885 items[r][c].val = val;
2886 }
2887
SetIndicator(int r,const Value & val)2888 void GridCtrl::SetIndicator(int r, const Value &val)
2889 {
2890 Set0(r, 0, val);
2891 }
2892
SetCtrl(int r,int c,Ctrl & ctrl)2893 void GridCtrl::SetCtrl(int r, int c, Ctrl& ctrl)
2894 {
2895 r += fixed_rows;
2896 c += fixed_cols;
2897 GetItem(r, c).SetCtrl(ctrl, false);
2898 ++genr_ctrls;
2899 if(ready)
2900 SyncCtrls(r, c);
2901 }
2902
SetCtrl(int r,int c,Ctrl * ctrl)2903 void GridCtrl::SetCtrl(int r, int c, Ctrl* ctrl)
2904 {
2905 r += fixed_rows;
2906 c += fixed_cols;
2907 GetItem(r, c).SetCtrl(*ctrl, true);
2908 ++genr_ctrls;
2909 if(ready)
2910 SyncCtrls(r, c);
2911 }
2912
SetCtrl(int c,Ctrl & ctrl)2913 void GridCtrl::SetCtrl(int c, Ctrl& ctrl)
2914 {
2915 c += fixed_cols;
2916 GetItem(rowidx, c).SetCtrl(ctrl, false);
2917 ++genr_ctrls;
2918 if(ready)
2919 SyncCtrls(rowidx, c);
2920 }
2921
SetCtrl(int c,Ctrl * ctrl)2922 void GridCtrl::SetCtrl(int c, Ctrl* ctrl)
2923 {
2924 c += fixed_cols;
2925 GetItem(rowidx, c).SetCtrl(*ctrl, true);
2926 ++genr_ctrls;
2927 if(ready)
2928 SyncCtrls(rowidx, c);
2929 }
2930
ClearCtrl(int r,int c)2931 void GridCtrl::ClearCtrl(int r, int c)
2932 {
2933 GridCtrl::Item& item = GetItem(r + fixed_rows, c + fixed_cols);
2934 if(item.ctrl)
2935 {
2936 item.ClearCtrl();
2937 --genr_ctrls;
2938 }
2939 }
2940
SetCtrlValue(int r,int c,const Value & val)2941 void GridCtrl::SetCtrlValue(int r, int c, const Value &val)
2942 {
2943 c += fixed_cols;
2944 int ri = vitems[r].id;
2945 Ctrl * ctrl = items[ri][c].ctrl;
2946 if(ctrl)
2947 ctrl->SetData(val);
2948 else
2949 {
2950 ctrl = edits[c].ctrl;
2951 if(ctrl && ctrlid.y == ri)
2952 ctrl->SetData(val);
2953 }
2954 }
2955
SetCtrlValue(int c,const Value & val)2956 void GridCtrl::SetCtrlValue(int c, const Value &val)
2957 {
2958 SetCtrlValue(rowidx, c, val);
2959 }
2960
SetLast(int c,const Value & val)2961 void GridCtrl::SetLast(int c, const Value &val)
2962 {
2963 c += fixed_cols;
2964 items[vitems[rowidx].id][c].val = val;
2965 RefreshItem(rowidx, c, false);
2966 }
2967
SetFixed(int r,int c,const Value & val)2968 void GridCtrl::SetFixed(int r, int c, const Value &val)
2969 {
2970 items[r][c + 1].val = val;
2971 Refresh();
2972 }
2973
GetFixed(int r,int c) const2974 Value GridCtrl::GetFixed(int r, int c) const
2975 {
2976 return items[vitems[r].id][c + fixed_cols].val;
2977 }
2978
GetFixed(int c) const2979 Value GridCtrl::GetFixed(int c) const
2980 {
2981 return items[0][c + fixed_cols].val;
2982 }
2983
Get0(int r,int c) const2984 Value GridCtrl::Get0(int r, int c) const
2985 {
2986 r = vitems[r].id;
2987 const Item &it = items[r][c];
2988 if(it.isjoined)
2989 {
2990 r = it.idy;
2991 c = it.idx;
2992 }
2993
2994 Ctrl * ctrl = items[r][c].ctrl;
2995
2996 if(!ctrl && ctrlid.y == r)
2997 ctrl = edits[c].ctrl;
2998
2999 return ctrl ? ctrl->GetData() : items[r][c].val;
3000 }
3001
Get(int r,int c) const3002 Value GridCtrl::Get(int r, int c) const
3003 {
3004 return Get0(r + fixed_rows, c + fixed_cols);
3005 }
3006
Get(int c) const3007 Value GridCtrl::Get(int c) const
3008 {
3009 return Get0(rowidx, c + fixed_cols);
3010 }
3011
Get(Id id) const3012 Value GridCtrl::Get(Id id) const
3013 {
3014 return Get0(rowidx, aliases.Get(id));
3015 }
3016
Get(int r,Id id) const3017 Value GridCtrl::Get(int r, Id id) const
3018 {
3019 return Get0(r + fixed_rows, aliases.Get(id));
3020 }
3021
Get() const3022 Value GridCtrl::Get() const
3023 {
3024 return Get0(curpos.y, curpos.x);
3025 }
3026
Get(const char * alias) const3027 Value GridCtrl::Get(const char * alias) const
3028 {
3029 return Get0(rowidx, aliases.Get(alias));
3030 }
3031
Get(int r,const char * alias) const3032 Value GridCtrl::Get(int r, const char * alias) const
3033 {
3034 return Get0(r + fixed_rows, aliases.Get(alias));
3035 }
3036
GetRaw(int r,int c) const3037 Value GridCtrl::GetRaw(int r, int c) const
3038 {
3039 return items[r][c].val;
3040 }
3041
GetFirst(int c) const3042 Value GridCtrl::GetFirst(int c) const
3043 {
3044 return Get0(fixed_rows, c + fixed_cols);
3045 }
3046
GetLast(int c) const3047 Value GridCtrl::GetLast(int c) const
3048 {
3049 return Get0(total_rows - 1, c + fixed_cols);
3050 }
3051
GetPrev(Id id) const3052 Value GridCtrl::GetPrev(Id id) const
3053 {
3054 return rowbkp[aliases.Get(id)];
3055 }
3056
GetPrev(int c) const3057 Value GridCtrl::GetPrev(int c) const
3058 {
3059 return rowbkp[c + fixed_cols];
3060 }
3061
GetNew(int c) const3062 Value GridCtrl::GetNew(int c) const
3063 {
3064 return Get0(rowidx, c + fixed_cols);
3065 }
3066
operator ()(int r,int c)3067 Value& GridCtrl::operator() (int r, int c)
3068 {
3069 return items[vitems[r + fixed_rows].id][c + fixed_cols].val;
3070 }
3071
operator ()(int c)3072 Value& GridCtrl::operator() (int c)
3073 {
3074 return items[vitems[rowidx].id][c + fixed_cols].val;
3075 }
3076
operator ()(Id id)3077 Value& GridCtrl::operator() (Id id)
3078 {
3079 return items[vitems[rowidx].id][aliases.Get(id)].val;
3080 }
3081
operator ()(int r,Id id)3082 Value& GridCtrl::operator() (int r, Id id)
3083 {
3084 return items[vitems[r + fixed_rows].id][aliases.Get(id)].val;
3085 }
3086
operator ()(const char * alias)3087 Value& GridCtrl::operator() (const char * alias)
3088 {
3089 return items[vitems[rowidx].id][aliases.Get(alias)].val;
3090 }
3091
operator ()(int r,const char * alias)3092 Value& GridCtrl::operator() (int r, const char * alias)
3093 {
3094 return items[vitems[r + fixed_rows].id][aliases.Get(alias)].val;
3095 }
3096
SetSummary(int c,const Value & val)3097 void GridCtrl::SetSummary(int c, const Value& val)
3098 {
3099 summary[c].val = val;
3100 RefreshSummary();
3101 }
3102
SetSummary(Id id,const Value & val)3103 void GridCtrl::SetSummary(Id id, const Value& val)
3104 {
3105 summary[aliases.Get(id)].val = val;
3106 RefreshSummary();
3107 }
3108
GetSummary(int c)3109 Value GridCtrl::GetSummary(int c)
3110 {
3111 return summary[c + fixed_cols].val;
3112 }
3113
GetSummary(Id id)3114 Value GridCtrl::GetSummary(Id id)
3115 {
3116 return summary[aliases.Get(id)].val;
3117 }
3118
IsModified(int r,int c)3119 bool GridCtrl::IsModified(int r, int c)
3120 {
3121 return items[vitems[r + fixed_rows].id][c + fixed_cols].modified;
3122 }
3123
IsModified(int c)3124 bool GridCtrl::IsModified(int c)
3125 {
3126 return items[vitems[rowidx].id][c + fixed_cols].modified;
3127 }
3128
IsModified(int r,Id id)3129 bool GridCtrl::IsModified(int r, Id id)
3130 {
3131 return items[vitems[r + fixed_rows].id][aliases.Get(id)].modified;
3132 }
3133
IsModified(Id id)3134 bool GridCtrl::IsModified(Id id)
3135 {
3136 return items[vitems[rowidx].id][aliases.Get(id)].modified;
3137 }
3138
ReadCol(int n,int start_row,int end_row) const3139 Vector<Value> GridCtrl::ReadCol(int n, int start_row, int end_row) const
3140 {
3141 Vector<Value> v;
3142 int idx = hitems[n < 0 ? colidx : n + fixed_cols].id;
3143
3144 if(start_row < 0)
3145 start_row = fixed_rows;
3146 else
3147 start_row += fixed_rows;
3148
3149 if(end_row < 0)
3150 end_row = total_rows - 1;
3151 else
3152 end_row += fixed_rows;
3153
3154 for(int i = start_row; i <= end_row; i++)
3155 v.Add(items[i][idx].val);
3156
3157 return v;
3158 }
3159
ReadRow(int n,int start_col,int end_col) const3160 Vector<Value> GridCtrl::ReadRow(int n, int start_col, int end_col) const
3161 {
3162 Vector<Value> v;
3163 int idy = vitems[n < 0 ? rowidx : n + fixed_rows].id;
3164
3165 if(start_col < 0)
3166 start_col = fixed_cols;
3167 else
3168 start_col += fixed_cols;
3169
3170 if(end_col < 0)
3171 end_col = total_cols - 1;
3172 else
3173 end_col += fixed_cols;
3174
3175 for(int i = start_col; i <= end_col; i++)
3176 v.Add(items[idy][i].val);
3177
3178 return v;
3179 }
3180
GetValues()3181 Vector< Vector<Value> > GridCtrl::GetValues()
3182 {
3183 Vector< Vector<Value> > v;
3184
3185 int rows_cnt = total_rows - fixed_rows;
3186 int cols_cnt = total_cols - fixed_cols;
3187
3188 v.SetCount(rows_cnt);
3189
3190 for(int i = 0; i < rows_cnt; i++)
3191 {
3192 v[i].SetCount(cols_cnt);
3193
3194 for(int j = 0; j < cols_cnt; j++)
3195 {
3196 const Value &val = items[i + fixed_rows][j + fixed_cols].val;
3197 if(IsType<AttrText>(val))
3198 {
3199 const AttrText& t = ValueTo<AttrText>(val);
3200 v[i][j] = t.text;
3201 }
3202 else
3203 v[i][j] = val;
3204 }
3205 }
3206
3207 return v;
3208 }
3209
SetValues(const Vector<Vector<Value>> & v)3210 void GridCtrl::SetValues(const Vector< Vector<Value> >& v)
3211 {
3212 int rows_cnt = v.GetCount();
3213
3214 if(rows_cnt <= 0)
3215 return;
3216
3217 int cols_cnt = v[0].GetCount();
3218
3219 int tc = total_cols - fixed_cols;
3220 if(cols_cnt > tc)
3221 cols_cnt = tc;
3222
3223 SetRowCount(rows_cnt);
3224
3225 for(int i = 0; i < rows_cnt; i++)
3226 for(int j = 0; j < cols_cnt; j++)
3227 {
3228 int r = i + fixed_rows;
3229 int c = j + fixed_cols;
3230 Ctrl * ctrl = items[r][c].ctrl;
3231 if(ctrl)
3232 ctrl->SetData(v[i][j]);
3233 items[r][c].val = v[i][j];
3234 }
3235
3236 SyncCtrls();
3237 SyncSummary();
3238 Refresh();
3239 }
3240
Add(const Vector<Value> & v,int offset,int count,bool hidden)3241 GridCtrl& GridCtrl::Add(const Vector<Value> &v, int offset, int count, bool hidden)
3242 {
3243 Append0(1, hidden ? 0 : GD_ROW_HEIGHT);
3244
3245 int cnt = min(count < 0 ? v.GetCount() : count,
3246 total_cols - fixed_cols);
3247
3248 int r0 = total_rows - 1;
3249 int r = vitems[r0].id;
3250 for(int i = offset; i < cnt; i++)
3251 items[r][i + fixed_cols].val = v[i];
3252
3253 RefreshRow(r0, 0, 0);
3254
3255 return *this;
3256 }
3257
IsColumn(const Id & id)3258 bool GridCtrl::IsColumn(const Id& id)
3259 {
3260 return valid_cursor ? hitems[curpos.x].id == aliases.Get(id) : false;
3261 }
3262
GetColumn(int n)3263 GridCtrl::ItemRect& GridCtrl::GetColumn(int n)
3264 {
3265 return hitems[GetIdCol(n + fixed_cols)];
3266 }
3267
GetColumn()3268 GridCtrl::ItemRect& GridCtrl::GetColumn()
3269 {
3270 return hitems[curpos.x];
3271 }
3272
GetRow(int n)3273 GridCtrl::ItemRect& GridCtrl::GetRow(int n)
3274 {
3275 return vitems[n + fixed_rows];
3276 }
3277
GetRow()3278 GridCtrl::ItemRect& GridCtrl::GetRow()
3279 {
3280 return vitems[rowidx];
3281 }
3282
GetCurrentRow() const3283 int GridCtrl::GetCurrentRow() const
3284 {
3285 return rowidx - fixed_rows;
3286 }
3287
IsCurrentRow() const3288 bool GridCtrl::IsCurrentRow() const
3289 {
3290 return rowidx == curpos.y;
3291 }
3292
RestoreCurrentRow()3293 void GridCtrl::RestoreCurrentRow()
3294 {
3295 rowidx = curpos.y;
3296 }
3297
GetCell(int n,int m)3298 GridCtrl::Item& GridCtrl::GetCell(int n, int m)
3299 {
3300 return items[vitems[n + fixed_rows].id][hitems[m + fixed_cols].id];
3301 }
3302
GetCell(int n,Id id)3303 GridCtrl::Item& GridCtrl::GetCell(int n, Id id)
3304 {
3305 return items[vitems[n + fixed_rows].id][hitems[aliases.Get(id)].id];
3306 }
3307
GetMouseCol(Point & p,bool relative,bool fixed,bool full)3308 int GridCtrl::GetMouseCol(Point &p, bool relative, bool fixed, bool full)
3309 {
3310 if(!full && p.x < fixed_width)
3311 return -1;
3312
3313 int dx = 0;
3314
3315 if(relative)
3316 dx += sbx;
3317
3318 int first_col = fixed ? 0 : max(firstVisCol, fixed_cols);
3319 int last_col = max(lastVisCol, fixed_cols - 1);
3320
3321 if(!fixed && last_col >= total_cols)
3322 return -1;
3323
3324 for(int i = first_col; i <= last_col; i++)
3325 {
3326 if(p.x >= hitems[i].nLeft(dx) &&
3327 p.x < hitems[i].nRight(dx))
3328 return i;
3329 }
3330 return -1;
3331 }
3332
GetMouseRow(Point & p,bool relative,bool fixed,bool full)3333 int GridCtrl::GetMouseRow(Point &p, bool relative, bool fixed, bool full)
3334 {
3335 if(!full && p.y < fixed_height)
3336 return -1;
3337
3338 int dy = 0;
3339
3340 if(relative)
3341 dy += sby;
3342
3343 int first_row = fixed ? 0 : max(firstVisRow, fixed_rows);
3344 int last_row = max(lastVisRow, fixed_rows - 1);
3345
3346 if(!fixed && last_row >= total_rows)
3347 return -1;
3348
3349 for(int i = first_row; i <= last_row; i++)
3350 {
3351 if(p.y >= vitems[i].nTop(dy) &&
3352 p.y < vitems[i].nBottom(dy))
3353 return i;
3354 }
3355 return -1;
3356 }
3357
MouseAccel(const Point & p,bool horz,bool vert,dword keyflags)3358 void GridCtrl::MouseAccel(const Point &p, bool horz, bool vert, dword keyflags)
3359 {
3360 Size sz = GetSize();
3361 int speedx = 0, speedy = 0;
3362 const int bound = 5;
3363
3364 if(horz)
3365 {
3366 if(p.x > sz.cx - bound)
3367 speedx = p.x - (sz.cx - bound);
3368 else if(p.x < fixed_width + bound)
3369 speedx = -(bound - p.x + fixed_width);
3370 }
3371
3372 if(vert)
3373 {
3374 if(p.y > sz.cy - bound)
3375 speedy = p.y - (sz.cy - bound);
3376 else if(p.y < fixed_height + bound)
3377 speedy = -(bound - p.y + fixed_height);
3378 }
3379
3380 if(speedx) sbx.Set(sbx + speedx);
3381 if(speedy) sby.Set(sby + speedy);
3382
3383 if(speedx || speedy)
3384 {
3385 LG(0, "speedx %d, speedy %d", speedx, speedy);
3386 MouseMove(p, keyflags);
3387 }
3388
3389 }
3390
HorzPosImage()3391 Image GridCtrl::HorzPosImage()
3392 {
3393 #ifdef PLATFORM_X11
3394 return Image::SizeHorz();
3395 #else
3396 return GridImg::HorzPos();
3397 #endif
3398 }
3399
VertPosImage()3400 Image GridCtrl::VertPosImage()
3401 {
3402 #ifdef PLATFORM_X11
3403 return Image::SizeVert();
3404 #else
3405 return GridImg::VertPos();
3406 #endif
3407 }
3408
CursorImage(Point p,dword keyflags)3409 Image GridCtrl::CursorImage(Point p, dword keyflags)
3410 {
3411 if(!moving_header && !moving_body && HasCapture())
3412 {
3413 if(resizing_cols && curSplitCol >= 0)
3414 return HorzPosImage();
3415 if(resizing_rows && curSplitRow >= 0)
3416 return VertPosImage();
3417 else
3418 return Image::Arrow();
3419 }
3420
3421 if(moving_header)
3422 {
3423 curSplitCol = GetSplitCol(p, -1);
3424 curSplitRow = GetSplitRow(p, -1);
3425
3426 if(resize_col_mode == 0 || resize_row_mode == 0)
3427 MouseAccel(p, fixed_top_click, fixed_left_click, keyflags);
3428
3429 return Image::Arrow();
3430 }
3431 else if(moving_body)
3432 {
3433 curSplitRow = GetSplitRow(Point(0, p.y), -1);
3434 return Image::Arrow();
3435 }
3436 else if(mouse_move)
3437 {
3438 curSplitCol = GetSplitCol(p);
3439 curSplitRow = GetSplitRow(p);
3440 mouse_move = false;
3441 }
3442
3443 curResizeCol = curResizeRow = false;
3444
3445 if(resizing_cols && curSplitCol >= 0 || resizeCol)
3446 {
3447 if(curSplitCol >= 0 && hitems[curSplitCol].join > 0)
3448 {
3449 int idy = GetMouseRow(p, true, p.y < fixed_height, true);
3450 if(idy >= 0)
3451 {
3452 Item &it = items[vitems[idy].id][hitems[curSplitCol].id];
3453 if(it.isjoined && it.idx + it.cx != curSplitCol)
3454 return Image::Arrow();
3455 }
3456 }
3457 curResizeCol = true;
3458 return HorzPosImage();
3459 }
3460 else if(resizing_rows && curSplitRow >= 0 || resizeRow)
3461 {
3462 if(curSplitRow >= 0 && vitems[curSplitRow].join > 0)
3463 {
3464 int idx = GetMouseCol(p, true, p.x < fixed_width, true);
3465 if(idx >= 0)
3466 {
3467 Item &it = items[vitems[curSplitRow].id][hitems[idx].id];
3468 if(it.isjoined && it.idy + it.cy != curSplitRow)
3469 return Image::Arrow();
3470 }
3471 }
3472 curResizeRow = true;
3473 return VertPosImage();
3474 }
3475 return Image::Arrow();
3476 }
3477
3478
UpdateHolder(bool force)3479 void GridCtrl::UpdateHolder(bool force)
3480 {
3481 if(size_changed || force)
3482 {
3483 holder.SetOffset(Point(fixed_width, fixed_height));
3484 holder.HSizePos(fixed_width, 0).VSizePos(fixed_height, summary_height);
3485 size_changed = false;
3486 }
3487 }
3488
SetCursor0(int x,int y,int opt,int dirx,int diry)3489 GridCtrl::CurState GridCtrl::SetCursor0(int x, int y, int opt, int dirx, int diry)
3490 {
3491 return SetCursor0(Point(x, y), opt, dirx, diry);
3492 }
3493
SetCursor0(Point p,int opt,int dirx,int diry)3494 GridCtrl::CurState GridCtrl::SetCursor0(Point p, int opt, int dirx, int diry)
3495 {
3496 CurState cs;
3497 if(!row_changing)
3498 {
3499 cs.valid = false;
3500 return cs;
3501 }
3502
3503 bool mouse = opt & CU_MOUSE;
3504 bool highlight = opt & CU_HIGHLIGHT;
3505 bool ctrlmode = opt & CU_CTRLMODE;
3506 bool hidectrls = opt & CU_HIDECTRLS;
3507
3508 Point tmpcur;
3509
3510 bool mouse_valid = true;
3511
3512 if(mouse)
3513 {
3514 tmpcur.x = GetMouseCol(p, true, false);
3515 tmpcur.y = GetMouseRow(p, true, false);
3516 if(tmpcur.x < 0 || tmpcur.y < 0)
3517 mouse_valid = false;
3518 }
3519 else
3520 tmpcur = p;
3521
3522 if(!highlight && dirx == 0 && diry == 0 && !IsValidCursor(tmpcur))
3523 {
3524 cs.valid = false;
3525 return cs;
3526 }
3527
3528 Point oldcur = highlight ? livecur : curpos;
3529
3530 bool oldvalid = IsValidCursorAll(oldcur);
3531 bool newvalid = false;
3532 Item *nit = NULL;
3533
3534 if(!highlight && mouse_valid)
3535 {
3536 bool quit = false;
3537
3538 int fc = max(fixed_cols, firstVisCol);
3539 int lc = lastVisCol;
3540 int fr = max(fixed_rows, firstVisRow);
3541 int lr = lastVisRow;
3542
3543 Item *oit = oldvalid ? &GetItem(oldcur) : NULL;
3544
3545 while(true)
3546 {
3547 bool cur = IsValidCursor(tmpcur, fc, lc, fr, lr);
3548
3549 bool hidden = true;
3550 bool clickable = true;
3551 bool group = true;
3552
3553 if(cur)
3554 {
3555 ItemRect& h = hitems[tmpcur.x];
3556 ItemRect& v = vitems[tmpcur.y];
3557 bool hx = dirx != 0 ? h.hidden : false;
3558 bool hy = diry != 0 ? v.hidden : false;
3559 hidden = hx || hy;
3560 clickable = h.clickable && v.clickable;
3561 if(oit && oit->group >= 0 && !select_row)
3562 {
3563 nit = &GetItem(tmpcur);
3564 group = nit->group != oit->group;
3565 }
3566 }
3567
3568 newvalid = cur && !hidden && clickable && group;
3569
3570 if(newvalid)
3571 {
3572 int idx = hitems[tmpcur.x].id;
3573 int idy = vitems[tmpcur.y].id;
3574
3575 Item &it = items[idy][idx];
3576
3577 newvalid = it.clickable;
3578
3579 if(newvalid && ctrlmode)
3580 {
3581 Ctrl * ctrl = it.ctrl;
3582 if(!ctrl && isedit)
3583 ctrl = edits[idx].ctrl;
3584
3585 if(ctrl && it.editable && ctrl->IsEnabled())
3586 break;
3587 }
3588 }
3589
3590 if(newvalid && !ctrlmode)
3591 break;
3592
3593 if(quit || (dirx == 0 && diry == 0))
3594 return cs;
3595
3596 if(dirx != 0)
3597 {
3598 tmpcur.x += dirx;
3599
3600 if(tmpcur.x > lc)
3601 {
3602 if(tab_changes_row && diry == 0)
3603 {
3604 tmpcur.y += 1;
3605 if(tmpcur.y > lr)
3606 {
3607 tmpcur.y = lr;
3608 tmpcur.x = lc;
3609 quit = true;
3610 }
3611 else
3612 tmpcur.x = fc;
3613 }
3614 else
3615 quit = true;
3616 }
3617 else if(tmpcur.x < fc)
3618 {
3619 if(tab_changes_row && diry == 0)
3620 {
3621 tmpcur.y -= 1;
3622 if(tmpcur.y < fr)
3623 {
3624 tmpcur.y = fr;
3625 tmpcur.x = fc;
3626 quit = true;
3627 }
3628 else
3629 tmpcur.x = lc;
3630 }
3631 else
3632 quit = true;
3633 }
3634 continue;
3635 }
3636
3637 if(diry != 0)
3638 {
3639 tmpcur.y += diry;
3640
3641 if(tmpcur.y < fr)
3642 {
3643 tmpcur.y = fr;
3644 quit = true;
3645 }
3646 else if(tmpcur.y > lr)
3647 {
3648 tmpcur.y = lr;
3649 quit = true;
3650 }
3651 }
3652 }
3653 }
3654 else
3655 {
3656 newvalid = IsValidCursor(tmpcur);
3657 if(newvalid && highlight)
3658 {
3659 if(!vitems[tmpcur.y].clickable || !hitems[tmpcur.x].clickable)
3660 newvalid = false;
3661 }
3662 }
3663
3664 bool isnewcol = oldcur.x != tmpcur.x;
3665 bool isnewrow = oldcur.y != tmpcur.y;
3666
3667 if(isnewcol || isnewrow)
3668 this->oldcur = oldcur;
3669
3670 cs.valid = newvalid;
3671
3672 if(!highlight)
3673 {
3674 if(!GetCtrlsData(!isnewrow))
3675 {
3676 cs.accepted = false;
3677 return cs;
3678 }
3679 else
3680 {
3681 cs.accepted = true;
3682 if(hidectrls && (edit_mode == GE_CELL || (edit_mode == GE_ROW && (isnewrow || !newvalid))))
3683 {
3684 UpdateCtrls(UC_HIDE | UC_CTRLS | UC_OLDCUR);
3685 if(!one_click_edit || !newvalid)
3686 WhenEndEdit();
3687 }
3688 }
3689
3690 oldvalid = IsValidCursorAll(oldcur);
3691 }
3692
3693 if(tmpcur == oldcur)
3694 return cs;
3695
3696 if(highlight)
3697 {
3698 livecur = tmpcur;
3699
3700 if(oldvalid)
3701 {
3702 SetItemCursor(oldcur, false, true);
3703 RefreshRow(oldcur.y, 0);
3704 }
3705 if(newvalid)
3706 {
3707 SetItemCursor(tmpcur, true, true);
3708 RefreshRow(tmpcur.y, 0);
3709 }
3710 return cs;
3711 }
3712
3713 if(!newvalid)
3714 return cs;
3715
3716 if(isnewrow)
3717 WhenBeforeChangeRow();
3718
3719 if(isnewcol)
3720 WhenBeforeChangeCol();
3721
3722 cs.newx = isnewcol;
3723 cs.newy = isnewrow;
3724
3725 Point t_curpos = curpos;
3726 Point t_curid = curid;
3727 int t_colidx = colidx;
3728 int t_rowidx = rowidx;
3729 bool t_valid_cursor = valid_cursor;
3730
3731 valid_cursor = true;
3732 curpos = tmpcur;
3733 colidx = curpos.x;
3734 rowidx = curpos.y;
3735
3736 curid.x = hitems[curpos.x].id;
3737 curid.y = vitems[curpos.y].id;
3738
3739 WhenCursor();
3740
3741 if(cancel_cursor)
3742 {
3743 cancel_cursor = false;
3744 curpos = t_curpos;
3745 curid = t_curid;
3746 colidx = t_colidx;
3747 rowidx = t_rowidx;
3748 valid_cursor = t_valid_cursor;
3749 cs.Clear();
3750 return cs;
3751 }
3752
3753 if(oldvalid)
3754 {
3755 SetItemCursor(oldcur, false, highlight);
3756 RefreshRow(oldcur.y, 0);
3757 }
3758
3759 SetItemCursor(tmpcur, true, false);
3760 if(isnewrow || (!select_row && isnewcol))
3761 RefreshRow(tmpcur.y, 0);
3762
3763 if(call_whenchangerow && isnewrow)
3764 {
3765 #ifdef LOG_CALLBACKS
3766 LGR(2, "WhenChangeRow()");
3767 LGR(2, Format("[row: %d]", rowidx));
3768 #endif
3769 WhenChangeRow();
3770 }
3771
3772 if(call_whenchangecol && isnewcol)
3773 {
3774 #ifdef LOG_CALLBACKS
3775 LGR(2, "WhenChangeCol()");
3776 LGR(2, Format("[col: %d]",colidx));
3777 #endif
3778 WhenChangeCol();
3779 }
3780
3781 if(isnewrow)
3782 SetCtrlsData();
3783
3784 LG(0, "cur(%d, %d)", curpos.x, curpos.y);
3785
3786 return cs;
3787 }
3788
GetWidth(int n)3789 int GridCtrl::GetWidth(int n)
3790 {
3791 if(n < 0) n = total_cols;
3792 if(n == 0) return 0;
3793 return hitems[n - 1].nRight();
3794 }
3795
GetHeight(int n)3796 int GridCtrl::GetHeight(int n)
3797 {
3798 if(n < 0) n = total_rows;
3799 if(n == 0) return 0;
3800 return vitems[n - 1].nBottom();
3801 }
3802
GetFixedWidth()3803 int GridCtrl::GetFixedWidth()
3804 {
3805 return GetWidth(fixed_cols);
3806 }
3807
GetFixedHeight()3808 int GridCtrl::GetFixedHeight()
3809 {
3810 return GetHeight(fixed_rows);
3811 }
3812
GetFirst0(Vector<ItemRect> & its,int total,int sb,int p)3813 int GridCtrl::GetFirst0(Vector<ItemRect> &its, int total, int sb, int p)
3814 {
3815 int l = 0;
3816 int r = total - 1;
3817
3818 while(l <= r)
3819 {
3820 int i = (l + r) / 2;
3821
3822 int p0 = its[i].nLeft(sb);
3823 int p1 = its[i].nRight(sb);
3824
3825 if(p0 <= p && p1 >= p)
3826 {
3827 if(!its[i].hidden)
3828 {
3829 return i;
3830 }
3831 else
3832 {
3833 for(int j = i + 1; j < total; j++)
3834 if(!its[j].hidden)
3835 return j;
3836 for(int j = i - 1; j > 0; j--)
3837 if(!its[j].hidden)
3838 return j;
3839
3840 return -1;
3841 }
3842 }
3843
3844 if(p1 < p)
3845 l = i + 1;
3846 else
3847 r = i - 1;
3848 }
3849 return -1;
3850 }
3851
GetFirstVisCol(int p)3852 int GridCtrl::GetFirstVisCol(int p)
3853 {
3854 return total_cols <= 2 ? fixed_cols : GetFirst0(hitems, total_cols, sbx, p);
3855 }
3856
GetFirstVisRow(int p)3857 int GridCtrl::GetFirstVisRow(int p)
3858 {
3859 return total_rows <= 1 ? fixed_rows : GetFirst0(vitems, total_rows, sby, p);
3860 }
3861
SetColWidth(int n,int width,bool recalc)3862 GridCtrl& GridCtrl::SetColWidth(int n, int width, bool recalc /* = true */)
3863 {
3864 if(resize_col_mode > 0 && n >= fixed_cols)
3865 return *this;
3866
3867 hitems[n].Width(width);
3868 Repaint(true, false);
3869
3870 return *this;
3871 }
3872
SetRowHeight(int n,int height,bool recalc)3873 GridCtrl& GridCtrl::SetRowHeight(int n, int height, bool recalc)
3874 {
3875 LG(0, "SetRowHeight %d %d", n, height);
3876
3877 if(resize_row_mode > 0 && n >= fixed_rows)
3878 return *this;
3879
3880 vitems[n].Height(height);
3881 Repaint(false, true);
3882
3883 return *this;
3884 }
3885
SetDiffItemSize(bool horizontal,RectItems & its,int n,int diff,bool newsize)3886 bool GridCtrl::SetDiffItemSize(bool horizontal, RectItems &its, int n, int diff, bool newsize)
3887 {
3888 if(diff == 0)
3889 return false;
3890
3891 if(diff < 0 && its[n].IsMin())
3892 return false;
3893
3894 if(diff > 0 && its[n].IsMax())
3895 return false;
3896
3897 int resize_mode = horizontal ? resize_col_mode : resize_row_mode;
3898
3899 if(resize_mode > 0 && diff > 0)
3900 {
3901 bool ismin = true;
3902 for(int i = n + 1; i < (horizontal ? total_cols : total_rows); i++)
3903 if(!its[i].IsMin())
3904 {
3905 ismin = false;
3906 break;
3907 }
3908 if(ismin)
3909 return false;
3910 }
3911
3912 double size = its[n].size + diff;
3913
3914 if(size <= its[n].min)
3915 {
3916 size = its[n].min;
3917 its[n].ismin = true;
3918 }
3919 else if(size >= its[n].max)
3920 {
3921 size = its[n].max;
3922 its[n].ismax = true;
3923 }
3924 else
3925 {
3926 its[n].ismin = false;
3927 its[n].ismax = false;
3928 }
3929
3930 double ddiff = size - its[n].size;
3931
3932 if(ddiff != 0)
3933 {
3934 Recalc(horizontal, its, n, size, ddiff);
3935 return true;
3936 }
3937 return false;
3938 }
3939
Recalc(bool horizontal,RectItems & its,int n,double size,double diff)3940 void GridCtrl::Recalc(bool horizontal, RectItems &its, int n, double size, double diff)
3941 {
3942 its[n].size = size;
3943
3944 Size sz = GetSize();
3945 int cnt = horizontal ? total_cols : total_rows;
3946 int maxsize = horizontal ? sz.cx : sz.cy;
3947 int tcnt = cnt;
3948
3949 int resize_mode = horizontal ? resize_col_mode : resize_row_mode;
3950
3951 if(resize_mode == 0)
3952 {
3953 for(int i = n + 1; i < cnt; i++)
3954 its[i].pos += diff;
3955 }
3956 else if(resize_mode == 1)
3957 {
3958 double imaxsize = 1.0 / (double) maxsize;
3959 double ms = maxsize;
3960
3961 loop:
3962 double sumprop = 0;
3963
3964 for(int i = cnt - 1; i >= n + 1; --i)
3965 {
3966 if(its[i].hidden) continue;
3967
3968 bool prop = (diff > 0 && its[i].IsMin() || diff < 0 && its[i].IsMax());
3969 if(!prop)
3970 sumprop += its[i].prop;
3971 }
3972
3973 double cps = sumprop != 0 ? -diff / sumprop : 0;
3974
3975 for(int i = cnt - 1; i >= n + 1; --i)
3976 {
3977 if(its[i].hidden)
3978 {
3979 its[i].pos = ms;
3980 continue;
3981 }
3982
3983 if(!(diff > 0 && its[i].IsMin() || diff < 0 && its[i].IsMax()))
3984 {
3985 double size = its[i].size + its[i].prop * cps;
3986
3987 bool minsize = (diff > 0 && size < its[i].min);
3988 bool maxsize = (diff < 0 && size > its[i].max);
3989
3990 its[i].ismin = minsize;
3991 its[i].ismax = maxsize;
3992
3993 if(minsize || maxsize)
3994 {
3995 diff += size - its[i].size;
3996 double ns = minsize ? its[i].min : its[i].max;
3997 its[i].size = ns;
3998 its[i].prop = ns * imaxsize;
3999 cnt = i + 1;
4000 goto loop;
4001 }
4002 its[i].size = size;
4003 its[i].prop = size * imaxsize;
4004 }
4005 ms -= its[i].size;
4006 its[i].pos = ms;
4007 }
4008
4009 its[n].size -= its[n].pos + its[n].size - ms;
4010 its[n].prop = its[n].size * imaxsize;
4011 }
4012
4013 CalcIntPos(its, n, maxsize, tcnt - 1, resize_mode, false);
4014 }
4015
CalcIntPos(RectItems & its,int n,int maxsize,int cnt,int resize_mode,bool renumber)4016 void GridCtrl::CalcIntPos(RectItems &its, int n, int maxsize, int cnt, int resize_mode, bool renumber)
4017 {
4018 its[0].npos = 0;
4019
4020 int last_vis = 1;
4021 int hidden = 0;
4022
4023 for(int i = (renumber ? 1 : max(1, n)); i <= cnt ; i++)
4024 {
4025 its[i].npos = Round(its[i].Left());
4026 its[i - 1].nsize = its[i].npos - its[i - 1].npos;
4027
4028 if(renumber)
4029 its[i].n = hidden;
4030
4031 if(its[i].hidden)
4032 hidden++;
4033 else
4034 last_vis = i;
4035 }
4036
4037 last_vis = cnt;
4038 if(resize_mode > 0)
4039 {
4040 int size = maxsize - its[last_vis].npos;
4041 its[last_vis].nsize = size ;//>= its[cnt].min && size <= its[cnt].max ? size : Round(its[cnt].size);
4042 }
4043 else
4044 its[last_vis].nsize = Round(its[last_vis].size);
4045 }
4046
UpdateSizes()4047 bool GridCtrl::UpdateSizes()
4048 {
4049 total_width = total_cols ? hitems[total_cols - 1].nRight() : 0;
4050 total_height = total_rows ? vitems[total_rows - 1].nRight() : 0;
4051
4052 int prev_summary_height = summary_height;
4053
4054 summary_height = summary_row ? GD_HDR_HEIGHT : 0;
4055
4056 size_changed = prev_summary_height != summary_height;
4057
4058 int new_fixed_width = fixed_cols ? hitems[fixed_cols - 1].nRight() : 0;
4059 int new_fixed_height = fixed_rows ? vitems[fixed_rows - 1].nRight() : 0;
4060
4061 Size sz = GetSize();
4062
4063 if(resize_col_mode > 0 && new_fixed_width >= sz.cx)
4064 new_fixed_width = GridCtrl::GD_IND_WIDTH;
4065
4066 if(resize_row_mode > 0 && new_fixed_height >= sz.cy)
4067 new_fixed_height = GridCtrl::GD_HDR_HEIGHT;
4068
4069 if(fixed_cols == 1 && !indicator)
4070 new_fixed_width = 0;
4071
4072 if(new_fixed_width != fixed_width)
4073 {
4074 fixed_width = new_fixed_width;
4075 size_changed = true;
4076 }
4077
4078 if(new_fixed_height != fixed_height)
4079 {
4080 fixed_height = new_fixed_height;
4081 size_changed = true;
4082 }
4083
4084 return size_changed;
4085 }
4086
UpdateCols(bool force)4087 bool GridCtrl::UpdateCols(bool force)
4088 {
4089 Size sz = GetSize();
4090 bool change = false;;
4091
4092 if((osz.cx != sz.cx && resize_col_mode > 0) || force || recalc_cols)
4093 {
4094 RecalcCols(-1);
4095 recalc_cols = false;
4096 change = true;
4097 }
4098
4099 osz.cx = sz.cx;
4100 return change;
4101 }
4102
UpdateRows(bool force)4103 bool GridCtrl::UpdateRows(bool force)
4104 {
4105 Size sz = GetSize();
4106 bool change = false;;
4107
4108 if((osz.cy != sz.cy && resize_row_mode > 0) || force || recalc_rows)
4109 {
4110 RecalcRows(-1);
4111 recalc_rows = false;
4112 change = true;
4113 }
4114 osz.cy = sz.cy;
4115 return change;
4116 }
4117
Recalc(bool horizontal,RectItems & its,int resize_mode)4118 bool GridCtrl::Recalc(bool horizontal, RectItems &its, int resize_mode)
4119 {
4120 Size sz = GetSize();
4121
4122 if(resize_mode < 0)
4123 resize_mode = horizontal ? resize_col_mode : resize_row_mode;
4124
4125 int fixed = horizontal ? fixed_cols : fixed_rows;
4126 int cnt = horizontal ? total_cols : total_rows;
4127 int tcnt = cnt;
4128
4129 its[0].pos = 0;
4130
4131 if(!horizontal && !header)
4132 its[0].size = 0;
4133
4134 if(resize_mode == 0)
4135 {
4136 for(int i = 1; i < cnt; i++)
4137 its[i].pos = its[i - 1].pos + its[i - 1].size;
4138 }
4139 else if(resize_mode == 1)
4140 {
4141 int cs = horizontal ? sz.cx - fixed_width
4142 : sz.cy - fixed_height;
4143
4144 //int cs = horizontal ? sz.cx : sz.cy;
4145
4146 if(cs <= 0)
4147 return false;
4148
4149 double imaxsize = 1.0 / cs;
4150
4151 for(int i = fixed; i < cnt; i++)
4152 {
4153 its[i].ismin = false;
4154 its[i].ismax = false;
4155 }
4156
4157 double sumprop = 0;
4158 for(int i = fixed; i < cnt; i++)
4159 if(!its[i].hidden)
4160 sumprop += its[i].prop;
4161
4162 double ics = sumprop <= 0 ? 0 : cs / sumprop;
4163 sumprop = 0;
4164
4165 for(int i = fixed; i < cnt; i++)
4166 {
4167 if(its[i].hidden)
4168 continue;
4169
4170 its[i].size = its[i].prop * ics;
4171
4172 if(its[i].size < its[i].min)
4173 {
4174 cs -= its[i].min;
4175 its[i].size = its[i].min;
4176 its[i].ismin = true;
4177 its[i].prop = its[i].min * imaxsize;
4178 }
4179 else if(its[i].size > its[i].max)
4180 {
4181 cs -= its[i].max;
4182 its[i].size = its[i].max;
4183 its[i].ismax = true;
4184 its[i].prop = its[i].max * imaxsize;
4185 }
4186 else
4187 sumprop += its[i].prop;
4188 }
4189
4190 ics = sumprop <= 0 ? 0 : cs / sumprop;
4191
4192 for(int i = fixed; i < cnt; i++)
4193 {
4194 its[i].pos = i == 0 ? 0 : its[i - 1].Right();
4195 if(its[i].hidden)
4196 {
4197 its[i].size = 0;
4198 //its[i].prop = 0;
4199 continue;
4200 }
4201
4202 if(!its[i].ismin && !its[i].ismax)
4203 its[i].size = its[i].prop * ics;
4204 its[i].prop = its[i].size * imaxsize;
4205 }
4206 }
4207
4208 CalcIntPos(its, 0, horizontal ? sz.cx : sz.cy, tcnt - 1, resize_mode, true);
4209
4210 UpdateVisColRow(horizontal);
4211 oldpos.x = sbx;
4212 oldpos.y = sby;
4213
4214 return true;
4215 }
4216
RecalcCols(int mode)4217 bool GridCtrl::RecalcCols(int mode)
4218 {
4219 return Recalc(true, hitems, mode);
4220 }
4221
RecalcRows(int mode)4222 bool GridCtrl::RecalcRows(int mode)
4223 {
4224 return Recalc(false, vitems, mode);
4225 }
4226
GetSplitCol(const Point & p,int splitSize,bool full)4227 int GridCtrl::GetSplitCol(const Point &p, int splitSize, bool full)
4228 {
4229 if(total_cols < 2)
4230 return -1;
4231
4232 int diff = 0;
4233 if(p.x > fixed_width || moving_body || moving_header)
4234 {
4235 if(!full && !full_col_resizing && p.y >= fixed_height)
4236 return -1;
4237 diff = sbx;
4238 }
4239 else if(p.y < fixed_height - splitSize)
4240 return -1;
4241
4242 int tc = splitSize >= 0 ? (resize_col_mode == 0 ? 0 : 1) : 0;
4243
4244 int fc = lastVisCol - tc;
4245 int lc = resizing_fixed_cols ? 1 : firstVisCol;
4246
4247 if(splitSize >= 0)
4248 {
4249 for(int i = fc; i >= lc; i--)
4250 {
4251 if(hitems[i].hidden) continue;
4252 int x = hitems[i].nRight(diff);
4253 if(p.x >= x - splitSize &&
4254 p.x <= x + splitSize)
4255 return i;
4256 }
4257 }
4258 else
4259 {
4260 int c = fc;
4261 for(int i = fc; i >= lc; i--)
4262 {
4263 if(!hitems[i].hidden) c = i;
4264 int x = hitems[c].nLeft(diff) + hitems[c].nWidth() / 2;
4265 if(p.x >= x)
4266 return c < fixed_cols ? firstVisCol - 1 : c;
4267 else if(i == lc)
4268 return c - 1;
4269 }
4270 }
4271
4272 return -1;
4273 }
4274
GetSplitRow(const Point & p,int splitSize,bool full)4275 int GridCtrl::GetSplitRow(const Point &p, int splitSize, bool full)
4276 {
4277 if(total_rows < 2)
4278 return -1;
4279
4280 int diff = 0;
4281 if(p.y > fixed_height || moving_body || moving_header)
4282 {
4283 if(!full && !moving_header && !moving_body && !full_row_resizing && p.x >= fixed_width)
4284 return -1;
4285 diff = sby;
4286 }
4287 else if(p.x < fixed_width)
4288 return -1;
4289
4290 int tr = splitSize >= 0 ? (resize_row_mode == 0 ? 0 : 1) : 0;
4291
4292 int fr = lastVisRow - tr;
4293 int lr = p.y < fixed_height && resizing_fixed_rows ? 0 : firstVisRow;
4294
4295 if(splitSize >= 0)
4296 {
4297 for(int i = fr; i >= lr; i--)
4298 {
4299 if(vitems[i].hidden)
4300 continue;
4301 int y = vitems[i].nBottom(diff);
4302 if(p.y >= y - splitSize &&
4303 p.y <= y + splitSize)
4304 return i;
4305 }
4306 }
4307 else
4308 {
4309 int c = fr;
4310 for(int i = fr; i >= lr; i--)
4311 {
4312 if(!vitems[i].hidden) c = i;
4313 int y = vitems[c].nTop(diff) + vitems[c].nHeight() / 2;
4314 if(p.y >= y)
4315 return c < fixed_rows ? firstVisRow - 1 : c;
4316 else if(i == lr)
4317 return c - 1;
4318 }
4319 }
4320
4321 return -1;
4322 }
4323
IsValidCursor(const Point & p,int fc,int lc,int fr,int lr) const4324 bool GridCtrl::IsValidCursor(const Point &p, int fc, int lc, int fr, int lr) const
4325 {
4326 return p.x >= fc && p.x <= lc &&
4327 p.y >= fr && p.y <= lr;
4328 }
4329
IsValidCursorVis(const Point & p) const4330 bool GridCtrl::IsValidCursorVis(const Point &p) const
4331 {
4332 return p.x >= firstVisCol && p.x <= lastVisCol &&
4333 p.y >= firstVisRow && p.y <= lastVisRow;
4334 }
4335
IsValidCursorAll(const Point & p) const4336 bool GridCtrl::IsValidCursorAll(const Point &p) const
4337 {
4338 return p.x >= fixed_cols && p.x < total_cols &&
4339 p.y >= fixed_rows && p.y < total_rows;
4340 }
4341
IsValidCursor(const Point & p) const4342 bool GridCtrl::IsValidCursor(const Point &p) const
4343 {
4344 return ready ? IsValidCursorVis(p) : IsValidCursorAll(p);
4345 }
4346
IsValidCursor(int c) const4347 bool GridCtrl::IsValidCursor(int c) const
4348 {
4349 c += fixed_rows;
4350 return c >= fixed_rows && c < total_rows;
4351 }
4352
IsRowEditable(int r)4353 bool GridCtrl::IsRowEditable(int r)
4354 {
4355 if(r < 0)
4356 r = curpos.y;
4357 else
4358 r += fixed_rows;
4359
4360 return vitems[r].editable && hitems[curpos.x].editable;
4361 }
4362
IsRowClickable(int r)4363 bool GridCtrl::IsRowClickable(int r /* = -1*/)
4364 {
4365 if(r < 0)
4366 r = curpos.y;
4367 else
4368 r += fixed_rows;
4369
4370 return vitems[r].clickable && hitems[curpos.x].clickable;
4371 }
4372
SetItemCursor(Point p,bool b,bool highlight)4373 void GridCtrl::SetItemCursor(Point p, bool b, bool highlight)
4374 {
4375 if(highlight)
4376 {
4377 hitems[p.x].Live(b);
4378 vitems[p.y].Live(b);
4379 GetItem(p).Live(b);
4380 }
4381 else
4382 {
4383 hitems[p.x].Cursor(b);
4384 vitems[p.y].Cursor(b);
4385 GetItem(p).Cursor(b);
4386 }
4387 }
4388
Indicator(bool b,int size)4389 GridCtrl& GridCtrl::Indicator(bool b, int size)
4390 {
4391 if(size < 0)
4392 size = GD_IND_WIDTH;
4393 indicator = b;
4394 fixed_width += size * (b ? 1 : -1);
4395 SetColWidth(0, b ? size : 0);
4396 return *this;
4397 }
4398
RefreshRow(int n,bool relative,bool fixed)4399 void GridCtrl::RefreshRow(int n, bool relative, bool fixed)
4400 {
4401 if(!ready)
4402 return;
4403 if(n < 0) { n = rowidx; relative = false; }
4404 if(relative) n += fixed_rows;
4405 if(vitems[n].hidden) return;
4406 int dy = fixed ? 0 : sby;
4407 int join = vitems[n].join;
4408 if(join > 0)
4409 {
4410 int s = n;
4411 while(s >= 0 && vitems[s].join > 0) s--;
4412 s++;
4413 int e = n;
4414 while(e < total_rows && vitems[e].join > 0) e++;
4415 e--;
4416 Refresh(Rect(0, vitems[s].nTop(dy), GetSize().cx, vitems[e].nBottom(dy)));
4417 }
4418 else
4419 Refresh(Rect(0, vitems[n].nTop(dy), GetSize().cx, vitems[n].nBottom(dy)));
4420 }
4421
RefreshCol(int n,bool relative,bool fixed)4422 void GridCtrl::RefreshCol(int n, bool relative, bool fixed)
4423 {
4424 if(!ready)
4425 return;
4426 if(n < 0) { n = curpos.x; relative = false; }
4427 if(relative) n += fixed_cols;
4428 if(hitems[n].hidden) return;
4429 int dx = fixed ? 0 : sbx;
4430 Refresh(Rect(hitems[n].nLeft(dx), 0, hitems[n].nRight(dx), GetSize().cy));
4431 }
4432
RefreshRows(int from,int to,bool relative,bool fixed)4433 void GridCtrl::RefreshRows(int from, int to, bool relative, bool fixed)
4434 {
4435 if(!ready)
4436 return;
4437 if(relative)
4438 {
4439 from += fixed_rows;
4440 to += fixed_rows;
4441 }
4442 Refresh(Rect(0, vitems[from].nTop(sby), GetSize().cx, vitems[to].nBottom(sby)));
4443 }
4444
RefreshFrom(int from)4445 void GridCtrl::RefreshFrom(int from)
4446 {
4447 Size sz = GetSize();
4448 int y = 0;
4449 if(resize_row_mode == 0)
4450 if(from > 2 && from <= total_rows)
4451 y = vitems[from - 1].nBottom(sby);
4452 Refresh(Rect(0, y, sz.cx, sz.cy));
4453 }
4454
RefreshItem(int r,int c,bool relative)4455 void GridCtrl::RefreshItem(int r, int c, bool relative)
4456 {
4457 if(!ready)
4458 return;
4459 if(relative)
4460 {
4461 c += fixed_cols;
4462 r += fixed_rows;
4463 }
4464 Refresh(GetItemRect(r, c));
4465 }
4466
RefreshNewRow()4467 void GridCtrl::RefreshNewRow()
4468 {
4469 RefreshRow(rowidx, 0);
4470 }
4471
RefreshTop()4472 void GridCtrl::RefreshTop()
4473 {
4474 Refresh(0, 0, GetSize().cx, fixed_height);
4475 }
4476
RefreshLeft()4477 void GridCtrl::RefreshLeft()
4478 {
4479 Refresh(0, fixed_height, fixed_width, GetSize().cy - fixed_height);
4480 }
4481
RefreshSummary()4482 void GridCtrl::RefreshSummary()
4483 {
4484 Size sz = GetSize();
4485 Refresh(0, sz.cy - GD_HDR_HEIGHT, sz.cx, GD_HDR_HEIGHT);
4486 }
4487
IsMouseBody(Point & p)4488 bool GridCtrl::IsMouseBody(Point &p)
4489 {
4490 return p.x >= fixed_width && p.x < total_width && p.y >= fixed_height && p.y < total_height;
4491 }
4492
GetIdCol(int id,bool checkall) const4493 int GridCtrl::GetIdCol(int id, bool checkall) const
4494 {
4495 for(int i = checkall ? 1 : fixed_cols; i < total_cols; i++)
4496 {
4497 if(id == hitems[i].id)
4498 return i;
4499 }
4500 return -1;
4501 }
4502
GetIdRow(int id,bool checkall) const4503 int GridCtrl::GetIdRow(int id, bool checkall) const
4504 {
4505 for(int i = checkall ? 0 : fixed_rows; i < total_rows; i++)
4506 {
4507 if(id == vitems[i].id)
4508 return i;
4509 }
4510 return -1;
4511 }
4512
GetNextRow(int n)4513 int GridCtrl::GetNextRow(int n)
4514 {
4515 n += fixed_rows;
4516 for(int i = n + 1; i < total_rows; i++)
4517 if(!vitems[i].hidden)
4518 return i - fixed_rows;
4519 return -1;
4520 }
4521
GetPrevRow(int n)4522 int GridCtrl::GetPrevRow(int n)
4523 {
4524 n += fixed_rows;
4525 for(int i = n - 1; i >= fixed_rows; i--)
4526 if(!vitems[i].hidden)
4527 return i - fixed_rows;
4528 return -1;
4529 }
4530
UpdateCursor()4531 void GridCtrl::UpdateCursor()
4532 {
4533 curpos.x = GetIdCol(curid.x);
4534 curpos.y = GetIdRow(curid.y);
4535 rowidx = curpos.y;
4536 shiftpos = curpos;
4537 ctrlid.y = curpos.y < 0 ? -1 : curid.y;
4538 ctrlpos.y = curpos.y;
4539 rowfnd = curpos.y;
4540 }
4541
Find(const Value & v,int col,int start_from,int opt) const4542 int GridCtrl::Find(const Value &v, int col, int start_from, int opt) const
4543 {
4544 for(int i = fixed_rows + start_from; i < total_rows; i++)
4545 {
4546 if(opt & GF::SKIP_CURRENT_ROW && i == rowidx)
4547 continue;
4548 if(opt & GF::SKIP_HIDDEN && vitems[i].hidden)
4549 continue;
4550 if(!vitems[i].skip && items[vitems[i].id][col + fixed_cols].val == v)
4551 return i - fixed_rows;
4552 }
4553 return -1;
4554 }
4555
Find(const Value & v,Id id,int opt) const4556 int GridCtrl::Find(const Value &v, Id id, int opt) const
4557 {
4558 return Find(v, aliases.Get(id) - fixed_cols, 0, opt);
4559 }
4560
FindInRow(const Value & v,int row,int start_from) const4561 int GridCtrl::FindInRow(const Value& v, int row, int start_from) const
4562 {
4563 for(int i = fixed_cols + start_from; i < total_cols; i++)
4564 {
4565 if(!hitems[i].skip && items[row + fixed_rows][hitems[i].id].val == v)
4566 return i - fixed_cols;
4567 }
4568 return -1;
4569 }
4570
FindCurrent(Id id,int opt) const4571 int GridCtrl::FindCurrent(Id id, int opt) const
4572 {
4573 int col = aliases.Get(id) - fixed_cols;
4574 return Find(Get(col), col, 0, opt);
4575 }
4576
Find(const Value & v0,Id id0,const Value & v1,Id id1,int opt) const4577 int GridCtrl::Find(const Value &v0, Id id0, const Value&v1, Id id1, int opt) const
4578 {
4579 int col0 = aliases.Get(id0);
4580 int col1 = aliases.Get(id1);
4581
4582 for(int i = fixed_rows; i < total_rows; i++)
4583 {
4584 if(opt & GF::SKIP_CURRENT_ROW && i == rowidx)
4585 continue;
4586 if(opt & GF::SKIP_HIDDEN && vitems[i].hidden)
4587 continue;
4588 if(!vitems[i].skip &&
4589 items[vitems[i].id][col0].val == v0 &&
4590 items[vitems[i].id][col1].val == v1)
4591 return i - fixed_rows;
4592 }
4593 return -1;
4594 }
4595
FindCurrent(Id id0,Id id1,int opt) const4596 int GridCtrl::FindCurrent(Id id0, Id id1, int opt) const
4597 {
4598 int col0 = aliases.Get(id0);
4599 int col1 = aliases.Get(id1);
4600
4601 const Value& val0 = items[vitems[rowidx].id][col0].val;
4602 const Value& val1 = items[vitems[rowidx].id][col1].val;
4603
4604 return Find(val0, id0, val1, id1, opt);
4605 }
4606
UpdateDefaults(int ri)4607 void GridCtrl::UpdateDefaults(int ri)
4608 {
4609 for(int i = 1; i < total_cols; i++)
4610 if(!IsNull(hitems[i].defval))
4611 items[ri][hitems[i].id].val = hitems[i].defval;
4612 }
4613
SetCtrlsData()4614 void GridCtrl::SetCtrlsData()
4615 {
4616 if(!valid_cursor)
4617 return;
4618
4619 for(int i = 1; i < total_cols; i++)
4620 {
4621 int idx = hitems[i].id;
4622 Item &it = items[curid.y][idx];
4623 Ctrl * ctrl = it.ctrl;
4624 if(!ctrl)
4625 ctrl = edits[idx].ctrl;
4626 if(ctrl)
4627 {
4628 ctrl->SetData(it.val);
4629 rowbkp[idx] = it.val;
4630 }
4631 }
4632 }
4633
GetCtrlsData(bool samerow,bool doall,bool updates)4634 bool GridCtrl::GetCtrlsData(bool samerow, bool doall, bool updates)
4635 {
4636 if(!valid_cursor || !HasCtrls())
4637 return true;
4638
4639 bool newrow = newrow_inserted || newrow_appended;
4640
4641 if(focused_ctrl)
4642 {
4643 Item &it = items[curid.y][focused_ctrl_id];
4644
4645 if(updates && edit_mode == GE_CELL && !focused_ctrl->Accept())
4646 return false;
4647
4648 Value v = focused_ctrl->GetData();
4649
4650 if(v.IsError())
4651 v = Null;
4652
4653 bool was_modified = it.modified;
4654
4655 it.modified = edit_mode == GE_CELL
4656 ? it.val != v
4657 : rowbkp[focused_ctrl_id] != v;
4658
4659 it.val = v;
4660
4661 if(it.modified)
4662 {
4663 if(!was_modified)
4664 row_modified++;
4665
4666 //it.val = v;
4667
4668 if(updates)
4669 {
4670 #ifdef LOG_CALLBACKS
4671 LGR(2, "WhenUpdateCell()");
4672 LGR(2, Format("[row: %d, colid: %d]", curid.y, focused_ctrl_id));
4673 LGR(2, Format("[oldval : %s]", AsString(rowbkp[focused_ctrl_id])));
4674 LGR(2, Format("[newval : %s]", AsString(v)));
4675 #endif
4676 WhenUpdateCell();
4677
4678 if(cancel_update_cell)
4679 {
4680 it.val = rowbkp[focused_ctrl_id];
4681 it.modified = false;
4682 if(edit_mode == GE_CELL)
4683 rowbkp[focused_ctrl_id] = it.val;
4684 cancel_update_cell = false;
4685 row_modified--;
4686 }
4687 }
4688 }
4689 }
4690
4691 if(!updates)
4692 return false;
4693
4694 if(!samerow || doall)
4695 {
4696 if(edit_mode == GE_ROW)
4697 {
4698 for(int i = fixed_cols; i < total_cols; ++i)
4699 {
4700 int idx = hitems[i].id;
4701 Ctrl * ctrl = GetCtrl(rowidx, i, true, false, false);
4702 if(ctrl && !ctrl->Accept())
4703 {
4704 focused_ctrl = ctrl;
4705 focused_ctrl_id = idx;
4706 ctrl->SetFocus();
4707 curpos.x = i;
4708 return false;
4709 }
4710 }
4711 }
4712
4713 if(row_modified)
4714 vitems[curid.y].operation = GridOperation::UPDATE;
4715
4716 WhenAcceptRow();
4717 if(cancel_accept)
4718 {
4719 cancel_accept = false;
4720 return false;
4721 }
4722
4723 bool removed = false;
4724 if(newrow)
4725 {
4726 #ifdef LOG_CALLBACKS
4727 LGR(2, Format("WhenInsertRow()", curid.y));
4728 LGR(2, Format("[row: %d]", curid.y));
4729 #endif
4730 removed = !WhenInsertRow0();
4731
4732 }
4733 else if(row_modified)
4734 {
4735 row_data = true;
4736 SetModify();
4737
4738 #ifdef LOG_CALLBACKS
4739 LGR(2, Format("WhenUpdateRow()", curid.y));
4740 LGR(2, Format("[row: %d]", curid.y));
4741 #endif
4742 WhenUpdateRow();
4743 }
4744
4745 if(!removed)
4746 {
4747 if(!cancel_accept && row_modified)
4748 {
4749 WhenAcceptedRow();
4750 /*
4751 if(auto_sorting)
4752 {
4753 GSort();
4754 UpdateCursor();
4755 Repaint(false, true);
4756 }
4757 */
4758 }
4759
4760 if(cancel_accept)
4761 {
4762 cancel_accept = false;
4763 return false;
4764 }
4765
4766 if(cancel_update)
4767 CancelCtrlsData(true);
4768 else
4769 ClearModified();
4770 }
4771 }
4772
4773 if(newrow && (!samerow || doall))
4774 {
4775 newrow_inserted = false;
4776 newrow_appended = false;
4777 }
4778
4779 return true;
4780 }
4781
CancelCtrlsData(bool all)4782 bool GridCtrl::CancelCtrlsData(bool all)
4783 {
4784 cancel_update = false;
4785
4786 int ie = total_cols;
4787 int is = 1;
4788
4789 if(!all && edit_mode == GE_CELL)
4790 {
4791 is = curpos.x;
4792 ie = is + 1;
4793 }
4794
4795 for(int i = is; i < ie; i++)
4796 {
4797 int id = hitems[i].id;
4798 Item &it = items[curid.y][id];
4799
4800 Ctrl * ctrl = it.ctrl;
4801 if(!ctrl)
4802 ctrl = edits[id].ctrl;
4803 if(ctrl)
4804 {
4805 ctrl->Reject();
4806 ctrl->SetData(rowbkp[id]);
4807
4808 if(it.modified)
4809 {
4810 it.modified = false;
4811 row_modified--;
4812 it.val = rowbkp[id];
4813 }
4814 }
4815 }
4816
4817 if(!row_modified)
4818 vitems[curid.y].operation = GridOperation::NONE;
4819
4820 return true;
4821 }
4822
UpdateCtrls(int opt)4823 void GridCtrl::UpdateCtrls(int opt /*= UC_CHECK_VIS | UC_SHOW | UC_CURSOR */)
4824 {
4825 if(!valid_cursor)
4826 return;
4827
4828 if((opt & UC_CHECK_VIS) && !HasCtrls())
4829 return;
4830
4831 Point cp(opt & UC_OLDCUR ? oldcur : curpos);
4832
4833 bool show = opt & UC_SHOW;
4834
4835 ctrlid.y = show ? (cp.y < 0 ? -1 : vitems[cp.y].id) : -1;
4836 ctrlpos.y = show ? cp.y : -1;
4837
4838 if(cp.y < 0)
4839 return;
4840
4841 Size sz = GetSize();
4842
4843 bool gofirst = (opt & UC_GOFIRST) && !IsCtrl(cp, false);
4844
4845 edit_ctrls = false;
4846
4847 bool nofocus = opt & UC_NOFOCUS;
4848
4849 focused_ctrl = NULL;
4850 focused_ctrl_id = -1;
4851 focused_col = -1;
4852
4853 for(int i = 1; i < total_cols; i++)
4854 {
4855 if(hitems[i].hidden)
4856 continue;
4857
4858 Ctrl* ctrl = GetCtrl(cp.y, i, show == false);
4859
4860 if(!ctrl)
4861 continue;
4862
4863 if(show)
4864 {
4865 if(newrow_appended || newrow_inserted)
4866 {
4867 if(!hitems[i].edit_insert)
4868 continue;
4869 }
4870 else
4871 {
4872 if(!hitems[i].edit_update)
4873 continue;
4874 }
4875 }
4876
4877 int id = hitems[i].id;
4878
4879 bool sync_ctrl = items[vitems[cp.y].id][id].ctrl;
4880 bool dorect = false;
4881 bool dorf = i == curpos.x;
4882
4883 if(gofirst)
4884 {
4885 dorf = true;
4886 gofirst = false;
4887 }
4888
4889 bool dofocus = !nofocus && !(opt & UC_HIDE) && dorf;
4890
4891 if(show)
4892 {
4893 dorect = edit_mode == GE_CELL ? dorf : (isedit || (opt & UC_CTRLS));
4894 dorect = dorect && GetItem(cp.y, i).editable;
4895 }
4896
4897 if(!sync_ctrl)
4898 {
4899 if(dorect)
4900 {
4901 Rect r = GetItemRect(ctrlpos.y, i, horz_grid, vert_grid, true, true);
4902
4903 if(!r.Intersects(sz))
4904 r.Set(0, 0, 0, 0);
4905
4906 ctrl->SetRect(AlignRect(r, i));
4907 ctrl->Show();
4908 edit_ctrls = true;
4909 }
4910 else
4911 {
4912 ctrl->SetRect(0, 0, 0, 0);
4913 ctrl->Hide();
4914 }
4915 }
4916
4917 if(dofocus && ctrl->IsShown())
4918 {
4919 ctrl->SetFocus();
4920 focused_ctrl = ctrl;
4921 focused_ctrl_id = id;
4922 focused_ctrl_val = hitems[i].defval;
4923 focused_col = i;
4924
4925 if(opt & UC_CURSOR)
4926 SetCursor0(i, cp.y);
4927 }
4928 }
4929
4930 if(!nofocus && !focused_ctrl)
4931 SetFocus();
4932
4933 if(opt & UC_CTRLS)
4934 isedit = edit_ctrls;
4935
4936 if(opt & UC_CTRLS_OFF)
4937 isedit = false;
4938
4939 if(!(opt & UC_SCROLL))
4940 RebuildToolBar();
4941
4942 if(isedit)
4943 popup.Close();
4944 }
4945
SyncCtrls(int row,int col)4946 void GridCtrl::SyncCtrls(int row, int col)
4947 {
4948 if(!genr_ctrls)
4949 return;
4950
4951 Size sz = GetSize();
4952
4953 int js = row < 0 ? 0 : row;
4954 int je = row < 0 ? total_rows : row + 1;
4955
4956 int is = col < 0 ? 1 : col;
4957 int ie = col < 0 ? total_cols : col + 1;
4958
4959 for(int j = js; j < je; j++)
4960 {
4961 int idy = vitems[j].id;
4962 bool fixed_row = j < fixed_rows;
4963 bool create_row = !fixed_row && vitems[j].editable;
4964
4965 for(int i = is; i < ie; i++)
4966 {
4967 bool fixed_col = i < fixed_cols;
4968 bool create_col = !fixed_col && hitems[i].editable;
4969
4970 int idx = hitems[i].id;
4971
4972 Item *it = &items[idy][idx];
4973
4974 if(it->isjoined)
4975 {
4976 it = &items[it->idy][it->idx];
4977 idx = it->idx;
4978 }
4979
4980 if(!it->ctrl && create_row && create_col && it->editable && edits[idx].factory)
4981 {
4982 One<Ctrl> newctrl;
4983 edits[idx].factory(newctrl);
4984 it->ctrl = newctrl.Detach();
4985 it->ctrl_flag = IC_FACTORY | IC_INIT | IC_OWNED;
4986 }
4987
4988 if(it->ctrl && (it->ctrl_flag & IC_INIT))
4989 {
4990 it->ctrl->SetData(it->val);
4991 it->ctrl->WhenAction << Proxy(WhenCtrlsAction);
4992 holder.AddChild(it->ctrl);
4993 it->ctrl_flag &= ~IC_INIT;
4994 }
4995
4996 if(it->ctrl)
4997 {
4998 if(it->isjoined && it->sync_flag == sync_flag)
4999 continue;
5000
5001 Rect r = GetItemRect(j, i, horz_grid, vert_grid, true, true);
5002 AlignRect(r, i);
5003
5004 if(r.Intersects(sz) && !fixed_col && !fixed_row && !vitems[j].hidden && !hitems[i].hidden)
5005 {
5006 it->ctrl->SetRect(r);
5007 it->ctrl->Show();
5008 }
5009 else if(it->ctrl->IsShown())
5010 {
5011 it->ctrl->SetRect(0, 0, 0, 0);
5012 it->ctrl->Hide();
5013 }
5014 }
5015
5016 if(it->isjoined)
5017 it->sync_flag = sync_flag;
5018 }
5019 }
5020 sync_flag = 1 - sync_flag;
5021 }
5022
SyncSummary()5023 void GridCtrl::SyncSummary()
5024 {
5025 if(!summary)
5026 return;
5027
5028 if(WhenUpdateSummary)
5029 {
5030 WhenUpdateSummary();
5031 }
5032 else
5033 {
5034 for(int i = fixed_cols; i < total_cols; i++)
5035 {
5036 Value t = 0;
5037
5038 int idx = hitems[i].id;
5039
5040 int sop = hitems[i].sop;
5041
5042 if(sop == SOP_NONE)
5043 continue;
5044
5045 int n = 0;
5046
5047 for(int j = fixed_rows; j < total_rows; j++)
5048 {
5049 if(vitems[j].IsHidden())
5050 continue;
5051
5052 if(sop == SOP_CNT)
5053 {
5054 ++n;
5055 continue;
5056 }
5057
5058 int idy = vitems[j].id;
5059
5060 Value v = items[idy][idx].val;
5061
5062 if(IsNull(v))
5063 continue;
5064
5065 ProcessSummaryValue(v);
5066
5067 if(n == 0 && (sop == SOP_MIN || sop == SOP_MAX))
5068 t = v;
5069
5070 if(IsNumber(v))
5071 {
5072 switch(sop)
5073 {
5074 case SOP_MIN:
5075 if(double(v) < double(t))
5076 t = v;
5077 break;
5078 case SOP_MAX:
5079 if(double(v) > double(t))
5080 t = v;
5081 break;
5082 case SOP_SUM:
5083 case SOP_AVG:
5084 t = double(t) + double(v);
5085 }
5086 }
5087 else if(IsType<Date>(v))
5088 {
5089 switch(sop)
5090 {
5091 case SOP_MIN:
5092 if((Date) v < (Date) t)
5093 t = v;
5094 break;
5095 case SOP_MAX:
5096 if((Date) v > (Date) t)
5097 t = v;
5098 break;
5099 case SOP_SUM:
5100 case SOP_AVG:
5101 t = v;
5102 break;
5103 }
5104 }
5105 }
5106
5107 if(sop == SOP_AVG)
5108 {
5109 if(IsNumber(t))
5110 t = double(t) / double(n);
5111 }
5112 else if(sop == SOP_CNT)
5113 {
5114 t = n;
5115 }
5116
5117 summary[idx].val = t;
5118 }
5119 }
5120
5121 if(summary_row)
5122 RefreshSummary();
5123 }
5124
UpdateSummary(bool b)5125 void GridCtrl::UpdateSummary(bool b)
5126 {
5127 update_summary = b;
5128 if(b)
5129 SyncSummary();
5130 }
5131
HasCtrls()5132 bool GridCtrl::HasCtrls()
5133 {
5134 return edit_ctrls || genr_ctrls;
5135 }
5136
SetCtrlFocus(int col)5137 void GridCtrl::SetCtrlFocus(int col)
5138 {
5139 oldcur.x = curpos.x;
5140 Ctrl * ctrl = GetCtrl(col + fixed_cols, rowidx, false, false);
5141 focused_ctrl = ctrl;
5142 focused_ctrl_id = hitems[col + fixed_cols].id;
5143 ctrl->SetFocus();
5144 curpos.x = col + fixed_cols;
5145 }
5146
SetCtrlFocus(Id id)5147 void GridCtrl::SetCtrlFocus(Id id)
5148 {
5149 SetCtrlFocus(aliases.Get(id));
5150 }
5151
Accept()5152 bool GridCtrl::Accept()
5153 {
5154 if(!EndEdit())
5155 return false;
5156 return Ctrl::Accept();
5157 }
5158
Reject()5159 void GridCtrl::Reject()
5160 {
5161 CancelEdit();
5162 Ctrl::Reject();
5163 }
5164
RestoreFocus()5165 void GridCtrl::RestoreFocus()
5166 {
5167 if(focused_ctrl && !focused_ctrl->HasFocusDeep())
5168 focused_ctrl->SetFocus();
5169 }
5170
ShowNextCtrl()5171 bool GridCtrl::ShowNextCtrl()
5172 {
5173 if(GoRight(1, 1))
5174 {
5175 UpdateCtrls(UC_CHECK_VIS | UC_SHOW);
5176 return true;
5177 }
5178 return false;
5179 }
5180
ShowPrevCtrl()5181 bool GridCtrl::ShowPrevCtrl()
5182 {
5183 if(GoLeft(1, 1))
5184 {
5185 UpdateCtrls(UC_CHECK_VIS | UC_SHOW);
5186 return true;
5187 }
5188 return false;
5189 }
5190
GetFocusedCtrlIndex()5191 int GridCtrl::GetFocusedCtrlIndex()
5192 {
5193 for(int i = 1; i < total_cols; i++)
5194 {
5195 int id = hitems[i].id;
5196
5197 Ctrl * ctrl = items[0][id].ctrl;
5198 if(ctrl && ctrl->HasFocusDeep())
5199 return i;
5200 }
5201 return -1;
5202 }
5203
GetCtrlPos(Ctrl * ctrl)5204 Point GridCtrl::GetCtrlPos(Ctrl * ctrl)
5205 {
5206 for(int i = fixed_rows; i < total_rows; i++)
5207 {
5208 int idy = vitems[i].id;
5209 for(int j = fixed_cols; j < total_cols; j++)
5210 {
5211 int idx = hitems[j].id;
5212 Ctrl * ci = items[idy][idx].ctrl;
5213 bool isedit = false;
5214 if(!ci)
5215 {
5216 ci = edits[idx].ctrl;
5217 isedit = true;
5218 }
5219 if(ci == ctrl || ci->HasChildDeep(ctrl))
5220 return Point(j, isedit ? ctrlpos.y : i);
5221 }
5222 }
5223 return Point(-1, -1);
5224 }
5225
Split(int state,bool sync)5226 void GridCtrl::Split(int state, bool sync)
5227 {
5228 if(resize_paint_mode < 2)
5229 {
5230 if(resize_paint_mode > 0 && state != GS_DOWN)
5231 {
5232 if(resizeCol) RefreshTop();
5233 if(resizeRow) RefreshLeft();
5234 }
5235
5236 if(state == GS_DOWN)
5237 DrawLine(true, false);
5238 else if(state == GS_MOVE)
5239 DrawLine(true, true);
5240 else
5241 DrawLine(false, true);
5242 }
5243
5244 if(state == GS_DOWN)
5245 {
5246 firstCol = firstRow = -1;
5247 return;
5248 }
5249
5250 if(state != GS_DOWN && (resize_paint_mode == 2 || state == GS_UP))
5251 {
5252 UpdateSizes();
5253 UpdateHolder();
5254 UpdateSb();
5255 Refresh();
5256 }
5257
5258 if((resize_paint_mode > 1 && state > GS_UP) || state == GS_UP)
5259 {
5260 SyncCtrls();
5261 UpdateCtrls(UC_CHECK_VIS | UC_SHOW);
5262 }
5263
5264 if(sync)
5265 Sync();
5266 }
5267
TabKey(bool enter_mode)5268 bool GridCtrl::TabKey(bool enter_mode)
5269 {
5270 if(!HasFocus() && !holder.HasFocusDeep())
5271 return false;
5272
5273 bool has_ctrls = HasCtrls();
5274
5275 if(has_ctrls)
5276 {
5277 bool isnext = ShowNextCtrl();
5278 if(tab_adds_row && !isnext && curpos.y == lastVisRow)
5279 {
5280 DoAppend();
5281 return true;
5282 }
5283 else
5284 return focused_ctrl ? true : (genr_ctrls > 0 && !edit_ctrls) ? true : isnext;
5285 }
5286
5287 if(tab_changes_row && ((enter_mode && has_ctrls) || (!enter_mode && !has_ctrls)))
5288 {
5289 bool isnext = false;
5290 if(select_row)
5291 {
5292 isnext = GoNext();
5293 if(!isnext && tab_adds_row)
5294 DoAppendNoEdit();
5295 }
5296 else
5297 {
5298 isnext = GoRight();
5299 if(!isnext && tab_adds_row)
5300 DoAppendNoEdit();
5301 }
5302 ClearSelection();
5303
5304 if(isnext)
5305 return true;
5306 }
5307 else if(!enter_mode)
5308 return false;
5309
5310 if(enter_mode && !has_ctrls)
5311 {
5312 SwitchEdit();
5313 return true;
5314 }
5315
5316 return false;
5317 }
5318
Key(dword key,int)5319 bool GridCtrl::Key(dword key, int)
5320 {
5321 if(!IsReadOnly())
5322 switch(key)
5323 {
5324 case K_ENTER:
5325 ClearSelection();
5326 WhenEnter();
5327 #ifdef LOG_CALLBACKS
5328 LGR(2, "WhenEnter()");
5329 #endif
5330
5331 if(enter_like_tab)
5332 return TabKey(true);
5333 else if(!SwitchEdit())
5334 return true;
5335 /*
5336 if(th.IsSorted())
5337 {
5338 th.Multisort();
5339 Refresh();
5340 }*/
5341
5342 return true;
5343 case K_ESCAPE:
5344 {
5345 bool quit = true;
5346 if(search_string.GetCount() > 0)
5347 {
5348 ClearFound();
5349 quit = false;
5350 }
5351 else if(HasCtrls())
5352 {
5353 bool canceled = CancelEdit();
5354 quit = !canceled;
5355 }
5356 if(quit)
5357 {
5358 WhenEscape();
5359 return false;
5360 }
5361 else
5362 return true;
5363 }
5364 case K_SHIFT|K_LEFT:
5365 GoLeft();
5366 DoShiftSelect();
5367 return true;
5368 case K_SHIFT|K_RIGHT:
5369 GoRight();
5370 DoShiftSelect();
5371 return true;
5372 case K_SHIFT|K_UP:
5373 GoPrev();
5374 DoShiftSelect();
5375 return true;
5376 case K_SHIFT|K_DOWN:
5377 GoNext();
5378 DoShiftSelect();
5379 return true;
5380 case K_SHIFT|K_PAGEUP:
5381 GoPageUp();
5382 DoShiftSelect();
5383 return true;
5384 case K_SHIFT|K_PAGEDOWN:
5385 GoPageDn();
5386 DoShiftSelect();
5387 return true;
5388 case K_SHIFT_HOME:
5389 GoBegin();
5390 DoShiftSelect();
5391 return true;
5392 case K_SHIFT_END:
5393 GoEnd();
5394 DoShiftSelect();
5395 return true;
5396 case K_CTRL|K_LEFT:
5397 GoLeft();
5398 DoCtrlSelect();
5399 return true;
5400 case K_CTRL|K_RIGHT:
5401 GoRight();
5402 DoCtrlSelect();
5403 return true;
5404 case K_CTRL|K_UP:
5405 if(select_row)
5406 break;
5407 GoPrev();
5408 DoCtrlSelect();
5409 return true;
5410 case K_CTRL|K_DOWN:
5411 if(select_row)
5412 break;
5413 GoNext();
5414 DoCtrlSelect();
5415 return true;
5416 case K_UP:
5417 GoPrev();
5418 ClearSelection();
5419 return true;
5420 case K_DOWN:
5421 GoNext();
5422 ClearSelection();
5423 return true;
5424 case K_LEFT:
5425 GoLeft();
5426 ClearSelection();
5427 return true;
5428 case K_RIGHT:
5429 GoRight();
5430 ClearSelection();
5431 return true;
5432
5433 case K_HOME:
5434 case K_CTRL_HOME:
5435 case K_CTRL_PAGEUP:
5436 GoBegin();
5437 ClearSelection();
5438 return true;
5439 case K_END:
5440 case K_CTRL_END:
5441 case K_CTRL_PAGEDOWN:
5442 GoEnd();
5443 ClearSelection();
5444 return true;
5445 case K_PAGEUP:
5446 GoPageUp();
5447 ClearSelection();
5448 return true;
5449 case K_PAGEDOWN:
5450 GoPageDn();
5451 ClearSelection();
5452 return true;
5453 case K_TAB:
5454 return TabKey(false);
5455 case K_SHIFT|K_TAB:
5456 if(HasCtrls())
5457 {
5458 bool isprev = ShowPrevCtrl();
5459 return focused_ctrl ? true : isprev;
5460 }
5461 else if(tab_changes_row)
5462 {
5463 bool isprev = false;
5464 if(select_row)
5465 isprev = GoPrev();
5466 else
5467 isprev = GoLeft();
5468 ClearSelection();
5469
5470 return isprev;
5471 }
5472 else
5473 return false;
5474 case K_CTRL|K_F:
5475 if(searching)
5476 {
5477 find.SetFocus();
5478 return true;
5479 }
5480 else
5481 return false;
5482 case K_BACKSPACE:
5483 {
5484 if(searching)
5485 {
5486 int cnt = search_string.GetCount();
5487 if(cnt > 0)
5488 {
5489 search_string.Remove(cnt - 1);
5490 find <<= search_string;
5491 ShowMatchedRows(search_string);
5492 }
5493 return true;
5494 }
5495 else
5496 return false;
5497 }
5498 case K_F3:
5499 if(rowfnd >= 0)
5500 {
5501 for(int i = rowfnd + 1; i < total_rows; i++)
5502 {
5503 if(vitems[i].IsFound())
5504 {
5505 rowfnd = i;
5506 SetCursor0(i);
5507 CenterCursor();
5508 WhenSearchCursor();
5509 return true;
5510 }
5511 }
5512 for(int i = fixed_rows; i < rowfnd; i++)
5513 {
5514 if(vitems[i].IsFound())
5515 {
5516 rowfnd = i;
5517 SetCursor0(i);
5518 CenterCursor();
5519 WhenSearchCursor();
5520 return true;
5521 }
5522 }
5523
5524 return true;
5525 }
5526 return false;
5527 case K_CTRL_W:
5528 WriteClipboardText(GetColumnWidths());
5529 return true;
5530 default:
5531 if(searching && !isedit && Search(key))
5532 return true;
5533 }
5534
5535 return MenuBar::Scan(WhenMenuBar, key);
5536 }
5537
Search(dword key)5538 bool GridCtrl::Search(dword key)
5539 {
5540 //if(key & K_UP)
5541 // return false;
5542
5543 if(key >= 32 && key < 65536)
5544 {
5545 search_string += (wchar) key;
5546 if(!ShowMatchedRows(search_string) && search_string.GetCount() > 0)
5547 search_string.Remove(search_string.GetCount() - 1);
5548 else
5549 find <<= search_string;
5550
5551 return true;
5552 }
5553 return false;
5554 }
5555
GetResizePanelHeight() const5556 int GridCtrl::GetResizePanelHeight() const
5557 {
5558 return (resize_panel.GetHeight() + 2) * resize_panel_open;
5559 }
5560
GetColumnName(int n) const5561 String GridCtrl::GetColumnName(int n) const
5562 {
5563 return hitems[GetIdCol(n + fixed_cols)].GetName();
5564 }
5565
GetColumnId(int n) const5566 Id GridCtrl::GetColumnId(int n) const
5567 {
5568 return aliases.GetKey(n + fixed_cols);
5569 }
5570
SwapCols(int n,int m)5571 void GridCtrl::SwapCols(int n, int m)
5572 {
5573 if(m == n ||
5574 n < fixed_cols || n > total_cols - 1 ||
5575 m < fixed_cols || m > total_cols - 1)
5576 return;
5577
5578 Swap(hitems[m], hitems[n]);
5579 UpdateCursor();
5580 Repaint(true, false);
5581 }
5582
CanMoveCol(int n,int m)5583 bool GridCtrl::CanMoveCol(int n, int m)
5584 {
5585 if(m == n || m == n - 1 ||
5586 n < 0 || n > total_cols - 1 ||
5587 m < 0 || m > total_cols - 1)
5588 return false;
5589 else
5590 {
5591 if(hitems[n].join > 0)
5592 {
5593 LG(2, "n=%d(%d) m=%d(%d)", n, hitems[n].join, m, hitems[m].join);
5594 if(m == n - 2 && hitems[n].join == hitems[n - 1].join)
5595 return true;
5596
5597 if(hitems[m].join != hitems[n].join)
5598 return false;
5599 }
5600 //tu sprawdzic join
5601 return true;
5602 }
5603 }
5604
MoveCol(int n,int m)5605 void GridCtrl::MoveCol(int n, int m)
5606 {
5607 LG(0, "%d->%d", n, m);
5608
5609 if(!CanMoveCol(n, m))
5610 {
5611 Repaint();
5612 return;
5613 }
5614
5615 ItemRect ir = hitems[n];
5616 if(m > total_cols)
5617 hitems.Add(ir);
5618 else
5619 hitems.Insert(m + 1, ir);
5620 if(m > n)
5621 hitems.Remove(n);
5622 else
5623 hitems.Remove(n + 1);
5624
5625 UpdateCursor();
5626 Repaint(true, false);
5627 }
5628
MoveRow(int n,int m,bool repaint)5629 bool GridCtrl::MoveRow(int n, int m, bool repaint)
5630 {
5631 LG(0, "%d->%d", n, m);
5632
5633 if(m == n || m == n - 1 ||
5634 n < 0 || n > total_rows - 1 ||
5635 m < -1 || m > total_rows - 1)
5636 {
5637 Repaint();
5638 return false;
5639 }
5640
5641 WhenMoveRow(n, m);
5642
5643 if(cancel_move)
5644 {
5645 cancel_move = false;
5646 return false;
5647 }
5648
5649 ItemRect ir = vitems[n];
5650 if(m > total_rows)
5651 vitems.Add(ir);
5652 else
5653 vitems.Insert(m + 1, ir);
5654 if(m > n)
5655 vitems.Remove(n);
5656 else
5657 vitems.Remove(n + 1);
5658
5659 if(repaint)
5660 {
5661 UpdateCursor();
5662 Repaint(false, true);
5663 }
5664
5665 SetOrder();
5666 SetModify();
5667
5668 return true;
5669 }
5670
MoveRows(int n,bool onerow)5671 void GridCtrl::MoveRows(int n, bool onerow)
5672 {
5673 if(selected_rows && !onerow)
5674 {
5675 Vector<ItemRect> vi;
5676 vi.Reserve(selected_rows);
5677 for(int i = fixed_rows; i < total_rows; i++)
5678 if(vitems[i].IsSelect())
5679 {
5680 WhenMoveRow(i, n);
5681 if(cancel_move)
5682 {
5683 cancel_move = false;
5684 return;
5685 }
5686 vi.Add(vitems[i]);
5687 }
5688
5689 int cnt = 0;
5690
5691 for(int i = total_rows - 1; i >= fixed_rows; i--)
5692 if(vitems[i].IsSelect())
5693 {
5694 vitems.Remove(i);
5695 if(i < n)
5696 cnt++;
5697 }
5698
5699 vitems.Insert(n - cnt, vi);
5700
5701 SetOrder();
5702 SetModify();
5703
5704 UpdateCursor();
5705 Repaint(false, true);
5706 }
5707 else
5708 {
5709 MoveRow(curpos.y, n - 1);
5710 }
5711 }
5712
SwapRows(int n,int m,bool repaint)5713 bool GridCtrl::SwapRows(int n, int m, bool repaint)
5714 {
5715 if(isedit || m == n ||
5716 n < fixed_rows || n > total_rows - 1 ||
5717 m < fixed_rows || m > total_rows - 1)
5718 return false;
5719
5720 WhenMoveRow(n, m);
5721
5722 if(cancel_move)
5723 {
5724 cancel_move = false;
5725 return false;
5726 }
5727
5728 Swap(vitems[m], vitems[n]);
5729 if(repaint)
5730 {
5731 UpdateCursor();
5732 Repaint(false, true);
5733 }
5734 SetOrder();
5735 SetModify();
5736 return true;
5737 }
5738
SwapUp(int cnt)5739 void GridCtrl::SwapUp(int cnt)
5740 {
5741 int yp = 0;
5742 bool first = false;
5743 bool repaint = false;
5744
5745 if(selected_rows == 0)
5746 {
5747 if(SwapRows(curpos.y, curpos.y - cnt))
5748 yp = vitems[curpos.y + cnt].nTop(sby + fixed_height);
5749 else
5750 return;
5751 }
5752 else
5753 {
5754 for(int i = fixed_rows; i < total_rows; i++)
5755 {
5756 if(vitems[i].IsSelect())
5757 {
5758 if(!SwapRows(i, i - cnt, false))
5759 return;
5760 if(!first)
5761 {
5762 yp = vitems[i].nTop(sby + fixed_height);
5763 first = true;
5764 }
5765 }
5766 }
5767 repaint = true;
5768 }
5769
5770 if(resize_row_mode == 0 && yp < 0)
5771 sby.Set(sby + yp);
5772
5773 if(repaint)
5774 {
5775 UpdateCursor();
5776 Repaint(false, true);
5777 }
5778 }
5779
SwapDown(int cnt)5780 void GridCtrl::SwapDown(int cnt)
5781 {
5782 int yp = 0;
5783 bool first = false;
5784 bool repaint = false;
5785
5786 if(selected_rows == 0)
5787 {
5788 if(SwapRows(curpos.y, curpos.y + cnt))
5789 yp = vitems[curpos.y - cnt].nBottom(sby);
5790 else
5791 return;
5792 }
5793 else
5794 {
5795 for(int i = total_rows - 1; i >= fixed_rows; i--)
5796 {
5797 if(vitems[i].IsSelect())
5798 {
5799 if(!SwapRows(i, i + cnt, false))
5800 return;
5801 if(!first)
5802 {
5803 yp = vitems[i].nBottom(sby);
5804 first = true;
5805 }
5806 }
5807 }
5808 repaint = true;
5809 }
5810
5811 int cy = GetSize().cy - bar.GetSize().cy;
5812 if(resize_row_mode == 0 && yp > cy)
5813 sby.Set(sby + yp - cy);
5814
5815 if(repaint)
5816 {
5817 UpdateCursor();
5818 Repaint(false, true);
5819 }
5820 }
5821
MouseLeave()5822 void GridCtrl::MouseLeave()
5823 {
5824 if(live_cursor)
5825 {
5826 LG(2, "MouseLeave:LiveCursor");
5827 SetCursor0(-1, -1, CU_HIGHLIGHT);
5828 }
5829 UpdateHighlighting(GS_BORDER, Point(0, 0));
5830 oldSplitCol = -1;
5831 oldSplitRow = -1;
5832 //popup.Close();
5833 }
5834
MouseWheel(Point p,int zdelta,dword keyflags)5835 void GridCtrl::MouseWheel(Point p, int zdelta, dword keyflags)
5836 {
5837 if(resize_row_mode == 0)
5838 {
5839 sby.Set(sby - zdelta / 4);
5840 }
5841 }
5842
GridColor(Color fg)5843 GridCtrl& GridCtrl::GridColor(Color fg)
5844 {
5845 fg_grid = fg;
5846 return *this;
5847 }
5848
FocusColor(Color fg,Color bg)5849 GridCtrl& GridCtrl::FocusColor(Color fg, Color bg)
5850 {
5851 fg_focus = fg;
5852 bg_focus = bg;
5853 return *this;
5854 }
5855
LiveColor(Color fg,Color bg)5856 GridCtrl& GridCtrl::LiveColor(Color fg, Color bg)
5857 {
5858 fg_live = fg;
5859 bg_live = bg;
5860 return *this;
5861 }
5862
OddColor(Color fg,Color bg)5863 GridCtrl& GridCtrl::OddColor(Color fg, Color bg)
5864 {
5865 fg_odd = fg;
5866 bg_odd = bg;
5867 return *this;
5868 }
5869
EvenColor(Color fg,Color bg)5870 GridCtrl& GridCtrl::EvenColor(Color fg, Color bg)
5871 {
5872 fg_even = fg;
5873 bg_even = bg;
5874 return *this;
5875 }
5876
ColoringMode(int m)5877 GridCtrl& GridCtrl::ColoringMode(int m)
5878 {
5879 coloring_mode = m;
5880 return *this;
5881 }
5882
ClearCursor(bool remove)5883 void GridCtrl::ClearCursor(bool remove)
5884 {
5885 if(!remove && valid_cursor)
5886 {
5887 SetItemCursor(curpos, false, false);
5888 RefreshRow(curpos.y, 0);
5889 }
5890
5891 curpos.x = curpos.y = -1;
5892 curid.x = curid.y = -1;
5893 rowidx = -1;
5894 valid_cursor = false;
5895 }
5896
ClearRow(int r,int column_offset)5897 void GridCtrl::ClearRow(int r, int column_offset)
5898 {
5899 if(r < 0)
5900 r = rowidx;
5901 else
5902 r -= fixed_rows;
5903 for(int i = fixed_cols + column_offset; i < total_cols; i++)
5904 items[vitems[r].id][hitems[i].id].val = Null;
5905
5906 SetCtrlsData();
5907 RefreshRow(rowidx, 0);
5908 }
5909
Clear(bool columns)5910 void GridCtrl::Clear(bool columns)
5911 {
5912 doscroll = false;
5913
5914 UpdateCtrls(UC_HIDE | UC_CTRLS);
5915
5916 int nrows = columns ? 1 : fixed_rows;
5917 items.Remove(nrows, items.GetCount() - nrows);
5918 vitems.Remove(nrows, vitems.GetCount() - nrows);
5919
5920 total_rows = nrows;
5921 fixed_rows = nrows;
5922
5923 if(columns)
5924 {
5925 hitems.Remove(1, hitems.GetCount() - 1);
5926 items[0].Remove(1, items[0].GetCount() - 1);
5927 rowbkp.Remove(1, rowbkp.GetCount() - 1);
5928 edits.Remove(1, edits.GetCount() - 1);
5929 sortOrder.Clear();
5930 total_cols = 1;
5931 total_width = 0;
5932 total_height = 0;
5933 firstCol = -1;
5934 lastCol = -1;
5935 fixed_cols = 1;
5936 coluid = 0;
5937 hcol = -1;
5938 sortCol = -1;
5939 genr_ctrls = 0;
5940 firstVisCol = fixed_cols;
5941 lastVisCol = total_cols - 1;
5942 }
5943 else
5944 {
5945 total_height = fixed_height;
5946 }
5947
5948 firstVisRow = fixed_rows;
5949 lastVisRow = total_rows - 1;
5950
5951 focused_ctrl = NULL;
5952
5953 valid_cursor = false;
5954
5955 firstRow = -1;
5956 lastRow = -1;
5957
5958 curpos.x = curpos.y = -1;
5959 curid.x = curid.y = -1;
5960
5961 hrow = -1;
5962
5963 rowidx = -1;
5964 rowuid = 0;
5965
5966 row_modified = 0;
5967
5968 UpdateSizes();
5969 UpdateSb();
5970
5971 if(ready)
5972 {
5973 UpdateHolder();
5974
5975 oldpos.x = sbx;
5976 oldpos.y = sby;
5977
5978 RebuildToolBar();
5979 Refresh();
5980 }
5981
5982 WhenEmpty();
5983 WhenCursor();
5984
5985 doscroll = true;
5986 }
5987
Reset()5988 void GridCtrl::Reset()
5989 {
5990 Clear(true);
5991 }
5992
ClearOperations()5993 void GridCtrl::ClearOperations()
5994 {
5995 for(int i = fixed_rows; i < total_rows; i++)
5996 vitems[i].operation.Clear();
5997 }
5998
ClearVersions()5999 void GridCtrl::ClearVersions()
6000 {
6001 for(int i = fixed_rows; i < total_rows; i++)
6002 vitems[i].operation.ClearVersion();
6003 }
6004
Begin()6005 void GridCtrl::Begin()
6006 {
6007 bkp_rowidx = rowidx;
6008 rowidx = fixed_rows;
6009 }
6010
End()6011 void GridCtrl::End()
6012 {
6013 rowidx = total_rows - 1;
6014 }
6015
IsEnd()6016 bool GridCtrl::IsEnd()
6017 {
6018 if(rowidx < total_rows)
6019 return true;
6020 else
6021 {
6022 rowidx = bkp_rowidx;
6023 return false;
6024 }
6025 }
6026
Next()6027 void GridCtrl::Next()
6028 {
6029 ++rowidx;
6030 }
6031
Prev()6032 void GridCtrl::Prev()
6033 {
6034 --rowidx;
6035 }
6036
Move(int r)6037 void GridCtrl::Move(int r)
6038 {
6039 rowidx = r + fixed_rows;
6040 }
6041
IsNext()6042 bool GridCtrl::IsNext()
6043 {
6044 return rowidx < total_rows - 1;
6045 }
6046
IsPrev()6047 bool GridCtrl::IsPrev()
6048 {
6049 return rowidx > fixed_rows;
6050 }
6051
IsFirst()6052 bool GridCtrl::IsFirst()
6053 {
6054 return rowidx == fixed_rows;
6055 }
6056
IsLast()6057 bool GridCtrl::IsLast()
6058 {
6059 return rowidx == total_rows - 1;
6060 }
6061
SetCursor0(int n)6062 int GridCtrl::SetCursor0(int n)
6063 {
6064 int t = curpos.y;
6065 SetCursor0(curpos.x < 0 ? firstVisCol : curpos.x, n);
6066 return t;
6067 }
6068
SetCursor(int n)6069 int GridCtrl::SetCursor(int n)
6070 {
6071 return SetCursor0(n + fixed_rows) - fixed_rows;
6072 }
6073
SetCursor(const Point & p)6074 void GridCtrl::SetCursor(const Point& p)
6075 {
6076 SetCursor0(Point(p.x + fixed_cols, p.y + fixed_rows), false);
6077 }
6078
SetCursorId(int id)6079 int GridCtrl::SetCursorId(int id)
6080 {
6081 id += fixed_rows;
6082 for(int i = fixed_rows; i < total_rows; i++)
6083 {
6084 if(vitems[i].id == id)
6085 return SetCursor(i - fixed_rows);
6086 }
6087 return -1;
6088 }
6089
GetCursor(bool rel) const6090 int GridCtrl::GetCursor(bool rel) const
6091 {
6092 if(rel)
6093 return valid_cursor ? vitems[curpos.y].id - fixed_rows : -1;
6094 else
6095 return valid_cursor ? curpos.y - fixed_rows : -1;
6096 }
6097
GetPrevCursor(bool rel) const6098 int GridCtrl::GetPrevCursor(bool rel) const
6099 {
6100 if(rel)
6101 return IsValidCursor(oldcur) ? vitems[oldcur.y].id - fixed_rows : -1;
6102 else
6103 return IsValidCursor(oldcur) ? oldcur.y - fixed_rows : -1;
6104 }
6105
GetCursor(int uid) const6106 int GridCtrl::GetCursor(int uid) const
6107 {
6108 for(int i = fixed_rows; i < total_rows; i++)
6109 if(vitems[i].uid == uid)
6110 return i - fixed_rows;
6111 return -1;
6112 }
6113
GetCursorPos() const6114 Point GridCtrl::GetCursorPos() const
6115 {
6116 return valid_cursor ? Point(curpos.x - fixed_cols, curpos.y - fixed_rows) : Point(-1, -1);
6117 }
6118
GetRowId() const6119 int GridCtrl::GetRowId() const
6120 {
6121 return valid_cursor ? vitems[curpos.y].id - fixed_rows : -1;
6122 }
6123
GetColId() const6124 int GridCtrl::GetColId() const
6125 {
6126 return valid_cursor ? hitems[curpos.x].id - fixed_cols: -1;
6127 }
6128
GetRowId(int n) const6129 int GridCtrl::GetRowId(int n) const { return vitems[n + fixed_rows].id - fixed_rows; }
GetColId(int n) const6130 int GridCtrl::GetColId(int n) const { return hitems[n + fixed_cols].id - fixed_cols; }
6131
GetColUId() const6132 int GridCtrl::GetColUId() const
6133 {
6134 return valid_cursor ? hitems[curpos.x].uid : -1;
6135 }
6136
GetRowUId() const6137 int GridCtrl::GetRowUId() const
6138 {
6139 return valid_cursor ? vitems[curpos.y].uid : -1;
6140 }
6141
FindCol(int id) const6142 int GridCtrl::FindCol(int id) const
6143 {
6144 for(int i = fixed_cols; i < total_cols; i++)
6145 if(hitems[i].id == id)
6146 return i - fixed_cols;
6147 return -1;
6148 }
6149
FindCol(const Id & id) const6150 int GridCtrl::FindCol(const Id& id) const
6151 {
6152 for(int i = fixed_cols; i < total_cols; i++)
6153 if(aliases.GetKey(i) == id)
6154 return i - fixed_cols;
6155 return -1;
6156 }
6157
FindCol(const String & s) const6158 int GridCtrl::FindCol(const String& s) const
6159 {
6160 for(int i = fixed_cols; i < total_cols; i++)
6161 if(hitems[i].GetName() == s)
6162 return i - fixed_cols;
6163 return -1;
6164 }
6165
FindRow(int id) const6166 int GridCtrl::FindRow(int id) const
6167 {
6168 for(int i = fixed_rows; i < total_rows; i++)
6169 if(vitems[i].id == id)
6170 return i - fixed_rows;
6171 return -1;
6172 }
6173
GetNewRowPos()6174 int GridCtrl::GetNewRowPos()
6175 {
6176 return rowidx > 0 ? rowidx - fixed_rows : -1;
6177 }
6178
GetNewRowId()6179 int GridCtrl::GetNewRowId()
6180 {
6181 return rowidx > 0 ? vitems[rowidx].id - fixed_rows : -1;
6182 }
6183
GetRemovedRowPos()6184 int GridCtrl::GetRemovedRowPos()
6185 {
6186 return rowidx > 0 ? rowidx - fixed_rows : -1;
6187 }
6188
CenterCursor()6189 void GridCtrl::CenterCursor()
6190 {
6191 if(IsEmpty() || !IsCursor())
6192 return;
6193
6194 sbx.Set(hitems[curpos.x].nLeft() - GetSize().cx / 2);
6195 sby.Set(vitems[curpos.y].nTop() - GetSize().cy / 2);
6196 }
6197
Go0(int jump,bool scroll,bool goleft,bool ctrlmode)6198 bool GridCtrl::Go0(int jump, bool scroll, bool goleft, bool ctrlmode)
6199 {
6200 if(IsEmpty())
6201 return false;
6202
6203 if(!ready)
6204 {
6205 UpdateSizes();
6206 UpdateSb();
6207 }
6208
6209 if(jump == GO_LEFT || jump == GO_RIGHT)
6210 {
6211 if(select_row && !ctrlmode && !draw_focus)
6212 {
6213 if(jump == GO_LEFT)
6214 sbx.Set(sbx.Get() - 5);
6215 else
6216 sbx.Set(sbx.Get() + 5);
6217 return false;
6218 }
6219 }
6220
6221 if(jump == GO_PREV)
6222 if(curpos.y >= 0 && curpos.y <= firstVisRow)
6223 return false;
6224
6225 if(jump == GO_NEXT)
6226 if(curpos.y >= 0 && curpos.y >= lastVisRow)
6227 return false;
6228
6229 if(jump == GO_PAGEUP || jump == GO_PAGEDN)
6230 {
6231 if(jump == GO_PAGEDN && curpos.y == lastVisRow)
6232 return false;
6233
6234 if(jump == GO_PAGEUP && curpos.y == firstVisRow)
6235 return false;
6236
6237 if(!valid_cursor)
6238 {
6239 GoFirstVisible();
6240 return true;
6241 }
6242 }
6243
6244 Size sz = GetSize();
6245 int sy = -1;
6246
6247 int opt = /*ctrls*/ ctrlmode ? CU_CTRLMODE : 0;
6248
6249 switch(jump)
6250 {
6251 case GO_BEGIN:
6252 {
6253 if(!SetCursor0(curpos.x < 0 ? firstVisCol : curpos.x, firstVisRow, opt, 0, 1))
6254 return false;
6255 sy = 0;
6256
6257 break;
6258 }
6259 case GO_END:
6260 {
6261 if(!SetCursor0((curpos.x < 0 || goleft) ? firstVisCol : curpos.x, lastVisRow, opt, 0, -1))
6262 return false;
6263 if(goleft)
6264 GoCursorLeftRight();
6265 else
6266 sy = total_height - fixed_height - summary_height;
6267
6268 break;
6269 }
6270 case GO_NEXT:
6271 {
6272 if(!SetCursor0(curpos.x < 0 ? firstVisCol : curpos.x,
6273 curpos.y < 0 ? firstVisRow : curpos.y + 1,
6274 opt, 0, 1))
6275 return false;
6276
6277 int b = vitems[curpos.y].nBottom(sby);
6278 int r = sz.cy - summary_height;
6279
6280 if(b > r)
6281 sy = sby + b - r;
6282
6283 break;
6284 }
6285 case GO_PREV:
6286 {
6287 if(!SetCursor0(curpos.x < 0 ? firstVisCol : curpos.x,
6288 curpos.y < 0 ? firstVisRow : curpos.y - 1,
6289 opt, 0, -1))
6290 return false;
6291
6292 int t = vitems[curpos.y].nTop(sby + fixed_height);
6293
6294 if(t < 0)
6295 sy = sby + t;
6296
6297 break;
6298 }
6299 case GO_LEFT:
6300 {
6301 if(!SetCursor0(curpos.x < 0 ? firstVisCol : curpos.x - 1,
6302 curpos.y < 0 ? firstVisRow : curpos.y,
6303 opt, -1, 0))
6304 return false;
6305
6306 break;
6307 }
6308 case GO_RIGHT:
6309 {
6310 if(!SetCursor0(curpos.x < 0 ? firstVisCol : curpos.x + 1,
6311 curpos.y < 0 ? firstVisRow : curpos.y,
6312 ctrlmode ? CU_CTRLMODE : 0, 1, 0))
6313 return false;
6314
6315 break;
6316 }
6317 case GO_PAGEUP:
6318 {
6319 int cp = curpos.y;
6320 int c = cp;
6321
6322 int yn = vitems[c].nTop() - sz.cy;
6323 int ya = vitems[c].nTop(sby);
6324
6325 bool found = false;
6326 int i;
6327 for(i = c - 1; i >= fixed_rows; i--)
6328 if(yn >= vitems[i].nTop() && yn < vitems[i].nBottom())
6329 {
6330 found = true;
6331 break;
6332 }
6333
6334 c = found ? i : firstVisRow;
6335
6336 if(!SetCursor0(curpos.x < 0 ? firstVisCol : curpos.x, c, opt, 0, 1))
6337 return false;
6338
6339 c = curpos.y;
6340
6341 if(scroll && resize_row_mode == 0)
6342 {
6343 int yc = vitems[c].nTop();
6344 int yt = vitems[cp].nTop(sby);
6345 int yb = vitems[cp].nBottom(sby);
6346
6347 if(yt < 0 || yb > sz.cy - 1)
6348 sby.Set(yc - sz.cy + vitems[c].nHeight());
6349 else
6350 sby.Set(yc - ya);
6351 }
6352
6353 break;
6354 }
6355 case GO_PAGEDN:
6356 {
6357 int cp = curpos.y;
6358 int c = cp;
6359
6360 int yn = vitems[c].nTop() + sz.cy;
6361 int ya = vitems[c].nTop(sby);
6362
6363 bool found = false;
6364 int i;
6365 for(i = c + 1; i < total_rows; i++)
6366 if(yn >= vitems[i].nTop() && yn < vitems[i].nBottom())
6367 {
6368 found = true;
6369 break;
6370 }
6371
6372 c = found ? i : lastVisRow;
6373
6374 if(!SetCursor0(curpos.x < 0 ? firstVisCol : curpos.x, c, opt, 0, -1))
6375 return false;
6376
6377 c = curpos.y;
6378
6379 if(scroll && resize_row_mode == 0)
6380 {
6381 int yc = vitems[c].nTop();
6382 int yt = vitems[cp].nTop(sby);
6383 int yb = vitems[cp].nBottom(sby);
6384
6385 if(yt < 0 || yb > sz.cy - 1)
6386 sby.Set(yc);
6387 else
6388 sby.Set(yc - ya);
6389 }
6390
6391 break;
6392 }
6393 }
6394
6395 if(jump == GO_LEFT || jump == GO_RIGHT)
6396 {
6397 if(scroll)
6398 GoCursorLeftRight();
6399 }
6400 else
6401 {
6402 if(scroll && resize_row_mode == 0 && sy >= 0)
6403 sby.Set(sy);
6404 }
6405
6406 opt = UC_CHECK_VIS;
6407 if(isedit)
6408 opt |= UC_SHOW;
6409 UpdateCtrls(opt);
6410
6411 return true;
6412 }
6413
GoCursorLeftRight()6414 void GridCtrl::GoCursorLeftRight()
6415 {
6416 if(resize_col_mode == 0)
6417 {
6418 int l = hitems[curpos.x].nLeft(sbx + fixed_width);
6419 int r = hitems[curpos.x].nRight(sbx);
6420 int w = GetSize().cx;
6421
6422 if(l < 0)
6423 sbx.Set(sbx + l);
6424 else if(r > w)
6425 sbx.Set(sbx + r - w);
6426 }
6427
6428 if(resize_row_mode == 0)
6429 {
6430 int t = vitems[curpos.y].nTop(sby + fixed_height);
6431 int b = vitems[curpos.y].nBottom(sby);
6432 int h = GetSize().cy - summary_height;
6433
6434 if(t < 0)
6435 sby.Set(sby + t);
6436 else if(b > h)
6437 sby.Set(sby + b - h);
6438 }
6439 }
6440
GoFirstVisible(bool scroll)6441 bool GridCtrl::GoFirstVisible(bool scroll)
6442 {
6443 if(IsEmpty())
6444 return false;
6445
6446 SetCursor0(curpos.x < 0 ? firstVisCol : curpos.x, max(firstVisRow, firstRow));
6447 if(scroll && resize_row_mode == 0)
6448 sby.Set(vitems[firstRow].nTop(/*fixed_height*/));
6449 if(isedit)
6450 UpdateCtrls();
6451
6452 return true;
6453 }
6454
GoBegin(bool scroll)6455 bool GridCtrl::GoBegin(bool scroll) { return Go0(GO_BEGIN, scroll); }
GoEnd(bool scroll,bool goleft)6456 bool GridCtrl::GoEnd(bool scroll, bool goleft) { return Go0(GO_END, scroll, goleft); }
GoNext(bool scroll)6457 bool GridCtrl::GoNext(bool scroll) { return Go0(GO_NEXT, scroll); }
GoPrev(bool scroll)6458 bool GridCtrl::GoPrev(bool scroll) { return Go0(GO_PREV, scroll); }
GoLeft(bool scroll,bool ctrlmode)6459 bool GridCtrl::GoLeft(bool scroll, bool ctrlmode) { return Go0(GO_LEFT, scroll, false, ctrlmode); }
GoRight(bool scroll,bool ctrlmode)6460 bool GridCtrl::GoRight(bool scroll, bool ctrlmode) { return Go0(GO_RIGHT, scroll, false, ctrlmode); }
GoPageUp(bool scroll)6461 bool GridCtrl::GoPageUp(bool scroll) { return Go0(GO_PAGEUP, scroll); }
GoPageDn(bool scroll)6462 bool GridCtrl::GoPageDn(bool scroll) { return Go0(GO_PAGEDN, scroll); }
6463
GetCtrl(const Point & p,bool check_visibility,bool hrel,bool vrel,bool check_edits)6464 Ctrl * GridCtrl::GetCtrl(const Point &p, bool check_visibility, bool hrel, bool vrel, bool check_edits)
6465 {
6466 return GetCtrl(p.y, p.x, check_visibility, hrel, vrel, check_edits);
6467 }
6468
GetCtrl(int r,int c,bool check_visibility,bool hrel,bool vrel,bool check_edits)6469 Ctrl * GridCtrl::GetCtrl(int r, int c, bool check_visibility, bool hrel, bool vrel, bool check_edits)
6470 {
6471 int idx = hrel ? fixed_cols + c : hitems[c].id;
6472 int idy = vrel ? fixed_rows + r : vitems[r].id;
6473 Ctrl * ctrl = items[idy][idx].ctrl;
6474 if(check_edits && !ctrl)
6475 ctrl = edits[idx].ctrl;
6476 if(check_visibility && ctrl && !ctrl->IsShown())
6477 ctrl = NULL;
6478 return ctrl;
6479 }
6480
GetCtrl(int r,int c)6481 Ctrl * GridCtrl::GetCtrl(int r, int c)
6482 {
6483 return GetCtrl(r + fixed_rows, c, true, true, false);
6484 }
6485
GetCtrlAt(int r,int c)6486 Ctrl * GridCtrl::GetCtrlAt(int r, int c)
6487 {
6488 return GetCtrl(r + fixed_rows, c, false, true, false);
6489 }
6490
GetCtrl(int c)6491 Ctrl * GridCtrl::GetCtrl(int c)
6492 {
6493 return GetCtrl(rowidx, c, true, true, false);
6494 }
6495
IsCtrl(Point & p,bool check_visibility)6496 bool GridCtrl::IsCtrl(Point &p, bool check_visibility)
6497 {
6498 return GetCtrl(p, check_visibility, false, false) != NULL;
6499 }
6500
GoTo(int r,bool setcursor,bool scroll)6501 void GridCtrl::GoTo(int r, bool setcursor, bool scroll)
6502 {
6503 r += fixed_rows;
6504
6505 if(setcursor)
6506 if(!SetCursor0(r))
6507 return;
6508
6509 if(scroll)
6510 {
6511 Size sz = GetSize();
6512 sby.Set(vitems[r].nTop() + vitems[r].nHeight() / 2 - sz.cy / 2);
6513 }
6514 }
6515
GoTo(int r,int c,bool setcursor,bool scroll)6516 void GridCtrl::GoTo(int r, int c, bool setcursor, bool scroll)
6517 {
6518 c += fixed_cols;
6519 r += fixed_rows;
6520
6521 if(setcursor)
6522 if(!SetCursor0(c, r))
6523 return;
6524
6525 if(scroll)
6526 {
6527 Size sz = GetSize();
6528 sbx.Set(hitems[c].nLeft() + hitems[c].nWidth() / 2 - sz.cx / 2);
6529 sby.Set(vitems[r].nTop() + vitems[r].nHeight() / 2 - sz.cy / 2);
6530 }
6531 }
6532
6533
GetCount() const6534 int GridCtrl::GetCount() const { return total_rows - fixed_rows; }
GetFixedCount() const6535 int GridCtrl::GetFixedCount() const { return fixed_rows; }
GetTotalCount() const6536 int GridCtrl::GetTotalCount() const { return total_rows; }
6537
GetVisibleCount() const6538 int GridCtrl::GetVisibleCount() const
6539 {
6540 int cnt = 0;
6541 for(int i = fixed_rows; i < total_rows; i++)
6542 if(!vitems[i].hidden)
6543 ++cnt;
6544 return cnt;
6545 }
6546
SetColsMin(int size)6547 GridCtrl& GridCtrl::SetColsMin(int size)
6548 {
6549 for(int i = 1; i < total_cols; i++)
6550 hitems[i].min = size;
6551
6552 return *this;
6553 }
6554
SetColsMax(int size)6555 GridCtrl& GridCtrl::SetColsMax(int size)
6556 {
6557 for(int i = 0; i < total_rows; i++)
6558 hitems[i].max = size;
6559
6560 return *this;
6561 }
6562
GotFocus()6563 void GridCtrl::GotFocus()
6564 {
6565 LG(3, "GotFocus");
6566 RestoreFocus();
6567 if(valid_cursor)
6568 RefreshRow(curpos.y, 0, 0);
6569 }
6570
LostFocus()6571 void GridCtrl::LostFocus()
6572 {
6573 LG(3, "LostFocus");
6574 if(valid_cursor)
6575 RefreshRow(curpos.y, 0, 0);
6576 popup.Close();
6577 }
6578
ChildGotFocus()6579 void GridCtrl::ChildGotFocus()
6580 {
6581 LG(3, "ChildGotFocus");
6582 if(valid_cursor)
6583 RefreshRow(curpos.y, 0, 0);
6584 Ctrl::ChildGotFocus();
6585 }
6586
ChildLostFocus()6587 void GridCtrl::ChildLostFocus()
6588 {
6589 LG(3, "ChildLostFocus");
6590 if(valid_cursor)
6591 {
6592 //if(focus_lost_accepting && !HasFocusDeep())
6593 // EndEdit();
6594 RefreshRow(curpos.y, 0, 0);
6595 }
6596 Ctrl::ChildLostFocus();
6597 }
6598
Repaint(bool do_recalc_cols,bool do_recalc_rows,int opt)6599 void GridCtrl::Repaint(bool do_recalc_cols /* = false*/, bool do_recalc_rows /* = false*/, int opt)
6600 {
6601 if(do_recalc_cols)
6602 {
6603 if(ready)
6604 {
6605 UpdateCols(true);
6606 firstCol = fixed_cols;
6607 }
6608 else
6609 recalc_cols = true;
6610 }
6611
6612 if(do_recalc_rows)
6613 {
6614 if(ready)
6615 {
6616 UpdateRows(true);
6617 firstRow = fixed_rows;
6618 }
6619 else
6620 recalc_rows = true;
6621 }
6622
6623 if(ready)
6624 {
6625 doscroll = false;
6626 UpdateSizes();
6627 UpdateSb();
6628 UpdateHolder();
6629 UpdateSummary();
6630 if(opt & RP_UPDCTRLS)
6631 UpdateCtrls();
6632 SyncCtrls();
6633 if(opt & RP_TOOLBAR)
6634 RebuildToolBar();
6635 doscroll = true;
6636 Refresh();
6637 }
6638 }
6639
Ready(bool b)6640 void GridCtrl::Ready(bool b)
6641 {
6642 ready = b;
6643 if(b)
6644 Repaint(true);
6645 }
6646
ResizeColMode(int m)6647 GridCtrl& GridCtrl::ResizeColMode(int m)
6648 {
6649 resize_col_mode = m;
6650 recalc_cols = true;
6651 RefreshLayout();
6652 return *this;
6653 }
6654
ResizeRowMode(int m)6655 GridCtrl& GridCtrl::ResizeRowMode(int m)
6656 {
6657 resize_row_mode = m;
6658 recalc_rows = true;
6659 RefreshLayout();
6660 return *this;
6661 }
6662
UpdateSb(bool horz,bool vert)6663 void GridCtrl::UpdateSb(bool horz, bool vert)
6664 {
6665 scrollbox.Width(ScrollBarSize());
6666
6667 if(horz)
6668 {
6669 sbx.SetTotal(resize_col_mode == 0 ? total_width - fixed_width : 0);
6670 sbx.SetPage(GetSize().cx - fixed_width);
6671 }
6672
6673 if(vert)
6674 {
6675 sby.SetTotal(resize_row_mode == 0 ? total_height - fixed_height + summary_height : 0);
6676 sby.SetPage(GetSize().cy - fixed_height);
6677 }
6678
6679 sbx.SetFrame(resize_row_mode == 0 && sby.GetTotal() > GetSize().cy - fixed_height ? scrollbox : NullFrame());
6680 }
6681
SwitchEdit()6682 bool GridCtrl::SwitchEdit()
6683 {
6684 if(!valid_cursor)
6685 return false;
6686
6687 Ctrl * ctrl = items[curid.y][curid.x].ctrl;
6688 if(ctrl)
6689 {
6690 if(ctrl->HasFocusDeep())
6691 EndEdit(true, true);
6692 SetFocus();
6693 rowbkp[curid.x] = ctrl->GetData();
6694 //items[curid.y][curid.x].val = ctrl->GetData();
6695 focused_ctrl = ctrl;
6696 focused_ctrl_id = curid.x;
6697 focused_ctrl_val = ctrl->GetData();
6698 ctrl->SetFocus();
6699 }
6700 else
6701 {
6702 if(isedit)
6703 EndEdit(true, true);
6704 else
6705 StartEdit();
6706 }
6707 return true;
6708 }
6709
StartEdit()6710 bool GridCtrl::StartEdit()
6711 {
6712 if(!valid_cursor || !IsRowEditable())
6713 return false;
6714
6715 WhenStartEdit();
6716
6717 SetCtrlsData();
6718 UpdateCtrls(UC_SHOW | UC_CURSOR | UC_CTRLS | (goto_first_edit ? UC_GOFIRST : 0));
6719 return true;
6720 }
6721
EndEdit(bool accept,bool doall,bool remove_row)6722 bool GridCtrl::EndEdit(bool accept, bool doall, bool remove_row)
6723 {
6724 if(!valid_cursor)
6725 return true;
6726
6727 if(accept && !GetCtrlsData(false, doall, accept))
6728 return false;
6729
6730 UpdateCtrls(UC_CTRLS);
6731
6732 if(!accept)
6733 {
6734 CancelCtrlsData();
6735 if(newrow_inserted || newrow_appended)
6736 {
6737 newrow_inserted = false;
6738 newrow_appended = false;
6739 if(remove_row)
6740 {
6741 WhenCancelNewRow();
6742 Remove0(curpos.y, 1, true, true, false);
6743 }
6744 }
6745 }
6746 WhenEndEdit();
6747 SyncSummary();
6748 return true;
6749 }
6750
Insert0(int row,int cnt,bool recalc,bool refresh,int size)6751 void GridCtrl::Insert0(int row, int cnt /* = 1*/, bool recalc /* = true*/, bool refresh /* = true*/, int size /* = GD_ROW_HEIGHT*/)
6752 {
6753 int id;
6754
6755 if(size < 0)
6756 size = GD_ROW_HEIGHT;
6757
6758 if(row < total_rows)
6759 {
6760 id = vitems[row].id;
6761 for(int i = 0; i < total_rows; i++)
6762 {
6763 if(vitems[i].id >= id)
6764 vitems[i].id += cnt;
6765 }
6766 }
6767 else
6768 id = total_rows;
6769
6770 ItemRect ir;
6771 ir.size = size;
6772 vitems.Insert(row, ir, cnt);
6773 items.InsertN(id, cnt);
6774
6775 for(int i = 0; i < cnt; i++)
6776 {
6777 int nid = id + i;
6778 int r = row + i;
6779 vitems[r].id = nid;
6780 vitems[r].uid = rowuid++;
6781 vitems[r].items = &items;
6782 vitems[r].operation = ready ? GridOperation::INSERT : GridOperation::NONE;
6783 items[nid].SetCount(total_cols);
6784 UpdateDefaults(nid);
6785 rowidx = r;
6786 total_rows++;
6787 WhenCreateRow();
6788 }
6789
6790 UpdateJoins(row, -1, cnt);
6791
6792 firstRow = -1;
6793
6794 if(recalc)
6795 {
6796 if(ready)
6797 {
6798 RecalcRows();
6799 UpdateSizes();
6800
6801 if(refresh)
6802 {
6803 UpdateSb();
6804 SyncSummary();
6805 SyncCtrls();
6806 RefreshFrom(row);
6807 }
6808 }
6809 else
6810 recalc_rows = true;
6811 }
6812
6813 SetOrder();
6814 SetModify();
6815 }
6816
Remove0(int row,int cnt,bool recalc,bool refresh,bool whens)6817 bool GridCtrl::Remove0(int row, int cnt /* = 1*/, bool recalc /* = true*/, bool refresh /* = true*/, bool whens /* = true*/)
6818 {
6819 if(cnt < 0)
6820 return false;
6821
6822 bool cancel = true;
6823 int x = -1;
6824 int y = -1;
6825
6826 for(int i = 0; i < cnt; i++)
6827 {
6828 int rid = row + i;
6829 rowidx = remove_hides ? rid : row;
6830
6831 if(vitems[rowidx].locked)
6832 continue;
6833
6834 int id = vitems[rowidx].id;
6835 int op = vitems[rowidx].operation;
6836
6837 vitems[rowidx].operation = GridOperation::REMOVE;
6838
6839 if(remove_hides)
6840 {
6841 vitems[rowidx].hidden = true;
6842 vitems[rowidx].tsize = vitems[rowidx].size;
6843 vitems[rowidx].size = 0;
6844 vitems[rowidx].nsize = 0;
6845 //for this row in hitems selected flag should be cleared too
6846 }
6847
6848 if(whens)
6849 {
6850 if(call_whenremoverow)
6851 {
6852 #ifdef LOG_CALLBACKS
6853 LGR(2, "WhenRemoveRow()");
6854 LGR(2, Format("[row: %d]", rowidx));
6855 #endif
6856 WhenRemoveRow();
6857 }
6858
6859 if(cancel_remove)
6860 {
6861 vitems[rowidx].operation = op;
6862 cancel_remove = false;
6863 cancel = false;
6864 if(i == cnt - 1)
6865 return cancel;
6866 else
6867 continue;
6868 }
6869 if(call_whenremoverow)
6870 WhenAcceptRow();
6871 }
6872
6873 if(vitems[rowidx].IsSelect())
6874 {
6875 int si = 0;
6876 for(int j = fixed_cols; j < total_cols; j++)
6877 if(GetItem(rowidx, j).IsSelect())
6878 si++;
6879
6880 selected_items -= si;
6881 selected_rows -= 1;
6882 }
6883
6884 if(!remove_hides)
6885 {
6886 for(int j = 0; j < total_rows; j++)
6887 if(vitems[j].id > id)
6888 vitems[j].id--;
6889 }
6890 else
6891 vitems[rowidx].style = 0; //bo IsSelect korzysta z pola style
6892
6893
6894 total_height -= vitems[rowidx].nHeight();
6895
6896 if(rid == ctrlid.y)
6897 UpdateCtrls(UC_HIDE | UC_CTRLS);
6898
6899 bool removed = false;
6900
6901 if(!remove_hides)
6902 {
6903 total_rows--;
6904 vitems.Remove(rowidx);
6905 items.Remove(id);
6906 removed = true;
6907 }
6908
6909 if(rid == curpos.y)
6910 {
6911 x = curpos.x;
6912 y = remove_hides ? curpos.y + cnt : curpos.y;
6913 ClearCursor(true);
6914 }
6915
6916 if(rid == oldcur.y)
6917 {
6918 oldcur.x = oldcur.y = -1;
6919 }
6920
6921 if(whens && removed)
6922 WhenRemovedRow();
6923 }
6924
6925 if(recalc)
6926 {
6927 if(ready)
6928 {
6929 RecalcRows();
6930 UpdateSizes();
6931
6932 if(refresh)
6933 {
6934 UpdateSb();
6935 SyncSummary();
6936 SyncCtrls();
6937 RefreshFrom(row);
6938
6939 if(x >= 0 && y >= 0)
6940 SetCursor0(x, max(fixed_rows, min(total_rows - 1, y)), 0, 0, -1);
6941
6942 if(!valid_cursor)
6943 RebuildToolBar();
6944 }
6945 }
6946 else
6947 {
6948 UpdateVisColRow(false);
6949 recalc_rows = true;
6950 }
6951 }
6952
6953 firstRow = -1;
6954
6955 if(IsEmpty())
6956 {
6957 WhenEmpty();
6958 WhenCursor();
6959 }
6960
6961 SetOrder();
6962 SetModify();
6963 return cancel;
6964 }
6965
Append0(int cnt,int size,bool refresh)6966 int GridCtrl::Append0(int cnt, int size, bool refresh)
6967 {
6968 if(size < 0)
6969 size = GD_ROW_HEIGHT;
6970
6971 vitems.AddN(cnt);
6972 items.AddN(cnt);
6973
6974 int j = total_rows;
6975 int k = j;
6976 int n = j > 0 ? vitems[j - 1].n + (int) vitems[j - 1].hidden : 0;
6977 for(int i = 0; i < cnt; i++)
6978 {
6979 ItemRect &ir = vitems[j];
6980 ir.parent = this;
6981 ir.items = &items;
6982 ir.size = ir.nsize = size;
6983 ir.operation = ready ? GridOperation::INSERT : GridOperation::NONE;
6984
6985 if(total_rows > 0)
6986 {
6987 ir.pos = ir.npos = vitems[j - 1].nBottom();
6988 ir.n = n;
6989 }
6990
6991 if(size == 0)
6992 ir.hidden = true;
6993 else
6994 {
6995 lastVisRow = j;
6996 if(firstVisRow < 0)
6997 firstVisRow = lastVisRow;
6998 }
6999
7000 items[j].SetCount(total_cols);
7001 ir.id = j++;
7002 ir.uid = rowuid++;
7003 UpdateDefaults(ir.id);
7004 rowidx = j - 1;
7005 total_rows = j;
7006 WhenCreateRow();
7007 }
7008
7009 total_height += size * cnt;
7010
7011 if(refresh && ready)
7012 {
7013 if(resize_row_mode > 0)
7014 UpdateRows(true);
7015 UpdateSb();
7016 SyncSummary();
7017 SyncCtrls();
7018 RefreshFrom(k);
7019 }
7020
7021 SetOrder();
7022 SetModify();
7023 return total_rows - fixed_rows;
7024 }
7025
Duplicate0(int row,int cnt,bool recalc,bool refresh)7026 bool GridCtrl::Duplicate0(int row, int cnt, bool recalc, bool refresh)
7027 {
7028 int id;
7029 int nrow = row + cnt;
7030
7031 if(nrow < total_rows)
7032 {
7033 id = vitems[nrow].id;
7034 for(int i = 0; i < total_rows; i++)
7035 {
7036 if(vitems[i].id >= id)
7037 vitems[i].id += cnt;
7038 }
7039 }
7040 else
7041 id = total_rows;
7042
7043 ItemRect ir;
7044 vitems.Insert(nrow, ir, cnt);
7045 items.InsertN(id, cnt);
7046
7047 int duplicated = 0;
7048
7049 for(int i = 0; i < cnt; i++)
7050 {
7051 int nid = id + i;
7052 int r = nrow + i;
7053 vitems[r].id = nid;
7054 vitems[r].uid = rowuid++;
7055 vitems[r].items = &items;
7056 vitems[r].size = vitems[row + i].size;
7057 items[nid].SetCount(total_cols);
7058
7059 int oid = vitems[row + i].id;
7060 for(int j = 1; j < total_cols; j++)
7061 items[nid][j].val = items[oid][j].val;
7062
7063 rowidx = r;
7064 total_rows++;
7065 WhenCreateRow();
7066
7067 duplicated++;
7068 WhenDuplicateRow();
7069 if(cancel_duplicate)
7070 {
7071 duplicated--;
7072 Remove0(r, 1, false, false, false);
7073 cancel_duplicate = false;
7074 }
7075
7076 }
7077
7078 firstRow = -1;
7079
7080 if(recalc)
7081 {
7082 if(ready)
7083 {
7084 RecalcRows();
7085 UpdateSizes();
7086
7087 if(refresh)
7088 {
7089 UpdateSb();
7090 SyncSummary();
7091 SyncCtrls();
7092 RefreshFrom(nrow);
7093 }
7094 }
7095 else
7096 recalc_rows = true;
7097 }
7098
7099 if(duplicated > 0)
7100 {
7101 SetOrder();
7102 SetModify();
7103 }
7104
7105 return duplicated > 0;
7106 }
7107
Append(int cnt,bool refresh,int height)7108 int GridCtrl::Append(int cnt, bool refresh, int height)
7109 {
7110 return Append0(cnt, height, refresh);
7111 }
7112
Insert(int i,int cnt)7113 void GridCtrl::Insert(int i, int cnt)
7114 {
7115 Insert0(fixed_rows + i, cnt);
7116 }
7117
Remove(int i,int cnt)7118 void GridCtrl::Remove(int i, int cnt)
7119 {
7120 Remove0(i < 0 ? rowidx : fixed_rows + i, cnt);
7121 }
7122
RemoveFirst(int cnt)7123 void GridCtrl::RemoveFirst(int cnt /* = 1*/)
7124 {
7125 Remove0(fixed_rows, min(total_rows - fixed_rows, cnt));
7126 }
7127
RemoveLast(int cnt)7128 void GridCtrl::RemoveLast(int cnt /* = 1*/)
7129 {
7130 Remove0(total_rows - cnt, min(total_rows - fixed_rows, cnt));
7131 }
7132
Duplicate(int i,int cnt)7133 void GridCtrl::Duplicate(int i, int cnt)
7134 {
7135 Duplicate0(fixed_rows + i, cnt);
7136 }
7137
Select(int n,int cnt)7138 void GridCtrl::Select(int n, int cnt /* = 1*/)
7139 {
7140 SelectCount(n + fixed_rows, cnt, true);
7141 }
7142
SelectCount(int i,int cnt,bool sel)7143 void GridCtrl::SelectCount(int i, int cnt, bool sel)
7144 {
7145 if(cnt <= 0)
7146 return;
7147 SelectRange(Point(fixed_cols, i), Point(total_cols - 1, i + cnt - 1), sel);
7148 }
7149
SelectRange(int from,int to,bool sel)7150 void GridCtrl::SelectRange(int from, int to, bool sel)
7151 {
7152 SelectRange(Point(fixed_cols, from), Point(total_cols - 1, to), sel);
7153 }
7154
ShiftSelect(int from,int to)7155 void GridCtrl::ShiftSelect(int from, int to)
7156 {
7157 ShiftSelect(Point(fixed_cols, from), Point(total_cols - 1, to));
7158 }
7159
SelectRange(Point from,Point to,bool sel,bool fullrow)7160 void GridCtrl::SelectRange(Point from, Point to, bool sel /* = true*/, bool fullrow /* = false*/)
7161 {
7162 Point f, t;
7163
7164 if(fullrow)
7165 {
7166 from.x = fixed_cols;
7167 to.x = total_cols - 1;
7168 }
7169
7170 if(from.y < to.y)
7171 {
7172 f = from;
7173 t = to;
7174 }
7175 else
7176 {
7177 f = to;
7178 t = from;
7179 }
7180
7181 int ymin = f.y;
7182 int ymax = t.y;
7183
7184 int xmin = f.x;
7185 int xmax = t.x;
7186
7187 if(xmin > xmax)
7188 {
7189 int t = xmin;
7190 xmin = xmax;
7191 xmax = t;
7192 }
7193
7194 for(int i = ymin; i <= ymax; i++)
7195 {
7196 ItemRect &ir = vitems[i];
7197 int yid = ir.id;
7198
7199 bool is_row_selected = false;
7200 bool do_refresh = false;
7201
7202 for(int j = fixed_cols; j < total_cols; j++)
7203 {
7204 int xid = hitems[j].id;
7205 Item &it = items[yid][xid];
7206
7207 if(j >= xmin && j <= xmax)
7208 {
7209 if(it.IsSelect() != sel)
7210 {
7211 it.Select(sel);
7212 do_refresh = true;
7213 }
7214 if(sel)
7215 {
7216 is_row_selected = true;
7217 selected_items++;
7218 }
7219 else
7220 selected_items--;
7221 }
7222 else if(it.IsSelect())
7223 is_row_selected = true;
7224 }
7225
7226 if(!ir.IsSelect())
7227 {
7228 if(is_row_selected)
7229 selected_rows++;
7230 }
7231 else if(!is_row_selected)
7232 selected_rows--;
7233
7234 ir.Select(is_row_selected);
7235
7236 if(do_refresh)
7237 RefreshRow(i, false, false);
7238
7239 }
7240 }
7241
SelectInverse(int from,int to)7242 void GridCtrl::SelectInverse(int from, int to)
7243 {
7244 int nfrom = min(from, to);
7245 int nto = max(from, to);
7246
7247 for(int i = nfrom ; i <= nto; i++)
7248 {
7249 vitems[i].Select(!vitems[i].IsSelect());
7250 if(vitems[i].IsSelect())
7251 selected_rows++;
7252 else
7253 selected_rows--;
7254 RefreshRow(i, 0);
7255 }
7256 }
7257
ShiftSelect(Point from,Point to)7258 void GridCtrl::ShiftSelect(Point from, Point to)
7259 {
7260 Point f, t;
7261
7262 if(from.y < to.y)
7263 {
7264 f = from;
7265 t = to;
7266 }
7267 else
7268 {
7269 f = to;
7270 t = from;
7271 }
7272
7273 if(select_row)
7274 {
7275 f.x = fixed_cols;
7276 t.x = total_cols;
7277 }
7278
7279 int ymin = f.y;
7280 int ymax = t.y;
7281
7282 int xmin = f.x;
7283 int xmax = t.x;
7284
7285 if(ymin == ymax && xmin > xmax)
7286 {
7287 int t = xmin;
7288 xmin = xmax;
7289 xmax = t;
7290 }
7291
7292 selected_rows = 0;
7293 selected_items = 0;
7294
7295 for(int i = fixed_rows; i < total_rows; i++)
7296 {
7297 ItemRect &ir = vitems[i];
7298 int yid = ir.id;
7299
7300 bool is_row_selected = false;
7301 bool do_refresh = false;
7302
7303 if((i >= ymin && i <= ymax))
7304 {
7305 for(int j = fixed_cols; j < total_cols; j++)
7306 {
7307 int xid = hitems[j].id;
7308
7309 bool s = true;
7310 if(i == ymin && ymin == ymax)
7311 s = (j >= xmin && j <= xmax);
7312 else if(i == ymin) s = (j >= xmin);
7313 else if(i == ymax) s = (j <= xmax);
7314
7315 if(items[yid][xid].IsSelect() != s)
7316 {
7317 items[yid][xid].Select(s);
7318 do_refresh = true;
7319 }
7320 if(s)
7321 {
7322 is_row_selected = true;
7323 selected_items++;
7324 }
7325 }
7326 }
7327 else
7328 {
7329 for(int j = fixed_cols; j < total_cols; j++)
7330 if(items[yid][j].IsSelect())
7331 {
7332 items[yid][j].Select(false);
7333 do_refresh = true;
7334 }
7335 }
7336
7337 if(is_row_selected)
7338 selected_rows++;
7339
7340 ir.Select(is_row_selected);
7341
7342 if(do_refresh)
7343 RefreshRow(i, false, false);
7344 }
7345 }
7346
DoShiftSelect()7347 void GridCtrl::DoShiftSelect()
7348 {
7349 if(!shiftmode)
7350 {
7351 if(!IsValidCursor(oldcur))
7352 return;
7353 shiftpos = oldcur;
7354 shiftmode = true;
7355 ShiftSelect(oldcur, curpos);
7356 }
7357 else
7358 ShiftSelect(shiftpos, curpos);
7359 }
7360
DoCtrlSelect()7361 void GridCtrl::DoCtrlSelect()
7362 {
7363 if(!IsValidCursor(oldcur))
7364 return;
7365
7366 if(shiftmode && !select_row)
7367 {
7368 ClearSelection();
7369 shiftpos = oldcur;
7370 }
7371
7372 if(!IsValidCursor(shiftpos))
7373 shiftpos = oldcur;
7374
7375 SelectRange(shiftpos, oldcur, false, select_row);
7376 SelectRange(shiftpos, curpos, true, select_row);
7377 }
7378
IsSelected(int n,bool relative)7379 bool GridCtrl::IsSelected(int n, bool relative)
7380 {
7381 //int id = vitems[n + (relative ? fixed_rows : 0)].id;
7382 int id = n + (relative ? fixed_rows : 0);
7383 return vitems[id].IsSelect() || vitems[id].IsCursor();
7384 }
7385
IsSelected(int n,int m,bool relative)7386 bool GridCtrl::IsSelected(int n, int m, bool relative)
7387 {
7388 int r = relative ? fixed_rows + n : n;
7389 int c = relative ? fixed_cols + m : m;
7390 Item &it = GetItem(r, c);
7391 return it.IsSelect() || it.IsCursor();
7392 }
7393
IsSelected()7394 bool GridCtrl::IsSelected()
7395 {
7396 return IsSelected(rowidx, false);
7397 }
7398
ClearSelection()7399 void GridCtrl::ClearSelection()
7400 {
7401 LG(0, "Cleared %d", selected_rows);
7402 shiftmode = false;
7403 shiftpos = curpos;
7404 if(selected_rows > 0)
7405 {
7406 for(int i = fixed_rows; i < total_rows; i++)
7407 {
7408 vitems[i].Select(0);
7409 for(int j = fixed_cols; j < total_cols; j++)
7410 items[i][j].Select(0);
7411 }
7412
7413 Refresh();
7414 selected_rows = 0;
7415 selected_items = 0;
7416 }
7417 }
7418
DoInsert0(bool edit,bool after)7419 void GridCtrl::DoInsert0(bool edit, bool after)
7420 {
7421 if(!valid_cursor)
7422 return;
7423
7424 if(!EndEdit())
7425 return;
7426
7427 SetItemCursor(curpos, false, false);
7428 RefreshRow(curpos.y, false);
7429 curpos.y += int(after);
7430 Insert0(curpos.y, 1, true, true, GD_ROW_HEIGHT);
7431 int y = curpos.y;
7432 curpos.y = -1;
7433 valid_cursor = false;
7434 call_whenchangecol = false;
7435 call_whenchangerow = false;
7436 SetCursor0(curpos.x, y > total_rows - 1 ? total_rows - 1 : y);
7437 call_whenchangecol = true;
7438 call_whenchangerow = true;
7439
7440 newrow_inserted = true;
7441
7442 if(edit)
7443 StartEdit();
7444
7445 if(!isedit)
7446 WhenInsertRow0();
7447
7448 WhenNewRow();
7449
7450 if(!edit)
7451 newrow_inserted = false;
7452 }
7453
DoInsertBefore0(bool edit)7454 void GridCtrl::DoInsertBefore0(bool edit)
7455 {
7456 DoInsert0(edit, false);
7457 }
7458
DoInsertAfter0(bool edit)7459 void GridCtrl::DoInsertAfter0(bool edit)
7460 {
7461 DoInsert0(edit, true);
7462 }
7463
DoDuplicate0()7464 void GridCtrl::DoDuplicate0()
7465 {
7466 int cy = 0;
7467 if(selected_rows == 0)
7468 {
7469 if(!valid_cursor)
7470 return;
7471 cy = curpos.y + 1;
7472 if(!Duplicate0(curpos.y, 1, false, false))
7473 cy = 0;
7474 }
7475 else if(!multi_select)
7476 {
7477 cy = GetMinRowSelected() + selected_rows * 2 - 1;
7478 if(!Duplicate0(GetMinRowSelected(), selected_rows, false, false))
7479 cy = 0;
7480 }
7481
7482 if(cy > 0)
7483 {
7484 Repaint(false, true);
7485 SetCursor0(curpos.x < 0 ? firstVisCol : curpos.x, max(fixed_rows, min(total_rows - 1, cy)));
7486 }
7487 }
7488
DoRemove()7489 void GridCtrl::DoRemove()
7490 {
7491 if(keep_last_row && GetCount() == 1)
7492 return;
7493
7494 if(!valid_cursor && selected_rows == 0)
7495 return;
7496
7497 if(ask_remove)
7498 {
7499 if(!PromptYesNo(Format(t_("Do you really want to delete selected %s ?"), selected_rows > 1 ? t_("rows") : t_("row"))))
7500 return;
7501 }
7502
7503 bool newrow = IsNewRow();
7504 CancelEdit(false);
7505
7506 int y = curpos.y;
7507 int ocy = curpos.y;
7508
7509 if(selected_rows == 0)
7510 {
7511 //do not call WhenRemoveRow when not new (not inserted) row
7512 Remove0(curpos.y, 1, true, true, !newrow);
7513 }
7514 else
7515 {
7516 int not_removed = 0;
7517
7518 minRowSelected = GetMinRowSelected();
7519 maxRowSelected = GetMaxRowSelected();
7520
7521 if(keep_last_row && (maxRowSelected - minRowSelected + 1) == GetCount())
7522 maxRowSelected--;
7523
7524 LG(0, "Min:%d, Max:%d", minRowSelected, maxRowSelected);
7525
7526 for(int i = minRowSelected; i <= maxRowSelected; i++)
7527 {
7528 int rid = remove_hides ? i : minRowSelected + not_removed;
7529 if(vitems[rid].IsSelect())
7530 {
7531 sel_begin = i == minRowSelected;
7532 sel_end = i == maxRowSelected;
7533
7534 if(Remove0(rid, 1, false, false))
7535 {
7536 /* curpos.y tez sie zmienia bo gdy w whenromoverow jest woloanie innego okna to
7537 grid traci fokus i wola sie lostfoucs, ktory wymaga poprawnego curpos.y */
7538 if(i == ocy)
7539 y = curpos.y = rid - 1;
7540 }
7541 else
7542 not_removed++;
7543 }
7544 else
7545 not_removed++;
7546 }
7547 RecalcRows();
7548 //UpdateSizes();
7549 SyncCtrls();
7550 UpdateSb();
7551 Refresh();
7552 curpos.y = -1;
7553 valid_cursor = false;
7554 SetCursor0(curpos.x < 0 ? firstVisCol : curpos.x, max(fixed_rows, min(total_rows - 1, y)), 0, 0, -1);
7555 shiftpos = curpos;
7556 }
7557 }
7558
DoAppend0(bool edit)7559 void GridCtrl::DoAppend0(bool edit)
7560 {
7561 if(!EndEdit())
7562 return; //powinno byc zakomentowane ale wtedy goend wola endedit ale juz dla rowidx wiekszego o 1..
7563
7564 Append0(1, GD_ROW_HEIGHT, true);
7565
7566 call_whenchangecol = false;
7567 call_whenchangerow = false;
7568 GoEnd(true, true);
7569 call_whenchangecol = true;
7570 call_whenchangerow = true;
7571
7572 newrow_appended = true;
7573
7574 if(edit)
7575 {
7576 StartEdit();
7577 GoCursorLeftRight();
7578 }
7579
7580 if(!isedit)
7581 WhenInsertRow0();
7582
7583 WhenNewRow();
7584
7585 if(!edit)
7586 newrow_appended = false;
7587
7588 }
7589
DoAppend()7590 void GridCtrl::DoAppend() { DoAppend0(edits_in_new_row); }
DoAppendNoEdit()7591 void GridCtrl::DoAppendNoEdit() { DoAppend0(0); }
DoInsertBefore()7592 void GridCtrl::DoInsertBefore() { DoInsertBefore0(1); }
DoInsertBeforeNoEdit()7593 void GridCtrl::DoInsertBeforeNoEdit() { DoInsertBefore0(0); }
DoInsertAfter()7594 void GridCtrl::DoInsertAfter() { DoInsertAfter0(1); }
DoInsertAfterNoEdit()7595 void GridCtrl::DoInsertAfterNoEdit() { DoInsertAfter0(0); }
DoDuplicate()7596 void GridCtrl::DoDuplicate() { DoDuplicate0(); }
DoEdit()7597 void GridCtrl::DoEdit() { StartEdit(); }
DoEndEdit()7598 void GridCtrl::DoEndEdit() { EndEdit(); }
DoCancelEdit()7599 void GridCtrl::DoCancelEdit() { EndEdit(false); }
DoSwapUp()7600 void GridCtrl::DoSwapUp() { SwapUp(); }
DoSwapDown()7601 void GridCtrl::DoSwapDown() { SwapDown(); }
DoGoBegin()7602 void GridCtrl::DoGoBegin() { GoBegin(); }
DoGoEnd()7603 void GridCtrl::DoGoEnd() { GoEnd(); }
DoGoNext()7604 void GridCtrl::DoGoNext() { GoNext(); }
DoGoPrev()7605 void GridCtrl::DoGoPrev() { GoPrev(); }
DoGoLeft()7606 void GridCtrl::DoGoLeft() { GoLeft(); }
DoGoRight()7607 void GridCtrl::DoGoRight() { GoRight(); }
DoGoPageUp()7608 void GridCtrl::DoGoPageUp() { GoPageUp(); }
DoGoPageDn()7609 void GridCtrl::DoGoPageDn() { GoPageDn(); }
7610
DoSelectAll()7611 void GridCtrl::DoSelectAll()
7612 {
7613 SelectCount(fixed_rows, total_rows - fixed_rows);
7614 }
7615
ShowRow(int n,bool refresh)7616 GridCtrl& GridCtrl::ShowRow(int n, bool refresh)
7617 {
7618 if(!vitems[n].hidden)
7619 return *this;
7620 vitems[n].hidden = false;
7621 vitems[n].size = vitems[n].tsize;
7622 if(refresh)
7623 Repaint(false, true);
7624
7625 return *this;
7626 }
7627
HideRow(int n,bool refresh)7628 GridCtrl& GridCtrl::HideRow(int n, bool refresh)
7629 {
7630 if(n < 0)
7631 n = rowidx;
7632
7633 if(vitems[n].hidden)
7634 return *this;
7635 vitems[n].hidden = true;
7636 vitems[n].tsize = vitems[n].size;
7637 vitems[n].size = 0;
7638 if(refresh)
7639 Repaint(false, true);
7640
7641 return *this;
7642 }
7643
ShowColumn(int n,bool refresh)7644 GridCtrl& GridCtrl::ShowColumn(int n, bool refresh)
7645 {
7646 if(!hitems[n].hidden)
7647 return *this;
7648 hitems[n].hidden = false;
7649 hitems[n].size = hitems[n].tsize;
7650 if(refresh)
7651 Repaint(true, false);
7652
7653 return *this;
7654 }
7655
HideColumn(int n,bool refresh)7656 GridCtrl& GridCtrl::HideColumn(int n, bool refresh)
7657 {
7658 if(hitems[n].hidden)
7659 return *this;
7660 hitems[n].hidden = true;
7661 hitems[n].tsize = hitems[n].size;
7662 if(refresh)
7663 Repaint(true, false);
7664
7665 return *this;
7666 }
7667
HideRows(bool repaint)7668 void GridCtrl::HideRows(bool repaint)
7669 {
7670 bool change = false;
7671 for(int i = fixed_rows; i < total_rows; i++)
7672 if(!vitems[i].hidden)
7673 {
7674 change = true;
7675 vitems[i].hidden = true;
7676 vitems[i].tsize = vitems[i].size;
7677 vitems[i].size = 0;
7678 }
7679 if(change || repaint)
7680 Repaint(false, true);
7681 }
7682
ShowRows(bool repaint)7683 void GridCtrl::ShowRows(bool repaint)
7684 {
7685 bool change = false;
7686 for(int i = fixed_rows; i < total_rows; i++)
7687 if(vitems[i].hidden)
7688 {
7689 change = true;
7690 vitems[i].hidden = false;
7691 vitems[i].size = vitems[i].tsize;
7692 }
7693 if(change || repaint)
7694 Repaint(false, true, UC_SCROLL);
7695 }
7696
MenuHideColumn(int n)7697 void GridCtrl::MenuHideColumn(int n)
7698 {
7699 if(hitems[n].hidden)
7700 ShowColumn(n);
7701 else
7702 HideColumn(n);
7703 }
7704
ShowMatchedRows(const WString & f)7705 int GridCtrl::ShowMatchedRows(const WString &f)
7706 {
7707 if(f.IsEmpty())
7708 {
7709 if(search_highlight)
7710 ClearFound();
7711 else
7712 ShowRows(true);
7713 return 0;
7714 }
7715
7716 if(!search_immediate && search_highlight)
7717 {
7718 ClearFound(true, false);
7719 //search_string = f;
7720 }
7721
7722 int first_matched_row = -1;
7723
7724 int s, e;
7725 for(int i = fixed_rows; i < total_rows; i++)
7726 {
7727 if(!vitems[i].clickable)
7728 continue;
7729
7730 int idv = vitems[i].id;
7731
7732 for(int j = fixed_cols; j < total_cols; j++)
7733 {
7734 int idh = hitems[j].id;
7735 Item &it = items[idv][idh];
7736 it.Found(false);
7737 it.fs = it.fe = 0;
7738
7739 if(hitems[j].hidden || !hitems[j].clickable)
7740 continue;
7741
7742 if(Match(f, (WString) GetStdConvertedColumn(idh, it.val), s, e))
7743 {
7744 first_matched_row = i;
7745 rowfnd = i;
7746 goto found_first_matched_row;
7747 }
7748 }
7749 }
7750
7751 if(first_matched_row < 0)
7752 return 0;
7753
7754 found_first_matched_row:
7755
7756 bool change = false;
7757
7758 int rows = 0;
7759 for(int i = fixed_rows; i < total_rows; i++)
7760 {
7761 if(!vitems[i].clickable)
7762 continue;
7763
7764 bool match = false;
7765 int idv = vitems[i].id;
7766 for(int j = fixed_cols; j < total_cols; j++)
7767 {
7768 int idh = hitems[j].id;
7769 Item &it = items[idv][idh];
7770 it.Found(false);
7771 it.fs = it.fe = 0;
7772
7773 if(hitems[j].hidden || !hitems[j].clickable)
7774 continue;
7775
7776 if(Match(f, (WString) GetStdConvertedColumn(idh, it.val), s, e))
7777 {
7778 match = true;
7779 it.Found(search_highlight);
7780 it.fs = s;
7781 it.fe = e;
7782
7783 if(!search_highlight)
7784 break;
7785 }
7786 }
7787
7788 if(match)
7789 {
7790 rows++;
7791 if(search_hide && vitems[i].hidden)
7792 {
7793 vitems[i].hidden = false;
7794 vitems[i].size = vitems[i].tsize;
7795 change = true;
7796 }
7797
7798 if(search_highlight_first)
7799 break;
7800 }
7801 else if(search_hide && !vitems[i].hidden)
7802 {
7803 vitems[i].hidden = true;
7804 vitems[i].tsize = vitems[i].size;
7805 vitems[i].size = 0;
7806 change = true;
7807 }
7808 vitems[i].found = match;
7809 }
7810
7811 if(rows > 0)
7812 {
7813 if(change || search_highlight)
7814 {
7815 LG(0, "Repaint %d", search_hide);
7816 Repaint(false, search_hide, 0);
7817 }
7818 }
7819 else if(search_hide)
7820 {
7821 for(int i = fixed_rows; i < total_rows; i++)
7822 {
7823 vitems[i].hidden = false;
7824 vitems[i].size = vitems[i].tsize;
7825 }
7826 }
7827
7828 if(search_move_cursor && first_matched_row >= 0)
7829 {
7830 SetCursor0(first_matched_row);
7831 CenterCursor();
7832 WhenSearchCursor();
7833 }
7834
7835 LG(0, "Matched rows %d", rows);
7836 return rows;
7837 }
7838
ClearFound(bool showrows,bool clear_string)7839 void GridCtrl::ClearFound(bool showrows, bool clear_string)
7840 {
7841 for(int i = 0; i < total_rows; i++)
7842 {
7843 vitems[i].found = false;
7844 for(int j = 0; j < total_cols; j++)
7845 {
7846 items[i][j].Found(false);
7847 items[i][j].fs = items[i][j].fe = 0;
7848 }
7849 }
7850 if(showrows)
7851 ShowRows(true);
7852
7853 if(clear_string)
7854 search_string.Clear();
7855
7856 WhenSearchCursor();
7857 }
7858
Match(const WString & f,const WString & s,int & fs,int & fe)7859 bool GridCtrl::Match(const WString &f, const WString &s, int &fs, int &fe)
7860 {
7861 int i = 0;
7862
7863 int fl = f.GetLength();
7864 int sl = s.GetLength();
7865
7866 if(fl > sl)
7867 return false;
7868
7869 for(int j = find_offset; j < sl; j++)
7870 {
7871 bool match;
7872 if(search_case)
7873 match = f[i] == s[j];
7874 else
7875 match = ToUpper(f[i]) == ToUpper(s[j]);
7876
7877 if(match)
7878 {
7879 if(++i == fl)
7880 {
7881 fs = j + 1 - fl;
7882 fe = j;
7883 return true;
7884 }
7885 }
7886 else
7887 i = 0;
7888 }
7889 return false;
7890 }
7891
DoFind()7892 void GridCtrl::DoFind()
7893 {
7894 UpdateCtrls(UC_CHECK_VIS | UC_HIDE | UC_CTRLS | UC_SCROLL | UC_NOFOCUS);
7895 ShowMatchedRows((WString) ~find);
7896 }
7897
WhenInsertRow0()7898 bool GridCtrl::WhenInsertRow0()
7899 {
7900 WhenInsertRow();
7901 if(cancel_insert)
7902 {
7903 WhenCancelNewRow();
7904 Remove0(curpos.y, 1, true, true, false);
7905 cancel_insert = false;
7906 return false;
7907 }
7908 return true;
7909 }
7910
GetMinRowSelected()7911 int GridCtrl::GetMinRowSelected()
7912 {
7913 int i = fixed_rows;
7914 while(i < total_rows && !vitems[i].IsSelect()) i++;
7915 return i > total_rows - 1 ? -1 : i;
7916 }
7917
GetMaxRowSelected()7918 int GridCtrl::GetMaxRowSelected()
7919 {
7920 int i = total_rows - 1;
7921 while(i >= fixed_rows && !vitems[i].IsSelect()) i--;
7922 return i < fixed_rows ? -1 : i;
7923 }
7924
CloseGrid()7925 void GridCtrl::CloseGrid()
7926 {
7927 GetTopWindow()->Close();
7928 }
7929
UpdateVisColRow(bool col)7930 void GridCtrl::UpdateVisColRow(bool col)
7931 {
7932 if(col)
7933 {
7934 firstVisCol = fixed_cols;
7935 lastVisCol = total_cols - 1;
7936
7937 for(int i = fixed_cols; i < total_cols; i++)
7938 if(!hitems[i].hidden)
7939 {
7940 firstVisCol = i;
7941 break;
7942 }
7943
7944 for(int i = total_cols - 1; i >= fixed_cols; i--)
7945 if(!hitems[i].hidden)
7946 {
7947 lastVisCol = i;
7948 break;
7949 }
7950 }
7951 else
7952 {
7953 firstVisRow = fixed_rows;
7954 lastVisRow = total_rows - 1;
7955
7956 for(int i = fixed_rows; i < total_rows; i++)
7957 if(!vitems[i].hidden)
7958 {
7959 firstVisRow = i;
7960 break;
7961 }
7962
7963 for(int i = total_rows - 1; i >= fixed_rows; i--)
7964 if(!vitems[i].hidden)
7965 {
7966 lastVisRow = i;
7967 break;
7968 }
7969 }
7970 }
7971
GetBarOffset()7972 Point GridCtrl::GetBarOffset()
7973 {
7974 Size bsz = bar.GetSize();
7975 return Point(bar.GetAlign() == BarCtrl::BAR_LEFT ? bsz.cx : 0,
7976 bar.GetAlign() == BarCtrl::BAR_TOP ? bsz.cy : 0);
7977 }
7978
ClearModified()7979 void GridCtrl::ClearModified()
7980 {
7981 row_modified = 0;
7982 for(int i = 0; i < total_cols; ++i)
7983 items[curid.y][i].modified = false;
7984 }
7985
Debug(int n)7986 void GridCtrl::Debug(int n)
7987 {
7988 if(n == 0)
7989 {
7990 LG("---- DEBUG 0 ----------");
7991 LG("firstVisCol %d", firstVisCol);
7992 LG("lastVisCol %d", lastVisCol);
7993 LG("firstVisRow %d", firstVisRow);
7994 LG("lastVisRow %d", lastVisRow);
7995 LG("firstCol %d", firstCol);
7996 LG("firstRow %d", firstRow);
7997 LG("lastCol %d", lastCol);
7998 LG("lastRow %d", lastRow);
7999 LG("total_cols %d", total_cols);
8000 LG("total_rows %d", total_rows);
8001 LG("curpos %d, %d", curpos.x, curpos.y);
8002 LG("sbPos %d, %d", sbx.Get(), sby.Get());
8003 LG("sbTotal %d, %d", sbx.GetTotal(), sby.GetTotal());
8004 LG("sbPage %d, %d", sbx.GetPage(), sby.GetPage());
8005 LG("Size %d, %d", GetSize().cx, GetSize().cy);
8006 LG("fixed_width %d", fixed_width);
8007 LG("fixed_height %d", fixed_height);
8008 LG("total_width %d", total_width);
8009 LG("total_height %d", total_height);
8010 LG("row_modified %d", row_modified);
8011 LG("selected_rows %d", selected_rows);
8012 LG("selected_items %d", selected_items);
8013 LG("---- END --------------");
8014 }
8015 if(n == 1)
8016 {
8017 LG("---- DEBUG 1 ----------");
8018 for(int i = 0; i < total_cols; i++)
8019 {
8020 LG("Col %d h:%d p:%d s:%d", i, hitems[i].hidden, hitems[i].npos, hitems[i].nsize);
8021 //LG("ismin %d ismax %d", hitems[i].ismin, hitems[i].ismax);
8022 }
8023 LG("---- END --------------");
8024 }
8025 if(n == 2)
8026 {
8027 LG("---- DEBUG 2 ----------");
8028 for(int i = 0; i < total_rows; i++)
8029 {
8030 LG("Row %d p:%d s:%d", i, vitems[i].npos, vitems[i].nsize);
8031 }
8032 LG("---- END --------------");
8033 }
8034 if(n == 3)
8035 {
8036 Point p = GetCtrlPos(focused_ctrl);
8037 LG(2, "Focused %x (%d, %d)", focused_ctrl, p.x, p.y);
8038 }
8039 }
8040
Serialize(Stream & s)8041 void GridCtrl::Serialize(Stream &s)
8042 {
8043 if(s.IsStoring())
8044 {
8045 s % total_cols;
8046 for(int i = 1; i < total_cols; i++)
8047 {
8048 int id = hitems[i].id;
8049 //s % String(aliases[id]);
8050 s % id;
8051 s % hitems[id];
8052 }
8053 }
8054 else
8055 {
8056 int tc;
8057 s % tc;
8058 for(int i = 1; i < tc; i++)
8059 {
8060 //String alias;
8061 //s % alias;
8062 //int n = aliases.Find(alias);
8063 int id;
8064 s % id;
8065 //if(id >= 0 && id < total_cols)
8066 s % hitems[id];
8067 }
8068 }
8069 }
8070
JoinCells(int left,int top,int right,int bottom,bool relative)8071 void GridCtrl::JoinCells(int left, int top, int right, int bottom, bool relative)
8072 {
8073 int fc = relative ? fixed_cols : 0;
8074 int fr = relative ? fixed_rows : 0;
8075
8076 left += fc;
8077 top += fr;
8078 right += fc;
8079 bottom += fr;
8080
8081 int idx = hitems[left].id;
8082 int idy = vitems[top].id;
8083 int cx = right - left;
8084 int cy = bottom - top;
8085
8086 for(int i = top; i <= bottom; ++i)
8087 {
8088 vitems[i].join++;
8089
8090 for(int j = left; j <= right; ++j)
8091 {
8092 Item &it = items[i][j];
8093
8094 it.idx = idx;
8095 it.idy = idy;
8096 it.cx = cx;
8097 it.cy = cy;
8098 it.group = join_group;
8099 it.isjoined = true;
8100
8101 if(i == top)
8102 hitems[j].join++;
8103 }
8104 }
8105
8106 JoinRect& jr = joins.Add();
8107 jr.r.Set(left, top, right, bottom);
8108 jr.group = join_group;
8109 jr.idx = idx;
8110 jr.idy = idy;
8111
8112 join_group++;
8113 }
8114
JoinFixedCells(int left,int top,int right,int bottom)8115 void GridCtrl::JoinFixedCells(int left, int top, int right, int bottom)
8116 {
8117 JoinCells(left, top, right, bottom, false);
8118 }
8119
JoinRow(int n,int left,int right)8120 void GridCtrl::JoinRow(int n, int left, int right)
8121 {
8122 if(n < 0)
8123 n = rowidx;
8124
8125 if(left < 0)
8126 left = fixed_cols;
8127 else
8128 left += fixed_cols;
8129
8130 if(right < 0)
8131 right = total_cols - fixed_cols;
8132 else
8133 right = total_cols - fixed_cols - right;
8134
8135 JoinCells(left, n, right, n, false);
8136 }
8137
JoinRow(int left,int right)8138 void GridCtrl::JoinRow(int left, int right)
8139 {
8140 JoinRow(-1, left, right);
8141 }
8142
8143 /*
8144
8145 jr.r.top = 2;
8146 jr.r.bottom = 6
8147
8148 2 -----------------------
8149 3 -----------------------
8150 +++++++++++++++++++++++ //insert at 4
8151 +++++++++++++++++++++++
8152 4 -----------------------
8153 5 -----------------------
8154 6 -----------------------
8155
8156 */
8157
UpdateJoins(int row,int col,int cnt)8158 void GridCtrl::UpdateJoins(int row, int col, int cnt)
8159 {
8160 if(row >= 0)
8161 {
8162 for(int i = 0; i < joins.GetCount(); i++)
8163 {
8164 JoinRect& jr = joins[i];
8165
8166 int top = jr.r.top;
8167 int bottom = jr.r.bottom;
8168
8169 if(row > top && row < bottom) // new row is inside cell rect, idy doesn't change but cy does
8170 {
8171 for(int r = jr.r.top; r <= jr.r.bottom; r++)
8172 {
8173 for(int c = jr.r.left; c <= jr.r.right; c++)
8174 {
8175 if(r < row || r > row)
8176 {
8177 Item& it = GetItem(r, c);
8178 it.cy += cnt;
8179 }
8180 else if(r == row)
8181 {
8182 for(int n = 0; n < cnt; n++)
8183 {
8184 Item& it = GetItem(r + n, c);
8185 it.group = jr.group;
8186 it.idx = jr.idx;
8187 it.idy = jr.idy;
8188 it.cx = jr.r.Width();
8189 it.cy = jr.r.Height() + cnt;
8190 it.isjoined = true;
8191
8192 if(c == jr.r.left)
8193 vitems[r + n].join++;
8194 }
8195 }
8196 }
8197 }
8198
8199 jr.r.bottom += cnt;
8200 }
8201 else if(row <= top) // idy changes
8202 {
8203 jr.idy += cnt;
8204
8205 for(int r = jr.r.top; r <= jr.r.bottom; r++)
8206 {
8207 for(int c = jr.r.left; c <= jr.r.right; c++)
8208 {
8209 Item& it = GetItem(r + cnt, c);
8210 it.idy = jr.idy;
8211 }
8212 }
8213
8214 jr.r.top += cnt;
8215 jr.r.bottom += cnt;
8216 }
8217 }
8218 }
8219
8220 if(col >= 0)
8221 {
8222 for(int i = 0; i < joins.GetCount(); i++)
8223 {
8224 JoinRect& jr = joins[i];
8225
8226 int left = jr.r.left;
8227 int right = jr.r.right;
8228
8229 if(col > left && col < right)
8230 {
8231 for(int c = jr.r.left; c <= jr.r.right; c++)
8232 {
8233 for(int r = jr.r.top; r <= jr.r.bottom; r++)
8234 {
8235 if(c < col || c > col)
8236 {
8237 Item& it = GetItem(r, c);
8238 it.cx += cnt;
8239 }
8240 else if(c == col)
8241 {
8242 for(int n = 0; n < cnt; n++)
8243 {
8244 Item& it = GetItem(r, c + n);
8245 it.group = jr.group;
8246 it.idx = jr.idx;
8247 it.idy = jr.idy;
8248 it.cx = jr.r.Width() + cnt;
8249 it.cy = jr.r.Height();
8250 it.isjoined = true;
8251
8252 if(r == jr.r.top)
8253 hitems[c + n].join++;
8254 }
8255 }
8256 }
8257 }
8258
8259 jr.r.right += cnt;
8260 }
8261 else if(col <= left)
8262 {
8263 jr.idx += cnt;
8264
8265 for(int c = jr.r.left; c <= jr.r.right; c++)
8266 {
8267 for(int r = jr.r.top; r <= jr.r.bottom; r++)
8268 {
8269 Item& it = GetItem(r, c + cnt);
8270 it.idx = jr.idx;
8271 }
8272 }
8273
8274 jr.r.left += cnt;
8275 jr.r.right += cnt;
8276 }
8277 }
8278 }
8279 }
8280
8281 /*----------------------------------------------------------------------------------------*/
8282
Paint(Draw & w)8283 void GridPopUp::Paint(Draw &w)
8284 {
8285 Size sz = GetSize();
8286 if(gd->row < 0 || gd->col < 0)
8287 gd->PaintFixed(w, false, false, 1, 1, sz.cx - 2, sz.cy - 2, val, style | GD::WRAP | GD::VCENTER, fnt);
8288 else
8289 gd->Paint(w, 1, 1, sz.cx - 2, sz.cy - 2, val, style | GD::WRAP | GD::VCENTER, fg, bg, fnt);
8290 DrawBorder(w, sz, BlackBorder);
8291 }
8292
Offset(Point p)8293 Point GridPopUp::Offset(Point p)
8294 {
8295 return p + GetScreenView().TopLeft() - ctrl->GetScreenView().TopLeft();
8296 }
8297
LeftDown(Point p,dword flags)8298 void GridPopUp::LeftDown(Point p, dword flags)
8299 {
8300 ctrl->LeftDown(Offset(p), flags);
8301 }
8302
LeftDrag(Point p,dword flags)8303 void GridPopUp::LeftDrag(Point p, dword flags)
8304 {
8305 Close();
8306 ctrl->LeftDrag(Offset(p), flags);
8307 }
8308
LeftDouble(Point p,dword flags)8309 void GridPopUp::LeftDouble(Point p, dword flags)
8310 {
8311 ctrl->LeftDouble(Offset(p), flags);
8312 }
8313
RightDown(Point p,dword flags)8314 void GridPopUp::RightDown(Point p, dword flags)
8315 {
8316 ctrl->RightDown(Offset(p), flags);
8317 }
8318
LeftUp(Point p,dword flags)8319 void GridPopUp::LeftUp(Point p, dword flags)
8320 {
8321 ctrl->LeftUp(Offset(p), flags);
8322 }
8323
MouseWheel(Point p,int zdelta,dword flags)8324 void GridPopUp::MouseWheel(Point p, int zdelta, dword flags)
8325 {
8326 ctrl->MouseWheel(Offset(p), zdelta, flags);
8327 }
8328
MouseLeave()8329 void GridPopUp::MouseLeave()
8330 {
8331 ctrl->MouseLeave();
8332 Close();
8333 }
8334
MouseEnter(Point p,dword flags)8335 void GridPopUp::MouseEnter(Point p, dword flags)
8336 {
8337 ctrl->MouseEnter(Offset(p), flags);
8338 }
8339
MouseMove(Point p,dword flags)8340 void GridPopUp::MouseMove(Point p, dword flags)
8341 {
8342 ctrl->MouseMove(Offset(p), flags);
8343 }
8344
CursorImage(Point p,dword flags)8345 Image GridPopUp::CursorImage(Point p, dword flags)
8346 {
8347 return ctrl->CursorImage(Offset(p), flags);
8348 }
8349
LostFocus()8350 void GridPopUp::LostFocus()
8351 {
8352 Close();
8353 }
8354
PopUp(Ctrl * owner,int x,int y,int width,int height)8355 void GridPopUp::PopUp(Ctrl *owner, int x, int y, int width, int height)
8356 {
8357 Rect r(x, y, x + width, y + height);
8358 if(r != GetRect())
8359 SetRect(r);
8360
8361 if(!open)
8362 {
8363 ctrl = owner;
8364 open = true;
8365 Ctrl::PopUp(owner, true, false, GUI_DropShadows());
8366 SetAlpha(230);
8367 }
8368 }
8369
Close()8370 void GridPopUp::Close()
8371 {
8372 open = false;
8373 Ctrl::Close();
8374 }
8375
UpdateHighlighting(int mode,Point p)8376 void GridCtrl::UpdateHighlighting(int mode, Point p)
8377 {
8378 if(resize_paint_mode < 1 && (resizeCol || resizeRow))
8379 return;
8380
8381 bool refresh = false;
8382
8383 if(hcol >= hitems.GetCount())
8384 hcol = -1;
8385
8386 if(mode == GS_UP)
8387 {
8388 if((p.x < 0 || p.x > GetSize().cx - 1) && hcol >= 0 && hitems[hcol].IsHighlight())
8389 {
8390 hitems[hcol].Highlight(0);
8391 refresh = true;
8392 hcol = -1;
8393 }
8394 }
8395 else if(mode == GS_MOVE)
8396 {
8397 int col = GetMouseCol(p, true, true, false);
8398 int row = hrow = GetMouseRow(p, false, true, true);
8399
8400 if(hcol >= 0 && (hcol != col || row != 0) && hitems[hcol].IsHighlight())
8401 {
8402 hitems[hcol].Highlight(0);
8403 refresh = true;
8404 }
8405 if(col >= 0 && row == 0 && !hitems[col].IsHighlight())
8406 {
8407 hitems[col].Highlight(1);
8408 hcol = col;
8409 refresh = true;
8410 }
8411 }
8412 else if(mode == GS_POPUP)
8413 {
8414 if(hcol >= 0)
8415 hitems[hcol].Highlight(0);
8416 refresh = true;
8417 hcol = moveCol;
8418 }
8419 else if(mode == GS_BORDER)
8420 {
8421 if(hcol >= 0 && hitems[hcol].IsHighlight())
8422 {
8423 hitems[hcol].Highlight(0);
8424 refresh = true;
8425 }
8426 }
8427 if(refresh)
8428 RefreshRow(0, 0, 1);
8429 }
8430
GetColumnWidths()8431 String GridCtrl::GetColumnWidths()
8432 {
8433 String s;
8434 for(int i = fixed_cols; i < total_cols; i++)
8435 {
8436 s += AsString(hitems[i].nsize);
8437 if(i < total_cols - 1)
8438 s += " ";
8439 }
8440 return s;
8441 }
8442
ColumnWidths(const char * s)8443 void GridCtrl::ColumnWidths(const char* s)
8444 {
8445 Vector<String> w = UPP::Split(s, ' ');
8446 for(int i = 0; i < min(w.GetCount(), GetColumnCount()); i++)
8447 hitems[i + fixed_cols].Width(atoi(w[i]));
8448 }
8449
SetDisplay(int r,int c,GridDisplay & gd)8450 void GridCtrl::SetDisplay(int r, int c, GridDisplay& gd)
8451 {
8452 GetItem(r + fixed_rows, c + fixed_cols).SetDisplay(gd);
8453 }
8454
8455 #ifdef flagGRIDSQL
FieldLayout(FieldOperator & f)8456 void GridCtrl::FieldLayout(FieldOperator& f)
8457 {
8458 for(int i = 1; i < total_cols; i++)
8459 {
8460 if(hitems[i].hidden)
8461 continue;
8462 int id = hitems[i].id;
8463 const Id& key = aliases.GetKey(id);
8464 f(key, items[vitems[rowidx].id][id].val);
8465 }
8466 }
8467
GetColumnList(bool skip_hidden) const8468 SqlSet GridCtrl::GetColumnList(bool skip_hidden) const
8469 {
8470 SqlSet s;
8471 for(int i = 1; i < total_cols; i++)
8472 {
8473 if(skip_hidden && hitems[i].hidden)
8474 continue;
8475 int id = hitems[i].id;
8476 s.Cat(SqlId(aliases.GetKey(id)));
8477 }
8478 return s;
8479 }
8480
8481 #endif
8482
8483
8484 /*----------------------------------------------------------------------------------------*/
GridFind()8485 GridFind::GridFind()
8486 {
8487 MultiButton::SubButton& btn = button.AddButton().Main();
8488 btn.WhenPush = THISBACK(Push);
8489 btn.SetMonoImage(CtrlImg::smallright());
8490
8491 button.SetStyle(button.StyleFrame());
8492 button.NoDisplay();
8493 button.AddTo(*this);
8494 }
8495
Key(dword key,int count)8496 bool GridFind::Key(dword key, int count)
8497 {
8498 if(key == K_ENTER && WhenEnter)
8499 {
8500 WhenEnter();
8501 return true;
8502 }
8503
8504 return EditString::Key(key, count);
8505 }
8506
GetMinSize() const8507 Size GridFind::GetMinSize() const
8508 {
8509 return button.GetMinSize();
8510 }
8511
Push()8512 void GridFind::Push()
8513 {
8514 MenuBar::Execute(WhenBar, GetScreenRect().TopRight());
8515 }
8516
8517 /*----------------------------------------------------------------------------------------*/
Paint(Draw & w)8518 void GridPopUpHeader::Paint(Draw &w)
8519 {
8520 Size sz = GetSize();
8521 dword style = chameleon ? GD::CHAMELEON : 0;
8522 Font stdfont(StdFont());
8523 display->PaintFixed(w, 1, 1, 0, 0, sz.cx, sz.cy,
8524 val, style, stdfont, false, true,
8525 sortmode, sortcol, sortcnt, true);
8526 }
8527
PopUp(Ctrl * owner,int x,int y,int width,int height)8528 void GridPopUpHeader::PopUp(Ctrl *owner, int x, int y, int width, int height)
8529 {
8530 SetRect(Rect(x, y, x + width, y + height));
8531 if(open)
8532 return;
8533 Ctrl::PopUp(owner, true, true, GUI_DropShadows());
8534 SetAlpha(200);
8535 open = true;
8536 }
8537
Close()8538 void GridPopUpHeader::Close()
8539 {
8540 open = false;
8541 Ctrl::Close();
8542 }
8543
8544 /*----------------------------------------------------------------------------------------*/
GridButton()8545 GridButton::GridButton()
8546 {
8547 n = 0;
8548 img = 0;
8549 }
8550
Paint(Draw & w)8551 void GridButton::Paint(Draw& w)
8552 {
8553 static Image (*vimg[])() = {
8554 &GridImg::Btn0N, &GridImg::Btn0H, &GridImg::Btn0P,
8555 &GridImg::Btn1N, &GridImg::Btn1H, &GridImg::Btn1P
8556 };
8557
8558 Size sz = GetSize();
8559 w.DrawImage(0, 0, sz.cx, sz.cy, vimg[img + n * 3]);
8560 }
8561
LeftDown(Point p,dword flags)8562 void GridButton::LeftDown(Point p, dword flags)
8563 {
8564 img = 2;
8565 Refresh();
8566 }
8567
LeftUp(Point p,dword flags)8568 void GridButton::LeftUp(Point p, dword flags)
8569 {
8570 img = 1;
8571 Refresh();
8572 Action();
8573 }
8574
MouseEnter(Point p,dword flags)8575 void GridButton::MouseEnter(Point p, dword flags)
8576 {
8577 img = flags & K_MOUSELEFT ? 2 : 1;
8578 Refresh();
8579 }
8580
MouseLeave()8581 void GridButton::MouseLeave()
8582 {
8583 img = 0;
8584 Refresh();
8585 }
8586
State(int reason)8587 void GridButton::State(int reason)
8588 {
8589 if(reason == CLOSE)
8590 img = 0;
8591 }
8592
GetStdSize() const8593 Size GridButton::GetStdSize() const
8594 {
8595 return n > 0 ? Size(14, 11) : Size(17, 17); //FIXME
8596 }
8597
SetButton(int b)8598 void GridButton::SetButton(int b)
8599 {
8600 n = b;
8601 }
8602
GridResizePanel()8603 GridResizePanel::GridResizePanel()
8604 {
8605 int h = max(16, Draw::GetStdFontCy()) + 5;
8606 Height(h);
8607 Size csz = close.GetStdSize();
8608 Add(close.LeftPos(1, csz.cx).TopPos((h - csz.cy) / 2, csz.cy));
8609 minsize.Clear();
8610 close.WhenAction = Proxy(WhenClose);
8611 }
8612
Paint(Draw & w)8613 void GridResizePanel::Paint(Draw& w)
8614 {
8615 Size sz = GetSize();
8616 w.DrawRect(sz, SColorFace);
8617 Size isz = CtrlsImg::SizeGrip().GetSize();
8618 w.DrawImage(sz.cx - isz.cx, sz.cy - isz.cy, CtrlsImg::SizeGrip());
8619 }
8620
MouseOnGrip(const Point & p)8621 bool GridResizePanel::MouseOnGrip(const Point &p)
8622 {
8623 Size isz = CtrlsImg::SizeGrip().GetSize();
8624 Size sz = GetSize();
8625 return (p.x > sz.cx - isz.cx && p.y > sz.cy - isz.cy);
8626 }
8627
SetMinSize(Size sz)8628 void GridResizePanel::SetMinSize(Size sz)
8629 {
8630 minsize = sz;
8631 }
8632
CursorImage(Point p,dword flags)8633 Image GridResizePanel::CursorImage(Point p, dword flags)
8634 {
8635 if(MouseOnGrip(p) || HasCapture())
8636 return Image::SizeBottomRight();
8637 return Image::Arrow();
8638 }
8639
LeftDown(Point p,dword flags)8640 void GridResizePanel::LeftDown(Point p, dword flags)
8641 {
8642 if(MouseOnGrip(p))
8643 {
8644 r = GetParent()->GetScreenRect();
8645 pos = GetMousePos();
8646 SetCapture();
8647 }
8648 }
8649
LeftUp(Point p,dword flags)8650 void GridResizePanel::LeftUp(Point p, dword flags)
8651 {
8652 ReleaseCapture();
8653 }
8654
MouseMove(Point p,dword flags)8655 void GridResizePanel::MouseMove(Point p, dword flags)
8656 {
8657 if(HasCapture())
8658 {
8659 Point curpos = GetMousePos();
8660 Point diff = curpos - pos;
8661 Rect r(this->r);
8662 r.right += diff.x;
8663 r.bottom += diff.y;
8664 bool setmin = false;
8665
8666 if(!minsize.IsEmpty())
8667 {
8668 if(r.right < r.left + minsize.cx)
8669 {
8670 r.right = r.left + minsize.cx;
8671 setmin = true;
8672 }
8673 if(r.bottom < r.top + minsize.cy)
8674 {
8675 r.bottom = r.top + minsize.cy;
8676 setmin = true;
8677 }
8678 }
8679 if(this->r != r || setmin)
8680 {
8681 GetParent()->SetRect(r);
8682 GetParent()->Sync();
8683 }
8684 }
8685 }
8686
8687 /*----------------------------------------------------------------------------------------*/
8688
Xmlize(XmlIO & xml,GridCtrl & g)8689 template<> void Xmlize(XmlIO& xml, GridCtrl& g) {
8690 Vector< Vector<Value> > v;
8691
8692 if(xml.IsLoading()) {
8693 xml("data", v);
8694 g.SetValues(v);
8695 } else {
8696 v = g.GetValues();
8697 xml("data", v);
8698 }
8699 }
8700
Jsonize(JsonIO & json,GridCtrl & g)8701 template<> void Jsonize(JsonIO& json, GridCtrl& g) {
8702 Vector< Vector<Value> > v;
8703
8704 if(json.IsLoading()) {
8705 json("data", v);
8706 g.SetValues(v);
8707 } else {
8708 v = g.GetValues();
8709 json("data", v);
8710 }
8711 }
8712
8713 /* after this assist++ sees nothing */
8714 //$-
8715 #define E__Addv0(I) Set(q, I - 1, p##I)
8716 #define E__AddF0(I) \
8717 GridCtrl& GridCtrl::Add(__List##I(E__Value)) { \
8718 int q = GetCount(); \
8719 __List##I(E__Addv0); \
8720 return *this; \
8721 }
8722 __Expand(E__AddF0)
8723
8724 #define E__Addv1(I) Set(q, I - 1, p##I)
8725 #define E__AddF1(I) \
8726 GridCtrl::ItemRect& GridCtrl::AddRow(__List##I(E__Value)) { \
8727 int q = GetCount(); \
8728 ItemRect& ir = AddRow(); \
8729 __List##I(E__Addv1); \
8730 return ir; \
8731 }
8732 __Expand(E__AddF1)
8733
8734 }
8735