/********************************************************************** Audacity: A Digital Audio Editor AButton.cpp Dominic Mazzoni *******************************************************************//** \class AButton \brief A wxButton with mouse-over behaviour. AButton is a custom button class for Audacity. The main feature it supports that a wxButton does not is mouseovers. It uses an image for all of its states: up, over, down, and disabled, allowing any sort of customization you want. Currently it does not support transparency effects, so the image musts be rectangular and opaque. *//*******************************************************************/ #include "../Audacity.h" #include "AButton.h" #include "../AColor.h" #include #include #include #include //This is needed for tooltips #include "../Project.h" #include BEGIN_EVENT_TABLE(AButton, wxWindow) EVT_MOUSE_EVENTS(AButton::OnMouseEvent) EVT_MOUSE_CAPTURE_LOST(AButton::OnCaptureLost) EVT_KEY_DOWN(AButton::OnKeyDown) EVT_SET_FOCUS(AButton::OnSetFocus) EVT_KILL_FOCUS(AButton::OnKillFocus) EVT_PAINT(AButton::OnPaint) EVT_SIZE(AButton::OnSize) EVT_ERASE_BACKGROUND(AButton::OnErase) END_EVENT_TABLE() AButton::AButton(wxWindow * parent, wxWindowID id, const wxPoint & pos, const wxSize & size, wxImage up, wxImage over, wxImage down, wxImage dis, bool toggle): wxWindow() { Init(parent, id, pos, size, ImageRoll(up), ImageRoll(over), ImageRoll(down), ImageRoll(dis), toggle); } AButton::AButton(wxWindow * parent, wxWindowID id, const wxPoint & pos, const wxSize & size, ImageRoll up, ImageRoll over, ImageRoll down, ImageRoll dis, bool toggle): wxWindow() { Init(parent, id, pos, size, up, over, down, dis, toggle); } AButton::~AButton() { } void AButton::Init(wxWindow * parent, wxWindowID id, const wxPoint & pos, const wxSize & size, ImageRoll up, ImageRoll over, ImageRoll down, ImageRoll dis, bool toggle) { Create(parent, id, pos, size); mWasShiftDown = false; mWasControlDown = false; mButtonIsDown = false; mIsClicking = false; mEnabled = true; mCursorIsInWindow = false; mToggle = toggle; mUseDisabledAsDownHiliteImage = false; mImage[0] = up; mImage[1] = over; mImage[2] = down; mImage[3] = dis; mAlternate = false; mButtonIsFocused = false; mFocusRect = GetRect().Deflate( 3, 3 ); SetSizeHints(mImage[0].GetMinSize(), mImage[0].GetMaxSize()); #if wxUSE_ACCESSIBILITY SetName( wxT("") ); SetAccessible(new AButtonAx(this)); #endif } void AButton::UseDisabledAsDownHiliteImage(bool flag) { mUseDisabledAsDownHiliteImage = flag; } void AButton::SetAlternateImages(wxImage up, wxImage over, wxImage down, wxImage dis) { mAltImage[0] = ImageRoll(up); mAltImage[1] = ImageRoll(over); mAltImage[2] = ImageRoll(down); mAltImage[3] = ImageRoll(dis); } void AButton::SetAlternateImages(ImageRoll up, ImageRoll over, ImageRoll down, ImageRoll dis) { mAltImage[0] = up; mAltImage[1] = over; mAltImage[2] = down; mAltImage[3] = dis; } void AButton::SetAlternate(bool useAlternateImages) { mAlternate = useAlternateImages; Refresh(false); } void AButton::SetFocusRect(wxRect & r) { mFocusRect = r; } AButton::AButtonState AButton::GetState() { AButtonState state; if (!mEnabled && (!mToggle || !mButtonIsDown)) return AButtonDis; if (mCursorIsInWindow) { if (mToggle) { if (mIsClicking) { state = mButtonIsDown ? AButtonUp : AButtonDown; if (mUseDisabledAsDownHiliteImage) { state = mButtonIsDown ? AButtonOver : AButtonDis; } } else { state = mButtonIsDown ? AButtonDown : AButtonOver; if (mUseDisabledAsDownHiliteImage) { state = mButtonIsDown ? AButtonDis : AButtonOver; } } } else { if (mIsClicking) { state = mButtonIsDown ? AButtonOver : AButtonDown; } else { state = mButtonIsDown ? AButtonDown : AButtonUp; } } } else { if (mToggle) { state = mButtonIsDown ? AButtonDown : AButtonUp; } else { state = mButtonIsDown ? AButtonDown : AButtonUp; } } return state; } void AButton::OnPaint(wxPaintEvent & event) { wxBufferedPaintDC dc(this); AButtonState buttonState = GetState(); if (mAlternate) mAltImage[buttonState].Draw(dc, GetClientRect()); else mImage[buttonState].Draw(dc, GetClientRect()); #if defined(__WXMSW__) if( mButtonIsFocused ) { AColor::DrawFocus( dc, mFocusRect ); } #endif } void AButton::OnErase(wxEraseEvent & event) { // Ignore it to prevent flashing } void AButton::OnSize(wxSizeEvent & event) { mFocusRect = GetRect().Deflate( 3, 3 ); Refresh(false); } bool AButton::HasAlternateImages() { return (mAltImage[0].Ok() && mAltImage[1].Ok() && mAltImage[2].Ok() && mAltImage[3].Ok()); } void AButton::OnMouseEvent(wxMouseEvent & event) { wxSize clientSize = GetClientSize(); AButtonState prevState = GetState(); if (event.Entering()) mCursorIsInWindow = true; else if (event.Leaving()) mCursorIsInWindow = false; else mCursorIsInWindow = (event.m_x >= 0 && event.m_y >= 0 && event.m_x < clientSize.x && event.m_y < clientSize.y); if (HasAlternateImages() && !mButtonIsDown) mAlternate = event.ShiftDown(); if (mEnabled && event.IsButton()) { if (event.ButtonIsDown(wxMOUSE_BTN_ANY)) { mIsClicking = true; CaptureMouse(); } else if (mIsClicking) { mIsClicking = false; if (HasCapture()) ReleaseMouse(); if (mCursorIsInWindow && (mToggle || !mButtonIsDown)) { if (mToggle) mButtonIsDown = !mButtonIsDown; else mButtonIsDown = true; mWasShiftDown = event.ShiftDown(); mWasControlDown = event.ControlDown(); Click(); } } } // Only redraw and change tooltips if the state has changed. AButtonState newState = GetState(); if (newState != prevState) { Refresh(false); if (mCursorIsInWindow) { #if wxUSE_TOOLTIPS // Not available in wxX11 // Display the tooltip in the status bar wxToolTip * pTip = this->GetToolTip(); if( pTip ) { wxString tipText = pTip->GetTip(); if (!mEnabled) tipText += _(" (disabled)"); GetActiveProject()->TP_DisplayStatusMessage(tipText); } #endif } else { GetActiveProject()->TP_DisplayStatusMessage(wxT("")); } } } void AButton::OnCaptureLost(wxMouseCaptureLostEvent & event) { wxMouseEvent e(wxEVT_LEFT_UP); e.m_x = -1; e.m_y = -1; OnMouseEvent(e); } void AButton::OnKeyDown(wxKeyEvent & event) { switch( event.GetKeyCode() ) { case WXK_RETURN: mWasShiftDown = event.ShiftDown(); mWasControlDown = event.ControlDown(); Click(); break; } event.Skip(); } void AButton::OnSetFocus(wxFocusEvent & event) { mButtonIsFocused = true; Refresh( false ); } void AButton::OnKillFocus(wxFocusEvent & event) { mButtonIsFocused = false; Refresh( false ); } bool AButton::WasShiftDown() { return mWasShiftDown; } bool AButton::WasControlDown() { return mWasControlDown; } void AButton::Enable() { mEnabled = true; this->Refresh(false); } void AButton::Disable() { mEnabled = false; if (GetCapture()==this) ReleaseMouse(); this->Refresh(false); } void AButton::PushDown() { mButtonIsDown = true; this->Refresh(false); } void AButton::PopUp() { mButtonIsDown = false; if (GetCapture()==this) ReleaseMouse(); this->Refresh(false); } void AButton::Click() { wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, GetId()); event.SetEventObject(this); GetEventHandler()->ProcessEvent(event); } void AButton::SetShift(bool shift) { mWasShiftDown = shift; } #if wxUSE_ACCESSIBILITY AButtonAx::AButtonAx( wxWindow *window ): wxWindowAccessible( window ) { } AButtonAx::~AButtonAx() { } // Performs the default action. childId is 0 (the action for this object) // or > 0 (the action for a child). // Return wxACC_NOT_SUPPORTED if there is no default action for this // window (e.g. an edit control). wxAccStatus AButtonAx::DoDefaultAction(int childId) { AButton *ab = wxDynamicCast( GetWindow(), AButton ); if(ab && ab->IsEnabled()) { ab->mWasShiftDown = false; ab->mWasControlDown = false; ab->Click(); } return wxACC_OK; } // Retrieves the address of an IDispatch interface for the specified child. // All objects must support this property. wxAccStatus AButtonAx::GetChild( int childId, wxAccessible** child ) { if( childId == wxACC_SELF ) { *child = this; } else { *child = NULL; } return wxACC_OK; } // Gets the number of children. wxAccStatus AButtonAx::GetChildCount(int* childCount) { *childCount = 0; return wxACC_OK; } // Gets the default action for this object (0) or > 0 (the action for // a child). Return wxACC_OK even if there is no action. actionName // is the action, or the empty string if there is no action. The // retrieved string describes the action that is performed on an // object, not what the object does as a result. For example, a // toolbar button that prints a document has a default action of // "Press" rather than "Prints the current document." wxAccStatus AButtonAx::GetDefaultAction(int childId, wxString* actionName) { *actionName = _( "Press" ); return wxACC_OK; } // Returns the description for this object or a child. wxAccStatus AButtonAx::GetDescription( int childId, wxString *description ) { description->Clear(); return wxACC_OK; } // Gets the window with the keyboard focus. // If childId is 0 and child is NULL, no object in // this subhierarchy has the focus. // If this object has the focus, child should be 'this'. wxAccStatus AButtonAx::GetFocus(int* childId, wxAccessible** child) { *childId = 0; *child = this; return wxACC_OK; } // Returns help text for this object or a child, similar to tooltip text. wxAccStatus AButtonAx::GetHelpText( int childId, wxString *helpText ) { #if wxUSE_TOOLTIPS // Not available in wxX11 AButton *ab = wxDynamicCast( GetWindow(), AButton ); wxToolTip *pTip = ab->GetToolTip(); if( pTip ) { *helpText = pTip->GetTip(); } return wxACC_OK; #else helpText->Clear(); return wxACC_NOT_SUPPORTED; #endif } // Returns the keyboard shortcut for this object or child. // Return e.g. ALT+K wxAccStatus AButtonAx::GetKeyboardShortcut( int childId, wxString *shortcut ) { shortcut->Clear(); return wxACC_OK; } // Returns the rectangle for this object (id = 0) or a child element (id > 0). // rect is in screen coordinates. wxAccStatus AButtonAx::GetLocation( wxRect& rect, int elementId ) { AButton *ab = wxDynamicCast( GetWindow(), AButton ); rect = ab->GetRect(); rect.SetPosition( ab->GetParent()->ClientToScreen( rect.GetPosition() ) ); return wxACC_OK; } // Gets the name of the specified object. wxAccStatus AButtonAx::GetName(int childId, wxString* name) { AButton *ab = wxDynamicCast( GetWindow(), AButton ); *name = ab->GetName(); if( name->IsEmpty() ) { *name = ab->GetLabel(); } if( name->IsEmpty() ) { *name = _("Button"); } return wxACC_OK; } // Returns a role constant. wxAccStatus AButtonAx::GetRole(int childId, wxAccRole* role) { *role = wxROLE_SYSTEM_PUSHBUTTON; return wxACC_OK; } // Gets a variant representing the selected children // of this object. // Acceptable values: // - a null variant (IsNull() returns TRUE) // - a list variant (GetType() == wxT("list")) // - an integer representing the selected child element, // or 0 if this object is selected (GetType() == wxT("long")) // - a "void*" pointer to a wxAccessible child object wxAccStatus AButtonAx::GetSelections( wxVariant *selections ) { return wxACC_NOT_IMPLEMENTED; } // Returns a state constant. wxAccStatus AButtonAx::GetState(int childId, long* state) { AButton *ab = wxDynamicCast( GetWindow(), AButton ); switch( ab->GetState() ) { case AButton::AButtonDown: *state = wxACC_STATE_SYSTEM_PRESSED | wxACC_STATE_SYSTEM_FOCUSABLE; break; case AButton::AButtonOver: *state = wxACC_STATE_SYSTEM_HOTTRACKED | wxACC_STATE_SYSTEM_FOCUSABLE; break; case AButton::AButtonDis: *state = wxACC_STATE_SYSTEM_UNAVAILABLE; break; default: *state = wxACC_STATE_SYSTEM_FOCUSABLE; break; } // Do not use mButtonIsFocused is not set until after this method // is called. *state |= ( ab == wxWindow::FindFocus() ? wxACC_STATE_SYSTEM_FOCUSED : 0 ); return wxACC_OK; } // Returns a localized string representing the value for the object // or child. wxAccStatus AButtonAx::GetValue(int childId, wxString* strValue) { return wxACC_NOT_SUPPORTED; } #endif // Indentation settings for Vim and Emacs and unique identifier for Arch, a // version control system. Please do not modify past this point. // // Local Variables: // c-basic-offset: 3 // indent-tabs-mode: nil // End: // // vim: et sts=3 sw=3 // arch-tag: c0be128d-3a41-4ff8-9dc5-2264a0439761