mirror of
https://github.com/cookiengineer/audacity
synced 2025-12-04 15:50:10 +01: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:
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user