mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-15 23:59:37 +02:00
Fix for http://bugzilla.audacityteam.org/show_bug.cgi?id=643 "Residual consistency issues with SHIFT showing Loop Play button icon" by Paul Licameli.
* Loop play-at-speed and cut preview play-at-speed implemented. * Shift or ctrl down now affect all relevant buttons, loop or cut preview, normal or at speed, and append-record.
This commit is contained in:
parent
30500b2e85
commit
7324997db6
@ -62,6 +62,10 @@ from there. Audacity will look for a file called "Pause.png".
|
||||
DEFINE_IMAGE( bmpFFwdDisabled, wxImage( 16, 16 ), wxT("FFwdDisabled"));
|
||||
DEFINE_IMAGE( bmpRecord, wxImage( 16, 16 ), wxT("Record"));
|
||||
DEFINE_IMAGE( bmpRecordDisabled, wxImage( 16, 16 ), wxT("RecordDisabled"));
|
||||
DEFINE_IMAGE( bmpCutPreview, wxImage( 16, 16 ), wxT("CutPreview"));
|
||||
DEFINE_IMAGE( bmpCutPreviewDisabled, wxImage( 16, 16 ), wxT("CutPreviewDisabled"));
|
||||
DEFINE_IMAGE( bmpAppendRecord, wxImage( 16, 16 ), wxT("AppendRecord"));
|
||||
DEFINE_IMAGE( bmpAppendRecordDisabled, wxImage( 16, 16 ), wxT("AppendRecordDisabled"));
|
||||
|
||||
SET_THEME_FLAGS( resFlagNewLine );
|
||||
DEFINE_IMAGE( bmpUpButtonLarge, wxImage( 48, 48 ), wxT("UpButtonLarge"));
|
||||
|
@ -1281,6 +1281,8 @@ void AudacityProject::CreateMenusAndCommands()
|
||||
c->AddCommand(wxT("InputGainDec"), _("Decrease recording volume"), FN(OnInputGainDec));
|
||||
|
||||
c->AddCommand(wxT("PlayAtSpeed"), _("Play at speed"), FN(OnPlayAtSpeed));
|
||||
c->AddCommand(wxT("PlayAtSpeedLooped"), _("Loop Play at speed"), FN(OnPlayAtSpeedLooped));
|
||||
c->AddCommand(wxT("PlayAtSpeedCutPreview"), _("Play Cut Preview at speed"), FN(OnPlayAtSpeedCutPreview));
|
||||
c->AddCommand(wxT("SetPlaySpeed"), _("Adjust playback speed"), FN(OnSetPlaySpeed));
|
||||
c->AddCommand(wxT("PlaySpeedInc"), _("Increase playback speed"), FN(OnPlaySpeedInc));
|
||||
c->AddCommand(wxT("PlaySpeedDec"), _("Decrease playback speed"), FN(OnPlaySpeedDec));
|
||||
@ -3004,7 +3006,23 @@ void AudacityProject::OnPlayAtSpeed()
|
||||
{
|
||||
TranscriptionToolBar *tb = GetTranscriptionToolBar();
|
||||
if (tb) {
|
||||
tb->PlayAtSpeed();
|
||||
tb->PlayAtSpeed(false, false);
|
||||
}
|
||||
}
|
||||
|
||||
void AudacityProject::OnPlayAtSpeedLooped()
|
||||
{
|
||||
TranscriptionToolBar *tb = GetTranscriptionToolBar();
|
||||
if (tb) {
|
||||
tb->PlayAtSpeed(true, false);
|
||||
}
|
||||
}
|
||||
|
||||
void AudacityProject::OnPlayAtSpeedCutPreview()
|
||||
{
|
||||
TranscriptionToolBar *tb = GetTranscriptionToolBar();
|
||||
if (tb) {
|
||||
tb->PlayAtSpeed(false, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,6 +127,8 @@ void OnInputGainDec();
|
||||
// Transcription control
|
||||
|
||||
void OnPlayAtSpeed();
|
||||
void OnPlayAtSpeedLooped();
|
||||
void OnPlayAtSpeedCutPreview();
|
||||
void OnSetPlaySpeed();
|
||||
void OnPlaySpeedInc();
|
||||
void OnPlaySpeedDec();
|
||||
|
@ -277,6 +277,7 @@ MixerTrackCluster::MixerTrackCluster(wxWindow* parent,
|
||||
true); // toggle button
|
||||
mToggleButton_Mute->SetName(_("Mute"));
|
||||
mToggleButton_Mute->SetAlternateImages(
|
||||
1,
|
||||
*(mMixerBoard->mImageMuteUp), *(mMixerBoard->mImageMuteOver),
|
||||
*(mMixerBoard->mImageMuteDown), *(mMixerBoard->mImageMuteDisabled));
|
||||
this->UpdateMute();
|
||||
@ -465,10 +466,10 @@ void MixerTrackCluster::UpdateName()
|
||||
void MixerTrackCluster::UpdateMute()
|
||||
{
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
mToggleButton_Mute->SetAlternate(mTrack->GetSolo());
|
||||
mToggleButton_Mute->SetAlternateIdx(mTrack->GetSolo() ? 1 : 0);
|
||||
if (mTrack->GetMute())
|
||||
#else
|
||||
mToggleButton_Mute->SetAlternate(mLeftTrack->GetSolo());
|
||||
mToggleButton_Mute->SetAlternateIdx(mLeftTrack->GetSolo() ? 1 : 0);
|
||||
if (mLeftTrack->GetMute())
|
||||
#endif
|
||||
mToggleButton_Mute->PushDown();
|
||||
@ -487,7 +488,7 @@ void MixerTrackCluster::UpdateSolo()
|
||||
mToggleButton_Solo->PushDown();
|
||||
else
|
||||
mToggleButton_Solo->PopUp();
|
||||
mToggleButton_Mute->SetAlternate(bIsSolo);
|
||||
mToggleButton_Mute->SetAlternateIdx(bIsSolo ? 1 : 0);
|
||||
}
|
||||
|
||||
void MixerTrackCluster::UpdatePan()
|
||||
@ -827,10 +828,10 @@ void MixerTrackCluster::OnButton_Mute(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
mProject->HandleTrackMute(mTrack, mToggleButton_Mute->WasShiftDown());
|
||||
mToggleButton_Mute->SetAlternate(mTrack->GetSolo());
|
||||
mToggleButton_Mute->SetAlternateIdx(mTrack->GetSolo() ? 1 : 0);
|
||||
#else
|
||||
mProject->HandleTrackMute(mLeftTrack, mToggleButton_Mute->WasShiftDown());
|
||||
mToggleButton_Mute->SetAlternate(mLeftTrack->GetSolo());
|
||||
mToggleButton_Mute->SetAlternateIdx(mLeftTrack->GetSolo() ? 1 : 0);
|
||||
#endif
|
||||
|
||||
// Update the TrackPanel correspondingly.
|
||||
@ -858,7 +859,7 @@ void MixerTrackCluster::OnButton_Solo(wxCommandEvent& WXUNUSED(event))
|
||||
mProject->HandleTrackSolo(mLeftTrack, mToggleButton_Solo->WasShiftDown());
|
||||
bool bIsSolo = mLeftTrack->GetSolo();
|
||||
#endif
|
||||
mToggleButton_Mute->SetAlternate(bIsSolo);
|
||||
mToggleButton_Mute->SetAlternateIdx(bIsSolo ? 1 : 0);
|
||||
|
||||
// Update the TrackPanel correspondingly.
|
||||
if (mProject->IsSoloSimple())
|
||||
|
@ -63,7 +63,7 @@ and use it for toolbar and window layouts too.
|
||||
|
||||
#include "Project.h"
|
||||
#include "toolbars/ToolBar.h"
|
||||
#include "toolbars/ControlToolBar.h"
|
||||
#include "toolbars/ToolManager.h"
|
||||
#include "ImageManipulation.h"
|
||||
#include "Theme.h"
|
||||
#include "Experimental.h"
|
||||
@ -223,9 +223,11 @@ void Theme::EnsureInitialised()
|
||||
void Theme::ApplyUpdatedImages()
|
||||
{
|
||||
AudacityProject *p = GetActiveProject();
|
||||
if( p->GetControlToolBar() )
|
||||
for( int ii = 0; ii < ToolBarCount; ++ii )
|
||||
{
|
||||
p->GetControlToolBar()->ReCreateButtons();
|
||||
ToolBar *pToolBar = p->mToolManager->GetToolBar(ii);
|
||||
if( pToolBar )
|
||||
pToolBar->ReCreateButtons();
|
||||
}
|
||||
}
|
||||
|
||||
|
8190
src/ThemeAsCeeCode.h
8190
src/ThemeAsCeeCode.h
File diff suppressed because it is too large
Load Diff
@ -49,6 +49,7 @@
|
||||
#include <wx/tooltip.h>
|
||||
|
||||
#include "ControlToolBar.h"
|
||||
#include "TranscriptionToolBar.h"
|
||||
#include "MeterToolBar.h"
|
||||
|
||||
#include "../AColor.h"
|
||||
@ -72,7 +73,6 @@ AudacityProject *ControlToolBar::mBusyProject = NULL;
|
||||
|
||||
BEGIN_EVENT_TABLE(ControlToolBar, ToolBar)
|
||||
EVT_CHAR(ControlToolBar::OnKeyEvent)
|
||||
EVT_TIMER(wxID_ANY, ControlToolBar::OnTimer)
|
||||
EVT_BUTTON(ID_PLAY_BUTTON, ControlToolBar::OnPlay)
|
||||
EVT_BUTTON(ID_STOP_BUTTON, ControlToolBar::OnStop)
|
||||
EVT_BUTTON(ID_RECORD_BUTTON, ControlToolBar::OnRecord)
|
||||
@ -89,8 +89,6 @@ END_EVENT_TABLE()
|
||||
ControlToolBar::ControlToolBar()
|
||||
: ToolBar(TransportBarID, _("Transport"), wxT("Control"))
|
||||
{
|
||||
mShiftKeyTimer.SetOwner(this);
|
||||
|
||||
mPaused = false;
|
||||
|
||||
gPrefs->Read(wxT("/GUI/ErgonomicTransportButtons"), &mErgonomicTransportButtons, true);
|
||||
@ -102,31 +100,12 @@ ControlToolBar::ControlToolBar()
|
||||
|
||||
ControlToolBar::~ControlToolBar()
|
||||
{
|
||||
wxTheApp->Disconnect( wxEVT_KEY_DOWN,
|
||||
wxKeyEventHandler( ControlToolBar::OnKeyDown ),
|
||||
NULL,
|
||||
this );
|
||||
|
||||
wxTheApp->Disconnect( wxEVT_KEY_UP,
|
||||
wxKeyEventHandler( ControlToolBar::OnKeyUp ),
|
||||
NULL,
|
||||
this );
|
||||
}
|
||||
|
||||
|
||||
void ControlToolBar::Create(wxWindow * parent)
|
||||
{
|
||||
ToolBar::Create(parent);
|
||||
|
||||
wxTheApp->Connect( wxEVT_KEY_DOWN,
|
||||
wxKeyEventHandler( ControlToolBar::OnKeyDown ),
|
||||
NULL,
|
||||
this );
|
||||
|
||||
wxTheApp->Connect( wxEVT_KEY_UP,
|
||||
wxKeyEventHandler( ControlToolBar::OnKeyUp ),
|
||||
NULL,
|
||||
this );
|
||||
}
|
||||
|
||||
// This is a convenience function that allows for button creation in
|
||||
@ -148,27 +127,16 @@ AButton *ControlToolBar::MakeButton(teBmps eEnabledUp, teBmps eEnabledDown, teBm
|
||||
return r;
|
||||
}
|
||||
|
||||
void ControlToolBar::MakeLoopImage()
|
||||
// static
|
||||
void ControlToolBar::MakeAlternateImages(AButton &button, int idx,
|
||||
teBmps eEnabledUp,
|
||||
teBmps eEnabledDown,
|
||||
teBmps eDisabled)
|
||||
{
|
||||
// JKC: See ToolBar::MakeButton() for almost identical code. Condense??
|
||||
|
||||
wxSize Size1( theTheme.ImageSize( bmpRecoloredUpLarge ));
|
||||
wxSize Size2( theTheme.ImageSize( bmpLoop ));
|
||||
|
||||
int xoff = (Size1.GetWidth() - Size2.GetWidth())/2;
|
||||
int yoff = (Size1.GetHeight() - Size2.GetHeight())/2;
|
||||
|
||||
wxImage * up2 = OverlayImage(bmpRecoloredUpLarge, bmpLoop, xoff, yoff);
|
||||
wxImage * hilite2 = OverlayImage(bmpRecoloredHiliteLarge, bmpLoop, xoff, yoff);
|
||||
wxImage * down2 = OverlayImage(bmpRecoloredDownLarge, bmpLoop, xoff + 1, yoff + 1);
|
||||
wxImage * disable2 = OverlayImage(bmpRecoloredUpLarge, bmpLoopDisabled, xoff, yoff);
|
||||
|
||||
mPlay->SetAlternateImages(*up2, *hilite2, *down2, *disable2);
|
||||
|
||||
delete up2;
|
||||
delete hilite2;
|
||||
delete down2;
|
||||
delete disable2;
|
||||
ToolBar::MakeAlternateImages(button, idx,
|
||||
bmpRecoloredUpLarge, bmpRecoloredDownLarge, bmpRecoloredHiliteLarge,
|
||||
eEnabledUp, eEnabledDown, eDisabled,
|
||||
theTheme.ImageSize( bmpRecoloredUpLarge ));
|
||||
}
|
||||
|
||||
void ControlToolBar::Populate()
|
||||
@ -180,8 +148,10 @@ void ControlToolBar::Populate()
|
||||
|
||||
mPlay = MakeButton( bmpPlay, bmpPlay, bmpPlayDisabled,
|
||||
ID_PLAY_BUTTON, true, _("Play"));
|
||||
|
||||
MakeLoopImage();
|
||||
MakeAlternateImages(*mPlay, 1, bmpLoop, bmpLoop, bmpLoopDisabled);
|
||||
MakeAlternateImages(*mPlay, 2,
|
||||
bmpCutPreview, bmpCutPreview, bmpCutPreviewDisabled);
|
||||
mPlay->FollowModifierKeys();
|
||||
|
||||
mStop = MakeButton( bmpStop, bmpStop, bmpStopDisabled ,
|
||||
ID_STOP_BUTTON, false, _("Stop"));
|
||||
@ -194,6 +164,9 @@ void ControlToolBar::Populate()
|
||||
|
||||
mRecord = MakeButton(bmpRecord, bmpRecord, bmpRecordDisabled,
|
||||
ID_RECORD_BUTTON, true, _("Record"));
|
||||
MakeAlternateImages(*mRecord, 1, bmpAppendRecord, bmpAppendRecord,
|
||||
bmpAppendRecordDisabled);
|
||||
mRecord->FollowModifierKeys();
|
||||
|
||||
#if wxUSE_TOOLTIPS
|
||||
RegenerateToolsTooltips();
|
||||
@ -397,7 +370,13 @@ void ControlToolBar::EnableDisableButtons()
|
||||
}
|
||||
}
|
||||
|
||||
mPlay->SetEnabled((!recording) || (tracks && !busy));
|
||||
const bool enablePlay = (!recording) || (tracks && !busy);
|
||||
mPlay->SetEnabled(enablePlay);
|
||||
// Enable and disable the other play button
|
||||
TranscriptionToolBar *const pttb = p->GetTranscriptionToolBar();
|
||||
if (pttb)
|
||||
pttb->SetEnabled(enablePlay);
|
||||
|
||||
mRecord->SetEnabled(!busy && !playing);
|
||||
|
||||
mStop->SetEnabled(busy);
|
||||
@ -406,14 +385,26 @@ void ControlToolBar::EnableDisableButtons()
|
||||
mPause->SetEnabled(true);
|
||||
}
|
||||
|
||||
void ControlToolBar::SetPlay(bool down, bool looped)
|
||||
void ControlToolBar::SetPlay(bool down, bool looped, bool cutPreview)
|
||||
{
|
||||
AudacityProject *p = GetActiveProject();
|
||||
TranscriptionToolBar *const pttb =
|
||||
p ? p->GetTranscriptionToolBar(): 0;
|
||||
if (down) {
|
||||
mPlay->SetAlternate(looped);
|
||||
mPlay->SetAlternateIdx(cutPreview ? 2 : looped ? 1 : 0);
|
||||
mPlay->PushDown();
|
||||
} else {
|
||||
if (pttb)
|
||||
// This disables cursor changes for modifier keys
|
||||
// in the other play button too
|
||||
pttb->SetPlaying(true, looped, cutPreview);
|
||||
}
|
||||
else {
|
||||
mPlay->PopUp();
|
||||
mPlay->SetAlternate(false);
|
||||
mPlay->SetAlternateIdx(0);
|
||||
if (pttb)
|
||||
// This reenables cursor changes for modifier keys
|
||||
// in the other play button too
|
||||
pttb->SetPlaying(false, looped, cutPreview);
|
||||
}
|
||||
EnableDisableButtons();
|
||||
}
|
||||
@ -444,13 +435,12 @@ bool ControlToolBar::IsRecordDown()
|
||||
{
|
||||
return mRecord->IsDown();
|
||||
}
|
||||
|
||||
void ControlToolBar::PlayPlayRegion(double t0, double t1,
|
||||
bool looped /* = false */,
|
||||
bool cutpreview /* = false */,
|
||||
TimeTrack *timetrack /* = NULL */)
|
||||
{
|
||||
SetPlay(true, looped);
|
||||
SetPlay(true, looped, cutpreview);
|
||||
|
||||
if (gAudioIO->IsBusy()) {
|
||||
SetPlay(false);
|
||||
@ -573,7 +563,7 @@ void ControlToolBar::PlayPlayRegion(double t0, double t1,
|
||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||
NoteTrackArray(),
|
||||
#endif
|
||||
NULL, p->GetRate(), tcp0, tcp1, p, false,
|
||||
timetrack, p->GetRate(), tcp0, tcp1, p, false,
|
||||
t0, t1-t0);
|
||||
} else
|
||||
{
|
||||
@ -677,48 +667,6 @@ void ControlToolBar::OnKeyEvent(wxKeyEvent & event)
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void ControlToolBar::OnKeyDown(wxKeyEvent & event)
|
||||
{
|
||||
event.Skip();
|
||||
|
||||
if (event.GetKeyCode() == WXK_SHIFT)
|
||||
{
|
||||
// Turn the "Play" button into a "Loop" button
|
||||
if (!mPlay->IsDown())
|
||||
mPlay->SetAlternate(true);
|
||||
mShiftKeyTimer.Start(100);
|
||||
}
|
||||
}
|
||||
|
||||
void ControlToolBar::OnKeyUp(wxKeyEvent & event)
|
||||
{
|
||||
event.Skip();
|
||||
|
||||
if (event.GetKeyCode() == WXK_SHIFT)
|
||||
{
|
||||
// Turn the "Loop" button into a "Play" button
|
||||
if (!mPlay->IsDown())
|
||||
mPlay->SetAlternate(false);
|
||||
}
|
||||
}
|
||||
|
||||
void ControlToolBar::OnTimer(wxTimerEvent & event)
|
||||
{
|
||||
event.Skip();
|
||||
|
||||
// bug 307 fix:
|
||||
// Shift key-up events get swallowed if a command with a Shift in its keyboard
|
||||
// shortcut opens a dialog, and ControlToolBar::OnKeyUp() doesn't get called.
|
||||
if (!wxGetKeyState(WXK_SHIFT))
|
||||
{
|
||||
wxKeyEvent dummyEvent;
|
||||
dummyEvent.m_keyCode = WXK_SHIFT;
|
||||
this->OnKeyUp(dummyEvent);
|
||||
mShiftKeyTimer.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ControlToolBar::OnPlay(wxCommandEvent & WXUNUSED(evt))
|
||||
{
|
||||
StopPlaying();
|
||||
@ -736,12 +684,11 @@ void ControlToolBar::OnStop(wxCommandEvent & WXUNUSED(evt))
|
||||
|
||||
void ControlToolBar::PlayDefault()
|
||||
{
|
||||
if(mPlay->WasControlDown())
|
||||
PlayCurrentRegion(false, true); /* play with cut preview */
|
||||
else if(mPlay->WasShiftDown())
|
||||
PlayCurrentRegion(true); /* play looped */
|
||||
else
|
||||
PlayCurrentRegion(false); /* play normal */
|
||||
// Let control have precedence over shift
|
||||
const bool cutPreview = mPlay->WasControlDown();
|
||||
const bool looped = !cutPreview &&
|
||||
mPlay->WasShiftDown();
|
||||
PlayCurrentRegion(looped, cutPreview);
|
||||
}
|
||||
|
||||
void ControlToolBar::StopPlaying(bool stopStream /* = true*/)
|
||||
|
@ -14,8 +14,6 @@
|
||||
#ifndef __AUDACITY_CONTROL_TOOLBAR__
|
||||
#define __AUDACITY_CONTROL_TOOLBAR__
|
||||
|
||||
#include <wx/timer.h>
|
||||
|
||||
#include "ToolBar.h"
|
||||
#include "../Theme.h"
|
||||
|
||||
@ -44,10 +42,6 @@ class ControlToolBar:public ToolBar {
|
||||
|
||||
void UpdatePrefs();
|
||||
virtual void OnKeyEvent(wxKeyEvent & event);
|
||||
void OnKeyDown(wxKeyEvent & event);
|
||||
void OnKeyUp(wxKeyEvent & event);
|
||||
|
||||
void OnTimer(wxTimerEvent & event);
|
||||
|
||||
// msmeyer: These are public, but it's far better to
|
||||
// call the "real" interface functions like PlayCurrentRegion() and
|
||||
@ -60,7 +54,7 @@ class ControlToolBar:public ToolBar {
|
||||
void OnPause(wxCommandEvent & evt);
|
||||
|
||||
//These allow buttons to be controlled externally:
|
||||
void SetPlay(bool down, bool looped=false);
|
||||
void SetPlay(bool down, bool looped=false, bool cutPreview = false);
|
||||
void SetStop(bool down);
|
||||
void SetRecord(bool down);
|
||||
|
||||
@ -94,7 +88,13 @@ class ControlToolBar:public ToolBar {
|
||||
int id,
|
||||
bool processdownevents,
|
||||
const wxChar *label);
|
||||
void MakeLoopImage();
|
||||
|
||||
static
|
||||
void MakeAlternateImages(AButton &button, int idx,
|
||||
teBmps eEnabledUp,
|
||||
teBmps eEnabledDown,
|
||||
teBmps eDisabled);
|
||||
|
||||
void ArrangeButtons();
|
||||
void SetupCutPreviewTracks(double playStart, double cutStart,
|
||||
double cutEnd, double playEnd);
|
||||
@ -118,8 +118,6 @@ class ControlToolBar:public ToolBar {
|
||||
AButton *mStop;
|
||||
AButton *mFF;
|
||||
|
||||
wxTimer mShiftKeyTimer;
|
||||
|
||||
static AudacityProject *mBusyProject;
|
||||
|
||||
// Maybe button state values shouldn't be duplicated in this toolbar?
|
||||
|
@ -503,22 +503,40 @@ AButton * ToolBar::MakeButton(teBmps eUp,
|
||||
int xoff = (size.GetWidth() - theTheme.Image(eStandardUp).GetWidth())/2;
|
||||
int yoff = (size.GetHeight() - theTheme.Image(eStandardUp).GetHeight())/2;
|
||||
|
||||
wxImage * up2 = OverlayImage(eUp, eStandardUp, xoff, yoff);
|
||||
wxImage * hilite2 = OverlayImage(eHilite, eStandardUp, xoff, yoff);
|
||||
wxImage * down2 = OverlayImage(eDown, eStandardDown, xoff + 1, yoff + 1);
|
||||
wxImage * disable2 = OverlayImage(eUp, eDisabled, xoff, yoff);
|
||||
typedef std::auto_ptr<wxImage> wxImagePtr;
|
||||
wxImagePtr up2 (OverlayImage(eUp, eStandardUp, xoff, yoff));
|
||||
wxImagePtr hilite2 (OverlayImage(eHilite, eStandardUp, xoff, yoff));
|
||||
wxImagePtr down2 (OverlayImage(eDown, eStandardDown, xoff + 1, yoff + 1));
|
||||
wxImagePtr disable2 (OverlayImage(eUp, eDisabled, xoff, yoff));
|
||||
|
||||
AButton * button =
|
||||
new AButton(this, id, placement, size, *up2, *hilite2, *down2,
|
||||
*disable2, processdownevents);
|
||||
|
||||
delete up2;
|
||||
delete down2;
|
||||
delete hilite2;
|
||||
delete disable2;
|
||||
return button;
|
||||
}
|
||||
|
||||
//static
|
||||
void ToolBar::MakeAlternateImages(AButton &button, int idx,
|
||||
teBmps eUp,
|
||||
teBmps eDown,
|
||||
teBmps eHilite,
|
||||
teBmps eStandardUp,
|
||||
teBmps eStandardDown,
|
||||
teBmps eDisabled,
|
||||
wxSize size)
|
||||
{
|
||||
int xoff = (size.GetWidth() - theTheme.Image(eStandardUp).GetWidth())/2;
|
||||
int yoff = (size.GetHeight() - theTheme.Image(eStandardUp).GetHeight())/2;
|
||||
|
||||
typedef std::auto_ptr<wxImage> wxImagePtr;
|
||||
wxImagePtr up (OverlayImage(eUp, eStandardUp, xoff, yoff));
|
||||
wxImagePtr hilite (OverlayImage(eHilite, eStandardUp, xoff, yoff));
|
||||
wxImagePtr down (OverlayImage(eDown, eStandardDown, xoff + 1, yoff + 1));
|
||||
wxImagePtr disable (OverlayImage(eUp, eDisabled, xoff, yoff));
|
||||
|
||||
button.SetAlternateImages(idx, *up, *hilite, *down, *disable);
|
||||
}
|
||||
|
||||
//
|
||||
// This changes the state a button (from up to down or vice versa)
|
||||
|
@ -127,6 +127,16 @@ class ToolBar:public wxPanel
|
||||
bool processdownevents,
|
||||
wxSize size);
|
||||
|
||||
static
|
||||
void MakeAlternateImages(AButton &button, int idx,
|
||||
teBmps eUp,
|
||||
teBmps eDown,
|
||||
teBmps eHilite,
|
||||
teBmps eStandardUp,
|
||||
teBmps eStandardDown,
|
||||
teBmps eDisabled,
|
||||
wxSize size);
|
||||
|
||||
void SetButton(bool down, AButton *button);
|
||||
|
||||
void MakeMacRecoloredImage(teBmps eBmpOut, teBmps eBmpIn);
|
||||
|
@ -162,6 +162,16 @@ AButton *TranscriptionToolBar::AddButton(
|
||||
return r;
|
||||
}
|
||||
|
||||
void TranscriptionToolBar::MakeAlternateImages(
|
||||
teBmps eFore, teBmps eDisabled,
|
||||
int id, unsigned altIdx)
|
||||
{
|
||||
ToolBar::MakeAlternateImages(*mButtons[id], altIdx,
|
||||
bmpRecoloredUpSmall, bmpRecoloredDownSmall, bmpRecoloredHiliteSmall,
|
||||
eFore, eFore, eDisabled,
|
||||
theTheme.ImageSize( bmpRecoloredUpSmall ));
|
||||
}
|
||||
|
||||
void TranscriptionToolBar::Populate()
|
||||
{
|
||||
// Very similar to code in ControlToolBar...
|
||||
@ -170,6 +180,9 @@ void TranscriptionToolBar::Populate()
|
||||
|
||||
AddButton(bmpPlay, bmpPlayDisabled, TTB_PlaySpeed,
|
||||
_("Play at selected speed"));
|
||||
MakeAlternateImages(bmpLoop, bmpLoopDisabled, TTB_PlaySpeed, 1);
|
||||
MakeAlternateImages(bmpCutPreview, bmpCutPreviewDisabled, TTB_PlaySpeed, 2);
|
||||
mButtons[TTB_PlaySpeed]->FollowModifierKeys();
|
||||
|
||||
//Add a slider that controls the speed of playback.
|
||||
const int SliderWidth=100;
|
||||
@ -386,7 +399,8 @@ void TranscriptionToolBar::GetSamples(WaveTrack *t, sampleCount *s0, sampleCount
|
||||
*slen = ss1 - ss0;
|
||||
}
|
||||
|
||||
void TranscriptionToolBar::OnPlaySpeed(wxCommandEvent & WXUNUSED(event))
|
||||
// Come here from button clicks, or commands
|
||||
void TranscriptionToolBar::PlayAtSpeed(bool looped, bool cutPreview)
|
||||
{
|
||||
// Can't do anything without an active project
|
||||
AudacityProject * p = GetActiveProject();
|
||||
@ -427,12 +441,22 @@ void TranscriptionToolBar::OnPlaySpeed(wxCommandEvent & WXUNUSED(event))
|
||||
#endif
|
||||
p->GetControlToolBar()->PlayPlayRegion(playRegionStart,
|
||||
playRegionEnd,
|
||||
false,
|
||||
false,
|
||||
looped,
|
||||
cutPreview,
|
||||
mTimeTrack);
|
||||
}
|
||||
}
|
||||
|
||||
// Come here from button clicks only
|
||||
void TranscriptionToolBar::OnPlaySpeed(wxCommandEvent & WXUNUSED(event))
|
||||
{
|
||||
// Let control have precedence over shift
|
||||
const bool cutPreview = mButtons[TTB_PlaySpeed]->WasControlDown();
|
||||
const bool looped = !cutPreview &&
|
||||
mButtons[TTB_PlaySpeed]->WasShiftDown();
|
||||
PlayAtSpeed(looped, cutPreview);
|
||||
}
|
||||
|
||||
void TranscriptionToolBar::OnSpeedSlider(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
mPlaySpeed = (mPlaySpeedSlider->Get()) * 100;
|
||||
@ -867,12 +891,6 @@ void TranscriptionToolBar::SetKeyType(wxCommandEvent & WXUNUSED(event))
|
||||
|
||||
}
|
||||
|
||||
void TranscriptionToolBar::PlayAtSpeed()
|
||||
{
|
||||
wxCommandEvent e;
|
||||
OnPlaySpeed(e);
|
||||
}
|
||||
|
||||
void TranscriptionToolBar::ShowPlaySpeedDialog()
|
||||
{
|
||||
mPlaySpeedSlider->ShowDialog();
|
||||
@ -881,6 +899,24 @@ void TranscriptionToolBar::ShowPlaySpeedDialog()
|
||||
OnSpeedSlider(e);
|
||||
}
|
||||
|
||||
void TranscriptionToolBar::SetEnabled(bool enabled)
|
||||
{
|
||||
mButtons[TTB_PlaySpeed]->SetEnabled(enabled);
|
||||
}
|
||||
|
||||
void TranscriptionToolBar::SetPlaying(bool down, bool looped, bool cutPreview)
|
||||
{
|
||||
AButton *const button = mButtons[TTB_PlaySpeed];
|
||||
if (down) {
|
||||
button->SetAlternateIdx(cutPreview ? 2 : looped ? 1 : 0);
|
||||
button->PushDown();
|
||||
}
|
||||
else {
|
||||
button->SetAlternateIdx(0);
|
||||
button->PopUp();
|
||||
}
|
||||
}
|
||||
|
||||
void TranscriptionToolBar::AdjustPlaySpeed(float adj)
|
||||
{
|
||||
if (adj < 0) {
|
||||
|
@ -92,10 +92,13 @@ class TranscriptionToolBar:public ToolBar {
|
||||
virtual double GetSensitivity();
|
||||
virtual void SetKeyType(wxCommandEvent & event);
|
||||
|
||||
void PlayAtSpeed();
|
||||
void PlayAtSpeed(bool looped, bool cutPreview);
|
||||
void ShowPlaySpeedDialog();
|
||||
void AdjustPlaySpeed(float adj);
|
||||
|
||||
void SetEnabled(bool enabled);
|
||||
void SetPlaying(bool down, bool looped, bool cutPreview);
|
||||
|
||||
private:
|
||||
|
||||
void InitializeTranscriptionToolBar();
|
||||
@ -103,6 +106,9 @@ class TranscriptionToolBar:public ToolBar {
|
||||
teBmps eFore, teBmps eDisabled,
|
||||
int id,
|
||||
const wxChar *label);
|
||||
void MakeAlternateImages(
|
||||
teBmps eFore, teBmps eDisabled,
|
||||
int id, unsigned altIdx);
|
||||
void GetSamples(WaveTrack *t, sampleCount *s0, sampleCount *slen);
|
||||
void SetButton(bool newstate, AButton *button);
|
||||
void RegenerateTooltips();
|
||||
|
@ -46,6 +46,110 @@ BEGIN_EVENT_TABLE(AButton, wxWindow)
|
||||
EVT_ERASE_BACKGROUND(AButton::OnErase)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
class AButton::Listener
|
||||
: public wxEvtHandler
|
||||
{
|
||||
public:
|
||||
Listener (AButton *button);
|
||||
~Listener();
|
||||
|
||||
void OnKeyDown(wxKeyEvent & event);
|
||||
void OnKeyUp(wxKeyEvent & event);
|
||||
void OnTimer(wxTimerEvent & event);
|
||||
|
||||
DECLARE_CLASS(AButton::Listener);
|
||||
DECLARE_EVENT_TABLE();
|
||||
|
||||
private:
|
||||
AButton *mButton;
|
||||
wxTimer mShiftKeyTimer;
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(AButton::Listener, wxEvtHandler);
|
||||
|
||||
BEGIN_EVENT_TABLE(AButton::Listener, wxEvtHandler)
|
||||
EVT_TIMER(wxID_ANY, AButton::Listener::OnTimer)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
AButton::Listener::Listener (AButton *button)
|
||||
: mButton(button)
|
||||
{
|
||||
mShiftKeyTimer.SetOwner(this);
|
||||
|
||||
wxTheApp->Connect( wxEVT_KEY_DOWN,
|
||||
wxKeyEventHandler( AButton::Listener::OnKeyDown ),
|
||||
NULL,
|
||||
this );
|
||||
|
||||
wxTheApp->Connect( wxEVT_KEY_UP,
|
||||
wxKeyEventHandler( AButton::Listener::OnKeyUp ),
|
||||
NULL,
|
||||
this );
|
||||
}
|
||||
|
||||
AButton::Listener::~Listener ()
|
||||
{
|
||||
wxTheApp->Disconnect( wxEVT_KEY_DOWN,
|
||||
wxKeyEventHandler( AButton::Listener::OnKeyDown ),
|
||||
NULL,
|
||||
this );
|
||||
|
||||
wxTheApp->Disconnect( wxEVT_KEY_UP,
|
||||
wxKeyEventHandler( AButton::Listener::OnKeyUp ),
|
||||
NULL,
|
||||
this );
|
||||
}
|
||||
|
||||
void AButton::Listener::OnKeyDown(wxKeyEvent & event)
|
||||
{
|
||||
// Really, it's all the same check for changes of key states.
|
||||
OnKeyUp(event);
|
||||
|
||||
// See comments in OnTimer()
|
||||
mShiftKeyTimer.Start(100);
|
||||
}
|
||||
|
||||
void AButton::Listener::OnKeyUp(wxKeyEvent & event)
|
||||
{
|
||||
event.Skip();
|
||||
|
||||
if (!mButton->IsDown())
|
||||
{
|
||||
int idx = 0;
|
||||
// Ignore the event, consult key states. One modifier key might
|
||||
// have gone up but another remained down.
|
||||
// Note that CMD (or CTRL) takes precedence over Shift if both are down
|
||||
// and alternates are defined for both
|
||||
// see also AButton::OnMouseEvent()
|
||||
if (wxGetKeyState(WXK_CONTROL) && mButton->HasAlternateImages(2))
|
||||
idx = 2;
|
||||
else if (wxGetKeyState(WXK_SHIFT) && mButton->HasAlternateImages(1))
|
||||
idx = 1;
|
||||
|
||||
// Turn e.g. the "Play" button into a "Loop" button
|
||||
// or "Cut Preview" button
|
||||
mButton->SetAlternateIdx(idx);
|
||||
}
|
||||
}
|
||||
|
||||
void AButton::Listener::OnTimer(wxTimerEvent & event)
|
||||
{
|
||||
event.Skip();
|
||||
|
||||
// bug 307 fix:
|
||||
// Shift key-up events get swallowed if a command with a Shift in its keyboard
|
||||
// shortcut opens a dialog, and OnKeyUp() doesn't get called.
|
||||
// With CTRL now causing the button to change appearance, presumably similar
|
||||
// can happen with that key.
|
||||
if (!wxGetKeyState(WXK_SHIFT) ||
|
||||
!wxGetKeyState(WXK_CONTROL))
|
||||
{
|
||||
wxKeyEvent dummy;
|
||||
this->OnKeyUp(dummy);
|
||||
mShiftKeyTimer.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
AButton::AButton(wxWindow * parent,
|
||||
wxWindowID id,
|
||||
const wxPoint & pos,
|
||||
@ -108,18 +212,19 @@ void AButton::Init(wxWindow * parent,
|
||||
mToggle = toggle;
|
||||
mUseDisabledAsDownHiliteImage = false;
|
||||
|
||||
mImage[0] = up;
|
||||
mImage[1] = over;
|
||||
mImage[2] = down;
|
||||
mImage[3] = dis;
|
||||
mImages.resize(1);
|
||||
mImages[0].mArr[0] = up;
|
||||
mImages[0].mArr[1] = over;
|
||||
mImages[0].mArr[2] = down;
|
||||
mImages[0].mArr[3] = dis;
|
||||
|
||||
mAlternate = false;
|
||||
mAlternateIdx = 0;
|
||||
|
||||
mButtonIsFocused = false;
|
||||
mFocusRect = GetRect().Deflate( 3, 3 );
|
||||
|
||||
SetSizeHints(mImage[0].GetMinSize(),
|
||||
mImage[0].GetMaxSize());
|
||||
SetSizeHints(mImages[0].mArr[0].GetMinSize(),
|
||||
mImages[0].mArr[0].GetMaxSize());
|
||||
|
||||
#if wxUSE_ACCESSIBILITY
|
||||
SetName( wxT("") );
|
||||
@ -132,38 +237,50 @@ void AButton::UseDisabledAsDownHiliteImage(bool flag)
|
||||
mUseDisabledAsDownHiliteImage = flag;
|
||||
}
|
||||
|
||||
void AButton::SetAlternateImages(wxImage up,
|
||||
void AButton::SetAlternateImages(unsigned idx,
|
||||
wxImage up,
|
||||
wxImage over,
|
||||
wxImage down,
|
||||
wxImage dis)
|
||||
{
|
||||
mAltImage[0] = ImageRoll(up);
|
||||
mAltImage[1] = ImageRoll(over);
|
||||
mAltImage[2] = ImageRoll(down);
|
||||
mAltImage[3] = ImageRoll(dis);
|
||||
if (1 + idx > mImages.size())
|
||||
mImages.resize(1 + idx);
|
||||
mImages[idx].mArr[0] = ImageRoll(up);
|
||||
mImages[idx].mArr[1] = ImageRoll(over);
|
||||
mImages[idx].mArr[2] = ImageRoll(down);
|
||||
mImages[idx].mArr[3] = ImageRoll(dis);
|
||||
}
|
||||
|
||||
void AButton::SetAlternateImages(ImageRoll up,
|
||||
void AButton::SetAlternateImages(unsigned idx,
|
||||
ImageRoll up,
|
||||
ImageRoll over,
|
||||
ImageRoll down,
|
||||
ImageRoll dis)
|
||||
{
|
||||
mAltImage[0] = up;
|
||||
mAltImage[1] = over;
|
||||
mAltImage[2] = down;
|
||||
mAltImage[3] = dis;
|
||||
if (1 + idx > mImages.size())
|
||||
mImages.resize(1 + idx);
|
||||
mImages[idx].mArr[0] = up;
|
||||
mImages[idx].mArr[1] = over;
|
||||
mImages[idx].mArr[2] = down;
|
||||
mImages[idx].mArr[3] = dis;
|
||||
}
|
||||
|
||||
void AButton::SetAlternate(bool useAlternateImages)
|
||||
void AButton::SetAlternateIdx(unsigned idx)
|
||||
{
|
||||
// If alternate-image-state is already correct then
|
||||
// nothing to do (saves repainting button).
|
||||
if( mAlternate == useAlternateImages )
|
||||
if( mAlternateIdx == idx )
|
||||
return;
|
||||
mAlternate = useAlternateImages;
|
||||
mAlternateIdx = idx;
|
||||
Refresh(false);
|
||||
}
|
||||
|
||||
void AButton::FollowModifierKeys()
|
||||
{
|
||||
if(!mListener.get())
|
||||
mListener.reset(new Listener(this));
|
||||
}
|
||||
|
||||
void AButton::SetFocusRect(wxRect & r)
|
||||
{
|
||||
mFocusRect = r;
|
||||
@ -218,10 +335,7 @@ void AButton::OnPaint(wxPaintEvent & WXUNUSED(event))
|
||||
|
||||
AButtonState buttonState = GetState();
|
||||
|
||||
if (mAlternate)
|
||||
mAltImage[buttonState].Draw(dc, GetClientRect());
|
||||
else
|
||||
mImage[buttonState].Draw(dc, GetClientRect());
|
||||
mImages[mAlternateIdx].mArr[buttonState].Draw(dc, GetClientRect());
|
||||
|
||||
#if defined(__WXMSW__)
|
||||
if( mButtonIsFocused )
|
||||
@ -242,12 +356,17 @@ void AButton::OnSize(wxSizeEvent & WXUNUSED(event))
|
||||
Refresh(false);
|
||||
}
|
||||
|
||||
bool AButton::HasAlternateImages()
|
||||
bool AButton::HasAlternateImages(unsigned idx)
|
||||
{
|
||||
return (mAltImage[0].Ok() &&
|
||||
mAltImage[1].Ok() &&
|
||||
mAltImage[2].Ok() &&
|
||||
mAltImage[3].Ok());
|
||||
if (mImages.size() <= idx)
|
||||
return false;
|
||||
|
||||
const ImageArr &images = mImages[idx];
|
||||
const ImageRoll (&arr)[4] = images.mArr;
|
||||
return (arr[0].Ok() &&
|
||||
arr[1].Ok() &&
|
||||
arr[2].Ok() &&
|
||||
arr[3].Ok());
|
||||
}
|
||||
|
||||
void AButton::OnMouseEvent(wxMouseEvent & event)
|
||||
@ -264,8 +383,17 @@ void AButton::OnMouseEvent(wxMouseEvent & event)
|
||||
(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 (!mButtonIsDown)
|
||||
{
|
||||
// Note that CMD (or CTRL) takes precedence over Shift if both are down
|
||||
// see also AButton::Listener::OnKeyUp()
|
||||
if (event.CmdDown() && HasAlternateImages(2))
|
||||
mAlternateIdx = 2;
|
||||
else if (event.ShiftDown() && HasAlternateImages(1))
|
||||
mAlternateIdx = 1;
|
||||
else
|
||||
mAlternateIdx = 0;
|
||||
}
|
||||
|
||||
if (mEnabled && event.IsButton()) {
|
||||
if (event.ButtonIsDown(wxMOUSE_BTN_ANY)) {
|
||||
|
@ -12,6 +12,8 @@
|
||||
#ifndef __AUDACITY_BUTTON__
|
||||
#define __AUDACITY_BUTTON__
|
||||
|
||||
#include <vector>
|
||||
|
||||
#if wxUSE_ACCESSIBILITY
|
||||
#include <wx/access.h>
|
||||
#endif
|
||||
@ -23,9 +25,12 @@
|
||||
|
||||
class AButton: public wxWindow {
|
||||
friend class AButtonAx;
|
||||
class Listener;
|
||||
|
||||
public:
|
||||
|
||||
// Construct button, specifying images (button up, highlight, button down,
|
||||
// and disabled) for the default state
|
||||
AButton(wxWindow * parent,
|
||||
wxWindowID id,
|
||||
const wxPoint & pos,
|
||||
@ -36,6 +41,8 @@ class AButton: public wxWindow {
|
||||
ImageRoll dis,
|
||||
bool toggle);
|
||||
|
||||
// Construct button, specifying images (button up, highlight, button down,
|
||||
// and disabled) for the default state
|
||||
AButton(wxWindow * parent,
|
||||
wxWindowID id,
|
||||
const wxPoint & pos,
|
||||
@ -48,17 +55,30 @@ class AButton: public wxWindow {
|
||||
|
||||
virtual ~ AButton();
|
||||
|
||||
virtual void SetAlternateImages(ImageRoll up,
|
||||
// Associate a set of four images (button up, highlight, button down,
|
||||
// disabled) with one nondefault state of the button
|
||||
virtual void SetAlternateImages(unsigned idx,
|
||||
ImageRoll up,
|
||||
ImageRoll over,
|
||||
ImageRoll down,
|
||||
ImageRoll dis);
|
||||
|
||||
virtual void SetAlternateImages(wxImage up,
|
||||
// Associate a set of four images (button up, highlight, button down,
|
||||
// disabled) with one nondefault state of the button
|
||||
virtual void SetAlternateImages(unsigned idx,
|
||||
wxImage up,
|
||||
wxImage over,
|
||||
wxImage down,
|
||||
wxImage dis);
|
||||
|
||||
virtual void SetAlternate(bool useAlternateImages);
|
||||
// Choose state of the button
|
||||
virtual void SetAlternateIdx(unsigned idx);
|
||||
|
||||
// Make the button change appearance with the modifier keys, no matter
|
||||
// where the mouse is:
|
||||
// Use state 2 when CTRL is down, else 1 when SHIFT is down, else 0
|
||||
virtual void FollowModifierKeys();
|
||||
|
||||
virtual void SetFocusRect(wxRect & r);
|
||||
|
||||
virtual bool IsEnabled() const { return mEnabled; }
|
||||
@ -103,7 +123,7 @@ class AButton: public wxWindow {
|
||||
|
||||
private:
|
||||
|
||||
bool HasAlternateImages();
|
||||
bool HasAlternateImages(unsigned idx);
|
||||
|
||||
void Init(wxWindow * parent,
|
||||
wxWindowID id,
|
||||
@ -115,7 +135,7 @@ class AButton: public wxWindow {
|
||||
ImageRoll dis,
|
||||
bool toggle);
|
||||
|
||||
bool mAlternate;
|
||||
unsigned mAlternateIdx;
|
||||
bool mToggle; // This bool, if true, makes the button able to
|
||||
// process events when it is in the down state, and
|
||||
// moving to the opposite state when it is clicked.
|
||||
@ -133,11 +153,13 @@ class AButton: public wxWindow {
|
||||
bool mEnabled;
|
||||
bool mUseDisabledAsDownHiliteImage;
|
||||
|
||||
ImageRoll mImage[4];
|
||||
ImageRoll mAltImage[4];
|
||||
struct ImageArr { ImageRoll mArr[4]; };
|
||||
std::vector<ImageArr> mImages;
|
||||
|
||||
wxRect mFocusRect;
|
||||
|
||||
std::auto_ptr<Listener> mListener;
|
||||
|
||||
public:
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
|
Loading…
x
Reference in New Issue
Block a user