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 (C) 2018-2024 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 along
17 * with this program. If not, see <http://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,
48 bool aAllowOpacityControl,
49 CUSTOM_COLORS_LIST* aUserColors,
50 const COLOR4D& aDefaultColor ) :
52{
53 m_allowMouseEvents = false;
54 m_allowOpacityCtrl = aAllowOpacityControl;
55 m_previousColor4D = aCurrentColor;
56 m_newColor4D = aCurrentColor;
58 m_bitmapRGB = nullptr;
59 m_bitmapHSV = nullptr;
60 m_selectedCursor = nullptr;
61 m_defaultColor = aDefaultColor;
62
64
65 m_OldColorRect->SetMinSize( FromDIP( wxSize( 20, 20 ) ) );
66 m_NewColorRect->SetMinSize( FromDIP( wxSize( 20, 20 ) ) );
67
68 m_colorValue->SetMinSize( wxSize( GetTextExtent( wxS( "#DDDDDDDD" ) ).x + FromDIP( 8 ), -1 ) );
69
71 {
72 m_SizerTransparency->Show( false );
73
74 if( aCurrentColor != COLOR4D::UNSPECIFIED )
75 {
76 m_previousColor4D.a = 1.0;
77 m_newColor4D.a = 1.0;
78 }
79 }
80
81 // UNSPECIFIED is ( 0, 0, 0, 0 ) but that is unfriendly for editing because you have to notice
82 // first that the value slider is all the way down before you get any color
83 if( aCurrentColor == COLOR4D::UNSPECIFIED )
84 m_val = 1.0;
85
87 wxASSERT( cfg );
88
89 m_notebook->SetSelection( cfg->m_ColorPicker.default_tab );
90
91 // Build the defined colors panel:
92 initDefinedColors( aUserColors );
93
101 if( aDefaultColor == COLOR4D::UNSPECIFIED )
102 m_resetToDefault->SetLabel( _( "Clear Color" ) );
103
105}
106
107
109{
111 wxASSERT( cfg );
112
113 cfg->m_ColorPicker.default_tab = m_notebook->GetSelection();
114
115 delete m_bitmapRGB;
116 delete m_bitmapHSV;
117
118 for( wxStaticBitmap* swatch : m_colorSwatches )
119 {
120 swatch->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED,
121 wxMouseEventHandler( DIALOG_COLOR_PICKER::buttColorClick ),
122 nullptr, this );
123 }
124}
125
126
127void DIALOG_COLOR_PICKER::updatePreview( wxStaticBitmap* aStaticBitmap, COLOR4D& aColor4D )
128{
129 wxSize swatchSize = aStaticBitmap->GetSize();
130 wxSize checkerboardSize = ConvertDialogToPixels( CHECKERBOARD_SIZE_DU );
131
132 wxBitmap newBm = COLOR_SWATCH::MakeBitmap( aColor4D, COLOR4D::WHITE,
133 ToPhys( swatchSize ),
134 ToPhys( checkerboardSize ),
135 aStaticBitmap->GetParent()->GetBackgroundColour() );
136
137 newBm.SetScaleFactor( GetDPIScaleFactor() );
138 aStaticBitmap->SetBitmap( newBm );
139}
140
141
143{
144 SetEditVals( ALL_CHANGED, false );
145
146 // Configure the spin control sizes
152
153 m_notebook->GetPage( 0 )->Layout();
154 m_notebook->GetPage( 1 )->Layout();
155
157
158 // Draw all bitmaps, with colors according to the color 4D
160 drawAll();
161
162 return true;
163}
164
165
167{
168 #define ID_COLOR_BLACK 2000 // colors_id = ID_COLOR_BLACK a ID_COLOR_BLACK + NBCOLORS-1
169
170 // Colors are built from the colorRefs() table (size NBCOLORS).
171 // The look is better when colorRefs() order is displayed in a grid matrix
172 // of 7 row and 5 columns, first filling a row, and after the next column.
173 // But the wxFlexGrid used here must be filled by columns, then next row
174 // the best interval colorRefs() from a matrix row to the next row is 6
175 // So when have to reorder the index used to explore colorRefs()
176 int grid_col = 0;
177 int grid_row = 0;
178 int table_row_count = 7;
179
180 wxSize swatchSize = ConvertDialogToPixels( SWATCH_SIZE_LARGE_DU );
181 wxSize checkerboardSize = ConvertDialogToPixels( CHECKERBOARD_SIZE_DU );
182 COLOR4D checkboardBackground = m_OldColorRect->GetParent()->GetBackgroundColour();
183
184 auto addSwatch =
185 [&]( int aId, COLOR4D aColor, const wxString& aColorName )
186 {
187 wxBitmap bm = COLOR_SWATCH::MakeBitmap( aColor, COLOR4D::WHITE,
188 ToPhys( swatchSize ),
189 ToPhys( checkerboardSize ),
190 checkboardBackground );
191
192 bm.SetScaleFactor( GetDPIScaleFactor() );
193 wxStaticBitmap* swatch = new wxStaticBitmap( m_panelDefinedColors, aId, bm );
194
195 m_fgridColor->Add( swatch, 0, wxALIGN_CENTER_VERTICAL, 5 );
196
197 wxStaticText* label = new wxStaticText( m_panelDefinedColors, wxID_ANY, aColorName,
198 wxDefaultPosition, wxDefaultSize, 0 );
199 m_fgridColor->Add( label, 1, wxALIGN_CENTER_VERTICAL | wxRIGHT, 15 );
200
201 m_colorSwatches.push_back( swatch );
202
203 swatch->Connect( wxEVT_LEFT_DOWN,
204 wxMouseEventHandler( DIALOG_COLOR_PICKER::buttColorClick ),
205 nullptr, this );
206 swatch->Connect( wxEVT_LEFT_DCLICK,
207 wxMouseEventHandler( DIALOG_COLOR_PICKER::colorDClick ),
208 nullptr, this );
209 };
210
211 // If no predefined list is given, build the default predefined colors:
212 if( aPredefinedColors )
213 {
214 for( unsigned jj = 0; jj < aPredefinedColors->size() && jj < NBCOLORS; ++jj )
215 {
216 CUSTOM_COLOR_ITEM* item = & *aPredefinedColors->begin() + jj;
217 int butt_ID = ID_COLOR_BLACK + jj;
218
219 addSwatch( butt_ID, item->m_Color, item->m_ColorName );
220 m_Color4DList.push_back( item->m_Color );
221 }
222 }
223 else
224 {
225 m_Color4DList.assign( NBCOLORS, COLOR4D( 0.0, 0.0, 0.0, 1.0 ) );
226
227 for( int jj = 0; jj < NBCOLORS; ++jj, grid_col++ )
228 {
229 if( grid_col * table_row_count >= NBCOLORS )
230 {
231 // the current grid row is filled, and we must fill the next grid row
232 grid_col = 0;
233 grid_row++;
234 }
235
236 int ii = grid_row + ( grid_col * table_row_count ); // The index in colorRefs()
237 int butt_ID = ID_COLOR_BLACK + ii;
238 COLOR4D buttcolor = COLOR4D( colorRefs()[ii].m_Numcolor );
239
240 addSwatch( butt_ID, buttcolor, wxGetTranslation( colorRefs()[ii].m_ColorName ) );
241 m_Color4DList[ butt_ID - ID_COLOR_BLACK ] = buttcolor;
242 }
243 }
244}
245
246
248{
249 wxSize bmsize = ToPhys( m_RgbBitmap->GetSize() );
250 int half_size = std::min( bmsize.x, bmsize.y )/2;
251
252 // We use here a Y axis from bottom to top and origin to center, So we need to map
253 // coordinated to write pixel in a wxImage. MAPX and MAPY are defined above so they
254 // must be undefined here to prevent compiler warnings.
255#undef MAPX
256#undef MAPY
257#define MAPX( xx ) bmsize.x / 2 + ( xx )
258#define MAPY( yy ) bmsize.y / 2 - ( yy )
259
260 // Reserve room to draw cursors inside the bitmap
261 half_size -= m_cursorsSize/2;
262
264
265 // Red blue area in X Z 3d axis
266 double inc = 255.0 / half_size;
267 double slope = SLOPE_AXIS/half_size;
268 color.g = 0.0;
269
270 wxImage img( bmsize ); // a temporary buffer to build the color map
271
272 // clear background (set the window bg color)
273 wxColor bg = GetBackgroundColour();
274
275 // Don't do standard-color lookups on OSX each time through the loop
276 wxColourBase::ChannelType bgR = bg.Red();
277 wxColourBase::ChannelType bgG = bg.Green();
278 wxColourBase::ChannelType bgB = bg.Blue();
279
280 for( int xx = 0; xx < bmsize.x; xx++ ) // blue axis
281 {
282 for( int yy = 0; yy < bmsize.y; yy++ ) // Red axis
283 img.SetRGB( xx, yy, bgR, bgG, bgB );
284 }
285
286 // Build the palette
287 for( int xx = 0; xx < half_size; xx++ ) // blue axis
288 {
289 color.b = inc * xx;
290
291 for( int yy = 0; yy < half_size; yy++ ) // Red axis
292 {
293 color.r = inc * yy;
294 img.SetRGB( MAPX( xx ), MAPY( yy - (slope*xx) ), color.r, color.g, color.b );
295 }
296 }
297
298 // Red green area in y Z 3d axis
299 color.b = 0.0;
300
301 for( int xx = 0; xx < half_size; xx++ ) // green axis
302 {
303 color.g = inc * xx;
304
305 for( int yy = 0; yy < half_size; yy++ ) // Red axis
306 {
307 color.r = inc * yy;
308 img.SetRGB( MAPX( -xx ), MAPY( yy - (slope*xx) ), color.r, color.g, color.b );
309 }
310 }
311
312 // Blue green area in x y 3d axis
313 color.r = 0.0;
314
315 for( int xx = 0; xx < half_size; xx++ ) // green axis
316 {
317 color.g = inc * xx;
318
319 for( int yy = 0; yy < half_size; yy++ ) // blue axis
320 {
321 color.b = inc * yy;
322
323 // Mapping the xx, yy color axis to draw coordinates is more tricky than previously
324 // in DC coordinates:
325 // the blue axis is the (0, 0) to half_size, (-yy - SLOPE_AXIS)
326 // the green axis is the (0, 0) to - half_size, (-yy - SLOPE_AXIS)
327 int drawX = -xx + yy;
328 int drawY = - std::min( xx,yy ) * 0.9;
329 img.SetRGB( MAPX( drawX ), MAPY( drawY - std::abs( slope*drawX ) ),
330 color.r, color.g, color.b );
331 }
332 }
333
334 delete m_bitmapRGB;
335 m_bitmapRGB = new wxBitmap( img, 24 );
336
337 m_bitmapRGB->SetScaleFactor( GetDPIScaleFactor() );
338 m_RgbBitmap->SetBitmap( *m_bitmapRGB );
339}
340
341
343{
344 wxSize bmsize = ToPhys( m_HsvBitmap->GetSize() );
345 int half_size = std::min( bmsize.x, bmsize.y )/2;
346
347 // We use here a Y axis from bottom to top and origin to center, So we need to map
348 // coordinated to write pixel in a wxImage
349 #define MAPX( xx ) bmsize.x / 2 + ( xx )
350 #define MAPY( yy ) bmsize.y / 2 - ( yy )
351
352 wxImage img( bmsize ); // a temporary buffer to build the color map
353
354 // clear background (set the window bg color)
355 wxColor bg = GetBackgroundColour();
356
357 // Don't do standard-color lookups on OSX each time through the loop
358 wxColourBase::ChannelType bgR = bg.Red();
359 wxColourBase::ChannelType bgG = bg.Green();
360 wxColourBase::ChannelType bgB = bg.Blue();
361
362 for( int xx = 0; xx < bmsize.x; xx++ ) // blue axis
363 {
364 for( int yy = 0; yy < bmsize.y; yy++ ) // Red axis
365 img.SetRGB( xx, yy, bgR, bgG, bgB );
366 }
367
368 // Reserve room to draw cursors inside the bitmap
369 half_size -= m_cursorsSize/2;
370
371 double hue, sat;
373 int sq_radius = half_size*half_size;
374
375 // Build the palette
376 for( int xx = -half_size; xx < half_size; xx++ )
377 {
378 for( int yy = -half_size; yy < half_size; yy++ )
379 {
380 sat = double(xx*xx + yy*yy) / sq_radius;
381
382 // sat is <= 1.0
383 // any value > 1.0 is not a valid HSB color:
384 if( sat > 1.0 )
385 continue;
386
387 // sat is the distance from center
388 sat = sqrt( sat );
389 hue = atan2( (double)yy, (double)xx ) * 180 / M_PI;
390
391 if( hue < 0.0 )
392 hue += 360.0;
393
394 color.FromHSV( hue, sat, 1.0 );
395
396 img.SetRGB( MAPX( xx ), MAPY( yy ), color.r*255, color.g*255, color.b*255 );
397 }
398 }
399
400 delete m_bitmapHSV;
401 m_bitmapHSV = new wxBitmap( img, 24 );
402
403 m_bitmapHSV->SetScaleFactor( GetDPIScaleFactor() );
404 m_HsvBitmap->SetBitmap( *m_bitmapHSV );
405}
406
407
409{
410 if( !m_bitmapRGB || m_bitmapRGB->GetSize() != ToPhys( m_RgbBitmap->GetSize() ) )
412
413 wxMemoryDC bitmapDC;
414 wxSize bmsize = m_bitmapRGB->GetSize();
415 int half_size = std::min( bmsize.x, bmsize.y ) / 2;
416
417 wxBitmap newBm( *m_bitmapRGB );
418 newBm.SetScaleFactor( 1.0 );
419
420 bitmapDC.SelectObject( newBm );
421
422 // Use Y axis from bottom to top and origin to center
423 bitmapDC.SetAxisOrientation( true, true );
424#if defined( __WXMSW__)
425 // For some reason, SetDeviceOrigin has changed in wxWidgets 3.1.6 or 3.1.7
426 bitmapDC.SetDeviceOrigin( half_size, -half_size );
427#else
428 bitmapDC.SetDeviceOrigin( half_size, half_size );
429#endif
430
431 // Reserve room to draw cursors inside the bitmap
432 half_size -= m_cursorsSize/2;
433
434 // Draw the 3 RGB cursors, using white color to make them always visible:
435 wxPen pen( wxColor( 255, 255, 255 ), 2 ); // use 2 pixels for pen size
436 wxBrush brush( wxColor( 0, 0, 0 ), wxBRUSHSTYLE_TRANSPARENT );
437 bitmapDC.SetPen( pen );
438 bitmapDC.SetBrush( brush );
439 int half_csize = m_cursorsSize / 2;
440
441 double slope = SLOPE_AXIS / half_size;
442
443 // Red axis cursor (Z 3Daxis):
444 m_cursorBitmapRed.x = 0;
445 m_cursorBitmapRed.y = m_newColor4D.r * half_size;
446 bitmapDC.DrawRectangle( m_cursorBitmapRed.x - half_csize,
447 m_cursorBitmapRed.y - half_csize,
449
450 // Blue axis cursor (X 3Daxis):
451 m_cursorBitmapBlue.x = m_newColor4D.b * half_size;
453 bitmapDC.DrawRectangle( m_cursorBitmapBlue.x - half_csize,
454 m_cursorBitmapBlue.y - half_csize,
456
457 // Green axis cursor (Y 3Daxis):
458 m_cursorBitmapGreen.x = m_newColor4D.g * half_size;
461
462 bitmapDC.DrawRectangle( m_cursorBitmapGreen.x - half_csize,
463 m_cursorBitmapGreen.y - half_csize,
465
466 // Draw the 3 RGB axis:
467 half_size += half_size/5;
468 bitmapDC.DrawLine( 0, 0, 0, half_size ); // Red axis (Z 3D axis)
469 bitmapDC.DrawLine( 0, 0, half_size, - half_size*slope ); // Blue axis (X 3D axis)
470 bitmapDC.DrawLine( 0, 0, -half_size, - half_size*slope ); // green axis (Y 3D axis)
471
472 newBm.SetScaleFactor( GetDPIScaleFactor() );
473 m_RgbBitmap->SetBitmap( newBm );
474
475 /* Deselect the Tool Bitmap from DC,
476 * in order to delete the MemoryDC safely without deleting the bitmap */
477 bitmapDC.SelectObject( wxNullBitmap );
478}
479
480
482{
483 if( !m_bitmapHSV || m_bitmapHSV->GetSize() != ToPhys( m_HsvBitmap->GetSize() ) )
485
486 wxMemoryDC bitmapDC;
487 wxSize bmsize = m_bitmapHSV->GetSize();
488 int half_size = std::min( bmsize.x, bmsize.y ) / 2;
489
490 wxBitmap newBm( *m_bitmapHSV );
491 newBm.SetScaleFactor( 1.0 );
492
493 bitmapDC.SelectObject( newBm );
494
495 // Use Y axis from bottom to top and origin to center
496 bitmapDC.SetAxisOrientation( true, true );
497#if defined( __WXMSW__)
498 // For some reason, SetDeviceOrigin has changed in wxWidgets 3.1.6 or 3.1.7
499 bitmapDC.SetDeviceOrigin( half_size, -half_size );
500#else
501 bitmapDC.SetDeviceOrigin( half_size, half_size );
502#endif
503
504 // Reserve room to draw cursors inside the bitmap
505 half_size -= m_cursorsSize / 2;
506
507 // Draw the HSB cursor:
508 m_cursorBitmapHSV.x = cos( m_hue * M_PI / 180.0 ) * half_size * m_sat;
509 m_cursorBitmapHSV.y = sin( m_hue * M_PI / 180.0 ) * half_size * m_sat;
510
511 wxPen pen( wxColor( 0, 0, 0 ), 2 ); // Use 2 pixels as pensize
512 wxBrush brush( wxColor( 0, 0, 0 ), wxBRUSHSTYLE_TRANSPARENT );
513 bitmapDC.SetPen( pen );
514 bitmapDC.SetBrush( brush );
515
516 bitmapDC.DrawRectangle( m_cursorBitmapHSV.x - ( m_cursorsSize / 2 ),
519
520 newBm.SetScaleFactor( GetDPIScaleFactor() );
521 m_HsvBitmap->SetBitmap( newBm );
522
523 /* Deselect the Tool Bitmap from DC,
524 * in order to delete the MemoryDC safely without deleting the bitmap
525 */
526 bitmapDC.SelectObject( wxNullBitmap );
527}
528
529
530void DIALOG_COLOR_PICKER::SetEditVals( CHANGED_COLOR aChanged, bool aCheckTransparency )
531{
532 if( aCheckTransparency )
533 {
534 // If they've changed the color, they probably don't want it to remain 100% transparent,
535 // and it looks like a bug when changing the color has no effect.
536 if( m_newColor4D.a == 0.0 )
537 m_newColor4D.a = 1.0;
538 }
539
541
542 if( aChanged == RED_CHANGED || aChanged == GREEN_CHANGED || aChanged == BLUE_CHANGED )
544
545 if( aChanged != RED_CHANGED )
547
548 if( aChanged != GREEN_CHANGED )
550
551 if( aChanged != BLUE_CHANGED )
553
554 if( aChanged != HUE_CHANGED )
555 m_spinCtrlHue->SetValue( (int)m_hue );
556
557 if( aChanged != SAT_CHANGED )
558 m_spinCtrlSaturation->SetValue( m_sat * 255 );
559
560 if( aChanged != VAL_CHANGED )
562
563 if( aChanged == HEX_CHANGED )
565 else
566 m_colorValue->ChangeValue( m_newColor4D.ToHexString() );
567}
568
569
571{
572 m_cursorsSize = ToPhys( FromDIP( 8 ) ); // Size of square cursors drawn on color bitmaps
573}
574
575
577{
579 m_NewColorRect->Freeze(); // Avoid flicker
580 m_HsvBitmap->Freeze();
581 m_RgbBitmap->Freeze();
585 m_NewColorRect->Thaw();
586 m_HsvBitmap->Thaw();
587 m_RgbBitmap->Thaw();
588 m_NewColorRect->Refresh();
589 m_HsvBitmap->Refresh();
590 m_RgbBitmap->Refresh();
591}
592
593
594void DIALOG_COLOR_PICKER::colorDClick( wxMouseEvent& event )
595{
596 wxPostEvent( this, wxCommandEvent( wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK ) );
597}
598
599
600void DIALOG_COLOR_PICKER::buttColorClick( wxMouseEvent& event )
601{
602 int id = event.GetId();
604 m_newColor4D.r = color.r;
605 m_newColor4D.g = color.g;
606 m_newColor4D.b = color.b;
607 m_newColor4D.a = color.a;
608
610 SetEditVals( ALL_CHANGED, false );
611
612 drawAll();
613
614 event.Skip();
615}
616
617
618void DIALOG_COLOR_PICKER::onRGBMouseClick( wxMouseEvent& event )
619{
620 m_allowMouseEvents = true;
621
622 // The cursor position is relative to the m_bitmapHSV wxBitmap center
623 wxPoint mousePos = ToPhys( event.GetPosition() );
624 wxSize bmsize = m_bitmapRGB->GetSize();
625 int half_size = std::min( bmsize.x, bmsize.y ) / 2;
626
627 mousePos.x -= half_size;
628 mousePos.y -= half_size;
629 mousePos.y = -mousePos.y; // Use the bottom to top vertical axis
630
631 wxPoint dist = m_cursorBitmapRed - mousePos;
632
633 if( std::abs( dist.x ) <= m_cursorsSize/2 && std::abs( dist.y ) <= m_cursorsSize/2 )
634 {
636 return;
637 }
638
639 dist = m_cursorBitmapGreen - mousePos;
640
641 if( std::abs( dist.x ) <= m_cursorsSize/2 && std::abs( dist.y ) <= m_cursorsSize/2 )
642 {
644 return;
645 }
646
647 dist = m_cursorBitmapBlue - mousePos;
648
649 if( std::abs( dist.x ) <= m_cursorsSize/2 && std::abs( dist.y ) <= m_cursorsSize/2 )
650 {
652 return;
653 }
654
655 m_selectedCursor = nullptr;
656}
657
658
659void DIALOG_COLOR_PICKER::onRGBMouseDrag( wxMouseEvent& event )
660{
661 if( !event.Dragging() || !m_allowMouseEvents )
662 {
663 m_selectedCursor = nullptr;
664 return;
665 }
666
670 {
671 return;
672 }
673
674 // Adjust the HSV cursor position to follow the mouse cursor
675 // The cursor position is relative to the m_bitmapHSV wxBitmap center
676 wxPoint mousePos = ToPhys( event.GetPosition() );
677 wxSize bmsize = m_bitmapRGB->GetSize();
678 int half_size = std::min( bmsize.x, bmsize.y ) / 2;
679
680 mousePos.x -= half_size;
681 mousePos.y -= half_size;
682 mousePos.y = -mousePos.y; // Use the bottom to top vertical axis
683
684 half_size -= m_cursorsSize / 2; // the actual half_size of the palette area
685
686 // Change colors according to the selected cursor:
688 {
689 if( mousePos.y >= 0 && mousePos.y <= half_size )
690 m_newColor4D.r = (double)mousePos.y / half_size;
691 else
692 return;
693 }
694
696 {
697 mousePos.x = -mousePos.x;
698
699 if( mousePos.x >= 0 && mousePos.x <= half_size )
700 m_newColor4D.g = (double)mousePos.x / half_size;
701 else
702 return;
703 }
704
706 {
707 if( mousePos.x >= 0 && mousePos.x <= half_size )
708 m_newColor4D.b = (double)mousePos.x / half_size;
709 else
710 return;
711 }
712
714 SetEditVals( ALL_CHANGED, true );
715
716 drawAll();
717}
718
719
720void DIALOG_COLOR_PICKER::onHSVMouseClick( wxMouseEvent& event )
721{
722 m_allowMouseEvents = true;
723
724 if( setHSvaluesFromCursor( event.GetPosition() ) )
725 drawAll();
726}
727
728
729void DIALOG_COLOR_PICKER::onHSVMouseDrag( wxMouseEvent& event )
730{
731 if( !event.Dragging() || !m_allowMouseEvents )
732 return;
733
734 if( setHSvaluesFromCursor( event.GetPosition() ) )
735 drawAll();
736}
737
738
739void DIALOG_COLOR_PICKER::onSize( wxSizeEvent& event )
740{
741 drawAll();
742
743 event.Skip();
744}
745
746
747void DIALOG_COLOR_PICKER::OnColorValueText( wxCommandEvent& event )
748{
749 if( m_newColor4D.SetFromHexString( m_colorValue->GetValue() ) )
750 {
752
753 SetEditVals( HEX_CHANGED, false );
754 drawAll();
755 }
756}
757
758
759bool DIALOG_COLOR_PICKER::setHSvaluesFromCursor( const wxPoint& aMouseCursor )
760{
761 wxPoint mousePos = ToPhys( aMouseCursor );
762 wxSize bmsize = m_bitmapHSV->GetSize();
763 int half_size = std::min( bmsize.x, bmsize.y ) / 2;
764
765 // Make the cursor position relative to the m_bitmapHSV wxBitmap center
766 mousePos.x -= half_size;
767 mousePos.y -= half_size;
768 mousePos.y = -mousePos.y; // Use the bottom to top vertical axis
769
770 // The HS cursor position is restricted to a circle of radius half_size
771 double dist_from_centre = hypot( (double)mousePos.x, (double)mousePos.y );
772
773 if( dist_from_centre > half_size )
774 {
775 // Saturation cannot be calculated:
776 return false;
777 }
778
779 m_cursorBitmapHSV = mousePos;
780
781 // Set saturation and hue from new cursor position:
782 half_size -= m_cursorsSize / 2; // the actual half_size of the palette area
783 m_sat = dist_from_centre / half_size;
784
785 if( m_sat > 1.0 )
786 m_sat = 1.0;
787
788 m_hue = atan2( mousePos.y, mousePos.x ) / M_PI * 180.0;
789
790 if( m_hue < 0 )
791 m_hue += 360.0;
792
794 SetEditVals( ALL_CHANGED, true );
795
796 return true;
797}
798
799
800void DIALOG_COLOR_PICKER::OnChangeAlpha( wxScrollEvent& event )
801{
802 double alpha = (double)event.GetPosition() / ALPHA_MAX;
803 m_newColor4D.a = alpha;
804 m_NewColorRect->Freeze(); // Avoid flicker
806 m_NewColorRect->Thaw();
807 m_NewColorRect->Refresh();
808 SetEditVals( ALPHA_CHANGED, false );
809}
810
811
812void DIALOG_COLOR_PICKER::OnChangeEditRed( wxSpinEvent& event )
813{
814 double val = (double)event.GetPosition() / 255.0;
815 m_newColor4D.r = val;
816 SetEditVals( RED_CHANGED, true );
817
818 drawAll();
819}
820
821
823{
824 double val = (double)event.GetPosition() / 255.0;
825 m_newColor4D.g = val;
826 SetEditVals( GREEN_CHANGED, true );
827
828 drawAll();
829}
830
831
833{
834 double val = (double)event.GetPosition() / 255.0;
835 m_newColor4D.b = val;
836 SetEditVals( BLUE_CHANGED, true );
837
838 drawAll();
839}
840
841
842void DIALOG_COLOR_PICKER::OnChangeEditHue( wxSpinEvent& event )
843{
844 m_hue = (double)event.GetPosition();
845
847
848 SetEditVals( HUE_CHANGED, true );
849
850 drawAll();
851}
852
853
854void DIALOG_COLOR_PICKER::OnChangeEditSat( wxSpinEvent& event )
855{
856 m_sat = (double)event.GetPosition() / 255.0;
857
859
860 SetEditVals( SAT_CHANGED, true );
861
862 drawAll();
863}
864
865
866void DIALOG_COLOR_PICKER::OnChangeBrightness( wxScrollEvent& event )
867{
868 m_val = (double)event.GetPosition() / 255.0;
869
871
872 SetEditVals( VAL_CHANGED, true );
873
874 drawAll();
875}
876
877
878void DIALOG_COLOR_PICKER::OnResetButton( wxCommandEvent& aEvent )
879{
884
886 SetEditVals( ALL_CHANGED, false );
887
888 drawAll();
889}
int color
Definition: DXF_plotter.cpp:58
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
APP_SETTINGS_BASE is a settings class that should be derived for each standalone KiCad application.
Definition: app_settings.h:92
COLOR_PICKER m_ColorPicker
Definition: app_settings.h:164
static wxBitmap MakeBitmap(const KIGFX::COLOR4D &aColor, const KIGFX::COLOR4D &aBackground, const wxSize &aSize, const wxSize &aCheckerboardSize, const KIGFX::COLOR4D &aCheckerboardBackground)
Class DIALOG_COLOR_PICKER_BASE.
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 initDefinedColors(CUSTOM_COLORS_LIST *aPredefinedColors)
Create the bitmap buttons for each defined colors.
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
DIALOG_COLOR_PICKER(wxWindow *aParent, const KIGFX::COLOR4D &aCurrentColor, bool aAllowOpacityControl, CUSTOM_COLORS_LIST *aUserColors=nullptr, const KIGFX::COLOR4D &aDefaultColor=KIGFX::COLOR4D::UNSPECIFIED)
Dialog constructor.
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.
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 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:95
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
double r
Red component.
Definition: color4d.h:392
double g
Green component.
Definition: color4d.h:393
void ToHSV(double &aOutHue, double &aOutSaturation, double &aOutValue, bool aAlwaysDefineHue=false) const
Convert current color (stored in RGB) to HSV format.
Definition: color4d.cpp:368
bool SetFromHexString(const wxString &aColorString)
Definition: color4d.cpp:177
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:422
wxString ToHexString() const
Definition: color4d.cpp:210
double a
Alpha component.
Definition: color4d.h:395
double b
Blue component.
Definition: color4d.h:394
const StructColors * colorRefs()
Global list of legacy color names, still used all over the place for constructing COLOR4D's.
Definition: color4d.cpp:40
@ NBCOLORS
Number of colors.
Definition: color4d.h:79
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)
CHANGED_COLOR
@ VAL_CHANGED
@ HUE_CHANGED
@ HEX_CHANGED
@ RED_CHANGED
@ ALL_CHANGED
@ ALPHA_CHANGED
@ GREEN_CHANGED
@ SAT_CHANGED
@ BLUE_CHANGED
std::vector< CUSTOM_COLOR_ITEM > CUSTOM_COLORS_LIST
#define _(s)
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:390
A class to handle a custom color (predefined color) for the color picker dialog.
KIGFX::COLOR4D m_Color