1 /* This file is part of the KDE libraries
2 Copyright (C) 1997 Martin Jones (mjones@kde.org)
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
17 Boston, MA 02110-1301, USA.
19 //-----------------------------------------------------------------------------
20 // KDE color selection dialog.
22 // 1999-09-27 Espen Sand <espensa@online.no>
23 // KColorDialog is now subclassed from KDialogBase. I have also extended
24 // KColorDialog::getColor() so that it contains a parent argument. This
25 // improves centering capability.
27 // layout management added Oct 1997 by Mario Weilguni
28 // <mweilguni@sime.com>
34 #include <qcheckbox.h>
35 #include <qcombobox.h>
36 #include <qdrawutil.h>
42 #include <qlineedit.h>
43 #include <qvalidator.h>
45 #include <qpushbutton.h>
49 #include <kapplication.h>
52 #include <kglobalsettings.h>
53 #include <kiconloader.h>
56 #include <kmessagebox.h>
57 #include <kseparator.h>
59 #include <kimageeffect.h>
61 #include "kcolordialog.h"
62 #include "kcolordrag.h"
63 #include "kstaticdeleter.h"
71 // defined in qapplication_x11.cpp
72 typedef int (*QX11EventFilter
) (XEvent
*);
73 extern QX11EventFilter
qt_set_x11_event_filter (QX11EventFilter filter
);
76 struct ColorPaletteNameType
78 const char* m_fileName
;
79 const char* m_displayName
;
82 const ColorPaletteNameType colorPaletteName
[]=
84 { "Recent_Colors", I18N_NOOP2( "palette name", "* Recent Colors *" ) },
85 { "Custom_Colors", I18N_NOOP2( "palette name", "* Custom Colors *" ) },
86 { "40.colors", I18N_NOOP2( "palette name", "Forty Colors" ) },
87 { "Royal.colors", I18N_NOOP2( "palette name", "Royal Colors" ) },
88 { "Web.colors", I18N_NOOP2( "palette name", "Web Colors" ) },
89 { 0, 0 } // end of data
92 const int recentColorIndex
= 0;
94 class KColorSpinBox
: public QSpinBox
97 KColorSpinBox(int minValue
, int maxValue
, int step
, QWidget
* parent
)
98 : QSpinBox(minValue
, maxValue
, step
, parent
, "kcolorspinbox")
101 // Override Qt's braindead auto-selection.
102 virtual void valueChange()
105 emit
valueChanged( value() );
106 emit
valueChanged( currentValueText() );
112 #define STANDARD_PAL_SIZE 17
117 r
= 0; g
= 0; b
= 0; h
= 0; s
= 0; v
= 0;
120 KColor::KColor( const KColor
&col
)
123 h
= col
.h
; s
= col
.s
; v
= col
.v
;
124 r
= col
.r
; g
= col
.g
; b
= col
.b
;
127 KColor::KColor( const QColor
&col
)
130 QColor::getRgb(&r
, &g
, &b
);
131 QColor::getHsv(&h
, &s
, &v
);
134 bool KColor::operator==(const KColor
& col
) const
136 return (h
== col
.h
) && (s
== col
.s
) && (v
== col
.v
) &&
137 (r
== col
.r
) && (g
== col
.g
) && (b
== col
.b
);
140 KColor
& KColor::operator=(const KColor
& col
)
142 *(QColor
*)this = col
;
143 h
= col
.h
; s
= col
.s
; v
= col
.v
;
144 r
= col
.r
; g
= col
.g
; b
= col
.b
;
149 KColor::setHsv(int _h
, int _s
, int _v
)
151 h
= _h
; s
= _s
; v
= _v
;
152 QColor::setHsv(h
, s
, v
);
153 QColor::rgb(&r
, &g
, &b
);
157 KColor::setRgb(int _r
, int _g
, int _b
)
159 r
= _r
; g
= _g
; b
= _b
;
160 QColor::setRgb(r
, g
, b
);
161 QColor::hsv(&h
, &s
, &v
);
165 KColor::rgb(int *_r
, int *_g
, int *_b
) const
167 *_r
= r
; *_g
= g
; *_b
= b
;
171 KColor::hsv(int *_h
, int *_s
, int *_v
) const
173 *_h
= h
; *_s
= s
; *_v
= v
;
177 static QColor
*standardPalette
= 0;
178 static KStaticDeleter
<QColor
> spd
;
180 static void createStandardPalette()
182 if ( standardPalette
)
185 spd
.setObject(standardPalette
, new QColor
[STANDARD_PAL_SIZE
], true/*array*/);
189 standardPalette
[i
++] = Qt::red
;
190 standardPalette
[i
++] = Qt::green
;
191 standardPalette
[i
++] = Qt::blue
;
192 standardPalette
[i
++] = Qt::cyan
;
193 standardPalette
[i
++] = Qt::magenta
;
194 standardPalette
[i
++] = Qt::yellow
;
195 standardPalette
[i
++] = Qt::darkRed
;
196 standardPalette
[i
++] = Qt::darkGreen
;
197 standardPalette
[i
++] = Qt::darkBlue
;
198 standardPalette
[i
++] = Qt::darkCyan
;
199 standardPalette
[i
++] = Qt::darkMagenta
;
200 standardPalette
[i
++] = Qt::darkYellow
;
201 standardPalette
[i
++] = Qt::white
;
202 standardPalette
[i
++] = Qt::lightGray
;
203 standardPalette
[i
++] = Qt::gray
;
204 standardPalette
[i
++] = Qt::darkGray
;
205 standardPalette
[i
++] = Qt::black
;
209 KHSSelector::KHSSelector( QWidget
*parent
, const char *name
)
210 : KXYSelector( parent
, name
)
212 setRange( 0, 0, 359, 255 );
215 void KHSSelector::updateContents()
217 drawPalette(&pixmap
);
220 void KHSSelector::resizeEvent( QResizeEvent
* )
225 void KHSSelector::drawContents( QPainter
*painter
)
227 painter
->drawPixmap( contentsRect().x(), contentsRect().y(), pixmap
);
230 void KHSSelector::drawPalette( QPixmap
*pixmap
)
232 int xSize
= contentsRect().width(), ySize
= contentsRect().height();
233 QImage
image( xSize
, ySize
, 32 );
238 for ( s
= ySize
-1; s
>= 0; s
-- )
240 p
= (uint
*) image
.scanLine( ySize
- s
- 1 );
241 for( h
= 0; h
< xSize
; h
++ )
243 col
.setHsv( 359*h
/(xSize
-1), 255*s
/(ySize
-1), 192 );
249 if ( QColor::numBitPlanes() <= 8 )
251 createStandardPalette();
252 KImageEffect::dither( image
, standardPalette
, STANDARD_PAL_SIZE
);
254 pixmap
->convertFromImage( image
);
258 //-----------------------------------------------------------------------------
260 KValueSelector::KValueSelector( QWidget
*parent
, const char *name
)
261 : KSelector( KSelector::Vertical
, parent
, name
), _hue(0), _sat(0)
264 pixmap
.setOptimization( QPixmap::BestOptim
);
267 KValueSelector::KValueSelector(Orientation o
, QWidget
*parent
, const char *name
269 : KSelector( o
, parent
, name
), _hue(0), _sat(0)
272 pixmap
.setOptimization( QPixmap::BestOptim
);
275 void KValueSelector::updateContents()
277 drawPalette(&pixmap
);
280 void KValueSelector::resizeEvent( QResizeEvent
* )
285 void KValueSelector::drawContents( QPainter
*painter
)
287 painter
->drawPixmap( contentsRect().x(), contentsRect().y(), pixmap
);
290 void KValueSelector::drawPalette( QPixmap
*pixmap
)
292 int xSize
= contentsRect().width(), ySize
= contentsRect().height();
293 QImage
image( xSize
, ySize
, 32 );
298 if ( orientation() == KSelector::Horizontal
)
300 for ( int v
= 0; v
< ySize
; v
++ )
302 p
= (uint
*) image
.scanLine( ySize
- v
- 1 );
304 for( int x
= 0; x
< xSize
; x
++ )
306 col
.setHsv( _hue
, _sat
, 255*x
/(xSize
-1) );
313 if( orientation() == KSelector::Vertical
)
315 for ( int v
= 0; v
< ySize
; v
++ )
317 p
= (uint
*) image
.scanLine( ySize
- v
- 1 );
318 col
.setHsv( _hue
, _sat
, 255*v
/(ySize
-1) );
320 for ( int i
= 0; i
< xSize
; i
++ )
325 if ( QColor::numBitPlanes() <= 8 )
327 createStandardPalette();
328 KImageEffect::dither( image
, standardPalette
, STANDARD_PAL_SIZE
);
330 pixmap
->convertFromImage( image
);
333 //-----------------------------------------------------------------------------
335 KColorCells::KColorCells( QWidget
*parent
, int rows
, int cols
)
336 : QGridView( parent
)
341 colors
= new QColor
[ rows
* cols
];
343 for ( int i
= 0; i
< rows
* cols
; i
++ )
344 colors
[i
] = QColor();
350 setAcceptDrops( true);
352 setHScrollBarMode( AlwaysOff
);
353 setVScrollBarMode( AlwaysOff
);
354 viewport()->setBackgroundMode( PaletteBackground
);
355 setBackgroundMode( PaletteBackground
);
358 KColorCells::~KColorCells()
363 void KColorCells::setColor( int colNum
, const QColor
&col
)
365 colors
[colNum
] = col
;
366 updateCell( colNum
/numCols(), colNum
%numCols() );
369 void KColorCells::paintCell( QPainter
*painter
, int row
, int col
)
376 qDrawShadePanel( painter
, 1, 1, cellWidth()-2,
377 cellHeight()-2, colorGroup(), true, 1, &brush
);
380 QColor color
= colors
[ row
* numCols() + col
];
381 if (!color
.isValid())
384 color
= backgroundColor();
387 painter
->setPen( color
);
388 painter
->setBrush( QBrush( color
) );
389 painter
->drawRect( w
, w
, cellWidth()-w
*2, cellHeight()-w
*2 );
391 if ( row
* numCols() + col
== selected
)
392 painter
->drawWinFocusRect( w
, w
, cellWidth()-w
*2, cellHeight()-w
*2 );
395 void KColorCells::resizeEvent( QResizeEvent
* )
397 setCellWidth( width() / numCols() );
398 setCellHeight( height() / numRows() );
401 void KColorCells::mousePressEvent( QMouseEvent
*e
)
407 int KColorCells::posToCell(const QPoint
&pos
, bool ignoreBorders
)
409 int row
= pos
.y() / cellHeight();
410 int col
= pos
.x() / cellWidth();
411 int cell
= row
* numCols() + col
;
416 int x
= pos
.x() - col
* cellWidth();
417 int y
= pos
.y() - row
* cellHeight();
418 if ( (x
< border
) || (x
> cellWidth()-border
) ||
419 (y
< border
) || (y
> cellHeight()-border
))
425 void KColorCells::mouseMoveEvent( QMouseEvent
*e
)
427 if( !(e
->state() && LeftButton
)) return;
430 int delay
= KGlobalSettings::dndEventDelay();
431 if(e
->x() > mPos
.x()+delay
|| e
->x() < mPos
.x()-delay
||
432 e
->y() > mPos
.y()+delay
|| e
->y() < mPos
.y()-delay
){
434 int cell
= posToCell(mPos
);
435 if ((cell
!= -1) && colors
[cell
].isValid())
437 KColorDrag
*d
= new KColorDrag( colors
[cell
], this);
444 void KColorCells::dragEnterEvent( QDragEnterEvent
*event
)
446 event
->accept( acceptDrags
&& KColorDrag::canDecode( event
));
449 void KColorCells::dropEvent( QDropEvent
*event
)
452 if( KColorDrag::decode( event
, c
)) {
453 int cell
= posToCell(event
->pos(), true);
458 void KColorCells::mouseReleaseEvent( QMouseEvent
*e
)
460 int cell
= posToCell(mPos
);
461 int currentCell
= posToCell(e
->pos());
463 // If we release the mouse in another cell and we don't have
464 // a drag we should ignore this event.
465 if (currentCell
!= cell
)
468 if ( (cell
!= -1) && (selected
!= cell
) )
470 int prevSel
= selected
;
472 updateCell( prevSel
/numCols(), prevSel
%numCols() );
473 updateCell( cell
/numCols(), cell
%numCols() );
478 emit
colorSelected( cell
);
481 void KColorCells::mouseDoubleClickEvent( QMouseEvent
* /*e*/ )
483 int cell
= posToCell(mPos
);
486 emit
colorDoubleClicked( cell
);
490 //-----------------------------------------------------------------------------
492 KColorPatch::KColorPatch( QWidget
*parent
) : QFrame( parent
)
494 setFrameStyle( QFrame::Panel
| QFrame::Sunken
);
496 setAcceptDrops( true);
499 KColorPatch::~KColorPatch()
502 QColor::destroyAllocContext( colContext
);
505 void KColorPatch::setColor( const QColor
&col
)
508 QColor::destroyAllocContext( colContext
);
509 colContext
= QColor::enterAllocContext();
510 color
.setRgb( col
.rgb() );
512 QColor::leaveAllocContext();
516 painter
.begin( this );
517 drawContents( &painter
);
521 void KColorPatch::drawContents( QPainter
*painter
)
523 painter
->setPen( color
);
524 painter
->setBrush( QBrush( color
) );
525 painter
->drawRect( contentsRect() );
528 void KColorPatch::mouseMoveEvent( QMouseEvent
*e
)
531 if( !(e
->state() && LeftButton
)) return;
532 KColorDrag
*d
= new KColorDrag( color
, this);
536 void KColorPatch::dragEnterEvent( QDragEnterEvent
*event
)
538 event
->accept( KColorDrag::canDecode( event
));
541 void KColorPatch::dropEvent( QDropEvent
*event
)
544 if( KColorDrag::decode( event
, c
)) {
546 emit
colorChanged( c
);
550 class KPaletteTable::KPaletteTablePrivate
553 QMap
<QString
,QColor
> m_namedColorMap
;
556 KPaletteTable::KPaletteTable( QWidget
*parent
, int minWidth
, int cols
)
557 : QWidget( parent
), cells(0), mPalette(0), mMinWidth(minWidth
), mCols(cols
)
559 d
= new KPaletteTablePrivate
;
561 i18n_namedColors
= i18n("Named Colors");
563 QStringList diskPaletteList
= KPalette::getPaletteList();
564 QStringList paletteList
;
566 // We must replace the untranslated file names by translate names (of course only for KDE's standard palettes)
567 for ( int i
= 0; colorPaletteName
[i
].m_fileName
; ++i
)
569 diskPaletteList
.remove( colorPaletteName
[i
].m_fileName
);
570 paletteList
.append( i18n( "palette name", colorPaletteName
[i
].m_displayName
) );
572 paletteList
+= diskPaletteList
;
573 paletteList
.append( i18n_namedColors
);
575 QVBoxLayout
*layout
= new QVBoxLayout( this );
577 combo
= new QComboBox( false, this );
578 combo
->insertStringList( paletteList
);
579 layout
->addWidget(combo
);
581 sv
= new QScrollView( this );
582 QSize cellSize
= QSize( mMinWidth
, 120);
583 sv
->setHScrollBarMode( QScrollView::AlwaysOff
);
584 sv
->setVScrollBarMode( QScrollView::AlwaysOn
);
585 QSize minSize
= QSize(sv
->verticalScrollBar()->width(), 0);
586 minSize
+= QSize(sv
->frameWidth(), 0);
587 minSize
+= QSize(cellSize
);
588 sv
->setFixedSize(minSize
);
589 layout
->addWidget(sv
);
591 mNamedColorList
= new KListBox( this, "namedColorList", 0 );
592 mNamedColorList
->setFixedSize(minSize
);
593 mNamedColorList
->hide();
594 layout
->addWidget(mNamedColorList
);
595 connect( mNamedColorList
, SIGNAL(highlighted( const QString
& )),
596 this, SLOT( slotColorTextSelected( const QString
& )) );
598 setFixedSize( sizeHint());
599 connect( combo
, SIGNAL(activated(const QString
&)),
600 this, SLOT(slotSetPalette( const QString
&)));
603 KPaletteTable::~KPaletteTable()
610 KPaletteTable::palette() const
612 return combo
->currentText();
616 static const char * const *namedColorFilePath( void )
619 // 2000-02-05 Espen Sand.
620 // Add missing filepaths here. Make sure the last entry is 0!
622 static const char * const path
[] =
627 "/usr/X11R6/lib/X11/rgb.txt",
628 "/usr/openwin/lib/X11/rgb.txt", // for Solaris.
638 KPaletteTable::readNamedColor( void )
640 if( mNamedColorList
->count() != 0 )
642 return; // Strings already present
645 KGlobal::locale()->insertCatalogue("kdelibs_colors");
648 // Code somewhat inspired by KPalette.
651 const char * const *path
= namedColorFilePath();
652 for( int i
=0; path
[i
]; ++i
)
654 QFile
paletteFile( path
[i
] );
655 if( !paletteFile
.open( IO_ReadOnly
) )
662 while( paletteFile
.readLine( line
, 100 ) != -1 )
664 int red
, green
, blue
;
667 if( sscanf(line
.ascii(), "%d %d %d%n", &red
, &green
, &blue
, &pos
) == 3 )
670 // Remove duplicates. Every name with a space and every name
671 // that start with "gray".
673 QString name
= line
.mid(pos
).stripWhiteSpace();
674 if( name
.isNull() || name
.find(' ') != -1 ||
675 name
.find( "gray" ) != -1 || name
.find( "grey" ) != -1 )
680 const QColor
color ( red
, green
, blue
);
681 if ( color
.isValid() )
683 const QString
colorName( i18n("color", name
.latin1() ) );
684 list
.append( colorName
);
685 d
->m_namedColorMap
[ colorName
] = color
;
691 mNamedColorList
->insertStringList( list
);
695 if( mNamedColorList
->count() == 0 )
698 // Give the error dialog box a chance to center above the
699 // widget (or dialog). If we had displayed it now we could get a
700 // situation where the (modal) error dialog box pops up first
701 // preventing the real dialog to become visible until the
702 // error dialog box is removed (== bad UI).
704 QTimer::singleShot( 10, this, SLOT(slotShowNamedColorReadError()) );
710 KPaletteTable::slotShowNamedColorReadError( void )
712 if( mNamedColorList
->count() == 0 )
714 QString msg
= i18n(""
715 "Unable to read X11 RGB color strings. The following "
716 "file location(s) were examined:\n");
718 const char * const *path
= namedColorFilePath();
719 for( int i
=0; path
[i
]; ++i
)
724 KMessageBox::sorry( this, msg
);
730 // 2000-02-12 Espen Sand
731 // Set the color in two steps. The setPalette() slot will not emit a signal
732 // with the current color setting. The reason is that setPalette() is used
733 // by the color selector dialog on startup. In the color selector dialog
734 // we normally want to display a startup color which we specify
735 // when the dialog is started. The slotSetPalette() slot below will
736 // set the palette and then use the information to emit a signal with the
737 // new color setting. It is only used by the combobox widget.
740 KPaletteTable::slotSetPalette( const QString
&_paletteName
)
742 setPalette( _paletteName
);
743 if( mNamedColorList
->isVisible() )
745 int item
= mNamedColorList
->currentItem();
746 mNamedColorList
->setCurrentItem( item
< 0 ? 0 : item
);
747 slotColorTextSelected( mNamedColorList
->currentText() );
751 slotColorCellSelected(0); // FIXME: We need to save the current value!!
757 KPaletteTable::setPalette( const QString
&_paletteName
)
759 QString
paletteName( _paletteName
);
760 if (paletteName
.isEmpty())
761 paletteName
= i18n_recentColors
;
763 if (combo
->currentText() != paletteName
)
766 for(int i
= 0; i
< combo
->count(); i
++)
768 if (combo
->text(i
) == paletteName
)
770 combo
->setCurrentItem(i
);
777 combo
->insertItem(paletteName
);
778 combo
->setCurrentItem(combo
->count()-1);
782 // We must again find the file name of the palette from the eventual translation
783 for ( int i
= 0; colorPaletteName
[i
].m_fileName
; ++i
)
785 if ( paletteName
== i18n( "palette name", colorPaletteName
[i
].m_displayName
) )
787 paletteName
= colorPaletteName
[i
].m_fileName
;
794 // 2000-02-12 Espen Sand
795 // The palette mode "i18n_namedColors" does not use the KPalette class.
796 // In fact, 'mPalette' and 'cells' are 0 when in this mode. The reason
797 // for this is maninly that KPalette reads from and writes to files using
798 // "locate()". The colors used in "i18n_namedColors" mode comes from the
799 // X11 diretory and is not writable. I don't think this fit in KPalette.
801 if( !mPalette
|| mPalette
->name() != paletteName
)
803 if( paletteName
== i18n_namedColors
)
806 mNamedColorList
->show();
809 delete cells
; cells
= 0;
810 delete mPalette
; mPalette
= 0;
814 mNamedColorList
->hide();
819 mPalette
= new KPalette(paletteName
);
820 int rows
= (mPalette
->nrColors()+mCols
-1) / mCols
;
821 if (rows
< 1) rows
= 1;
822 cells
= new KColorCells( sv
->viewport(), rows
, mCols
);
823 cells
->setShading(false);
824 cells
->setAcceptDrags(false);
825 QSize cellSize
= QSize( mMinWidth
, mMinWidth
* rows
/ mCols
);
826 cells
->setFixedSize( cellSize
);
827 for( int i
= 0; i
< mPalette
->nrColors(); i
++)
829 cells
->setColor( i
, mPalette
->color(i
) );
831 connect( cells
, SIGNAL( colorSelected( int ) ),
832 SLOT( slotColorCellSelected( int ) ) );
833 connect( cells
, SIGNAL( colorDoubleClicked( int ) ),
834 SLOT( slotColorCellDoubleClicked( int ) ) );
835 sv
->addChild( cells
);
837 sv
->updateScrollBars();
845 KPaletteTable::slotColorCellSelected( int col
)
847 if (!mPalette
|| (col
>= mPalette
->nrColors()))
849 emit
colorSelected( mPalette
->color(col
), mPalette
->colorName(col
) );
853 KPaletteTable::slotColorCellDoubleClicked( int col
)
855 if (!mPalette
|| (col
>= mPalette
->nrColors()))
857 emit
colorDoubleClicked( mPalette
->color(col
), mPalette
->colorName(col
) );
862 KPaletteTable::slotColorTextSelected( const QString
&colorText
)
864 emit
colorSelected( d
->m_namedColorMap
[ colorText
], colorText
);
869 KPaletteTable::addToCustomColors( const QColor
&color
)
871 setPalette(i18n_customColors
);
872 mPalette
->addColor( color
);
876 setPalette(i18n_customColors
);
880 KPaletteTable::addToRecentColors( const QColor
&color
)
883 // 2000-02-12 Espen Sand.
884 // The 'mPalette' is always 0 when current mode is i18n_namedColors
886 bool recentIsSelected
= false;
887 if ( mPalette
&& mPalette
->name() == colorPaletteName
[ recentColorIndex
].m_fileName
)
891 recentIsSelected
= true;
893 KPalette
*recentPal
= new KPalette( colorPaletteName
[ recentColorIndex
].m_fileName
);
894 if (recentPal
->findColor(color
) == -1)
896 recentPal
->addColor( color
);
900 if (recentIsSelected
)
901 setPalette( i18n( "palette name", colorPaletteName
[ recentColorIndex
].m_displayName
) );
904 class KColorDialog::KColorDialogPrivate
{
906 KPaletteTable
*table
;
907 QString originalPalette
;
915 KColorSpinBox
*hedit
;
916 KColorSpinBox
*sedit
;
917 KColorSpinBox
*vedit
;
918 KColorSpinBox
*redit
;
919 KColorSpinBox
*gedit
;
920 KColorSpinBox
*bedit
;
922 KHSSelector
*hsSelector
;
924 KValueSelector
*valuePal
;
925 QVBoxLayout
* l_right
;
926 QGridLayout
* tl_layout
;
927 QCheckBox
*cbDefaultColor
;
931 QX11EventFilter oldfilter
;
936 KColorDialog::KColorDialog( QWidget
*parent
, const char *name
, bool modal
)
937 :KDialogBase( parent
, name
, modal
, i18n("Select Color"),
938 modal
? Help
|Ok
|Cancel
: Help
|Close
,
941 d
= new KColorDialogPrivate
;
942 d
->bRecursion
= true;
943 d
->bColorPicking
= false;
947 d
->cbDefaultColor
= 0L;
948 setHelp( QString::fromLatin1("kcolordialog.html"), QString::null
);
949 connect( this, SIGNAL(okClicked(void)),this,SLOT(slotWriteSettings(void)));
950 connect( this, SIGNAL(closeClicked(void)),this,SLOT(slotWriteSettings(void)));
955 // Create the top level page and its layout
957 QWidget
*page
= new QWidget( this );
958 setMainWidget( page
);
960 QGridLayout
*tl_layout
= new QGridLayout( page
, 3, 3, 0, spacingHint() );
961 d
->tl_layout
= tl_layout
;
962 tl_layout
->addColSpacing( 1, spacingHint() * 2 );
965 // the more complicated part: the left side
968 QVBoxLayout
*l_left
= new QVBoxLayout();
969 tl_layout
->addLayout(l_left
, 0, 0);
972 // add a H-Box for the XY-Selector and a grid for the
975 QHBoxLayout
*l_ltop
= new QHBoxLayout();
976 l_left
->addLayout(l_ltop
);
978 // a little space between
979 l_left
->addSpacing(10);
981 QGridLayout
*l_lbot
= new QGridLayout(3, 6);
982 l_left
->addLayout(l_lbot
);
985 // the palette and value selector go into the H-box
987 d
->hsSelector
= new KHSSelector( page
);
988 d
->hsSelector
->setMinimumSize(140, 70);
989 l_ltop
->addWidget(d
->hsSelector
, 8);
990 connect( d
->hsSelector
, SIGNAL( valueChanged( int, int ) ),
991 SLOT( slotHSChanged( int, int ) ) );
993 d
->valuePal
= new KValueSelector( page
);
994 d
->valuePal
->setMinimumSize(26, 70);
995 l_ltop
->addWidget(d
->valuePal
, 1);
996 connect( d
->valuePal
, SIGNAL( valueChanged( int ) ),
997 SLOT( slotVChanged( int ) ) );
1001 // add the HSV fields
1003 label
= new QLabel( i18n("H:"), page
);
1004 label
->setAlignment(AlignRight
| AlignVCenter
);
1005 l_lbot
->addWidget(label
, 0, 2);
1006 d
->hedit
= new KColorSpinBox( 0, 359, 1, page
);
1007 d
->hedit
->setValidator( new QIntValidator( d
->hedit
) );
1008 l_lbot
->addWidget(d
->hedit
, 0, 3);
1009 connect( d
->hedit
, SIGNAL( valueChanged(int) ),
1010 SLOT( slotHSVChanged() ) );
1012 label
= new QLabel( i18n("S:"), page
);
1013 label
->setAlignment(AlignRight
| AlignVCenter
);
1014 l_lbot
->addWidget(label
, 1, 2);
1015 d
->sedit
= new KColorSpinBox( 0, 255, 1, page
);
1016 d
->sedit
->setValidator( new QIntValidator( d
->sedit
) );
1017 l_lbot
->addWidget(d
->sedit
, 1, 3);
1018 connect( d
->sedit
, SIGNAL( valueChanged(int) ),
1019 SLOT( slotHSVChanged() ) );
1021 label
= new QLabel( i18n("V:"), page
);
1022 label
->setAlignment(AlignRight
| AlignVCenter
);
1023 l_lbot
->addWidget(label
, 2, 2);
1024 d
->vedit
= new KColorSpinBox( 0, 255, 1, page
);
1025 d
->vedit
->setValidator( new QIntValidator( d
->vedit
) );
1026 l_lbot
->addWidget(d
->vedit
, 2, 3);
1027 connect( d
->vedit
, SIGNAL( valueChanged(int) ),
1028 SLOT( slotHSVChanged() ) );
1031 // add the RGB fields
1033 label
= new QLabel( i18n("R:"), page
);
1034 label
->setAlignment(AlignRight
| AlignVCenter
);
1035 l_lbot
->addWidget(label
, 0, 4);
1036 d
->redit
= new KColorSpinBox( 0, 255, 1, page
);
1037 d
->redit
->setValidator( new QIntValidator( d
->redit
) );
1038 l_lbot
->addWidget(d
->redit
, 0, 5);
1039 connect( d
->redit
, SIGNAL( valueChanged(int) ),
1040 SLOT( slotRGBChanged() ) );
1042 label
= new QLabel( i18n("G:"), page
);
1043 label
->setAlignment(AlignRight
| AlignVCenter
);
1044 l_lbot
->addWidget( label
, 1, 4);
1045 d
->gedit
= new KColorSpinBox( 0, 255,1, page
);
1046 d
->gedit
->setValidator( new QIntValidator( d
->gedit
) );
1047 l_lbot
->addWidget(d
->gedit
, 1, 5);
1048 connect( d
->gedit
, SIGNAL( valueChanged(int) ),
1049 SLOT( slotRGBChanged() ) );
1051 label
= new QLabel( i18n("B:"), page
);
1052 label
->setAlignment(AlignRight
| AlignVCenter
);
1053 l_lbot
->addWidget(label
, 2, 4);
1054 d
->bedit
= new KColorSpinBox( 0, 255, 1, page
);
1055 d
->bedit
->setValidator( new QIntValidator( d
->bedit
) );
1056 l_lbot
->addWidget(d
->bedit
, 2, 5);
1057 connect( d
->bedit
, SIGNAL( valueChanged(int) ),
1058 SLOT( slotRGBChanged() ) );
1061 // the entry fields should be wide enough to hold 8888888
1063 int w
= d
->hedit
->fontMetrics().width("8888888");
1064 d
->hedit
->setFixedWidth(w
);
1065 d
->sedit
->setFixedWidth(w
);
1066 d
->vedit
->setFixedWidth(w
);
1068 d
->redit
->setFixedWidth(w
);
1069 d
->gedit
->setFixedWidth(w
);
1070 d
->bedit
->setFixedWidth(w
);
1073 // add a layout for the right side
1075 d
->l_right
= new QVBoxLayout
;
1076 tl_layout
->addLayout(d
->l_right
, 0, 2);
1079 // Add the palette table
1081 d
->table
= new KPaletteTable( page
);
1082 d
->l_right
->addWidget(d
->table
, 10);
1084 connect( d
->table
, SIGNAL( colorSelected( const QColor
&, const QString
& ) ),
1085 SLOT( slotColorSelected( const QColor
&, const QString
& ) ) );
1089 SIGNAL( colorDoubleClicked( const QColor
&, const QString
& ) ),
1090 SLOT( slotColorDoubleClicked( const QColor
&, const QString
& ) )
1092 // Store the default value for saving time.
1093 d
->originalPalette
= d
->table
->palette();
1096 // a little space between
1098 d
->l_right
->addSpacing(10);
1100 QHBoxLayout
*l_hbox
= new QHBoxLayout( d
->l_right
);
1103 // The add to custom colors button
1105 QPushButton
*button
= new QPushButton( page
);
1106 button
->setText(i18n("&Add to Custom Colors"));
1107 l_hbox
->addWidget(button
, 0, AlignLeft
);
1108 connect( button
, SIGNAL( clicked()), SLOT( slotAddToCustomColors()));
1111 // The color picker button
1113 button
= new QPushButton( page
);
1114 button
->setPixmap( BarIcon("colorpicker"));
1115 l_hbox
->addWidget(button
, 0, AlignHCenter
);
1116 connect( button
, SIGNAL( clicked()), SLOT( slotColorPicker()));
1119 // a little space between
1121 d
->l_right
->addSpacing(10);
1124 // and now the entry fields and the patch (=colored box)
1126 QGridLayout
*l_grid
= new QGridLayout( d
->l_right
, 2, 3);
1128 l_grid
->setColStretch(2, 1);
1130 label
= new QLabel( page
);
1131 label
->setText(i18n("Name:"));
1132 l_grid
->addWidget(label
, 0, 1, AlignLeft
);
1134 d
->colorName
= new QLabel( page
);
1135 l_grid
->addWidget(d
->colorName
, 0, 2, AlignLeft
);
1137 label
= new QLabel( page
);
1138 label
->setText(i18n("HTML:"));
1139 l_grid
->addWidget(label
, 1, 1, AlignLeft
);
1141 d
->htmlName
= new QLineEdit( page
);
1142 d
->htmlName
->setMaxLength( 13 ); // Qt's QColor allows 12 hexa-digits
1143 d
->htmlName
->setText("#FFFFFF"); // But HTML uses only 6, so do not worry about the size
1144 w
= d
->htmlName
->fontMetrics().width(QString::fromLatin1("#DDDDDDD"));
1145 d
->htmlName
->setFixedWidth(w
);
1146 l_grid
->addWidget(d
->htmlName
, 1, 2, AlignLeft
);
1148 connect( d
->htmlName
, SIGNAL( textChanged(const QString
&) ),
1149 SLOT( slotHtmlChanged() ) );
1151 d
->patch
= new KColorPatch( page
);
1152 d
->patch
->setFixedSize(48, 48);
1153 l_grid
->addMultiCellWidget(d
->patch
, 0, 1, 0, 0, AlignHCenter
| AlignVCenter
);
1154 connect( d
->patch
, SIGNAL( colorChanged( const QColor
&)),
1155 SLOT( setColor( const QColor
&)));
1157 tl_layout
->activate();
1158 page
->setMinimumSize( page
->sizeHint() );
1161 d
->bRecursion
= false;
1162 d
->bEditHsv
= false;
1163 d
->bEditRgb
= false;
1164 d
->bEditHtml
= false;
1168 col
.setHsv( 0, 0, 255 );
1171 d
->htmlName
->installEventFilter(this);
1172 d
->hsSelector
->installEventFilter(this);
1173 d
->hsSelector
->setAcceptDrops(true);
1176 KColorDialog::~KColorDialog()
1179 if (d
->bColorPicking
)
1180 qt_set_x11_event_filter(d
->oldfilter
);
1186 KColorDialog::eventFilter( QObject
*obj
, QEvent
*ev
)
1188 if ((obj
== d
->htmlName
) || (obj
== d
->hsSelector
))
1191 case QEvent::DragEnter
:
1192 case QEvent::DragMove
:
1193 case QEvent::DragLeave
:
1195 case QEvent::DragResponse
:
1196 qApp
->sendEvent(d
->patch
, ev
);
1201 return KDialogBase::eventFilter(obj
, ev
);
1205 KColorDialog::setDefaultColor( const QColor
& col
)
1207 if ( !d
->cbDefaultColor
)
1210 // a little space between
1212 d
->l_right
->addSpacing(10);
1215 // and the "default color" checkbox, under all items on the right side
1217 d
->cbDefaultColor
= new QCheckBox( i18n( "Default color" ), mainWidget() );
1218 d
->cbDefaultColor
->setChecked(true);
1220 d
->l_right
->addWidget( d
->cbDefaultColor
);
1222 mainWidget()->setMaximumSize( QWIDGETSIZE_MAX
, QWIDGETSIZE_MAX
); // cancel setFixedSize()
1223 d
->tl_layout
->activate();
1224 mainWidget()->setMinimumSize( mainWidget()->sizeHint() );
1227 connect( d
->cbDefaultColor
, SIGNAL( clicked() ), SLOT( slotDefaultColorClicked() ) );
1230 d
->defaultColor
= col
;
1232 slotDefaultColorClicked();
1235 QColor
KColorDialog::defaultColor() const
1237 return d
->defaultColor
;
1240 void KColorDialog::slotDefaultColorClicked()
1242 if ( d
->cbDefaultColor
->isChecked() )
1244 d
->selColor
= d
->defaultColor
;
1245 showColor( d
->selColor
, i18n( "-default-" ) );
1248 showColor( d
->selColor
, QString::null
);
1253 KColorDialog::readSettings()
1255 KConfig
* config
= KGlobal::config();
1257 QString oldgroup
= config
->group();
1259 config
->setGroup("Colors");
1260 QString palette
= config
->readEntry("CurrentPalette");
1261 d
->table
->setPalette(palette
);
1262 config
->setGroup( oldgroup
);
1266 KColorDialog::slotWriteSettings()
1268 KConfig
* config
= KGlobal::config();
1269 config
->setGroup("Colors");
1270 QString palette
= d
->table
->palette();
1271 if (!config
->hasDefault("CurrentPalette") &&
1272 (d
->table
->palette() == d
->originalPalette
))
1274 config
->revertToDefault("CurrentPalette");
1278 config
->writeEntry("CurrentPalette", d
->table
->palette());
1283 KColorDialog::color() const
1285 if ( d
->cbDefaultColor
&& d
->cbDefaultColor
->isChecked() )
1287 if ( d
->selColor
.isValid() )
1288 d
->table
->addToRecentColors( d
->selColor
);
1292 void KColorDialog::setColor( const QColor
&col
)
1298 // static function to display dialog and return color
1300 int KColorDialog::getColor( QColor
&theColor
, QWidget
*parent
)
1302 KColorDialog
dlg( parent
, "Color Selector", true );
1303 if ( theColor
.isValid() )
1304 dlg
.setColor( theColor
);
1305 int result
= dlg
.exec();
1307 if ( result
== Accepted
)
1309 theColor
= dlg
.color();
1316 // static function to display dialog and return color
1318 int KColorDialog::getColor( QColor
&theColor
, const QColor
& defaultCol
, QWidget
*parent
)
1320 KColorDialog
dlg( parent
, "Color Selector", true );
1321 dlg
.setDefaultColor( defaultCol
);
1322 dlg
.setColor( theColor
);
1323 int result
= dlg
.exec();
1325 if ( result
== Accepted
)
1326 theColor
= dlg
.color();
1331 void KColorDialog::slotRGBChanged( void )
1333 if (d
->bRecursion
) return;
1334 int red
= d
->redit
->value();
1335 int grn
= d
->gedit
->value();
1336 int blu
= d
->bedit
->value();
1338 if ( red
> 255 || red
< 0 ) return;
1339 if ( grn
> 255 || grn
< 0 ) return;
1340 if ( blu
> 255 || blu
< 0 ) return;
1343 col
.setRgb( red
, grn
, blu
);
1346 d
->bEditRgb
= false;
1349 void KColorDialog::slotHtmlChanged( void )
1351 if (d
->bRecursion
|| d
->htmlName
->text().isEmpty()) return;
1353 QString
strColor( d
->htmlName
->text() );
1355 // Assume that a user does not want to type the # all the time
1356 if ( strColor
[0] != '#' )
1358 bool signalsblocked
= d
->htmlName
->signalsBlocked();
1359 d
->htmlName
->blockSignals(true);
1360 strColor
.prepend("#");
1361 d
->htmlName
->setText(strColor
);
1362 d
->htmlName
->blockSignals(signalsblocked
);
1365 const QColor
color( strColor
);
1367 if ( color
.isValid() )
1369 KColor
col( color
);
1370 d
->bEditHtml
= true;
1372 d
->bEditHtml
= false;
1376 void KColorDialog::slotHSVChanged( void )
1378 if (d
->bRecursion
) return;
1379 int hue
= d
->hedit
->value();
1380 int sat
= d
->sedit
->value();
1381 int val
= d
->vedit
->value();
1383 if ( hue
> 359 || hue
< 0 ) return;
1384 if ( sat
> 255 || sat
< 0 ) return;
1385 if ( val
> 255 || val
< 0 ) return;
1388 col
.setHsv( hue
, sat
, val
);
1391 d
->bEditHsv
= false;
1394 void KColorDialog::slotHSChanged( int h
, int s
)
1397 d
->selColor
.hsv(&_h
, &_s
, &v
);
1401 col
.setHsv( h
, s
, v
);
1405 void KColorDialog::slotVChanged( int v
)
1408 d
->selColor
.hsv(&h
, &s
, &_v
);
1410 col
.setHsv( h
, s
, v
);
1414 void KColorDialog::slotColorSelected( const QColor
&color
)
1419 void KColorDialog::slotAddToCustomColors( )
1421 d
->table
->addToCustomColors( d
->selColor
);
1424 void KColorDialog::slotColorSelected( const QColor
&color
, const QString
&name
)
1426 _setColor( color
, name
);
1429 void KColorDialog::slotColorDoubleClicked
1431 const QColor
& color
,
1432 const QString
& name
1435 _setColor(color
, name
);
1439 void KColorDialog::_setColor(const KColor
&color
, const QString
&name
)
1441 if (color
.isValid())
1443 if (d
->cbDefaultColor
&& d
->cbDefaultColor
->isChecked())
1444 d
->cbDefaultColor
->setChecked(false);
1445 d
->selColor
= color
;
1449 if (d
->cbDefaultColor
&& d
->cbDefaultColor
->isChecked())
1450 d
->cbDefaultColor
->setChecked(true);
1451 d
->selColor
= d
->defaultColor
;
1454 showColor( d
->selColor
, name
);
1456 emit
colorSelected( d
->selColor
);
1459 // show but don't set into selColor, nor emit colorSelected
1460 void KColorDialog::showColor( const KColor
&color
, const QString
&name
)
1462 d
->bRecursion
= true;
1465 d
->colorName
->setText( i18n("-unnamed-"));
1467 d
->colorName
->setText( name
);
1469 d
->patch
->setColor( color
);
1471 setRgbEdit( color
);
1472 setHsvEdit( color
);
1473 setHtmlEdit( color
);
1476 color
.hsv( &h
, &s
, &v
);
1477 d
->hsSelector
->setValues( h
, s
);
1478 d
->valuePal
->blockSignals(true);
1479 d
->valuePal
->setHue( h
);
1480 d
->valuePal
->setSaturation( s
);
1481 d
->valuePal
->setValue( v
);
1482 d
->valuePal
->updateContents();
1483 d
->valuePal
->blockSignals(false);
1484 d
->valuePal
->repaint( false );
1485 d
->bRecursion
= false;
1489 static QWidget
*kde_color_dlg_widget
= 0;
1492 static int kde_color_dlg_handler(XEvent
*event
)
1494 if (event
->type
== ButtonRelease
)
1496 QMouseEvent
e( QEvent::MouseButtonRelease
, QPoint(),
1497 QPoint(event
->xmotion
.x_root
, event
->xmotion
.y_root
) , 0, 0 );
1498 QApplication::sendEvent( kde_color_dlg_widget
, &e
);
1505 KColorDialog::slotColorPicker()
1507 d
->bColorPicking
= true;
1509 d
->oldfilter
= qt_set_x11_event_filter(kde_color_dlg_handler
);
1511 kde_color_dlg_widget
= this;
1512 grabMouse( crossCursor
);
1517 KColorDialog::mouseReleaseEvent( QMouseEvent
*e
)
1519 if (d
->bColorPicking
)
1521 d
->bColorPicking
= false;
1523 qt_set_x11_event_filter(d
->oldfilter
);
1528 _setColor( grabColor( e
->globalPos() ) );
1531 KDialogBase::mouseReleaseEvent( e
);
1535 KColorDialog::grabColor(const QPoint
&p
)
1537 QWidget
*desktop
= QApplication::desktop();
1538 QPixmap pm
= QPixmap::grabWindow( desktop
->winId(), p
.x(), p
.y(), 1, 1);
1539 QImage i
= pm
.convertToImage();
1540 return i
.pixel(0,0);
1544 KColorDialog::keyPressEvent( QKeyEvent
*e
)
1546 if (d
->bColorPicking
)
1548 if (e
->key() == Key_Escape
)
1550 d
->bColorPicking
= false;
1552 qt_set_x11_event_filter(d
->oldfilter
);
1561 KDialogBase::keyPressEvent( e
);
1564 void KColorDialog::setRgbEdit( const KColor
&col
)
1566 if (d
->bEditRgb
) return;
1568 col
.rgb( &r
, &g
, &b
);
1570 d
->redit
->setValue( r
);
1571 d
->gedit
->setValue( g
);
1572 d
->bedit
->setValue( b
);
1575 void KColorDialog::setHtmlEdit( const KColor
&col
)
1577 if (d
->bEditHtml
) return;
1579 col
.rgb( &r
, &g
, &b
);
1582 num
.sprintf("#%02X%02X%02X", r
,g
,b
);
1583 d
->htmlName
->setText( num
);
1587 void KColorDialog::setHsvEdit( const KColor
&col
)
1589 if (d
->bEditHsv
) return;
1591 col
.hsv( &h
, &s
, &v
);
1593 d
->hedit
->setValue( h
);
1594 d
->sedit
->setValue( s
);
1595 d
->vedit
->setValue( v
);
1598 void KHSSelector::virtual_hook( int id
, void* data
)
1599 { KXYSelector::virtual_hook( id
, data
); }
1601 void KValueSelector::virtual_hook( int id
, void* data
)
1602 { KSelector::virtual_hook( id
, data
); }
1604 void KPaletteTable::virtual_hook( int, void* )
1605 { /*BASE::virtual_hook( id, data );*/ }
1607 void KColorCells::virtual_hook( int, void* )
1608 { /*BASE::virtual_hook( id, data );*/ }
1610 void KColorPatch::virtual_hook( int, void* )
1611 { /*BASE::virtual_hook( id, data );*/ }
1613 void KColorDialog::virtual_hook( int id
, void* data
)
1614 { KDialogBase::virtual_hook( id
, data
); }
1617 #include "kcolordialog.moc"