315 lines
6.9 KiB
C++
315 lines
6.9 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 "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"
|
|
#include "../Theme.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_LEFT_UP(Grabber::OnLeftUp)
|
|
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(const TranslatableString &toolTip)
|
|
{
|
|
wxWindow::SetToolTip( toolTip.Stripped().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;
|
|
if (!state)
|
|
mPressed = state;
|
|
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 left button up events
|
|
//
|
|
void Grabber::OnLeftUp(wxMouseEvent & event)
|
|
{
|
|
// Normally, "left up" events are handled by the ToolManager::OnMouse() method
|
|
// but, if the user double clicks a grabber, the "left up" event will come here
|
|
// instead, so just "unpush" the button.
|
|
PushButton(false);
|
|
|
|
event.Skip();
|
|
}
|
|
|
|
//
|
|
// Handle mouse enter events
|
|
//
|
|
void Grabber::OnEnter(wxMouseEvent & WXUNUSED(event))
|
|
{
|
|
#if defined(__WXMAC__)
|
|
// Bug 2416: On Mac, we can get Enter events from grabbers other
|
|
// than the one being dragged. So, ignore Enter events if another
|
|
// window has captured the mouse.
|
|
if (wxWindow::GetCapture() != nullptr)
|
|
{
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
// 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 defined(__WXMAC__)
|
|
// Bug 2416: On Mac, we can get Leave events from grabbers other
|
|
// than the one being dragged. So, ignore Leave events if another
|
|
// window has captured the mouse.
|
|
if (wxWindow::GetCapture() != nullptr)
|
|
{
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
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.
|
|
// Audacity Flicker-free StaticBitmap.
|
|
BEGIN_EVENT_TABLE(AStaticBitmap,wxStaticBitmap)
|
|
EVT_ERASE_BACKGROUND(AStaticBitmap::OnErase)
|
|
END_EVENT_TABLE()
|
|
|
|
|