Audacity  3.0.3
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 /**********************************************************************/
39 class 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 
135 void 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 
154 void 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 
165 void 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 
180 bool 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 
193 void NumericEditor::ApplyEdit(int row, int col, wxGrid *grid)
194 {
195  grid->GetTable()->SetValue(row, col, mValueAsString);
196 }
197 
199 {
201 }
202 
203 bool 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
215 wxGridCellEditor *NumericEditor::Clone() const
216 {
218 }
219 
220 wxString NumericEditor::GetValue() const
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 
240 void NumericEditor::SetRate(double rate)
241 {
242  mRate = rate;
243 }
244 
246 {
247 }
248 
249 void 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 
311 wxSize NumericRenderer::GetBestSize(wxGrid &grid,
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
341 wxGridCellRenderer *NumericRenderer::Clone() const
342 {
343  return safenew NumericRenderer{ mType };
344 }
345 
346 ChoiceEditor::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 
356 ChoiceEditor::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
368 wxGridCellEditor *ChoiceEditor::Clone() const
369 {
370  return safenew ChoiceEditor(mChoices);
371 }
372 
373 void 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 
385 void 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 
396 void 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 
409 bool 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 
419 bool 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 
443 void 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 
453 void ChoiceEditor::SetChoices(const wxArrayString &choices)
454 {
455  mChoices = choices;
456 }
457 
458 wxString ChoiceEditor::GetValue() const
459 {
460  return mChoices[Choice()->GetSelection()];
461 }
462 
466 
467 BEGIN_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 
474 Grid::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,
492  NumericConverter::SecondsFormat(), 44100.0 });
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 
522 void Grid::OnSetFocus(wxFocusEvent &event)
523 {
524  event.Skip();
525 
526 #if wxUSE_ACCESSIBILITY
527  mAx->SetCurrentCell(GetGridCursorRow(), GetGridCursorCol());
528 #endif
529 }
530 
531 void 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 
542 void 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 
551 void 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
748 void Grid::ClearGrid()
749 {
750  wxGrid::ClearGrid();
751 
752  mAx->TableUpdated();
753 
754  return;
755 }
756 
757 bool 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 
766 bool Grid::AppendRows(int numRows, bool updateLabels)
767 {
768  bool res = wxGrid::AppendRows(numRows, updateLabels);
769 
770  mAx->TableUpdated();
771 
772  return res;
773 }
774 
775 bool 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 
784 bool 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 
793 bool Grid::AppendCols(int numCols, bool updateLabels)
794 {
795  bool res = wxGrid::AppendCols(numCols, updateLabels);
796 
797  mAx->TableUpdated();
798 
799  return res;
800 }
801 
802 bool 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 
811 GridAx::GridAx(Grid *grid)
812 : WindowAccessible(grid->GetGridWindow())
813 {
814  mGrid = grid;
815  mLastId = -1;
816 }
817 
818 void GridAx::TableUpdated()
819 {
820  NotifyEvent(wxACC_EVENT_OBJECT_REORDER,
821  mGrid->GetGridWindow(),
822  wxOBJID_CLIENT,
823  0);
824 }
825 
826 void 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 
852 bool 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.
869 wxAccStatus 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.
882 wxAccStatus 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."
895 wxAccStatus 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.
903 wxAccStatus 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.
911 wxAccStatus 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
920 wxAccStatus 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.
929 wxAccStatus 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.
949 wxAccStatus 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 
993 wxAccStatus GridAx::GetParent(wxAccessible ** WXUNUSED(parent))
994 {
995  return wxACC_NOT_IMPLEMENTED;
996 }
997 
998 // Returns a role constant.
999 wxAccStatus 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
1025 wxAccStatus GridAx::GetSelections(wxVariant * WXUNUSED(selections))
1026 {
1027  return wxACC_NOT_IMPLEMENTED;
1028 }
1029 
1030 // Returns a state constant.
1031 wxAccStatus 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__)
1077 wxAccStatus GridAx::GetValue(int childId, wxString *strValue)
1078 #else
1079 wxAccStatus 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.
1095 wxAccStatus 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'.
1117 wxAccStatus 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
ChoiceEditor::ChoiceEditor
ChoiceEditor(size_t count=0, const wxString choices[]=NULL)
Definition: Grid.cpp:346
ChoiceEditor::mHandler
ChoiceEditor::FocusHandler mHandler
ChoiceEditor::FocusHandler::DisconnectEvent
void DisconnectEvent(wxWindow *w)
Definition: Grid.h:164
NumericEditor::GetRate
double GetRate() const
Definition: Grid.cpp:230
ChoiceEditor::EndEdit
bool EndEdit(int row, int col, wxGrid *grid)
Definition: Grid.cpp:409
NumericEditor::mFormat
NumericFormatSymbol mFormat
Definition: Grid.h:74
ChoiceEditor::Choice
wxChoice * Choice() const
Definition: Grid.h:150
NumericEditor::Reset
void Reset() override
Definition: Grid.cpp:198
make_iterator_range
IteratorRange< Iterator > make_iterator_range(const Iterator &i1, const Iterator &i2)
Definition: MemoryX.h:549
GRID_VALUE_FREQUENCY
#define GRID_VALUE_FREQUENCY
Definition: Grid.h:35
NumericTextCtrl::Options::AutoPos
Options & AutoPos(bool enable)
Definition: NumericTextCtrl.h:190
GRID_VALUE_TIME
#define GRID_VALUE_TIME
Definition: Grid.h:34
ChoiceEditor::mValueAsString
wxString mValueAsString
Definition: Grid.h:176
flag
static std::once_flag flag
Definition: WaveformView.cpp:1124
Grid::~Grid
~Grid()
Definition: Grid.cpp:510
NumericRenderer::~NumericRenderer
~NumericRenderer() override
Definition: Grid.cpp:245
ChoiceEditor::ApplyEdit
void ApplyEdit(int row, int col, wxGrid *grid) override
Definition: Grid.cpp:443
Grid
Supplies an accessible grid based on wxGrid.
Definition: Grid.h:185
Grid.h
SelectedRegion.h
Grid::OnEditorShown
void OnEditorShown(wxGridEvent &event)
Definition: Grid.cpp:542
NumericEditor::mType
NumericConverter::Type mType
Definition: Grid.h:76
Grid::OnKeyDown
void OnKeyDown(wxKeyEvent &event)
Definition: Grid.cpp:551
ChoiceEditor::GetValue
wxString GetValue() const override
Definition: Grid.cpp:458
ChoiceEditor::mChoices
wxArrayString mChoices
Definition: Grid.h:174
NumericEditor::mOldString
wxString mOldString
Definition: Grid.h:78
GRID_VALUE_CHOICE
#define GRID_VALUE_CHOICE
Definition: Grid.h:117
ChoiceEditor::Reset
void Reset() override
Definition: Grid.cpp:448
SelectedRegion::UndefinedFrequency
static const int UndefinedFrequency
Definition: SelectedRegion.h:41
NumericConverter::HertzFormat
static NumericFormatSymbol HertzFormat()
Definition: NumericTextCtrl.cpp:699
NumericEditor::NumericEditor
NumericEditor(NumericConverter::Type type, const NumericFormatSymbol &format, double rate)
Definition: Grid.cpp:123
NumericTextCtrl
Definition: NumericTextCtrl.h:172
NumericTextCtrl::SetValue
void SetValue(double newValue)
Definition: NumericTextCtrl.cpp:1472
NumericEditor::GetFormat
NumericFormatSymbol GetFormat() const
Definition: Grid.cpp:225
ComponentInterfaceSymbol
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
Definition: ComponentInterfaceSymbol.h:27
NumericTextCtrl::Options
Definition: NumericTextCtrl.h:178
NumericEditor::mValueAsString
wxString mValueAsString
Definition: Grid.h:79
NumericEditor::BeginEdit
void BeginEdit(int row, int col, wxGrid *grid) override
Definition: Grid.cpp:165
ChoiceEditor::SetSize
void SetSize(const wxRect &rect) override
Definition: Grid.cpp:385
NumericEditor::EndEdit
bool EndEdit(int row, int col, const wxGrid *grid, const wxString &oldval, wxString *newval) override
Definition: Grid.cpp:180
NumericEditor::GetNumericTextControl
NumericTextCtrl * GetNumericTextControl() const
Definition: Grid.h:69
NumericRenderer
wxGridCellRenderer for the NumericTextCtrl.
Definition: Grid.h:87
BasicUI::Get
Services * Get()
Fetch the global instance, or nullptr if none is yet installed.
Definition: BasicUI.cpp:26
NumericEditor::mRate
double mRate
Definition: Grid.h:75
ChoiceEditor::~ChoiceEditor
~ChoiceEditor()
Definition: Grid.cpp:361
name
const TranslatableString name
Definition: Distortion.cpp:98
NumericConverter::TIME
@ TIME
Definition: NumericTextCtrl.h:52
ChoiceEditor::Create
void Create(wxWindow *parent, wxWindowID id, wxEvtHandler *evtHandler) override
Definition: Grid.cpp:373
NumericRenderer::mType
NumericConverter::Type mType
Definition: Grid.h:109
format
int format
Definition: ExportPCM.cpp:56
ChoiceEditor::FocusHandler::ConnectEvent
void ConnectEvent(wxWindow *w)
Definition: Grid.h:158
WindowAccessible
An alternative to using wxWindowAccessible, which in wxWidgets 3.1.1 contained GetParent() which was ...
NumericEditor::mOld
double mOld
Definition: Grid.h:77
Grid::OnSelectCell
void OnSelectCell(wxGridEvent &event)
Definition: Grid.cpp:531
NumericConverter::FREQUENCY
@ FREQUENCY
Definition: NumericTextCtrl.h:54
NumericEditor::SetRate
void SetRate(double rate)
Definition: Grid.cpp:240
NumericEditor
wxGridCellEditor for the NumericTextCtrl.
Definition: Grid.h:38
id
int id
Definition: WaveTrackControls.cpp:591
ChoiceEditor::BeginEdit
void BeginEdit(int row, int col, wxGrid *grid) override
Definition: Grid.cpp:396
NumericConverter::GetString
wxString GetString()
Definition: NumericTextCtrl.cpp:1228
NumericRenderer::GetBestSize
wxSize GetBestSize(wxGrid &grid, wxGridCellAttr &attr, wxDC &dc, int row, int col) override
Definition: Grid.cpp:311
NumericConverter
NumericConverter provides the advanced formatting control used in the selection bar of Audacity.
Definition: NumericTextCtrl.h:48
WindowAccessible.h
ChoiceEditor::Clone
wxGridCellEditor * Clone() const override
Definition: Grid.cpp:368
NumericRenderer::Clone
wxGridCellRenderer * Clone() const override
Definition: Grid.cpp:341
ChoiceEditor::mOld
wxString mOld
Definition: Grid.h:175
_
#define _(s)
Definition: Internat.h:75
ChoiceEditor
Modified version of wxGridChoiceEditor using wxChoice instead of wxComboBox.
Definition: Grid.h:121
NumericEditor::Clone
wxGridCellEditor * Clone() const override
Definition: Grid.cpp:215
NumericRenderer::Draw
void Draw(wxGrid &grid, wxGridCellAttr &attr, wxDC &dc, const wxRect &rect, int row, int col, bool isSelected) override
Definition: Grid.cpp:249
NumericEditor::IsAcceptedKey
bool IsAcceptedKey(wxKeyEvent &event) override
Definition: Grid.cpp:203
NumericEditor::SetSize
void SetSize(const wxRect &rect) override
Definition: Grid.cpp:154
ChoiceEditor::SetChoices
void SetChoices(const wxArrayString &choices)
Definition: Grid.cpp:453
NumericEditor::Create
void Create(wxWindow *parent, wxWindowID id, wxEvtHandler *handler) override
Definition: Grid.cpp:135
NumericEditor::SetFormat
void SetFormat(const NumericFormatSymbol &format)
Definition: Grid.cpp:235
NumericEditor::~NumericEditor
~NumericEditor()
Definition: Grid.cpp:131
anonymous_namespace{wxWidgetsBasicUI.cpp}::GetParent
wxWindow * GetParent(const BasicUI::WindowPlacement &placement)
Definition: wxWidgetsBasicUI.cpp:39
safenew
#define safenew
Definition: MemoryX.h:10
NumericConverter::Type
Type
Definition: NumericTextCtrl.h:51
NumericConverter::GetValue
double GetValue()
Definition: NumericTextCtrl.cpp:1172
END_EVENT_TABLE
END_EVENT_TABLE()
NumericEditor::ApplyEdit
void ApplyEdit(int row, int col, wxGrid *grid) override
Definition: Grid.cpp:193
Grid::OnSetFocus
void OnSetFocus(wxFocusEvent &event)
Definition: Grid.cpp:522
NumericEditor::GetValue
wxString GetValue() const override
Definition: Grid.cpp:220
NumericConverter::SecondsFormat
static NumericFormatSymbol SecondsFormat()
Definition: NumericTextCtrl.cpp:692