KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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
25#include <wx/dcmemory.h>
26
27#include <dpi_scaling_common.h>
29#include <memory>
30
31wxDEFINE_EVENT( COLOR_SWATCH_CHANGED, wxCommandEvent );
32
33using KIGFX::COLOR4D;
34
35
36// See selcolor.cpp:
37extern COLOR4D DisplayColorFrame( wxWindow* aParent, COLOR4D aOldColor );
38
39
40wxBitmap COLOR_SWATCH::MakeBitmap( const COLOR4D& aColor, const COLOR4D& aBackground,
41 const wxSize& aSize, const wxSize& aCheckerboardSize,
42 const COLOR4D& aCheckerboardBackground )
43{
44 wxBitmap bitmap( aSize );
45 wxMemoryDC iconDC;
46
47 iconDC.SelectObject( bitmap );
48
49 RenderToDC( &iconDC, aColor, aBackground, aSize, aCheckerboardSize, aCheckerboardBackground );
50
51 return bitmap;
52}
53
54
55void COLOR_SWATCH::RenderToDC( wxDC* aDC, const KIGFX::COLOR4D& aColor,
56 const KIGFX::COLOR4D& aBackground, const wxRect& aRect,
57 const wxSize& aCheckerboardSize,
58 const KIGFX::COLOR4D& aCheckerboardBackground )
59{
60 wxBrush brush;
61 wxPen pen;
62
63 brush.SetStyle( wxBRUSHSTYLE_SOLID );
64
65 if( aColor == COLOR4D::UNSPECIFIED )
66 {
67 // Draw a checkerboard
68 COLOR4D white;
69 COLOR4D black;
70 bool rowCycle;
71
72 if( aCheckerboardBackground.GetBrightness() > 0.4 )
73 {
74 white = COLOR4D::WHITE;
75 black = white.Darkened( 0.15 );
76 rowCycle = true;
77 }
78 else
79 {
80 black = COLOR4D::BLACK;
81 white = black.Brightened( 0.15 );
82 rowCycle = false;
83 }
84
85 for( int x = aRect.GetLeft(); x < aRect.GetRight(); x += aCheckerboardSize.x )
86 {
87 bool colCycle = rowCycle;
88
89 for( int y = aRect.GetTop(); y < aRect.GetBottom(); y += aCheckerboardSize.y )
90 {
91 COLOR4D color = colCycle ? black : white;
92 brush.SetColour( color.ToColour() );
93 pen.SetColour( color.ToColour() );
94
95 aDC->SetBrush( brush );
96 aDC->SetPen( pen );
97 aDC->DrawRectangle( x, y, aCheckerboardSize.x, aCheckerboardSize.y );
98
99 colCycle = !colCycle;
100 }
101
102 rowCycle = !rowCycle;
103 }
104 }
105 else
106 {
107 brush.SetColour( aBackground.WithAlpha(1.0).ToColour() );
108 pen.SetColour( aBackground.WithAlpha(1.0).ToColour() );
109
110 aDC->SetBrush( brush );
111 aDC->SetPen( pen );
112 aDC->DrawRectangle( aRect );
113
114 brush.SetColour( aColor.ToColour() );
115 pen.SetColour( aColor.ToColour() );
116
117 aDC->SetBrush( brush );
118 aDC->SetPen( pen );
119 aDC->DrawRectangle( aRect );
120 }
121}
122
123
124COLOR_SWATCH::COLOR_SWATCH( wxWindow* aParent, const COLOR4D& aColor, int aID,
125 const COLOR4D& aBackground, const COLOR4D& aDefault,
126 SWATCH_SIZE aSwatchSize, bool aTriggerWithSingleClick ) :
127 wxPanel( aParent, aID ),
128 m_color( aColor ),
129 m_background( aBackground ),
130 m_default( aDefault ),
131 m_userColors( nullptr ),
132 m_readOnly( false ),
133 m_supportsOpacity( true )
134{
135 wxASSERT_MSG( aSwatchSize != SWATCH_EXPAND, wxS( "SWATCH_EXPAND not supported in COLOR_SWATCH" ) );
136
137 switch( aSwatchSize )
138 {
139 case SWATCH_MEDIUM: m_size = ConvertDialogToPixels( SWATCH_SIZE_MEDIUM_DU ); break;
140 case SWATCH_SMALL: m_size = ConvertDialogToPixels( SWATCH_SIZE_SMALL_DU ); break;
141 case SWATCH_LARGE: m_size = ConvertDialogToPixels( SWATCH_SIZE_LARGE_DU ); break;
142 case SWATCH_EXPAND: m_size = ConvertDialogToPixels( SWATCH_SIZE_LARGE_DU ); break;
143 }
144
145 m_checkerboardSize = ConvertDialogToPixels( CHECKERBOARD_SIZE_DU );
146 m_checkerboardBg = aParent->GetBackgroundColour();
147
148#ifdef __WXMSW__
149 // These need additional scaling on Windows because of some discrepancy between pixel and
150 // content scaling that only affects certain widgets on Windows HiDPI. On other platforms, the
151 // value returned by ConvertDialogToPixels appears to be correct.
152 DPI_SCALING_COMMON dpi( nullptr, aParent );
153
156#endif
157
158 auto sizer = new wxBoxSizer( wxHORIZONTAL );
159 SetSizer( sizer );
160
161 wxBitmap bitmap = COLOR_SWATCH::MakeBitmap( aColor, aBackground, m_size,
163 m_swatch = new wxStaticBitmap( this, aID, bitmap );
164
165 sizer->Add( m_swatch, 0, 0 );
166
167 setupEvents( aTriggerWithSingleClick );
168}
169
170
171COLOR_SWATCH::COLOR_SWATCH( wxWindow* aParent, wxWindowID aID, const wxPoint& aPos,
172 const wxSize& aSize, long aStyle ) :
173 wxPanel( aParent, aID, aPos, aSize, aStyle ),
174 m_userColors( nullptr ),
175 m_readOnly( false ),
176 m_supportsOpacity( true )
177{
178 if( aSize == wxDefaultSize )
179 m_size = ConvertDialogToPixels( SWATCH_SIZE_MEDIUM_DU );
180 else
181 m_size = aSize;
182
183 m_checkerboardSize = ConvertDialogToPixels( CHECKERBOARD_SIZE_DU );
184 m_checkerboardBg = aParent->GetBackgroundColour();
185
186 SetSize( m_size );
187
188 auto sizer = new wxBoxSizer( wxHORIZONTAL );
189 SetSizer( sizer );
190
191 wxBitmap bitmap = COLOR_SWATCH::MakeBitmap( COLOR4D::UNSPECIFIED, COLOR4D::UNSPECIFIED,
193 m_swatch = new wxStaticBitmap( this, aID, bitmap );
194
195 sizer->Add( m_swatch, 0, 0 );
196
197 setupEvents( false );
198}
199
200
201void COLOR_SWATCH::setupEvents( bool aTriggerWithSingleClick )
202{
203 wxWindow* topLevelParent = wxGetTopLevelParent( GetParent() );
204
205 if( topLevelParent && dynamic_cast<DIALOG_SHIM*>( topLevelParent ) )
206 {
207 m_swatch->Bind( wxEVT_LEFT_DOWN,
208 [this] ( wxMouseEvent& aEvt )
209 {
211 } );
212 }
213 else
214 {
215 // forward click to any other listeners, since we don't want them
216 m_swatch->Bind( wxEVT_LEFT_DOWN, &COLOR_SWATCH::rePostEvent, this );
217
218 // bind the events that trigger the dialog
219 m_swatch->Bind( wxEVT_LEFT_DCLICK,
220 [this] ( wxMouseEvent& aEvt )
221 {
223 } );
224
225 if( aTriggerWithSingleClick )
226 {
227 m_swatch->Bind( wxEVT_LEFT_UP,
228 [this] ( wxMouseEvent& aEvt )
229 {
231 } );
232 }
233 }
234
235 m_swatch->Bind( wxEVT_MIDDLE_DOWN,
236 [this] ( wxMouseEvent& aEvt )
237 {
239 } );
240
241 m_swatch->Bind( wxEVT_RIGHT_DOWN, &COLOR_SWATCH::rePostEvent, this );
242}
243
244
245void COLOR_SWATCH::rePostEvent( wxEvent& aEvent )
246{
247 wxPostEvent( this, aEvent );
248}
249
250
251static void sendSwatchChangeEvent( COLOR_SWATCH& aSender )
252{
253 wxCommandEvent changeEvt( COLOR_SWATCH_CHANGED, aSender.GetId() );
254
255 // use this class as the object (alternative might be to
256 // set a custom event class but that's more work)
257 changeEvt.SetEventObject( &aSender );
258
259 wxPostEvent( &aSender, changeEvt );
260}
261
262
263void COLOR_SWATCH::SetSwatchColor( const COLOR4D& aColor, bool aSendEvent )
264{
265 m_color = aColor;
266
268 m_swatch->SetBitmap( bm );
269
270 if( aSendEvent )
271 sendSwatchChangeEvent( *this );
272}
273
274
276{
277 m_default = aColor;
278}
279
280
282{
283 m_background = aBackground;
285 m_swatch->SetBitmap( bm );
286}
287
288
290{
291 return m_color;
292}
293
294
296{
297 if( m_readOnly )
298 {
301
302 return;
303 }
304
305 DIALOG_COLOR_PICKER dialog( ::wxGetTopLevelParent( this ), m_color, m_supportsOpacity,
307
308 if( dialog.ShowModal() == wxID_OK )
309 {
310 COLOR4D newColor = dialog.GetColor();
311
312 if( newColor != COLOR4D::UNSPECIFIED || m_default == COLOR4D::UNSPECIFIED )
313 {
314 m_color = newColor;
315
316 wxBitmap bm = MakeBitmap( newColor, m_background, m_size, m_checkerboardSize,
318 m_swatch->SetBitmap( bm );
319
320 sendSwatchChangeEvent( *this );
321 }
322 }
323}
324
325
327{
328 m_checkerboardBg = m_parent->GetBackgroundColour();
330 m_swatch->SetBitmap( bm );
331}
int color
Definition: DXF_plotter.cpp:58
A simple color swatch of the kind used to set layer colors.
Definition: color_swatch.h:57
void SetSwatchColor(const KIGFX::COLOR4D &aColor, bool aSendEvent)
Set the current swatch color directly.
wxSize m_checkerboardSize
Definition: color_swatch.h:155
KIGFX::COLOR4D m_checkerboardBg
Definition: color_swatch.h:156
KIGFX::COLOR4D m_default
Definition: color_swatch.h:149
bool m_supportsOpacity
If opacity is not supported the color chooser dialog will be displayed without it.
Definition: color_swatch.h:163
wxStaticBitmap * m_swatch
Definition: color_swatch.h:152
void OnDarkModeToggle()
Respond to a change in the OS's DarkMode setting.
void GetNewSwatchColor()
Prompt for a new colour, using the colour picker dialog.
bool m_readOnly
A read-only swatch won't show the color chooser dialog but otherwise works normally.
Definition: color_swatch.h:159
KIGFX::COLOR4D GetSwatchColor() const
COLOR_SWATCH(wxWindow *aParent, const KIGFX::COLOR4D &aColor, int aID, const KIGFX::COLOR4D &aBackground, const KIGFX::COLOR4D &aDefault, SWATCH_SIZE aSwatchType, bool aTriggerWithSingleClick=false)
Construct a COLOR_SWATCH.
KIGFX::COLOR4D m_color
Definition: color_swatch.h:147
KIGFX::COLOR4D m_background
Definition: color_swatch.h:148
static void RenderToDC(wxDC *aDC, const KIGFX::COLOR4D &aColor, const KIGFX::COLOR4D &aBackground, const wxRect &aRect, const wxSize &aCheckerboardSize, const KIGFX::COLOR4D &aCheckerboardBackground)
void setupEvents(bool aTriggerWithSingleClick)
std::function< void()> m_readOnlyCallback
Definition: color_swatch.h:160
void SetDefaultColor(const KIGFX::COLOR4D &aColor)
Sets the color that will be chosen with the "Reset to Default" button in the chooser.
void SetSwatchBackground(const KIGFX::COLOR4D &aBackground)
Set the swatch background color.
CUSTOM_COLORS_LIST * m_userColors
Definition: color_swatch.h:150
void rePostEvent(wxEvent &aEvent)
Pass unwanted events on to listeners of this object.
static wxBitmap MakeBitmap(const KIGFX::COLOR4D &aColor, const KIGFX::COLOR4D &aBackground, const wxSize &aSize, const wxSize &aCheckerboardSize, const KIGFX::COLOR4D &aCheckerboardBackground)
KIGFX::COLOR4D GetColor()
Dialog helper object to sit in the inheritance tree between wxDialog and any class written by wxFormB...
Definition: dialog_shim.h:83
Class to handle configuration and automatic determination of the DPI scale to use for canvases.
double GetContentScaleFactor() const override
Get the content scale factor, which may be different from the scale factor on some platforms.
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
COLOR4D WithAlpha(double aAlpha) const
Return a color with the same color, but the given alpha.
Definition: color4d.h:311
COLOR4D Darkened(double aFactor) const
Return a color that is darker by a given factor, without modifying object.
Definition: color4d.h:282
double GetBrightness() const
Returns the brightness value of the color ranged from 0.0 to 1.0.
Definition: color4d.h:333
COLOR4D Brightened(double aFactor) const
Return a color that is brighter by a given factor, without modifying object.
Definition: color4d.h:268
wxColour ToColour() const
Definition: color4d.cpp:220
wxDEFINE_EVENT(COLOR_SWATCH_CHANGED, wxCommandEvent)
static void sendSwatchChangeEvent(COLOR_SWATCH &aSender)
COLOR4D DisplayColorFrame(wxWindow *aParent, COLOR4D aOldColor)
static const wxSize SWATCH_SIZE_LARGE_DU(24, 16)
static const wxSize SWATCH_SIZE_MEDIUM_DU(24, 10)
static const wxSize CHECKERBOARD_SIZE_DU(3, 3)
static const wxSize SWATCH_SIZE_SMALL_DU(8, 6)
SWATCH_SIZE
Definition: color_swatch.h:39
@ SWATCH_MEDIUM
Definition: color_swatch.h:41
@ SWATCH_LARGE
Definition: color_swatch.h:42
@ SWATCH_EXPAND
Definition: color_swatch.h:43
@ SWATCH_SMALL
Definition: color_swatch.h:40