KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_color_picker.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * 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, see <https://www.gnu.org/licenses/>.
18 */
19
20
21#include <kiplatform/ui.h>
23#include <cmath>
24#include <algorithm>
25#include <kiface_base.h>
28#include <wx/bitmap.h>
29#include <wx/dcmemory.h>
30
31#define ALPHA_MAX 100 // the max value returned by the alpha (opacity) slider
32#define SLOPE_AXIS ( bmsize.y / 5.28 ) // was 50 at 264 size
33
34using KIGFX::COLOR4D;
35
36// Configure the spin controls contained inside the dialog
37void configureSpinCtrl( wxSpinCtrl* aCtrl )
38{
39 wxSize textLength = aCtrl->GetTextExtent( "999" );
40 wxSize ctrlSize = aCtrl->GetSizeFromTextSize( textLength );
41
42 aCtrl->SetMinSize( ctrlSize );
43 aCtrl->SetSize( ctrlSize );
44}
45
46
47DIALOG_COLOR_PICKER::DIALOG_COLOR_PICKER( wxWindow* aParent, const COLOR4D& aCurrentColor, bool aAllowOpacityControl,
48 std::vector<CUSTOM_COLOR_ITEM>* aUserColors, const COLOR4D& aDefaultColor ) :
50{
51 m_allowMouseEvents = false;
52 m_allowOpacityCtrl = aAllowOpacityControl;
53 m_previousColor4D = aCurrentColor;
54 m_newColor4D = aCurrentColor;
55 m_newColor4D.ToHSV( m_hue, m_sat, m_val, true );
56 m_bitmapRGB = nullptr;
57 m_bitmapHSV = nullptr;
58 m_selectedCursor = nullptr;
59 m_defaultColor = aDefaultColor;
60
62
63 m_OldColorRect->SetMinSize( FromDIP( wxSize( 20, 20 ) ) );
64 m_NewColorRect->SetMinSize( FromDIP( wxSize( 20, 20 ) ) );
65
66 m_colorValue->SetMinSize( wxSize( GetTextExtent( wxS( "@{color(DEVICE_BACKGROUND)}" ) ).x + FromDIP( 8 ), -1 ) );
67
69 {
70 m_SizerTransparency->Show( false );
71
72 if( aCurrentColor != COLOR4D::UNSPECIFIED )
73 {
74 m_previousColor4D.a = 1.0;
75 m_newColor4D.a = 1.0;
76 }
77 }
78
79 // UNSPECIFIED is ( 0, 0, 0, 0 ) but that is unfriendly for editing because you have to notice
80 // first that the value slider is all the way down before you get any color
81 if( aCurrentColor == COLOR4D::UNSPECIFIED )
82 m_val = 1.0;
83
85 wxASSERT( cfg );
86
87 m_notebook->SetSelection( cfg->m_ColorPicker.default_tab );
88
89 // Build the defined colors panel:
90 initDefinedColors( aUserColors );
91
99 if( aDefaultColor == COLOR4D::UNSPECIFIED )
100 m_resetToDefault->SetLabel( _( "Clear Color" ) );
101
103}
104
105
107{
109 wxASSERT( cfg );
110
111 if( cfg )
112 cfg->m_ColorPicker.default_tab = m_notebook->GetSelection();
113
114 delete m_bitmapRGB;
115 delete m_bitmapHSV;
116
117 for( wxStaticBitmap* swatch : m_colorSwatches )
118 {
119 swatch->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED,
120 wxMouseEventHandler( DIALOG_COLOR_PICKER::buttColorClick ),
121 nullptr, this );
122 }
123}
124
125
126void DIALOG_COLOR_PICKER::updatePreview( wxStaticBitmap* aStaticBitmap, COLOR4D& aColor4D )
127{
128 wxSize swatchSize = aStaticBitmap->GetSize();
129 wxSize checkerboardSize = ConvertDialogToPixels( CHECKERBOARD_SIZE_DU );
130
131 wxBitmap newBm = COLOR_SWATCH::MakeBitmap( aColor4D, COLOR4D::WHITE,
132 ToPhys( swatchSize ),
133 ToPhys( checkerboardSize ),
134 aStaticBitmap->GetParent()->GetBackgroundColour() );
135
136 newBm.SetScaleFactor( GetDPIScaleFactor() );
137 aStaticBitmap->SetBitmap( newBm );
138}
139
140
142{
143 SetEditVals( INIT, false );
144
145 // Configure the spin control sizes
151
152 m_notebook->GetPage( 0 )->Layout();
153 m_notebook->GetPage( 1 )->Layout();
154
156
157 // Draw all bitmaps, with colors according to the color 4D
159 drawAll();
160
161 return true;
162}
163
164
165void DIALOG_COLOR_PICKER::initDefinedColors( std::vector<CUSTOM_COLOR_ITEM>* aPredefinedColors )
166{
167 #define ID_COLOR_BLACK 2000 // colors_id = ID_COLOR_BLACK a ID_COLOR_BLACK + NBCOLORS-1
168
169 // Colors are built from the colorRefs() table (size NBCOLORS).
170 // The look is better when colorRefs() order is displayed in a grid matrix
171 // of 7 row and 5 columns, first filling a row, and after the next column.
172 // But the wxFlexGrid used here must be filled by columns, then next row
173 // the best interval colorRefs() from a matrix row to the next row is 6
174 // So when have to reorder the index used to explore colorRefs()
175 int grid_col = 0;
176 int grid_row = 0;
177 int table_row_count = 7;
178
179 wxSize swatchSize = ConvertDialogToPixels( SWATCH_SIZE_LARGE_DU );
180 wxSize checkerboardSize = ConvertDialogToPixels( CHECKERBOARD_SIZE_DU );
181 COLOR4D checkboardBackground = m_OldColorRect->GetParent()->GetBackgroundColour();
182
183 auto addSwatch =
184 [&]( int aId, COLOR4D aColor, const wxString& aColorName )
185 {
186 wxBitmap bm = COLOR_SWATCH::MakeBitmap( aColor, COLOR4D::WHITE,
187 ToPhys( swatchSize ),
188 ToPhys( checkerboardSize ),
189 checkboardBackground );
190
191 bm.SetScaleFactor( GetDPIScaleFactor() );
192 wxStaticBitmap* swatch = new wxStaticBitmap( m_panelDefinedColors, aId, bm );
193
194 m_fgridColor->Add( swatch, 0, wxALIGN_CENTER_VERTICAL, 5 );
195
196 wxStaticText* label = new wxStaticText( m_panelDefinedColors, wxID_ANY, aColorName,
197 wxDefaultPosition, wxDefaultSize, 0 );
198 m_fgridColor->Add( label, 1, wxALIGN_CENTER_VERTICAL | wxRIGHT, 15 );
199
200 m_colorSwatches.push_back( swatch );
201
202 swatch->Connect( wxEVT_LEFT_DOWN,
203 wxMouseEventHandler( DIALOG_COLOR_PICKER::buttColorClick ),
204 nullptr, this );
205 swatch->Connect( wxEVT_LEFT_DCLICK,
206 wxMouseEventHandler( DIALOG_COLOR_PICKER::colorDClick ),
207 nullptr, this );
208 };
209
210 // If no predefined list is given, build the default predefined colors:
211 if( aPredefinedColors )
212 {
213 for( unsigned jj = 0; jj < aPredefinedColors->size() && jj < NBCOLORS; ++jj )
214 {
215 CUSTOM_COLOR_ITEM* item = & *aPredefinedColors->begin() + jj;
216 int butt_ID = ID_COLOR_BLACK + jj;
217
218 addSwatch( butt_ID, item->m_Color, item->m_ColorName );
219 m_Color4DList.push_back( item->m_Color );
220 }
221 }
222 else
223 {
224 m_Color4DList.assign( NBCOLORS, COLOR4D( 0.0, 0.0, 0.0, 1.0 ) );
225
226 for( int jj = 0; jj < NBCOLORS; ++jj, grid_col++ )
227 {
228 if( grid_col * table_row_count >= NBCOLORS )
229 {
230 // the current grid row is filled, and we must fill the next grid row
231 grid_col = 0;
232 grid_row++;
233 }
234
235 int ii = grid_row + ( grid_col * table_row_count ); // The index in colorRefs()
236 int butt_ID = ID_COLOR_BLACK + ii;
237 COLOR4D buttcolor = COLOR4D( colorRefs()[ii].m_Numcolor );
238
239 addSwatch( butt_ID, buttcolor, wxGetTranslation( colorRefs()[ii].m_ColorName ) );
240 m_Color4DList[ butt_ID - ID_COLOR_BLACK ] = buttcolor;
241 }
242 }
243}
244
245
247{
248 wxSize bmsize = ToPhys( m_RgbBitmap->GetSize() );
249 int half_size = std::min( bmsize.x, bmsize.y )/2;
250
251 // We use here a Y axis from bottom to top and origin to center, So we need to map
252 // coordinated to write pixel in a wxImage. MAPX and MAPY are defined above so they
253 // must be undefined here to prevent compiler warnings.
254#undef MAPX
255#undef MAPY
256#define MAPX( xx ) bmsize.x / 2 + ( xx )
257#define MAPY( yy ) bmsize.y / 2 - ( yy )
258
259 // Reserve room to draw cursors inside the bitmap
260 half_size -= m_cursorsSize/2;
261
262 COLOR4D color;
263
264 // Red blue area in X Z 3d axis
265 double inc = 255.0 / half_size;
266 double slope = SLOPE_AXIS/half_size;
267 color.g = 0.0;
268
269 wxImage img( bmsize ); // a temporary buffer to build the color map
270
271 // clear background (set the window bg color)
272 wxColor bg = GetBackgroundColour();
273
274 // Don't do standard-color lookups on OSX each time through the loop
275 wxColourBase::ChannelType bgR = bg.Red();
276 wxColourBase::ChannelType bgG = bg.Green();
277 wxColourBase::ChannelType bgB = bg.Blue();
278
279 for( int xx = 0; xx < bmsize.x; xx++ ) // blue axis
280 {
281 for( int yy = 0; yy < bmsize.y; yy++ ) // Red axis
282 img.SetRGB( xx, yy, bgR, bgG, bgB );
283 }
284
285 // Build the palette
286 for( int xx = 0; xx < half_size; xx++ ) // blue axis
287 {
288 color.b = inc * xx;
289
290 for( int yy = 0; yy < half_size; yy++ ) // Red axis
291 {
292 color.r = inc * yy;
293 img.SetRGB( MAPX( xx ), MAPY( yy - (slope*xx) ), color.r, color.g, color.b );
294 }
295 }
296
297 // Red green area in y Z 3d axis
298 color.b = 0.0;
299
300 for( int xx = 0; xx < half_size; xx++ ) // green axis
301 {
302 color.g = inc * xx;
303
304 for( int yy = 0; yy < half_size; yy++ ) // Red axis
305 {
306 color.r = inc * yy;
307 img.SetRGB( MAPX( -xx ), MAPY( yy - (slope*xx) ), color.r, color.g, color.b );
308 }
309 }
310
311 // Blue green area in x y 3d axis
312 color.r = 0.0;
313
314 for( int xx = 0; xx < half_size; xx++ ) // green axis
315 {
316 color.g = inc * xx;
317
318 for( int yy = 0; yy < half_size; yy++ ) // blue axis
319 {
320 color.b = inc * yy;
321
322 // Mapping the xx, yy color axis to draw coordinates is more tricky than previously
323 // in DC coordinates:
324 // the blue axis is the (0, 0) to half_size, (-yy - SLOPE_AXIS)
325 // the green axis is the (0, 0) to - half_size, (-yy - SLOPE_AXIS)
326 int drawX = -xx + yy;
327 int drawY = - std::min( xx,yy ) * 0.9;
328 img.SetRGB( MAPX( drawX ), MAPY( drawY - std::abs( slope*drawX ) ),
329 color.r, color.g, color.b );
330 }
331 }
332
333 delete m_bitmapRGB;
334 m_bitmapRGB = new wxBitmap( img, 24 );
335
336 m_bitmapRGB->SetScaleFactor( GetDPIScaleFactor() );
337}
338
339
341{
342 wxSize bmsize = ToPhys( m_HsvBitmap->GetSize() );
343 int half_size = std::min( bmsize.x, bmsize.y )/2;
344
345 // We use here a Y axis from bottom to top and origin to center, So we need to map
346 // coordinated to write pixel in a wxImage
347 #define MAPX( xx ) bmsize.x / 2 + ( xx )
348 #define MAPY( yy ) bmsize.y / 2 - ( yy )
349
350 wxImage img( bmsize ); // a temporary buffer to build the color map
351
352 // clear background (set the window bg color)
353 wxColor bg = GetBackgroundColour();
354
355 // Don't do standard-color lookups on OSX each time through the loop
356 wxColourBase::ChannelType bgR = bg.Red();
357 wxColourBase::ChannelType bgG = bg.Green();
358 wxColourBase::ChannelType bgB = bg.Blue();
359
360 for( int xx = 0; xx < bmsize.x; xx++ ) // blue axis
361 {
362 for( int yy = 0; yy < bmsize.y; yy++ ) // Red axis
363 img.SetRGB( xx, yy, bgR, bgG, bgB );
364 }
365
366 // Reserve room to draw cursors inside the bitmap
367 half_size -= m_cursorsSize/2;
368
369 double hue, sat;
370 COLOR4D color;
371 int sq_radius = half_size*half_size;
372
373 // Build the palette
374 for( int xx = -half_size; xx < half_size; xx++ )
375 {
376 for( int yy = -half_size; yy < half_size; yy++ )
377 {
378 sat = double(xx*xx + yy*yy) / sq_radius;
379
380 // sat is <= 1.0
381 // any value > 1.0 is not a valid HSB color:
382 if( sat > 1.0 )
383 continue;
384
385 // sat is the distance from center
386 sat = sqrt( sat );
387 hue = atan2( (double)yy, (double)xx ) * 180 / M_PI;
388
389 if( hue < 0.0 )
390 hue += 360.0;
391
392 color.FromHSV( hue, sat, 1.0 );
393
394 img.SetRGB( MAPX( xx ), MAPY( yy ), color.r * 255, color.g * 255, color.b * 255 );
395 }
396 }
397
398 delete m_bitmapHSV;
399 m_bitmapHSV = new wxBitmap( img, 24 );
400
401 m_bitmapHSV->SetScaleFactor( GetDPIScaleFactor() );
402}
403
404
406{
407 if( !m_bitmapRGB || m_bitmapRGB->GetSize() != ToPhys( m_RgbBitmap->GetSize() ) )
409
410 wxSize bmsize = m_bitmapRGB->GetSize();
411 int half_size = std::min( bmsize.x, bmsize.y ) / 2;
412
413 wxBitmap newBm( *m_bitmapRGB );
414 newBm.SetScaleFactor( 1.0 );
415
416 {
417 wxMemoryDC bitmapDC( newBm );
418
419 // Use Y axis from bottom to top and origin to center
420 bitmapDC.SetAxisOrientation( true, true );
421
422 #if defined( __WXMSW__ ) && !wxCHECK_VERSION( 3, 3, 0 )
423 // For some reason, SetDeviceOrigin has changed in wxWidgets 3.1.6 or 3.1.7
424 // It was fixed in wx >= 3.3
425 bitmapDC.SetDeviceOrigin( half_size, -half_size );
426 #else
427 bitmapDC.SetDeviceOrigin( half_size, half_size );
428 #endif
429
430 // Reserve room to draw cursors inside the bitmap
431 half_size -= m_cursorsSize / 2;
432
433 // Draw the 3 RGB cursors, using white color to make them always visible:
434 wxPen pen( wxColor( 255, 255, 255 ), 2 ); // use 2 pixels for pen size
435 wxBrush brush( wxColor( 0, 0, 0 ), wxBRUSHSTYLE_TRANSPARENT );
436 bitmapDC.SetPen( pen );
437 bitmapDC.SetBrush( brush );
438 int half_csize = m_cursorsSize / 2;
439
440 double slope = SLOPE_AXIS / half_size;
441
442 // Red axis cursor (Z 3Daxis):
443 m_cursorBitmapRed.x = 0;
444 m_cursorBitmapRed.y = m_newColor4D.r * half_size;
445 bitmapDC.DrawRectangle( m_cursorBitmapRed.x - half_csize,
446 m_cursorBitmapRed.y - half_csize,
448
449 // Blue axis cursor (X 3Daxis):
450 m_cursorBitmapBlue.x = m_newColor4D.b * half_size;
452 bitmapDC.DrawRectangle( m_cursorBitmapBlue.x - half_csize,
453 m_cursorBitmapBlue.y - half_csize,
455
456 // Green axis cursor (Y 3Daxis):
457 m_cursorBitmapGreen.x = m_newColor4D.g * half_size;
460
461 bitmapDC.DrawRectangle( m_cursorBitmapGreen.x - half_csize,
462 m_cursorBitmapGreen.y - half_csize,
464
465 // Draw the 3 RGB axis:
466 half_size += half_size/5;
467 bitmapDC.DrawLine( 0, 0, 0, half_size ); // Red axis (Z 3D axis)
468 bitmapDC.DrawLine( 0, 0, half_size, - half_size*slope ); // Blue axis (X 3D axis)
469 bitmapDC.DrawLine( 0, 0, -half_size, - half_size*slope ); // green axis (Y 3D axis)
470 }
471
472 newBm.SetScaleFactor( GetDPIScaleFactor() );
473 m_RgbBitmap->SetBitmap( newBm );
474}
475
476
478{
479 if( !m_bitmapHSV || m_bitmapHSV->GetSize() != ToPhys( m_HsvBitmap->GetSize() ) )
481
482 wxSize bmsize = m_bitmapHSV->GetSize();
483 int half_size = std::min( bmsize.x, bmsize.y ) / 2;
484
485 wxBitmap newBm( *m_bitmapHSV );
486 newBm.SetScaleFactor( 1.0 );
487
488 {
489 wxMemoryDC bitmapDC( newBm );
490
491 // Use Y axis from bottom to top and origin to center
492 bitmapDC.SetAxisOrientation( true, true );
493 #if defined( __WXMSW__ ) && !wxCHECK_VERSION(3,3,0)
494 // For some reason, SetDeviceOrigin has changed in wxWidgets 3.1.6 or 3.1.7
495 // It was fixed in wx >= 3.3
496 bitmapDC.SetDeviceOrigin( half_size, -half_size );
497 #else
498 bitmapDC.SetDeviceOrigin( half_size, half_size );
499 #endif
500
501 // Reserve room to draw cursors inside the bitmap
502 half_size -= m_cursorsSize / 2;
503
504 // Draw the HSB cursor:
505 m_cursorBitmapHSV.x = cos( m_hue * M_PI / 180.0 ) * half_size * m_sat;
506 m_cursorBitmapHSV.y = sin( m_hue * M_PI / 180.0 ) * half_size * m_sat;
507
508 wxPen pen( wxColor( 0, 0, 0 ), 2 ); // Use 2 pixels as pensize
509 wxBrush brush( wxColor( 0, 0, 0 ), wxBRUSHSTYLE_TRANSPARENT );
510 bitmapDC.SetPen( pen );
511 bitmapDC.SetBrush( brush );
512
513 bitmapDC.DrawRectangle( m_cursorBitmapHSV.x - ( m_cursorsSize / 2 ),
516 }
517
518 newBm.SetScaleFactor( GetDPIScaleFactor() );
519 m_HsvBitmap->SetBitmap( newBm );
520}
521
522
523void DIALOG_COLOR_PICKER::SetEditVals( CHANGED_COLOR aChanged, bool aCheckTransparency )
524{
525 if( aCheckTransparency )
526 {
527 // If they've changed the color, they probably don't want it to remain 100% transparent,
528 // and it looks like a bug when changing the color has no effect.
529 if( m_newColor4D.a == 0.0 )
530 m_newColor4D.a = 1.0;
531 }
532
534
535 if( aChanged == RED_CHANGED || aChanged == GREEN_CHANGED || aChanged == BLUE_CHANGED )
536 m_newColor4D.ToHSV( m_hue, m_sat, m_val, true );
537
538 if( aChanged != RED_CHANGED )
539 m_spinCtrlRed->SetValue( normalizeToInt( m_newColor4D.r ) );
540
541 if( aChanged != GREEN_CHANGED )
543
544 if( aChanged != BLUE_CHANGED )
546
547 if( aChanged != HUE_CHANGED )
548 m_spinCtrlHue->SetValue( (int)m_hue );
549
550 if( aChanged != SAT_CHANGED )
551 m_spinCtrlSaturation->SetValue( m_sat * 255 );
552
553 if( aChanged != VAL_CHANGED )
555
556 if( aChanged == INIT )
557 {
558 if( m_newColor4D.m_text )
559 m_colorValue->ChangeValue( *m_newColor4D.m_text );
560 else
561 m_colorValue->ChangeValue( m_newColor4D.ToHexString() );
562 }
563 else if( aChanged != HEX_CHANGED )
564 {
565 m_newColor4D.m_text = nullptr;
566 m_colorValue->ChangeValue( m_newColor4D.ToHexString() );
567 }
568}
569
570
572{
573 m_cursorsSize = ToPhys( FromDIP( 8 ) ); // Size of square cursors drawn on color bitmaps
574}
575
576
578{
580 m_NewColorRect->Freeze(); // Avoid flicker
581 m_HsvBitmap->Freeze();
582 m_RgbBitmap->Freeze();
586 m_NewColorRect->Thaw();
587 m_HsvBitmap->Thaw();
588 m_RgbBitmap->Thaw();
589 m_NewColorRect->Refresh();
590 m_HsvBitmap->Refresh();
591 m_RgbBitmap->Refresh();
592}
593
594
595void DIALOG_COLOR_PICKER::colorDClick( wxMouseEvent& event )
596{
597 wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
598}
599
600
601void DIALOG_COLOR_PICKER::buttColorClick( wxMouseEvent& event )
602{
603 int id = event.GetId();
604 COLOR4D color( m_Color4DList[id - ID_COLOR_BLACK] );
605 m_newColor4D.r = color.r;
606 m_newColor4D.g = color.g;
607 m_newColor4D.b = color.b;
608 m_newColor4D.a = color.a;
609
610 m_newColor4D.ToHSV( m_hue, m_sat, m_val, true );
611 SetEditVals( ALL_CHANGED, false );
612
613 drawAll();
614
615 event.Skip();
616}
617
618
619void DIALOG_COLOR_PICKER::onRGBMouseClick( wxMouseEvent& event )
620{
621 m_allowMouseEvents = true;
622
623 // The cursor position is relative to the m_bitmapHSV wxBitmap center
624 wxPoint mousePos = ToPhys( event.GetPosition() );
625 wxSize bmsize = m_bitmapRGB->GetSize();
626 int half_size = std::min( bmsize.x, bmsize.y ) / 2;
627
628 mousePos.x -= half_size;
629 mousePos.y -= half_size;
630 mousePos.y = -mousePos.y; // Use the bottom to top vertical axis
631
632 wxPoint dist = m_cursorBitmapRed - mousePos;
633
634 if( std::abs( dist.x ) <= m_cursorsSize/2 && std::abs( dist.y ) <= m_cursorsSize/2 )
635 {
637 return;
638 }
639
640 dist = m_cursorBitmapGreen - mousePos;
641
642 if( std::abs( dist.x ) <= m_cursorsSize / 2 && std::abs( dist.y ) <= m_cursorsSize / 2 )
643 {
645 return;
646 }
647
648 dist = m_cursorBitmapBlue - mousePos;
649
650 if( std::abs( dist.x ) <= m_cursorsSize / 2 && std::abs( dist.y ) <= m_cursorsSize / 2 )
651 {
653 return;
654 }
655
656 m_selectedCursor = nullptr;
657}
658
659
660void DIALOG_COLOR_PICKER::onRGBMouseDrag( wxMouseEvent& event )
661{
662 if( !event.Dragging() || !m_allowMouseEvents )
663 {
664 m_selectedCursor = nullptr;
665 return;
666 }
667
671 {
672 return;
673 }
674
675 // Adjust the HSV cursor position to follow the mouse cursor
676 // The cursor position is relative to the m_bitmapHSV wxBitmap center
677 wxPoint mousePos = ToPhys( event.GetPosition() );
678 wxSize bmsize = m_bitmapRGB->GetSize();
679 int half_size = std::min( bmsize.x, bmsize.y ) / 2;
680
681 mousePos.x -= half_size;
682 mousePos.y -= half_size;
683 mousePos.y = -mousePos.y; // Use the bottom to top vertical axis
684
685 half_size -= m_cursorsSize / 2; // the actual half_size of the palette area
686
687 // Change colors according to the selected cursor:
689 {
690 if( mousePos.y >= 0 && mousePos.y <= half_size )
691 m_newColor4D.r = (double)mousePos.y / half_size;
692 else
693 return;
694 }
695
697 {
698 mousePos.x = -mousePos.x;
699
700 if( mousePos.x >= 0 && mousePos.x <= half_size )
701 m_newColor4D.g = (double)mousePos.x / half_size;
702 else
703 return;
704 }
705
707 {
708 if( mousePos.x >= 0 && mousePos.x <= half_size )
709 m_newColor4D.b = (double)mousePos.x / half_size;
710 else
711 return;
712 }
713
714 m_newColor4D.ToHSV( m_hue, m_sat, m_val, true );
715 SetEditVals( ALL_CHANGED, true );
716
717 drawAll();
718}
719
720
721void DIALOG_COLOR_PICKER::onHSVMouseClick( wxMouseEvent& event )
722{
723 m_allowMouseEvents = true;
724
725 if( setHSvaluesFromCursor( event.GetPosition() ) )
726 drawAll();
727}
728
729
730void DIALOG_COLOR_PICKER::onHSVMouseDrag( wxMouseEvent& event )
731{
732 if( !event.Dragging() || !m_allowMouseEvents )
733 return;
734
735 if( setHSvaluesFromCursor( event.GetPosition() ) )
736 drawAll();
737}
738
739
740void DIALOG_COLOR_PICKER::onSize( wxSizeEvent& event )
741{
742 drawAll();
743
744 event.Skip();
745}
746
747
748void DIALOG_COLOR_PICKER::OnColorValueText( wxCommandEvent& event )
749{
750 if( m_newColor4D.SetFromHexString( m_colorValue->GetValue() ) )
751 m_newColor4D.ToHSV( m_hue, m_sat, m_val, true );
752
753 SetEditVals( HEX_CHANGED, false );
754 drawAll();
755}
756
757
758bool DIALOG_COLOR_PICKER::setHSvaluesFromCursor( const wxPoint& aMouseCursor )
759{
760 wxPoint mousePos = ToPhys( aMouseCursor );
761 wxSize bmsize = m_bitmapHSV->GetSize();
762 int half_size = std::min( bmsize.x, bmsize.y ) / 2;
763
764 // Make the cursor position relative to the m_bitmapHSV wxBitmap center
765 mousePos.x -= half_size;
766 mousePos.y -= half_size;
767 mousePos.y = -mousePos.y; // Use the bottom to top vertical axis
768
769 // The HS cursor position is restricted to a circle of radius half_size
770 double dist_from_centre = hypot( (double)mousePos.x, (double)mousePos.y );
771
772 if( dist_from_centre > half_size )
773 {
774 // Saturation cannot be calculated:
775 return false;
776 }
777
778 m_cursorBitmapHSV = mousePos;
779
780 // Set saturation and hue from new cursor position:
781 half_size -= m_cursorsSize / 2; // the actual half_size of the palette area
782 m_sat = dist_from_centre / half_size;
783
784 if( m_sat > 1.0 )
785 m_sat = 1.0;
786
787 m_hue = atan2( mousePos.y, mousePos.x ) / M_PI * 180.0;
788
789 if( m_hue < 0 )
790 m_hue += 360.0;
791
792 m_newColor4D.FromHSV( m_hue, m_sat, m_val );
793 SetEditVals( ALL_CHANGED, true );
794
795 return true;
796}
797
798
799void DIALOG_COLOR_PICKER::OnChangeAlpha( wxScrollEvent& event )
800{
801 double alpha = (double)event.GetPosition() / ALPHA_MAX;
802 m_newColor4D.a = alpha;
803 m_NewColorRect->Freeze(); // Avoid flicker
805 m_NewColorRect->Thaw();
806 m_NewColorRect->Refresh();
807 SetEditVals( ALPHA_CHANGED, false );
808}
809
810
811void DIALOG_COLOR_PICKER::OnChangeEditRed( wxSpinEvent& event )
812{
813 double val = (double)event.GetPosition() / 255.0;
814 m_newColor4D.r = val;
815 SetEditVals( RED_CHANGED, true );
816
817 drawAll();
818}
819
820
822{
823 double val = (double)event.GetPosition() / 255.0;
824 m_newColor4D.g = val;
825 SetEditVals( GREEN_CHANGED, true );
826
827 drawAll();
828}
829
830
832{
833 double val = (double)event.GetPosition() / 255.0;
834 m_newColor4D.b = val;
835 SetEditVals( BLUE_CHANGED, true );
836
837 drawAll();
838}
839
840
841void DIALOG_COLOR_PICKER::OnChangeEditHue( wxSpinEvent& event )
842{
843 m_hue = (double)event.GetPosition();
844
845 m_newColor4D.FromHSV( m_hue, m_sat, m_val );
846
847 SetEditVals( HUE_CHANGED, true );
848
849 drawAll();
850}
851
852
853void DIALOG_COLOR_PICKER::OnChangeEditSat( wxSpinEvent& event )
854{
855 m_sat = (double)event.GetPosition() / 255.0;
856
857 m_newColor4D.FromHSV( m_hue, m_sat, m_val );
858
859 SetEditVals( SAT_CHANGED, true );
860
861 drawAll();
862}
863
864
865void DIALOG_COLOR_PICKER::OnChangeBrightness( wxScrollEvent& event )
866{
867 m_val = (double)event.GetPosition() / 255.0;
868
869 m_newColor4D.FromHSV( m_hue, m_sat, m_val );
870
871 SetEditVals( VAL_CHANGED, true );
872
873 drawAll();
874}
875
876
877void DIALOG_COLOR_PICKER::OnResetButton( wxCommandEvent& aEvent )
878{
883
884 m_newColor4D.ToHSV( m_hue, m_sat, m_val, true );
885 SetEditVals( ALL_CHANGED, false );
886
887 drawAll();
888}
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
APP_SETTINGS_BASE is a settings class that should be derived for each standalone KiCad application.
COLOR_PICKER m_ColorPicker
static const COLOR4D WHITE
Definition color4d.h:402
static const COLOR4D UNSPECIFIED
For legacy support; used as a value to indicate color hasn't been set yet.
Definition color4d.h:399
static wxBitmap MakeBitmap(const KIGFX::COLOR4D &aColor, const KIGFX::COLOR4D &aBackground, const wxSize &aSize, const wxSize &aCheckerboardSize, const KIGFX::COLOR4D &aCheckerboardBackground, const std::vector< int > &aMargins={ 0, 0, 0, 0 })
DIALOG_COLOR_PICKER_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &title=_("Color Picker"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
KIGFX::COLOR4D m_previousColor4D
the initial color4d
void buttColorClick(wxMouseEvent &event)
Event handler for double click on color buttons.
void OnResetButton(wxCommandEvent &aEvent) override
void colorDClick(wxMouseEvent &event)
called when creating the dialog
void OnChangeAlpha(wxScrollEvent &event) override
Event handlers from wxSpinControl.
void onRGBMouseDrag(wxMouseEvent &event) override
wxPoint m_cursorBitmapGreen
the green cursor on the RGB bitmap palette.
KIGFX::COLOR4D m_newColor4D
the current color4d
double m_val
the current value (0 ... 1.0)
void OnChangeEditGreen(wxSpinEvent &event) override
void createRGBBitmap()
generate the bitmap that shows the RVB color space
std::vector< wxStaticBitmap * > m_colorSwatches
list of defined colors buttons
wxBitmap * m_bitmapRGB
the basic RGB palette
void OnChangeEditBlue(wxSpinEvent &event) override
wxPoint m_cursorBitmapBlue
the blue cursor on the RGB bitmap palette.
DIALOG_COLOR_PICKER(wxWindow *aParent, const KIGFX::COLOR4D &aCurrentColor, bool aAllowOpacityControl, std::vector< CUSTOM_COLOR_ITEM > *aUserColors=nullptr, const KIGFX::COLOR4D &aDefaultColor=KIGFX::COLOR4D::UNSPECIFIED)
Dialog constructor.
wxBitmap * m_bitmapHSV
the basic HUV palette
void OnColorValueText(wxCommandEvent &event) override
Event handler for the reset button press.
void createHSVBitmap()
generate the bitmap that shows the HSV color circle
std::vector< KIGFX::COLOR4D > m_Color4DList
the list of color4d ordered by button ID, for predefined colors
void onRGBMouseClick(wxMouseEvent &event) override
wxPoint m_cursorBitmapRed
the red cursor on the RGB bitmap palette.
double m_hue
the current hue, in degrees (0 ... 360)
bool setHSvaluesFromCursor(const wxPoint &aMouseCursor)
Manage the Hue and Saturation settings when the mouse cursor is at aMouseCursor.
void OnChangeEditSat(wxSpinEvent &event) override
mouse handlers, when clicking on a palette bitmap
double m_sat
the current saturation (0 ... 1.0)
bool m_allowOpacityCtrl
true to show the widget, false to keep alpha channel = 1.0
bool TransferDataToWindow() override
void drawHSVPalette()
draws the HSV color circle
void onHSVMouseClick(wxMouseEvent &event) override
void onHSVMouseDrag(wxMouseEvent &event) override
void updatePreview(wxStaticBitmap *aStaticBitmap, KIGFX::COLOR4D &aColor4D)
Event handler from wxSlider: brightness (value) control.
void onSize(wxSizeEvent &event) override
KIGFX::COLOR4D m_defaultColor
The default color4d.
void initDefinedColors(std::vector< CUSTOM_COLOR_ITEM > *aPredefinedColors)
Create the bitmap buttons for each defined colors.
void OnChangeEditRed(wxSpinEvent &event) override
void OnChangeEditHue(wxSpinEvent &event) override
int normalizeToInt(double aValue, int aValMax=255)
void SetEditVals(CHANGED_COLOR aChanged, bool aCheckTransparency)
wxPoint m_cursorBitmapHSV
the cursor on the HSV bitmap palette.
void drawRGBPalette()
draws the RVB color space
void OnChangeBrightness(wxScrollEvent &event) override
Event handler from wxSlider: alpha (transparency) control.
wxPoint * m_selectedCursor
the ref cursor to the selected cursor, if any, or null.
void SetupStandardButtons(std::map< int, wxString > aLabels={})
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
APP_SETTINGS_BASE * KifaceSettings() const
Definition kiface_base.h:91
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:101
double r
Red component.
Definition color4d.h:390
double g
Green component.
Definition color4d.h:391
void FromHSV(double aInH, double aInS, double aInV)
Changes currently used color to the one given by hue, saturation and value parameters.
Definition color4d.cpp:439
double a
Alpha component.
Definition color4d.h:393
double b
Blue component.
Definition color4d.h:392
const StructColors * colorRefs()
Global list of legacy color names, still used all over the place for constructing COLOR4D's.
Definition color4d.cpp:36
@ NBCOLORS
Number of colors.
Definition color4d.h:75
static const wxSize SWATCH_SIZE_LARGE_DU(24, 16)
static const wxSize CHECKERBOARD_SIZE_DU(3, 3)
#define SLOPE_AXIS
#define ID_COLOR_BLACK
void configureSpinCtrl(wxSpinCtrl *aCtrl)
#define ALPHA_MAX
#define MAPX(xx)
#define MAPY(yy)
@ VAL_CHANGED
@ HUE_CHANGED
@ HEX_CHANGED
@ RED_CHANGED
@ ALL_CHANGED
@ ALPHA_CHANGED
@ GREEN_CHANGED
@ SAT_CHANGED
@ BLUE_CHANGED
#define _(s)
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:411
A class to handle a custom color (predefined color) for the color picker dialog.
#define M_PI