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-2020 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_i.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  NULL, 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  NULL, this );
187  };
188 
189  // If no predefined list is given, build the default predefined colors:
190  if( aPredefinedColors )
191  {
192  for( unsigned jj = 0; jj < aPredefinedColors->size() && jj < NBCOLORS; ++jj )
193  {
194  CUSTOM_COLOR_ITEM* item = & *aPredefinedColors->begin() + jj;
195  int butt_ID = ID_COLOR_BLACK + jj;
196 
197  addSwatch( butt_ID, item->m_Color, item->m_ColorName );
198  m_Color4DList.push_back( item->m_Color );
199  }
200  }
201  else
202  {
203  m_Color4DList.assign( NBCOLORS, COLOR4D( 0.0, 0.0, 0.0, 1.0 ) );
204 
205  for( int jj = 0; jj < NBCOLORS; ++jj, grid_col++ )
206  {
207  if( grid_col * table_row_count >= NBCOLORS )
208  { // the current grid row is filled, and we must fill the next grid row
209  grid_col = 0;
210  grid_row++;
211  }
212 
213  int ii = grid_row + ( grid_col * table_row_count ); // The index in colorRefs()
214  int butt_ID = ID_COLOR_BLACK + ii;
215  COLOR4D buttcolor = COLOR4D( colorRefs()[ii].m_Numcolor );
216 
217  addSwatch( butt_ID, buttcolor, wxGetTranslation( colorRefs()[ii].m_ColorName ) );
218  m_Color4DList[ butt_ID - ID_COLOR_BLACK ] = buttcolor;
219  }
220  }
221 }
222 
223 
225 {
226  wxMemoryDC bitmapDC;
227  wxSize bmsize = m_RgbBitmap->GetSize();
228  int half_size = std::min( bmsize.x, bmsize.y )/2;
229  m_bitmapRGB = new wxBitmap( bmsize );
230  bitmapDC.SelectObject( *m_bitmapRGB );
231  wxPen pen;
232 
233  // clear background (set the window bg color)
234  wxBrush bgbrush( GetBackgroundColour() );
235  bitmapDC.SetBackground( bgbrush );
236  bitmapDC.Clear();
237 
238  // Use Y axis from bottom to top and origin to center
239  bitmapDC.SetAxisOrientation( true, true );
240  bitmapDC.SetDeviceOrigin( half_size, half_size );
241 
242  // Reserve room to draw cursors inside the bitmap
243  half_size -= m_cursorsSize/2;
244 
245  COLOR4D color;
246 
247  // Red blue area in X Z 3d axis
248  double inc = 1.0 / half_size;
249  #define SLOPE_AXIS 50.0
250  double slope = SLOPE_AXIS/half_size;
251  color.g = 0.0;
252 
253  for( int xx = 0; xx < half_size; xx++ ) // blue axis
254  {
255  color.b = inc * xx;
256 
257  for( int yy = 0; yy < half_size; yy++ ) // Red axis
258  {
259  color.r = inc * yy;
260 
261  pen.SetColour( color.ToColour() );
262  bitmapDC.SetPen( pen );
263  bitmapDC.DrawPoint( xx, yy - (slope*xx) );
264  }
265  }
266 
267  // Red green area in y Z 3d axis
268  color.b = 0.0;
269  for( int xx = 0; xx < half_size; xx++ ) // green axis
270  {
271  color.g = inc * xx;
272 
273  for( int yy = 0; yy < half_size; yy++ ) // Red axis
274  {
275  color.r = inc * yy;
276 
277  pen.SetColour( color.ToColour() );
278  bitmapDC.SetPen( pen );
279  bitmapDC.DrawPoint( -xx, yy - (slope*xx) );
280  }
281  }
282 
283  // Blue green area in x y 3d axis
284  color.r = 0.0;
285  for( int xx = 0; xx < half_size; xx++ ) // green axis
286  {
287  color.g = inc * xx;
288 
289  for( int yy = 0; yy < half_size; yy++ ) // blue axis
290  {
291  color.b = inc * yy;
292 
293  pen.SetColour( color.ToColour() );
294  bitmapDC.SetPen( pen );
295 
296  // Mapping the xx, yy color axis to draw coordinates is more tricky than previously
297  // in DC coordinates:
298  // the blue axis is the (0, 0) to half_size, (-yy - SLOPE_AXIS)
299  // the green axis is the (0, 0) to - half_size, (-yy - SLOPE_AXIS)
300  int drawX = -xx + yy;
301  int drawY = - std::min( xx,yy ) * 0.9;
302  bitmapDC.DrawPoint( drawX, drawY - std::abs( slope*drawX ) );
303  }
304  }
305 }
306 
307 
309 {
310  wxMemoryDC bitmapDC;
311  wxSize bmsize = m_HsvBitmap->GetSize();
312  int half_size = std::min( bmsize.x, bmsize.y )/2;
313  delete m_bitmapHSV;
314  m_bitmapHSV = new wxBitmap( bmsize );
315  bitmapDC.SelectObject( *m_bitmapHSV );
316  wxPen pen;
317 
318  // clear background (set the window bd color)
319  wxBrush bgbrush( GetBackgroundColour() );
320  bitmapDC.SetBackground( bgbrush );
321  bitmapDC.Clear();
322 
323  // Use Y axis from bottom to top and origin to center
324  bitmapDC.SetAxisOrientation( true, true );
325  bitmapDC.SetDeviceOrigin( half_size, half_size );
326 
327  // Reserve room to draw cursors inside the bitmap
328  half_size -= m_cursorsSize/2;
329 
330  double hue, sat;
331  COLOR4D color;
332  int sq_radius = half_size*half_size;
333 
334  for( int xx = -half_size; xx < half_size; xx++ )
335  {
336  for( int yy = -half_size; yy < half_size; yy++ )
337  {
338  sat = double(xx*xx + yy*yy) / sq_radius;
339 
340  // sat is <= 1.0
341  // any value > 1.0 is not a valid HSB color:
342  if( sat > 1.0 )
343  continue;
344 
345  // sat is the distance from center
346  sat = sqrt( sat );
347  hue = atan2( (double)yy, (double)xx ) * 180 / M_PI;
348 
349  if( hue < 0.0 )
350  hue += 360.0;
351 
352  color.FromHSV( hue, sat, 1.0 );
353 
354  pen.SetColour( color.ToColour() );
355  bitmapDC.SetPen( pen );
356  bitmapDC.DrawPoint( xx, yy );
357  }
358  }
359 
360  /* Deselect the Tool Bitmap from DC,
361  * in order to delete the MemoryDC safely without deleting the bitmap
362  */
363  bitmapDC.SelectObject( wxNullBitmap );
364 }
365 
366 
368 {
369  if( !m_bitmapRGB || m_bitmapRGB->GetSize() != m_RgbBitmap->GetSize() )
370  createRGBBitmap();
371 
372  wxMemoryDC bitmapDC;
373  wxSize bmsize = m_bitmapRGB->GetSize();
374  int half_size = std::min( bmsize.x, bmsize.y )/2;
375  wxBitmap newBm( *m_bitmapRGB );
376  bitmapDC.SelectObject( newBm );
377 
378  // Use Y axis from bottom to top and origin to center
379  bitmapDC.SetAxisOrientation( true, true );
380  bitmapDC.SetDeviceOrigin( half_size, half_size );
381 
382  // Reserve room to draw cursors inside the bitmap
383  half_size -= m_cursorsSize/2;
384 
385  // Draw the 3 RGB cursors, using white color to make them always visible:
386  wxPen pen( wxColor( 255, 255, 255 ) );
387  wxBrush brush( wxColor( 0, 0, 0 ), wxBRUSHSTYLE_TRANSPARENT );
388  bitmapDC.SetPen( pen );
389  bitmapDC.SetBrush( brush );
390  int half_csize = m_cursorsSize/2;
391 
392  #define SLOPE_AXIS 50.0
393  double slope = SLOPE_AXIS/half_size;
394 
395  // Red axis cursor (Z 3Daxis):
396  m_cursorBitmapRed.x = 0;
397  m_cursorBitmapRed.y = m_newColor4D.r * half_size;
398  bitmapDC.DrawRectangle( m_cursorBitmapRed.x - half_csize,
399  m_cursorBitmapRed.y - half_csize,
401 
402  // Blue axis cursor (X 3Daxis):
403  m_cursorBitmapBlue.x = m_newColor4D.b * half_size;
405  bitmapDC.DrawRectangle( m_cursorBitmapBlue.x - half_csize,
406  m_cursorBitmapBlue.y - half_csize,
408 
409  // Green axis cursor (Y 3Daxis):
410  m_cursorBitmapGreen.x = m_newColor4D.g * half_size;
413 
414  bitmapDC.DrawRectangle( m_cursorBitmapGreen.x - half_csize,
415  m_cursorBitmapGreen.y - half_csize,
417 
418  // Draw the 3 RGB axis:
419  half_size += half_size/5;
420  bitmapDC.DrawLine( 0, 0, 0, half_size ); // Red axis (Z 3D axis)
421  bitmapDC.DrawLine( 0, 0, half_size, - half_size*slope ); // Blue axis (X 3D axis)
422  bitmapDC.DrawLine( 0, 0, -half_size, - half_size*slope ); // green axis (Y 3D axis)
423 
424  m_RgbBitmap->SetBitmap( newBm );
425  /* Deselect the Tool Bitmap from DC,
426  * in order to delete the MemoryDC safely without deleting the bitmap */
427  bitmapDC.SelectObject( wxNullBitmap );
428 }
429 
430 
432 {
433  if( !m_bitmapHSV || m_bitmapHSV->GetSize() != m_HsvBitmap->GetSize() )
434  createHSVBitmap();
435 
436  wxMemoryDC bitmapDC;
437  wxSize bmsize = m_bitmapHSV->GetSize();
438  int half_size = std::min( bmsize.x, bmsize.y )/2;
439  wxBitmap newBm( *m_bitmapHSV );
440  bitmapDC.SelectObject( newBm );
441 
442  // Use Y axis from bottom to top and origin to center
443  bitmapDC.SetAxisOrientation( true, true );
444  bitmapDC.SetDeviceOrigin( half_size, half_size );
445 
446  // Reserve room to draw cursors inside the bitmap
447  half_size -= m_cursorsSize/2;
448 
449  // Draw the HSB cursor:
450  m_cursorBitmapHSV.x = cos( m_hue * M_PI / 180.0 ) * half_size * m_sat;
451  m_cursorBitmapHSV.y = sin( m_hue * M_PI / 180.0 ) * half_size * m_sat;
452 
453  wxPen pen( wxColor( 0, 0, 0 ) );
454  wxBrush brush( wxColor( 0, 0, 0 ), wxBRUSHSTYLE_TRANSPARENT );
455  bitmapDC.SetPen( pen );
456  bitmapDC.SetBrush( brush );
457 
458  int half_csize = m_cursorsSize/2;
459  bitmapDC.DrawRectangle( m_cursorBitmapHSV.x- half_csize,
460  m_cursorBitmapHSV.y-half_csize,
462 
463  m_HsvBitmap->SetBitmap( newBm );
464  /* Deselect the Tool Bitmap from DC,
465  * in order to delete the MemoryDC safely without deleting the bitmap
466  */
467  bitmapDC.SelectObject( wxNullBitmap );
468 }
469 
470 
471 void DIALOG_COLOR_PICKER::SetEditVals( CHANGED_COLOR aChanged, bool aCheckTransparency )
472 {
473  if( aCheckTransparency )
474  {
475  // If they've changed the color, they probably don't want it to remain 100% transparent,
476  // and it looks like a bug when changing the color has no effect.
477  if( m_newColor4D.a == 0.0 )
478  m_newColor4D.a = 1.0;
479  }
480 
482 
483  if( aChanged == RED_CHANGED || aChanged == GREEN_CHANGED || aChanged == BLUE_CHANGED )
484  m_newColor4D.ToHSV( m_hue, m_sat, m_val, true );
485 
486  if( aChanged != RED_CHANGED )
487  m_spinCtrlRed->SetValue( normalizeToInt( m_newColor4D.r ) );
488 
489  if( aChanged != GREEN_CHANGED )
491 
492  if( aChanged != BLUE_CHANGED )
494 
495  if( aChanged != HUE_CHANGED )
496  m_spinCtrlHue->SetValue( (int)m_hue );
497 
498  if( aChanged != SAT_CHANGED )
499  m_spinCtrlSaturation->SetValue( m_sat * 255 );
500 
501  if( aChanged != VAL_CHANGED )
502  m_sliderBrightness->SetValue(normalizeToInt( m_val ) );
503 
504  if( aChanged != HEX_CHANGED )
505  m_colorValue->ChangeValue( m_newColor4D.ToWxString( wxC2S_CSS_SYNTAX ) );
506 }
507 
508 
510 {
511  m_NewColorRect->Freeze(); // Avoid flicker
512  m_HsvBitmap->Freeze();
513  m_RgbBitmap->Freeze();
515  drawHSVPalette();
516  drawRGBPalette();
517  m_NewColorRect->Thaw();
518  m_HsvBitmap->Thaw();
519  m_RgbBitmap->Thaw();
520  m_NewColorRect->Refresh();
521  m_HsvBitmap->Refresh();
522  m_RgbBitmap->Refresh();
523 }
524 
525 
526 void DIALOG_COLOR_PICKER::buttColorClick( wxMouseEvent& event )
527 {
528  int id = event.GetId();
530  m_newColor4D.r = color.r;
531  m_newColor4D.g = color.g;
532  m_newColor4D.b = color.b;
533  m_newColor4D.a = color.a;
534 
535  m_newColor4D.ToHSV( m_hue, m_sat, m_val, true );
536  SetEditVals( ALL_CHANGED, false );
537 
538  drawAll();
539 
540  event.Skip();
541 }
542 
543 
544 void DIALOG_COLOR_PICKER::onRGBMouseClick( wxMouseEvent& event )
545 {
546  m_allowMouseEvents = true;
547  wxPoint mousePos = event.GetPosition();
548 
549  // The cursor position is relative to the m_bitmapHSV wxBitmap center
550  wxSize bmsize = m_bitmapRGB->GetSize();
551  int half_size = std::min( bmsize.x, bmsize.y )/2;
552  mousePos.x -= half_size;
553  mousePos.y -= half_size;
554  mousePos.y = -mousePos.y; // Use the bottom to top vertical axis
555 
556  wxPoint dist = m_cursorBitmapRed - mousePos;
557 
558  if( std::abs( dist.x ) <= m_cursorsSize/2 && std::abs( dist.y ) <= m_cursorsSize/2 )
559  {
561  return;
562  }
563 
564  dist = m_cursorBitmapGreen - mousePos;
565 
566  if( std::abs( dist.x ) <= m_cursorsSize/2 && std::abs( dist.y ) <= m_cursorsSize/2 )
567  {
569  return;
570  }
571 
572  dist = m_cursorBitmapBlue - mousePos;
573 
574  if( std::abs( dist.x ) <= m_cursorsSize/2 && std::abs( dist.y ) <= m_cursorsSize/2 )
575  {
577  return;
578  }
579 
580  m_selectedCursor = nullptr;
581 }
582 
583 
584 void DIALOG_COLOR_PICKER::onRGBMouseDrag( wxMouseEvent& event )
585 {
586  if( !event.Dragging() || !m_allowMouseEvents )
587  {
588  m_selectedCursor = nullptr;
589  return;
590  }
591 
595  return;
596 
597  // Adjust the HSV cursor position to follow the mouse cursor
598  // The cursor position is relative to the m_bitmapHSV wxBitmap center
599  wxPoint mousePos = event.GetPosition();
600  wxSize bmsize = m_bitmapRGB->GetSize();
601  int half_size = std::min( bmsize.x, bmsize.y )/2;
602  mousePos.x -= half_size;
603  mousePos.y -= half_size;
604  mousePos.y = -mousePos.y; // Use the bottom to top vertical axis
605 
606  half_size -= m_cursorsSize/2; // the actual half_size of the palette area
607 
608  // Change colors according to the selected cursor:
610  {
611  if( mousePos.y >= 0 && mousePos.y <= half_size )
612  m_newColor4D.r = (double)mousePos.y / half_size;
613  else
614  return;
615  }
616 
618  {
619  mousePos.x = -mousePos.x;
620 
621  if( mousePos.x >= 0 && mousePos.x <= half_size )
622  m_newColor4D.g = (double)mousePos.x / half_size;
623  else
624  return;
625  }
626 
628  {
629  if( mousePos.x >= 0 && mousePos.x <= half_size )
630  m_newColor4D.b = (double)mousePos.x / half_size;
631  else
632  return;
633  }
634 
635  m_newColor4D.ToHSV( m_hue, m_sat, m_val, true );
636  SetEditVals( ALL_CHANGED, true );
637 
638  drawAll();
639 }
640 
641 
642 void DIALOG_COLOR_PICKER::onHSVMouseClick( wxMouseEvent& event )
643 {
644  m_allowMouseEvents = true;
645 
646  if( setHSvaluesFromCursor( event.GetPosition() ) )
647  drawAll();
648 }
649 
650 
651 void DIALOG_COLOR_PICKER::onHSVMouseDrag( wxMouseEvent& event )
652 {
653  if( !event.Dragging() || !m_allowMouseEvents )
654  return;
655 
656  if( setHSvaluesFromCursor( event.GetPosition() ) )
657  drawAll();
658 }
659 
660 
661 void DIALOG_COLOR_PICKER::OnColorValueText( wxCommandEvent& event )
662 {
663  m_newColor4D.SetFromWxString( m_colorValue->GetValue() );
664  m_newColor4D.ToHSV( m_hue, m_sat, m_val, true );
665 
666  SetEditVals( HEX_CHANGED, true );
667  drawAll();
668 }
669 
670 
671 bool DIALOG_COLOR_PICKER::setHSvaluesFromCursor( wxPoint aMouseCursor )
672 {
673  wxPoint mousePos = aMouseCursor;
674  wxSize bmsize = m_bitmapHSV->GetSize();
675  int half_size = std::min( bmsize.x, bmsize.y )/2;
676  // Make the cursor position relative to the m_bitmapHSV wxBitmap center
677  mousePos.x -= half_size;
678  mousePos.y -= half_size;
679  mousePos.y = -mousePos.y; // Use the bottom to top vertical axis
680 
681  // The HS cursor position is restricted to a circle of radius half_size
682  double dist_from_centre = hypot( (double)mousePos.x, (double)mousePos.y );
683 
684  if( dist_from_centre > half_size )
685  // Saturation cannot be calculated:
686  return false;
687 
688  m_cursorBitmapHSV = mousePos;
689 
690  // Set saturation and hue from new cursor position:
691  half_size -= m_cursorsSize/2; // the actual half_size of the palette area
692  m_sat = dist_from_centre / half_size;
693 
694  if( m_sat > 1.0 )
695  m_sat = 1.0;
696 
697  m_hue = atan2( mousePos.y, mousePos.x ) / M_PI * 180.0;
698 
699  if( m_hue < 0 )
700  m_hue += 360.0;
701 
703  SetEditVals( ALL_CHANGED, true );
704 
705  return true;
706 }
707 
708 
709 void DIALOG_COLOR_PICKER::OnChangeAlpha( wxScrollEvent& event )
710 {
711  double alpha = (double)event.GetPosition() / ALPHA_MAX;
712  m_newColor4D.a = alpha;
713  m_NewColorRect->Freeze(); // Avoid flicker
715  m_NewColorRect->Thaw();
716  m_NewColorRect->Refresh();
717 }
718 
719 
720 void DIALOG_COLOR_PICKER::OnChangeEditRed( wxSpinEvent& event )
721 {
722  double val = (double)event.GetPosition() / 255.0;
723  m_newColor4D.r = val;
724  SetEditVals( RED_CHANGED, true );
725 
726  drawAll();
727 }
728 
729 
730 void DIALOG_COLOR_PICKER::OnChangeEditGreen( wxSpinEvent& event )
731 {
732  double val = (double)event.GetPosition() / 255.0;
733  m_newColor4D.g = val;
734  SetEditVals( GREEN_CHANGED, true );
735 
736  drawAll();
737 }
738 
739 
740 void DIALOG_COLOR_PICKER::OnChangeEditBlue( wxSpinEvent& event )
741 {
742  double val = (double)event.GetPosition() / 255.0;
743  m_newColor4D.b = val;
744  SetEditVals( BLUE_CHANGED, true );
745 
746  drawAll();
747 }
748 
749 
750 void DIALOG_COLOR_PICKER::OnChangeEditHue( wxSpinEvent& event )
751 {
752  m_hue = (double)event.GetPosition();
753 
755 
756  SetEditVals( HUE_CHANGED, true );
757 
758  drawAll();
759 }
760 
761 
762 void DIALOG_COLOR_PICKER::OnChangeEditSat( wxSpinEvent& event )
763 {
764  m_sat = (double)event.GetPosition() / 255.0;
765 
767 
768  SetEditVals( SAT_CHANGED, true );
769 
770  drawAll();
771 }
772 
773 
774 void DIALOG_COLOR_PICKER::OnChangeBrightness( wxScrollEvent& event )
775 {
776  m_val = (double)event.GetPosition() / 255.0;
777 
779 
780  SetEditVals( VAL_CHANGED, true );
781 
782  drawAll();
783 }
784 
785 
786 void DIALOG_COLOR_PICKER::OnResetButton( wxCommandEvent& aEvent )
787 {
792 
793  m_newColor4D.ToHSV( m_hue, m_sat, m_val, true );
794  SetEditVals( ALL_CHANGED, false );
795 
796  drawAll();
797 }
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:312
void drawRGBPalette()
draws the RVB color space
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:60
void OnChangeAlpha(wxScrollEvent &event) override
Event handlers from wxSpinControl.
static wxBitmap MakeBitmap(KIGFX::COLOR4D aColor, KIGFX::COLOR4D aBackground, wxSize aSize, wxSize aCheckerboardSize, KIGFX::COLOR4D aCheckerboardBackground)
Make a simple color swatch bitmap.
int normalizeToInt(double aValue, int aValMax=255)
static const wxSize SWATCH_SIZE_LARGE_DU(24, 16)
void onHSVMouseDrag(wxMouseEvent &event) override
APP_SETTINGS_BASE * KifaceSettings() const
Definition: kiface_i.h:92
void OnColorValueText(wxCommandEvent &event) override
Event handler for the reset button press.
double g
Green component.
Definition: color4d.h:364
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
bool setHSvaluesFromCursor(wxPoint aMouseCursor)
Manage the Hue and Saturation settings when the mouse cursor is at aMouseCursor.
void OnChangeBrightness(wxScrollEvent &event) override
Event handler from wxSlider: alpha (transparency) control.
KIGFX::COLOR4D m_newColor4D
the current color4d
void onHSVMouseClick(wxMouseEvent &event) override
wxPoint m_cursorBitmapHSV
the cursor on the HSV bitmap palette.
double b
Blue component.
Definition: color4d.h:365
Number of colors.
Definition: color4d.h:79
void SetEditVals(CHANGED_COLOR aChanged, bool aCheckTransparency)
double a
Alpha component.
Definition: color4d.h:366
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
#define NULL
KIGFX::COLOR4D m_previousColor4D
the initial color4d
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
void createRGBBitmap()
generate the bitmap that shows the RVB color space
#define ALPHA_MAX
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)
const StructColors * colorRefs()
Global list of legacy color names, still used all over the place for constructing COLOR4D's.
Definition: color4d.cpp:37
void buttColorClick(wxMouseEvent &event)
called when creating the dialog
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:365
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
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:363
COLOR_PICKER m_ColorPicker
Definition: app_settings.h:173
#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.