Audacity 3.2.0
AButton.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 AButton.cpp
6
7 Dominic Mazzoni
8
9*******************************************************************//*******************************************************************/
23
24
25#include "AButton.h"
26
27#include "AColor.h"
28#include "AllThemeResources.h"
29#include "Theme.h"
30#include "TrackArt.h"
31
32#include <wx/setup.h> // for wxUSE_* macros
33
34#include <wx/dcbuffer.h>
35#include <wx/eventfilter.h>
36
37//This is needed for tooltips
38#include "Project.h"
39#include "ProjectStatus.h"
40#include "../ProjectWindowBase.h"
41#include <wx/tooltip.h>
42
43
44BEGIN_EVENT_TABLE(AButton, wxWindow)
45 EVT_MOUSE_EVENTS(AButton::OnMouseEvent)
46 EVT_MOUSE_CAPTURE_LOST(AButton::OnCaptureLost)
47 EVT_KEY_DOWN(AButton::OnKeyDown)
48 EVT_CHAR_HOOK(AButton::OnCharHook)
49 EVT_SET_FOCUS(AButton::OnSetFocus)
50 EVT_KILL_FOCUS(AButton::OnKillFocus)
51 EVT_PAINT(AButton::OnPaint)
52 EVT_SIZE(AButton::OnSize)
53 EVT_ERASE_BACKGROUND(AButton::OnErase)
55
56// LL: An alternative to this might be to just use the wxEVT_KILL_FOCUS
57// or wxEVT_ACTIVATE events.
58class AButton::Listener final
59 : public wxEventFilter
60{
61public:
62 Listener (AButton *button);
63 ~Listener();
64
65 int FilterEvent(wxEvent &event) override;
66
67 void OnEvent();
68
69private:
71};
72
74: mButton(button)
75{
76 wxEvtHandler::AddFilter(this);
77}
78
80{
81 wxEvtHandler::RemoveFilter(this);
82}
83
85{
86 if (!mButton->IsDown())
87 {
88 int idx = 0;
89 // Ignore the event, consult key states. One modifier key might
90 // have gone up but another remained down.
91 // Note that CMD (or CTRL) takes precedence over Shift if both are down
92 // and alternates are defined for both
93 // see also AButton::OnMouseEvent()
94 if (wxGetKeyState(WXK_CONTROL) && mButton->HasAlternateImages(2))
95 idx = 2;
96 else if (wxGetKeyState(WXK_SHIFT) && mButton->HasAlternateImages(1))
97 idx = 1;
98
99 // Turn e.g. the "Play" button into a "Loop" button
100 // or "Cut Preview" button
101 mButton->SetAlternateIdx(idx);
102 }
103}
104
106{
107 if (event.GetEventType() == wxEVT_KEY_DOWN ||
108 event.GetEventType() == wxEVT_KEY_UP)
109 OnEvent();
110 else if (event.GetEventType() == wxEVT_SET_FOCUS)
111 // A modal dialog might have eaten the modifier key-up with its own
112 // filter before we saw it; this is adequate to fix the button image
113 // when the dialog disappears.
114 OnEvent();
115 return Event_Skip;
116}
117
118AButton::AButton(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, bool toggle)
119{
120 Init(parent, id, pos, size, toggle);
121}
122
123AButton::AButton(wxWindow * parent,
124 wxWindowID id,
125 const wxPoint & pos,
126 const wxSize & size,
127 const wxImage& up,
128 const wxImage& over,
129 const wxImage& down,
130 const wxImage& overDown,
131 const wxImage& dis,
132 bool toggle)
133{
134 Init(parent, id, pos, size, toggle);
135
136 SetAlternateImages(0, up, over, down, overDown, dis);
137
138 SetMinSize(mImages[0][AButtonUp].GetSize());
139 SetMaxSize(mImages[0][AButtonUp].GetSize());
140}
141
143{
144 if(HasCapture())
145 ReleaseMouse();
146}
147
149{
150 if(mType != type)
151 {
152 mType = type;
153 InvalidateBestSize();
154 Refresh(false);
155 PostSizeEventToParent();
156 }
157}
158
160{
161 if(mid == mFrameMid)
162 return;
163 mFrameMid = mid;
164
165 if(mType == FrameButton)
166 {
167 InvalidateBestSize();
168 Refresh(false);
169 PostSizeEventToParent();
170 }
171}
172
173
174void AButton::Init(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, bool toggle)
175{
176 SetBackgroundStyle(wxBG_STYLE_PAINT);
177 SetBackgroundColour(theTheme.Colour(clrMedium));
178
179 // Bug in wxWidgets 2.8.12: by default pressing Enter on an AButton is interpreted as
180 // a navigation event - move to next control. As a workaround, the style wxWANTS_CHARS
181 // results in all characters being available in the OnKeyDown function below. Note
182 // that OnKeyDown now has to handle navigation.
183 Create(parent, id, pos, size, wxWANTS_CHARS);
184
185 mToggle = toggle;
186
187 mFocusRect = GetClientRect().Deflate( 3, 3 );
188
189#if wxUSE_ACCESSIBILITY
190 SetName( wxT("") );
191 SetAccessible(safenew AButtonAx(this));
192#endif
193}
194
196{
198}
199
201{
202 wxWindow::SetToolTip( toolTip.Stripped().Translation() );
203}
204
206{
207 wxWindow::SetLabel( toolTip.Stripped().Translation() );
208 if(mType == FrameButton)
209 InvalidateBestSize();
210}
211
212// This compensates for a but in wxWidgets 3.0.2 for mac:
213// Couldn't set focus from keyboard when AcceptsFocus returns false;
214// this bypasses that limitation
216{
217 auto temp = TemporarilyAllowFocus();
218 SetFocus();
219}
220
221void AButton::SetImages(const wxImage& up, const wxImage& over, const wxImage& down, const wxImage& overDown, const wxImage& dis)
222{
223 SetAlternateImages(0, up, over, down, overDown, dis);
224}
225
227 const wxImage& up,
228 const wxImage& over,
229 const wxImage& down,
230 const wxImage& overDown,
231 const wxImage& dis)
232{
233 if (1 + idx > mImages.size())
234 mImages.resize(1 + idx);
235 mImages[idx][AButtonUp] = up;
236 mImages[idx][AButtonOver] = over;
237 mImages[idx][AButtonDown] = down;
238 mImages[idx][AButtonOverDown] = overDown;
239 mImages[idx][AButtonDis] = dis;
240}
241
242void AButton::SetIcon(const wxImage& icon)
243{
244 SetAlternateIcon(0, icon);
245}
246
247void AButton::SetIcon(AButtonState state, const wxImage& icon)
248{
249 SetAlternateIcon(0, state, icon);
250}
251
252void AButton::SetIcons(const wxImage& up, const wxImage& down, const wxImage& disabled)
253{
254 SetAlternateIcons(0, up, down, disabled);
255}
256
257void AButton::SetAlternateIcon(unsigned idx, const wxImage& icon)
258{
259 if(1 + idx > mIcons.size())
260 mIcons.resize(1 + idx);
261 mIcons[idx][AButtonUp] = icon;
262 mIcons[idx][AButtonOver] = mIcons[idx][AButtonDown] =
263 mIcons[idx][AButtonDis] = mIcons[idx][AButtonOverDown] = wxNullImage;
264 Refresh(false);
265}
266
267void AButton::SetAlternateIcon(unsigned idx, AButtonState state, const wxImage& icon)
268{
269 if(1 + idx > mIcons.size())
270 mIcons.resize(1 + idx);
271 mIcons[idx][state] = icon;
272 Refresh(false);
273}
274
275void AButton::SetAlternateIcons(unsigned idx, const wxImage& up, const wxImage& down, const wxImage& disabled)
276{
277 if(1 + idx > mIcons.size())
278 mIcons.resize(1 + idx);
279 mIcons[idx][AButtonUp] = up;
280 mIcons[idx][AButtonOver] = up;
281 mIcons[idx][AButtonDown] = down;
282 mIcons[idx][AButtonOverDown] = down;
283 mIcons[idx][AButtonDis] = disabled;
284 Refresh(false);
285}
286
287void AButton::SetAlternateIdx(unsigned idx)
288{
289 // If alternate-image-state is already correct then
290 // nothing to do (saves repainting button).
291 if( mAlternateIdx == idx )
292 return;
293 mAlternateIdx = idx;
294 Refresh(false);
295 PostSizeEventToParent();
296}
297
299{
300 if(!mListener)
301 mListener = std::make_unique<Listener>(this);
302}
303
304void AButton::SetFocusRect(const wxRect & r)
305{
306 mFocusRect = r;
307 mForceFocusRect = true;
308}
309
311{
312 AButtonState state;
313
314 if (!mEnabled && (!mToggle || !mButtonIsDown))
315 return AButtonDis;
316
317 if (mCursorIsInWindow) {
318 if (mToggle) {
319 if (mIsClicking) {
323 }
324 }
325 else {
329 }
330 }
331 }
332 else {
333 if (mIsClicking) {
335 }
336 else {
338 }
339 }
340 }
341 else {
343 }
344
345 return state;
346}
347
348void AButton::OnPaint(wxPaintEvent & WXUNUSED(event))
349{
350 wxBufferedPaintDC dc(this);
351
352 dc.SetPen(*wxTRANSPARENT_PEN);
353 dc.SetBrush(GetBackgroundColour());
354 dc.Clear();
355
356 const auto buttonRect = GetClientRect();
357 const auto imageIdx = HasAlternateImages(mAlternateIdx) ? mAlternateIdx : 0;
358
359 if(imageIdx == mAlternateIdx || HasAlternateImages(imageIdx))
360 {
361 const auto buttonState = GetState();
362 if(mType == ImageButton)
363 dc.DrawBitmap(mImages[imageIdx][buttonState], buttonRect.GetTopLeft());
364 else if(mType == FrameButton || mType == FrameTextButton)
365 {
366 wxBitmap bitmap = mImages[imageIdx][buttonState];
367 AColor::DrawFrame(dc, buttonRect, bitmap, mFrameMid);
368
369 const auto border = bitmap.GetSize() / 4;
370
371 wxImage* icon{};
372 if(mIcons.size() > mAlternateIdx)
373 icon = &mIcons[mAlternateIdx][buttonState];
374 if((icon == nullptr || !icon->IsOk()) && !mIcons.empty())
375 {
376 icon = &mIcons[0][buttonState];
377 if(!icon->IsOk())
378 icon = &mIcons[0][AButtonUp];
379 }
380 if(mType == FrameTextButton && !GetLabel().IsEmpty())
381 {
382 dc.SetFont(GetFont());
383 auto textRect = buttonRect;
384 if(icon != nullptr && icon->IsOk())
385 {
386 auto fontMetrics = dc.GetFontMetrics();
387 auto sumHeight = fontMetrics.height + icon->GetHeight() + border.y;
388
389 dc.DrawBitmap(*icon,
390 buttonRect.x + (buttonRect.width - icon->GetWidth()) / 2,
391 buttonRect.y + (buttonRect.height - sumHeight) / 2);
392 textRect = wxRect(
393 buttonRect.x,
394 buttonRect.y + buttonRect.height / 2 + sumHeight / 2 - fontMetrics.height,
395 buttonRect.width,
396 fontMetrics.height);
397 }
398 dc.SetPen(GetForegroundColour());
399 dc.DrawLabel(GetLabel(), textRect, wxALIGN_CENTER);
400 }
401 else if(icon != nullptr && icon->IsOk())
402 {
403 dc.DrawBitmap(*icon,
404 buttonRect.x + (buttonRect.width - icon->GetWidth()) / 2,
405 buttonRect.y + (buttonRect.height - icon->GetHeight()) / 2);
406 }
407 }
408 else
409 {
410 wxBitmap bitmap = mImages[imageIdx][buttonState];
411 AColor::DrawHStretch(dc, GetClientRect(), bitmap);
412 if(!GetLabel().IsEmpty())
413 {
414 dc.SetFont(GetFont());
415 const auto text = TrackArt::TruncateText(dc, GetLabel(), GetClientSize().GetWidth() - 6);
416 if(!text.IsEmpty())
417 {
418 dc.SetPen(GetForegroundColour());
419 dc.DrawLabel(text, GetClientRect(), wxALIGN_CENTER);
420 }
421 }
422 }
423 }
424
425 if(HasFocus())
427}
428
429void AButton::OnErase(wxEraseEvent & WXUNUSED(event))
430{
431 // Ignore it to prevent flashing
432}
433
434void AButton::OnSize(wxSizeEvent & WXUNUSED(event))
435{
436 if (!mForceFocusRect)
437 {
438 mFocusRect = GetClientRect().Deflate( 3, 3 );
439 }
440 Refresh(false);
441}
442
443bool AButton::s_AcceptsFocus{ false };
444
445bool AButton::HasAlternateImages(unsigned idx) const
446{
447 if (mImages.size() <= idx)
448 return false;
449
450 const auto &arr = mImages[idx];
451 return (arr[0].Ok() &&
452 arr[1].Ok() &&
453 arr[2].Ok() &&
454 arr[3].Ok() &&
455 arr[4].Ok());
456}
457
458void AButton::OnMouseEvent(wxMouseEvent & event)
459{
460 wxSize clientSize = GetClientSize();
461 AButtonState prevState = GetState();
462
463 if (event.Entering()) {
464 // Bug 1201: On Mac, unsetting and re-setting the tooltip may be needed
465 // to make it pop up when we want it.
466 auto text = GetToolTipText();
467 UnsetToolTip();
468 wxWindow::SetToolTip(text);
469 mCursorIsInWindow = true;
470 }
471 else if (event.Leaving())
472 mCursorIsInWindow = false;
473 else
475 (event.m_x >= 0 && event.m_y >= 0 &&
476 event.m_x < clientSize.x && event.m_y < clientSize.y);
477
478 if (mEnabled && event.IsButton()) {
479 if (event.ButtonIsDown(wxMOUSE_BTN_LEFT)) {
480 mIsClicking = true;
481 if (event.ButtonDClick())
482 mIsDoubleClicked = true;
483 if( !HasCapture() )
484 CaptureMouse();
485 }
486 else if (mIsClicking) {
487 mIsClicking = false;
488
489 if (HasCapture())
490 ReleaseMouse();
491
493 if (mToggle)
495
496 mWasShiftDown = event.ShiftDown();
497 mWasControlDown = event.ControlDown();
498
499 Click();
500 }
501 }
502 }
503
504 // Only redraw and change tooltips if the state has changed.
505 AButtonState newState = GetState();
506
507 if (newState != prevState) {
508 Refresh(false);
509
511 UpdateStatus();
512 else {
513 auto pProject = FindProjectFromWindow( this );
514 if (pProject)
515 ProjectStatus::Get( *pProject ).Set({});
516 }
517 }
518 else
519 event.Skip();
520}
521
523{
524 if (mCursorIsInWindow) {
525#if wxUSE_TOOLTIPS // Not available in wxX11
526 // Display the tooltip in the status bar
527 wxToolTip * pTip = this->GetToolTip();
528 if( pTip ) {
529 auto tipText = Verbatim( pTip->GetTip() );
530 if (!mEnabled)
531 tipText.Join( XO("(disabled)"), " " );
532 auto pProject = FindProjectFromWindow( this );
533 if (pProject)
534 ProjectStatus::Get( *pProject ).Set( tipText );
535 }
536#endif
537 }
538}
539
540void AButton::OnCaptureLost(wxMouseCaptureLostEvent & WXUNUSED(event))
541{
542 wxMouseEvent e(wxEVT_LEFT_UP);
543 e.m_x = -1;
544 e.m_y = -1;
545 OnMouseEvent(e);
546}
547
548// Note that OnKeyDown has to handle navigation because wxWANTS_CHARS
549// flag was set - see above.
550void AButton::OnKeyDown(wxKeyEvent & event)
551{
552 switch( event.GetKeyCode() )
553 {
554 case WXK_RIGHT:
555 case WXK_DOWN:
556 Navigate(wxNavigationKeyEvent::IsForward);
557 break;
558 case WXK_LEFT:
559 case WXK_UP:
560 Navigate(wxNavigationKeyEvent::IsBackward);
561 break;
562 case WXK_TAB:
563 Navigate(wxNavigationKeyEvent::FromTab | (event.ShiftDown()
564 ? wxNavigationKeyEvent::IsBackward
565 : wxNavigationKeyEvent::IsForward));
566 break;
567 default:
568 event.Skip();
569 }
570}
571
572void AButton::OnCharHook(wxKeyEvent& event)
573{
574 switch(event.GetKeyCode())
575 {
576 case WXK_RETURN:
577 case WXK_NUMPAD_ENTER:
578 if( !mEnabled )
579 break;
580 mWasShiftDown = event.ShiftDown();
581 mWasControlDown = event.ControlDown();
582 if(mToggle)
583 {
585 Refresh(false);
586#if wxUSE_ACCESSIBILITY
587 GetAccessible()->NotifyEvent(wxACC_EVENT_OBJECT_NAMECHANGE,
588 this, wxOBJID_CLIENT, wxACC_SELF);
589#endif
590 }
591 Click();
592 break;
593 default:
594 event.Skip();
595 }
596}
597
598void AButton::OnSetFocus(wxFocusEvent & WXUNUSED(event))
599{
600 Refresh( false );
601}
602
603void AButton::OnKillFocus(wxFocusEvent & WXUNUSED(event))
604{
605 Refresh( false );
606}
607
609{
610 return mWasShiftDown;
611}
612
614{
615 return mWasControlDown;
616}
617
619{
620 bool changed = wxWindow::Enable(true);
621 if ( !mEnabled ) {
622 mEnabled = true;
623 Refresh(false);
624 }
625}
626
628{
629 // Bug 1565: Tooltips not showing on disabled buttons.
630 // The fix is to NOT tell windows that the button is disabled.
631 // The button's appearance will still change to show it is disabled
632 // since we control that rather than windows.
633#ifndef __WXMSW__
634 wxWindow::Enable(false);
635#endif
636 if (GetCapture()==this)
637 ReleaseMouse();
638 if ( mEnabled ) {
639 mEnabled = false;
640 Refresh(false);
641 }
642}
643
645{
646 if (!mButtonIsDown) {
647 mButtonIsDown = true;
648 this->Refresh(false);
649 }
650}
651
653{
654 if (mButtonIsDown) {
655 mButtonIsDown = false;
656
657 this->Refresh(false);
658 }
659
660 if (GetCapture()==this)
661 ReleaseMouse();
662}
663
665{
666 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, GetId());
667 event.SetEventObject(this);
668 // Be sure to use SafelyProcessEvent so that exceptions do not propagate
669 // out of DoDefaultAction
670 GetEventHandler()->SafelyProcessEvent(event);
671}
672
673void AButton::SetShift(bool shift)
674{
675 mWasShiftDown = shift;
676}
677
678void AButton::SetControl(bool control)
679{
680 mWasControlDown = control;
681}
682
684{
685 const auto imageIdx = HasAlternateImages(mAlternateIdx) ? mAlternateIdx : 0;
686 if(imageIdx == mAlternateIdx || HasAlternateImages(imageIdx))
687 {
688 const auto& image = mImages[imageIdx][AButtonUp];
689 switch(mType)
690 {
691 case FrameButton:
692 {
693 const auto icon = !mIcons.empty() ? &mIcons[0][AButtonUp] : nullptr;
694 if(icon->IsOk())
695 return icon->GetSize();
696 return image.GetSize();
697 }
698 case FrameTextButton:
699 {
700 //Only AButtonUp is used to estimate size
701 auto icon = !mIcons.empty() ? &mIcons[0][AButtonUp] : nullptr;
702 if(!GetLabel().IsEmpty())
703 {
704 const auto border = (image.GetSize() - wxSize { mFrameMid, mFrameMid }) / 4;
705
706 wxMemoryDC dc;
707 dc.SetFont(GetFont());
708 auto bestSize = dc.GetTextExtent(GetLabel());
709 if(icon != nullptr && icon->IsOk())
710 {
711 bestSize.x = std::max(bestSize.x, icon->GetWidth());
712 bestSize.y = bestSize.y > 0
713 ? bestSize.y + border.y + icon->GetHeight()
714 : icon->GetHeight();
715 }
716 if(bestSize.x > 0)
717 bestSize.x += border.x * 2;
718 if(bestSize.y > 0)
719 bestSize.y += border.y * 2;
720 return bestSize;
721 }
722 if(icon->Ok())
723 return icon->GetSize();
724 return image.GetSize();
725 }
726 case TextButton:
727 return {-1, image.GetHeight() };
728 default:
729 return image.GetSize();
730 }
731 }
732 return wxWindow::DoGetBestClientSize();
733}
734
736 s_AcceptsFocus = true;
738}
739
740#if wxUSE_ACCESSIBILITY
741
742AButtonAx::AButtonAx( wxWindow *window ):
743 WindowAccessible( window )
744{
745}
746
747AButtonAx::~AButtonAx()
748{
749}
750
751// Performs the default action. childId is 0 (the action for this object)
752// or > 0 (the action for a child).
753// Return wxACC_NOT_SUPPORTED if there is no default action for this
754// window (e.g. an edit control).
755wxAccStatus AButtonAx::DoDefaultAction(int WXUNUSED(childId))
756{
757 AButton *ab = wxDynamicCast( GetWindow(), AButton );
758
759 if(ab && ab->IsEnabled()) {
760 ab->mWasShiftDown = false;
761 ab->mWasControlDown = false;
762 if(ab->mToggle)
763 {
764 ab->mButtonIsDown = !ab->mButtonIsDown;
765 ab->Refresh(false);
766 }
767 ab->Click();
768 }
769
770 return wxACC_OK;
771}
772
773// Retrieves the address of an IDispatch interface for the specified child.
774// All objects must support this property.
775wxAccStatus AButtonAx::GetChild( int childId, wxAccessible** child )
776{
777 if( childId == wxACC_SELF )
778 {
779 *child = this;
780 }
781 else
782 {
783 *child = NULL;
784 }
785
786 return wxACC_OK;
787}
788
789// Gets the number of children.
790wxAccStatus AButtonAx::GetChildCount(int* childCount)
791{
792 *childCount = 0;
793
794 return wxACC_OK;
795}
796
797// Gets the default action for this object (0) or > 0 (the action for
798// a child). Return wxACC_OK even if there is no action. actionName
799// is the action, or the empty string if there is no action. The
800// retrieved string describes the action that is performed on an
801// object, not what the object does as a result. For example, a
802// toolbar button that prints a document has a default action of
803// "Press" rather than "Prints the current document."
804wxAccStatus AButtonAx::GetDefaultAction(int WXUNUSED(childId), wxString* actionName)
805{
806 *actionName = _( "Press" );
807
808 return wxACC_OK;
809}
810
811// Returns the description for this object or a child.
812wxAccStatus AButtonAx::GetDescription( int WXUNUSED(childId), wxString *description )
813{
814 description->clear();
815
816 return wxACC_OK;
817}
818
819// Gets the window with the keyboard focus.
820// If childId is 0 and child is NULL, no object in
821// this subhierarchy has the focus.
822// If this object has the focus, child should be 'this'.
823wxAccStatus AButtonAx::GetFocus(int* childId, wxAccessible** child)
824{
825 *childId = 0;
826 *child = this;
827
828 return wxACC_OK;
829}
830
831// Returns help text for this object or a child, similar to tooltip text.
832wxAccStatus AButtonAx::GetHelpText( int WXUNUSED(childId), wxString *helpText )
833{
834#if wxUSE_TOOLTIPS // Not available in wxX11
835 AButton *ab = wxDynamicCast( GetWindow(), AButton );
836
837 wxToolTip *pTip = ab->GetToolTip();
838 if( pTip )
839 {
840 *helpText = pTip->GetTip();
841 }
842
843 return wxACC_OK;
844#else
845 helpText->clear();
846
847 return wxACC_NOT_SUPPORTED;
848#endif
849}
850
851// Returns the keyboard shortcut for this object or child.
852// Return e.g. ALT+K
853wxAccStatus AButtonAx::GetKeyboardShortcut( int WXUNUSED(childId), wxString *shortcut )
854{
855 shortcut->clear();
856
857 return wxACC_OK;
858}
859
860// Returns the rectangle for this object (id = 0) or a child element (id > 0).
861// rect is in screen coordinates.
862wxAccStatus AButtonAx::GetLocation( wxRect& rect, int WXUNUSED(elementId) )
863{
864 AButton *ab = wxDynamicCast( GetWindow(), AButton );
865
866 rect = ab->GetRect();
867 rect.SetPosition( ab->GetParent()->ClientToScreen( rect.GetPosition() ) );
868
869 return wxACC_OK;
870}
871
872// Gets the name of the specified object.
873wxAccStatus AButtonAx::GetName(int WXUNUSED(childId), wxString* name)
874{
875 AButton *ab = wxDynamicCast( GetWindow(), AButton );
876
877 *name = ab->GetName();
878 if( name->empty() )
879 {
880 *name = ab->GetLabel();
881 }
882
883 if( name->empty() )
884 {
885 *name = _("Button");
886 }
887
888 /* In the MSAA frame work, there isn't such a thing as a toggle button.
889 In particular, narrator does not read the wxACC_STATE_SYSTEM_PRESSED state at all.
890 So to imitate a toggle button, include the role and the state in the name, and
891 create a name change event when the state changes. To enable screen reader
892 scripts to determine the state of the toggle button in the absence of the
893 accessibility state indicating this, add the '\a' character to the end of the name
894 when the button is pressed. ('\a' is read silently by screen readers.) */
895 if (ab->mToggle) {
896 *name += wxT(" ") +
897 _("Button")
898 + wxT(" ") +
899 /* i18n-hint: whether a button is pressed or not pressed */
900 (ab->IsDown() ? _("pressed") + wxT('\a') : _("not pressed"));
901 }
902
903 return wxACC_OK;
904}
905
906// Returns a role constant.
907wxAccStatus AButtonAx::GetRole(int WXUNUSED(childId), wxAccRole* role)
908{
909 AButton* ab = wxDynamicCast(GetWindow(), AButton);
910
911 // For a toggle button, the role is included in the name, so read nothing
912 *role = ab->mToggle ? wxROLE_SYSTEM_STATICTEXT : wxROLE_SYSTEM_PUSHBUTTON;
913
914 return wxACC_OK;
915}
916
917// Gets a variant representing the selected children
918// of this object.
919// Acceptable values:
920// - a null variant (IsNull() returns TRUE)
921// - a list variant (GetType() == wxT("list"))
922// - an integer representing the selected child element,
923// or 0 if this object is selected (GetType() == wxT("long"))
924// - a "void*" pointer to a wxAccessible child object
925wxAccStatus AButtonAx::GetSelections( wxVariant * WXUNUSED(selections) )
926{
927 return wxACC_NOT_IMPLEMENTED;
928}
929
930// Returns a state constant.
931wxAccStatus AButtonAx::GetState(int WXUNUSED(childId), long* state)
932{
933 AButton *ab = wxDynamicCast( GetWindow(), AButton );
934 *state = 0;
935 if(!ab->IsEnabled())
936 *state = wxACC_STATE_SYSTEM_UNAVAILABLE;
937 else
938 {
939 // For a toggle button, the state is included in the name
940 if(ab->mButtonIsDown && !ab->mToggle)
941 *state |= wxACC_STATE_SYSTEM_PRESSED;
942
943 if(ab->mCursorIsInWindow)
944 *state |= wxACC_STATE_SYSTEM_HOTTRACKED;
945
946 *state |= wxACC_STATE_SYSTEM_FOCUSABLE;
947 if(ab->HasFocus())
948 *state |= wxACC_STATE_SYSTEM_FOCUSED;
949 }
950 return wxACC_OK;
951}
952
953// Returns a localized string representing the value for the object
954// or child.
955wxAccStatus AButtonAx::GetValue(int WXUNUSED(childId), wxString* WXUNUSED(strValue))
956{
957 return wxACC_NOT_SUPPORTED;
958}
959
960#endif
wxEVT_COMMAND_BUTTON_CLICKED
wxImage(22, 22)
wxT("CloseDown"))
END_EVENT_TABLE()
const TranslatableString name
Definition: Distortion.cpp:76
XO("Cut/Copy/Paste")
#define _(s)
Definition: Internat.h:73
#define safenew
Definition: MemoryX.h:10
AudacityProject * FindProjectFromWindow(wxWindow *pWindow)
THEME_API Theme theTheme
Definition: Theme.cpp:82
TranslatableString Verbatim(wxString str)
Require calls to the one-argument constructor to go through this distinct global function name.
static std::once_flag flag
AButton * mButton
Definition: AButton.cpp:70
Listener(AButton *button)
Definition: AButton.cpp:73
int FilterEvent(wxEvent &event) override
Definition: AButton.cpp:105
A wxButton with mouse-over behaviour.
Definition: AButton.h:104
wxRect mFocusRect
Definition: AButton.h:283
bool mUseDisabledAsDownHiliteImage
Definition: AButton.h:277
void SetShift(bool shift)
Definition: AButton.cpp:673
bool mButtonIsDown
Definition: AButton.h:274
void SetButtonType(Type type)
Definition: AButton.cpp:148
bool mCursorIsInWindow
Definition: AButton.h:273
void SetControl(bool control)
Definition: AButton.cpp:678
void SetIcons(const wxImage &up, const wxImage &down, const wxImage &disabled)
Definition: AButton.cpp:252
void SetImages(const wxImage &up, const wxImage &over, const wxImage &down, const wxImage &overDown, const wxImage &dis)
Definition: AButton.cpp:221
void UseDisabledAsDownHiliteImage(bool flag)
Definition: AButton.cpp:195
AButtonState
Definition: AButton.h:118
@ AButtonUp
Definition: AButton.h:119
@ AButtonDis
Definition: AButton.h:123
@ AButtonOver
Definition: AButton.h:120
@ AButtonDown
Definition: AButton.h:121
@ AButtonOverDown
Definition: AButton.h:122
void PushDown()
Definition: AButton.cpp:644
std::unique_ptr< bool, Resetter > TempAllowFocus
Definition: AButton.h:251
bool mIsClicking
Definition: AButton.h:275
bool HasAlternateImages(unsigned idx) const
Definition: AButton.cpp:445
bool mWasShiftDown
Definition: AButton.h:270
bool IsDown()
Definition: AButton.h:226
void Click()
Definition: AButton.cpp:664
void OnSize(wxSizeEvent &event)
Definition: AButton.cpp:434
void OnSetFocus(wxFocusEvent &event)
Definition: AButton.cpp:598
void OnKillFocus(wxFocusEvent &event)
Definition: AButton.cpp:603
void UpdateStatus()
Definition: AButton.cpp:522
void SetToolTip(const TranslatableString &toolTip)
Definition: AButton.cpp:200
static TempAllowFocus TemporarilyAllowFocus()
Definition: AButton.cpp:735
static bool s_AcceptsFocus
Definition: AButton.h:249
void SetAlternateIdx(unsigned idx)
Definition: AButton.cpp:287
void OnPaint(wxPaintEvent &event)
Definition: AButton.cpp:348
Type mType
Definition: AButton.h:288
void SetFocusRect(const wxRect &r)
Definition: AButton.cpp:304
bool WasControlDown()
Definition: AButton.cpp:613
void OnErase(wxEraseEvent &event)
Definition: AButton.cpp:429
wxSize DoGetBestClientSize() const override
Definition: AButton.cpp:683
void SetFocusFromKbd() override
Definition: AButton.cpp:215
std::unique_ptr< Listener > mListener
Definition: AButton.h:286
void Disable()
Definition: AButton.cpp:627
friend class AButtonAx
Definition: AButton.h:105
bool mIsDoubleClicked
Definition: AButton.h:278
void OnMouseEvent(wxMouseEvent &event)
Definition: AButton.cpp:458
void SetAlternateIcon(unsigned idx, const wxImage &icon)
Definition: AButton.cpp:257
void Enable()
Definition: AButton.cpp:618
void PopUp()
Definition: AButton.cpp:652
bool IsEnabled() const
Definition: AButton.h:197
@ TextButton
Definition: AButton.h:112
@ FrameButton
Definition: AButton.h:114
@ ImageButton
Definition: AButton.h:113
@ FrameTextButton
Definition: AButton.h:115
std::vector< std::array< wxImage, AButtonStateCount > > mIcons
Definition: AButton.h:280
bool mEnabled
Definition: AButton.h:276
void SetAlternateIcons(unsigned idx, const wxImage &up, const wxImage &down, const wxImage &disabled)
Definition: AButton.cpp:275
int mFrameMid
Definition: AButton.h:289
void SetAlternateImages(unsigned idx, const wxImage &up, const wxImage &over, const wxImage &down, const wxImage &overDown, const wxImage &dis)
Definition: AButton.cpp:226
bool WasShiftDown()
Definition: AButton.cpp:608
AButtonState GetState()
Definition: AButton.cpp:310
AButton(wxWindow *parent=nullptr, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, bool toggle=false)
Definition: AButton.cpp:118
void OnKeyDown(wxKeyEvent &event)
Definition: AButton.cpp:550
bool mToggle
Definition: AButton.h:263
unsigned mAlternateIdx
Definition: AButton.h:262
std::vector< std::array< wxImage, AButtonStateCount > > mImages
Definition: AButton.h:281
void OnCharHook(wxKeyEvent &event)
Definition: AButton.cpp:572
virtual ~AButton()
Definition: AButton.cpp:142
bool mWasControlDown
Definition: AButton.h:271
void SetIcon(const wxImage &icon)
Definition: AButton.cpp:242
void FollowModifierKeys()
Definition: AButton.cpp:298
void Init(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size, bool toggle)
Definition: AButton.cpp:174
void OnCaptureLost(wxMouseCaptureLostEvent &event)
Definition: AButton.cpp:540
void SetLabel(const TranslatableString &label)
Definition: AButton.cpp:205
void SetFrameMid(int mid)
Definition: AButton.cpp:159
bool mForceFocusRect
Definition: AButton.h:284
static void DrawFrame(wxDC &dc, const wxRect &r, wxBitmap &bitmap, int mid)
Definition: AColor.cpp:329
static void DrawHStretch(wxDC &dc, const wxRect &rect, wxBitmap &bitmap)
Definition: AColor.cpp:312
static void DrawFocus(wxDC &dc, wxRect &r)
Definition: AColor.cpp:247
static ProjectStatus & Get(AudacityProject &project)
void Set(const TranslatableString &msg, StatusBarField field=MainStatusBarField())
wxColour & Colour(int iIndex)
Holds a msgid for the translation catalog; may also bind format arguments.
wxString Translation() const
TranslatableString Stripped(unsigned options=MenuCodes) const
non-mutating, constructs another TranslatableString object
An alternative to using wxWindowAccessible, which in wxWidgets 3.1.1 contained GetParent() which was ...
void SetFocus(const WindowPlacement &focus)
Set the window that accepts keyboard input.
Definition: BasicUI.h:392
AUDACITY_DLL_API wxString TruncateText(wxDC &dc, const wxString &text, const int maxWidth)
Definition: TrackArt.cpp:173