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