Audacity 3.2.0
Grid.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 Grid.cpp
6
7 Leland Lucius
8
9*******************************************************************//*******************************************************************/
15#include "Grid.h"
16
17#include <wx/setup.h> // for wxUSE_* macros
18
19#include <wx/defs.h>
20#include <wx/choice.h>
21#include <wx/clipbrd.h>
22#include <wx/dc.h>
23#include <wx/grid.h>
24#include <wx/settings.h>
25#include <wx/toplevel.h>
26
27#include "IteratorX.h"
29
30#include "SelectedRegion.h"
31
32#if wxUSE_ACCESSIBILITY
33#include "WindowAccessible.h"
34
35/**********************************************************************/
39class GridAx final : public WindowAccessible
40{
41
42 public:
43
44 GridAx(const FormatterContext& project, Grid *grid);
45
46 void SetCurrentCell(int row, int col);
47 void TableUpdated();
48 bool GetRowCol(int childId, int & row, int & col);
49
50 // Retrieves the address of an IDispatch interface for the specified child.
51 // All objects must support this property.
52 wxAccStatus GetChild(int childId, wxAccessible **child) override;
53
54 // Gets the number of children.
55 wxAccStatus GetChildCount(int *childCount) override;
56
57 // Gets the default action for this object (0) or > 0 (the action for a child).
58 // Return wxACC_OK even if there is no action. actionName is the action, or the empty
59 // string if there is no action.
60 // The retrieved string describes the action that is performed on an object,
61 // not what the object does as a result. For example, a toolbar button that prints
62 // a document has a default action of "Press" rather than "Prints the current document."
63 wxAccStatus GetDefaultAction(int childId, wxString *actionName) override;
64
65 // Returns the description for this object or a child.
66 wxAccStatus GetDescription(int childId, wxString *description) override;
67
68 // Gets the window with the keyboard focus.
69 // If childId is 0 and child is NULL, no object in
70 // this subhierarchy has the focus.
71 // If this object has the focus, child should be 'this'.
72 wxAccStatus GetFocus(int *childId, wxAccessible **child) override;
73
74 // Returns help text for this object or a child, similar to tooltip text.
75 wxAccStatus GetHelpText(int childId, wxString *helpText) override;
76
77 // Returns the keyboard shortcut for this object or child.
78 // Return e.g. ALT+K
79 wxAccStatus GetKeyboardShortcut(int childId, wxString *shortcut) override;
80
81 // Returns the rectangle for this object (id = 0) or a child element (id > 0).
82 // rect is in screen coordinates.
83 wxAccStatus GetLocation(wxRect & rect, int elementId) override;
84
85 // Gets the name of the specified object.
86 wxAccStatus GetName(int childId, wxString *name) override;
87
88 // Gets the parent, or NULL.
89 wxAccStatus GetParent(wxAccessible **parent) override;
90
91 // Returns a role constant.
92 wxAccStatus GetRole(int childId, wxAccRole *role) override;
93
94 // Gets a variant representing the selected children
95 // of this object.
96 // Acceptable values:
97 // - a null variant (IsNull() returns TRUE)
98 // - a list variant (GetType() == wxT("list"))
99 // - an integer representing the selected child element,
100 // or 0 if this object is selected (GetType() == wxT("long"))
101 // - a "void*" pointer to a wxAccessible child object
102 wxAccStatus GetSelections(wxVariant *selections) override;
103
104 // Returns a state constant.
105 wxAccStatus GetState(int childId, long* state) override;
106
107 // Returns a localized string representing the value for the object
108 // or child.
109 wxAccStatus GetValue(int childId, wxString* strValue) override;
110
111#if defined(__WXMAC__)
112 // Selects the object or child.
113 wxAccStatus Select(int childId, wxAccSelectionFlags selectFlags) override;
114#endif
115 FormatterContext mContext;
116
117 Grid *mGrid;
118 int mLastId;
119
120};
121#endif
122
124 const FormatterContext& context, NumericConverterType type,
125 const NumericFormatID& format)
126 : mContext { context }
127{
128 mType = std::move(type);
129 mFormat = format;
130 mOld = 0.0;
131}
132
134{
135}
136
137void NumericEditor::Create(wxWindow *parent, wxWindowID id, wxEvtHandler *handler)
138{
139 wxASSERT(parent); // to justify safenew
140 auto control = safenew NumericTextCtrl(mContext,
141 parent, wxID_ANY,
142 mType,
143 mFormat,
144 mOld,
146 .AutoPos(true)
147 .InvalidValue(mType == NumericConverterType_FREQUENCY(),
149 );
150 m_control = control;
151
152 wxGridCellEditor::Create(parent, id, handler);
153}
154
155void NumericEditor::SetSize(const wxRect &rect)
156{
157 wxSize size = m_control->GetSize();
158
159 // Always center...looks bad otherwise
160 int x = rect.x + ((rect.width / 2) - (size.x / 2)) + 1;
161 int y = rect.y + ((rect.height / 2) - (size.y / 2)) + 1;
162
163 m_control->Move(x, y);
164}
165
166void NumericEditor::BeginEdit(int row, int col, wxGrid *grid)
167{
168 wxGridTableBase *table = grid->GetTable();
169
170 mOldString = table->GetValue(row, col);
171 mOldString.ToDouble(&mOld);
172
173 auto control = GetNumericTextControl();
174 control->SetValue(mOld);
175 control->EnableMenu();
176
177 control->SetFocus();
178}
179
180
181bool NumericEditor::EndEdit(int WXUNUSED(row), int WXUNUSED(col), const wxGrid *WXUNUSED(grid), const wxString &WXUNUSED(oldval), wxString *newval)
182{
183 double newtime = GetNumericTextControl()->GetValue();
184 bool changed = newtime != mOld;
185
186 if (changed) {
187 mValueAsString = wxString::Format(wxT("%g"), newtime);
188 *newval = mValueAsString;
189 }
190
191 return changed;
192}
193
194void NumericEditor::ApplyEdit(int row, int col, wxGrid *grid)
195{
196 grid->GetTable()->SetValue(row, col, mValueAsString);
197}
198
200{
202}
203
204bool NumericEditor::IsAcceptedKey(wxKeyEvent &event)
205{
206 if (wxGridCellEditor::IsAcceptedKey(event)) {
207 if (event.GetKeyCode() == WXK_RETURN) {
208 return true;
209 }
210 }
211
212 return false;
213}
214
215// Clone is required by wxwidgets; implemented via copy constructor
216wxGridCellEditor *NumericEditor::Clone() const
217{
219}
220
222{
223 return wxString::Format(wxT("%g"), GetNumericTextControl()->GetValue());
224}
225
227{
228 return mFormat;
229}
230
232{
233 mFormat = format;
234}
235
237{
238}
239
240void NumericRenderer::Draw(wxGrid &grid,
241 wxGridCellAttr &attr,
242 wxDC &dc,
243 const wxRect &rect,
244 int row,
245 int col,
246 bool isSelected)
247{
248 wxGridCellRenderer::Draw(grid, attr, dc, rect, row, col, isSelected);
249
250 wxGridTableBase *table = grid.GetTable();
251 NumericEditor *ne =
252 static_cast<NumericEditor *>(grid.GetCellEditor(row, col));
253 wxString tstr;
254
255 if (ne) {
256 double value;
257
258 table->GetValue(row, col).ToDouble(&value);
259
260 NumericTextCtrl tt(mContext, &grid, wxID_ANY,
261 mType,
262 ne->GetFormat(),
263 value,
265 wxPoint(10000, 10000)); // create offscreen
266 tstr = tt.GetString();
267
268 ne->DecRef();
269 }
270
271 dc.SetBackgroundMode(wxTRANSPARENT);
272
273 if (grid.IsEnabled())
274 {
275 if (isSelected)
276 {
277 dc.SetTextBackground(grid.GetSelectionBackground());
278 dc.SetTextForeground(grid.GetSelectionForeground());
279 }
280 else
281 {
282 dc.SetTextBackground(attr.GetBackgroundColour());
283 dc.SetTextForeground(attr.GetTextColour());
284 }
285 }
286 else
287 {
288 dc.SetTextBackground(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
289 dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT));
290 }
291
292 dc.SetFont(attr.GetFont());
293
294 int hAlign, vAlign;
295
296 attr.GetAlignment(&hAlign, &vAlign);
297
298 grid.DrawTextRectangle(dc, tstr, rect, hAlign, vAlign);
299}
300
302 wxGridCellAttr & WXUNUSED(attr),
303 wxDC & WXUNUSED(dc),
304 int row,
305 int col)
306{
307 wxGridTableBase *table = grid.GetTable();
308 NumericEditor *ne =
309 static_cast<NumericEditor *>(grid.GetCellEditor(row, col));
310 wxSize sz;
311
312 if (ne) {
313 double value;
314 table->GetValue(row, col).ToDouble(&value);
315 NumericTextCtrl tt(mContext, &grid, wxID_ANY,
316 mType,
317 ne->GetFormat(),
318 value,
320 wxPoint(10000, 10000)); // create offscreen
321 sz = tt.GetSize();
322
323 ne->DecRef();
324 }
325
326 return sz;
327}
328
329// Clone is required by wxwidgets; implemented via copy constructor
330wxGridCellRenderer *NumericRenderer::Clone() const
331{
333}
334
335ChoiceEditor::ChoiceEditor(size_t count, const wxString choices[])
336{
337 if (count) {
338 mChoices.reserve(count);
339 for (size_t n = 0; n < count; n++) {
340 mChoices.push_back(choices[n]);
341 }
342 }
343}
344
345ChoiceEditor::ChoiceEditor(const wxArrayString &choices)
346{
347 mChoices = choices;
348}
349
351{
352 if (m_control)
353 mHandler.DisconnectEvent(m_control);
354}
355
356// Clone is required by wxwidgets; implemented via copy constructor
357wxGridCellEditor *ChoiceEditor::Clone() const
358{
360}
361
362void ChoiceEditor::Create(wxWindow* parent, wxWindowID id, wxEvtHandler* evtHandler)
363{
364 m_control = safenew wxChoice(parent,
365 id,
366 wxDefaultPosition,
367 wxDefaultSize,
368 mChoices);
369
370 wxGridCellEditor::Create(parent, id, evtHandler);
371 mHandler.ConnectEvent(m_control);
372}
373
374void ChoiceEditor::SetSize(const wxRect &rect)
375{
376 wxSize size = m_control->GetSize();
377
378 // Always center...looks bad otherwise
379 int x = rect.x + ((rect.width / 2) - (size.x / 2)) + 1;
380 int y = rect.y + ((rect.height / 2) - (size.y / 2)) + 1;
381
382 m_control->Move(x, y);
383}
384
385void ChoiceEditor::BeginEdit(int row, int col, wxGrid* grid)
386{
387 if (!m_control)
388 return;
389
390 mOld = grid->GetTable()->GetValue(row, col);
391
392 Choice()->Clear();
393 Choice()->Append(mChoices);
394 Choice()->SetSelection( make_iterator_range( mChoices ).index( mOld ) );
395 Choice()->SetFocus();
396}
397
398bool ChoiceEditor::EndEdit(int row, int col, wxGrid *grid)
399{
400 wxString newvalue;
401 bool changed = EndEdit(row, col, grid, mOld, &newvalue);
402 if (changed) {
403 ApplyEdit(row, col, grid);
404 }
405 return changed;
406}
407
408bool ChoiceEditor::EndEdit(int WXUNUSED(row), int WXUNUSED(col),
409 const wxGrid* WXUNUSED(grid),
410 const wxString &WXUNUSED(oldval), wxString *newval)
411{
412 int sel = Choice()->GetSelection();
413
414 // This can happen if the wxChoice control is displayed and the list of choices get changed
415 if ((sel < 0) || (sel >= (int)(mChoices.size())))
416 {
417 return false;
418 }
419
420 wxString val = mChoices[sel];
421 bool changed = val != mOld;
422
423 if (changed)
424 {
425 mValueAsString = val;
426 *newval = val;
427 }
428
429 return changed;
430}
431
432void ChoiceEditor::ApplyEdit(int row, int col, wxGrid *grid)
433{
434 grid->GetTable()->SetValue(row, col, mValueAsString);
435}
436
438{
439 Choice()->SetSelection( make_iterator_range( mChoices ).index( mOld ) );
440}
441
442void ChoiceEditor::SetChoices(const wxArrayString &choices)
443{
444 mChoices = choices;
445}
446
448{
449 return mChoices[Choice()->GetSelection()];
450}
451
455
456BEGIN_EVENT_TABLE(Grid, wxGrid)
457 EVT_SET_FOCUS(Grid::OnSetFocus)
458 EVT_KEY_DOWN(Grid::OnKeyDown)
459 EVT_GRID_SELECT_CELL(Grid::OnSelectCell)
460 EVT_GRID_EDITOR_SHOWN(Grid::OnEditorShown)
462
464 const FormatterContext& context,
465 wxWindow* parent,
466 wxWindowID id,
467 const wxPoint& pos,
468 const wxSize& size,
469 long style,
470 const wxString& name)
471: wxGrid(parent, id, pos, size, style | wxWANTS_CHARS, name), mContext(context)
472{
473#if wxUSE_ACCESSIBILITY
474 GetGridWindow()->SetAccessible(mAx = safenew GridAx(mContext, this));
475#endif
476
477 // RegisterDataType takes ownership of renderer and editor
478
479 RegisterDataType(GRID_VALUE_TIME,
482 { mContext, NumericConverterType_TIME(),
484
485 RegisterDataType(GRID_VALUE_FREQUENCY,
488 { mContext, NumericConverterType_FREQUENCY(),
490
491 RegisterDataType(GRID_VALUE_CHOICE,
492 safenew wxGridCellStringRenderer,
494
495 // Bug #2803:
496 // Ensure selection doesn't show up.
497 SetSelectionForeground(GetDefaultCellTextColour());
498 SetSelectionBackground(GetDefaultCellBackgroundColour());
499}
500
502{
503#if wxUSE_ACCESSIBILITY
504 int cnt = mChildren.size();
505 while (cnt--) {
506 // PRL: I found this loop destroying right-to-left.
507 // Is the sequence of destruction important?
508 mChildren.pop_back();
509 }
510#endif
511}
512
513void Grid::OnSetFocus(wxFocusEvent &event)
514{
515 event.Skip();
516
517#if wxUSE_ACCESSIBILITY
518 mAx->SetCurrentCell(GetGridCursorRow(), GetGridCursorCol());
519#endif
520}
521
522void Grid::OnSelectCell(wxGridEvent &event)
523{
524 event.Skip();
525
526 MakeCellVisible(event.GetRow(), event.GetCol());
527
528#if wxUSE_ACCESSIBILITY
529 mAx->SetCurrentCell(event.GetRow(), event.GetCol());
530#endif
531}
532
533void Grid::OnEditorShown(wxGridEvent &event)
534{
535 event.Skip();
536
537 // Bug #2803 (comment 7):
538 // Select row whenever an editor is displayed
539 SelectRow(GetGridCursorRow());
540}
541
542void Grid::OnKeyDown(wxKeyEvent &event)
543{
544 auto keyCode = event.GetKeyCode();
545 int crow = GetGridCursorRow();
546 int ccol = GetGridCursorCol();
547
548 if (event.CmdDown() && crow != wxGridNoCellCoords.GetRow() && ccol != wxGridNoCellCoords.GetCol())
549 {
550 wxClipboardLocker cb;
551
552 switch (keyCode)
553 {
554 case 'C': // Copy
555 {
556 wxTextDataObject *data = safenew wxTextDataObject(GetCellValue(crow, ccol));
557 wxClipboard::Get()->SetData(data);
558 return;
559 }
560 break;
561
562 case 'X': // Cut
563 {
564 wxTextDataObject *data = safenew wxTextDataObject(GetCellValue(crow, ccol));
565 wxClipboard::Get()->SetData(data);
566 SetCellValue(crow, ccol, "" );
567 return;
568 }
569 break;
570
571 case 'V': // Paste
572 {
573 if (wxClipboard::Get()->IsSupported(wxDF_UNICODETEXT))
574 {
575 wxTextDataObject data;
576 if (wxClipboard::Get()->GetData(data))
577 {
578 SetCellValue(crow, ccol, data.GetText());
579 return;
580 }
581 }
582 }
583 break;
584 }
585 }
586
587 switch (keyCode)
588 {
589 case WXK_LEFT:
590 case WXK_RIGHT:
591 {
592 int rows = GetNumberRows();
593 int cols = GetNumberCols();
594
595 const bool has_cells = rows > 0 && cols > 0;
596
597 if (has_cells) {
598 int crow = GetGridCursorRow();
599 int ccol = GetGridCursorCol();
600
601 const bool has_no_selection = crow == wxGridNoCellCoords.GetRow() || ccol == wxGridNoCellCoords.GetCol();
602
603 if (has_no_selection) {
604 SetGridCursor(0, 0);
605 }
606 else if (event.GetKeyCode() == WXK_LEFT) {
607 if (crow == 0 && ccol == 0) {
608 // do nothing
609 }
610 else if (ccol == 0) {
611 SetGridCursor(crow - 1, cols - 1);
612 }
613 else {
614 SetGridCursor(crow, ccol - 1);
615 }
616 }
617 else {
618 if (crow == rows - 1 && ccol == cols - 1) {
619 // do nothing
620 }
621 else if (ccol == cols - 1) {
622 SetGridCursor(crow + 1, 0);
623 }
624 else {
625 SetGridCursor(crow, ccol + 1);
626 }
627 }
628 }
629
630#if wxUSE_ACCESSIBILITY
631 // Make sure the NEW cell is made available to the screen reader
632 mAx->SetCurrentCell(GetGridCursorRow(), GetGridCursorCol());
633#endif
634 }
635 break;
636
637 case WXK_TAB:
638 {
639 if (event.ControlDown()) {
640 int flags = wxNavigationKeyEvent::FromTab |
641 ( event.ShiftDown() ?
642 wxNavigationKeyEvent::IsBackward :
643 wxNavigationKeyEvent::IsForward );
644 Navigate(flags);
645 return;
646 }
647
648 int rows = GetNumberRows();
649 int cols = GetNumberCols();
650 int crow = GetGridCursorRow();
651 int ccol = GetGridCursorCol();
652
653 const auto is_empty = rows <= 0 || cols <= 0;
654 const auto has_no_selection = crow == wxGridNoCellCoords.GetRow() || ccol == wxGridNoCellCoords.GetCol();
655
656 if (event.ShiftDown()) {
657 if (is_empty) {
658 Navigate(wxNavigationKeyEvent::FromTab | wxNavigationKeyEvent::IsBackward);
659 return;
660 }
661
662 if (crow == 0 && ccol == 0) {
663 Navigate(wxNavigationKeyEvent::FromTab | wxNavigationKeyEvent::IsBackward);
664 return;
665 }
666
667 if (has_no_selection) {
668 SetGridCursor(rows -1, cols - 1);
669 }
670 else if (ccol == 0) {
671 SetGridCursor(crow - 1, cols - 1);
672 }
673 else {
674 SetGridCursor(crow, ccol - 1);
675 }
676 }
677 else {
678 if (is_empty) {
679 Navigate(wxNavigationKeyEvent::FromTab | wxNavigationKeyEvent::IsForward);
680 return;
681 }
682
683 if (crow == rows - 1 && ccol == cols - 1) {
684 Navigate(wxNavigationKeyEvent::FromTab | wxNavigationKeyEvent::IsForward);
685 return;
686 }
687
688 if (has_no_selection) {
689 SetGridCursor(0, 0);
690 }
691 else if (ccol == cols - 1) {
692 SetGridCursor(crow + 1, 0);
693 }
694 else {
695 SetGridCursor(crow, ccol + 1);
696 }
697 }
698
699 MakeCellVisible(GetGridCursorRow(), GetGridCursorCol());
700
701#if wxUSE_ACCESSIBILITY
702 // Make sure the NEW cell is made available to the screen reader
703 mAx->SetCurrentCell(GetGridCursorRow(), GetGridCursorCol());
704#endif
705 }
706 break;
707
708 case WXK_RETURN:
709 case WXK_NUMPAD_ENTER:
710 {
711 if (!IsCellEditControlShown()) {
712 wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow);
713 wxWindow *def = tlw->GetDefaultItem();
714 if (def && def->IsEnabled()) {
715 wxCommandEvent cevent(wxEVT_COMMAND_BUTTON_CLICKED,
716 def->GetId());
717 cevent.SetEventObject( def );
718 GetParent()->GetEventHandler()->ProcessEvent(cevent);
719 }
720 }
721 else {
722 wxGrid::OnKeyDown(event);
723
724 // This looks strange, but what it does is selects the cell when
725 // enter is pressed after editing. Without it, Jaws and Window-Eyes
726 // do not speak the NEW cell contents (the one below the edited one).
727 SetGridCursor(GetGridCursorRow(), GetGridCursorCol());
728 }
729 break;
730 }
731
732 default:
733 wxGrid::OnKeyDown(event);
734 break;
735 }
736}
737
738#if wxUSE_ACCESSIBILITY
739void Grid::ClearGrid()
740{
741 wxGrid::ClearGrid();
742
743 mAx->TableUpdated();
744
745 return;
746}
747
748bool Grid::InsertRows(int pos, int numRows, bool updateLabels)
749{
750 bool res = wxGrid::InsertRows(pos, numRows, updateLabels);
751
752 mAx->TableUpdated();
753
754 return res;
755}
756
757bool Grid::AppendRows(int numRows, bool updateLabels)
758{
759 bool res = wxGrid::AppendRows(numRows, updateLabels);
760
761 mAx->TableUpdated();
762
763 return res;
764}
765
766bool Grid::DeleteRows(int pos, int numRows, bool updateLabels)
767{
768 bool res = wxGrid::DeleteRows(pos, numRows, updateLabels);
769
770 mAx->TableUpdated();
771
772 return res;
773}
774
775bool Grid::InsertCols(int pos, int numCols, bool updateLabels)
776{
777 bool res = wxGrid::InsertCols(pos, numCols, updateLabels);
778
779 mAx->TableUpdated();
780
781 return res;
782}
783
784bool Grid::AppendCols(int numCols, bool updateLabels)
785{
786 bool res = wxGrid::AppendCols(numCols, updateLabels);
787
788 mAx->TableUpdated();
789
790 return res;
791}
792
793bool Grid::DeleteCols(int pos, int numCols, bool updateLabels)
794{
795 bool res = wxGrid::DeleteCols(pos, numCols, updateLabels);
796
797 mAx->TableUpdated();
798
799 return res;
800}
801
802GridAx::GridAx(const FormatterContext& context, Grid* grid)
803 : WindowAccessible(grid->GetGridWindow())
804 , mContext(context)
805{
806 mGrid = grid;
807 mLastId = -1;
808}
809
810void GridAx::TableUpdated()
811{
812 NotifyEvent(wxACC_EVENT_OBJECT_REORDER,
813 mGrid->GetGridWindow(),
814 wxOBJID_CLIENT,
815 0);
816}
817
818void GridAx::SetCurrentCell(int row, int col)
819{
820 int id = (((row * mGrid->GetNumberCols()) + col) + 1);
821
822 if (mLastId != -1) {
823 NotifyEvent(wxACC_EVENT_OBJECT_SELECTIONREMOVE,
824 mGrid->GetGridWindow(),
825 wxOBJID_CLIENT,
826 mLastId);
827 }
828
829 if (mGrid == wxWindow::FindFocus()) {
830 NotifyEvent(wxACC_EVENT_OBJECT_FOCUS,
831 mGrid->GetGridWindow(),
832 wxOBJID_CLIENT,
833 id);
834 }
835
836 NotifyEvent(wxACC_EVENT_OBJECT_SELECTION,
837 mGrid->GetGridWindow(),
838 wxOBJID_CLIENT,
839 id);
840
841 mLastId = id;
842}
843
844bool GridAx::GetRowCol(int childId, int & row, int & col)
845{
846 if (childId == wxACC_SELF) {
847 return false;
848 }
849
850 int cols = mGrid->GetNumberCols();
851 int id = childId - 1;
852
853 row = id / cols;
854 col = id % cols;
855
856 return true;
857}
858
859// Retrieves the address of an IDispatch interface for the specified child.
860// All objects must support this property.
861wxAccStatus GridAx::GetChild(int childId, wxAccessible** child)
862{
863 if (childId == wxACC_SELF) {
864 *child = this;
865 }
866 else {
867 *child = NULL;
868 }
869
870 return wxACC_OK;
871}
872
873// Gets the number of children.
874wxAccStatus GridAx::GetChildCount(int *childCount)
875{
876 *childCount = mGrid->GetNumberRows() * mGrid->GetNumberCols();
877
878 return wxACC_OK;
879}
880
881// Gets the default action for this object (0) or > 0 (the action for a child).
882// Return wxACC_OK even if there is no action. actionName is the action, or the empty
883// string if there is no action.
884// The retrieved string describes the action that is performed on an object,
885// not what the object does as a result. For example, a toolbar button that prints
886// a document has a default action of "Press" rather than "Prints the current document."
887wxAccStatus GridAx::GetDefaultAction(int WXUNUSED(childId), wxString *actionName)
888{
889 actionName->clear();
890
891 return wxACC_OK;
892}
893
894// Returns the description for this object or a child.
895wxAccStatus GridAx::GetDescription(int WXUNUSED(childId), wxString *description)
896{
897 description->clear();
898
899 return wxACC_OK;
900}
901
902// Returns help text for this object or a child, similar to tooltip text.
903wxAccStatus GridAx::GetHelpText(int WXUNUSED(childId), wxString *helpText)
904{
905 helpText->clear();
906
907 return wxACC_OK;
908}
909
910// Returns the keyboard shortcut for this object or child.
911// Return e.g. ALT+K
912wxAccStatus GridAx::GetKeyboardShortcut(int WXUNUSED(childId), wxString *shortcut)
913{
914 shortcut->clear();
915
916 return wxACC_OK;
917}
918
919// Returns the rectangle for this object (id = 0) or a child element (id > 0).
920// rect is in screen coordinates.
921wxAccStatus GridAx::GetLocation(wxRect & rect, int elementId)
922{
923 wxRect r;
924 int row;
925 int col;
926
927 if (GetRowCol(elementId, row, col)) {
928 rect = mGrid->CellToRect(row, col);
929 rect.SetPosition(mGrid->CalcScrolledPosition(rect.GetPosition()));
930 rect.SetPosition(mGrid->GetGridWindow()->ClientToScreen(rect.GetPosition()));
931 }
932 else {
933 rect = mGrid->GetRect();
934 rect.SetPosition(mGrid->GetParent()->ClientToScreen(rect.GetPosition()));
935 }
936
937 return wxACC_OK;
938}
939
940// Gets the name of the specified object.
941wxAccStatus GridAx::GetName(int childId, wxString *name)
942{
943 int row;
944 int col;
945
946 if (GetRowCol(childId, row, col)) {
947 wxString n = mGrid->GetColLabelValue(col);
948 wxString v = mGrid->GetCellValue(row, col);
949 if (v.empty()) {
950 v = _("Empty");
951 }
952
953 // Hack to provide a more intelligible response
954 NumericEditor *dt =
955 static_cast<NumericEditor *>(mGrid->GetDefaultEditorForType(GRID_VALUE_TIME));
956 NumericEditor *df =
957 static_cast<NumericEditor *>(mGrid->GetDefaultEditorForType(GRID_VALUE_FREQUENCY));
958 NumericEditor *c =
959 static_cast<NumericEditor *>(mGrid->GetCellEditor(row, col));
960
961 if (c && dt && df && ( c == dt || c == df)) {
962 double value;
963 v.ToDouble(&value);
965 c->GetFormat(),
966 value);
967
968 v = converter.GetString();
969 }
970
971 if (c)
972 c->DecRef();
973 if (dt)
974 dt->DecRef();
975 if (df)
976 df->DecRef();
977
978 *name = n + wxT(" ") + v;
979 }
980
981 return wxACC_OK;
982}
983
984wxAccStatus GridAx::GetParent(wxAccessible ** WXUNUSED(parent))
985{
986 return wxACC_NOT_IMPLEMENTED;
987}
988
989// Returns a role constant.
990wxAccStatus GridAx::GetRole(int childId, wxAccRole *role)
991{
992 if (childId == wxACC_SELF) {
993#if defined(__WXMSW__)
994 *role = wxROLE_SYSTEM_TABLE;
995#endif
996
997#if defined(__WXMAC__)
998 *role = wxROLE_SYSTEM_GROUPING;
999#endif
1000 }
1001 else {
1002 *role = wxROLE_SYSTEM_TEXT;
1003 }
1004
1005 return wxACC_OK;
1006}
1007
1008// Gets a variant representing the selected children
1009// of this object.
1010// Acceptable values:
1011// - a null variant (IsNull() returns TRUE)
1012// - a list variant (GetType() == wxT("list"))
1013// - an integer representing the selected child element,
1014// or 0 if this object is selected (GetType() == wxT("long"))
1015// - a "void*" pointer to a wxAccessible child object
1016wxAccStatus GridAx::GetSelections(wxVariant * WXUNUSED(selections))
1017{
1018 return wxACC_NOT_IMPLEMENTED;
1019}
1020
1021// Returns a state constant.
1022wxAccStatus GridAx::GetState(int childId, long *state)
1023{
1024 int flag = wxACC_STATE_SYSTEM_FOCUSABLE |
1025 wxACC_STATE_SYSTEM_SELECTABLE;
1026 int col;
1027 int row;
1028
1029 if (!GetRowCol(childId, row, col)) {
1030 *state = 0;
1031 return wxACC_FAIL;
1032 }
1033
1034#if defined(__WXMSW__)
1035 flag |= wxACC_STATE_SYSTEM_FOCUSED |
1036 wxACC_STATE_SYSTEM_SELECTED;
1037
1038 if (mGrid->IsReadOnly(row, col)) {
1039 // It would be more logical to also include the state
1040 // wxACC_STATE_SYSTEM_FOCUSABLE, but this causes Window-Eyes to
1041 // no longer read the cell as disabled
1042 flag = wxACC_STATE_SYSTEM_UNAVAILABLE | wxACC_STATE_SYSTEM_FOCUSED;
1043 }
1044#endif
1045
1046#if defined(__WXMAC__)
1047 if (mGrid->IsInSelection(row, col)) {
1048 flag |= wxACC_STATE_SYSTEM_SELECTED;
1049 }
1050
1051 if (mGrid->GetGridCursorRow() == row && mGrid->GetGridCursorCol() == col) {
1052 flag |= wxACC_STATE_SYSTEM_FOCUSED;
1053 }
1054
1055 if (mGrid->IsReadOnly(row, col)) {
1056 flag |= wxACC_STATE_SYSTEM_UNAVAILABLE;
1057 }
1058#endif
1059
1060 *state = flag;
1061
1062 return wxACC_OK;
1063}
1064
1065// Returns a localized string representing the value for the object
1066// or child.
1067#if defined(__WXMAC__)
1068wxAccStatus GridAx::GetValue(int childId, wxString *strValue)
1069#else
1070wxAccStatus GridAx::GetValue(int WXUNUSED(childId), wxString *strValue)
1071#endif
1072{
1073 strValue->clear();
1074
1075#if defined(__WXMSW__)
1076 return wxACC_OK;
1077#endif
1078
1079#if defined(__WXMAC__)
1080 return GetName(childId, strValue);
1081#endif
1082}
1083
1084#if defined(__WXMAC__)
1085// Selects the object or child.
1086wxAccStatus GridAx::Select(int childId, wxAccSelectionFlags selectFlags)
1087{
1088 int row;
1089 int col;
1090
1091 if (GetRowCol(childId, row, col)) {
1092
1093 if (selectFlags & wxACC_SEL_TAKESELECTION) {
1094 mGrid->SetGridCursor(row, col);
1095 }
1096
1097 mGrid->SelectBlock(row, col, row, col, selectFlags & wxACC_SEL_ADDSELECTION);
1098 }
1099
1100 return wxACC_OK;
1101}
1102#endif
1103
1104// Gets the window with the keyboard focus.
1105// If childId is 0 and child is NULL, no object in
1106// this subhierarchy has the focus.
1107// If this object has the focus, child should be 'this'.
1108wxAccStatus GridAx::GetFocus(int * childId, wxAccessible **child)
1109{
1110 if (mGrid == wxWindow::FindFocus()) {
1111 if (mGrid->GetNumberRows() * mGrid->GetNumberCols() == 0) {
1112 *child = this;
1113 }
1114 else {
1115 *childId = mGrid->GetGridCursorRow()*mGrid->GetNumberCols() +
1116 mGrid->GetGridCursorCol() + 1;
1117 }
1118 }
1119
1120 return wxACC_OK;
1121}
1122
1123#endif // wxUSE_ACCESSIBILITY
wxEVT_COMMAND_BUTTON_CLICKED
wxT("CloseDown"))
END_EVENT_TABLE()
#define GRID_VALUE_TIME
Definition: Grid.h:36
#define GRID_VALUE_FREQUENCY
Definition: Grid.h:37
#define GRID_VALUE_CHOICE
Definition: Grid.h:123
#define _(s)
Definition: Internat.h:73
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: IteratorX.h:210
#define safenew
Definition: MemoryX.h:10
const NumericConverterType & NumericConverterType_FREQUENCY()
const NumericConverterType & NumericConverterType_TIME()
wxString name
Definition: TagsEditor.cpp:166
const auto project
int id
static std::once_flag flag
void ConnectEvent(wxWindow *w)
Definition: Grid.h:163
void DisconnectEvent(wxWindow *w)
Definition: Grid.h:169
Modified version of wxGridChoiceEditor using wxChoice instead of wxComboBox.
Definition: Grid.h:127
wxChoice * Choice() const
Definition: Grid.h:155
void SetSize(const wxRect &rect) override
Definition: Grid.cpp:374
void Create(wxWindow *parent, wxWindowID id, wxEvtHandler *evtHandler) override
Definition: Grid.cpp:362
wxArrayString mChoices
Definition: Grid.h:179
wxString mOld
Definition: Grid.h:180
bool EndEdit(int row, int col, wxGrid *grid)
Definition: Grid.cpp:398
void ApplyEdit(int row, int col, wxGrid *grid) override
Definition: Grid.cpp:432
void Reset() override
Definition: Grid.cpp:437
wxGridCellEditor * Clone() const override
Definition: Grid.cpp:357
wxString GetValue() const override
Definition: Grid.cpp:447
ChoiceEditor::FocusHandler mHandler
~ChoiceEditor()
Definition: Grid.cpp:350
ChoiceEditor(size_t count=0, const wxString choices[]=NULL)
Definition: Grid.cpp:335
void BeginEdit(int row, int col, wxGrid *grid) override
Definition: Grid.cpp:385
wxString mValueAsString
Definition: Grid.h:181
void SetChoices(const wxArrayString &choices)
Definition: Grid.cpp:442
const wxString & Internal() const
A context in which formatter operates.
Supplies an accessible grid based on wxGrid.
Definition: Grid.h:190
~Grid()
Definition: Grid.cpp:501
void OnKeyDown(wxKeyEvent &event)
Definition: Grid.cpp:542
void OnSelectCell(wxGridEvent &event)
Definition: Grid.cpp:522
void OnSetFocus(wxFocusEvent &event)
Definition: Grid.cpp:513
void OnEditorShown(wxGridEvent &event)
Definition: Grid.cpp:533
An explicitly nonlocalized string, not meant for the user to see.
Definition: Identifier.h:22
NumericConverter provides the advanced formatting control used in the selection bar of Audacity.
wxGridCellEditor for the NumericTextCtrl.
Definition: Grid.h:40
void Reset() override
Definition: Grid.cpp:199
wxString mOldString
Definition: Grid.h:77
NumericFormatID mFormat
Definition: Grid.h:74
NumericTextCtrl * GetNumericTextControl() const
Definition: Grid.h:69
wxString GetValue() const override
Definition: Grid.cpp:221
void ApplyEdit(int row, int col, wxGrid *grid) override
Definition: Grid.cpp:194
void SetFormat(const NumericFormatID &format)
Definition: Grid.cpp:231
void Create(wxWindow *parent, wxWindowID id, wxEvtHandler *handler) override
Definition: Grid.cpp:137
~NumericEditor()
Definition: Grid.cpp:133
NumericConverterType mType
Definition: Grid.h:75
FormatterContext mContext
Definition: Grid.h:80
bool IsAcceptedKey(wxKeyEvent &event) override
Definition: Grid.cpp:204
NumericEditor(const FormatterContext &context, NumericConverterType type, const NumericFormatID &format)
Definition: Grid.cpp:123
void SetSize(const wxRect &rect) override
Definition: Grid.cpp:155
NumericFormatID GetFormat() const
Definition: Grid.cpp:226
double mOld
Definition: Grid.h:76
void BeginEdit(int row, int col, wxGrid *grid) override
Definition: Grid.cpp:166
wxString mValueAsString
Definition: Grid.h:78
bool EndEdit(int row, int col, const wxGrid *grid, const wxString &oldval, wxString *newval) override
Definition: Grid.cpp:181
wxGridCellEditor * Clone() const override
Definition: Grid.cpp:216
wxGridCellRenderer for the NumericTextCtrl.
Definition: Grid.h:88
FormatterContext mContext
Definition: Grid.h:115
wxGridCellRenderer * Clone() const override
Definition: Grid.cpp:330
~NumericRenderer() override
Definition: Grid.cpp:236
void Draw(wxGrid &grid, wxGridCellAttr &attr, wxDC &dc, const wxRect &rect, int row, int col, bool isSelected) override
Definition: Grid.cpp:240
NumericConverterType mType
Definition: Grid.h:114
wxSize GetBestSize(wxGrid &grid, wxGridCellAttr &attr, wxDC &dc, int row, int col) override
Definition: Grid.cpp:301
void SetValue(double newValue)
static const int UndefinedFrequency
An alternative to using wxWindowAccessible, which in wxWidgets 3.1.1 contained GetParent() which was ...
Services * Get()
Fetch the global instance, or nullptr if none is yet installed.
Definition: BasicUI.cpp:202
std::unique_ptr< WindowPlacement > FindFocus()
Find the window that is accepting keyboard input, if any.
Definition: BasicUI.h:383
NUMERIC_FORMATS_API NumericFormatSymbol HertzFormat()
NUMERIC_FORMATS_API NumericFormatSymbol SecondsFormat()
Options & AutoPos(bool enable)