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