Change to the linux kernel coding style
[wmaker-crm.git] / WINGs / wcolorpanel.c
1 /*
2  * ColorPanel for WINGs
3  *
4  * by   ]d                              : Original idea and basic initial code
5  *      Pascal Hofstee                  : Code for wheeldrawing and calculating
6  *                                        colors from it.
7  *                                        Primary coder of this Color Panel.
8  *      Alban Hertroys                  : Optimizations for algorithms for color-
9  *                                        wheel. Also custom ColorPalettes and
10  *                                        magnifying glass. Secondary coder ;)
11  *      Alfredo K. Kojima               : For pointing out memory-allocation
12  *                                        problems and similair code-issues
13  *      Marco van Hylckama-Vlieg        : For once again doing the artwork ;-)
14  *
15  */
16
17 /* TODO:
18  *      -       Look at further optimization of colorWheel matrix calculation.
19  *              It appears to be rather symmetric in angles of 60 degrees,
20  *              while it is optimized in angles of 90 degrees.
21  *      -       Custom color-lists and custom colors in custom color-lists.
22  *      -       Stored colors
23  *      -       Resizing
24  */
25
26 #include "wconfig.h"
27 #include "WINGsP.h"
28 #include "rgb.h"
29 #include <math.h>
30 #include <unistd.h>
31 #include <ctype.h>
32 #include <fcntl.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <dirent.h>
36 #include <errno.h>
37
38 /* BUG There's something fishy with shaped windows */
39 /* Whithout shape extension the magnified image is completely broken -Dan */
40 #if 0
41 # ifdef SHAPE
42 #  define SHAPE_WAS_DEFINED
43 #  undef SHAPE
44 # endif
45 #endif
46
47 #ifdef SHAPE
48 # include <X11/extensions/shape.h>
49 #endif
50
51 char *WMColorPanelColorChangedNotification = "WMColorPanelColorChangedNotification";
52
53 /*
54  * Bitmaps for magnifying glass cursor
55  */
56
57 /* Cursor */
58 #define Cursor_x_hot 11
59 #define Cursor_y_hot 11
60 #define Cursor_width 32
61 #define Cursor_height 32
62 static unsigned char Cursor_bits[] = {
63         0x00, 0x7e, 0x00, 0x00, 0xc0, 0x81, 0x03, 0x00, 0x20, 0x00, 0x04, 0x00, 0x10, 0x00, 0x08,
64         0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x20, 0x00, 0x02, 0x00, 0x40, 0x00, 0x02, 0x00,
65         0x40, 0x00, 0x02, 0x00, 0x40, 0x00, 0x01, 0x42, 0x80, 0x00, 0x01, 0x24, 0x80, 0x00, 0x01,
66         0x00, 0x80, 0x00, 0x01, 0x00, 0x80, 0x00, 0x01, 0x24, 0x80, 0x00, 0x01, 0x42, 0x80, 0x00,
67         0x02, 0x00, 0x40, 0x00, 0x02, 0x00, 0x40, 0x00, 0x02, 0x00, 0x40, 0x00, 0x04, 0x00, 0x20,
68         0x00, 0x08, 0x00, 0x50, 0x00, 0x10, 0x00, 0x88, 0x00, 0x20, 0x00, 0x5c, 0x01, 0xc0, 0x81,
69         0x3b, 0x02, 0x00, 0x7e, 0x70, 0x05, 0x00, 0x00, 0xe0, 0x08, 0x00, 0x00, 0xc0, 0x15, 0x00,
70         0x00, 0x80, 0x23, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x5c,
71         0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x70
72 };
73
74 /* Cursor shape-mask */
75 #define Cursor_shape_width 32
76 #define Cursor_shape_height 32
77 static unsigned char Cursor_shape_bits[] = {
78         0x00, 0x7e, 0x00, 0x00, 0xc0, 0x81, 0x03, 0x00, 0x20, 0x00, 0x04, 0x00, 0x10, 0x00, 0x08,
79         0x00, 0x08, 0x00, 0x10, 0x00, 0x04, 0x00, 0x20, 0x00, 0x02, 0x00, 0x40, 0x00, 0x02, 0x00,
80         0x40, 0x00, 0x02, 0x00, 0x40, 0x00, 0x01, 0x42, 0x80, 0x00, 0x01, 0x24, 0x80, 0x00, 0x01,
81         0x00, 0x80, 0x00, 0x01, 0x00, 0x80, 0x00, 0x01, 0x24, 0x80, 0x00, 0x01, 0x42, 0x80, 0x00,
82         0x02, 0x00, 0x40, 0x00, 0x02, 0x00, 0x40, 0x00, 0x02, 0x00, 0x40, 0x00, 0x04, 0x00, 0x20,
83         0x00, 0x08, 0x00, 0x70, 0x00, 0x10, 0x00, 0xf8, 0x00, 0x20, 0x00, 0xfc, 0x01, 0xc0, 0x81,
84         0xfb, 0x03, 0x00, 0x7e, 0xf0, 0x07, 0x00, 0x00, 0xe0, 0x0f, 0x00, 0x00, 0xc0, 0x1f, 0x00,
85         0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfc,
86         0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x70
87 };
88
89 /* Clip-mask for magnified pixels */
90 #define Cursor_mask_width 24
91 #define Cursor_mask_height 24
92 static unsigned char Cursor_mask_bits[] = {
93         0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0xc0, 0xff, 0x03, 0xe0, 0xff, 0x07,
94         0xf0, 0xff, 0x0f, 0xf8, 0xff, 0x1f, 0xfc, 0xff, 0x3f, 0xfc, 0xff, 0x3f,
95         0xfc, 0xff, 0x3f, 0xfe, 0xff, 0x7f, 0xfe, 0xff, 0x7f, 0xfe, 0xff, 0x7f,
96         0xfe, 0xff, 0x7f, 0xfe, 0xff, 0x7f, 0xfe, 0xff, 0x7f, 0xfc, 0xff, 0x3f,
97         0xfc, 0xff, 0x3f, 0xfc, 0xff, 0x3f, 0xf8, 0xff, 0x1f, 0xf0, 0xff, 0x0f,
98         0xe0, 0xff, 0x07, 0xc0, 0xff, 0x03, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00
99 };
100
101 typedef struct MovingView {
102         WMView *view;           /* The view this is all about */
103         XImage *image;          /* What's under the view */
104         XImage *dirtyRect;      /* Storage of overlapped image area */
105         Pixmap magPix;          /* Magnified part of pixmap */
106         RColor color;           /* Color of a pixel in the image */
107         int x, y;               /* Position of view */
108 } MovingView;
109
110 typedef struct CPColor {
111         RColor rgb;             /* The RGB values of the color  */
112         RHSVColor hsv;          /* The HSV values of the color  */
113         enum {                  /* Which one was last set ?     */
114                 cpNone,
115                 cpRGB,
116                 cpHSV
117         } set;
118 } CPColor;
119
120 typedef struct WheelMatrix {
121         unsigned int width, height;     /* Size of the colorwheel */
122         unsigned char *data[3]; /* Wheel data (R,G,B) */
123         unsigned char values[256];      /* Precalculated values R,G & B = 0-255 */
124 } wheelMatrix;
125
126 typedef struct W_ColorPanel {
127         WMWindow *win;
128         WMFont *font8;
129         WMFont *font12;
130         void *clientData;
131         WMAction2 *action;
132
133         /* Common Stuff */
134         WMColorWell *colorWell;
135         WMButton *magnifyBtn;
136         WMButton *wheelBtn;
137         WMButton *slidersBtn;
138         WMButton *customPaletteBtn;
139         WMButton *colorListBtn;
140
141         /* Magnifying Glass */
142         MovingView *magnifyGlass;
143
144         /* ColorWheel Panel */
145         WMFrame *wheelFrm;
146         WMSlider *wheelBrightnessS;
147         WMView *wheelView;
148
149         /* Slider Panels */
150         WMFrame *slidersFrm;
151         WMFrame *seperatorFrm;
152         WMButton *grayBtn;
153         WMButton *rgbBtn;
154         WMButton *cmykBtn;
155         WMButton *hsbBtn;
156         /* Gray Scale Panel */
157         WMFrame *grayFrm;
158         WMLabel *grayMinL;
159         WMLabel *grayMaxL;
160         WMSlider *grayBrightnessS;
161         WMTextField *grayBrightnessT;
162         WMButton *grayPresetBtn[7];
163
164         /* RGB Panel */
165         WMFrame *rgbFrm;
166         WMLabel *rgbMinL;
167         WMLabel *rgbMaxL;
168         WMSlider *rgbRedS;
169         WMSlider *rgbGreenS;
170         WMSlider *rgbBlueS;
171         WMTextField *rgbRedT;
172         WMTextField *rgbGreenT;
173         WMTextField *rgbBlueT;
174
175         /* CMYK Panel */
176         WMFrame *cmykFrm;
177         WMLabel *cmykMinL;
178         WMLabel *cmykMaxL;
179         WMSlider *cmykCyanS;
180         WMSlider *cmykMagentaS;
181         WMSlider *cmykYellowS;
182         WMSlider *cmykBlackS;
183         WMTextField *cmykCyanT;
184         WMTextField *cmykMagentaT;
185         WMTextField *cmykYellowT;
186         WMTextField *cmykBlackT;
187
188         /* HSB Panel */
189         WMFrame *hsbFrm;
190         WMSlider *hsbHueS;
191         WMSlider *hsbSaturationS;
192         WMSlider *hsbBrightnessS;
193         WMTextField *hsbHueT;
194         WMTextField *hsbSaturationT;
195         WMTextField *hsbBrightnessT;
196
197         /* Custom Palette Panel */
198         WMFrame *customPaletteFrm;
199         WMPopUpButton *customPaletteHistoryBtn;
200         WMFrame *customPaletteContentFrm;
201         WMPopUpButton *customPaletteMenuBtn;
202         WMView *customPaletteContentView;
203
204         /* Color List Panel */
205         WMFrame *colorListFrm;
206         WMPopUpButton *colorListHistoryBtn;
207         WMList *colorListContentLst;
208         WMPopUpButton *colorListColorMenuBtn;
209         WMPopUpButton *colorListListMenuBtn;
210
211         /* Look-Up Tables and Images */
212         wheelMatrix *wheelMtrx;
213         Pixmap wheelImg;
214         Pixmap selectionImg;
215         Pixmap selectionBackImg;
216         RImage *customPaletteImg;
217         char *lastBrowseDir;
218
219         /* Common Data Fields */
220         CPColor color;          /* Current color */
221         WMColorPanelMode mode;  /* Current color selection mode */
222         WMColorPanelMode slidersmode;   /* Current color sel. mode sliders panel */
223         WMColorPanelMode lastChanged;   /* Panel that last changed the color */
224         int colx, coly;         /* (x,y) of sel.-marker in WheelMode */
225         int palx, paly;         /* (x,y) of sel.-marker in
226                                    CustomPaletteMode */
227         double palXRatio, palYRatio;    /* Ratios in x & y between
228                                            original and scaled
229                                            palettesize */
230         int currentPalette;
231         char *configurationPath;
232
233         struct {
234                 unsigned int continuous:1;
235                 unsigned int dragging:1;
236         } flags;
237 } W_ColorPanel;
238
239 enum {
240         CPmenuNewFromFile,
241         CPmenuRename,
242         CPmenuRemove,
243         CPmenuCopy,
244         CPmenuNewFromClipboard
245 } customPaletteMenuItem;
246
247 enum {
248         CLmenuAdd,
249         CLmenuRename,
250         CLmenuRemove
251 } colorListMenuItem;
252
253 #define PWIDTH                  194
254 #define PHEIGHT                 266
255 #define colorWheelSize          150
256 #define customPaletteWidth      182
257 #define customPaletteHeight     106
258 #define knobThickness           8
259
260 #define SPECTRUM_WIDTH          511
261 #define SPECTRUM_HEIGHT         360
262
263 #define COLORWHEEL_PART         1
264 #define CUSTOMPALETTE_PART      2
265 #define BUFSIZE                 1024
266
267 #define MAX_LENGTH              1024
268
269 #ifndef M_PI
270 #define M_PI 3.14159265358979323846
271 #endif
272
273 /* Silly hack for Windows systems with cygwin */
274 #ifndef O_BINARY
275 # define O_BINARY 0
276 #endif
277
278 static int fetchFile(char *toPath, char *imageSrcFile, char *imageDestFileName);
279 char *generateNewFilename(char *curName);
280 void convertCPColor(CPColor * color);
281 RColor ulongToRColor(WMScreen * scr, unsigned long value);
282 unsigned char getShift(unsigned char value);
283
284 static void modeButtonCallback(WMWidget * w, void *data);
285 static int getPickerPart(W_ColorPanel * panel, int x, int y);
286 static void readConfiguration(W_ColorPanel * panel);
287 static void readXColors(W_ColorPanel * panel);
288
289 static void closeWindowCallback(WMWidget * w, void *data);
290
291 static Cursor magnifyGrabPointer(W_ColorPanel * panel);
292 static WMPoint magnifyInitialize(W_ColorPanel * panel);
293 static void magnifyPutCursor(WMWidget * w, void *data);
294 static Pixmap magnifyCreatePixmap(WMColorPanel * panel);
295 static void magnifyGetImageStored(W_ColorPanel * panel, int x1, int y1, int x2, int y2);
296 static XImage *magnifyGetImage(WMScreen * scr, XImage * image, int x, int y, int w, int h);
297
298 static wheelMatrix *wheelCreateMatrix(unsigned int width, unsigned int height);
299 static void wheelDestroyMatrix(wheelMatrix * matrix);
300 static void wheelInitMatrix(W_ColorPanel * panel);
301 static void wheelCalculateValues(W_ColorPanel * panel, int maxvalue);
302 static void wheelRender(W_ColorPanel * panel);
303 static Bool wheelInsideColorWheel(W_ColorPanel * panel, unsigned long ofs);
304 static void wheelPaint(W_ColorPanel * panel);
305
306 static void wheelHandleEvents(XEvent * event, void *data);
307 static void wheelHandleActionEvents(XEvent * event, void *data);
308 static void wheelBrightnessSliderCallback(WMWidget * w, void *data);
309 static void wheelUpdateSelection(W_ColorPanel * panel);
310 static void wheelUndrawSelection(W_ColorPanel * panel);
311
312 static void wheelPositionSelection(W_ColorPanel * panel, int x, int y);
313 static void wheelPositionSelectionOutBounds(W_ColorPanel * panel, int x, int y);
314 static void wheelUpdateBrightnessGradientFromLocation(W_ColorPanel * panel);
315 static void wheelUpdateBrightnessGradient(W_ColorPanel * panel, CPColor topColor);
316
317 static void grayBrightnessSliderCallback(WMWidget * w, void *data);
318 static void grayPresetButtonCallback(WMWidget * w, void *data);
319 static void grayBrightnessTextFieldCallback(void *observerData, WMNotification * notification);
320
321 static void rgbSliderCallback(WMWidget * w, void *data);
322 static void rgbTextFieldCallback(void *observerData, WMNotification * notification);
323
324 static void cmykSliderCallback(WMWidget * w, void *data);
325 static void cmykTextFieldCallback(void *observerData, WMNotification * notification);
326
327 static void hsbSliderCallback(WMWidget * w, void *data);
328 static void hsbTextFieldCallback(void *observerData, WMNotification * notification);
329 static void hsbUpdateBrightnessGradient(W_ColorPanel * panel);
330 static void hsbUpdateSaturationGradient(W_ColorPanel * panel);
331 static void hsbUpdateHueGradient(W_ColorPanel * panel);
332
333 static void customRenderSpectrum(W_ColorPanel * panel);
334 static void customSetPalette(W_ColorPanel * panel);
335 static void customPaletteHandleEvents(XEvent * event, void *data);
336 static void customPaletteHandleActionEvents(XEvent * event, void *data);
337 static void customPalettePositionSelection(W_ColorPanel * panel, int x, int y);
338 static void customPalettePositionSelectionOutBounds(W_ColorPanel * panel, int x, int y);
339 static void customPaletteMenuCallback(WMWidget * w, void *data);
340 static void customPaletteHistoryCallback(WMWidget * w, void *data);
341
342 static void customPaletteMenuNewFromFile(W_ColorPanel * panel);
343 static void customPaletteMenuRename(W_ColorPanel * panel);
344 static void customPaletteMenuRemove(W_ColorPanel * panel);
345
346 static void colorListPaintItem(WMList * lPtr, int index, Drawable d, char *text, int state, WMRect * rect);
347 static void colorListSelect(WMWidget * w, void *data);
348 static void colorListColorMenuCallback(WMWidget * w, void *data);
349 static void colorListListMenuCallback(WMWidget * w, void *data);
350 static void colorListListMenuNew(W_ColorPanel * panel);
351
352 static void wheelInit(W_ColorPanel * panel);
353 static void grayInit(W_ColorPanel * panel);
354 static void rgbInit(W_ColorPanel * panel);
355 static void cmykInit(W_ColorPanel * panel);
356 static void hsbInit(W_ColorPanel * panel);
357
358 void WMSetColorPanelAction(WMColorPanel * panel, WMAction2 * action, void *data)
359 {
360         panel->action = action;
361         panel->clientData = data;
362 }
363
364 static WMColorPanel *makeColorPanel(WMScreen * scrPtr, char *name)
365 {
366         WMColorPanel *panel;
367         RImage *image;
368         WMPixmap *pixmap;
369         RColor from;
370         RColor to;
371         WMColor *textcolor, *graybuttoncolor;
372         int i;
373         GC bgc = WMColorGC(scrPtr->black);
374         GC wgc = WMColorGC(scrPtr->white);
375
376         panel = wmalloc(sizeof(WMColorPanel));
377         memset(panel, 0, sizeof(WMColorPanel));
378
379         panel->color.rgb.red = 0;
380         panel->color.rgb.green = 0;
381         panel->color.rgb.blue = 0;
382         panel->color.hsv.hue = 0;
383         panel->color.hsv.saturation = 0;
384         panel->color.hsv.value = 0;
385         panel->color.set = cpNone;      /* Color has not been set yet */
386
387         panel->font8 = WMSystemFontOfSize(scrPtr, 8);
388         panel->font12 = WMSystemFontOfSize(scrPtr, 12);
389
390         panel->win = WMCreateWindowWithStyle(scrPtr, name,
391                                              WMTitledWindowMask | WMClosableWindowMask | WMResizableWindowMask);
392         WMResizeWidget(panel->win, PWIDTH, PHEIGHT);
393         WMSetWindowTitle(panel->win, _("Colors"));
394         WMSetWindowCloseAction(panel->win, closeWindowCallback, panel);
395
396         /* Set Default ColorPanel Mode(s) */
397         panel->mode = WMWheelModeColorPanel;
398         panel->lastChanged = 0;
399         panel->slidersmode = WMRGBModeColorPanel;
400         panel->configurationPath = wstrconcat(wusergnusteppath(), "/Library/Colors/");
401
402         /* Some General Purpose Widgets */
403         panel->colorWell = WMCreateColorWell(panel->win);
404         WMResizeWidget(panel->colorWell, 134, 36);
405         WSetColorWellBordered(panel->colorWell, False);
406         WMMoveWidget(panel->colorWell, 56, 4);
407
408         panel->magnifyBtn = WMCreateCustomButton(panel->win, WBBStateLightMask | WBBStateChangeMask);
409         WMResizeWidget(panel->magnifyBtn, 46, 36);
410         WMMoveWidget(panel->magnifyBtn, 6, 4);
411         WMSetButtonAction(panel->magnifyBtn, magnifyPutCursor, panel);
412         WMSetButtonImagePosition(panel->magnifyBtn, WIPImageOnly);
413         WMSetButtonImage(panel->magnifyBtn, scrPtr->magnifyIcon);
414
415         panel->wheelBtn = WMCreateCustomButton(panel->win, WBBStateLightMask | WBBStateChangeMask);
416         WMResizeWidget(panel->wheelBtn, 46, 32);
417         WMMoveWidget(panel->wheelBtn, 6, 44);
418         WMSetButtonAction(panel->wheelBtn, modeButtonCallback, panel);
419         WMSetButtonImagePosition(panel->wheelBtn, WIPImageOnly);
420         WMSetButtonImage(panel->wheelBtn, scrPtr->wheelIcon);
421
422         panel->slidersBtn = WMCreateCustomButton(panel->win, WBBStateLightMask | WBBStateChangeMask);
423         WMResizeWidget(panel->slidersBtn, 46, 32);
424         WMMoveWidget(panel->slidersBtn, 52, 44);
425         WMSetButtonAction(panel->slidersBtn, modeButtonCallback, panel);
426         WMSetButtonImagePosition(panel->slidersBtn, WIPImageOnly);
427         WMSetButtonImage(panel->slidersBtn, scrPtr->rgbIcon);
428
429         panel->customPaletteBtn = WMCreateCustomButton(panel->win, WBBStateLightMask | WBBStateChangeMask);
430         WMResizeWidget(panel->customPaletteBtn, 46, 32);
431         WMMoveWidget(panel->customPaletteBtn, 98, 44);
432         WMSetButtonAction(panel->customPaletteBtn, modeButtonCallback, panel);
433         WMSetButtonImagePosition(panel->customPaletteBtn, WIPImageOnly);
434         WMSetButtonImage(panel->customPaletteBtn, scrPtr->customPaletteIcon);
435
436         panel->colorListBtn = WMCreateCustomButton(panel->win, WBBStateLightMask | WBBStateChangeMask);
437         WMResizeWidget(panel->colorListBtn, 46, 32);
438         WMMoveWidget(panel->colorListBtn, 144, 44);
439         WMSetButtonAction(panel->colorListBtn, modeButtonCallback, panel);
440         WMSetButtonImagePosition(panel->colorListBtn, WIPImageOnly);
441         WMSetButtonImage(panel->colorListBtn, scrPtr->colorListIcon);
442
443         /* Let's Group some of them together */
444         WMGroupButtons(panel->wheelBtn, panel->slidersBtn);
445         WMGroupButtons(panel->wheelBtn, panel->customPaletteBtn);
446         WMGroupButtons(panel->wheelBtn, panel->colorListBtn);
447
448         /* Widgets for the ColorWheel Panel */
449         panel->wheelFrm = WMCreateFrame(panel->win);
450         WMSetFrameRelief(panel->wheelFrm, WRFlat);
451         WMResizeWidget(panel->wheelFrm, PWIDTH - 8, PHEIGHT - 80 - 26);
452         WMMoveWidget(panel->wheelFrm, 5, 80);
453
454         panel->wheelView = W_CreateView(W_VIEW(panel->wheelFrm));
455         /* XXX Can we create a view ? */
456         W_ResizeView(panel->wheelView, colorWheelSize + 4, colorWheelSize + 4);
457         W_MoveView(panel->wheelView, 0, 0);
458
459         /* Create an event handler to handle expose/click events in ColorWheel */
460         WMCreateEventHandler(panel->wheelView,
461                              ButtonPressMask | ButtonReleaseMask | EnterWindowMask |
462                              LeaveWindowMask | ButtonMotionMask, wheelHandleActionEvents, panel);
463
464         WMCreateEventHandler(panel->wheelView, ExposureMask, wheelHandleEvents, panel);
465
466         panel->wheelBrightnessS = WMCreateSlider(panel->wheelFrm);
467         WMResizeWidget(panel->wheelBrightnessS, 16, 153);
468         WMMoveWidget(panel->wheelBrightnessS, 5 + colorWheelSize + 14, 1);
469         WMSetSliderMinValue(panel->wheelBrightnessS, 0);
470         WMSetSliderMaxValue(panel->wheelBrightnessS, 255);
471         WMSetSliderAction(panel->wheelBrightnessS, wheelBrightnessSliderCallback, panel);
472         WMSetSliderKnobThickness(panel->wheelBrightnessS, knobThickness);
473
474         panel->wheelMtrx = wheelCreateMatrix(colorWheelSize + 4, colorWheelSize + 4);
475         wheelInitMatrix(panel);
476
477         /* Widgets for the Slider Panels */
478         panel->slidersFrm = WMCreateFrame(panel->win);
479         WMSetFrameRelief(panel->slidersFrm, WRFlat);
480         WMResizeWidget(panel->slidersFrm, PWIDTH - 8, PHEIGHT - 80 - 26);
481         WMMoveWidget(panel->slidersFrm, 4, 80);
482
483         panel->seperatorFrm = WMCreateFrame(panel->slidersFrm);
484         WMSetFrameRelief(panel->seperatorFrm, WRPushed);
485         WMResizeWidget(panel->seperatorFrm, PWIDTH - 8, 2);
486         WMMoveWidget(panel->seperatorFrm, 0, 1);
487
488         panel->grayBtn = WMCreateCustomButton(panel->slidersFrm, WBBStateLightMask | WBBStateChangeMask);
489         WMResizeWidget(panel->grayBtn, 46, 24);
490         WMMoveWidget(panel->grayBtn, 1, 8);
491         WMSetButtonAction(panel->grayBtn, modeButtonCallback, panel);
492         WMSetButtonImagePosition(panel->grayBtn, WIPImageOnly);
493         WMSetButtonImage(panel->grayBtn, scrPtr->grayIcon);
494
495         panel->rgbBtn = WMCreateCustomButton(panel->slidersFrm, WBBStateLightMask | WBBStateChangeMask);
496         WMResizeWidget(panel->rgbBtn, 46, 24);
497         WMMoveWidget(panel->rgbBtn, 47, 8);
498         WMSetButtonAction(panel->rgbBtn, modeButtonCallback, panel);
499         WMSetButtonImagePosition(panel->rgbBtn, WIPImageOnly);
500         WMSetButtonImage(panel->rgbBtn, scrPtr->rgbIcon);
501
502         panel->cmykBtn = WMCreateCustomButton(panel->slidersFrm, WBBStateLightMask | WBBStateChangeMask);
503         WMResizeWidget(panel->cmykBtn, 46, 24);
504         WMMoveWidget(panel->cmykBtn, 93, 8);
505         WMSetButtonAction(panel->cmykBtn, modeButtonCallback, panel);
506         WMSetButtonImagePosition(panel->cmykBtn, WIPImageOnly);
507         WMSetButtonImage(panel->cmykBtn, scrPtr->cmykIcon);
508
509         panel->hsbBtn = WMCreateCustomButton(panel->slidersFrm, WBBStateLightMask | WBBStateChangeMask);
510         WMResizeWidget(panel->hsbBtn, 46, 24);
511         WMMoveWidget(panel->hsbBtn, 139, 8);
512         WMSetButtonAction(panel->hsbBtn, modeButtonCallback, panel);
513         WMSetButtonImagePosition(panel->hsbBtn, WIPImageOnly);
514         WMSetButtonImage(panel->hsbBtn, scrPtr->hsbIcon);
515
516         /* Let's Group the Slider Panel Buttons Together */
517         WMGroupButtons(panel->grayBtn, panel->rgbBtn);
518         WMGroupButtons(panel->grayBtn, panel->cmykBtn);
519         WMGroupButtons(panel->grayBtn, panel->hsbBtn);
520
521         textcolor = WMDarkGrayColor(scrPtr);
522
523         /* Widgets for GrayScale Panel */
524         panel->grayFrm = WMCreateFrame(panel->slidersFrm);
525         WMSetFrameRelief(panel->grayFrm, WRFlat);
526         WMResizeWidget(panel->grayFrm, PWIDTH - 8, PHEIGHT - 80 - 26 - 32);
527         WMMoveWidget(panel->grayFrm, 0, 34);
528
529         panel->grayMinL = WMCreateLabel(panel->grayFrm);
530         WMResizeWidget(panel->grayMinL, 20, 10);
531         WMMoveWidget(panel->grayMinL, 2, 2);
532         WMSetLabelText(panel->grayMinL, "0");
533         WMSetLabelTextAlignment(panel->grayMinL, WALeft);
534         WMSetLabelTextColor(panel->grayMinL, textcolor);
535         WMSetLabelFont(panel->grayMinL, panel->font8);
536
537         panel->grayMaxL = WMCreateLabel(panel->grayFrm);
538         WMResizeWidget(panel->grayMaxL, 40, 10);
539         WMMoveWidget(panel->grayMaxL, 104, 2);
540         WMSetLabelText(panel->grayMaxL, "100");
541         WMSetLabelTextAlignment(panel->grayMaxL, WARight);
542         WMSetLabelTextColor(panel->grayMaxL, textcolor);
543         WMSetLabelFont(panel->grayMaxL, panel->font8);
544
545         panel->grayBrightnessS = WMCreateSlider(panel->grayFrm);
546         WMResizeWidget(panel->grayBrightnessS, 141, 16);
547         WMMoveWidget(panel->grayBrightnessS, 2, 14);
548         WMSetSliderMinValue(panel->grayBrightnessS, 0);
549         WMSetSliderMaxValue(panel->grayBrightnessS, 100);
550         WMSetSliderKnobThickness(panel->grayBrightnessS, knobThickness);
551         WMSetSliderAction(panel->grayBrightnessS, grayBrightnessSliderCallback, panel);
552
553         from.red = 0;
554         from.green = 0;
555         from.blue = 0;
556
557         to.red = 255;
558         to.green = 255;
559         to.blue = 255;
560
561         image = RRenderGradient(141, 16, &from, &to, RGRD_HORIZONTAL);
562         pixmap = WMCreatePixmapFromRImage(scrPtr, image, 0);
563         RReleaseImage(image);
564
565         if (pixmap)
566                 W_PaintText(W_VIEW(panel->grayBrightnessS), pixmap->pixmap,
567                             panel->font12, 2, 0, 100, WALeft, scrPtr->white,
568                             False, _("Brightness"), strlen(_("Brightness")));
569         else
570                 wwarning(_("Color Panel: Could not allocate memory"));
571
572         WMSetSliderImage(panel->grayBrightnessS, pixmap);
573         WMReleasePixmap(pixmap);
574
575         panel->grayBrightnessT = WMCreateTextField(panel->grayFrm);
576         WMResizeWidget(panel->grayBrightnessT, 40, 18);
577         WMMoveWidget(panel->grayBrightnessT, 146, 13);
578         WMSetTextFieldAlignment(panel->grayBrightnessT, WALeft);
579         WMAddNotificationObserver(grayBrightnessTextFieldCallback, panel,
580                                   WMTextDidEndEditingNotification, panel->grayBrightnessT);
581
582         for (i = 0; i < 7; i++) {
583                 pixmap = WMCreatePixmap(scrPtr, 13, 13, scrPtr->depth, False);
584
585                 graybuttoncolor = WMCreateRGBColor(scrPtr, (255 / 6) * i << 8,
586                                                    (255 / 6) * i << 8, (255 / 6) * i << 8, True);
587                 WMPaintColorSwatch(graybuttoncolor, pixmap->pixmap, 0, 0, 15, 15);
588                 WMReleaseColor(graybuttoncolor);
589
590                 panel->grayPresetBtn[i] = WMCreateCommandButton(panel->grayFrm);
591                 WMResizeWidget(panel->grayPresetBtn[i], 20, 24);
592                 WMMoveWidget(panel->grayPresetBtn[i], 2 + (i * 20), 34);
593                 WMSetButtonAction(panel->grayPresetBtn[i], grayPresetButtonCallback, panel);
594                 WMSetButtonImage(panel->grayPresetBtn[i], pixmap);
595                 WMSetButtonImagePosition(panel->grayPresetBtn[i], WIPImageOnly);
596                 WMReleasePixmap(pixmap);
597
598         }
599
600         /* End of GrayScale Panel */
601
602         /* Widgets for RGB Panel */
603         panel->rgbFrm = WMCreateFrame(panel->slidersFrm);
604         WMSetFrameRelief(panel->rgbFrm, WRFlat);
605         WMResizeWidget(panel->rgbFrm, PWIDTH - 8, PHEIGHT - 80 - 26 - 32);
606         WMMoveWidget(panel->rgbFrm, 0, 34);
607
608         panel->rgbMinL = WMCreateLabel(panel->rgbFrm);
609         WMResizeWidget(panel->rgbMinL, 20, 10);
610         WMMoveWidget(panel->rgbMinL, 2, 2);
611         WMSetLabelText(panel->rgbMinL, "0");
612         WMSetLabelTextAlignment(panel->rgbMinL, WALeft);
613         WMSetLabelTextColor(panel->rgbMinL, textcolor);
614         WMSetLabelFont(panel->rgbMinL, panel->font8);
615
616         panel->rgbMaxL = WMCreateLabel(panel->rgbFrm);
617         WMResizeWidget(panel->rgbMaxL, 40, 10);
618         WMMoveWidget(panel->rgbMaxL, 104, 2);
619         WMSetLabelText(panel->rgbMaxL, "255");
620         WMSetLabelTextAlignment(panel->rgbMaxL, WARight);
621         WMSetLabelTextColor(panel->rgbMaxL, textcolor);
622         WMSetLabelFont(panel->rgbMaxL, panel->font8);
623
624         panel->rgbRedS = WMCreateSlider(panel->rgbFrm);
625         WMResizeWidget(panel->rgbRedS, 141, 16);
626         WMMoveWidget(panel->rgbRedS, 2, 14);
627         WMSetSliderMinValue(panel->rgbRedS, 0);
628         WMSetSliderMaxValue(panel->rgbRedS, 255);
629         WMSetSliderKnobThickness(panel->rgbRedS, knobThickness);
630         WMSetSliderAction(panel->rgbRedS, rgbSliderCallback, panel);
631
632         to.red = 255;
633         to.green = 0;
634         to.blue = 0;
635
636         image = RRenderGradient(141, 16, &from, &to, RGRD_HORIZONTAL);
637         pixmap = WMCreatePixmapFromRImage(scrPtr, image, 0);
638         RReleaseImage(image);
639
640         if (pixmap)
641                 W_PaintText(W_VIEW(panel->rgbRedS), pixmap->pixmap, panel->font12,
642                             2, 0, 100, WALeft, scrPtr->white, False, _("Red"), strlen(_("Red")));
643         else
644                 wwarning(_("Color Panel: Could not allocate memory"));
645
646         WMSetSliderImage(panel->rgbRedS, pixmap);
647         WMReleasePixmap(pixmap);
648
649         panel->rgbRedT = WMCreateTextField(panel->rgbFrm);
650         WMResizeWidget(panel->rgbRedT, 40, 18);
651         WMMoveWidget(panel->rgbRedT, 146, 13);
652         WMSetTextFieldAlignment(panel->rgbRedT, WALeft);
653         WMAddNotificationObserver(rgbTextFieldCallback, panel, WMTextDidEndEditingNotification, panel->rgbRedT);
654
655         panel->rgbGreenS = WMCreateSlider(panel->rgbFrm);
656         WMResizeWidget(panel->rgbGreenS, 141, 16);
657         WMMoveWidget(panel->rgbGreenS, 2, 36);
658         WMSetSliderMinValue(panel->rgbGreenS, 0);
659         WMSetSliderMaxValue(panel->rgbGreenS, 255);
660         WMSetSliderKnobThickness(panel->rgbGreenS, knobThickness);
661         WMSetSliderAction(panel->rgbGreenS, rgbSliderCallback, panel);
662
663         to.red = 0;
664         to.green = 255;
665         to.blue = 0;
666
667         image = RRenderGradient(141, 16, &from, &to, RGRD_HORIZONTAL);
668         pixmap = WMCreatePixmapFromRImage(scrPtr, image, 0);
669         RReleaseImage(image);
670
671         if (pixmap)
672                 W_PaintText(W_VIEW(panel->rgbGreenS), pixmap->pixmap, panel->font12,
673                             2, 0, 100, WALeft, scrPtr->white, False, _("Green"), strlen(_("Green")));
674         else
675                 wwarning(_("Color Panel: Could not allocate memory"));
676
677         WMSetSliderImage(panel->rgbGreenS, pixmap);
678         WMReleasePixmap(pixmap);
679
680         panel->rgbGreenT = WMCreateTextField(panel->rgbFrm);
681         WMResizeWidget(panel->rgbGreenT, 40, 18);
682         WMMoveWidget(panel->rgbGreenT, 146, 35);
683         WMSetTextFieldAlignment(panel->rgbGreenT, WALeft);
684         WMAddNotificationObserver(rgbTextFieldCallback, panel, WMTextDidEndEditingNotification, panel->rgbGreenT);
685
686         panel->rgbBlueS = WMCreateSlider(panel->rgbFrm);
687         WMResizeWidget(panel->rgbBlueS, 141, 16);
688         WMMoveWidget(panel->rgbBlueS, 2, 58);
689         WMSetSliderMinValue(panel->rgbBlueS, 0);
690         WMSetSliderMaxValue(panel->rgbBlueS, 255);
691         WMSetSliderKnobThickness(panel->rgbBlueS, knobThickness);
692         WMSetSliderAction(panel->rgbBlueS, rgbSliderCallback, panel);
693
694         to.red = 0;
695         to.green = 0;
696         to.blue = 255;
697
698         image = RRenderGradient(141, 16, &from, &to, RGRD_HORIZONTAL);
699         pixmap = WMCreatePixmapFromRImage(scrPtr, image, 0);
700         RReleaseImage(image);
701
702         if (pixmap)
703                 W_PaintText(W_VIEW(panel->rgbBlueS), pixmap->pixmap, panel->font12,
704                             2, 0, 100, WALeft, scrPtr->white, False, _("Blue"), strlen(_("Blue")));
705         else
706                 wwarning(_("Color Panel: Could not allocate memory"));
707
708         WMSetSliderImage(panel->rgbBlueS, pixmap);
709         WMReleasePixmap(pixmap);
710
711         panel->rgbBlueT = WMCreateTextField(panel->rgbFrm);
712         WMResizeWidget(panel->rgbBlueT, 40, 18);
713         WMMoveWidget(panel->rgbBlueT, 146, 57);
714         WMSetTextFieldAlignment(panel->rgbBlueT, WALeft);
715         WMAddNotificationObserver(rgbTextFieldCallback, panel, WMTextDidEndEditingNotification, panel->rgbBlueT);
716         /* End of RGB Panel */
717
718         /* Widgets for CMYK Panel */
719         panel->cmykFrm = WMCreateFrame(panel->slidersFrm);
720         WMSetFrameRelief(panel->cmykFrm, WRFlat);
721         WMResizeWidget(panel->cmykFrm, PWIDTH - 8, PHEIGHT - 80 - 26 - 32);
722         WMMoveWidget(panel->cmykFrm, 0, 34);
723
724         panel->cmykMinL = WMCreateLabel(panel->cmykFrm);
725         WMResizeWidget(panel->cmykMinL, 20, 10);
726         WMMoveWidget(panel->cmykMinL, 2, 2);
727         WMSetLabelText(panel->cmykMinL, "0");
728         WMSetLabelTextAlignment(panel->cmykMinL, WALeft);
729         WMSetLabelTextColor(panel->cmykMinL, textcolor);
730         WMSetLabelFont(panel->cmykMinL, panel->font8);
731
732         panel->cmykMaxL = WMCreateLabel(panel->cmykFrm);
733         WMResizeWidget(panel->cmykMaxL, 40, 10);
734         WMMoveWidget(panel->cmykMaxL, 104, 2);
735         WMSetLabelText(panel->cmykMaxL, "100");
736         WMSetLabelTextAlignment(panel->cmykMaxL, WARight);
737         WMSetLabelTextColor(panel->cmykMaxL, textcolor);
738         WMSetLabelFont(panel->cmykMaxL, panel->font8);
739
740         panel->cmykCyanS = WMCreateSlider(panel->cmykFrm);
741         WMResizeWidget(panel->cmykCyanS, 141, 16);
742         WMMoveWidget(panel->cmykCyanS, 2, 14);
743         WMSetSliderMinValue(panel->cmykCyanS, 0);
744         WMSetSliderMaxValue(panel->cmykCyanS, 100);
745         WMSetSliderKnobThickness(panel->cmykCyanS, knobThickness);
746         WMSetSliderAction(panel->cmykCyanS, cmykSliderCallback, panel);
747
748         from.red = 255;
749         from.green = 255;
750         from.blue = 255;
751
752         to.red = 0;
753         to.green = 255;
754         to.blue = 255;
755
756         image = RRenderGradient(141, 16, &from, &to, RGRD_HORIZONTAL);
757         pixmap = WMCreatePixmapFromRImage(scrPtr, image, 0);
758         RReleaseImage(image);
759
760         if (pixmap)
761                 W_PaintText(W_VIEW(panel->cmykCyanS), pixmap->pixmap, panel->font12,
762                             2, 0, 100, WALeft, scrPtr->black, False, _("Cyan"), strlen(_("Cyan")));
763         else
764                 wwarning(_("Color Panel: Could not allocate memory"));
765
766         WMSetSliderImage(panel->cmykCyanS, pixmap);
767         WMReleasePixmap(pixmap);
768
769         panel->cmykCyanT = WMCreateTextField(panel->cmykFrm);
770         WMResizeWidget(panel->cmykCyanT, 40, 18);
771         WMMoveWidget(panel->cmykCyanT, 146, 13);
772         WMSetTextFieldAlignment(panel->cmykCyanT, WALeft);
773         WMAddNotificationObserver(cmykTextFieldCallback, panel, WMTextDidEndEditingNotification, panel->cmykCyanT);
774
775         panel->cmykMagentaS = WMCreateSlider(panel->cmykFrm);
776         WMResizeWidget(panel->cmykMagentaS, 141, 16);
777         WMMoveWidget(panel->cmykMagentaS, 2, 36);
778         WMSetSliderMinValue(panel->cmykMagentaS, 0);
779         WMSetSliderMaxValue(panel->cmykMagentaS, 100);
780         WMSetSliderKnobThickness(panel->cmykMagentaS, knobThickness);
781         WMSetSliderAction(panel->cmykMagentaS, cmykSliderCallback, panel);
782
783         to.red = 255;
784         to.green = 0;
785         to.blue = 255;
786
787         image = RRenderGradient(141, 16, &from, &to, RGRD_HORIZONTAL);
788         pixmap = WMCreatePixmapFromRImage(scrPtr, image, 0);
789         RReleaseImage(image);
790
791         if (pixmap)
792                 W_PaintText(W_VIEW(panel->cmykMagentaS), pixmap->pixmap, panel->font12,
793                             2, 0, 100, WALeft, scrPtr->black, False, _("Magenta"), strlen(_("Magenta")));
794         else
795                 wwarning(_("Color Panel: Could not allocate memory"));
796
797         WMSetSliderImage(panel->cmykMagentaS, pixmap);
798         WMReleasePixmap(pixmap);
799
800         panel->cmykMagentaT = WMCreateTextField(panel->cmykFrm);
801         WMResizeWidget(panel->cmykMagentaT, 40, 18);
802         WMMoveWidget(panel->cmykMagentaT, 146, 35);
803         WMSetTextFieldAlignment(panel->cmykMagentaT, WALeft);
804         WMAddNotificationObserver(cmykTextFieldCallback, panel,
805                                   WMTextDidEndEditingNotification, panel->cmykMagentaT);
806
807         panel->cmykYellowS = WMCreateSlider(panel->cmykFrm);
808         WMResizeWidget(panel->cmykYellowS, 141, 16);
809         WMMoveWidget(panel->cmykYellowS, 2, 58);
810         WMSetSliderMinValue(panel->cmykYellowS, 0);
811         WMSetSliderMaxValue(panel->cmykYellowS, 100);
812         WMSetSliderKnobThickness(panel->cmykYellowS, knobThickness);
813         WMSetSliderAction(panel->cmykYellowS, cmykSliderCallback, panel);
814
815         to.red = 255;
816         to.green = 255;
817         to.blue = 0;
818
819         image = RRenderGradient(141, 16, &from, &to, RGRD_HORIZONTAL);
820         pixmap = WMCreatePixmapFromRImage(scrPtr, image, 0);
821         RReleaseImage(image);
822
823         if (pixmap)
824                 W_PaintText(W_VIEW(panel->cmykYellowS), pixmap->pixmap, panel->font12,
825                             2, 0, 100, WALeft, scrPtr->black, False, _("Yellow"), strlen(_("Yellow")));
826         else
827                 wwarning(_("Color Panel: Could not allocate memory"));
828
829         WMSetSliderImage(panel->cmykYellowS, pixmap);
830         WMReleasePixmap(pixmap);
831
832         panel->cmykYellowT = WMCreateTextField(panel->cmykFrm);
833         WMResizeWidget(panel->cmykYellowT, 40, 18);
834         WMMoveWidget(panel->cmykYellowT, 146, 57);
835         WMSetTextFieldAlignment(panel->cmykYellowT, WALeft);
836         WMAddNotificationObserver(cmykTextFieldCallback, panel,
837                                   WMTextDidEndEditingNotification, panel->cmykYellowT);
838
839         panel->cmykBlackS = WMCreateSlider(panel->cmykFrm);
840         WMResizeWidget(panel->cmykBlackS, 141, 16);
841         WMMoveWidget(panel->cmykBlackS, 2, 80);
842         WMSetSliderMinValue(panel->cmykBlackS, 0);
843         WMSetSliderMaxValue(panel->cmykBlackS, 100);
844         WMSetSliderValue(panel->cmykBlackS, 0);
845         WMSetSliderKnobThickness(panel->cmykBlackS, knobThickness);
846         WMSetSliderAction(panel->cmykBlackS, cmykSliderCallback, panel);
847
848         to.red = 0;
849         to.green = 0;
850         to.blue = 0;
851
852         image = RRenderGradient(141, 16, &from, &to, RGRD_HORIZONTAL);
853         pixmap = WMCreatePixmapFromRImage(scrPtr, image, 0);
854         RReleaseImage(image);
855
856         if (pixmap)
857                 W_PaintText(W_VIEW(panel->cmykBlackS), pixmap->pixmap, panel->font12,
858                             2, 0, 100, WALeft, scrPtr->black, False, _("Black"), strlen(_("Black")));
859         else
860                 wwarning(_("Color Panel: Could not allocate memory"));
861
862         WMSetSliderImage(panel->cmykBlackS, pixmap);
863         WMReleasePixmap(pixmap);
864
865         panel->cmykBlackT = WMCreateTextField(panel->cmykFrm);
866         WMResizeWidget(panel->cmykBlackT, 40, 18);
867         WMMoveWidget(panel->cmykBlackT, 146, 79);
868         WMSetTextFieldAlignment(panel->cmykBlackT, WALeft);
869         WMAddNotificationObserver(cmykTextFieldCallback, panel,
870                                   WMTextDidEndEditingNotification, panel->cmykBlackT);
871         /* End of CMYK Panel */
872
873         /* Widgets for HSB Panel */
874         panel->hsbFrm = WMCreateFrame(panel->slidersFrm);
875         WMSetFrameRelief(panel->hsbFrm, WRFlat);
876         WMResizeWidget(panel->hsbFrm, PWIDTH - 8, PHEIGHT - 80 - 26 - 32);
877         WMMoveWidget(panel->hsbFrm, 0, 34);
878
879         panel->hsbHueS = WMCreateSlider(panel->hsbFrm);
880         WMResizeWidget(panel->hsbHueS, 141, 16);
881         WMMoveWidget(panel->hsbHueS, 2, 14);
882         WMSetSliderMinValue(panel->hsbHueS, 0);
883         WMSetSliderMaxValue(panel->hsbHueS, 359);
884         WMSetSliderKnobThickness(panel->hsbHueS, knobThickness);
885         WMSetSliderAction(panel->hsbHueS, hsbSliderCallback, panel);
886
887         panel->hsbHueT = WMCreateTextField(panel->hsbFrm);
888         WMResizeWidget(panel->hsbHueT, 40, 18);
889         WMMoveWidget(panel->hsbHueT, 146, 13);
890         WMSetTextFieldAlignment(panel->hsbHueT, WALeft);
891         WMAddNotificationObserver(hsbTextFieldCallback, panel, WMTextDidEndEditingNotification, panel->hsbHueT);
892
893         panel->hsbSaturationS = WMCreateSlider(panel->hsbFrm);
894         WMResizeWidget(panel->hsbSaturationS, 141, 16);
895         WMMoveWidget(panel->hsbSaturationS, 2, 36);
896         WMSetSliderMinValue(panel->hsbSaturationS, 0);
897         WMSetSliderMaxValue(panel->hsbSaturationS, 100);
898         WMSetSliderKnobThickness(panel->hsbSaturationS, knobThickness);
899         WMSetSliderAction(panel->hsbSaturationS, hsbSliderCallback, panel);
900
901         panel->hsbSaturationT = WMCreateTextField(panel->hsbFrm);
902         WMResizeWidget(panel->hsbSaturationT, 40, 18);
903         WMMoveWidget(panel->hsbSaturationT, 146, 35);
904         WMSetTextFieldAlignment(panel->hsbSaturationT, WALeft);
905         WMAddNotificationObserver(hsbTextFieldCallback, panel,
906                                   WMTextDidEndEditingNotification, panel->hsbSaturationT);
907
908         panel->hsbBrightnessS = WMCreateSlider(panel->hsbFrm);
909         WMResizeWidget(panel->hsbBrightnessS, 141, 16);
910         WMMoveWidget(panel->hsbBrightnessS, 2, 58);
911         WMSetSliderMinValue(panel->hsbBrightnessS, 0);
912         WMSetSliderMaxValue(panel->hsbBrightnessS, 100);
913         WMSetSliderKnobThickness(panel->hsbBrightnessS, knobThickness);
914         WMSetSliderAction(panel->hsbBrightnessS, hsbSliderCallback, panel);
915
916         panel->hsbBrightnessT = WMCreateTextField(panel->hsbFrm);
917         WMResizeWidget(panel->hsbBrightnessT, 40, 18);
918         WMMoveWidget(panel->hsbBrightnessT, 146, 57);
919         WMSetTextFieldAlignment(panel->hsbBrightnessT, WALeft);
920         WMAddNotificationObserver(hsbTextFieldCallback, panel,
921                                   WMTextDidEndEditingNotification, panel->hsbBrightnessT);
922         /* End of HSB Panel */
923
924         WMReleaseColor(textcolor);
925
926         /* Widgets for the CustomPalette Panel */
927         panel->customPaletteFrm = WMCreateFrame(panel->win);
928         WMSetFrameRelief(panel->customPaletteFrm, WRFlat);
929         WMResizeWidget(panel->customPaletteFrm, PWIDTH - 8, PHEIGHT - 80 - 26);
930         WMMoveWidget(panel->customPaletteFrm, 5, 80);
931
932         panel->customPaletteHistoryBtn = WMCreatePopUpButton(panel->customPaletteFrm);
933         WMAddPopUpButtonItem(panel->customPaletteHistoryBtn, _("Spectrum"));
934         WMSetPopUpButtonSelectedItem(panel->customPaletteHistoryBtn,
935                                      WMGetPopUpButtonNumberOfItems(panel->customPaletteHistoryBtn) - 1);
936         WMSetPopUpButtonAction(panel->customPaletteHistoryBtn, customPaletteHistoryCallback, panel);
937         WMResizeWidget(panel->customPaletteHistoryBtn, PWIDTH - 8, 20);
938         WMMoveWidget(panel->customPaletteHistoryBtn, 0, 0);
939
940         panel->customPaletteContentFrm = WMCreateFrame(panel->customPaletteFrm);
941         WMSetFrameRelief(panel->customPaletteContentFrm, WRSunken);
942         WMResizeWidget(panel->customPaletteContentFrm, PWIDTH - 8, PHEIGHT - 156);
943         WMMoveWidget(panel->customPaletteContentFrm, 0, 23);
944
945         panel->customPaletteContentView = W_CreateView(W_VIEW(panel->customPaletteContentFrm));
946         /* XXX Test if we can create a view */
947         W_ResizeView(panel->customPaletteContentView, customPaletteWidth, customPaletteHeight);
948         W_MoveView(panel->customPaletteContentView, 2, 2);
949
950         /* Create event handler to handle expose/click events in CustomPalette */
951         WMCreateEventHandler(panel->customPaletteContentView,
952                              ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask |
953                              ButtonMotionMask, customPaletteHandleActionEvents, panel);
954
955         WMCreateEventHandler(panel->customPaletteContentView, ExposureMask, customPaletteHandleEvents, panel);
956
957         panel->customPaletteMenuBtn = WMCreatePopUpButton(panel->customPaletteFrm);
958         WMSetPopUpButtonPullsDown(panel->customPaletteMenuBtn, 1);
959         WMSetPopUpButtonText(panel->customPaletteMenuBtn, _("Palette"));
960         WMSetPopUpButtonAction(panel->customPaletteMenuBtn, customPaletteMenuCallback, panel);
961         WMResizeWidget(panel->customPaletteMenuBtn, PWIDTH - 8, 20);
962         WMMoveWidget(panel->customPaletteMenuBtn, 0, PHEIGHT - 130);
963
964         WMAddPopUpButtonItem(panel->customPaletteMenuBtn, _("New from File..."));
965         WMAddPopUpButtonItem(panel->customPaletteMenuBtn, _("Rename..."));
966         WMAddPopUpButtonItem(panel->customPaletteMenuBtn, _("Remove"));
967         WMAddPopUpButtonItem(panel->customPaletteMenuBtn, _("Copy"));
968         WMAddPopUpButtonItem(panel->customPaletteMenuBtn, _("New from Clipboard"));
969
970         WMSetPopUpButtonItemEnabled(panel->customPaletteMenuBtn, CPmenuRename, 0);
971         WMSetPopUpButtonItemEnabled(panel->customPaletteMenuBtn, CPmenuRemove, 0);
972         WMSetPopUpButtonItemEnabled(panel->customPaletteMenuBtn, CPmenuCopy, 0);
973         WMSetPopUpButtonItemEnabled(panel->customPaletteMenuBtn, CPmenuNewFromClipboard, 0);
974
975         customRenderSpectrum(panel);
976         panel->currentPalette = 0;
977         panel->palx = customPaletteWidth / 2;
978         panel->paly = customPaletteHeight / 2;
979
980         /* Widgets for the ColorList Panel */
981         panel->colorListFrm = WMCreateFrame(panel->win);
982         WMSetFrameRelief(panel->colorListFrm, WRFlat);
983         WMResizeWidget(panel->colorListFrm, PWIDTH - 8, PHEIGHT - 80 - 26);
984         WMMoveWidget(panel->colorListFrm, 5, 80);
985
986         panel->colorListHistoryBtn = WMCreatePopUpButton(panel->colorListFrm);
987         WMAddPopUpButtonItem(panel->colorListHistoryBtn, _("X11-Colors"));
988         WMSetPopUpButtonSelectedItem(panel->colorListHistoryBtn,
989                                      WMGetPopUpButtonNumberOfItems(panel->colorListHistoryBtn) - 1);
990         /*  WMSetPopUpButtonAction(panel->colorListHistoryBtn,
991          *  colorListHistoryCallback, panel); */
992         WMResizeWidget(panel->colorListHistoryBtn, PWIDTH - 8, 20);
993         WMMoveWidget(panel->colorListHistoryBtn, 0, 0);
994
995         panel->colorListContentLst = WMCreateList(panel->colorListFrm);
996         WMSetListAction(panel->colorListContentLst, colorListSelect, panel);
997         WMSetListUserDrawProc(panel->colorListContentLst, colorListPaintItem);
998         WMResizeWidget(panel->colorListContentLst, PWIDTH - 8, PHEIGHT - 156);
999         WMMoveWidget(panel->colorListContentLst, 0, 23);
1000         WMHangData(panel->colorListContentLst, panel);
1001
1002         panel->colorListColorMenuBtn = WMCreatePopUpButton(panel->colorListFrm);
1003         WMSetPopUpButtonPullsDown(panel->colorListColorMenuBtn, 1);
1004         WMSetPopUpButtonText(panel->colorListColorMenuBtn, _("Color"));
1005         WMSetPopUpButtonAction(panel->colorListColorMenuBtn, colorListColorMenuCallback, panel);
1006         WMResizeWidget(panel->colorListColorMenuBtn, (PWIDTH - 16) / 2, 20);
1007         WMMoveWidget(panel->colorListColorMenuBtn, 0, PHEIGHT - 130);
1008
1009         WMAddPopUpButtonItem(panel->colorListColorMenuBtn, _("Add..."));
1010         WMAddPopUpButtonItem(panel->colorListColorMenuBtn, _("Rename..."));
1011         WMAddPopUpButtonItem(panel->colorListColorMenuBtn, _("Remove"));
1012
1013         WMSetPopUpButtonItemEnabled(panel->colorListColorMenuBtn, CLmenuAdd, 0);
1014         WMSetPopUpButtonItemEnabled(panel->colorListColorMenuBtn, CLmenuRename, 0);
1015         WMSetPopUpButtonItemEnabled(panel->colorListColorMenuBtn, CLmenuRemove, 0);
1016
1017         panel->colorListListMenuBtn = WMCreatePopUpButton(panel->colorListFrm);
1018         WMSetPopUpButtonPullsDown(panel->colorListListMenuBtn, 1);
1019         WMSetPopUpButtonText(panel->colorListListMenuBtn, _("List"));
1020         WMSetPopUpButtonAction(panel->colorListListMenuBtn, colorListListMenuCallback, panel);
1021         WMResizeWidget(panel->colorListListMenuBtn, (PWIDTH - 16) / 2, 20);
1022         WMMoveWidget(panel->colorListListMenuBtn, (PWIDTH - 16) / 2 + 8, PHEIGHT - 130);
1023
1024         WMAddPopUpButtonItem(panel->colorListListMenuBtn, _("New..."));
1025         WMAddPopUpButtonItem(panel->colorListListMenuBtn, _("Rename..."));
1026         WMAddPopUpButtonItem(panel->colorListListMenuBtn, _("Remove"));
1027
1028         WMSetPopUpButtonItemEnabled(panel->colorListListMenuBtn, CLmenuAdd, 0);
1029         WMSetPopUpButtonItemEnabled(panel->colorListListMenuBtn, CLmenuRename, 0);
1030         WMSetPopUpButtonItemEnabled(panel->colorListListMenuBtn, CLmenuRemove, 0);
1031
1032         WMRealizeWidget(panel->win);
1033         WMMapSubwidgets(panel->win);
1034
1035         WMMapSubwidgets(panel->wheelFrm);
1036         WMMapSubwidgets(panel->slidersFrm);
1037         WMMapSubwidgets(panel->grayFrm);
1038         WMMapSubwidgets(panel->rgbFrm);
1039         WMMapSubwidgets(panel->cmykFrm);
1040         WMMapSubwidgets(panel->hsbFrm);
1041         WMMapSubwidgets(panel->customPaletteFrm);
1042         WMMapSubwidgets(panel->customPaletteContentFrm);
1043         WMMapSubwidgets(panel->colorListFrm);
1044
1045         /* Pixmap to indicate selection positions
1046          * wheelframe MUST be mapped.
1047          */
1048         panel->selectionImg = XCreatePixmap(scrPtr->display, WMWidgetXID(panel->win), 4, 4, scrPtr->depth);
1049         XFillRectangle(scrPtr->display, panel->selectionImg, bgc, 0, 0, 4, 4);
1050         XFillRectangle(scrPtr->display, panel->selectionImg, wgc, 1, 1, 2, 2);
1051
1052         readConfiguration(panel);
1053         readXColors(panel);
1054
1055         return panel;
1056 }
1057
1058 WMColorPanel *WMGetColorPanel(WMScreen * scrPtr)
1059 {
1060         WMColorPanel *panel;
1061
1062         if (scrPtr->sharedColorPanel)
1063                 return scrPtr->sharedColorPanel;
1064
1065         panel = makeColorPanel(scrPtr, "colorPanel");
1066
1067         scrPtr->sharedColorPanel = panel;
1068
1069         return panel;
1070 }
1071
1072 void WMFreeColorPanel(WMColorPanel * panel)
1073 {
1074         W_Screen *scr = WMWidgetScreen(panel->win);
1075
1076         if (panel == scr->sharedColorPanel) {
1077                 scr->sharedColorPanel = NULL;
1078         }
1079
1080         if (!panel)
1081                 return;
1082
1083         WMRemoveNotificationObserver(panel);
1084         WMUnmapWidget(panel->win);
1085
1086         /* fonts */
1087         WMReleaseFont(panel->font8);
1088         WMReleaseFont(panel->font12);
1089
1090         /* pixmaps */
1091         wheelDestroyMatrix(panel->wheelMtrx);
1092         if (panel->wheelImg)
1093                 XFreePixmap(scr->display, panel->wheelImg);
1094         if (panel->selectionImg)
1095                 XFreePixmap(scr->display, panel->selectionImg);
1096         if (panel->selectionBackImg)
1097                 XFreePixmap(scr->display, panel->selectionBackImg);
1098         RReleaseImage(panel->customPaletteImg);
1099
1100         /* structs */
1101         if (panel->lastBrowseDir)
1102                 wfree(panel->lastBrowseDir);
1103         if (panel->configurationPath)
1104                 wfree(panel->configurationPath);
1105
1106         WMDestroyWidget(panel->win);
1107
1108         wfree(panel);
1109 }
1110
1111 void WMCloseColorPanel(WMColorPanel * panel)
1112 {
1113         WMFreeColorPanel(panel);
1114 }
1115
1116 void WMShowColorPanel(WMColorPanel * panel)
1117 {
1118         WMScreen *scr = WMWidgetScreen(panel->win);
1119         WMColor *white = WMWhiteColor(scr);
1120
1121         if (panel->color.set == cpNone)
1122                 WMSetColorPanelColor(panel, white);
1123         WMReleaseColor(white);
1124
1125         if (panel->mode != WMWheelModeColorPanel)
1126                 WMPerformButtonClick(panel->wheelBtn);
1127
1128         WMMapWidget(panel->win);
1129 }
1130
1131 static void closeWindowCallback(WMWidget * w, void *data)
1132 {
1133         W_ColorPanel *panel = (W_ColorPanel *) data;
1134
1135         WMCloseColorPanel(panel);
1136 }
1137
1138 static void readConfiguration(W_ColorPanel * panel)
1139 {
1140         /* XXX Doesn't take care of "invalid" files */
1141
1142         DIR *dPtr;
1143         struct dirent *dp;
1144         struct stat stat_buf;
1145         int item;
1146
1147         if (stat(panel->configurationPath, &stat_buf) != 0) {
1148                 if (mkdir(panel->configurationPath, S_IRWXU | S_IRGRP | S_IROTH | S_IXGRP | S_IXOTH) != 0) {
1149                         wsyserror(_("Color Panel: Could not create directory %s needed"
1150                                     " to store configurations"), panel->configurationPath);
1151                         WMSetPopUpButtonEnabled(panel->customPaletteMenuBtn, False);
1152                         WMSetPopUpButtonEnabled(panel->colorListColorMenuBtn, False);
1153                         WMSetPopUpButtonEnabled(panel->colorListListMenuBtn, False);
1154                         WMRunAlertPanel(WMWidgetScreen(panel->win), panel->win,
1155                                         _("File Error"),
1156                                         _("Could not create ColorPanel configuration directory"),
1157                                         _("OK"), NULL, NULL);
1158                 }
1159                 return;
1160         }
1161
1162         if (!(dPtr = opendir(panel->configurationPath))) {
1163                 wwarning(_("Color Panel: Could not find file"), "%s", panel->configurationPath);
1164                 return;
1165         }
1166
1167         while ((dp = readdir(dPtr)) != NULL) {
1168                 unsigned int perm_mask;
1169                 char *path = wstrconcat(panel->configurationPath,
1170                                         dp->d_name);
1171
1172                 if (dp->d_name[0] != '.') {
1173                         item = WMGetPopUpButtonNumberOfItems(panel->customPaletteHistoryBtn);
1174                         WMAddPopUpButtonItem(panel->customPaletteHistoryBtn, dp->d_name);
1175
1176                         perm_mask = (access(path, R_OK) == 0);
1177                         WMSetPopUpButtonItemEnabled(panel->customPaletteHistoryBtn, item, perm_mask);
1178                 }
1179                 wfree(path);
1180         }
1181         closedir(dPtr);
1182 }
1183
1184 static void readXColors(W_ColorPanel * panel)
1185 {
1186         WMListItem *item;
1187         RGBColor *entry;
1188
1189         for (entry = rgbColors; entry->name != NULL; entry++) {
1190                 item = WMAddListItem(panel->colorListContentLst, entry->name);
1191                 item->clientData = (void *)&(entry->color);
1192         }
1193 }
1194
1195 void WMSetColorPanelPickerMode(WMColorPanel * panel, WMColorPanelMode mode)
1196 {
1197         W_Screen *scr = WMWidgetScreen(panel->win);
1198
1199         if (mode != WMWheelModeColorPanel) {
1200                 WMUnmapWidget(panel->wheelFrm);
1201                 if (panel->selectionBackImg) {
1202                         XFreePixmap(WMWidgetScreen(panel->win)->display, panel->selectionBackImg);
1203                         panel->selectionBackImg = None;
1204                 }
1205         }
1206         if (mode != WMGrayModeColorPanel)
1207                 WMUnmapWidget(panel->grayFrm);
1208         if (mode != WMRGBModeColorPanel)
1209                 WMUnmapWidget(panel->rgbFrm);
1210         if (mode != WMCMYKModeColorPanel)
1211                 WMUnmapWidget(panel->cmykFrm);
1212         if (mode != WMHSBModeColorPanel)
1213                 WMUnmapWidget(panel->hsbFrm);
1214         if (mode != WMCustomPaletteModeColorPanel) {
1215                 WMUnmapWidget(panel->customPaletteFrm);
1216                 if (panel->selectionBackImg) {
1217                         XFreePixmap(WMWidgetScreen(panel->win)->display, panel->selectionBackImg);
1218                         panel->selectionBackImg = None;
1219                 }
1220         }
1221         if (mode != WMColorListModeColorPanel)
1222                 WMUnmapWidget(panel->colorListFrm);
1223         if ((mode != WMGrayModeColorPanel) && (mode != WMRGBModeColorPanel) &&
1224             (mode != WMCMYKModeColorPanel) && (mode != WMHSBModeColorPanel))
1225                 WMUnmapWidget(panel->slidersFrm);
1226         else
1227                 panel->slidersmode = mode;
1228
1229         if (mode == WMWheelModeColorPanel) {
1230                 WMMapWidget(panel->wheelFrm);
1231                 WMSetButtonSelected(panel->wheelBtn, True);
1232                 if (panel->lastChanged != WMWheelModeColorPanel)
1233                         wheelInit(panel);
1234                 wheelRender(panel);
1235                 wheelPaint(panel);
1236         } else if (mode == WMGrayModeColorPanel) {
1237                 WMMapWidget(panel->slidersFrm);
1238                 WMSetButtonSelected(panel->slidersBtn, True);
1239                 WMMapWidget(panel->grayFrm);
1240                 WMSetButtonSelected(panel->grayBtn, True);
1241                 WMSetButtonImage(panel->slidersBtn, scr->grayIcon);
1242                 if (panel->lastChanged != WMGrayModeColorPanel)
1243                         grayInit(panel);
1244         } else if (mode == WMRGBModeColorPanel) {
1245                 WMMapWidget(panel->slidersFrm);
1246                 WMSetButtonSelected(panel->slidersBtn, True);
1247                 WMMapWidget(panel->rgbFrm);
1248                 WMSetButtonSelected(panel->rgbBtn, True);
1249                 WMSetButtonImage(panel->slidersBtn, scr->rgbIcon);
1250                 if (panel->lastChanged != WMRGBModeColorPanel)
1251                         rgbInit(panel);
1252         } else if (mode == WMCMYKModeColorPanel) {
1253                 WMMapWidget(panel->slidersFrm);
1254                 WMSetButtonSelected(panel->slidersBtn, True);
1255                 WMMapWidget(panel->cmykFrm);
1256                 WMSetButtonSelected(panel->cmykBtn, True);
1257                 WMSetButtonImage(panel->slidersBtn, scr->cmykIcon);
1258                 if (panel->lastChanged != WMCMYKModeColorPanel)
1259                         cmykInit(panel);
1260         } else if (mode == WMHSBModeColorPanel) {
1261                 WMMapWidget(panel->slidersFrm);
1262                 WMSetButtonSelected(panel->slidersBtn, True);
1263                 WMMapWidget(panel->hsbFrm);
1264                 WMSetButtonSelected(panel->hsbBtn, True);
1265                 WMSetButtonImage(panel->slidersBtn, scr->hsbIcon);
1266                 if (panel->lastChanged != WMHSBModeColorPanel)
1267                         hsbInit(panel);
1268         } else if (mode == WMCustomPaletteModeColorPanel) {
1269                 WMMapWidget(panel->customPaletteFrm);
1270                 WMSetButtonSelected(panel->customPaletteBtn, True);
1271                 customSetPalette(panel);
1272         } else if (mode == WMColorListModeColorPanel) {
1273                 WMMapWidget(panel->colorListFrm);
1274                 WMSetButtonSelected(panel->colorListBtn, True);
1275         }
1276
1277         panel->mode = mode;
1278 }
1279
1280 WMColor *WMGetColorPanelColor(WMColorPanel * panel)
1281 {
1282         return WMGetColorWellColor(panel->colorWell);
1283 }
1284
1285 void WMSetColorPanelColor(WMColorPanel * panel, WMColor * color)
1286 {
1287         WMSetColorWellColor(panel->colorWell, color);
1288
1289         panel->color.rgb.red = color->color.red >> 8;
1290         panel->color.rgb.green = color->color.green >> 8;
1291         panel->color.rgb.blue = color->color.blue >> 8;
1292         panel->color.set = cpRGB;
1293
1294         if (panel->mode == panel->lastChanged)
1295                 panel->lastChanged = 0;
1296
1297         WMSetColorPanelPickerMode(panel, panel->mode);
1298 }
1299
1300 static void updateSwatch(WMColorPanel * panel, CPColor color)
1301 {
1302         WMScreen *scr = WMWidgetScreen(panel->win);
1303         WMColor *wellcolor;
1304
1305         if (color.set != cpRGB)
1306                 convertCPColor(&color);
1307
1308         panel->color = color;
1309
1310         wellcolor = WMCreateRGBColor(scr, color.rgb.red << 8, color.rgb.green << 8, color.rgb.blue << 8, True);
1311
1312         WMSetColorWellColor(panel->colorWell, wellcolor);
1313         WMReleaseColor(wellcolor);
1314
1315         if (!panel->flags.dragging || panel->flags.continuous) {
1316                 if (panel->action)
1317                         (*panel->action) (panel, panel->clientData);
1318
1319                 WMPostNotificationName(WMColorPanelColorChangedNotification, panel, NULL);
1320         }
1321 }
1322
1323 static void modeButtonCallback(WMWidget * w, void *data)
1324 {
1325         W_ColorPanel *panel = (W_ColorPanel *) (data);
1326
1327         if (w == panel->wheelBtn)
1328                 WMSetColorPanelPickerMode(panel, WMWheelModeColorPanel);
1329         else if (w == panel->slidersBtn)
1330                 WMSetColorPanelPickerMode(panel, panel->slidersmode);
1331         else if (w == panel->customPaletteBtn)
1332                 WMSetColorPanelPickerMode(panel, WMCustomPaletteModeColorPanel);
1333         else if (w == panel->colorListBtn)
1334                 WMSetColorPanelPickerMode(panel, WMColorListModeColorPanel);
1335         else if (w == panel->grayBtn)
1336                 WMSetColorPanelPickerMode(panel, WMGrayModeColorPanel);
1337         else if (w == panel->rgbBtn)
1338                 WMSetColorPanelPickerMode(panel, WMRGBModeColorPanel);
1339         else if (w == panel->cmykBtn)
1340                 WMSetColorPanelPickerMode(panel, WMCMYKModeColorPanel);
1341         else if (w == panel->hsbBtn)
1342                 WMSetColorPanelPickerMode(panel, WMHSBModeColorPanel);
1343 }
1344
1345 /******************  Magnifying Cursor Functions *******************/
1346
1347 static XImage *magnifyGetImage(WMScreen * scr, XImage * image, int x, int y, int w, int h)
1348 {
1349         int x0 = 0, y0 = 0, w0 = w, h0 = h;
1350         const int displayWidth = DisplayWidth(scr->display, scr->screen),
1351             displayHeight = DisplayHeight(scr->display, scr->screen);
1352
1353         if (!(image && image->data)) {
1354                 /* The image in panel->magnifyGlass->image does not exist yet.
1355                  * Grab one from the screen (not beyond) and use it from now on.
1356                  */
1357                 if (!(image = XGetImage(scr->display, scr->rootWin,
1358                                         x - Cursor_x_hot, y - Cursor_y_hot, w, h, AllPlanes, ZPixmap)))
1359                         wwarning(_("Color Panel: X failed request"));
1360
1361                 return image;
1362         }
1363
1364         /* Coordinate correction for back pixmap
1365          * if magnifying glass is at screen-borders
1366          */
1367
1368         /* Figure 1: Shifting of rectangle-to-grab at top/left screen borders
1369          * Hatched area is beyond screen border.
1370          *
1371          * |<-Cursor_x_hot->|
1372          *  ________________|_____
1373          * |/ / / / / / /|  |     |
1374          * | / / / / / / |(x,y)   |
1375          * |/_/_/_/_/_/_/|________|
1376          * |<----x0----->|<--w0-->|
1377          *               0
1378          */
1379
1380         /* Figure 2: Shifting of rectangle-to-grab at bottom/right
1381          * screen borders
1382          * Hatched area is beyond screen border
1383          *
1384          * |<-Cursor_x_hot->|
1385          *  ________________|_______________
1386          * |                |  | / / / / / /|
1387          * |              (x,y)|/ / / / / / |
1388          * |___________________|_/_/_/_/_/_/|
1389          * |<-------w0-------->|            |
1390          * |<---------------w--|----------->|
1391          * |                   |
1392          * x0                  Displaywidth-1
1393          */
1394
1395         if (x < Cursor_x_hot) { /* see fig. 1 */
1396                 x0 = Cursor_x_hot - x;
1397                 w0 = w - x0;
1398         }
1399
1400         if (displayWidth - 1 < x - Cursor_x_hot + w) {  /* see fig. 2 */
1401                 w0 = (displayWidth) - (x - Cursor_x_hot);
1402         }
1403
1404         if (y < Cursor_y_hot) { /* see fig. 1 */
1405                 y0 = Cursor_y_hot - y;
1406                 h0 = h - y0;
1407         }
1408
1409         if (displayHeight - 1 < y - Cursor_y_hot + h) { /* see fig. 2 */
1410                 h0 = (displayHeight) - (y - Cursor_y_hot);
1411         }
1412         /* end of coordinate correction */
1413
1414         /* Grab an image from the screen, clipped if necessary,
1415          * and put it in the existing panel->magnifyGlass->image
1416          * with the corresponding clipping offset.
1417          */
1418         if (!XGetSubImage(scr->display, scr->rootWin,
1419                           x - Cursor_x_hot + x0, y - Cursor_y_hot + y0, w0, h0, AllPlanes, ZPixmap, image, x0, y0))
1420                 wwarning(_("Color Panel: X failed request"));
1421
1422         return NULL;
1423 }
1424
1425 static void magnifyGetImageStored(WMColorPanel * panel, int x1, int y1, int x2, int y2)
1426 {
1427         /* (x1, y1) = topleft corner of existing rectangle
1428          * (x2, y2) = topleft corner of new position
1429          */
1430
1431         W_Screen *scr = WMWidgetScreen(panel->win);
1432         int xa = 0, ya = 0, xb = 0, yb = 0;
1433         int width, height;
1434         const int dx = abs(x2 - x1), dy = abs(y2 - y1);
1435         XImage *image;
1436         const int x_min = Cursor_x_hot,
1437             y_min = Cursor_y_hot,
1438             x_max = DisplayWidth(scr->display, scr->screen) - 1 -
1439             (Cursor_mask_width - Cursor_x_hot),
1440             y_max = DisplayHeight(scr->display, scr->screen) - 1 - (Cursor_mask_height - Cursor_y_hot);
1441
1442         if ((dx == 0) && (dy == 0) && panel->magnifyGlass->image)
1443                 return;         /* No movement */
1444
1445         if (x1 < x2)
1446                 xa = dx;
1447         else
1448                 xb = dx;
1449
1450         if (y1 < y2)
1451                 ya = dy;
1452         else
1453                 yb = dy;
1454
1455         width = Cursor_mask_width - dx;
1456         height = Cursor_mask_height - dy;
1457
1458         /* If the traversed distance is larger than the size of the magnifying
1459          * glass contents, there is no need to do dirty rectangles. A whole new
1460          * rectangle can be grabbed (unless that rectangle falls partially
1461          * off screen).
1462          * Destroying the image and setting it to NULL will achieve that later on.
1463          *
1464          * Of course, grabbing an XImage beyond the borders of the screen will
1465          * cause trouble, this is considdered a special case. Part of the screen
1466          * is grabbed, but there is no need for dirty rectangles.
1467          */
1468         if ((width <= 0) || (height <= 0)) {
1469                 if ((x2 >= x_min) && (y2 >= y_min) && (x2 <= x_max) && (y2 <= y_max)) {
1470                         if (panel->magnifyGlass->image)
1471                                 XDestroyImage(panel->magnifyGlass->image);
1472                         panel->magnifyGlass->image = NULL;
1473                 }
1474         } else {
1475                 if (panel->magnifyGlass->image) {
1476                         /* Get dirty rectangle from panel->magnifyGlass->image */
1477                         panel->magnifyGlass->dirtyRect =
1478                             XSubImage(panel->magnifyGlass->image, xa, ya, width, height);
1479                         if (!panel->magnifyGlass->dirtyRect) {
1480                                 wwarning(_("Color Panel: X failed request"));
1481                                 return; /* X returned a NULL from XSubImage */
1482                         }
1483                 }
1484         }
1485
1486         /* Get image from screen */
1487         image = magnifyGetImage(scr, panel->magnifyGlass->image, x2, y2, Cursor_mask_width, Cursor_mask_height);
1488         if (image) {            /* Only reassign if a *new* image was grabbed */
1489                 panel->magnifyGlass->image = image;
1490                 return;
1491         }
1492
1493         /* Copy previously stored rectangle on covered part of image */
1494         if (panel->magnifyGlass->image && panel->magnifyGlass->dirtyRect) {
1495                 int old_height;
1496
1497                 /* "width" and "height" are used as coordinates here,
1498                  * and run from [0...width-1] and [0...height-1] respectively.
1499                  */
1500                 width--;
1501                 height--;
1502                 old_height = height;
1503
1504                 for (; width >= 0; width--)
1505                         for (height = old_height; height >= 0; height--)
1506                                 XPutPixel(panel->magnifyGlass->image, xb + width, yb + height,
1507                                           XGetPixel(panel->magnifyGlass->dirtyRect, width, height));
1508                 XDestroyImage(panel->magnifyGlass->dirtyRect);
1509                 panel->magnifyGlass->dirtyRect = NULL;
1510         }
1511
1512         return;
1513 }
1514
1515 static Pixmap magnifyCreatePixmap(WMColorPanel * panel)
1516 {
1517         W_Screen *scr = WMWidgetScreen(panel->win);
1518         int u, v;
1519 #ifndef SHAPE
1520         Pixmap pixmap;
1521 #endif
1522         unsigned long color;
1523
1524         if (!panel->magnifyGlass->image)
1525                 return None;
1526
1527         if (!panel->magnifyGlass->magPix)
1528                 return None;
1529
1530         /*
1531          * Copy an area of only 5x5 pixels from the center of the image.
1532          */
1533         for (u = 0; u < 5; u++) {
1534                 for (v = 0; v < 5; v++) {
1535                         color = XGetPixel(panel->magnifyGlass->image, u + 9, v + 9);
1536
1537                         XSetForeground(scr->display, scr->copyGC, color);
1538
1539                         if ((u == 2) && (v == 2))       /* (2,2) is center pixel (unmagn.) */
1540                                 panel->magnifyGlass->color = ulongToRColor(scr, color);
1541
1542                         /* The center square must eventually be centered around the
1543                          * hotspot. The image needs shifting to achieve this. The amount of
1544                          * shifting is (Cursor_mask_width/2 - 2 * square_size) = 11-10 = 1
1545                          *  _ _ _ _ _
1546                          * |_|_|_|_|_|
1547                          *      ^------- center of center square == Cursor_x_hot
1548                          */
1549                         XFillRectangle(scr->display, panel->magnifyGlass->magPix,
1550                                        scr->copyGC,
1551                                        u * 5 + (u == 0 ? 0 : -1), v * 5 + (v == 0 ? 0 : -1),
1552                                        (u == 0 ? 4 : 5), (v == 0 ? 4 : 5));
1553                 }
1554         }
1555
1556 #ifdef SHAPE
1557         return panel->magnifyGlass->magPix;
1558 #else
1559         pixmap = XCreatePixmap(scr->display, W_DRAWABLE(scr), Cursor_mask_width, Cursor_mask_height, scr->depth);
1560         if (!pixmap)
1561                 return None;
1562
1563         XPutImage(scr->display, pixmap, scr->copyGC, panel->magnifyGlass->image,
1564                   0, 0, 0, 0, Cursor_mask_width, Cursor_mask_height);
1565
1566         /* Copy the magnified pixmap, with the clip mask, to background pixmap */
1567         XCopyArea(scr->display, panel->magnifyGlass->magPix, pixmap,
1568                   scr->clipGC, 0, 0, Cursor_mask_width, Cursor_mask_height, 0, 0);
1569         /* (2,2) puts center pixel on center of glass */
1570
1571         return pixmap;
1572 #endif
1573
1574 }
1575
1576 static WMView *magnifyCreateView(W_ColorPanel * panel)
1577 {
1578         W_Screen *scr = WMWidgetScreen(panel->win);
1579         WMView *magView;
1580
1581         magView = W_CreateTopView(scr);
1582         if (!magView)
1583                 return NULL;
1584
1585         magView->self = panel->win;
1586         magView->flags.topLevel = 1;
1587         magView->attribFlags |= CWOverrideRedirect | CWSaveUnder;
1588         magView->attribs.override_redirect = True;
1589         magView->attribs.save_under = True;
1590
1591         W_ResizeView(magView, Cursor_mask_width, Cursor_mask_height);
1592
1593         W_RealizeView(magView);
1594
1595         return magView;
1596 }
1597
1598 static Cursor magnifyGrabPointer(W_ColorPanel * panel)
1599 {
1600         W_Screen *scr = WMWidgetScreen(panel->win);
1601         Pixmap magPixmap, magPixmap2;
1602         Cursor magCursor;
1603         XColor fgColor = { 0, 0, 0, 0, DoRed | DoGreen | DoBlue };
1604         XColor bgColor = { 0, 0xbf00, 0xa000, 0x5000, DoRed | DoGreen | DoBlue };
1605
1606         /* Cursor creation stuff */
1607         magPixmap = XCreatePixmapFromBitmapData(scr->display, W_DRAWABLE(scr),
1608                                                 (char *)Cursor_bits, Cursor_width, Cursor_height, 1, 0, 1);
1609         magPixmap2 = XCreatePixmapFromBitmapData(scr->display, W_DRAWABLE(scr),
1610                                                  (char *)Cursor_shape_bits, Cursor_width, Cursor_height, 1, 0, 1);
1611
1612         magCursor = XCreatePixmapCursor(scr->display, magPixmap, magPixmap2,
1613                                         &fgColor, &bgColor, Cursor_x_hot, Cursor_y_hot);
1614
1615         XFreePixmap(scr->display, magPixmap);
1616         XFreePixmap(scr->display, magPixmap2);
1617
1618         XRecolorCursor(scr->display, magCursor, &fgColor, &bgColor);
1619
1620         /* Set up Pointer */
1621         XGrabPointer(scr->display, panel->magnifyGlass->view->window, True,
1622                      PointerMotionMask | ButtonPressMask,
1623                      GrabModeAsync, GrabModeAsync, scr->rootWin, magCursor, CurrentTime);
1624
1625         return magCursor;
1626 }
1627
1628 static WMPoint magnifyInitialize(W_ColorPanel * panel)
1629 {
1630         W_Screen *scr = WMWidgetScreen(panel->win);
1631         int x, y, u, v;
1632         unsigned int mask;
1633         Pixmap pixmap, clip_mask;
1634         WMPoint point;
1635         Window root_return, child_return;
1636
1637         clip_mask = XCreatePixmapFromBitmapData(scr->display, W_DRAWABLE(scr),
1638                                                 (char *)Cursor_mask_bits, Cursor_mask_width, Cursor_mask_height,
1639                                                 1, 0, 1);
1640         panel->magnifyGlass->magPix = XCreatePixmap(scr->display, W_DRAWABLE(scr),
1641                                                     5 * 5 - 1, 5 * 5 - 1, scr->depth);
1642
1643         XQueryPointer(scr->display, scr->rootWin, &root_return, &child_return, &x, &y, &u, &v, &mask);
1644
1645         panel->magnifyGlass->image = NULL;
1646
1647         /* Clipmask to make magnified view-contents circular */
1648 #ifdef SHAPE
1649         XShapeCombineMask(scr->display, WMViewXID(panel->magnifyGlass->view),
1650                           ShapeBounding, 0, 0, clip_mask, ShapeSet);
1651 #else
1652         /* Clip circle in glass cursor */
1653         XSetClipMask(scr->display, scr->clipGC, clip_mask);
1654         XSetClipOrigin(scr->display, scr->clipGC, 0, 0);
1655 #endif
1656
1657         XFreePixmap(scr->display, clip_mask);
1658
1659         /* Draw initial magnifying glass contents */
1660         magnifyGetImageStored(panel, x, y, x, y);
1661
1662         pixmap = magnifyCreatePixmap(panel);
1663         XSetWindowBackgroundPixmap(scr->display, WMViewXID(panel->magnifyGlass->view), pixmap);
1664         XClearWindow(scr->display, WMViewXID(panel->magnifyGlass->view));
1665         XFlush(scr->display);
1666
1667 #ifndef SHAPE
1668         XFreePixmap(scr->display, pixmap);
1669 #endif
1670
1671         point.x = x;
1672         point.y = y;
1673
1674         return point;
1675 }
1676
1677 static void magnifyPutCursor(WMWidget * w, void *data)
1678 {
1679         W_ColorPanel *panel = (W_ColorPanel *) (data);
1680         W_Screen *scr = WMWidgetScreen(panel->win);
1681         Cursor magCursor;
1682         Pixmap pixmap;
1683         XEvent event;
1684         WMPoint initialPosition;
1685
1686         /* Destroy wheelBackImg, so it'll update properly */
1687         if (panel->selectionBackImg) {
1688                 XFreePixmap(WMWidgetScreen(panel->win)->display, panel->selectionBackImg);
1689                 panel->selectionBackImg = None;
1690         }
1691
1692         /* Create magnifying glass */
1693         panel->magnifyGlass = wmalloc(sizeof(MovingView));
1694         panel->magnifyGlass->view = magnifyCreateView(panel);
1695         if (!panel->magnifyGlass->view)
1696                 return;
1697
1698         initialPosition = magnifyInitialize(panel);
1699         panel->magnifyGlass->x = initialPosition.x;
1700         panel->magnifyGlass->y = initialPosition.y;
1701
1702         W_MoveView(panel->magnifyGlass->view,
1703                    panel->magnifyGlass->x - Cursor_x_hot, panel->magnifyGlass->y - Cursor_y_hot);
1704         W_MapView(panel->magnifyGlass->view);
1705
1706         magCursor = magnifyGrabPointer(panel);
1707
1708         while (panel->magnifyGlass->image) {
1709                 WMNextEvent(scr->display, &event);
1710
1711                 /* Pack motion events */
1712                 while (XCheckTypedEvent(scr->display, MotionNotify, &event)) {
1713                 }
1714
1715                 switch (event.type) {
1716                 case ButtonPress:
1717                         XDestroyImage(panel->magnifyGlass->image);
1718                         panel->magnifyGlass->image = NULL;
1719
1720                         if (event.xbutton.button == Button1) {
1721                                 panel->color.rgb = panel->magnifyGlass->color;
1722                                 panel->color.set = cpRGB;
1723                                 updateSwatch(panel, panel->color);
1724                         }
1725                         switch (panel->mode) {
1726                         case WMWheelModeColorPanel:
1727                                 wheelInit(panel);
1728                                 wheelRender(panel);
1729                                 wheelPaint(panel);
1730                                 break;
1731                         case WMGrayModeColorPanel:
1732                                 grayInit(panel);
1733                                 break;
1734                         case WMRGBModeColorPanel:
1735                                 rgbInit(panel);
1736                                 break;
1737                         case WMCMYKModeColorPanel:
1738                                 cmykInit(panel);
1739                                 break;
1740                         case WMHSBModeColorPanel:
1741                                 hsbInit(panel);
1742                                 break;
1743                         default:
1744                                 break;
1745                         }
1746                         panel->lastChanged = panel->mode;
1747
1748                         WMSetButtonSelected(panel->magnifyBtn, False);
1749                         break;
1750
1751                 case MotionNotify:
1752                         while (XPending(event.xmotion.display)) {
1753                                 XEvent ev;
1754                                 XPeekEvent(event.xmotion.display, &ev);
1755                                 if (ev.type == MotionNotify)
1756                                         XNextEvent(event.xmotion.display, &event);
1757                                 else
1758                                         break;
1759                         }
1760
1761                         /* Get a "dirty rectangle" */
1762                         magnifyGetImageStored(panel,
1763                                               panel->magnifyGlass->x, panel->magnifyGlass->y,
1764                                               event.xmotion.x_root, event.xmotion.y_root);
1765
1766                         /* Update coordinates */
1767                         panel->magnifyGlass->x = event.xmotion.x_root;
1768                         panel->magnifyGlass->y = event.xmotion.y_root;
1769
1770                         /* Move view */
1771                         W_MoveView(panel->magnifyGlass->view,
1772                                    panel->magnifyGlass->x - Cursor_x_hot, panel->magnifyGlass->y - Cursor_y_hot);
1773
1774                         /* Put new image (with magn.) in view */
1775                         pixmap = magnifyCreatePixmap(panel);
1776                         if (pixmap != None) {
1777                                 /* Change the window background */
1778                                 XSetWindowBackgroundPixmap(scr->display,
1779                                                            WMViewXID(panel->magnifyGlass->view), pixmap);
1780                                 /* Force an Expose (handled by X) */
1781                                 XClearWindow(scr->display, WMViewXID(panel->magnifyGlass->view));
1782                                 /* Synchronize the event queue, so the Expose is handled NOW */
1783                                 XFlush(scr->display);
1784 #ifndef SHAPE
1785                                 XFreePixmap(scr->display, pixmap);
1786 #endif
1787                         }
1788                         break;
1789
1790                         /* Try XQueryPointer for this !!! It returns windows that the pointer
1791                          * is over. Note: We found this solving the invisible donkey cap bug
1792                          */
1793 #if 0                           /* As it is impossible to make this work in all cases,
1794                                  * we consider it confusing. Therefore we disabled it.
1795                                  */
1796                 case FocusOut:  /* fall through */
1797                 case FocusIn:
1798                         /*
1799                          * Color Panel window (panel->win) lost or received focus.
1800                          * We need to update the pixmap in the magnifying glass.
1801                          *
1802                          * BUG Doesn't work with focus switches between two windows
1803                          * if none of them is the color panel.
1804                          */
1805                         XUngrabPointer(scr->display, CurrentTime);
1806                         W_UnmapView(panel->magnifyGlass->view);
1807
1808                         magnifyInitialize(panel);
1809
1810                         W_MapView(panel->magnifyGlass->view);
1811                         XGrabPointer(scr->display, panel->magnifyGlass->view->window,
1812                                      True, PointerMotionMask | ButtonPressMask,
1813                                      GrabModeAsync, GrabModeAsync, scr->rootWin, magCursor, CurrentTime);
1814                         break;
1815 #endif
1816                 default:
1817                         WMHandleEvent(&event);
1818                         break;
1819                 }               /* of switch */
1820         }
1821
1822         XUngrabPointer(scr->display, CurrentTime);
1823         XFreeCursor(scr->display, magCursor);
1824
1825         XFreePixmap(scr->display, panel->magnifyGlass->magPix);
1826         panel->magnifyGlass->magPix = None;
1827
1828         W_UnmapView(panel->magnifyGlass->view);
1829         W_DestroyView(panel->magnifyGlass->view);
1830         panel->magnifyGlass->view = NULL;
1831
1832         wfree(panel->magnifyGlass);
1833 }
1834
1835 /******************  ColorWheel Functions  ************************/
1836
1837 static wheelMatrix *wheelCreateMatrix(unsigned int width, unsigned int height)
1838 {
1839         wheelMatrix *matrix = NULL;
1840         int i;
1841
1842         assert((width > 0) && (height > 0));
1843
1844         matrix = wmalloc(sizeof(wheelMatrix));
1845         memset(matrix, 0, sizeof(wheelMatrix));
1846         matrix->width = width;
1847         matrix->height = height;
1848
1849         for (i = 0; i < 3; i++) {
1850                 matrix->data[i] = wmalloc(width * height * sizeof(unsigned char));
1851         }
1852
1853         return matrix;
1854 }
1855
1856 static void wheelDestroyMatrix(wheelMatrix * matrix)
1857 {
1858         int i;
1859
1860         if (!matrix)
1861                 return;
1862
1863         for (i = 0; i < 3; i++) {
1864                 if (matrix->data[i])
1865                         wfree(matrix->data[i]);
1866         }
1867         wfree(matrix);
1868 }
1869
1870 static void wheelInitMatrix(W_ColorPanel * panel)
1871 {
1872         int i;
1873         int x, y;
1874         unsigned char *rp, *gp, *bp;
1875         CPColor cpColor;
1876         long ofs[4];
1877         int xcor, ycor;
1878         unsigned short sat;
1879         int dhue[4];
1880         const int cw_halfsize = (colorWheelSize + 4) / 2,
1881             cw_sqsize = (colorWheelSize + 4) * (colorWheelSize + 4), uchar_shift = getShift(sizeof(unsigned char));
1882
1883         if (!panel->wheelMtrx)
1884                 return;
1885
1886         cpColor.hsv.value = 255;
1887         cpColor.set = cpHSV;
1888
1889         ofs[0] = -1;
1890         ofs[1] = -(colorWheelSize + 4);
1891
1892         /* offsets are counterclockwise (in triangles).
1893          *
1894          *     ofs[0] ---->
1895          *      _______________________________________
1896          * [1] |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|  o
1897          *  s  |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|  f
1898          *  f  |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|  s
1899          *  o  | | | | | | | | | | | | | | | | | | | | | [3]
1900          *
1901          *                                  <---- ofs[2]
1902          *       ____
1903          *      |\  /| <-- triangles
1904          *      | \/ |
1905          *      | /\ |
1906          *      |/__\|
1907          */
1908
1909         for (y = 0; y < cw_halfsize; y++) {
1910                 for (x = y; x < (colorWheelSize + 4 - y); x++) {
1911                         /* (xcor, ycor) is (x,y) relative to center of matrix */
1912                         xcor = 2 * x - 4 - colorWheelSize;
1913                         ycor = 2 * y - 4 - colorWheelSize;
1914
1915                         /* RColor.saturation is unsigned char and will wrap after 255 */
1916                         sat = rint(255.0 * sqrt(xcor * xcor + ycor * ycor) / colorWheelSize);
1917
1918                         cpColor.hsv.saturation = (unsigned char)sat;
1919
1920                         ofs[0]++;       /* top quarter of matrix */
1921                         ofs[1] += colorWheelSize + 4;   /* left quarter */
1922                         ofs[2] = cw_sqsize - 1 - ofs[0];        /* bottom quarter */
1923                         ofs[3] = cw_sqsize - 1 - ofs[1];        /* right quarter */
1924
1925                         if (sat < 256) {
1926                                 if (xcor != 0)
1927                                         dhue[0] = rint(atan((double)ycor / (double)xcor) *
1928                                                        (180.0 / M_PI)) + (xcor < 0 ? 180.0 : 0.0);
1929                                 else
1930                                         dhue[0] = 270;
1931
1932                                 dhue[0] = 360 - dhue[0];        /* Reverse direction of ColorWheel */
1933                                 dhue[1] = 270 - dhue[0] + (dhue[0] > 270 ? 360 : 0);
1934                                 dhue[2] = dhue[0] - 180 + (dhue[0] < 180 ? 360 : 0);
1935                                 dhue[3] = 90 - dhue[0] + (dhue[0] > 90 ? 360 : 0);
1936
1937                                 for (i = 0; i < 4; i++) {
1938                                         rp = panel->wheelMtrx->data[0] + (ofs[i] << uchar_shift);
1939                                         gp = panel->wheelMtrx->data[1] + (ofs[i] << uchar_shift);
1940                                         bp = panel->wheelMtrx->data[2] + (ofs[i] << uchar_shift);
1941
1942                                         cpColor.hsv.hue = dhue[i];
1943                                         convertCPColor(&cpColor);
1944
1945                                         *rp = (unsigned char)(cpColor.rgb.red);
1946                                         *gp = (unsigned char)(cpColor.rgb.green);
1947                                         *bp = (unsigned char)(cpColor.rgb.blue);
1948                                 }
1949                         } else {
1950                                 for (i = 0; i < 4; i++) {
1951                                         rp = panel->wheelMtrx->data[0] + (ofs[i] << uchar_shift);
1952                                         gp = panel->wheelMtrx->data[1] + (ofs[i] << uchar_shift);
1953                                         bp = panel->wheelMtrx->data[2] + (ofs[i] << uchar_shift);
1954
1955                                         *rp = (unsigned char)0;
1956                                         *gp = (unsigned char)0;
1957                                         *bp = (unsigned char)0;
1958                                 }
1959                         }
1960                 }
1961
1962                 ofs[0] += 2 * y + 1;
1963                 ofs[1] += 1 - (colorWheelSize + 4) * (colorWheelSize + 4 - 1 - 2 * y);
1964         }
1965 }
1966
1967 static void wheelCalculateValues(W_ColorPanel * panel, int maxvalue)
1968 {
1969         unsigned int i;
1970         unsigned int v;
1971
1972         for (i = 0; i < 256; i++) {
1973                 /* We divide by 128 in advance, and check whether that number divides
1974                  * by 2 properly. If not, we add one to round the number correctly
1975                  */
1976                 v = (i * maxvalue) >> 7;
1977                 panel->wheelMtrx->values[i] = (unsigned char)((v >> 1) + (v & 0x01));
1978         }
1979 }
1980
1981 static void wheelRender(W_ColorPanel * panel)
1982 {
1983         W_Screen *scr = WMWidgetScreen(panel->win);
1984         int x, y;
1985         RImage *image;
1986         unsigned char *ptr;
1987         RColor gray;
1988         unsigned long ofs = 0;
1989         /*unsigned char     shift = getShift(sizeof(unsigned char)); */
1990
1991         image = RCreateImage(colorWheelSize + 4, colorWheelSize + 4, True);
1992         if (!image) {
1993                 wwarning(_("Color Panel: Could not allocate memory"));
1994                 return;
1995         }
1996
1997         ptr = image->data;
1998
1999         /* TODO Make this transparent istead of gray */
2000         gray.red = gray.blue = 0xae;
2001         gray.green = 0xaa;
2002
2003         for (y = 0; y < colorWheelSize + 4; y++) {
2004                 for (x = 0; x < colorWheelSize + 4; x++) {
2005                         if (wheelInsideColorWheel(panel, ofs)) {
2006                                 *(ptr++) =
2007                                     (unsigned char)(panel->wheelMtrx->values[panel->wheelMtrx->data[0][ofs]]);
2008                                 *(ptr++) =
2009                                     (unsigned char)(panel->wheelMtrx->values[panel->wheelMtrx->data[1][ofs]]);
2010                                 *(ptr++) =
2011                                     (unsigned char)(panel->wheelMtrx->values[panel->wheelMtrx->data[2][ofs]]);
2012                                 *(ptr++) = 0;
2013                         } else {
2014                                 *(ptr++) = (unsigned char)(gray.red);
2015                                 *(ptr++) = (unsigned char)(gray.green);
2016                                 *(ptr++) = (unsigned char)(gray.blue);
2017                                 *(ptr++) = 255;
2018                         }
2019                         ofs++;
2020                 }
2021         }
2022
2023         if (panel->wheelImg)
2024                 XFreePixmap(scr->display, panel->wheelImg);
2025
2026         RConvertImage(scr->rcontext, image, &panel->wheelImg);
2027         RReleaseImage(image);
2028
2029         /* Check if backimage exists. If it doesn't, allocate and fill it */
2030         if (!panel->selectionBackImg) {
2031                 panel->selectionBackImg = XCreatePixmap(scr->display,
2032                                                         W_VIEW(panel->wheelFrm)->window, 4, 4, scr->depth);
2033                 XCopyArea(scr->display, panel->wheelImg, panel->selectionBackImg,
2034                           scr->copyGC, panel->colx - 2, panel->coly - 2, 4, 4, 0, 0);
2035                 /* -2 is hot spot correction */
2036         }
2037 }
2038
2039 static Bool wheelInsideColorWheel(W_ColorPanel * panel, unsigned long ofs)
2040 {
2041         return ((panel->wheelMtrx->data[0][ofs] != 0) &&
2042                 (panel->wheelMtrx->data[1][ofs] != 0) && (panel->wheelMtrx->data[2][ofs] != 0));
2043 }
2044
2045 static void wheelPaint(W_ColorPanel * panel)
2046 {
2047         W_Screen *scr = WMWidgetScreen(panel->win);
2048
2049         XCopyArea(scr->display, panel->wheelImg, panel->wheelView->window,
2050                   scr->copyGC, 0, 0, colorWheelSize + 4, colorWheelSize + 4, 0, 0);
2051
2052         /* Draw selection image */
2053         XCopyArea(scr->display, panel->selectionImg, panel->wheelView->window,
2054                   scr->copyGC, 0, 0, 4, 4, panel->colx - 2, panel->coly - 2);
2055 }
2056
2057 static void wheelHandleEvents(XEvent * event, void *data)
2058 {
2059         W_ColorPanel *panel = (W_ColorPanel *) data;
2060
2061         switch (event->type) {
2062         case Expose:
2063                 if (event->xexpose.count != 0)  /* TODO Improve */
2064                         break;
2065                 wheelPaint(panel);
2066                 break;
2067         }
2068 }
2069
2070 static void wheelHandleActionEvents(XEvent * event, void *data)
2071 {
2072         W_ColorPanel *panel = (W_ColorPanel *) data;
2073
2074         switch (event->type) {
2075         case ButtonPress:
2076                 if (getPickerPart(panel, event->xbutton.x, event->xbutton.y) == COLORWHEEL_PART) {
2077
2078                         panel->lastChanged = WMWheelModeColorPanel;
2079                         panel->flags.dragging = 1;
2080
2081                         wheelPositionSelection(panel, event->xbutton.x, event->xbutton.y);
2082                 }
2083                 break;
2084
2085         case ButtonRelease:
2086                 panel->flags.dragging = 0;
2087                 if (!panel->flags.continuous) {
2088                         if (panel->action)
2089                                 (*panel->action) (panel, panel->clientData);
2090                 }
2091                 break;
2092
2093         case MotionNotify:
2094                 if (panel->flags.dragging) {
2095                         if (getPickerPart(panel, event->xmotion.x, event->xmotion.y) == COLORWHEEL_PART) {
2096                                 wheelPositionSelection(panel, event->xmotion.x, event->xmotion.y);
2097                         } else
2098                                 wheelPositionSelectionOutBounds(panel, event->xmotion.x, event->xmotion.y);
2099                 }
2100                 break;
2101         }
2102 }
2103
2104 static int getPickerPart(W_ColorPanel * panel, int x, int y)
2105 {
2106         int lx, ly;
2107         unsigned long ofs;
2108
2109         lx = x;
2110         ly = y;
2111
2112         if (panel->mode == WMWheelModeColorPanel) {
2113                 if ((lx >= 2) && (lx <= 2 + colorWheelSize) && (ly >= 2) && (ly <= 2 + colorWheelSize)) {
2114
2115                         ofs = ly * panel->wheelMtrx->width + lx;
2116
2117                         if (wheelInsideColorWheel(panel, ofs))
2118                                 return COLORWHEEL_PART;
2119                 }
2120         }
2121
2122         if (panel->mode == WMCustomPaletteModeColorPanel) {
2123                 if ((lx >= 2) && (lx < customPaletteWidth - 2) && (ly >= 2) && (ly < customPaletteHeight - 2)) {
2124                         return CUSTOMPALETTE_PART;
2125                 }
2126         }
2127
2128         return 0;
2129 }
2130
2131 static void wheelBrightnessSliderCallback(WMWidget * w, void *data)
2132 {
2133         int value;
2134
2135         W_ColorPanel *panel = (W_ColorPanel *) data;
2136
2137         value = 255 - WMGetSliderValue(panel->wheelBrightnessS);
2138
2139         wheelCalculateValues(panel, value);
2140
2141         if (panel->color.set == cpRGB) {
2142                 convertCPColor(&panel->color);
2143                 panel->color.set = cpHSV;
2144         }
2145
2146         panel->color.hsv.value = value;
2147
2148         wheelRender(panel);
2149         wheelPaint(panel);
2150         wheelUpdateSelection(panel);
2151 }
2152
2153 static void wheelUpdateSelection(W_ColorPanel * panel)
2154 {
2155         W_Screen *scr = WMWidgetScreen(panel->win);
2156
2157         updateSwatch(panel, panel->color);
2158         panel->lastChanged = WMWheelModeColorPanel;
2159
2160         /* Redraw color selector (and make a backup of the part it will cover) */
2161         XCopyArea(scr->display, panel->wheelImg, panel->selectionBackImg,
2162                   scr->copyGC, panel->colx - 2, panel->coly - 2, 4, 4, 0, 0);
2163         /* "-2" is correction for hotspot location */
2164         XCopyArea(scr->display, panel->selectionImg, panel->wheelView->window,
2165                   scr->copyGC, 0, 0, 4, 4, panel->colx - 2, panel->coly - 2);
2166         /* see above */
2167 }
2168
2169 static void wheelUndrawSelection(W_ColorPanel * panel)
2170 {
2171         W_Screen *scr = WMWidgetScreen(panel->win);
2172
2173         XCopyArea(scr->display, panel->selectionBackImg, panel->wheelView->window,
2174                   scr->copyGC, 0, 0, 4, 4, panel->colx - 2, panel->coly - 2);
2175         /* see above */
2176 }
2177
2178 static void wheelPositionSelection(W_ColorPanel * panel, int x, int y)
2179 {
2180         unsigned long ofs = (y * panel->wheelMtrx->width) + x;
2181
2182         panel->color.rgb.red = panel->wheelMtrx->values[panel->wheelMtrx->data[0][ofs]];
2183
2184         panel->color.rgb.green = panel->wheelMtrx->values[panel->wheelMtrx->data[1][ofs]];
2185
2186         panel->color.rgb.blue = panel->wheelMtrx->values[panel->wheelMtrx->data[2][ofs]];
2187         panel->color.set = cpRGB;
2188
2189         wheelUndrawSelection(panel);
2190
2191         panel->colx = x;
2192         panel->coly = y;
2193
2194         wheelUpdateSelection(panel);
2195         wheelUpdateBrightnessGradientFromLocation(panel);
2196 }
2197
2198 static void wheelPositionSelectionOutBounds(W_ColorPanel * panel, int x, int y)
2199 {
2200         int hue;
2201         int xcor, ycor;
2202         CPColor cpColor;
2203
2204         xcor = x * 2 - colorWheelSize - 4;
2205         ycor = y * 2 - colorWheelSize - 4;
2206
2207         panel->color.hsv.saturation = 255;
2208         panel->color.hsv.value = 255 - WMGetSliderValue(panel->wheelBrightnessS);
2209
2210         if (xcor != 0)
2211                 hue = rint(atan(-(double)ycor / (double)xcor) * (180.0 / M_PI));
2212         else {
2213                 if (ycor < 0)
2214                         hue = 90;
2215                 else
2216                         hue = 270;
2217         }
2218
2219         if (xcor < 0)
2220                 hue += 180;
2221
2222         if ((xcor > 0) && (ycor > 0))
2223                 hue += 360;
2224
2225         panel->color.hsv.hue = hue;
2226         panel->color.set = cpHSV;
2227         convertCPColor(&panel->color);
2228
2229         wheelUndrawSelection(panel);
2230
2231         panel->colx = 2 + rint((colorWheelSize * (1.0 + cos(panel->color.hsv.hue * (M_PI / 180.0)))) / 2.0);
2232         /* "+2" because of "colorWheelSize + 4" */
2233         panel->coly = 2 + rint((colorWheelSize * (1.0 + sin(-panel->color.hsv.hue * (M_PI / 180.0)))) / 2.0);
2234
2235         wheelUpdateSelection(panel);
2236         cpColor = panel->color;
2237         wheelUpdateBrightnessGradient(panel, cpColor);
2238 }
2239
2240 static void wheelUpdateBrightnessGradientFromLocation(W_ColorPanel * panel)
2241 {
2242         CPColor from;
2243         unsigned long ofs;
2244
2245         ofs = panel->coly * panel->wheelMtrx->width + panel->colx;
2246
2247         from.rgb.red = panel->wheelMtrx->data[0][ofs];
2248         from.rgb.green = panel->wheelMtrx->data[1][ofs];
2249         from.rgb.blue = panel->wheelMtrx->data[2][ofs];
2250         from.set = cpRGB;
2251
2252         wheelUpdateBrightnessGradient(panel, from);
2253 }
2254
2255 static void wheelUpdateBrightnessGradient(W_ColorPanel * panel, CPColor topColor)
2256 {
2257         RColor to;
2258         RImage *sliderImg;
2259         WMPixmap *sliderPxmp;
2260
2261         to.red = to.green = to.blue = 0;
2262
2263         if (topColor.set == cpHSV)
2264                 convertCPColor(&topColor);
2265
2266         sliderImg = RRenderGradient(16, 153, &(topColor.rgb), &to, RGRD_VERTICAL);
2267         sliderPxmp = WMCreatePixmapFromRImage(WMWidgetScreen(panel->win), sliderImg, 0);
2268         RReleaseImage(sliderImg);
2269         WMSetSliderImage(panel->wheelBrightnessS, sliderPxmp);
2270         WMReleasePixmap(sliderPxmp);
2271 }
2272
2273 /****************** Grayscale Panel Functions ***************/
2274
2275 static void grayBrightnessSliderCallback(WMWidget * w, void *data)
2276 {
2277         CPColor cpColor;
2278         int value;
2279         char tmp[4];
2280         W_ColorPanel *panel = (W_ColorPanel *) data;
2281
2282         value = WMGetSliderValue(panel->grayBrightnessS);
2283
2284         sprintf(tmp, "%d", value);
2285
2286         WMSetTextFieldText(panel->grayBrightnessT, tmp);
2287         cpColor.rgb.red = cpColor.rgb.green = cpColor.rgb.blue = rint(2.55 * value);
2288         cpColor.set = cpRGB;
2289
2290         updateSwatch(panel, cpColor);
2291         panel->lastChanged = WMGrayModeColorPanel;
2292 }
2293
2294 static void grayPresetButtonCallback(WMWidget * w, void *data)
2295 {
2296         CPColor cpColor;
2297         char tmp[4];
2298         int value;
2299         int i = 0;
2300         W_ColorPanel *panel = (W_ColorPanel *) data;
2301
2302         while (i < 7) {
2303                 if (w == panel->grayPresetBtn[i])
2304                         break;
2305                 i++;
2306         }
2307
2308         value = rint((100.0 * i) / 6.0);
2309         sprintf(tmp, "%d", value);
2310
2311         WMSetTextFieldText(panel->grayBrightnessT, tmp);
2312         cpColor.rgb.red = cpColor.rgb.green = cpColor.rgb.blue = rint((255.0 * i) / 6.0);
2313         cpColor.set = cpRGB;
2314
2315         WMSetSliderValue(panel->grayBrightnessS, rint((100.0 * i) / 6.0));
2316
2317         updateSwatch(panel, cpColor);
2318         panel->lastChanged = WMGrayModeColorPanel;
2319 }
2320
2321 static void grayBrightnessTextFieldCallback(void *observerData, WMNotification * notification)
2322 {
2323         CPColor cpColor;
2324         char tmp[4];
2325         int value;
2326         W_ColorPanel *panel = (W_ColorPanel *) observerData;
2327
2328         value = atoi(WMGetTextFieldText(panel->grayBrightnessT));
2329         if (value > 100)
2330                 value = 100;
2331         if (value < 0)
2332                 value = 0;
2333
2334         sprintf(tmp, "%d", value);
2335         WMSetTextFieldText(panel->grayBrightnessT, tmp);
2336         WMSetSliderValue(panel->grayBrightnessS, value);
2337
2338         cpColor.rgb.red = cpColor.rgb.green = cpColor.rgb.blue = rint((255.0 * value) / 100.0);
2339         cpColor.set = cpRGB;
2340
2341         updateSwatch(panel, cpColor);
2342         panel->lastChanged = WMGrayModeColorPanel;
2343 }
2344
2345 /******************* RGB Panel Functions *****************/
2346
2347 static void rgbSliderCallback(WMWidget * w, void *data)
2348 {
2349         CPColor cpColor;
2350         int value[3];
2351         char tmp[4];
2352         W_ColorPanel *panel = (W_ColorPanel *) data;
2353
2354         value[0] = WMGetSliderValue(panel->rgbRedS);
2355         value[1] = WMGetSliderValue(panel->rgbGreenS);
2356         value[2] = WMGetSliderValue(panel->rgbBlueS);
2357
2358         sprintf(tmp, "%d", value[0]);
2359         WMSetTextFieldText(panel->rgbRedT, tmp);
2360         sprintf(tmp, "%d", value[1]);
2361         WMSetTextFieldText(panel->rgbGreenT, tmp);
2362         sprintf(tmp, "%d", value[2]);
2363         WMSetTextFieldText(panel->rgbBlueT, tmp);
2364
2365         cpColor.rgb.red = value[0];
2366         cpColor.rgb.green = value[1];
2367         cpColor.rgb.blue = value[2];
2368         cpColor.set = cpRGB;
2369
2370         updateSwatch(panel, cpColor);
2371         panel->lastChanged = WMRGBModeColorPanel;
2372 }
2373
2374 static void rgbTextFieldCallback(void *observerData, WMNotification * notification)
2375 {
2376         CPColor cpColor;
2377         int value[3];
2378         char tmp[4];
2379         int n;
2380         W_ColorPanel *panel = (W_ColorPanel *) observerData;
2381
2382         value[0] = atoi(WMGetTextFieldText(panel->rgbRedT));
2383         value[1] = atoi(WMGetTextFieldText(panel->rgbGreenT));
2384         value[2] = atoi(WMGetTextFieldText(panel->rgbBlueT));
2385
2386         for (n = 0; n < 3; n++) {
2387                 if (value[n] > 255)
2388                         value[n] = 255;
2389                 if (value[n] < 0)
2390                         value[n] = 0;
2391         }
2392
2393         sprintf(tmp, "%d", value[0]);
2394         WMSetTextFieldText(panel->rgbRedT, tmp);
2395         sprintf(tmp, "%d", value[1]);
2396         WMSetTextFieldText(panel->rgbGreenT, tmp);
2397         sprintf(tmp, "%d", value[2]);
2398         WMSetTextFieldText(panel->rgbBlueT, tmp);
2399
2400         WMSetSliderValue(panel->rgbRedS, value[0]);
2401         WMSetSliderValue(panel->rgbGreenS, value[1]);
2402         WMSetSliderValue(panel->rgbBlueS, value[2]);
2403
2404         cpColor.rgb.red = value[0];
2405         cpColor.rgb.green = value[1];
2406         cpColor.rgb.blue = value[2];
2407         cpColor.set = cpRGB;
2408
2409         updateSwatch(panel, cpColor);
2410         panel->lastChanged = WMRGBModeColorPanel;
2411 }
2412
2413 /******************* CMYK Panel Functions *****************/
2414
2415 static void cmykSliderCallback(WMWidget * w, void *data)
2416 {
2417         CPColor cpColor;
2418         int value[4];
2419         char tmp[4];
2420         W_ColorPanel *panel = (W_ColorPanel *) data;
2421         double scale;
2422
2423         value[0] = WMGetSliderValue(panel->cmykCyanS);
2424         value[1] = WMGetSliderValue(panel->cmykMagentaS);
2425         value[2] = WMGetSliderValue(panel->cmykYellowS);
2426         value[3] = WMGetSliderValue(panel->cmykBlackS);
2427
2428         sprintf(tmp, "%d", value[0]);
2429         WMSetTextFieldText(panel->cmykCyanT, tmp);
2430         sprintf(tmp, "%d", value[1]);
2431         WMSetTextFieldText(panel->cmykMagentaT, tmp);
2432         sprintf(tmp, "%d", value[2]);
2433         WMSetTextFieldText(panel->cmykYellowT, tmp);
2434         sprintf(tmp, "%d", value[3]);
2435         WMSetTextFieldText(panel->cmykBlackT, tmp);
2436
2437         scale = 2.55 * (1.0 - (value[3] / 100.0));
2438         cpColor.rgb.red = rint((100.0 - value[0]) * scale);
2439         cpColor.rgb.green = rint((100.0 - value[1]) * scale);
2440         cpColor.rgb.blue = rint((100.0 - value[2]) * scale);
2441         cpColor.set = cpRGB;
2442
2443         updateSwatch(panel, cpColor);
2444         panel->lastChanged = WMCMYKModeColorPanel;
2445 }
2446
2447 static void cmykTextFieldCallback(void *observerData, WMNotification * notification)
2448 {
2449         CPColor cpColor;
2450         int value[4];
2451         char tmp[4];
2452         int n;
2453         double scale;
2454         W_ColorPanel *panel = (W_ColorPanel *) observerData;
2455
2456         value[0] = atoi(WMGetTextFieldText(panel->cmykCyanT));
2457         value[1] = atoi(WMGetTextFieldText(panel->cmykMagentaT));
2458         value[2] = atoi(WMGetTextFieldText(panel->cmykYellowT));
2459         value[3] = atoi(WMGetTextFieldText(panel->cmykBlackT));
2460
2461         for (n = 0; n < 4; n++) {
2462                 if (value[n] > 100)
2463                         value[n] = 100;
2464                 if (value[n] < 0)
2465                         value[n] = 0;
2466         }
2467
2468         sprintf(tmp, "%d", value[0]);
2469         WMSetTextFieldText(panel->cmykCyanT, tmp);
2470
2471         sprintf(tmp, "%d", value[1]);
2472         WMSetTextFieldText(panel->cmykMagentaT, tmp);
2473
2474         sprintf(tmp, "%d", value[2]);
2475         WMSetTextFieldText(panel->cmykYellowT, tmp);
2476
2477         sprintf(tmp, "%d", value[3]);
2478         WMSetTextFieldText(panel->cmykBlackT, tmp);
2479
2480         WMSetSliderValue(panel->cmykCyanS, value[0]);
2481         WMSetSliderValue(panel->cmykMagentaS, value[1]);
2482         WMSetSliderValue(panel->cmykYellowS, value[2]);
2483         WMSetSliderValue(panel->cmykBlackS, value[3]);
2484
2485         scale = 2.55 * (1.0 - (value[3] / 100.0));
2486         cpColor.rgb.red = rint((100.0 - value[0]) * scale);
2487         cpColor.rgb.green = rint((100.0 - value[1]) * scale);
2488         cpColor.rgb.blue = rint((100.0 - value[2]) * scale);
2489         cpColor.set = cpRGB;
2490
2491         updateSwatch(panel, cpColor);
2492         panel->lastChanged = WMCMYKModeColorPanel;
2493 }
2494
2495 /********************** HSB Panel Functions ***********************/
2496
2497 static void hsbSliderCallback(WMWidget * w, void *data)
2498 {
2499         CPColor cpColor;
2500         int value[3];
2501         char tmp[4];
2502         W_ColorPanel *panel = (W_ColorPanel *) data;
2503
2504         value[0] = WMGetSliderValue(panel->hsbHueS);
2505         value[1] = WMGetSliderValue(panel->hsbSaturationS);
2506         value[2] = WMGetSliderValue(panel->hsbBrightnessS);
2507
2508         sprintf(tmp, "%d", value[0]);
2509         WMSetTextFieldText(panel->hsbHueT, tmp);
2510         sprintf(tmp, "%d", value[1]);
2511         WMSetTextFieldText(panel->hsbSaturationT, tmp);
2512         sprintf(tmp, "%d", value[2]);
2513         WMSetTextFieldText(panel->hsbBrightnessT, tmp);
2514
2515         cpColor.hsv.hue = value[0];
2516         cpColor.hsv.saturation = value[1] * 2.55;
2517         cpColor.hsv.value = value[2] * 2.55;
2518         cpColor.set = cpHSV;
2519
2520         convertCPColor(&cpColor);
2521
2522         panel->lastChanged = WMHSBModeColorPanel;
2523         updateSwatch(panel, cpColor);
2524
2525         if (w != panel->hsbBrightnessS)
2526                 hsbUpdateBrightnessGradient(panel);
2527         if (w != panel->hsbSaturationS)
2528                 hsbUpdateSaturationGradient(panel);
2529         if (w != panel->hsbHueS)
2530                 hsbUpdateHueGradient(panel);
2531 }
2532
2533 static void hsbTextFieldCallback(void *observerData, WMNotification * notification)
2534 {
2535         CPColor cpColor;
2536         int value[3];
2537         char tmp[4];
2538         int n;
2539         W_ColorPanel *panel = (W_ColorPanel *) observerData;
2540
2541         value[0] = atoi(WMGetTextFieldText(panel->hsbHueT));
2542         value[1] = atoi(WMGetTextFieldText(panel->hsbSaturationT));
2543         value[2] = atoi(WMGetTextFieldText(panel->hsbBrightnessT));
2544
2545         if (value[0] > 359)
2546                 value[0] = 359;
2547         if (value[0] < 0)
2548                 value[0] = 0;
2549
2550         for (n = 1; n < 3; n++) {
2551                 if (value[n] > 100)
2552                         value[n] = 100;
2553                 if (value[n] < 0)
2554                         value[n] = 0;
2555         }
2556
2557         sprintf(tmp, "%d", value[0]);
2558         WMSetTextFieldText(panel->hsbHueT, tmp);
2559         sprintf(tmp, "%d", value[1]);
2560         WMSetTextFieldText(panel->hsbSaturationT, tmp);
2561         sprintf(tmp, "%d", value[2]);
2562         WMSetTextFieldText(panel->hsbBrightnessT, tmp);
2563
2564         WMSetSliderValue(panel->hsbHueS, value[0]);
2565         WMSetSliderValue(panel->hsbSaturationS, value[1]);
2566         WMSetSliderValue(panel->hsbBrightnessS, value[2]);
2567
2568         cpColor.hsv.hue = value[0];
2569         cpColor.hsv.saturation = value[1] * 2.55;
2570         cpColor.hsv.value = value[2] * 2.55;
2571         cpColor.set = cpHSV;
2572
2573         convertCPColor(&cpColor);
2574
2575         panel->lastChanged = WMHSBModeColorPanel;
2576         updateSwatch(panel, cpColor);
2577
2578         hsbUpdateBrightnessGradient(panel);
2579         hsbUpdateSaturationGradient(panel);
2580         hsbUpdateHueGradient(panel);
2581 }
2582
2583 static void hsbUpdateBrightnessGradient(W_ColorPanel * panel)
2584 {
2585         W_Screen *scr = WMWidgetScreen(panel->win);
2586         RColor from;
2587         CPColor to;
2588         RImage *sliderImg;
2589         WMPixmap *sliderPxmp;
2590
2591         from.red = from.green = from.blue = 0;
2592         to.hsv = panel->color.hsv;
2593         to.hsv.value = 255;
2594         to.set = cpHSV;
2595
2596         convertCPColor(&to);
2597
2598         sliderImg = RRenderGradient(141, 16, &from, &(to.rgb), RGRD_HORIZONTAL);
2599         sliderPxmp = WMCreatePixmapFromRImage(scr, sliderImg, 0);
2600         RReleaseImage(sliderImg);
2601
2602         if (sliderPxmp)
2603                 W_PaintText(W_VIEW(panel->hsbBrightnessS), sliderPxmp->pixmap,
2604                             panel->font12, 2, 0, 100, WALeft, scr->white,
2605                             False, _("Brightness"), strlen(_("Brightness")));
2606         else
2607                 wwarning(_("Color Panel: Could not allocate memory"));
2608
2609         WMSetSliderImage(panel->hsbBrightnessS, sliderPxmp);
2610         WMReleasePixmap(sliderPxmp);
2611 }
2612
2613 static void hsbUpdateSaturationGradient(W_ColorPanel * panel)
2614 {
2615         W_Screen *scr = WMWidgetScreen(panel->win);
2616         CPColor from;
2617         CPColor to;
2618         RImage *sliderImg;
2619         WMPixmap *sliderPxmp;
2620
2621         from.hsv = panel->color.hsv;
2622         from.hsv.saturation = 0;
2623         from.set = cpHSV;
2624         convertCPColor(&from);
2625
2626         to.hsv = panel->color.hsv;
2627         to.hsv.saturation = 255;
2628         to.set = cpHSV;
2629         convertCPColor(&to);
2630
2631         sliderImg = RRenderGradient(141, 16, &(from.rgb), &(to.rgb), RGRD_HORIZONTAL);
2632         sliderPxmp = WMCreatePixmapFromRImage(scr, sliderImg, 0);
2633         RReleaseImage(sliderImg);
2634
2635         if (sliderPxmp)
2636                 W_PaintText(W_VIEW(panel->hsbSaturationS), sliderPxmp->pixmap,
2637                             panel->font12, 2, 0, 100, WALeft,
2638                             from.hsv.value < 128 ? scr->white : scr->black, False,
2639                             _("Saturation"), strlen(_("Saturation")));
2640         else
2641                 wwarning(_("Color Panel: Could not allocate memory"));
2642
2643         WMSetSliderImage(panel->hsbSaturationS, sliderPxmp);
2644         WMReleasePixmap(sliderPxmp);
2645 }
2646
2647 static void hsbUpdateHueGradient(W_ColorPanel * panel)
2648 {
2649         W_Screen *scr = WMWidgetScreen(panel->win);
2650         RColor **colors = NULL;
2651         RHSVColor hsvcolor;
2652         RImage *sliderImg;
2653         WMPixmap *sliderPxmp;
2654         int i;
2655
2656         hsvcolor = panel->color.hsv;
2657
2658         colors = wmalloc(sizeof(RColor *) * (8));
2659         for (i = 0; i < 7; i++) {
2660                 hsvcolor.hue = (360 * i) / 6;
2661                 colors[i] = wmalloc(sizeof(RColor));
2662                 RHSVtoRGB(&hsvcolor, colors[i]);
2663         }
2664         colors[7] = NULL;
2665
2666         sliderImg = RRenderMultiGradient(141, 16, colors, RGRD_HORIZONTAL);
2667         sliderPxmp = WMCreatePixmapFromRImage(scr, sliderImg, 0);
2668         RReleaseImage(sliderImg);
2669
2670         if (sliderPxmp)
2671                 W_PaintText(W_VIEW(panel->hsbHueS), sliderPxmp->pixmap,
2672                             panel->font12, 2, 0, 100, WALeft,
2673                             hsvcolor.value < 128 ? scr->white : scr->black, False, _("Hue"), strlen(_("Hue")));
2674         else
2675                 wwarning(_("Color Panel: Could not allocate memory"));
2676
2677         WMSetSliderImage(panel->hsbHueS, sliderPxmp);
2678         WMReleasePixmap(sliderPxmp);
2679
2680         for (i = 0; i < 7; i++)
2681                 wfree(colors[i]);
2682
2683         wfree(colors);
2684 }
2685
2686 /*************** Custom Palette Functions ****************/
2687
2688 static void customRenderSpectrum(W_ColorPanel * panel)
2689 {
2690         RImage *spectrum;
2691         int x, y;
2692         unsigned char *ptr;
2693         CPColor cpColor;
2694
2695         spectrum = RCreateImage(SPECTRUM_WIDTH, SPECTRUM_HEIGHT, False);
2696
2697         ptr = spectrum->data;
2698
2699         for (y = 0; y < SPECTRUM_HEIGHT; y++) {
2700                 cpColor.hsv.hue = y;
2701                 cpColor.hsv.saturation = 0;
2702                 cpColor.hsv.value = 255;
2703                 cpColor.set = cpHSV;
2704
2705                 for (x = 0; x < SPECTRUM_WIDTH; x++) {
2706                         convertCPColor(&cpColor);
2707
2708                         *(ptr++) = (unsigned char)cpColor.rgb.red;
2709                         *(ptr++) = (unsigned char)cpColor.rgb.green;
2710                         *(ptr++) = (unsigned char)cpColor.rgb.blue;
2711
2712                         if (x < (SPECTRUM_WIDTH / 2))
2713                                 cpColor.hsv.saturation++;
2714
2715                         if (x > (SPECTRUM_WIDTH / 2))
2716                                 cpColor.hsv.value--;
2717                 }
2718         }
2719         if (panel->customPaletteImg) {
2720                 RReleaseImage(panel->customPaletteImg);
2721                 panel->customPaletteImg = NULL;
2722         }
2723         panel->customPaletteImg = spectrum;
2724 }
2725
2726 static void customSetPalette(W_ColorPanel * panel)
2727 {
2728         W_Screen *scr = WMWidgetScreen(panel->win);
2729         RImage *scaledImg;
2730         Pixmap image;
2731         int item;
2732
2733         image = XCreatePixmap(scr->display, W_DRAWABLE(scr), customPaletteWidth, customPaletteHeight, scr->depth);
2734         scaledImg = RScaleImage(panel->customPaletteImg, customPaletteWidth, customPaletteHeight);
2735         RConvertImage(scr->rcontext, scaledImg, &image);
2736         RReleaseImage(scaledImg);
2737
2738         XCopyArea(scr->display, image, panel->customPaletteContentView->window,
2739                   scr->copyGC, 0, 0, customPaletteWidth, customPaletteHeight, 0, 0);
2740
2741         /* Check backimage exists. If it doesn't, allocate and fill it */
2742         if (!panel->selectionBackImg) {
2743                 panel->selectionBackImg = XCreatePixmap(scr->display,
2744                                                         panel->customPaletteContentView->window, 4, 4, scr->depth);
2745         }
2746
2747         XCopyArea(scr->display, image, panel->selectionBackImg, scr->copyGC,
2748                   panel->palx - 2, panel->paly - 2, 4, 4, 0, 0);
2749         XCopyArea(scr->display, panel->selectionImg,
2750                   panel->customPaletteContentView->window, scr->copyGC, 0, 0, 4, 4,
2751                   panel->palx - 2, panel->paly - 2);
2752         XFreePixmap(scr->display, image);
2753
2754         panel->palXRatio = (double)(panel->customPaletteImg->width) / (double)(customPaletteWidth);
2755         panel->palYRatio = (double)(panel->customPaletteImg->height) / (double)(customPaletteHeight);
2756
2757         item = WMGetPopUpButtonSelectedItem(panel->customPaletteHistoryBtn);
2758 }
2759
2760 static void customPalettePositionSelection(W_ColorPanel * panel, int x, int y)
2761 {
2762         W_Screen *scr = WMWidgetScreen(panel->win);
2763         unsigned long ofs;
2764
2765         /* undraw selection */
2766         XCopyArea(scr->display, panel->selectionBackImg,
2767                   panel->customPaletteContentView->window, scr->copyGC, 0, 0, 4, 4,
2768                   panel->palx - 2, panel->paly - 2);
2769
2770         panel->palx = x;
2771         panel->paly = y;
2772
2773         ofs = (rint(x * panel->palXRatio) + rint(y * panel->palYRatio) * panel->customPaletteImg->width) * 3;
2774
2775         panel->color.rgb.red = panel->customPaletteImg->data[ofs];
2776         panel->color.rgb.green = panel->customPaletteImg->data[ofs + 1];
2777         panel->color.rgb.blue = panel->customPaletteImg->data[ofs + 2];
2778         panel->color.set = cpRGB;
2779
2780         updateSwatch(panel, panel->color);
2781         panel->lastChanged = WMCustomPaletteModeColorPanel;
2782
2783         /* Redraw color selector (and make a backup of the part it will cover) */
2784         XCopyArea(scr->display, panel->customPaletteContentView->window, panel->selectionBackImg, scr->copyGC, panel->palx - 2, panel->paly - 2, 4, 4, 0, 0);   /* "-2" is correction for hotspot location */
2785         XCopyArea(scr->display, panel->selectionImg, panel->customPaletteContentView->window, scr->copyGC, 0, 0, 4, 4, panel->palx - 2, panel->paly - 2);       /* see above */
2786 }
2787
2788 static void customPalettePositionSelectionOutBounds(W_ColorPanel * panel, int x, int y)
2789 {
2790         if (x < 2)
2791                 x = 2;
2792         if (y < 2)
2793                 y = 2;
2794         if (x >= customPaletteWidth)
2795                 x = customPaletteWidth - 2;
2796         if (y >= customPaletteHeight)
2797                 y = customPaletteHeight - 2;
2798
2799         customPalettePositionSelection(panel, x, y);
2800 }
2801
2802 static void customPaletteHandleEvents(XEvent * event, void *data)
2803 {
2804         W_ColorPanel *panel = (W_ColorPanel *) data;
2805
2806         switch (event->type) {
2807         case Expose:
2808                 if (event->xexpose.count != 0)  /* TODO Improve. */
2809                         break;
2810                 customSetPalette(panel);
2811                 break;
2812         }
2813 }
2814
2815 static void customPaletteHandleActionEvents(XEvent * event, void *data)
2816 {
2817         W_ColorPanel *panel = (W_ColorPanel *) data;
2818         int x, y;
2819
2820         switch (event->type) {
2821         case ButtonPress:
2822                 x = event->xbutton.x;
2823                 y = event->xbutton.y;
2824
2825                 if (getPickerPart(panel, x, y) == CUSTOMPALETTE_PART) {
2826                         panel->flags.dragging = 1;
2827                         customPalettePositionSelection(panel, x, y);
2828                 }
2829                 break;
2830
2831         case ButtonRelease:
2832                 panel->flags.dragging = 0;
2833                 if (!panel->flags.continuous) {
2834                         if (panel->action)
2835                                 (*panel->action) (panel, panel->clientData);
2836                 }
2837                 break;
2838
2839         case MotionNotify:
2840                 x = event->xmotion.x;
2841                 y = event->xmotion.y;
2842
2843                 if (panel->flags.dragging) {
2844                         if (getPickerPart(panel, x, y) == CUSTOMPALETTE_PART) {
2845                                 customPalettePositionSelection(panel, x, y);
2846                         } else
2847                                 customPalettePositionSelectionOutBounds(panel, x, y);
2848                 }
2849                 break;
2850         }
2851 }
2852
2853 static void customPaletteMenuCallback(WMWidget * w, void *data)
2854 {
2855         W_ColorPanel *panel = (W_ColorPanel *) data;
2856         int item = WMGetPopUpButtonSelectedItem(panel->customPaletteMenuBtn);
2857
2858         switch (item) {
2859         case CPmenuNewFromFile:
2860                 customPaletteMenuNewFromFile(panel);
2861                 break;
2862         case CPmenuRename:
2863                 customPaletteMenuRename(panel);
2864                 break;
2865         case CPmenuRemove:
2866                 customPaletteMenuRemove(panel);
2867                 break;
2868         case CPmenuCopy:
2869                 break;
2870         case CPmenuNewFromClipboard:
2871                 break;
2872         }
2873 }
2874
2875 static void customPaletteMenuNewFromFile(W_ColorPanel * panel)
2876 {
2877         W_Screen *scr = WMWidgetScreen(panel->win);
2878         WMOpenPanel *browseP;
2879         char *filepath;
2880         char *filename = NULL;
2881         char *spath;
2882         char *tmp;
2883         int i;
2884         RImage *tmpImg = NULL;
2885
2886         if ((!panel->lastBrowseDir) || (strcmp(panel->lastBrowseDir, "\0") == 0))
2887                 spath = wexpandpath(wgethomedir());
2888         else
2889                 spath = wexpandpath(panel->lastBrowseDir);
2890
2891         browseP = WMGetOpenPanel(scr);
2892         WMSetFilePanelCanChooseDirectories(browseP, 0);
2893         WMSetFilePanelCanChooseFiles(browseP, 1);
2894
2895         /* Get a filename */
2896         if (WMRunModalFilePanelForDirectory(browseP, panel->win, spath,
2897                                             _("Open Palette"), RSupportedFileFormats())) {
2898                 filepath = WMGetFilePanelFileName(browseP);
2899
2900                 /* Get seperation position between path and filename */
2901                 i = strrchr(filepath, '/') - filepath + 1;
2902                 if (i > strlen(filepath))
2903                         i = strlen(filepath);
2904
2905                 /* Store last browsed path */
2906                 if (panel->lastBrowseDir)
2907                         wfree(panel->lastBrowseDir);
2908                 panel->lastBrowseDir = wmalloc((i + 1) * sizeof(char));
2909                 strncpy(panel->lastBrowseDir, filepath, i);
2910                 panel->lastBrowseDir[i] = '\0';
2911
2912                 /* Get filename from path */
2913                 filename = wstrdup(filepath + i);
2914
2915                 /* Check for duplicate files, and rename it if there are any */
2916                 tmp = wstrconcat(panel->configurationPath, filename);
2917                 while (access(tmp, F_OK) == 0) {
2918                         char *newName;
2919
2920                         wfree(tmp);
2921
2922                         newName = generateNewFilename(filename);
2923                         wfree(filename);
2924                         filename = newName;
2925
2926                         tmp = wstrconcat(panel->configurationPath, filename);
2927                 }
2928                 wfree(tmp);
2929
2930                 /* Copy image to $(gnustepdir)/Library/Colors/ &
2931                  * Add filename to history menu */
2932                 if (fetchFile(panel->configurationPath, filepath, filename) == 0) {
2933
2934                         /* filepath is a "local" path now the file has been copied */
2935                         wfree(filepath);
2936                         filepath = wstrconcat(panel->configurationPath, filename);
2937
2938                         /* load the image & add menu entries */
2939                         tmpImg = RLoadImage(scr->rcontext, filepath, 0);
2940                         if (tmpImg) {
2941                                 if (panel->customPaletteImg)
2942                                         RReleaseImage(panel->customPaletteImg);
2943                                 panel->customPaletteImg = tmpImg;
2944
2945                                 customSetPalette(panel);
2946                                 WMAddPopUpButtonItem(panel->customPaletteHistoryBtn, filename);
2947
2948                                 panel->currentPalette =
2949                                     WMGetPopUpButtonNumberOfItems(panel->customPaletteHistoryBtn) - 1;
2950
2951                                 WMSetPopUpButtonSelectedItem(panel->customPaletteHistoryBtn,
2952                                                              panel->currentPalette);
2953                         }
2954                 } else {
2955                         tmp = wstrconcat(panel->configurationPath, filename);
2956
2957                         i = remove(tmp);        /* Delete the file, it doesn't belong here */
2958                         WMRunAlertPanel(scr, panel->win, _("File Error"),
2959                                         _("Invalid file format !"), _("OK"), NULL, NULL);
2960                         if (i != 0) {
2961                                 wsyserror(_("can't remove file %s"), tmp);
2962                                 WMRunAlertPanel(scr, panel->win, _("File Error"),
2963                                                 _("Couldn't remove file from Configuration Directory !"),
2964                                                 _("OK"), NULL, NULL);
2965                         }
2966                         wfree(tmp);
2967                 }
2968                 wfree(filepath);
2969                 wfree(filename);
2970         }
2971         WMFreeFilePanel(browseP);
2972
2973         wfree(spath);
2974 }
2975
2976 static void customPaletteMenuRename(W_ColorPanel * panel)
2977 {
2978         W_Screen *scr = WMWidgetScreen(panel->win);
2979         char *toName = NULL;
2980         char *fromName;
2981         char *toPath, *fromPath;
2982         int item;
2983         int index;
2984
2985         item = WMGetPopUpButtonSelectedItem(panel->customPaletteHistoryBtn);
2986         fromName = WMGetPopUpButtonItem(panel->customPaletteHistoryBtn, item);
2987
2988         toName = WMRunInputPanel(scr, panel->win, _("Rename"), _("Rename palette to:"),
2989                                  fromName, _("OK"), _("Cancel"));
2990
2991         if (toName) {
2992
2993                 /* As some people do certain stupid things... */
2994                 if (strcmp(toName, fromName) == 0) {
2995                         wfree(toName);
2996                         return;
2997                 }
2998
2999                 /* For normal people */
3000                 fromPath = wstrconcat(panel->configurationPath, fromName);
3001                 toPath = wstrconcat(panel->configurationPath, toName);
3002
3003                 if (access(toPath, F_OK) == 0) {
3004                         /* Careful, this palette exists already */
3005                         if (WMRunAlertPanel(scr, panel->win, _("Warning"),
3006                                             _("Palette already exists !\n\nOverwrite ?"), _("No"), _("Yes"),
3007                                             NULL) == 1) {
3008                                 /* "No" = 0, "Yes" = 1 */
3009                                 int items = WMGetPopUpButtonNumberOfItems(panel->customPaletteHistoryBtn);
3010
3011                                 remove(toPath);
3012
3013                                 /* Remove from History list too */
3014                                 index = 1;
3015                                 while ((index < items)
3016                                        &&
3017                                        (strcmp(WMGetPopUpButtonItem(panel->customPaletteHistoryBtn, index), toName)
3018                                         != 0))
3019                                         index++;
3020
3021                                 if (index < items) {
3022                                         WMRemovePopUpButtonItem(panel->customPaletteHistoryBtn, index);
3023                                         if (index < item)
3024                                                 item--;
3025                                 }
3026
3027                         } else {
3028                                 wfree(fromPath);
3029                                 wfree(toName);
3030                                 wfree(toPath);
3031
3032                                 return;
3033                         }
3034                 }
3035
3036                 if (rename(fromPath, toPath) != 0)
3037                         wsyserror(_("Couldn't rename palette %s to %s\n"), fromName, toName);
3038                 else {
3039                         WMRemovePopUpButtonItem(panel->customPaletteHistoryBtn, item);
3040                         WMInsertPopUpButtonItem(panel->customPaletteHistoryBtn, item, toName);
3041
3042                         WMSetPopUpButtonSelectedItem(panel->customPaletteHistoryBtn, item);
3043                 }
3044                 wfree(fromPath);
3045                 wfree(toPath);
3046                 wfree(toName);
3047         }
3048 }
3049
3050 static void customPaletteMenuRemove(W_ColorPanel * panel)
3051 {
3052         W_Screen *scr = WMWidgetScreen(panel->win);
3053         char *text;
3054         char *tmp;
3055         int choice;
3056         int item;
3057
3058         item = WMGetPopUpButtonSelectedItem(panel->customPaletteHistoryBtn);
3059
3060         tmp = wstrconcat(_("This will permanently remove the palette "),
3061                          WMGetPopUpButtonItem(panel->customPaletteHistoryBtn, item));
3062         text = wstrconcat(tmp, _(".\n\nAre you sure you want to remove this palette ?"));
3063         wfree(tmp);
3064
3065         choice = WMRunAlertPanel(scr, panel->win, _("Remove"), text, _("Yes"), _("No"), NULL);
3066         /* returns 0 (= "Yes") or 1 (="No") */
3067         wfree(text);
3068
3069         if (choice == 0) {
3070
3071                 tmp = wstrconcat(panel->configurationPath,
3072                                  WMGetPopUpButtonItem(panel->customPaletteHistoryBtn, item));
3073
3074                 if (remove(tmp) == 0) {
3075                         /* item-1 always exists */
3076                         WMSetPopUpButtonSelectedItem(panel->customPaletteHistoryBtn, item - 1);
3077
3078                         customPaletteHistoryCallback(panel->customPaletteHistoryBtn, panel);
3079                         customSetPalette(panel);
3080
3081                         WMRemovePopUpButtonItem(panel->customPaletteHistoryBtn, item);
3082
3083                 } else {
3084                         wsyserror(_("Couldn't remove palette %s\n"), tmp);
3085                 }
3086
3087                 wfree(tmp);
3088         }
3089 }
3090
3091 static void customPaletteHistoryCallback(WMWidget * w, void *data)
3092 {
3093         W_ColorPanel *panel = (W_ColorPanel *) data;
3094         W_Screen *scr = WMWidgetScreen(panel->win);
3095         int item;
3096         char *filename;
3097         RImage *tmp = NULL;
3098         unsigned char perm_mask;
3099
3100         item = WMGetPopUpButtonSelectedItem(panel->customPaletteHistoryBtn);
3101         if (item == panel->currentPalette)
3102                 return;
3103
3104         if (item == 0) {
3105                 customRenderSpectrum(panel);
3106
3107                 WMSetPopUpButtonItemEnabled(panel->customPaletteMenuBtn, CPmenuRename, False);
3108                 WMSetPopUpButtonItemEnabled(panel->customPaletteMenuBtn, CPmenuRemove, False);
3109         } else {
3110                 /* Load file from configpath */
3111                 filename = wstrconcat(panel->configurationPath,
3112                                       WMGetPopUpButtonItem(panel->customPaletteHistoryBtn, item));
3113
3114                 /* If the file corresponding to the item does not exist,
3115                  * remove it from the history list and select the next one.
3116                  */
3117                 perm_mask = (access(filename, F_OK) == 0);
3118                 if (!perm_mask) {
3119                         /* File does not exist */
3120                         wfree(filename);
3121                         WMSetPopUpButtonSelectedItem(panel->customPaletteHistoryBtn, item - 1);
3122                         WMRemovePopUpButtonItem(panel->customPaletteHistoryBtn, item);
3123                         customPaletteHistoryCallback(w, data);
3124                         return;
3125                 }
3126
3127                 /* Get the image */
3128                 tmp = RLoadImage(scr->rcontext, filename, 0);
3129                 if (tmp) {
3130                         if (panel->customPaletteImg) {
3131                                 RReleaseImage(panel->customPaletteImg);
3132                                 panel->customPaletteImg = NULL;
3133                         }
3134                         panel->customPaletteImg = tmp;
3135                 }
3136
3137                 /* If the image is not writable, don't allow removing/renaming */
3138                 perm_mask = (access(filename, W_OK) == 0);
3139                 WMSetPopUpButtonItemEnabled(panel->customPaletteMenuBtn, CPmenuRename, perm_mask);
3140                 WMSetPopUpButtonItemEnabled(panel->customPaletteMenuBtn, CPmenuRemove, perm_mask);
3141
3142                 wfree(filename);
3143         }
3144         customSetPalette(panel);
3145
3146         panel->currentPalette = item;
3147 }
3148
3149 /************************* ColorList Panel Functions **********************/
3150
3151 static void colorListPaintItem(WMList * lPtr, int index, Drawable d, char *text, int state, WMRect * rect)
3152 {
3153         WMScreen *scr = WMWidgetScreen(lPtr);
3154         Display *dpy = WMScreenDisplay(scr);
3155         WMView *view = W_VIEW(lPtr);
3156         RColor *color = (RColor *) WMGetListItem(lPtr, index)->clientData;
3157         W_ColorPanel *panel = WMGetHangedData(lPtr);
3158         int width, height, x, y;
3159         WMColor *fillColor;
3160
3161         width = rect->size.width;
3162         height = rect->size.height;
3163         x = rect->pos.x;
3164         y = rect->pos.y;
3165
3166         if (state & WLDSSelected)
3167                 XFillRectangle(dpy, d, WMColorGC(scr->white), x, y, width, height);
3168         else
3169                 XFillRectangle(dpy, d, WMColorGC(view->backColor), x, y, width, height);
3170
3171         fillColor = WMCreateRGBColor(scr, color->red << 8, color->green << 8, color->blue << 8, True);
3172
3173         XFillRectangle(dpy, d, WMColorGC(fillColor), x, y, 15, height);
3174         WMReleaseColor(fillColor);
3175
3176         WMDrawString(scr, d, scr->black, panel->font12, x + 18, y, text, strlen(text));
3177 }
3178
3179 static void colorListSelect(WMWidget * w, void *data)
3180 {
3181         W_ColorPanel *panel = (W_ColorPanel *) data;
3182         CPColor cpColor;
3183
3184         cpColor.rgb = *((RColor *) WMGetListSelectedItem(w)->clientData);
3185         cpColor.set = cpRGB;
3186
3187         panel->lastChanged = WMColorListModeColorPanel;
3188         updateSwatch(panel, cpColor);
3189 }
3190
3191 static void colorListColorMenuCallback(WMWidget * w, void *data)
3192 {
3193         W_ColorPanel *panel = (W_ColorPanel *) data;
3194         int item = WMGetPopUpButtonSelectedItem(panel->colorListColorMenuBtn);
3195
3196         switch (item) {
3197         case CLmenuAdd:
3198                 break;
3199         case CLmenuRename:
3200                 break;
3201         case CLmenuRemove:
3202                 break;
3203         }
3204 }
3205
3206 static void colorListListMenuCallback(WMWidget * w, void *data)
3207 {
3208         W_ColorPanel *panel = (W_ColorPanel *) data;
3209         int item = WMGetPopUpButtonSelectedItem(panel->colorListListMenuBtn);
3210
3211         switch (item) {
3212         case CLmenuAdd:
3213                 /* New Color List */
3214                 colorListListMenuNew(panel);
3215                 break;
3216         case CLmenuRename:
3217                 break;
3218         case CLmenuRemove:
3219                 break;
3220         }
3221 }
3222
3223 static void colorListListMenuNew(W_ColorPanel * panel)
3224 {
3225
3226 }
3227
3228 /*************** Panel Initialisation Functions *****************/
3229
3230 static void wheelInit(W_ColorPanel * panel)
3231 {
3232         CPColor cpColor;
3233
3234         if (panel->color.set != cpHSV)
3235                 convertCPColor(&panel->color);
3236
3237         WMSetSliderValue(panel->wheelBrightnessS, 255 - panel->color.hsv.value);
3238
3239         panel->colx = 2 + rint((colorWheelSize / 2.0) *
3240                                (1 + (panel->color.hsv.saturation / 255.0) *
3241                                 cos(panel->color.hsv.hue * M_PI / 180.0)));
3242         panel->coly = 2 + rint((colorWheelSize / 2.0) *
3243                                (1 + (panel->color.hsv.saturation / 255.0) *
3244                                 sin(-panel->color.hsv.hue * M_PI / 180.0)));
3245
3246         wheelCalculateValues(panel, panel->color.hsv.value);
3247
3248         cpColor = panel->color;
3249         cpColor.hsv.value = 255;
3250         cpColor.set = cpHSV;
3251         wheelUpdateBrightnessGradient(panel, cpColor);
3252 }
3253
3254 static void grayInit(W_ColorPanel * panel)
3255 {
3256         int value;
3257         char tmp[4];
3258
3259         if (panel->color.set != cpHSV)
3260                 convertCPColor(&panel->color);
3261
3262         value = rint(panel->color.hsv.value / 2.55);
3263         WMSetSliderValue(panel->grayBrightnessS, value);
3264
3265         sprintf(tmp, "%d", value);
3266         WMSetTextFieldText(panel->grayBrightnessT, tmp);
3267 }
3268
3269 static void rgbInit(W_ColorPanel * panel)
3270 {
3271         char tmp[4];
3272
3273         if (panel->color.set != cpRGB)
3274                 convertCPColor(&panel->color);
3275
3276         WMSetSliderValue(panel->rgbRedS, panel->color.rgb.red);
3277         WMSetSliderValue(panel->rgbGreenS, panel->color.rgb.green);
3278         WMSetSliderValue(panel->rgbBlueS, panel->color.rgb.blue);
3279
3280         sprintf(tmp, "%d", panel->color.rgb.red);
3281         WMSetTextFieldText(panel->rgbRedT, tmp);
3282         sprintf(tmp, "%d", panel->color.rgb.green);
3283         WMSetTextFieldText(panel->rgbGreenT, tmp);
3284         sprintf(tmp, "%d", panel->color.rgb.blue);
3285         WMSetTextFieldText(panel->rgbBlueT, tmp);
3286 }
3287
3288 static void cmykInit(W_ColorPanel * panel)
3289 {
3290         int value[3];
3291         char tmp[4];
3292
3293         if (panel->color.set != cpRGB)
3294                 convertCPColor(&panel->color);
3295
3296         value[0] = rint((255 - panel->color.rgb.red) / 2.55);
3297         value[1] = rint((255 - panel->color.rgb.green) / 2.55);
3298         value[2] = rint((255 - panel->color.rgb.blue) / 2.55);
3299
3300         WMSetSliderValue(panel->cmykCyanS, value[0]);
3301         WMSetSliderValue(panel->cmykMagentaS, value[1]);
3302         WMSetSliderValue(panel->cmykYellowS, value[2]);
3303         WMSetSliderValue(panel->cmykBlackS, 0);
3304
3305         sprintf(tmp, "%d", value[0]);
3306         WMSetTextFieldText(panel->cmykCyanT, tmp);
3307         sprintf(tmp, "%d", value[1]);
3308         WMSetTextFieldText(panel->cmykMagentaT, tmp);
3309         sprintf(tmp, "%d", value[2]);
3310         WMSetTextFieldText(panel->cmykYellowT, tmp);
3311         WMSetTextFieldText(panel->cmykBlackT, "0");
3312 }
3313
3314 static void hsbInit(W_ColorPanel * panel)
3315 {
3316         int value[3];
3317         char tmp[4];
3318
3319         if (panel->color.set != cpHSV)
3320                 convertCPColor(&panel->color);
3321
3322         value[0] = panel->color.hsv.hue;
3323         value[1] = rint(panel->color.hsv.saturation / 2.55);
3324         value[2] = rint(panel->color.hsv.value / 2.55);
3325
3326         WMSetSliderValue(panel->hsbHueS, value[0]);
3327         WMSetSliderValue(panel->hsbSaturationS, value[1]);
3328         WMSetSliderValue(panel->hsbBrightnessS, value[2]);
3329
3330         sprintf(tmp, "%d", value[0]);
3331         WMSetTextFieldText(panel->hsbHueT, tmp);
3332         sprintf(tmp, "%d", value[1]);
3333         WMSetTextFieldText(panel->hsbSaturationT, tmp);
3334         sprintf(tmp, "%d", value[2]);
3335         WMSetTextFieldText(panel->hsbBrightnessT, tmp);
3336
3337         hsbUpdateBrightnessGradient(panel);
3338         hsbUpdateSaturationGradient(panel);
3339         hsbUpdateHueGradient(panel);
3340 }
3341
3342 /************************** Common utility functions ************************/
3343
3344 static int fetchFile(char *toPath, char *srcFile, char *destFile)
3345 {
3346         int src, dest;
3347         int n;
3348         char *tmp;
3349         char buf[BUFSIZE];
3350
3351         if ((src = open(srcFile, O_RDONLY | O_BINARY)) == 0) {
3352                 wsyserror(_("Could not open %s"), srcFile);
3353                 return -1;
3354         }
3355
3356         tmp = wstrconcat(toPath, destFile);
3357         if ((dest = open(tmp, O_RDWR | O_CREAT | O_BINARY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))
3358             == 0) {
3359                 wsyserror(_("Could not create %s"), tmp);
3360                 wfree(tmp);
3361                 return -1;
3362         }
3363         wfree(tmp);
3364
3365         /* Copy the file */
3366         while ((n = read(src, buf, BUFSIZE)) > 0) {
3367                 if (write(dest, buf, n) != n) {
3368                         wsyserror(_("Write error on file %s"), destFile);
3369                         return -1;
3370                 }
3371         }
3372
3373         return 0;
3374 }
3375
3376 char *generateNewFilename(char *curName)
3377 {
3378         int n;
3379         char c;
3380         int baseLen;
3381         char *ptr;
3382         char *newName;
3383
3384         assert(curName);
3385
3386         ptr = curName;
3387
3388         if (((ptr = strrchr(ptr, '{')) == 0) || sscanf(ptr, "{%i}%c", &n, &c) != 1)
3389                 return wstrconcat(curName, " {1}");
3390
3391         baseLen = ptr - curName - 1;
3392
3393         newName = wmalloc(baseLen + 16);
3394         strncpy(newName, curName, baseLen);
3395         newName[baseLen] = 0;
3396
3397         sprintf(&newName[baseLen], " {%i}", n + 1);
3398
3399         return newName;
3400 }
3401
3402 void convertCPColor(CPColor * color)
3403 {
3404         unsigned short old_hue = 0;
3405
3406         switch (color->set) {
3407         case cpNone:
3408                 wwarning(_("Color Panel: Color unspecified"));
3409                 return;
3410         case cpRGB:
3411                 old_hue = color->hsv.hue;
3412                 RRGBtoHSV(&(color->rgb), &(color->hsv));
3413
3414                 /* In black the hue is undefined, and may change by conversion
3415                  * Same for white. */
3416                 if (((color->rgb.red == 0) &&
3417                      (color->rgb.green == 0) &&
3418                      (color->rgb.blue == 0)) ||
3419                     ((color->rgb.red == 0) && (color->rgb.green == 0) && (color->rgb.blue == 255))
3420                     )
3421                         color->hsv.hue = old_hue;
3422                 break;
3423         case cpHSV:
3424                 RHSVtoRGB(&(color->hsv), &(color->rgb));
3425                 break;
3426         }
3427 }
3428
3429 #define ABS_SHIFT(val, shift) \
3430     (((shift) > 0) ? (val) >> (shift) : (val) << -(shift))
3431
3432 RColor ulongToRColor(WMScreen * scr, unsigned long value)
3433 {
3434         RColor color;
3435         XColor *xcolor = NULL;
3436
3437         if (!(xcolor = wmalloc(sizeof(XColor)))) {
3438                 wwarning(_("Color Panel: Could not allocate memory"));
3439                 color.red = 0;
3440                 color.green = 0;
3441                 color.blue = 0;
3442                 return color;
3443         }
3444
3445         xcolor->pixel = value;
3446         XQueryColor(scr->display, scr->rcontext->cmap, xcolor);
3447
3448         color.red = xcolor->red >> 8;
3449         color.green = xcolor->green >> 8;
3450         color.blue = xcolor->blue >> 8;
3451
3452         wfree(xcolor);
3453
3454         return color;
3455 }
3456
3457 unsigned char getShift(unsigned char value)
3458 {
3459         unsigned char i = -1;
3460
3461         if (value == 0)
3462                 return 0;
3463
3464         while (value) {
3465                 value >>= 1;
3466                 i++;
3467         }
3468
3469         return i;
3470 }
3471
3472 #ifdef SHAPE_WAS_DEFINED
3473 #undef SHAPE_WAS_DEFINED
3474 #define SHAPE
3475 #endif