Molecular Modeling Software
リビジョン | 822395e078b3385b7f0fe070d54260d41723631e (tree) |
---|---|
日時 | 2022-09-19 12:50:11 |
作者 | Toshi Nagata <alchemist.2005@nift...> |
コミッター | Toshi Nagata |
Handling key and mouse events in listctrl is improved
@@ -80,7 +80,7 @@ MyListCtrl::Create(wxWindow* parent, wxWindowID wid, const wxPoint& pos, const w | ||
80 | 80 | { |
81 | 81 | this->wxWindow::Create(parent, wid, pos, size); |
82 | 82 | |
83 | - header = new wxWindow(this, 1001, wxPoint(0, 0), wxSize(size.x, 16)); | |
83 | + header = new wxWindow(this, 1001, wxPoint(0, 0), wxSize(size.x, 16), wxWANTS_CHARS); | |
84 | 84 | scroll = new wxScrolledWindow(this, 1002, wxPoint(0, 16), wxSize(size.x, (size.y <= 16 ? -1 : size.y - 16))); |
85 | 85 | |
86 | 86 | // Connect events |
@@ -98,6 +98,9 @@ MyListCtrl::Create(wxWindow* parent, wxWindowID wid, const wxPoint& pos, const w | ||
98 | 98 | scroll->Bind(wxEVT_SCROLLWIN_PAGEUP, &MyListCtrl::OnScrollWin, this); |
99 | 99 | scroll->Bind(wxEVT_SCROLLWIN_THUMBRELEASE, &MyListCtrl::OnScrollWin, this); |
100 | 100 | scroll->Bind(wxEVT_SCROLLWIN_THUMBTRACK, &MyListCtrl::OnScrollWin, this); |
101 | + scroll->Bind(wxEVT_CHAR, &MyListCtrl::OnCharInScroll, this); | |
102 | + scroll->Bind(wxEVT_SET_FOCUS, &MyListCtrl::OnSetFocusInScroll, this); | |
103 | + scroll->Bind(wxEVT_KILL_FOCUS, &MyListCtrl::OnKillFocusInScroll, this); | |
101 | 104 | |
102 | 105 | // Set Fonts |
103 | 106 | cellFont = GetFont(); |
@@ -108,10 +111,13 @@ MyListCtrl::Create(wxWindow* parent, wxWindowID wid, const wxPoint& pos, const w | ||
108 | 111 | wxClientDC dc(this); |
109 | 112 | int w, h, descent, leading; |
110 | 113 | dc.GetTextExtent(_T("M"), &w, &h, &descent, &leading, &cellFont); |
111 | - rowHeight = h + 2; | |
114 | + rowHeight = h + FromFrameDIP(scroll, 2); | |
112 | 115 | dc.GetTextExtent(_T("M"), &w, &h, &descent, &leading, &headerFont); |
113 | - headerHeight = h + 2; | |
116 | + headerHeight = h + FromFrameDIP(scroll, 2); | |
114 | 117 | header->SetSize(wxSize(size.x, headerHeight)); |
118 | + pageHeight = rowHeight; | |
119 | + pageWidth = rowHeight; | |
120 | + scroll->SetScrollbars(rowHeight, rowHeight, 1, 1, true); | |
115 | 121 | } |
116 | 122 | |
117 | 123 | // Set sizer |
@@ -191,8 +197,12 @@ MyListCtrl::RefreshTable(bool refreshWindow) | ||
191 | 197 | // Set the subwindow infos |
192 | 198 | sz.y = headerHeight; |
193 | 199 | header->SetMinSize(sz); |
194 | - scroll->SetScrollbars(rowHeight, rowHeight, floor((pageWidth + rowHeight - 1) / rowHeight), nrows); | |
195 | 200 | scroll->SetVirtualSize(pageWidth, pageHeight); |
201 | + int pageSize = floor((pageWidth + rowHeight - 1) / rowHeight); | |
202 | + if (scroll->GetScrollPageSize(wxHORIZONTAL) != pageSize) | |
203 | + scroll->SetScrollPageSize(wxHORIZONTAL, pageSize); | |
204 | + if (scroll->GetScrollPageSize(wxVERTICAL) != pageSize) | |
205 | + scroll->SetScrollPageSize(wxVERTICAL, nrows); | |
196 | 206 | Layout(); |
197 | 207 | } |
198 | 208 | needsReload = false; |
@@ -221,13 +231,8 @@ MyListCtrl::OnPaint(wxPaintEvent &event) | ||
221 | 231 | |
222 | 232 | wxColour colour; |
223 | 233 | bool isActive; |
224 | - // Get the nearest TopLevelWindow and see if it is active or not | |
225 | - wxWindow *win = this; | |
226 | - while (win != NULL && !win->IsKindOf(wxCLASSINFO(wxTopLevelWindow))) | |
227 | - win = win->GetParent(); | |
228 | - if (win != NULL && ((wxTopLevelWindow *)win)->IsActive()) | |
229 | - isActive = true; | |
230 | - else isActive = false; | |
234 | + isActive = scroll->HasFocus(); | |
235 | + isPaintActive = isActive; | |
231 | 236 | wxPaintDC dc(scroll); |
232 | 237 | scroll->DoPrepareDC(dc); |
233 | 238 | int ox, oy; |
@@ -236,9 +241,9 @@ MyListCtrl::OnPaint(wxPaintEvent &event) | ||
236 | 241 | wxSize sz = scroll->GetClientSize(); |
237 | 242 | bool showDragTarget = (draggingRows && (dragTargetRow != mouseRow && dragTargetRow != mouseRow + 1)); |
238 | 243 | // Draw background |
239 | - dc.SetPen(wxNullPen); | |
244 | + dc.SetPen(*wxTRANSPARENT_PEN); | |
240 | 245 | dc.SetBrush(*wxWHITE_BRUSH); |
241 | - dc.DrawRectangle(0, 0, sz.x, sz.y); | |
246 | + dc.DrawRectangle(ox, oy, sz.x, sz.y); | |
242 | 247 | int i, j; |
243 | 248 | basex = 0; |
244 | 249 | for (i = 0; i < ncols; i++) { |
@@ -501,6 +506,16 @@ MyListCtrl::OnLeftDown(wxMouseEvent &event) | ||
501 | 506 | bool isRowSelected, selectionChanged = false; |
502 | 507 | if (editText) |
503 | 508 | EndEditText(); |
509 | + if (!isPaintActive) { | |
510 | + // The scroll is still displayed in inactive state; | |
511 | + // Set focus to scroll, and do nothing else. | |
512 | + // This flag is used because we actually want to intercept the mouseDown | |
513 | + // for 'just activate the listview', but wxWidgets may not allow processing | |
514 | + // mouseDown event _before_ the scroll view gets focus. | |
515 | + scroll->SetFocus(); | |
516 | + Refresh(); | |
517 | + return; | |
518 | + } | |
504 | 519 | pos = event.GetPosition(); |
505 | 520 | if (FindItemAtPosition(pos, &row, &col) && dataSource != NULL && (n = dataSource->HasPopUpMenu(this, row, col, &items)) > 0) { |
506 | 521 | wxMenu mnu; |
@@ -588,7 +603,6 @@ MyListCtrl::OnLeftDown(wxMouseEvent &event) | ||
588 | 603 | // Actually no change occurred |
589 | 604 | selectionChangeNotificationRequired = false; |
590 | 605 | } |
591 | - SetFocus(); // Set focus to MyListCtrl, not wxScrolledWindow | |
592 | 606 | Refresh(); |
593 | 607 | } |
594 | 608 |
@@ -667,11 +681,11 @@ MyListCtrl::OnLeftUp(wxMouseEvent &event) | ||
667 | 681 | dragged = true; |
668 | 682 | if (row != mouseRow) { |
669 | 683 | if (draggingRows) { |
670 | - // TODO: change selection; it should be implemented in dataSource | |
671 | 684 | dataSource->DragSelectionToRow(this, dragTargetRow); |
672 | 685 | selectionChanged = true; |
673 | 686 | } |
674 | 687 | } |
688 | + lastMouseRow = dragTargetRow; | |
675 | 689 | } |
676 | 690 | if (!dragged) { |
677 | 691 | if (mouseMode == 1 || mouseMode == 4) { |
@@ -820,8 +834,6 @@ MyListCtrl::GetScrollPosition(int *xpos, int *ypos) | ||
820 | 834 | bool |
821 | 835 | MyListCtrl::SetScrollPosition(int xpos, int ypos) |
822 | 836 | { |
823 | - wxSize vsz = scroll->GetVirtualSize(); | |
824 | - wxSize sz = scroll->GetSize(); | |
825 | 837 | bool retval = true; |
826 | 838 | int xlim = scroll->GetScrollLines(wxHORIZONTAL) - scroll->GetScrollPageSize(wxHORIZONTAL); |
827 | 839 | int ylim = scroll->GetScrollLines(wxVERTICAL) - scroll->GetScrollPageSize(wxVERTICAL); |
@@ -843,7 +855,16 @@ MyListCtrl::SetScrollPosition(int xpos, int ypos) | ||
843 | 855 | retval = false; |
844 | 856 | ypos = 0; |
845 | 857 | } |
858 | + // TextCtrl may be moved during the scroll, so amend the position | |
846 | 859 | scroll->Scroll(xpos, ypos); |
860 | + if (editText) { | |
861 | + wxRect r; | |
862 | + int delta = FromFrameDIP(scroll, 2); | |
863 | + if (GetItemRectForRowAndColumn(r, editRow, editColumn)) { | |
864 | + editText->SetPosition(wxPoint(r.x - delta, r.y - delta)); | |
865 | + } | |
866 | + } | |
867 | + header->Refresh(); | |
847 | 868 | return retval; |
848 | 869 | } |
849 | 870 |
@@ -875,6 +896,7 @@ MyListCtrl::EnsureVisible(int row, int col) | ||
875 | 896 | } |
876 | 897 | if (scx >= 0 || scy >= 0) { |
877 | 898 | scroll->Scroll(scx, scy); |
899 | + header->Refresh(); | |
878 | 900 | return true; |
879 | 901 | } else return false; |
880 | 902 | } |
@@ -883,24 +905,24 @@ void | ||
883 | 905 | MyListCtrl::StartEditText(int row, int col) |
884 | 906 | { |
885 | 907 | wxRect r; |
908 | + int delta = FromFrameDIP(scroll, 2); | |
909 | + EnsureVisible(row, col); | |
886 | 910 | if (!GetItemRectForRowAndColumn(r, row, col)) |
887 | 911 | return; |
888 | - int i, tx, ty; | |
889 | - int cy = rowHeight * row; | |
890 | - int cx = 0; | |
891 | - for (i = 0; i < col; i++) { | |
892 | - cx += colWidths[i]; | |
893 | - } | |
894 | - scroll->CalcScrolledPosition(cx, cy, &tx, &ty); | |
895 | 912 | if (editText == NULL) { |
896 | - editText = new wxTextCtrl(scroll, -1, "", wxPoint(r.x - 2, r.y - 2), wxSize(r.width + 4, r.height + 4), wxTE_PROCESS_ENTER); | |
913 | + editText = new wxTextCtrl(scroll, -1, "", wxPoint(r.x - delta, r.y - delta), wxSize(r.width + delta * 2, r.height + delta * 2), wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB | wxWANTS_CHARS); | |
897 | 914 | editText->Bind(wxEVT_CHAR, &MyListCtrl::OnCharInText, this); |
915 | + editText->Bind(wxEVT_CHAR_HOOK, &MyListCtrl::OnCharHookInText, this); | |
898 | 916 | } else { |
899 | 917 | FinalizeEdit(); |
900 | - editText->SetPosition(wxPoint(r.x - 2, r.y - 2)); | |
901 | - editText->SetSize(wxSize(r.width + 4, r.height + 4)); | |
918 | + editText->SetPosition(wxPoint(r.x - delta, r.y - delta)); | |
919 | + editText->SetSize(wxSize(r.width + delta * 2, r.height + delta * 2)); | |
920 | + } | |
921 | + if (selection.size() != 1 || !IsRowSelected(row)) { | |
922 | + UnselectAllRows(); | |
923 | + SelectRow(row); | |
924 | + PostSelectionChangeNotification(); | |
902 | 925 | } |
903 | - EnsureVisible(row, col); | |
904 | 926 | wxString str = dataSource->GetItemText(this, row, col); |
905 | 927 | editText->SetValue(str); |
906 | 928 | editText->Show(); |
@@ -908,11 +930,6 @@ MyListCtrl::StartEditText(int row, int col) | ||
908 | 930 | editText->SelectAll(); |
909 | 931 | editRow = row; |
910 | 932 | editColumn = col; |
911 | - if (selection.size() != 1 || !IsRowSelected(row)) { | |
912 | - UnselectAllRows(); | |
913 | - SelectRow(row); | |
914 | - PostSelectionChangeNotification(); | |
915 | - } | |
916 | 933 | } |
917 | 934 | |
918 | 935 | void |
@@ -935,6 +952,7 @@ MyListCtrl::EndEditText(bool setValueFlag) | ||
935 | 952 | editText->Hide(); |
936 | 953 | editText->Destroy(); |
937 | 954 | editText = NULL; |
955 | + scroll->SetFocus(); | |
938 | 956 | } |
939 | 957 | |
940 | 958 | void |
@@ -1003,8 +1021,62 @@ MyListCtrl::OnCharInText(wxKeyEvent &event) | ||
1003 | 1021 | EndEditText(); |
1004 | 1022 | } else |
1005 | 1023 | event.Skip(); |
1006 | - // TODO: arrow up/down key should change selected row (if multiple rows are selected, then | |
1007 | - // start from the last clicked row) | |
1024 | +} | |
1025 | + | |
1026 | +void | |
1027 | +MyListCtrl::OnCharHookInText(wxKeyEvent &event) | |
1028 | +{ | |
1029 | +#if defined(__WXMAC__) || defined(__WXOSX__) | |
1030 | + // On macOS, shift-TAB is consumed by wxWidgets even when wxTE_PROCESS_TAB and wxWANTS_CHARS | |
1031 | + // are specified (why?); so, we intercept the TAB and shift-TAB here | |
1032 | + int kc = event.GetKeyCode(); | |
1033 | + if (kc == WXK_TAB || kc == WXK_NUMPAD_TAB) { | |
1034 | + OnCharInText(event); | |
1035 | + } else event.Skip(); | |
1036 | +#else | |
1037 | + event.Skip(); | |
1038 | +#endif | |
1039 | +} | |
1040 | + | |
1041 | +void | |
1042 | +MyListCtrl::OnCharInScroll(wxKeyEvent &event) | |
1043 | +{ | |
1044 | + int kc = event.GetKeyCode(); | |
1045 | + if (kc == WXK_DOWN || kc == WXK_UP) { | |
1046 | + int row; | |
1047 | + if (selection.size() > 0) { | |
1048 | + if (selection.size() > 1) { | |
1049 | + if (lastMouseRow >= 0 && lastMouseRow < nrows) | |
1050 | + row = lastMouseRow; | |
1051 | + else if (kc == WXK_DOWN) | |
1052 | + row = selection[selection.size() - 1]; | |
1053 | + else | |
1054 | + row = selection[0]; | |
1055 | + } else row = selection[0]; | |
1056 | + if (kc == WXK_UP && row > 0) | |
1057 | + row--; | |
1058 | + else if (kc == WXK_DOWN && row < nrows - 1) | |
1059 | + row++; | |
1060 | + else return; // Ignore key | |
1061 | + UnselectAllRows(); | |
1062 | + SelectRow(row); | |
1063 | + PostSelectionChangeNotification(); | |
1064 | + Refresh(); | |
1065 | + lastMouseRow = row; // Fake as if this row was clicked | |
1066 | + } | |
1067 | + } else event.Skip(); | |
1068 | +} | |
1069 | + | |
1070 | +void | |
1071 | +MyListCtrl::OnSetFocusInScroll(wxFocusEvent &event) | |
1072 | +{ | |
1073 | + Refresh(); | |
1074 | +} | |
1075 | + | |
1076 | +void | |
1077 | +MyListCtrl::OnKillFocusInScroll(wxFocusEvent &event) | |
1078 | +{ | |
1079 | + Refresh(); | |
1008 | 1080 | } |
1009 | 1081 | |
1010 | 1082 | void |
@@ -144,6 +144,10 @@ public: | ||
144 | 144 | void OnMotion(wxMouseEvent &event); |
145 | 145 | void OnScrollWin(wxScrollWinEvent &event); |
146 | 146 | void OnCharInText(wxKeyEvent &event); |
147 | + void OnCharHookInText(wxKeyEvent &event); | |
148 | + void OnCharInScroll(wxKeyEvent &event); | |
149 | + void OnSetFocusInScroll(wxFocusEvent &event); | |
150 | + void OnKillFocusInScroll(wxFocusEvent &event); | |
147 | 151 | |
148 | 152 | void EnableSelectionChangeNotification(bool flag) { selectionChangeNotificationEnabled = flag; } |
149 | 153 |
@@ -154,6 +158,7 @@ public: | ||
154 | 158 | bool selectionChangeNotificationRequired; |
155 | 159 | bool selectionChangeNotificationEnabled; |
156 | 160 | bool needsReload; |
161 | + bool isPaintActive; // Flag to show whether the scroll had focus in the last OnPaint call | |
157 | 162 | int lastPopUpColumn, lastPopUpRow; |
158 | 163 | wxFont cellFont; |
159 | 164 | wxFont headerFont; |