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