KiCad PCB EDA Suite
color_swatch.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2017-2021 KiCad Developers, see AUTHORS.txt for contributors.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, you may find one here:
18  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19  * or you may search the http://www.gnu.org website for the version 2 license,
20  * or you may write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23 
24 #include <widgets/color_swatch.h>
25 #include <wx/dcmemory.h>
26 
28 #include <memory>
29 
30 wxDEFINE_EVENT( COLOR_SWATCH_CHANGED, wxCommandEvent );
31 
32 using KIGFX::COLOR4D;
33 
34 
35 // See selcolor.cpp:
36 extern COLOR4D DisplayColorFrame( wxWindow* aParent, COLOR4D aOldColor );
37 
38 
39 wxBitmap COLOR_SWATCH::MakeBitmap( const COLOR4D& aColor, const COLOR4D& aBackground,
40  const wxSize& aSize, const wxSize& aCheckerboardSize,
41  const COLOR4D& aCheckerboardBackground )
42 {
43  wxBitmap bitmap( aSize );
44  wxBrush brush;
45  wxPen pen;
46  wxMemoryDC iconDC;
47 
48  iconDC.SelectObject( bitmap );
49  brush.SetStyle( wxBRUSHSTYLE_SOLID );
50 
51  if( aColor == COLOR4D::UNSPECIFIED )
52  {
53  // Draw a checkerboard
54  COLOR4D white;
55  COLOR4D black;
56  bool rowCycle;
57 
58  if( aCheckerboardBackground.GetBrightness() > 0.4 )
59  {
60  white = COLOR4D::WHITE;
61  black = white.Darkened( 0.15 );
62  rowCycle = true;
63  }
64  else
65  {
66  black = COLOR4D::BLACK;
67  white = black.Brightened( 0.15 );
68  rowCycle = false;
69  }
70 
71  for( int x = 0; x < aSize.x; x += aCheckerboardSize.x )
72  {
73  bool colCycle = rowCycle;
74 
75  for( int y = 0; y < aSize.y; y += aCheckerboardSize.y )
76  {
77  COLOR4D color = colCycle ? black : white;
78  brush.SetColour( color.ToColour() );
79  pen.SetColour( color.ToColour() );
80 
81  iconDC.SetBrush( brush );
82  iconDC.SetPen( pen );
83  iconDC.DrawRectangle( x, y, x + aCheckerboardSize.x, y + aCheckerboardSize.y );
84 
85  colCycle = !colCycle;
86  }
87 
88  rowCycle = !rowCycle;
89  }
90  }
91  else
92  {
93  brush.SetColour( aBackground.WithAlpha(1.0).ToColour() );
94  pen.SetColour( aBackground.WithAlpha(1.0).ToColour() );
95 
96  iconDC.SetBrush( brush );
97  iconDC.SetPen( pen );
98  iconDC.DrawRectangle( 0, 0, aSize.x, aSize.y );
99 
100  brush.SetColour( aColor.ToColour() );
101  pen.SetColour( aColor.ToColour() );
102 
103  iconDC.SetBrush( brush );
104  iconDC.SetPen( pen );
105  iconDC.DrawRectangle( 0, 0, aSize.x, aSize.y );
106  }
107 
108  return bitmap;
109 }
110 
111 
112 COLOR_SWATCH::COLOR_SWATCH( wxWindow* aParent, const COLOR4D& aColor, int aID,
113  const COLOR4D& aBackground, const COLOR4D& aDefault,
114  SWATCH_SIZE aSwatchSize ) :
115  wxPanel( aParent, aID ),
116  m_color( aColor ),
117  m_background( aBackground ),
118  m_default( aDefault ),
119  m_userColors( nullptr ),
120  m_readOnly( false ),
121  m_supportsOpacity( true )
122 {
123  wxASSERT_MSG( aSwatchSize != SWATCH_EXPAND, "SWATCH_EXPAND not supported in COLOR_SWATCH" );
124 
125  switch( aSwatchSize )
126  {
127  case SWATCH_MEDIUM: m_size = ConvertDialogToPixels( SWATCH_SIZE_MEDIUM_DU ); break;
128  case SWATCH_SMALL: m_size = ConvertDialogToPixels( SWATCH_SIZE_SMALL_DU ); break;
129  case SWATCH_LARGE: m_size = ConvertDialogToPixels( SWATCH_SIZE_LARGE_DU ); break;
130  case SWATCH_EXPAND: m_size = ConvertDialogToPixels( SWATCH_SIZE_LARGE_DU ); break;
131  }
132 
133  m_checkerboardSize = ConvertDialogToPixels( CHECKERBOARD_SIZE_DU );
134  m_checkerboardBg = aParent->GetBackgroundColour();
135 
136  auto sizer = new wxBoxSizer( wxHORIZONTAL );
137  SetSizer( sizer );
138 
139  wxBitmap bitmap = COLOR_SWATCH::MakeBitmap( aColor, aBackground, m_size,
141  m_swatch = new wxStaticBitmap( this, aID, bitmap );
142 
143  sizer->Add( m_swatch, 0, 0 );
144 
145  setupEvents();
146 }
147 
148 
149 COLOR_SWATCH::COLOR_SWATCH( wxWindow* aParent, wxWindowID aID, const wxPoint& aPos,
150  const wxSize& aSize, long aStyle ) :
151  wxPanel( aParent, aID, aPos, aSize, aStyle ),
152  m_userColors( nullptr ),
153  m_readOnly( false ),
154  m_supportsOpacity( true )
155 {
156  if( aSize == wxDefaultSize )
157  m_size = ConvertDialogToPixels( SWATCH_SIZE_MEDIUM_DU );
158  else
159  m_size = aSize;
160 
161  m_checkerboardSize = ConvertDialogToPixels( CHECKERBOARD_SIZE_DU );
162  m_checkerboardBg = aParent->GetBackgroundColour();
163 
164  SetSize( m_size );
165 
166  auto sizer = new wxBoxSizer( wxHORIZONTAL );
167  SetSizer( sizer );
168 
169  wxBitmap bitmap = COLOR_SWATCH::MakeBitmap( COLOR4D::UNSPECIFIED, COLOR4D::UNSPECIFIED,
171  m_swatch = new wxStaticBitmap( this, aID, bitmap );
172 
173  sizer->Add( m_swatch, 0, 0 );
174 
175  setupEvents();
176 }
177 
178 
180 {
181  wxWindow* topLevelParent = GetParent();
182 
183  while( topLevelParent && !topLevelParent->IsTopLevel() )
184  topLevelParent = topLevelParent->GetParent();
185 
186  if( topLevelParent && dynamic_cast<DIALOG_SHIM*>( topLevelParent ) )
187  {
188  m_swatch->Bind( wxEVT_LEFT_DOWN,
189  [this] ( wxMouseEvent& aEvt )
190  {
192  } );
193  }
194  else
195  {
196  // forward click to any other listeners, since we don't want them
197  m_swatch->Bind( wxEVT_LEFT_DOWN, &COLOR_SWATCH::rePostEvent, this );
198 
199  // bind the events that trigger the dialog
200  m_swatch->Bind( wxEVT_LEFT_DCLICK,
201  [this] ( wxMouseEvent& aEvt )
202  {
204  } );
205  }
206 
207  m_swatch->Bind( wxEVT_MIDDLE_DOWN,
208  [this] ( wxMouseEvent& aEvt )
209  {
211  } );
212 
213  m_swatch->Bind( wxEVT_RIGHT_DOWN, &COLOR_SWATCH::rePostEvent, this );
214 }
215 
216 
217 void COLOR_SWATCH::rePostEvent( wxEvent& aEvent )
218 {
219  wxPostEvent( this, aEvent );
220 }
221 
222 
223 static void sendSwatchChangeEvent( COLOR_SWATCH& aSender )
224 {
225  wxCommandEvent changeEvt( COLOR_SWATCH_CHANGED );
226 
227  // use this class as the object (alternative might be to
228  // set a custom event class but that's more work)
229  changeEvt.SetEventObject( &aSender );
230 
231  wxPostEvent( &aSender, changeEvt );
232 }
233 
234 
235 void COLOR_SWATCH::SetSwatchColor( const COLOR4D& aColor, bool aSendEvent )
236 {
237  m_color = aColor;
238 
240  m_swatch->SetBitmap( bm );
241 
242  if( aSendEvent )
243  sendSwatchChangeEvent( *this );
244 }
245 
246 
248 {
249  m_default = aColor;
250 }
251 
252 
253 void COLOR_SWATCH::SetSwatchBackground( const COLOR4D& aBackground )
254 {
255  m_background = aBackground;
257  m_swatch->SetBitmap( bm );
258 }
259 
260 
262 {
263  return m_color;
264 }
265 
266 
268 {
269  if( m_readOnly )
270  {
271  if( m_readOnlyCallback )
273 
274  return;
275  }
276 
277  DIALOG_COLOR_PICKER dialog( ::wxGetTopLevelParent( this ), m_color, m_supportsOpacity,
279 
280  if( dialog.ShowModal() == wxID_OK )
281  {
282  COLOR4D newColor = dialog.GetColor();
283 
284  if( newColor != COLOR4D::UNSPECIFIED || m_default == COLOR4D::UNSPECIFIED )
285  {
286  m_color = newColor;
287 
288  wxBitmap bm = MakeBitmap( newColor, m_background, m_size, m_checkerboardSize,
290  m_swatch->SetBitmap( bm );
291 
292  sendSwatchChangeEvent( *this );
293  }
294  }
295 }
void SetSwatchColor(const KIGFX::COLOR4D &aColor, bool aSendEvent)
Set the current swatch color directly.
COLOR4D DisplayColorFrame(wxWindow *aParent, COLOR4D aOldColor)
KIGFX::COLOR4D GetSwatchColor() const
double GetBrightness() const
Returns the brightness value of the color ranged from 0.0 to 1.0.
Definition: color4d.h:327
void setupEvents()
static wxBitmap MakeBitmap(const KIGFX::COLOR4D &aColor, const KIGFX::COLOR4D &aBackground, const wxSize &aSize, const wxSize &aCheckerboardSize, const KIGFX::COLOR4D &aCheckerboardBackground)
int color
Definition: DXF_plotter.cpp:60
static const wxSize SWATCH_SIZE_LARGE_DU(24, 16)
COLOR4D WithAlpha(double aAlpha) const
Return a color with the same color, but the given alpha.
Definition: color4d.h:305
Definition: color4d.h:44
COLOR_SWATCH(wxWindow *aParent, const KIGFX::COLOR4D &aColor, int aID, const KIGFX::COLOR4D &aBackground, const KIGFX::COLOR4D &aDefault, SWATCH_SIZE aSwatchType)
Construct a COLOR_SWATCH.
COLOR4D Darkened(double aFactor) const
Return a color that is darker by a given factor, without modifying object.
Definition: color4d.h:276
bool m_supportsOpacity
If opacity is not supported the color chooser dialog will be displayed without it.
Definition: color_swatch.h:145
KIGFX::COLOR4D m_default
Definition: color_swatch.h:131
COLOR4D Brightened(double aFactor) const
Return a color that is brighter by a given factor, without modifying object.
Definition: color4d.h:262
wxSize m_checkerboardSize
Definition: color_swatch.h:137
KIGFX::COLOR4D m_background
Definition: color_swatch.h:130
static const wxSize SWATCH_SIZE_MEDIUM_DU(24, 10)
std::function< void()> m_readOnlyCallback
Definition: color_swatch.h:142
void SetDefaultColor(const KIGFX::COLOR4D &aColor)
Sets the color that will be chosen with the "Reset to Default" button in the chooser.
CUSTOM_COLORS_LIST * m_userColors
Definition: color_swatch.h:132
Definition: color4d.h:48
wxStaticBitmap * m_swatch
Definition: color_swatch.h:134
wxDEFINE_EVENT(COLOR_SWATCH_CHANGED, wxCommandEvent)
KIGFX::COLOR4D m_checkerboardBg
Definition: color_swatch.h:138
bool m_readOnly
A read-only swatch won't show the color chooser dialog but otherwise works normally.
Definition: color_swatch.h:141
static void sendSwatchChangeEvent(COLOR_SWATCH &aSender)
void rePostEvent(wxEvent &aEvent)
Pass unwanted events on to listeners of this object.
static const wxSize CHECKERBOARD_SIZE_DU(3, 3)
KIGFX::COLOR4D GetColor()
A simple color swatch of the kind used to set layer colors.
Definition: color_swatch.h:56
static const wxSize SWATCH_SIZE_SMALL_DU(8, 6)
void GetNewSwatchColor()
Prompt for a new colour, using the colour picker dialog.
KIGFX::COLOR4D m_color
Definition: color_swatch.h:129
SWATCH_SIZE
Definition: color_swatch.h:38
void SetSwatchBackground(const KIGFX::COLOR4D &aBackground)
Set the swatch background color.
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:103