diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 2199f07497..df08770f15 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -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 diff --git a/common/widgets/color_swatch.cpp b/common/widgets/color_swatch.cpp new file mode 100644 index 0000000000..745537d4ba --- /dev/null +++ b/common/widgets/color_swatch.cpp @@ -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 + +#include +#include + +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 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( 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 ); + } +} diff --git a/include/widgets/color_swatch.h b/include/widgets/color_swatch.h new file mode 100644 index 0000000000..910f84b09d --- /dev/null +++ b/include/widgets/color_swatch.h @@ -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 + +#include + +#include + + +/** + * 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_ diff --git a/pcbnew/layer_widget.cpp b/pcbnew/layer_widget.cpp index d63c3f9141..b29541dd3a 100644 --- a/pcbnew/layer_widget.cpp +++ b/pcbnew/layer_widget.cpp @@ -37,18 +37,12 @@ #include #include -#include -#include + +#include #include -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 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( aParent, aID, bitmap ); - - ret->SetName( makeColorTxt( aColor ) ); - - return ret; -} - - /** * Function shrinkFont * reduces the size of the wxFont associated with \a aControl @@ -273,48 +217,20 @@ void LAYER_WIDGET::OnLeftDownLayers( wxMouseEvent& event ) } -void LAYER_WIDGET::OnMiddleDownLayerColor( wxMouseEvent& aEvent ) +void LAYER_WIDGET::OnLayerSwatchChanged( wxCommandEvent& aEvent ) { - auto eventSource = static_cast( aEvent.GetEventObject() ); + auto eventSource = static_cast( aEvent.GetEventObject() ); - wxString colorTxt = eventSource->GetName(); + COLOR4D newColor = eventSource->GetSwatchColor(); - COLOR4D oldColor; - wxASSERT( oldColor.SetFromWxString( colorTxt ) ); - COLOR4D newColor = COLOR4D::UNSPECIFIED; + LAYER_NUM layer = getDecodedId( eventSource->GetId() ); - if( AreArbitraryColorsAllowed() ) - { - wxColourData colourData; - colourData.SetColour( oldColor.ToColour() ); - wxColourDialog* dialog = new wxColourDialog( m_LayerScrolledWindow, &colourData ); + // tell the client code. + OnLayerColorChange( layer, newColor ); - 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 ); - - LAYER_NUM layer = getDecodedId( eventSource->GetId() ); - - // tell the client code. - OnLayerColorChange( layer, newColor ); - - // notify others - wxCommandEvent event( EVT_LAYER_COLOR_CHANGE ); - wxPostEvent( this, event ); - } + // 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( aEvent.GetEventObject() ); + auto eventSource = static_cast( aEvent.GetEventObject() ); - wxString colorTxt = eventSource->GetName(); + COLOR4D newColor = eventSource->GetSwatchColor(); - COLOR4D oldColor; - wxASSERT( oldColor.SetFromWxString( colorTxt ) ); - COLOR4D newColor = COLOR4D::UNSPECIFIED; + LAYER_NUM id = getDecodedId( eventSource->GetId() ); - if( AreArbitraryColorsAllowed() ) - { - wxColourData colourData; - colourData.SetColour( oldColor.ToColour() ); - wxColourDialog *dialog = new wxColourDialog( m_LayerScrolledWindow, &colourData ); + // tell the client code. + OnRenderColorChange( id, newColor ); - 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 ); - - 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( 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 ); } } diff --git a/pcbnew/layer_widget.h b/pcbnew/layer_widget.h index 892de638d2..635ee18a23 100644 --- a/pcbnew/layer_widget.h +++ b/pcbnew/layer_widget.h @@ -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 );