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 const auto isFrameTextButton = mType == FrameTextVButton || mType == FrameTextHButton;
363 if(mType == ImageButton)
364 dc.DrawBitmap(mImages[imageIdx][buttonState], buttonRect.GetTopLeft());
365 else if(mType == FrameButton || isFrameTextButton)
366 {
367 wxBitmap bitmap = mImages[imageIdx][buttonState];
368 AColor::DrawFrame(dc, buttonRect, bitmap, mFrameMid);
369
370 const auto border = bitmap.GetSize() / 4;
371
372 wxImage* icon{};
373 if(mIcons.size() > mAlternateIdx)
374 icon = &mIcons[mAlternateIdx][buttonState];
375 if((icon == nullptr || !icon->IsOk()) && !mIcons.empty())
376 {
377 icon = &mIcons[0][buttonState];
378 if(!icon->IsOk())
379 icon = &mIcons[0][AButtonUp];
380 }
381 if(isFrameTextButton && !GetLabel().IsEmpty())
382 {
383 dc.SetFont(GetFont());
384 auto textRect = buttonRect;
385 if(icon != nullptr && icon->IsOk())
386 {
387 const auto fontMetrics = dc.GetFontMetrics();
389 {
390 const auto sumHeight = fontMetrics.height + icon->GetHeight() + border.y;
391
392 dc.DrawBitmap(*icon,
393 buttonRect.x + (buttonRect.width - icon->GetWidth()) / 2,
394 buttonRect.y + (buttonRect.height - sumHeight) / 2);
395 textRect = wxRect(
396 buttonRect.x,
397 buttonRect.y + buttonRect.height / 2 + sumHeight / 2 - fontMetrics.height,
398 buttonRect.width,
399 fontMetrics.height);
400 }
401 else
402 {
403 const auto sumWidth = icon->GetWidth() + border.x + dc.GetTextExtent(GetLabel()).GetWidth();
404 const auto iconCenter = buttonRect.height / 2;
405 const auto textLeft = iconCenter + icon->GetWidth() / 2 + border.x;
406
407 dc.DrawBitmap(*icon,
408 buttonRect.x + iconCenter - icon->GetWidth() / 2,
409 buttonRect.y + iconCenter - icon->GetHeight() / 2);
410 textRect = wxRect(
411 buttonRect.x + textLeft,
412 buttonRect.y + border.y,
413 buttonRect.width - textLeft,
414 buttonRect.height - border.y * 2
415 );
416 }
417 }
418 dc.SetPen(GetForegroundColour());
419 dc.DrawLabel(GetLabel(), textRect, wxALIGN_CENTER);
420 }
421 else if(icon != nullptr && icon->IsOk())
422 {
423 dc.DrawBitmap(*icon,
424 buttonRect.x + (buttonRect.width - icon->GetWidth()) / 2,
425 buttonRect.y + (buttonRect.height - icon->GetHeight()) / 2);
426 }
427 }
428 else
429 {
430 wxBitmap bitmap = mImages[imageIdx][buttonState];
431 AColor::DrawHStretch(dc, GetClientRect(), bitmap);
432 if(!GetLabel().IsEmpty())
433 {
434 dc.SetFont(GetFont());
435 const auto text = TrackArt::TruncateText(dc, GetLabel(), GetClientSize().GetWidth() - 6);
436 if(!text.IsEmpty())
437 {
438 dc.SetPen(GetForegroundColour());
439 dc.DrawLabel(text, GetClientRect(), wxALIGN_CENTER);
440 }
441 }
442 }
443 }
444
445 if(HasFocus())
447}
448
449void AButton::OnErase(wxEraseEvent & WXUNUSED(event))
450{
451 // Ignore it to prevent flashing
452}
453
454void AButton::OnSize(wxSizeEvent & WXUNUSED(event))
455{
456 if (!mForceFocusRect)
457 {
458 mFocusRect = GetClientRect().Deflate( 3, 3 );
459 }
460 Refresh(false);
461}
462
463bool AButton::s_AcceptsFocus{ false };
464
465bool AButton::HasAlternateImages(unsigned idx) const
466{
467 if (mImages.size() <= idx)
468 return false;
469
470 const auto &arr = mImages[idx];
471 return (arr[0].Ok() &&
472 arr[1].Ok() &&
473 arr[2].Ok() &&
474 arr[3].Ok() &&
475 arr[4].Ok());
476}
477
478void AButton::OnMouseEvent(wxMouseEvent & event)
479{
480 wxSize clientSize = GetClientSize();
481 AButtonState prevState = GetState();
482
483 if (event.Entering()) {
484 // Bug 1201: On Mac, unsetting and re-setting the tooltip may be needed
485 // to make it pop up when we want it.
486 auto text = GetToolTipText();
487 UnsetToolTip();
488 wxWindow::SetToolTip(text);
489 mCursorIsInWindow = true;
490 }
491 else if (event.Leaving())
492 mCursorIsInWindow = false;
493 else
495 (event.m_x >= 0 && event.m_y >= 0 &&
496 event.m_x < clientSize.x && event.m_y < clientSize.y);
497
498 if (mEnabled && event.IsButton()) {
499 if (event.ButtonIsDown(wxMOUSE_BTN_LEFT)) {
500 mIsClicking = true;
501 if (event.ButtonDClick())
502 mIsDoubleClicked = true;
503 if( !HasCapture() )
504 CaptureMouse();
505 }
506 else if (mIsClicking) {
507 mIsClicking = false;
508
509 if (HasCapture())
510 ReleaseMouse();
511
513 if (mToggle)
515
516 mWasShiftDown = event.ShiftDown();
517 mWasControlDown = event.ControlDown();
518
519 Click();
520 }
521 }
522 }
523
524 // Only redraw and change tooltips if the state has changed.
525 AButtonState newState = GetState();
526
527 if (newState != prevState) {
528 Refresh(false);
529
531 UpdateStatus();
532 else {
533 auto pProject = FindProjectFromWindow( this );
534 if (pProject)
535 ProjectStatus::Get( *pProject ).Set({});
536 }
537 }
538 else
539 event.Skip();
540}
541
543{
544 if (mCursorIsInWindow) {
545#if wxUSE_TOOLTIPS // Not available in wxX11
546 // Display the tooltip in the status bar
547 wxToolTip * pTip = this->GetToolTip();
548 if( pTip ) {
549 auto tipText = Verbatim( pTip->GetTip() );
550 if (!mEnabled)
551 tipText.Join( XO("(disabled)"), " " );
552 auto pProject = FindProjectFromWindow( this );
553 if (pProject)
554 ProjectStatus::Get( *pProject ).Set( tipText );
555 }
556#endif
557 }
558}
559
560void AButton::OnCaptureLost(wxMouseCaptureLostEvent & WXUNUSED(event))
561{
562 wxMouseEvent e(wxEVT_LEFT_UP);
563 e.m_x = -1;
564 e.m_y = -1;
565 OnMouseEvent(e);
566}
567
568// Note that OnKeyDown has to handle navigation because wxWANTS_CHARS
569// flag was set - see above.
570void AButton::OnKeyDown(wxKeyEvent & event)
571{
572 switch( event.GetKeyCode() )
573 {
574 case WXK_RIGHT:
575 case WXK_DOWN:
576 Navigate(wxNavigationKeyEvent::IsForward);
577 break;
578 case WXK_LEFT:
579 case WXK_UP:
580 Navigate(wxNavigationKeyEvent::IsBackward);
581 break;
582 case WXK_TAB:
583 Navigate(wxNavigationKeyEvent::FromTab | (event.ShiftDown()
584 ? wxNavigationKeyEvent::IsBackward
585 : wxNavigationKeyEvent::IsForward));
586 break;
587 default:
588 event.Skip();
589 }
590}
591
592void AButton::OnCharHook(wxKeyEvent& event)
593{
594 switch(event.GetKeyCode())
595 {
596 case WXK_RETURN:
597 case WXK_NUMPAD_ENTER:
598 if( !mEnabled )
599 break;
600 mWasShiftDown = event.ShiftDown();
601 mWasControlDown = event.ControlDown();
602 if(mToggle)
603 {
605 Refresh(false);
606#if wxUSE_ACCESSIBILITY
607 GetAccessible()->NotifyEvent(wxACC_EVENT_OBJECT_NAMECHANGE,
608 this, wxOBJID_CLIENT, wxACC_SELF);
609#endif
610 }
611 Click();
612 break;
613 default:
614 event.Skip();
615 }
616}
617
618void AButton::OnSetFocus(wxFocusEvent & WXUNUSED(event))
619{
620 Refresh( false );
621}
622
623void AButton::OnKillFocus(wxFocusEvent & WXUNUSED(event))
624{
625 Refresh( false );
626}
627
629{
630 return mWasShiftDown;
631}
632
634{
635 return mWasControlDown;
636}
637
639{
640 bool changed = wxWindow::Enable(true);
641 if ( !mEnabled ) {
642 mEnabled = true;
643 Refresh(false);
644 }
645}
646
648{
649 // Bug 1565: Tooltips not showing on disabled buttons.
650 // The fix is to NOT tell windows that the button is disabled.
651 // The button's appearance will still change to show it is disabled
652 // since we control that rather than windows.
653#ifndef __WXMSW__
654 wxWindow::Enable(false);
655#endif
656 if (GetCapture()==this)
657 ReleaseMouse();
658 if ( mEnabled ) {
659 mEnabled = false;
660 Refresh(false);
661 }
662}
663
665{
666 if (!mButtonIsDown) {
667 mButtonIsDown = true;
668 this->Refresh(false);
669 }
670}
671
673{
674 if (mButtonIsDown) {
675 mButtonIsDown = false;
676
677 this->Refresh(false);
678 }
679
680 if (GetCapture()==this)
681 ReleaseMouse();
682}
683
685{
686 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, GetId());
687 event.SetEventObject(this);
688 // Be sure to use SafelyProcessEvent so that exceptions do not propagate
689 // out of DoDefaultAction
690 GetEventHandler()->SafelyProcessEvent(event);
691}
692
693void AButton::SetShift(bool shift)
694{
695 mWasShiftDown = shift;
696}
697
698void AButton::SetControl(bool control)
699{
700 mWasControlDown = control;
701}
702
704{
705 const auto imageIdx = HasAlternateImages(mAlternateIdx) ? mAlternateIdx : 0;
706 if(imageIdx == mAlternateIdx || HasAlternateImages(imageIdx))
707 {
708 const auto& image = mImages[imageIdx][AButtonUp];
709 switch(mType)
710 {
711 case FrameButton:
712 {
713 const auto icon = !mIcons.empty() ? &mIcons[0][AButtonUp] : nullptr;
714 if(icon->IsOk())
715 return icon->GetSize();
716 return image.GetSize();
717 }
718 case FrameTextVButton:
719 case FrameTextHButton:
720 {
721 //Only AButtonUp is used to estimate size
722 auto icon = !mIcons.empty() ? &mIcons[0][AButtonUp] : nullptr;
723 if(!GetLabel().IsEmpty())
724 {
725 const auto border = (image.GetSize() - wxSize { mFrameMid, mFrameMid }) / 4;
726
727 wxMemoryDC dc;
728 dc.SetFont(GetFont());
729 auto bestSize = dc.GetTextExtent(GetLabel());
730 if(icon != nullptr && icon->IsOk())
731 {
733 {
734 bestSize.x = std::max(bestSize.x, icon->GetWidth());
735 bestSize.y = bestSize.y > 0
736 ? bestSize.y + border.y + icon->GetHeight()
737 : icon->GetHeight();
738 }
739 else
740 {
741 bestSize.x += image.GetWidth() + border.x;
742 bestSize.y = std::max(image.GetHeight(), bestSize.y);
743 }
744 }
745 if(bestSize.x > 0)
746 bestSize.x += border.x * 2;
747 if(bestSize.y > 0)
748 bestSize.y += border.y * 2;
749 return bestSize;
750 }
751 if(icon->Ok())
752 return icon->GetSize();
753 return image.GetSize();
754 }
755 case TextButton:
756 return {-1, image.GetHeight() };
757 default:
758 return image.GetSize();
759 }
760 }
761 return wxWindow::DoGetBestClientSize();
762}
763
765 s_AcceptsFocus = true;
767}
768
769#if wxUSE_ACCESSIBILITY
770
771AButtonAx::AButtonAx( wxWindow *window ):
772 WindowAccessible( window )
773{
774}
775
776AButtonAx::~AButtonAx()
777{
778}
779
780// Performs the default action. childId is 0 (the action for this object)
781// or > 0 (the action for a child).
782// Return wxACC_NOT_SUPPORTED if there is no default action for this
783// window (e.g. an edit control).
784wxAccStatus AButtonAx::DoDefaultAction(int WXUNUSED(childId))
785{
786 AButton *ab = wxDynamicCast( GetWindow(), AButton );
787
788 if(ab && ab->IsEnabled()) {
789 ab->mWasShiftDown = false;
790 ab->mWasControlDown = false;
791 if(ab->mToggle)
792 {
793 ab->mButtonIsDown = !ab->mButtonIsDown;
794 ab->Refresh(false);
795 }
796 ab->Click();
797 }
798
799 return wxACC_OK;
800}
801
802// Retrieves the address of an IDispatch interface for the specified child.
803// All objects must support this property.
804wxAccStatus AButtonAx::GetChild( int childId, wxAccessible** child )
805{
806 if( childId == wxACC_SELF )
807 {
808 *child = this;
809 }
810 else
811 {
812 *child = NULL;
813 }
814
815 return wxACC_OK;
816}
817
818// Gets the number of children.
819wxAccStatus AButtonAx::GetChildCount(int* childCount)
820{
821 *childCount = 0;
822
823 return wxACC_OK;
824}
825
826// Gets the default action for this object (0) or > 0 (the action for
827// a child). Return wxACC_OK even if there is no action. actionName
828// is the action, or the empty string if there is no action. The
829// retrieved string describes the action that is performed on an
830// object, not what the object does as a result. For example, a
831// toolbar button that prints a document has a default action of
832// "Press" rather than "Prints the current document."
833wxAccStatus AButtonAx::GetDefaultAction(int WXUNUSED(childId), wxString* actionName)
834{
835 *actionName = _( "Press" );
836
837 return wxACC_OK;
838}
839
840// Returns the description for this object or a child.
841wxAccStatus AButtonAx::GetDescription( int WXUNUSED(childId), wxString *description )
842{
843 description->clear();
844
845 return wxACC_OK;
846}
847
848// Gets the window with the keyboard focus.
849// If childId is 0 and child is NULL, no object in
850// this subhierarchy has the focus.
851// If this object has the focus, child should be 'this'.
852wxAccStatus AButtonAx::GetFocus(int* childId, wxAccessible** child)
853{
854 *childId = 0;
855 *child = this;
856
857 return wxACC_OK;
858}
859
860// Returns help text for this object or a child, similar to tooltip text.
861wxAccStatus AButtonAx::GetHelpText( int WXUNUSED(childId), wxString *helpText )
862{
863#if wxUSE_TOOLTIPS // Not available in wxX11
864 AButton *ab = wxDynamicCast( GetWindow(), AButton );
865
866 wxToolTip *pTip = ab->GetToolTip();
867 if( pTip )
868 {
869 *helpText = pTip->GetTip();
870 }
871
872 return wxACC_OK;
873#else
874 helpText->clear();
875
876 return wxACC_NOT_SUPPORTED;
877#endif
878}
879
880// Returns the keyboard shortcut for this object or child.
881// Return e.g. ALT+K
882wxAccStatus AButtonAx::GetKeyboardShortcut( int WXUNUSED(childId), wxString *shortcut )
883{
884 shortcut->clear();
885
886 return wxACC_OK;
887}
888
889// Returns the rectangle for this object (id = 0) or a child element (id > 0).
890// rect is in screen coordinates.
891wxAccStatus AButtonAx::GetLocation( wxRect& rect, int WXUNUSED(elementId) )
892{
893 AButton *ab = wxDynamicCast( GetWindow(), AButton );
894
895 rect = ab->GetRect();
896 rect.SetPosition( ab->GetParent()->ClientToScreen( rect.GetPosition() ) );
897
898 return wxACC_OK;
899}
900
901// Gets the name of the specified object.
902wxAccStatus AButtonAx::GetName(int WXUNUSED(childId), wxString* name)
903{
904 AButton *ab = wxDynamicCast( GetWindow(), AButton );
905
906 *name = ab->GetName();
907 if( name->empty() )
908 {
909 *name = ab->GetLabel();
910 }
911
912 if( name->empty() )
913 {
914 *name = _("Button");
915 }
916
917 /* In the MSAA frame work, there isn't such a thing as a toggle button.
918 In particular, narrator does not read the wxACC_STATE_SYSTEM_PRESSED state at all.
919 So to imitate a toggle button, include the role and the state in the name, and
920 create a name change event when the state changes. To enable screen reader
921 scripts to determine the state of the toggle button in the absence of the
922 accessibility state indicating this, add the '\a' character to the end of the name
923 when the button is pressed. ('\a' is read silently by screen readers.) */
924 if (ab->mToggle) {
925 *name += wxT(" ") +
926 _("Button")
927 + wxT(" ") +
928 /* i18n-hint: whether a button is pressed or not pressed */
929 (ab->IsDown() ? _("pressed") + wxT('\a') : _("not pressed"));
930 }
931
932 return wxACC_OK;
933}
934
935// Returns a role constant.
936wxAccStatus AButtonAx::GetRole(int WXUNUSED(childId), wxAccRole* role)
937{
938 AButton* ab = wxDynamicCast(GetWindow(), AButton);
939
940 // For a toggle button, the role is included in the name, so read nothing
941 *role = ab->mToggle ? wxROLE_SYSTEM_STATICTEXT : wxROLE_SYSTEM_PUSHBUTTON;
942
943 return wxACC_OK;
944}
945
946// Gets a variant representing the selected children
947// of this object.
948// Acceptable values:
949// - a null variant (IsNull() returns TRUE)
950// - a list variant (GetType() == wxT("list"))
951// - an integer representing the selected child element,
952// or 0 if this object is selected (GetType() == wxT("long"))
953// - a "void*" pointer to a wxAccessible child object
954wxAccStatus AButtonAx::GetSelections( wxVariant * WXUNUSED(selections) )
955{
956 return wxACC_NOT_IMPLEMENTED;
957}
958
959// Returns a state constant.
960wxAccStatus AButtonAx::GetState(int WXUNUSED(childId), long* state)
961{
962 AButton *ab = wxDynamicCast( GetWindow(), AButton );
963 *state = 0;
964 if(!ab->IsEnabled())
965 *state = wxACC_STATE_SYSTEM_UNAVAILABLE;
966 else
967 {
968 // For a toggle button, the state is included in the name
969 if(ab->mButtonIsDown && !ab->mToggle)
970 *state |= wxACC_STATE_SYSTEM_PRESSED;
971
972 if(ab->mCursorIsInWindow)
973 *state |= wxACC_STATE_SYSTEM_HOTTRACKED;
974
975 *state |= wxACC_STATE_SYSTEM_FOCUSABLE;
976 if(ab->HasFocus())
977 *state |= wxACC_STATE_SYSTEM_FOCUSED;
978 }
979 return wxACC_OK;
980}
981
982// Returns a localized string representing the value for the object
983// or child.
984wxAccStatus AButtonAx::GetValue(int WXUNUSED(childId), wxString* WXUNUSED(strValue))
985{
986 return wxACC_NOT_SUPPORTED;
987}
988
989#endif
wxEVT_COMMAND_BUTTON_CLICKED
wxImage(22, 22)
wxT("CloseDown"))
END_EVENT_TABLE()
XO("Cut/Copy/Paste")
#define _(s)
Definition: Internat.h:73
#define safenew
Definition: MemoryX.h:10
AudacityProject * FindProjectFromWindow(wxWindow *pWindow)
wxString name
Definition: TagsEditor.cpp:166
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:284
bool mUseDisabledAsDownHiliteImage
Definition: AButton.h:278
void SetShift(bool shift)
Definition: AButton.cpp:693
bool mButtonIsDown
Definition: AButton.h:275
void SetButtonType(Type type)
Definition: AButton.cpp:148
bool mCursorIsInWindow
Definition: AButton.h:274
void SetControl(bool control)
Definition: AButton.cpp:698
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:119
@ AButtonUp
Definition: AButton.h:120
@ AButtonDis
Definition: AButton.h:124
@ AButtonOver
Definition: AButton.h:121
@ AButtonDown
Definition: AButton.h:122
@ AButtonOverDown
Definition: AButton.h:123
void PushDown()
Definition: AButton.cpp:664
std::unique_ptr< bool, Resetter > TempAllowFocus
Definition: AButton.h:252
bool mIsClicking
Definition: AButton.h:276
bool HasAlternateImages(unsigned idx) const
Definition: AButton.cpp:465
bool mWasShiftDown
Definition: AButton.h:271
bool IsDown()
Definition: AButton.h:227
void Click()
Definition: AButton.cpp:684
void OnSize(wxSizeEvent &event)
Definition: AButton.cpp:454
void OnSetFocus(wxFocusEvent &event)
Definition: AButton.cpp:618
void OnKillFocus(wxFocusEvent &event)
Definition: AButton.cpp:623
void UpdateStatus()
Definition: AButton.cpp:542
void SetToolTip(const TranslatableString &toolTip)
Definition: AButton.cpp:200
static TempAllowFocus TemporarilyAllowFocus()
Definition: AButton.cpp:764
static bool s_AcceptsFocus
Definition: AButton.h:250
void SetAlternateIdx(unsigned idx)
Definition: AButton.cpp:287
void OnPaint(wxPaintEvent &event)
Definition: AButton.cpp:348
Type mType
Definition: AButton.h:289
void SetFocusRect(const wxRect &r)
Definition: AButton.cpp:304
bool WasControlDown()
Definition: AButton.cpp:633
void OnErase(wxEraseEvent &event)
Definition: AButton.cpp:449
wxSize DoGetBestClientSize() const override
Definition: AButton.cpp:703
void SetFocusFromKbd() override
Definition: AButton.cpp:215
std::unique_ptr< Listener > mListener
Definition: AButton.h:287
void Disable()
Definition: AButton.cpp:647
friend class AButtonAx
Definition: AButton.h:105
bool mIsDoubleClicked
Definition: AButton.h:279
void OnMouseEvent(wxMouseEvent &event)
Definition: AButton.cpp:478
void SetAlternateIcon(unsigned idx, const wxImage &icon)
Definition: AButton.cpp:257
void Enable()
Definition: AButton.cpp:638
void PopUp()
Definition: AButton.cpp:672
bool IsEnabled() const
Definition: AButton.h:198
@ TextButton
Definition: AButton.h:112
@ FrameTextVButton
Definition: AButton.h:115
@ FrameButton
Definition: AButton.h:114
@ ImageButton
Definition: AButton.h:113
@ FrameTextHButton
Definition: AButton.h:116
std::vector< std::array< wxImage, AButtonStateCount > > mIcons
Definition: AButton.h:281
bool mEnabled
Definition: AButton.h:277
void SetAlternateIcons(unsigned idx, const wxImage &up, const wxImage &down, const wxImage &disabled)
Definition: AButton.cpp:275
int mFrameMid
Definition: AButton.h:290
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:628
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:570
bool mToggle
Definition: AButton.h:264
unsigned mAlternateIdx
Definition: AButton.h:263
std::vector< std::array< wxImage, AButtonStateCount > > mImages
Definition: AButton.h:282
void OnCharHook(wxKeyEvent &event)
Definition: AButton.cpp:592
virtual ~AButton()
Definition: AButton.cpp:142
bool mWasControlDown
Definition: AButton.h:272
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:560
void SetLabel(const TranslatableString &label)
Definition: AButton.cpp:205
void SetFrameMid(int mid)
Definition: AButton.cpp:159
bool mForceFocusRect
Definition: AButton.h:285
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