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