Move layer/render swatches to own class

This introduces COLOR_SWATCH, which is a reusable
widget that shows a color swatch and can invoke the colour picker
when duble/middle clicked.

It uses it's own wxCommandEvent to signal the change.

This makes the layer widget simpler internally, and also allows other
code to show identical swatches if needed.
This commit is contained in:
John Beard 2017-02-21 20:31:19 +08:00 committed by Maciej Suminski
parent e609bc3f0d
commit b8d0b0d7be
5 changed files with 303 additions and 148 deletions

View File

@ -165,6 +165,7 @@ set( COMMON_DLG_SRCS
)
set( COMMON_WIDGET_SRCS
widgets/color_swatch.cpp
widgets/mathplot.cpp
widgets/widget_hotkey_list.cpp
widgets/two_column_tree_list.cpp

View File

@ -0,0 +1,174 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
* Copyright (C) 2017 KiCad Developers, see AUTHORS.TXT for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <widgets/color_swatch.h>
#include <wx/colour.h>
#include <wx/colordlg.h>
wxDEFINE_EVENT(COLOR_SWATCH_CHANGED, wxCommandEvent);
using KIGFX::COLOR4D;
const static int SWATCH_SIZE_X = 14;
const static int SWATCH_SIZE_Y = 12;
// See selcolor.cpp:
extern COLOR4D DisplayColorFrame( wxWindow* aParent, COLOR4D aOldColor );
/**
* Make a simple color swatch bitmap
*/
static wxBitmap makeBitmap( COLOR4D aColor )
{
wxBitmap bitmap( SWATCH_SIZE_X, SWATCH_SIZE_Y );
wxBrush brush;
wxMemoryDC iconDC;
iconDC.SelectObject( bitmap );
brush.SetColour( aColor.ToColour() );
brush.SetStyle( wxBRUSHSTYLE_SOLID );
iconDC.SetBrush( brush );
iconDC.DrawRectangle( 0, 0, SWATCH_SIZE_X, SWATCH_SIZE_Y );
return bitmap;
}
/**
* Function makeColorButton
* creates a wxStaticBitmap and assigns it a solid color and a control ID
*/
static std::unique_ptr<wxStaticBitmap> makeColorSwatch(
wxWindow* aParent, COLOR4D aColor, int aID )
{
// construct a bitmap of the right color and make the swatch from it
wxBitmap bitmap = makeBitmap( aColor );
auto ret = std::make_unique<wxStaticBitmap>( aParent, aID, bitmap );
return ret;
}
COLOR_SWATCH::COLOR_SWATCH( wxWindow* aParent, COLOR4D aColor, int aID,
bool aArbitraryColors ):
wxPanel( aParent, aID ),
m_arbitraryColors( aArbitraryColors ),
m_color( aColor )
{
auto sizer = new wxBoxSizer( wxHORIZONTAL );
SetSizer( sizer );
auto swatch = makeColorSwatch( this, m_color, aID );
m_swatch = swatch.get(); // hold a handle
sizer->Add( swatch.release(), 0, 0 );
// forward click to any other listeners, since we don't want them
m_swatch->Bind( wxEVT_LEFT_DOWN, &COLOR_SWATCH::rePostEvent, this );
m_swatch->Bind( wxEVT_RIGHT_DOWN, &COLOR_SWATCH::rePostEvent, this );
// bind the events that trigger the dialog
m_swatch->Bind( wxEVT_LEFT_DCLICK, [this] ( wxMouseEvent& aEvt ) {
GetNewSwatchColor();
} );
m_swatch->Bind( wxEVT_MIDDLE_DOWN, [this] ( wxMouseEvent& aEvt ) {
GetNewSwatchColor();
} );
}
void COLOR_SWATCH::rePostEvent( wxEvent& aEvt )
{
wxPostEvent( this, aEvt );
}
static void sendSwatchChangeEvent( COLOR_SWATCH& aSender )
{
wxCommandEvent changeEvt( COLOR_SWATCH_CHANGED );
// use this class as the object (alternative might be to
// set a custom event class but that's more work)
changeEvt.SetEventObject( &aSender );
wxPostEvent( &aSender, changeEvt );
}
void COLOR_SWATCH::SetSwatchColor( COLOR4D aColor, bool sendEvent )
{
m_color = aColor;
wxBitmap bm = makeBitmap( aColor );
m_swatch->SetBitmap( bm );
if( sendEvent )
{
sendSwatchChangeEvent( *this );
}
}
COLOR4D COLOR_SWATCH::GetSwatchColor() const
{
return m_color;
}
void COLOR_SWATCH::GetNewSwatchColor()
{
COLOR4D newColor = COLOR4D::UNSPECIFIED;
if( m_arbitraryColors )
{
wxColourData colourData;
colourData.SetColour( m_color.ToColour() );
wxColourDialog* dialog = new wxColourDialog( this, &colourData );
if( dialog->ShowModal() == wxID_OK )
{
newColor = COLOR4D( dialog->GetColourData().GetColour() );
}
}
else
{
newColor = DisplayColorFrame( this, m_color );
}
if( newColor != COLOR4D::UNSPECIFIED )
{
m_color = newColor;
wxBitmap bm = makeBitmap( newColor );
m_swatch->SetBitmap( bm );
sendSwatchChangeEvent( *this );
}
}

View File

@ -0,0 +1,92 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2017 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef COLOR_SWATCH__H_
#define COLOR_SWATCH__H_
#include <wx/wx.h>
#include <common.h>
#include <gal/color4d.h>
/**
* Class representing a simple color swatch, of the kind used to
* set layer colors
*/
class COLOR_SWATCH: public wxPanel
{
public:
/**
* Construct a COLOR_SWATCH
*
* @param aParent parent window
* @param aColor initial swatch color
* @param aID id to use when sending swatch events
*/
COLOR_SWATCH( wxWindow* aParent, KIGFX::COLOR4D aColor, int aID,
bool aArbitraryColors );
/**
* Set the current swatch color directly.
*/
void SetSwatchColor( KIGFX::COLOR4D aColor, bool sendEvent );
/**
* @return the current swatch color
*/
KIGFX::COLOR4D GetSwatchColor() const;
/**
* Prompt for a new colour, using the colour picker dialog.
*
* A colour change event will be sent if it's set.
*/
void GetNewSwatchColor();
private:
/**
* Pass unwanted events on to listeners of this object
*/
void rePostEvent( wxEvent& aEvt );
///> Can the swatch have any color, or only preset ones?
bool m_arbitraryColors;
///> The current colour of the swatch
KIGFX::COLOR4D m_color;
///> Handle of the actual swatch shown
wxStaticBitmap* m_swatch;
};
/**
* Event signalling a swatch has changed color
*/
wxDECLARE_EVENT(COLOR_SWATCH_CHANGED, wxCommandEvent);
#endif // COLOR_SWATCH__H_

View File

@ -37,18 +37,12 @@
#include <macros.h>
#include <common.h>
#include <wx/colour.h>
#include <wx/colordlg.h>
#include <widgets/color_swatch.h>
#include <algorithm>
const static int SWATCH_SIZE_X = 14;
const static int SWATCH_SIZE_Y = 12;
// See selcolor.cpp:
extern COLOR4D DisplayColorFrame( wxWindow* aParent, COLOR4D aOldColor );
const wxEventType LAYER_WIDGET::EVT_LAYER_COLOR_CHANGE = wxNewEventType();
/* XPM
@ -149,56 +143,6 @@ static const char * rightarrow_alternate_xpm[] = {
"..oO "};
/**
* Function makeColorTxt
* returns a string representing the color in CSS format
* For example: "rgba(255, 0, 0, 255)"
*/
static wxString makeColorTxt( COLOR4D aColor )
{
return aColor.ToWxString( wxC2S_CSS_SYNTAX );
}
static wxBitmap makeBitmap( COLOR4D aColor )
{
wxBitmap bitmap( SWATCH_SIZE_X, SWATCH_SIZE_Y );
wxBrush brush;
wxMemoryDC iconDC;
iconDC.SelectObject( bitmap );
brush.SetColour( aColor.ToColour() );
brush.SetStyle( wxBRUSHSTYLE_SOLID );
iconDC.SetBrush( brush );
iconDC.DrawRectangle( 0, 0, SWATCH_SIZE_X, SWATCH_SIZE_Y );
return bitmap;
}
/**
* Function makeColorButton
* creates a wxStaticBitmap and assigns it a solid color and a control ID
*/
static std::unique_ptr<wxStaticBitmap> makeColorSwatch( wxWindow* aParent,
COLOR4D aColor, int aID )
{
// dynamically make a wxBitMap and brush it with the appropriate color,
// then create a wxBitmapButton from it.
wxBitmap bitmap = makeBitmap( aColor );
// save the color value in the name, no where else to put it.
auto ret = std::make_unique<wxStaticBitmap>( aParent, aID, bitmap );
ret->SetName( makeColorTxt( aColor ) );
return ret;
}
/**
* Function shrinkFont
* reduces the size of the wxFont associated with \a aControl
@ -273,38 +217,11 @@ void LAYER_WIDGET::OnLeftDownLayers( wxMouseEvent& event )
}
void LAYER_WIDGET::OnMiddleDownLayerColor( wxMouseEvent& aEvent )
void LAYER_WIDGET::OnLayerSwatchChanged( wxCommandEvent& aEvent )
{
auto eventSource = static_cast<wxStaticBitmap*>( aEvent.GetEventObject() );
auto eventSource = static_cast<COLOR_SWATCH*>( aEvent.GetEventObject() );
wxString colorTxt = eventSource->GetName();
COLOR4D oldColor;
wxASSERT( oldColor.SetFromWxString( colorTxt ) );
COLOR4D newColor = COLOR4D::UNSPECIFIED;
if( AreArbitraryColorsAllowed() )
{
wxColourData colourData;
colourData.SetColour( oldColor.ToColour() );
wxColourDialog* dialog = new wxColourDialog( m_LayerScrolledWindow, &colourData );
if( dialog->ShowModal() == wxID_OK )
{
newColor = COLOR4D( dialog->GetColourData().GetColour() );
}
}
else
{
newColor = DisplayColorFrame( this, oldColor );
}
if( newColor != COLOR4D::UNSPECIFIED )
{
eventSource->SetName( makeColorTxt( newColor ) );
wxBitmap bm = makeBitmap( newColor.ToColour() );
eventSource->SetBitmap( bm );
COLOR4D newColor = eventSource->GetSwatchColor();
LAYER_NUM layer = getDecodedId( eventSource->GetId() );
@ -314,7 +231,6 @@ void LAYER_WIDGET::OnMiddleDownLayerColor( wxMouseEvent& aEvent )
// notify others
wxCommandEvent event( EVT_LAYER_COLOR_CHANGE );
wxPostEvent( this, event );
}
passOnFocus();
}
@ -329,44 +245,17 @@ void LAYER_WIDGET::OnLayerCheckBox( wxCommandEvent& event )
}
void LAYER_WIDGET::OnMiddleDownRenderColor( wxMouseEvent& aEvent )
void LAYER_WIDGET::OnRenderSwatchChanged( wxCommandEvent& aEvent )
{
auto eventSource = static_cast<wxStaticBitmap*>( aEvent.GetEventObject() );
auto eventSource = static_cast<COLOR_SWATCH*>( aEvent.GetEventObject() );
wxString colorTxt = eventSource->GetName();
COLOR4D oldColor;
wxASSERT( oldColor.SetFromWxString( colorTxt ) );
COLOR4D newColor = COLOR4D::UNSPECIFIED;
if( AreArbitraryColorsAllowed() )
{
wxColourData colourData;
colourData.SetColour( oldColor.ToColour() );
wxColourDialog *dialog = new wxColourDialog( m_LayerScrolledWindow, &colourData );
if( dialog->ShowModal() == wxID_OK )
{
newColor = COLOR4D( dialog->GetColourData().GetColour() );
}
}
else
{
newColor = DisplayColorFrame( this, oldColor );
}
if( newColor != COLOR4D::UNSPECIFIED )
{
eventSource->SetName( makeColorTxt( newColor ) );
wxBitmap bm = makeBitmap( newColor );
eventSource->SetBitmap( bm );
COLOR4D newColor = eventSource->GetSwatchColor();
LAYER_NUM id = getDecodedId( eventSource->GetId() );
// tell the client code.
OnRenderColorChange( id, newColor );
}
passOnFocus();
}
@ -458,12 +347,12 @@ void LAYER_WIDGET::insertLayerRow( int aRow, const ROW& aSpec )
// column 1 (COLUMN_COLORBM)
col = COLUMN_COLORBM;
auto bmb = makeColorSwatch( m_LayerScrolledWindow, aSpec.color, encodeId( col, aSpec.id ) );
bmb->Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( LAYER_WIDGET::OnLeftDownLayers ), NULL, this );
bmb->Connect( wxEVT_LEFT_DCLICK, wxMouseEventHandler( LAYER_WIDGET::OnMiddleDownLayerColor ), NULL, this );
bmb->Connect( wxEVT_MIDDLE_DOWN, wxMouseEventHandler( LAYER_WIDGET::OnMiddleDownLayerColor ), NULL, this );
auto bmb = new COLOR_SWATCH( m_LayerScrolledWindow, aSpec.color, encodeId( col, aSpec.id ),
AreArbitraryColorsAllowed() );
bmb->Bind( wxEVT_LEFT_DOWN, &LAYER_WIDGET::OnLeftDownLayers, this );
bmb->Bind( COLOR_SWATCH_CHANGED, &LAYER_WIDGET::OnLayerSwatchChanged, this );
bmb->SetToolTip( _("Left double click or middle click for color change, right click for menu" ) );
m_LayersFlexGridSizer->wxSizer::Insert( index+col, bmb.release(), 0, flags );
m_LayersFlexGridSizer->wxSizer::Insert( index+col, bmb, 0, flags );
// column 2 (COLUMN_COLOR_LYR_CB)
col = COLUMN_COLOR_LYR_CB;
@ -495,13 +384,11 @@ void LAYER_WIDGET::insertRenderRow( int aRow, const ROW& aSpec )
col = 0;
if( aSpec.color != COLOR4D::UNSPECIFIED )
{
auto bmb = makeColorSwatch(m_RenderScrolledWindow, aSpec.color, encodeId( col, aSpec.id ) );
//makeColorSwatch( m_RenderScrolledWindow, aSpec.color, encodeId( col, aSpec.id ) );
bmb->Connect( wxEVT_LEFT_DCLICK, wxMouseEventHandler( LAYER_WIDGET::OnMiddleDownRenderColor ), NULL, this );
bmb->Connect( wxEVT_MIDDLE_DOWN, wxMouseEventHandler( LAYER_WIDGET::OnMiddleDownRenderColor ), NULL, this );
auto bmb = new COLOR_SWATCH( m_RenderScrolledWindow, aSpec.color, encodeId( col, aSpec.id ),
AreArbitraryColorsAllowed() );
bmb->Bind( COLOR_SWATCH_CHANGED, &LAYER_WIDGET::OnRenderSwatchChanged, this );
bmb->SetToolTip( _( "Left double click or middle click for color change" ) );
m_RenderFlexGridSizer->wxSizer::Insert( index+col, bmb.release(), 0, flags );
m_RenderFlexGridSizer->wxSizer::Insert( index+col, bmb, 0, flags );
// could add a left click handler on the color button that toggles checkbox.
}
@ -803,13 +690,10 @@ void LAYER_WIDGET::SetLayerColor( LAYER_NUM aLayer, COLOR4D aColor )
if( row >= 0 )
{
int col = 1; // bitmap button is column 1
wxBitmapButton* bmb = (wxBitmapButton*) getLayerComp( row, col );
auto bmb = static_cast<COLOR_SWATCH*>( getLayerComp( row, col ) );
wxASSERT( bmb );
wxBitmap bm = makeBitmap( aColor );
bmb->SetBitmapLabel( bm );
bmb->SetName( makeColorTxt( aColor ) ); // save color value in name as string
bmb->SetSwatchColor( aColor, false );
}
}

View File

@ -157,10 +157,10 @@ protected:
void OnLeftDownLayers( wxMouseEvent& event );
/**
* Function OnMiddleDownLayerColor
* is called only from a color button when user right clicks.
* Function OnSwatchChanged()
* is called when a user changes a swatch color
*/
void OnMiddleDownLayerColor( wxMouseEvent& event );
void OnLayerSwatchChanged( wxCommandEvent& aEvent );
/**
* Function OnLayerCheckBox
@ -169,7 +169,11 @@ protected:
*/
void OnLayerCheckBox( wxCommandEvent& event );
void OnMiddleDownRenderColor( wxMouseEvent& event );
/**
* Function OnRenderSwatchChanged
* Called when user has changed the swatch color of a render entry
*/
void OnRenderSwatchChanged( wxCommandEvent& aEvent );
void OnRenderCheckBox( wxCommandEvent& event );