1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-08-01 08:29:27 +02:00
audacity/src/widgets/Grabber.cpp
2019-12-16 10:58:05 -05:00

279 lines
6.0 KiB
C++

/**********************************************************************
Audacity: A Digital Audio Editor
Grabber.cpp
Leland Lucius
*******************************************************************//**
\file Grabber.cpp
Implements Grabber
*//*******************************************************************//**
\class Grabber
\brief The widget to the left of a ToolBar that allows it to be dragged
around to NEW positions.
*//**********************************************************************/
#include "../Audacity.h"
#include "Grabber.h"
#include <wx/defs.h>
#include <wx/dcclient.h>
#include <wx/event.h>
#include <wx/intl.h>
#include <wx/window.h>
#include "../AColor.h"
#include "../AllThemeResources.h"
#include "../Internat.h"
////////////////////////////////////////////////////////////
/// Methods for Grabber
////////////////////////////////////////////////////////////
DEFINE_EVENT_TYPE(EVT_GRABBER_CLICKED)
BEGIN_EVENT_TABLE(Grabber, wxWindow)
EVT_ENTER_WINDOW(Grabber::OnEnter)
EVT_LEAVE_WINDOW(Grabber::OnLeave)
EVT_LEFT_DOWN(Grabber::OnLeftDown)
EVT_ERASE_BACKGROUND( Grabber::OnErase )
EVT_PAINT(Grabber::OnPaint)
EVT_KEY_DOWN(Grabber::OnKeyDown)
END_EVENT_TABLE()
//
// Constructor
//
Grabber::Grabber(wxWindow * parent, wxWindowID id)
: wxWindow(parent,
id,
wxDefaultPosition,
wxSize(grabberWidth, 27),
wxFULL_REPAINT_ON_RESIZE)
{
mOver = false;
mPressed = false;
mAsSpacer = false;
SetBackgroundColour( theTheme.Colour( clrMedium ) );
/* i18n-hint: A 'Grabber' is a region you can click and drag on
It's used to drag a track around (when in multi-tool mode) rather
than requiring that you use the drag tool. It's shown as a series
of horizontal bumps */
SetLabel(_("Grabber"));
SetName(_("Grabber"));
}
//
// Destructor
//
Grabber::~Grabber()
{
}
//
// Queue a drag event
//
void Grabber::SendEvent(wxEventType type, const wxPoint & pos, bool escaping)
{
wxWindow *parent = GetParent();
// Initialize event and convert mouse coordinates to screen space
GrabberEvent e(type, GetId(), parent->ClientToScreen(pos), escaping);
// Set the object of our desire
e.SetEventObject(parent);
// Queue the event
parent->GetEventHandler()->AddPendingEvent(e);
}
void Grabber::SetAsSpacer( bool bIsSpacer ) {
if( mAsSpacer != bIsSpacer ){
// HACK: Use a wider rectangle to also cover one pixel of space just to the right.
wxSize siz = GetSize();
siz.IncBy( bIsSpacer ? 1:-1, 0 );
SetSize( siz );
}
mAsSpacer = bIsSpacer;
};
void Grabber::SetToolTip(TranslatableString toolTip)
{
wxWindow::SetToolTip( toolTip.Strip().Translation() );
}
//
// Draw the grabber
//
void Grabber::DrawGrabber( wxDC & dc )
{
wxRect r = GetRect();
// PaintDC positions are relative to the grabber, not the parent window.
// So use 0,0 as origin for draw, so that the grabber draws right if
// positioned in its parent at some non zero position.
r.SetPosition( wxPoint(0,0) );
int y, left, right, top, bottom;
AColor::Medium(&dc, mOver );
dc.DrawRectangle(r);
// HACK: We used a wider rectangle to also cover one pixel of space just to the right.
if( mAsSpacer )
r.width -= 1;
#ifndef __WXMAC__
// Add a box
r.width -= 1;
r.height -= 1;
AColor::Bevel(dc, !mPressed, r);
r.width += 1;
r.height += 1;
#endif
// No bumps in a spacer grabber.
if( mAsSpacer )
return;
// Calculate the bump rectangle
r.Deflate(3, 3);
if ((r.GetHeight() % 4) < 2) {
r.Offset(0, 1);
}
// Cache
left = r.GetLeft();
right = r.GetRight();
top = r.GetTop();
bottom = r.GetBottom();
// Draw the raised bumps
if (mPressed) {
AColor::Dark(&dc, false);
}
else {
AColor::Light(&dc, false);
}
for (y = top; y < bottom; y += 4) {
AColor::Line(dc, left, y, right, y);
}
// Draw the pushed bumps
if (mPressed) {
AColor::Light(&dc, false);
}
else {
AColor::Dark(&dc, false);
}
for (y = top + 1; y <= bottom; y += 4) {
AColor::Line(dc, left, y, right, y);
}
}
//
// Change the button state
//
void Grabber::PushButton(bool state )
{
if( mAsSpacer )
return;
wxRect r = GetRect();
mOver = r.Contains(ScreenToClient(wxGetMousePosition()));
// Redraw button
mPressed = state;
Refresh(false);
}
//
// Handle left button down events
//
void Grabber::OnLeftDown(wxMouseEvent & event)
{
// Button should be drawn pushed
PushButton(true);
// Notify parent
SendEvent(EVT_GRABBER_CLICKED, event.GetPosition(), false);
event.Skip();
}
//
// Handle mouse enter events
//
void Grabber::OnEnter(wxMouseEvent & WXUNUSED(event))
{
// Bug 1201: On Mac, unsetting and re-setting the tooltip may be needed
// to make it pop up when we want it.
const auto text = GetToolTipText();
UnsetToolTip();
wxWindow::SetToolTip(text);
if( mAsSpacer )
return;
// Redraw highlighted
mOver = true;
Refresh(false);
}
//
// Handle mouse leave events
//
void Grabber::OnLeave(wxMouseEvent & WXUNUSED(event))
{
if (!GetCapture()) {
// Redraw plain
mOver = false;
Refresh(false);
}
}
void Grabber::OnErase( wxEraseEvent & WXUNUSED(event) )
{
// Ignore it to prevent flashing
}
//
// Handle the paint events
//
void Grabber::OnPaint(wxPaintEvent & WXUNUSED(event))
{
wxPaintDC dc(this);
// Redraw the grabber
DrawGrabber(dc);
}
void Grabber::OnKeyDown(wxKeyEvent &event)
{
event.Skip();
if(event.GetKeyCode() == WXK_ESCAPE) {
// We must not only skip this key event, but propagate it up the window
// hierarchy, so that ToolFrame detects it too.
event.ResumePropagation(wxEVENT_PROPAGATE_MAX);
SendEvent(EVT_GRABBER_CLICKED, wxPoint{ -1, -1 }, true);
}
}
// Piggy back in same source file as Grabber.
// Audcaity Flicker-free StaticBitmap.
BEGIN_EVENT_TABLE(AStaticBitmap,wxStaticBitmap)
EVT_ERASE_BACKGROUND(AStaticBitmap::OnErase)
END_EVENT_TABLE()