1214 lines
30 KiB
C++
1214 lines
30 KiB
C++
/**********************************************************************
|
|
|
|
Audacity: A Digital Audio Editor
|
|
|
|
ToolManager.cpp
|
|
|
|
Dominic Mazzoni
|
|
Shane T. Mueller
|
|
Leland Lucius
|
|
|
|
See ToolManager.h for details.
|
|
|
|
*******************************************************************//**
|
|
|
|
\file ToolManager.cpp
|
|
|
|
Implements ToolManager
|
|
|
|
*//*******************************************************************//**
|
|
|
|
\class ToolManager
|
|
\brief Manages the ToolDocks and handles the dragging, floating, and
|
|
docking of ToolBars.
|
|
|
|
*//**********************************************************************/
|
|
|
|
#include "../Audacity.h"
|
|
|
|
// For compilers that support precompilation, includes "wx/wx.h".
|
|
#include <wx/wxprec.h>
|
|
|
|
#ifndef WX_PRECOMP
|
|
#include <wx/app.h>
|
|
#include <wx/defs.h>
|
|
#include <wx/event.h>
|
|
#include <wx/frame.h>
|
|
#include <wx/gdicmn.h>
|
|
#include <wx/intl.h>
|
|
#include <wx/region.h>
|
|
#include <wx/settings.h>
|
|
#include <wx/sysopt.h>
|
|
#include <wx/timer.h>
|
|
#include <wx/utils.h>
|
|
#include <wx/window.h>
|
|
#endif /* */
|
|
|
|
#include <wx/minifram.h>
|
|
#include <wx/popupwin.h>
|
|
|
|
#if defined(__WXMAC__)
|
|
#include <wx/mac/uma.h>
|
|
#endif
|
|
|
|
#include "ToolManager.h"
|
|
#include "ControlToolBar.h"
|
|
#include "DeviceToolBar.h"
|
|
#include "EditToolBar.h"
|
|
#include "MeterToolBar.h"
|
|
#include "MixerToolBar.h"
|
|
#include "SelectionBar.h"
|
|
#include "ToolsToolBar.h"
|
|
#include "TranscriptionToolBar.h"
|
|
|
|
#include "../AColor.h"
|
|
#include "../AllThemeResources.h"
|
|
#include "../ImageManipulation.h"
|
|
#include "../Prefs.h"
|
|
#include "../Project.h"
|
|
#include "../Theme.h"
|
|
#include "../widgets/AButton.h"
|
|
#include "../widgets/Grabber.h"
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// Methods for ToolFrame
|
|
////////////////////////////////////////////////////////////
|
|
#define sizerW 11
|
|
|
|
//
|
|
// Constructor
|
|
//
|
|
class ToolFrame:public wxFrame
|
|
{
|
|
public:
|
|
|
|
ToolFrame( wxWindow *parent, ToolManager *manager, ToolBar *bar, wxPoint pos )
|
|
: wxFrame( parent,
|
|
bar->GetId(),
|
|
wxEmptyString,
|
|
pos,
|
|
wxDefaultSize,
|
|
wxNO_BORDER |
|
|
wxFRAME_NO_TASKBAR |
|
|
wxFRAME_TOOL_WINDOW |
|
|
wxFRAME_FLOAT_ON_PARENT )
|
|
{
|
|
int width = bar->GetSize().x;
|
|
int border;
|
|
|
|
// OSX doesn't need a border, but Windows and Linux do
|
|
border = 1;
|
|
#if defined(__WXMAC__)
|
|
border = 0;
|
|
|
|
// WXMAC doesn't support wxFRAME_FLOAT_ON_PARENT, so we do
|
|
//
|
|
// LL: I've commented this out because if you have, for instance, the meter
|
|
// toolbar undocked and large and then you open a dialog like an effect,
|
|
// the dialog may appear behind the dialog and you can't move either one.
|
|
//
|
|
// However, I'm leaving it here because I don't remember why I'd included
|
|
// it in the first place.
|
|
// SetWindowClass((WindowRef)d.MacGetWindowRef(), kFloatingWindowClass);
|
|
#endif
|
|
|
|
// Save parameters
|
|
mParent = parent;
|
|
mManager = manager;
|
|
mBar = bar;
|
|
|
|
// Transfer the bar to the ferry
|
|
bar->Reparent( this );
|
|
|
|
// We use a sizer to maintain proper spacing
|
|
wxBoxSizer *s = new wxBoxSizer( wxHORIZONTAL );
|
|
|
|
// Add the bar to the sizer
|
|
s->Add( bar, 1, wxEXPAND | wxALL, border );
|
|
|
|
// Add space for the resize grabber
|
|
if( bar->IsResizable() )
|
|
{
|
|
s->Add( sizerW, 1 );
|
|
width += sizerW;
|
|
}
|
|
|
|
SetSize( width + 2, bar->GetMinSize().y + 2 );
|
|
|
|
// Attach the sizer and resize the window to fit
|
|
SetSizer( s );
|
|
Layout();
|
|
|
|
// Inform toolbar of change
|
|
bar->SetDocked( NULL, true );
|
|
|
|
// Make sure resizable floaters don't get any smaller than initial size
|
|
if( bar->IsResizable() )
|
|
{
|
|
// Calc the minimum size of the frame
|
|
mMinSize = bar->GetMinSize() + ( GetSize() - bar->GetSize() );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Transition a toolbar from float to dragging
|
|
//
|
|
void OnGrabber( GrabberEvent & event )
|
|
{
|
|
// Pass it on to the manager since it isn't in the handling hierarchy
|
|
mManager->ProcessEvent( event );
|
|
}
|
|
|
|
//
|
|
// Handle toolbar updates
|
|
//
|
|
void OnToolBarUpdate( wxCommandEvent & event )
|
|
{
|
|
// Resize floater window to exactly contain toolbar
|
|
mBar->GetParent()->SetClientSize( mBar->GetMinSize() );
|
|
|
|
// Allow it to propagate to our parent
|
|
event.Skip();
|
|
}
|
|
|
|
//
|
|
// Handle frame paint events
|
|
//
|
|
void OnPaint( wxPaintEvent & event )
|
|
{
|
|
wxPaintDC dc( this );
|
|
wxSize sz = GetSize();
|
|
wxRect r;
|
|
|
|
dc.SetPen( wxColour( 90, 90, 90 ) );
|
|
|
|
#if !defined(__WXMAC__)
|
|
dc.SetBackground(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE)));
|
|
dc.Clear();
|
|
dc.SetBrush( *wxTRANSPARENT_BRUSH );
|
|
dc.DrawRectangle( 0, 0, sz.GetWidth(), sz.GetHeight() );
|
|
#endif
|
|
|
|
if( mBar->IsResizable() )
|
|
{
|
|
r.x = sz.x - sizerW - 2,
|
|
r.y = sz.y - sizerW - 2;
|
|
r.width = sizerW + 2;
|
|
r.height = sizerW + 2;
|
|
|
|
AColor::Line(dc, r.GetLeft(), r.GetBottom(), r.GetRight(), r.GetTop() );
|
|
AColor::Line(dc, r.GetLeft() + 3, r.GetBottom(), r.GetRight(), r.GetTop() + 3 );
|
|
AColor::Line(dc, r.GetLeft() + 6, r.GetBottom(), r.GetRight(), r.GetTop() + 6 );
|
|
AColor::Line(dc, r.GetLeft() + 9, r.GetBottom(), r.GetRight(), r.GetTop() + 9 );
|
|
}
|
|
|
|
}
|
|
|
|
void OnMotion( wxMouseEvent & event )
|
|
{
|
|
// Don't do anything if we're docked or not resizeable
|
|
if( mBar->IsDocked() || !mBar->IsResizable() )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Retrieve the mouse position
|
|
wxPoint pos = ClientToScreen( event.GetPosition() );
|
|
if( HasCapture() && event.Dragging() )
|
|
{
|
|
wxRect rect = GetRect();
|
|
|
|
rect.SetBottomRight( pos );
|
|
if( rect.width < mMinSize.x )
|
|
{
|
|
rect.width = mMinSize.x;
|
|
}
|
|
|
|
if( rect.height < mMinSize.y )
|
|
{
|
|
rect.height = mMinSize.y;
|
|
}
|
|
|
|
SetMinSize( rect.GetSize() );
|
|
SetSize( rect.GetSize() );
|
|
Layout();
|
|
Refresh( false );
|
|
}
|
|
else if( HasCapture() && event.LeftUp() )
|
|
{
|
|
ReleaseMouse();
|
|
}
|
|
else if( !HasCapture() )
|
|
{
|
|
wxRect rect = GetRect();
|
|
wxRect r;
|
|
|
|
r.x = rect.GetRight() - sizerW - 2,
|
|
r.y = rect.GetBottom() - sizerW - 2;
|
|
r.width = sizerW + 2;
|
|
r.height = sizerW + 2;
|
|
|
|
// Is left click within resize grabber?
|
|
if( r.Contains( pos ) && !event.Leaving() )
|
|
{
|
|
SetCursor( wxCURSOR_SIZENWSE );
|
|
if( event.LeftDown() )
|
|
{
|
|
CaptureMouse();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetCursor( wxCURSOR_ARROW );
|
|
}
|
|
}
|
|
}
|
|
|
|
void OnCaptureLost( wxMouseCaptureLostEvent & event )
|
|
{
|
|
if( HasCapture() )
|
|
{
|
|
ReleaseMouse();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Do not allow the window to close through keyboard accelerators
|
|
// (like ALT+F4 on Windows)
|
|
//
|
|
void OnClose( wxCloseEvent & event )
|
|
{
|
|
event.Veto();
|
|
}
|
|
|
|
private:
|
|
|
|
wxWindow *mParent;
|
|
ToolManager *mManager;
|
|
ToolBar *mBar;
|
|
wxSize mMinSize;
|
|
|
|
public:
|
|
|
|
DECLARE_CLASS( ToolFrame );
|
|
DECLARE_EVENT_TABLE();
|
|
};
|
|
|
|
IMPLEMENT_CLASS( ToolFrame, wxFrame );
|
|
|
|
BEGIN_EVENT_TABLE( ToolFrame, wxFrame )
|
|
EVT_GRABBER( wxID_ANY, ToolFrame::OnGrabber )
|
|
EVT_PAINT( ToolFrame::OnPaint )
|
|
EVT_MOUSE_EVENTS( ToolFrame::OnMotion )
|
|
EVT_MOUSE_CAPTURE_LOST( ToolFrame::OnCaptureLost )
|
|
EVT_CLOSE( ToolFrame::OnClose )
|
|
EVT_COMMAND( wxID_ANY, EVT_TOOLBAR_UPDATED, ToolFrame::OnToolBarUpdate )
|
|
END_EVENT_TABLE()
|
|
|
|
IMPLEMENT_CLASS( ToolManager, wxEvtHandler );
|
|
|
|
////////////////////////////////////////////////////////////
|
|
/// Methods for ToolManager
|
|
////////////////////////////////////////////////////////////
|
|
|
|
BEGIN_EVENT_TABLE( ToolManager, wxEvtHandler )
|
|
EVT_GRABBER( wxID_ANY, ToolManager::OnGrabber )
|
|
EVT_TIMER( wxID_ANY, ToolManager::OnTimer )
|
|
END_EVENT_TABLE()
|
|
|
|
//
|
|
// Constructor
|
|
//
|
|
ToolManager::ToolManager( AudacityProject *parent )
|
|
: wxEvtHandler()
|
|
{
|
|
wxPoint pt[ 3 ];
|
|
|
|
#if defined(__WXMAC__)
|
|
// Save original transition
|
|
mTransition = wxSystemOptions::GetOptionInt( wxMAC_WINDOW_PLAIN_TRANSITION );
|
|
#endif
|
|
|
|
// Initialize everything
|
|
mParent = parent;
|
|
mLastPos.x = mBarPos.x = -1;
|
|
mLastPos.y = mBarPos.y = -1;
|
|
mDragWindow = NULL;
|
|
mDragDock = NULL;
|
|
mDragBar = NULL;
|
|
|
|
// Create the down arrow
|
|
pt[ 0 ].x = 0;
|
|
pt[ 0 ].y = 0;
|
|
pt[ 1 ].x = 9;
|
|
pt[ 1 ].y = 9;
|
|
pt[ 2 ].x = 18;
|
|
pt[ 2 ].y = 0;
|
|
|
|
// Create the shaped region
|
|
mDown = new wxRegion( 3, &pt[0] );
|
|
|
|
// Create the down arrow
|
|
pt[ 0 ].x = 9;
|
|
pt[ 0 ].y = 0;
|
|
pt[ 1 ].x = 0;
|
|
pt[ 1 ].y = 9;
|
|
pt[ 2 ].x = 9;
|
|
pt[ 2 ].y = 18;
|
|
|
|
// Create the shaped region
|
|
mLeft = new wxRegion( 3, &pt[0] );
|
|
|
|
// Create the indicator frame
|
|
mIndicator = new wxFrame( NULL,
|
|
wxID_ANY,
|
|
wxEmptyString,
|
|
wxDefaultPosition,
|
|
wxSize( 32, 32 ),
|
|
wxFRAME_TOOL_WINDOW |
|
|
wxFRAME_SHAPED |
|
|
wxNO_BORDER |
|
|
wxFRAME_NO_TASKBAR |
|
|
wxSTAY_ON_TOP );
|
|
|
|
// Hook the creation event...only needed on GTK, but doesn't hurt for all
|
|
mIndicator->Connect( wxEVT_CREATE,
|
|
wxWindowCreateEventHandler( ToolManager::OnIndicatorCreate ),
|
|
NULL,
|
|
this );
|
|
|
|
// Hook the paint event...needed for all
|
|
mIndicator->Connect( wxEVT_PAINT,
|
|
wxPaintEventHandler( ToolManager::OnIndicatorPaint ),
|
|
NULL,
|
|
this );
|
|
|
|
// It's a little shy
|
|
mIndicator->Hide();
|
|
|
|
// Hook the parents mouse events...using the parent helps greatly
|
|
// under GTK
|
|
mParent->Connect( wxEVT_LEFT_UP,
|
|
wxMouseEventHandler( ToolManager::OnMouse ),
|
|
NULL,
|
|
this );
|
|
mParent->Connect( wxEVT_MOTION,
|
|
wxMouseEventHandler( ToolManager::OnMouse ),
|
|
NULL,
|
|
this );
|
|
mParent->Connect( wxEVT_MOUSE_CAPTURE_LOST,
|
|
wxMouseCaptureLostEventHandler( ToolManager::OnCaptureLost ),
|
|
NULL,
|
|
this );
|
|
|
|
// Create the top and bottom docks
|
|
mTopDock = new ToolDock( this, mParent, TopDockID );
|
|
mBotDock = new ToolDock( this, mParent, BotDockID );
|
|
|
|
// Create all of the toolbars
|
|
mBars[ ToolsBarID ] = new ToolsToolBar();
|
|
mBars[ TransportBarID ] = new ControlToolBar();
|
|
mBars[ MeterBarID ] = new MeterToolBar();
|
|
mBars[ EditBarID ] = new EditToolBar();
|
|
mBars[ MixerBarID ] = new MixerToolBar();
|
|
mBars[ TranscriptionBarID ] = new TranscriptionToolBar();
|
|
mBars[ SelectionBarID ] = new SelectionBar();
|
|
mBars[ DeviceBarID ] = new DeviceToolBar();
|
|
|
|
// We own the timer
|
|
mTimer.SetOwner( this );
|
|
|
|
// Process the toolbar config settings
|
|
ReadConfig();
|
|
}
|
|
|
|
//
|
|
// Destructer
|
|
//
|
|
ToolManager::~ToolManager()
|
|
{
|
|
// Save the toolbar states
|
|
WriteConfig();
|
|
|
|
// Remove handlers from parent
|
|
mParent->Disconnect( wxEVT_LEFT_UP,
|
|
wxMouseEventHandler( ToolManager::OnMouse ),
|
|
NULL,
|
|
this );
|
|
mParent->Disconnect( wxEVT_MOTION,
|
|
wxMouseEventHandler( ToolManager::OnMouse ),
|
|
NULL,
|
|
this );
|
|
mParent->Disconnect( wxEVT_MOUSE_CAPTURE_LOST,
|
|
wxMouseCaptureLostEventHandler( ToolManager::OnCaptureLost ),
|
|
NULL,
|
|
this );
|
|
|
|
// Remove our event handlers
|
|
mIndicator->Disconnect( wxEVT_CREATE,
|
|
wxWindowCreateEventHandler( ToolManager::OnIndicatorCreate ),
|
|
NULL,
|
|
this );
|
|
mIndicator->Disconnect( wxEVT_PAINT,
|
|
wxPaintEventHandler( ToolManager::OnIndicatorPaint ),
|
|
NULL,
|
|
this );
|
|
|
|
// Must destroy the window since it doesn't have a parent
|
|
mIndicator->Destroy();
|
|
|
|
// Delete the indicator regions
|
|
delete mLeft;
|
|
delete mDown;
|
|
}
|
|
|
|
void ToolManager::Reset()
|
|
{
|
|
int ndx;
|
|
|
|
// The mInputMeter and mOutputMeter may be in use if audio is playing
|
|
// when this happens.
|
|
gAudioIO->SetMeters( NULL, NULL );
|
|
|
|
// Disconnect all docked bars
|
|
for( ndx = 0; ndx < ToolBarCount; ndx++ )
|
|
{
|
|
wxWindow *parent;
|
|
ToolDock *dock;
|
|
ToolBar *bar = mBars[ ndx ];
|
|
|
|
// Disconnect the bar
|
|
if( bar->IsDocked() )
|
|
{
|
|
bar->GetDock()->Undock( bar );
|
|
parent = NULL;
|
|
}
|
|
else
|
|
{
|
|
parent = bar->GetParent();
|
|
}
|
|
|
|
if( ndx == SelectionBarID )
|
|
{
|
|
dock = mBotDock;
|
|
|
|
wxCommandEvent e;
|
|
bar->GetEventHandler()->ProcessEvent(e);
|
|
}
|
|
else
|
|
{
|
|
dock = mTopDock;
|
|
bar->ReCreateButtons();
|
|
}
|
|
|
|
bar->EnableDisableButtons();
|
|
#if 0
|
|
if( bar->IsResizable() )
|
|
{
|
|
bar->SetSize(bar->GetBestFittingSize());
|
|
}
|
|
#endif
|
|
dock->Dock( bar );
|
|
|
|
Expose( ndx, true );
|
|
|
|
if( parent )
|
|
{
|
|
parent->Destroy();
|
|
}
|
|
}
|
|
// TODO:??
|
|
// If audio was playing, we stopped the VU meters,
|
|
// It would be nice to show them again, but hardly essential as
|
|
// they will show up again on the next play.
|
|
// SetVUMeters(AudacityProject *p);
|
|
LayoutToolBars();
|
|
Updated();
|
|
}
|
|
|
|
//
|
|
// Read the toolbar states
|
|
//
|
|
void ToolManager::ReadConfig()
|
|
{
|
|
wxString oldpath = gPrefs->GetPath();
|
|
wxArrayInt unordered[ DockCount ];
|
|
int order[ DockCount ][ ToolBarCount ];
|
|
bool show[ ToolBarCount ];
|
|
int width[ ToolBarCount ];
|
|
int height[ ToolBarCount ];
|
|
int x, y;
|
|
int dock, ord, ndx;
|
|
|
|
#if defined(__WXMAC__)
|
|
// Disable window animation
|
|
wxSystemOptions::SetOption( wxMAC_WINDOW_PLAIN_TRANSITION, 1 );
|
|
#endif
|
|
|
|
// Invalidate all order entries
|
|
for( dock = 0; dock < DockCount; dock++ )
|
|
{
|
|
for( ord = 0; ord < ToolBarCount; ord++ )
|
|
{
|
|
order[ dock ][ ord ] = NoBarID;
|
|
}
|
|
}
|
|
|
|
// Change to the bar root
|
|
gPrefs->SetPath( wxT("/GUI/ToolBars") );
|
|
|
|
// Load and apply settings for each bar
|
|
for( ndx = 0; ndx < ToolBarCount; ndx++ )
|
|
{
|
|
ToolBar *bar = mBars[ ndx ];
|
|
|
|
// Change to the bar subkey
|
|
gPrefs->SetPath( bar->GetSection() );
|
|
|
|
// Read in all the settings
|
|
gPrefs->Read( wxT("Dock"), &dock, ndx == SelectionBarID ? BotDockID : TopDockID );
|
|
gPrefs->Read( wxT("Order"), &ord, NoBarID );
|
|
gPrefs->Read( wxT("Show"), &show[ ndx ], true );
|
|
|
|
gPrefs->Read( wxT("X"), &x, -1 );
|
|
gPrefs->Read( wxT("Y"), &y, -1 );
|
|
gPrefs->Read( wxT("W"), &width[ ndx ], -1 );
|
|
gPrefs->Read( wxT("H"), &height[ ndx ], -1 );
|
|
|
|
// Docked or floating?
|
|
if( dock )
|
|
{
|
|
// Default to top dock if the ID isn't valid
|
|
if( dock < NoDockID || dock > DockCount ) {
|
|
dock = TopDockID;
|
|
}
|
|
|
|
// Create the bar with the correct parent
|
|
if( dock == TopDockID )
|
|
{
|
|
bar->Create( mTopDock );
|
|
}
|
|
else
|
|
{
|
|
bar->Create( mBotDock );
|
|
}
|
|
|
|
#ifdef EXPERIMENTAL_SYNC_LOCK
|
|
// Set the width
|
|
if( width[ ndx ] >= bar->GetSize().x )
|
|
{
|
|
wxSize sz( width[ ndx ], bar->GetSize().y );
|
|
bar->SetSize( sz );
|
|
bar->Layout();
|
|
}
|
|
#else
|
|
// note that this section is here because if you had been using linking and now you aren't,
|
|
// the space for the extra button is stored in audacity.cfg, and so you get an extra space
|
|
// in the EditToolbar.
|
|
// It is needed so that the meterToolbar size gets preserved.
|
|
// Longer-term we should find a better fix for this.
|
|
wxString thisBar = bar->GetSection();
|
|
if( thisBar != wxT("Edit"))
|
|
{
|
|
// Set the width
|
|
if( width[ ndx ] >= bar->GetSize().x )
|
|
{
|
|
wxSize sz( width[ ndx ], bar->GetSize().y );
|
|
bar->SetSize( sz );
|
|
bar->Layout();
|
|
}
|
|
}
|
|
#endif
|
|
// Is order within range and unoccupied?
|
|
if( ( ord >= 0 ) &&
|
|
( ord < ToolBarCount ) &&
|
|
( order[ dock - 1 ][ ord ] == NoBarID ) )
|
|
{
|
|
// Insert at ordered location
|
|
order[ dock - 1 ][ ord ] = ndx;
|
|
}
|
|
else
|
|
{
|
|
// These must go at the end
|
|
unordered[ dock - 1 ].Add( ndx );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Create the bar (with the top dock being temporary parent)
|
|
bar->Create( mTopDock );
|
|
|
|
// Construct a new floater
|
|
ToolFrame *f = new ToolFrame( mParent, this, bar, wxPoint( x, y ) );
|
|
|
|
// Set the width and height
|
|
if( width[ ndx ] != -1 && height[ ndx ] != -1 )
|
|
{
|
|
wxSize sz( width[ ndx ], height[ ndx ] );
|
|
f->SetSizeHints( sz );
|
|
f->SetSize( sz );
|
|
f->Layout();
|
|
}
|
|
|
|
// Show or hide it
|
|
bar->Expose( show[ ndx ] );
|
|
|
|
// Inform toolbar of change
|
|
bar->SetDocked( NULL, false );
|
|
}
|
|
|
|
// Change back to the bar root
|
|
//gPrefs->SetPath( wxT("..") ); <-- Causes a warning...
|
|
// May or may not have gone into a subdirectory,
|
|
// so use an absolute path.
|
|
gPrefs->SetPath( wxT("/GUI/ToolBars") );
|
|
}
|
|
|
|
// Add all toolbars to their target dock
|
|
for( dock = 0; dock < DockCount; dock++ )
|
|
{
|
|
ToolDock *d = ( dock + 1 == TopDockID ? mTopDock : mBotDock );
|
|
|
|
// Add all ordered toolbars
|
|
for( ord = 0; ord < ToolBarCount; ord++ )
|
|
{
|
|
ndx = order[ dock ][ ord ];
|
|
|
|
// Bypass empty slots
|
|
if( ndx != NoBarID )
|
|
{
|
|
ToolBar *t = mBars[ ndx ];
|
|
|
|
// Dock it
|
|
d->Dock( t );
|
|
|
|
// Hide the bar
|
|
if( !show[ t->GetId() ] )
|
|
{
|
|
d->ShowHide( t->GetId() );
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add all unordered toolbars
|
|
for( ord = 0; ord < (int) unordered[ dock ].GetCount(); ord++ )
|
|
{
|
|
ToolBar *t = mBars[ unordered[ dock ][ ord ] ];
|
|
|
|
// Dock it
|
|
d->Dock( t );
|
|
|
|
// Hide the bar
|
|
if( !show[ t->GetId() ] )
|
|
{
|
|
d->ShowHide( t->GetId() );
|
|
}
|
|
}
|
|
}
|
|
|
|
// Restore original config path
|
|
gPrefs->SetPath( oldpath );
|
|
|
|
#if defined(__WXMAC__)
|
|
// Reinstate original transition
|
|
wxSystemOptions::SetOption( wxMAC_WINDOW_PLAIN_TRANSITION, mTransition );
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Save the toolbar states
|
|
//
|
|
void ToolManager::WriteConfig()
|
|
{
|
|
if( !gPrefs )
|
|
{
|
|
return;
|
|
}
|
|
|
|
wxString oldpath = gPrefs->GetPath();
|
|
int ndx;
|
|
|
|
// Change to the bar root
|
|
gPrefs->SetPath( wxT("/GUI/ToolBars") );
|
|
|
|
// Save state of each bar
|
|
for( ndx = 0; ndx < ToolBarCount; ndx++ )
|
|
{
|
|
ToolBar *bar = mBars[ ndx ];
|
|
|
|
// Change to the bar subkey
|
|
gPrefs->SetPath( bar->GetSection() );
|
|
|
|
// Search both docks for toolbar order
|
|
int to = mTopDock->GetOrder( bar );
|
|
int bo = mBotDock->GetOrder( bar );
|
|
|
|
// Save
|
|
gPrefs->Write( wxT("Dock"), to ? TopDockID : bo ? BotDockID : NoDockID );
|
|
gPrefs->Write( wxT("Order"), to + bo );
|
|
gPrefs->Write( wxT("Show"), IsVisible( ndx ) );
|
|
|
|
wxPoint pos( -1, -1 );
|
|
wxSize sz = bar->GetSize();
|
|
if( !bar->IsDocked() )
|
|
{
|
|
pos = bar->GetParent()->GetPosition();
|
|
sz = bar->GetParent()->GetSize();
|
|
}
|
|
gPrefs->Write( wxT("X"), pos.x );
|
|
gPrefs->Write( wxT("Y"), pos.y );
|
|
gPrefs->Write( wxT("W"), sz.x );
|
|
gPrefs->Write( wxT("H"), sz.y );
|
|
|
|
// Kill the bar
|
|
bar->Destroy();
|
|
|
|
// Change back to the bar root
|
|
gPrefs->SetPath( wxT("..") );
|
|
}
|
|
|
|
// Restore original config path
|
|
gPrefs->SetPath( oldpath );
|
|
gPrefs->Flush();
|
|
}
|
|
|
|
//
|
|
// Return a pointer to the specified toolbar
|
|
//
|
|
ToolBar *ToolManager::GetToolBar( int type ) const
|
|
{
|
|
return mBars[ type ];
|
|
}
|
|
|
|
//
|
|
// Return a pointer to the top dock
|
|
//
|
|
ToolDock *ToolManager::GetTopDock()
|
|
{
|
|
return mTopDock;
|
|
}
|
|
|
|
//
|
|
// Return a pointer to the bottom dock
|
|
//
|
|
ToolDock *ToolManager::GetBotDock()
|
|
{
|
|
return mBotDock;
|
|
}
|
|
|
|
//
|
|
// Queues an EVT_TOOLBAR_UPDATED command event to notify any
|
|
// interest parties of an updated toolbar or dock layout
|
|
//
|
|
void ToolManager::Updated()
|
|
{
|
|
// Queue an update event
|
|
wxCommandEvent e( EVT_TOOLBAR_UPDATED );
|
|
mParent->GetEventHandler()->AddPendingEvent( e );
|
|
}
|
|
|
|
//
|
|
// Return docked state of specified toolbar
|
|
//
|
|
bool ToolManager::IsDocked( int type )
|
|
{
|
|
return mBars[ type ]->IsDocked();
|
|
}
|
|
|
|
//
|
|
// Returns the visibility of the specified toolbar
|
|
//
|
|
bool ToolManager::IsVisible( int type )
|
|
{
|
|
ToolBar *t = mBars[ type ];
|
|
|
|
return t->IsVisible();
|
|
|
|
// If toolbar is floating
|
|
if( !t->IsDocked() )
|
|
{
|
|
// Must return state of floater window
|
|
return t->GetParent()->IsShown();
|
|
}
|
|
|
|
// Return state of docked toolbar
|
|
return t->IsShown();
|
|
}
|
|
|
|
//
|
|
// Toggles the visible/hidden state of a toolbar
|
|
//
|
|
void ToolManager::ShowHide( int type )
|
|
{
|
|
ToolBar *t = mBars[ type ];
|
|
|
|
// Handle docked and floaters differently
|
|
if( t->IsDocked() )
|
|
{
|
|
t->GetDock()->ShowHide( type );
|
|
}
|
|
else
|
|
{
|
|
t->Expose( !t->IsVisible() );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set the visible/hidden state of a toolbar
|
|
//
|
|
void ToolManager::Expose( int type, bool show )
|
|
{
|
|
ToolBar *t = mBars[ type ];
|
|
|
|
// Handle docked and floaters differently
|
|
if( t->IsDocked() )
|
|
{
|
|
t->GetDock()->Expose( type, show );
|
|
}
|
|
else
|
|
{
|
|
t->Expose( show );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Ask both docks to (re)layout their bars
|
|
//
|
|
void ToolManager::LayoutToolBars()
|
|
{
|
|
// Update the layout
|
|
mTopDock->LayoutToolBars();
|
|
mBotDock->LayoutToolBars();
|
|
}
|
|
|
|
//
|
|
// Tell the toolbars that preferences have been updated
|
|
//
|
|
void ToolManager::UpdatePrefs()
|
|
{
|
|
for( int ndx = 0; ndx < ToolBarCount; ndx++ )
|
|
{
|
|
ToolBar *bar = mBars[ ndx ];
|
|
if( bar )
|
|
{
|
|
bar->UpdatePrefs();
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Handle toolbar dragging
|
|
//
|
|
void ToolManager::OnMouse( wxMouseEvent & event )
|
|
{
|
|
// Go ahead and set the event to propagate
|
|
event.Skip();
|
|
|
|
// Can't do anything if we're not dragging. This also prevents
|
|
// us from intercepting events that don't belong to us from the
|
|
// parent since we're Connect()ed to a couple.
|
|
if( !mDragWindow )
|
|
{
|
|
return;
|
|
}
|
|
|
|
#if defined(__WXMAC__)
|
|
// Disable window animation
|
|
wxSystemOptions::SetOption( wxMAC_WINDOW_PLAIN_TRANSITION, 1 );
|
|
#endif
|
|
|
|
// Retrieve the event position
|
|
wxPoint pos =
|
|
( (wxWindow *)event.GetEventObject() )->ClientToScreen( event.GetPosition() );
|
|
|
|
// Button was released...finish the drag
|
|
if( !event.LeftIsDown() )
|
|
{
|
|
// Release capture
|
|
if( mParent->HasCapture() )
|
|
{
|
|
mParent->ReleaseMouse();
|
|
}
|
|
|
|
// Hide the indicator
|
|
mIndicator->Hide();
|
|
|
|
// Transition the bar to a dock
|
|
if( mDragDock && !event.ShiftDown() )
|
|
{
|
|
// Trip over...everyone ashore that's going ashore...
|
|
mDragDock->Dock( mDragBar, mDragBefore );
|
|
|
|
// Done with the floater
|
|
mDragWindow->Destroy();
|
|
mDragBar->Refresh(false);
|
|
}
|
|
else
|
|
{
|
|
// Calling SetDocked() to force the grabber button to popup
|
|
mDragBar->SetDocked( NULL, false );
|
|
}
|
|
|
|
// Done dragging
|
|
mDragWindow = NULL;
|
|
mDragDock = NULL;
|
|
mDragBar = NULL;
|
|
mLastPos.x = mBarPos.x = -1;
|
|
mLastPos.y = mBarPos.y = -1;
|
|
mTimer.Stop();
|
|
}
|
|
else if( event.Dragging() && pos != mLastPos )
|
|
{
|
|
// Make toolbar follow the mouse
|
|
mDragWindow->Move( pos - mDragOffset );
|
|
|
|
// Remember to prevent excessive movement
|
|
mLastPos = pos;
|
|
|
|
// Calc the top dock hittest rectangle
|
|
wxRect tr = mTopDock->GetRect();
|
|
tr.SetBottom( tr.GetBottom() + 10 );
|
|
tr.SetPosition( mTopDock->GetParent()->ClientToScreen( tr.GetPosition() ) );
|
|
|
|
// Calc the bottom dock hittest rectangle
|
|
wxRect br = mBotDock->GetRect();
|
|
br.SetTop( br.GetTop() - 10 );
|
|
br.SetBottom( br.GetBottom() + 20 );
|
|
br.SetPosition( mBotDock->GetParent()->ClientToScreen( br.GetPosition() ) );
|
|
|
|
// Is mouse pointer within either dock?
|
|
ToolDock *dock = NULL;
|
|
if( tr.Contains( pos ) )
|
|
{
|
|
dock = mTopDock;
|
|
}
|
|
else if( br.Contains( pos ) )
|
|
{
|
|
dock = mBotDock;
|
|
}
|
|
|
|
// Looks like we have a winner...
|
|
if( dock )
|
|
{
|
|
wxPoint p;
|
|
wxRect r;
|
|
|
|
// Calculate where the bar would be placed
|
|
mDragBefore = dock->PositionBar( mDragBar, pos, r );
|
|
|
|
// If different than the last time, the indicator must be moved
|
|
if( r != mBarPos )
|
|
{
|
|
wxRect dr = dock->GetRect();
|
|
|
|
// Hide the indicator before changing the shape
|
|
mIndicator->Hide();
|
|
|
|
// Decide which direction the arrow should point
|
|
if( r.GetBottom() >= dr.GetHeight() )
|
|
{
|
|
p.x = dr.GetLeft() + ( dr.GetWidth() / 2 );
|
|
p.y = dr.GetBottom() - mDown->GetBox().GetHeight();
|
|
mCurrent = mDown;
|
|
}
|
|
else
|
|
{
|
|
p.x = dr.GetLeft() + r.GetLeft();
|
|
p.y = dr.GetTop() + r.GetTop() +
|
|
( ( r.GetHeight() - mLeft->GetBox().GetHeight() ) / 2 );
|
|
mCurrent = mLeft;
|
|
}
|
|
|
|
// Change the shape while hidden and then show it if okay
|
|
mIndicator->SetShape( *mCurrent );
|
|
if( !event.ShiftDown() )
|
|
{
|
|
mIndicator->Show();
|
|
mIndicator->Update();
|
|
}
|
|
|
|
// Move it into position
|
|
// LL: Do this after the Show() since KDE doesn't move the window
|
|
// if it's not shown. (Do it outside if the previous IF as well)
|
|
mIndicator->Move( dock->GetParent()->ClientToScreen( p ) );
|
|
|
|
// Remember for next go round
|
|
mBarPos = r;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Hide the indicator if it's still shown
|
|
if( mBarPos.x != -1 )
|
|
{
|
|
// Hide any
|
|
mIndicator->Hide();
|
|
mBarPos.x = -1;
|
|
mBarPos.y = -1;
|
|
}
|
|
}
|
|
|
|
// Remember to which dock the drag bar belongs.
|
|
mDragDock = dock;
|
|
}
|
|
|
|
#if defined(__WXMAC__)
|
|
// Reinstate original transition
|
|
wxSystemOptions::SetOption( wxMAC_WINDOW_PLAIN_TRANSITION, mTransition );
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Deal with new capture lost event
|
|
//
|
|
void ToolManager::OnCaptureLost( wxMouseCaptureLostEvent & event )
|
|
{
|
|
// Can't do anything if we're not dragging. This also prevents
|
|
// us from intercepting events that don't belong to us from the
|
|
// parent since we're Connect()ed to a couple.
|
|
if( !mDragWindow )
|
|
{
|
|
event.Skip();
|
|
return;
|
|
}
|
|
|
|
// Simulate button up
|
|
wxMouseEvent e(wxEVT_LEFT_UP);
|
|
e.SetEventObject(mParent);
|
|
OnMouse(e);
|
|
}
|
|
|
|
//
|
|
// Watch for shift key changes
|
|
//
|
|
void ToolManager::OnTimer( wxTimerEvent & event )
|
|
{
|
|
// Go ahead and set the event to propagate
|
|
event.Skip();
|
|
|
|
// Can't do anything if we're not dragging. This also prevents
|
|
// us from intercepting events that don't belong to us from the
|
|
// parent since we're Connect()ed to a couple.
|
|
if( !mDragWindow )
|
|
{
|
|
return;
|
|
}
|
|
|
|
bool state = wxGetKeyState( WXK_SHIFT );
|
|
if( mLastState != state )
|
|
{
|
|
mLastState = state;
|
|
|
|
#if defined(__WXMAC__)
|
|
// Disable window animation
|
|
wxSystemOptions::SetOption( wxMAC_WINDOW_PLAIN_TRANSITION, 1 );
|
|
#endif
|
|
|
|
mIndicator->Show( !state );
|
|
|
|
#if defined(__WXMAC__)
|
|
// Disable window animation
|
|
wxSystemOptions::SetOption( wxMAC_WINDOW_PLAIN_TRANSITION, mTransition );
|
|
#endif
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Handle Indicator paint events
|
|
//
|
|
// Really only needed for the Mac since SetBackgroundColour()
|
|
// doesn't seem to work with shaped frames.
|
|
//
|
|
void ToolManager::OnIndicatorPaint( wxPaintEvent & event )
|
|
{
|
|
wxWindow *w = (wxWindow *)event.GetEventObject();
|
|
wxPaintDC dc( w );
|
|
dc.SetBackground( *wxBLUE_BRUSH );
|
|
dc.Clear();
|
|
}
|
|
|
|
//
|
|
// Handle Indicator creation event
|
|
//
|
|
// Without this, the initial Indicator window will be a solid blue square
|
|
// until the next time it changes.
|
|
//
|
|
void ToolManager::OnIndicatorCreate( wxWindowCreateEvent & event )
|
|
{
|
|
#if defined(__WXGTK__)
|
|
mIndicator->SetShape( *mCurrent );
|
|
#endif
|
|
event.Skip();
|
|
}
|
|
|
|
//
|
|
// Transition a toolbar from float to dragging
|
|
//
|
|
void ToolManager::OnGrabber( GrabberEvent & event )
|
|
{
|
|
// No need to propagate any further
|
|
event.Skip( false );
|
|
|
|
// Remember which bar we're dragging
|
|
mDragBar = mBars[ event.GetId() ];
|
|
|
|
// Calculate the drag offset
|
|
wxPoint mp = event.GetPosition();
|
|
mDragOffset = mp -
|
|
mDragBar->GetParent()->ClientToScreen( mDragBar->GetPosition() ) +
|
|
wxPoint( 1, 1 );
|
|
|
|
// Must set the bar afloat if it's currently docked
|
|
if( mDragBar->IsDocked() )
|
|
{
|
|
#if defined(__WXMAC__)
|
|
// Disable window animation
|
|
wxSystemOptions::SetOption( wxMAC_WINDOW_PLAIN_TRANSITION, 1 );
|
|
#endif
|
|
|
|
// Adjust the starting position
|
|
mp -= mDragOffset;
|
|
|
|
// Inform toolbar of change
|
|
mDragBar->SetDocked( NULL, true );
|
|
|
|
// Construct a new floater
|
|
mDragWindow = new ToolFrame( mParent, this, mDragBar, mp );
|
|
|
|
// Make sure the ferry is visible
|
|
mDragWindow->Show();
|
|
|
|
// Notify parent of change
|
|
Updated();
|
|
|
|
#if defined(__WXMAC__)
|
|
// Reinstate original transition
|
|
wxSystemOptions::SetOption( wxMAC_WINDOW_PLAIN_TRANSITION, mTransition );
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
mDragWindow = (ToolFrame *) mDragBar->GetParent();
|
|
}
|
|
|
|
// We want all mouse events from this point on
|
|
mParent->CaptureMouse();
|
|
|
|
// Start monitoring shift key changes
|
|
mLastState = wxGetKeyState( WXK_SHIFT );
|
|
mTimer.Start( 100 );
|
|
}
|
|
|
|
// 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: 2f4ec75c-bdb7-4889-96d-5d00abc41027
|