Line data Source code
1 : /* Copyright (C) 2008-2012 by George Williams */
2 : /*
3 : * Redistribution and use in source and binary forms, with or without
4 : * modification, are permitted provided that the following conditions are met:
5 :
6 : * Redistributions of source code must retain the above copyright notice, this
7 : * list of conditions and the following disclaimer.
8 :
9 : * Redistributions in binary form must reproduce the above copyright notice,
10 : * this list of conditions and the following disclaimer in the documentation
11 : * and/or other materials provided with the distribution.
12 :
13 : * The name of the author may not be used to endorse or promote products
14 : * derived from this software without specific prior written permission.
15 :
16 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 : * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 : * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 : * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 : * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 : * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 : * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 : * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 : * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 : */
27 : #include <ggadget.h>
28 : #include <gwidget.h>
29 :
30 : #include <string.h>
31 : #include <stdlib.h>
32 : #include <math.h>
33 :
34 0 : static GImage *ColorWheel(int width,int height) {
35 : struct hslrgb col;
36 : GImage *wheel;
37 : struct _GImage *base;
38 : int i,j;
39 : double x,y, hh, hw;
40 : uint32 *row;
41 :
42 0 : memset(&col,0,sizeof(col));
43 0 : col.v = 1.0;
44 :
45 0 : if ( width<10 ) width = 10;
46 0 : if ( height<10 ) height = 10;
47 0 : hh = height/2.0; hw = width/2.0;
48 :
49 0 : wheel = GImageCreate(it_true,width,height);
50 0 : base = wheel->u.image;
51 0 : for ( i=0; i<height; ++i ) {
52 0 : row = (uint32 *) (base->data + i*base->bytes_per_line);
53 0 : y = (i-hh)/(hh-1);
54 0 : for ( j=0; j<width; ++j ) {
55 0 : x = (j-hw)/(hw-1);
56 0 : col.s = sqrt(x*x + y*y);
57 0 : if ( col.s>1.0 ) {
58 0 : *row++ = 0xffffff;
59 : } else {
60 0 : col.h = atan2(y,x)*180/3.1415926535897932;
61 0 : if ( col.h < 0 ) col.h += 360;
62 0 : gHSV2RGB(&col);
63 0 : *row++ = COLOR_CREATE( (int) rint(255*col.r), (int) rint(255*col.g), (int) rint(255*col.b));
64 : }
65 : }
66 : }
67 0 : return( wheel );
68 : }
69 :
70 : #define GRAD_WIDTH 20
71 0 : static GImage *Gradient(int height) {
72 : GImage *grad;
73 : struct _GImage *base;
74 : int i,j,c;
75 : uint32 *row;
76 :
77 0 : if ( height<10 ) height = 10;
78 :
79 0 : grad = GImageCreate(it_true,GRAD_WIDTH,height);
80 0 : base = grad->u.image;
81 0 : for ( i=0; i<height; ++i ) {
82 0 : row = (uint32 *) (base->data + i*base->bytes_per_line);
83 0 : c = 255*(height-1-i)/(height-1);
84 0 : for ( j=0; j<GRAD_WIDTH; ++j ) {
85 0 : *row++ = COLOR_CREATE(c,c,c);
86 : }
87 : }
88 0 : return( grad );
89 : }
90 :
91 : /* ************************************************************************** */
92 : #define USEFUL_MAX 6
93 :
94 : static uint8 image_data[] = {
95 : 0x00, 0x00,
96 : 0x7f, 0xfe,
97 : 0x7f, 0xfe,
98 : 0x7f, 0xfe,
99 : 0x7f, 0xfe,
100 : 0x7f, 0xfe,
101 : 0x7f, 0xfe,
102 : 0x7f, 0xfe,
103 : 0x7f, 0xfe,
104 : 0x7f, 0xfe,
105 : 0x7f, 0xfe,
106 : 0x00, 0x00,
107 : };
108 : static GClut cluts[2*USEFUL_MAX] = {
109 : { 2, 0, COLOR_UNKNOWN, GCLUT_CLUT_EMPTY },
110 : { 2, 0, COLOR_UNKNOWN, GCLUT_CLUT_EMPTY },
111 : { 2, 0, COLOR_UNKNOWN, GCLUT_CLUT_EMPTY },
112 : { 2, 0, COLOR_UNKNOWN, GCLUT_CLUT_EMPTY },
113 : { 2, 0, COLOR_UNKNOWN, GCLUT_CLUT_EMPTY },
114 : { 2, 0, COLOR_UNKNOWN, GCLUT_CLUT_EMPTY },
115 : { 2, 0, COLOR_UNKNOWN, GCLUT_CLUT_EMPTY },
116 : { 2, 0, COLOR_UNKNOWN, GCLUT_CLUT_EMPTY },
117 : { 2, 0, COLOR_UNKNOWN, GCLUT_CLUT_EMPTY },
118 : { 2, 0, COLOR_UNKNOWN, GCLUT_CLUT_EMPTY },
119 : { 2, 0, COLOR_UNKNOWN, GCLUT_CLUT_EMPTY },
120 : { 2, 0, COLOR_UNKNOWN, GCLUT_CLUT_EMPTY }
121 : };
122 : static struct _GImage bases[2*USEFUL_MAX] = {
123 : { it_mono, 0,16,12,2, (uint8 *) image_data, &cluts[0], COLOR_UNKNOWN },
124 : { it_mono, 0,16,12,2, (uint8 *) image_data, &cluts[1], COLOR_UNKNOWN },
125 : { it_mono, 0,16,12,2, (uint8 *) image_data, &cluts[2], COLOR_UNKNOWN },
126 : { it_mono, 0,16,12,2, (uint8 *) image_data, &cluts[3], COLOR_UNKNOWN },
127 : { it_mono, 0,16,12,2, (uint8 *) image_data, &cluts[4], COLOR_UNKNOWN },
128 : { it_mono, 0,16,12,2, (uint8 *) image_data, &cluts[5], COLOR_UNKNOWN },
129 : { it_mono, 0,16,12,2, (uint8 *) image_data, &cluts[6], COLOR_UNKNOWN },
130 : { it_mono, 0,16,12,2, (uint8 *) image_data, &cluts[7], COLOR_UNKNOWN },
131 : { it_mono, 0,16,12,2, (uint8 *) image_data, &cluts[8], COLOR_UNKNOWN },
132 : { it_mono, 0,16,12,2, (uint8 *) image_data, &cluts[9], COLOR_UNKNOWN },
133 : { it_mono, 0,16,12,2, (uint8 *) image_data, &cluts[10], COLOR_UNKNOWN },
134 : { it_mono, 0,16,12,2, (uint8 *) image_data, &cluts[11], COLOR_UNKNOWN }
135 : };
136 : static GImage blanks[2*USEFUL_MAX] = {
137 : { 0, { &bases[0] }, NULL },
138 : { 0, { &bases[1] }, NULL },
139 : { 0, { &bases[2] }, NULL },
140 : { 0, { &bases[3] }, NULL },
141 : { 0, { &bases[4] }, NULL },
142 : { 0, { &bases[5] }, NULL },
143 : { 0, { &bases[6] }, NULL },
144 : { 0, { &bases[7] }, NULL },
145 : { 0, { &bases[8] }, NULL },
146 : { 0, { &bases[9] }, NULL },
147 : { 0, { &bases[10] }, NULL },
148 : { 0, { &bases[11] }, NULL }
149 : };
150 : /* ************************************************************************** */
151 : struct hslrgba recent_cols[USEFUL_MAX+1];
152 :
153 : struct gcol_data {
154 : GImage *wheel;
155 : GImage *grad;
156 : int wheel_width, wheel_height;
157 : GWindow gw;
158 : GWindow wheelw, gradw, colw;
159 : int done, pressed;
160 : struct hslrgba col, origcol;
161 : struct hslrgba user_cols[USEFUL_MAX+1];
162 : };
163 :
164 : #define CID_Red 1001
165 : #define CID_Green 1002
166 : #define CID_Blue 1003
167 :
168 : #define CID_Hue 1011
169 : #define CID_Saturation 1012
170 : #define CID_Value 1013
171 :
172 : #define CID_Alpha 1019
173 :
174 : #define CID_Wheel 1021
175 : #define CID_Grad 1022
176 : #define CID_Color 1023
177 :
178 : static int cids[] = { CID_Hue, CID_Saturation, CID_Value, CID_Red, CID_Green, CID_Blue, CID_Alpha, 0 };
179 : static char *labnames[] = { N_("Hue:"), N_("Saturation:"), N_("Value:"), N_("Red:"), N_("Green:"), N_("Blue:"), N_("Opacity:") };
180 :
181 0 : static int GCol_OK(GGadget *g, GEvent *e) {
182 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
183 0 : struct gcol_data *d = GDrawGetUserData(GGadgetGetWindow(g));
184 0 : double *offs[7] = { &d->col.h, &d->col.s, &d->col.v, &d->col.r, &d->col.g, &d->col.b, &d->col.alpha };
185 0 : int err = false, i;
186 : double val;
187 :
188 0 : for ( i=0; i<7; ++i ) {
189 0 : val = GetReal8(d->gw,cids[i],_(labnames[i]),&err);
190 0 : if ( err )
191 0 : return( true );
192 0 : if ( i==0 ) {
193 0 : val = fmod(val,360);
194 0 : if ( val<0 ) val += 360;
195 : } else {
196 0 : if ( val<0 || val>1 ) {
197 0 : gwwv_post_error(_("Value out of bounds"), _("Saturation and Value, and the three colors must be between 0 and 1"));
198 0 : return( true );
199 : }
200 : }
201 0 : *offs[i] = val;
202 : }
203 :
204 0 : d->done = true;
205 : }
206 0 : return( true );
207 : }
208 :
209 0 : static int GCol_Cancel(GGadget *g, GEvent *e) {
210 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_buttonactivate ) {
211 0 : struct gcol_data *d = GDrawGetUserData(GGadgetGetWindow(g));
212 0 : d->col.rgb = d->col.hsv = false;
213 0 : d->done = true;
214 : }
215 0 : return( true );
216 : }
217 :
218 0 : static int GCol_TextChanged(GGadget *g, GEvent *e) {
219 0 : if ( e->type==et_controlevent && e->u.control.subtype == et_textchanged ) {
220 0 : struct gcol_data *d = GDrawGetUserData(GGadgetGetWindow(g));
221 0 : double *offs[7] = { &d->col.h, &d->col.s, &d->col.v, &d->col.r, &d->col.g, &d->col.b, &d->col.alpha };
222 0 : int i, err = false;
223 : int low, high;
224 : double val;
225 : char text[50];
226 :
227 0 : if ( GGadgetGetCid(g)==CID_Alpha ) {
228 0 : low = 3; high=7;
229 : /* Didn't actually change the rgb values, but parse them */
230 : /* This is in case we need to clear the error flag */
231 0 : d->col.hsv = false;
232 0 : d->col.rgb = true;
233 0 : } else if ( GGadgetGetCid(g)>=CID_Hue ) {
234 0 : low = 0; high=3;
235 0 : d->col.hsv = true;
236 0 : d->col.rgb = false;
237 : } else {
238 0 : low = 3; high=6;
239 0 : d->col.hsv = false;
240 0 : d->col.rgb = true;
241 : }
242 0 : for ( i=low; i<high; ++i ) {
243 0 : val = GetCalmReal8(d->gw,cids[i],_(labnames[i]),&err);
244 0 : if ( err )
245 0 : break;
246 0 : if ( i==0 ) {
247 0 : val = fmod(val,360);
248 0 : if ( val<0 ) val += 360;
249 : } else {
250 0 : if ( val<0 || val>1 ) {
251 0 : err = true;
252 0 : break;
253 : }
254 : }
255 0 : *offs[i] = val;
256 : }
257 0 : if ( err ) {
258 0 : d->col.hsv = d->col.rgb = false;
259 0 : } else if ( d->col.hsv ) {
260 0 : gHSV2RGB((struct hslrgb *) &d->col);
261 0 : for ( i=3; i<6; ++i ) {
262 0 : sprintf( text, "%.2f", *offs[i]);
263 0 : GGadgetSetTitle8(GWidgetGetControl(d->gw,cids[i]),text);
264 : }
265 : } else {
266 0 : gRGB2HSV((struct hslrgb *) &d->col);
267 0 : sprintf( text, "%3.0f", *offs[0]);
268 0 : GGadgetSetTitle8(GWidgetGetControl(d->gw,cids[0]),text);
269 0 : for ( i=1; i<3; ++i ) {
270 0 : sprintf( text, "%.2f", *offs[i]);
271 0 : GGadgetSetTitle8(GWidgetGetControl(d->gw,cids[i]),text);
272 : }
273 : }
274 0 : GDrawRequestExpose(d->wheelw,NULL,false);
275 0 : GDrawRequestExpose(d->gradw,NULL,false);
276 0 : GDrawRequestExpose(d->colw,NULL,false);
277 : }
278 0 : return( true );
279 : }
280 :
281 0 : static void GCol_ShowTexts(struct gcol_data *d) {
282 0 : double *offs[7] = { &d->col.h, &d->col.s, &d->col.v, &d->col.r, &d->col.g, &d->col.b, &d->col.alpha };
283 : int i;
284 : char text[50];
285 :
286 0 : gHSV2RGB((struct hslrgb *) &d->col);
287 0 : sprintf( text, "%3.0f", *offs[0]);
288 0 : GGadgetSetTitle8(GWidgetGetControl(d->gw,cids[0]),text);
289 0 : for ( i=1; i<7; ++i ) {
290 0 : sprintf( text, "%.2f", *offs[i]);
291 0 : GGadgetSetTitle8(GWidgetGetControl(d->gw,cids[i]),text);
292 : }
293 0 : }
294 :
295 0 : static int wheel_e_h(GWindow gw, GEvent *event) {
296 0 : struct gcol_data *d = GDrawGetUserData(gw);
297 : GRect size;
298 0 : if ( event->type==et_expose ) {
299 : GRect circle;
300 0 : GDrawGetSize(d->wheelw,&size);
301 0 : if ( d->wheel==NULL ||
302 0 : GImageGetHeight(d->wheel)!=size.height ||
303 0 : GImageGetWidth(d->wheel)!=size.width ) {
304 0 : if ( d->wheel!=NULL )
305 0 : GImageDestroy(d->wheel);
306 0 : d->wheel = ColorWheel(size.width,size.height);
307 : }
308 0 : GDrawDrawImage(gw,d->wheel,NULL,0,0);
309 0 : if ( d->col.hsv ) {
310 0 : double s = sin(d->col.h*3.1415926535897932/180.);
311 0 : double c = cos(d->col.h*3.1415926535897932/180.);
312 0 : int y = (int) rint(d->col.s*(size.height-1)*s/2.0) + size.height/2;
313 0 : int x = (int) rint(d->col.s*(size.width-1)*c/2.0) + size.width/2;
314 0 : circle.x = x-3; circle.y = y-3;
315 0 : circle.width = circle.height = 7;
316 0 : GDrawDrawElipse(gw,&circle,0x000000);
317 : }
318 0 : } else if ( event->type == et_mousedown ||
319 0 : (event->type==et_mousemove && d->pressed) ||
320 0 : event->type==et_mouseup ) {
321 : Color rgb;
322 : struct hslrgba temp;
323 0 : GDrawGetSize(d->wheelw,&size);
324 0 : if ( event->u.mouse.y>=0 && event->u.mouse.y<size.height &&
325 0 : event->u.mouse.x>=0 && event->u.mouse.x<size.width ) {
326 0 : rgb = GImageGetPixelRGBA(d->wheel,event->u.mouse.x,event->u.mouse.y);
327 0 : temp.r = ((rgb>>16)&0xff)/255.;
328 0 : temp.g = ((rgb>>8)&0xff)/255.;
329 0 : temp.b = ((rgb )&0xff)/255.;
330 0 : gRGB2HSV((struct hslrgb *) &temp);
331 0 : d->col.h = temp.h; d->col.s = temp.s;
332 0 : GCol_ShowTexts(d);
333 0 : GDrawRequestExpose(d->colw,NULL,false);
334 0 : GDrawRequestExpose(d->wheelw,NULL,false);
335 : }
336 0 : if ( event->type == et_mousedown )
337 0 : d->pressed = true;
338 0 : else if ( event->type == et_mouseup )
339 0 : d->pressed = false;
340 0 : } else if ( event->type==et_resize ) {
341 0 : GDrawRequestExpose(gw,NULL,false);
342 0 : } else if ( event->type == et_char ) {
343 0 : return( false );
344 : }
345 0 : return( true );
346 : }
347 :
348 0 : static int grad_e_h(GWindow gw, GEvent *event) {
349 0 : struct gcol_data *d = GDrawGetUserData(gw);
350 : GRect size;
351 0 : if ( event->type==et_expose ) {
352 0 : GDrawGetSize(d->wheelw,&size);
353 0 : if ( d->grad==NULL || GImageGetHeight(d->grad)!=size.height ) {
354 0 : if ( d->grad!=NULL )
355 0 : GImageDestroy(d->grad);
356 0 : d->grad = Gradient(size.height);
357 : }
358 0 : GDrawDrawImage(gw,d->grad,NULL,0,0);
359 0 : if ( d->col.hsv ) {
360 0 : int y = size.height-1-(int) rint(size.height*d->col.v);
361 0 : int col = d->col.v>.5 ? 0x000000 : 0xffffff;
362 0 : GDrawDrawLine(gw,0,y,GRAD_WIDTH,y,col);
363 : }
364 0 : } else if ( event->type == et_mousedown ||
365 0 : (event->type==et_mousemove && d->pressed) ||
366 0 : event->type==et_mouseup ) {
367 0 : GDrawGetSize(d->wheelw,&size);
368 0 : if ( event->u.mouse.y<0 )
369 0 : event->u.mouse.y =0;
370 0 : else if ( event->u.mouse.y>=size.height )
371 0 : event->u.mouse.y = size.height-1;
372 0 : d->col.v = (size.height-1-event->u.mouse.y) / (double) (size.height-1);
373 0 : if ( d->col.v<0 ) d->col.v = 0;
374 0 : if ( d->col.v>1 ) d->col.v = 1;
375 0 : GCol_ShowTexts(d);
376 0 : GDrawRequestExpose(d->colw,NULL,false);
377 0 : GDrawRequestExpose(d->gradw,NULL,false);
378 0 : if ( event->type == et_mousedown )
379 0 : d->pressed = true;
380 0 : else if ( event->type == et_mouseup )
381 0 : d->pressed = false;
382 0 : } else if ( event->type==et_resize ) {
383 0 : GDrawRequestExpose(gw,NULL,false);
384 0 : } else if ( event->type == et_char ) {
385 0 : return( false );
386 : }
387 0 : return( true );
388 : }
389 :
390 0 : static void TranslucentRect(GWindow gw,GRect *size,int col,double alpha, int h) {
391 0 : if ( alpha==1.0 )
392 0 : GDrawFillRect(gw,size,col);
393 : else {
394 0 : int r = COLOR_RED(col), g = COLOR_GREEN(col), b = COLOR_BLUE(col);
395 0 : double white_bias = 255.*(1.0-alpha);
396 0 : Color dark = (((int) rint(r*alpha))<<16) |
397 0 : (((int) rint(g*alpha))<<8 ) |
398 0 : (((int) rint(b*alpha)) );
399 0 : Color light= (((int) rint(white_bias+r*alpha))<<16) |
400 0 : (((int) rint(white_bias+g*alpha))<<8 ) |
401 0 : (((int) rint(white_bias+b*alpha)) );
402 : GRect small, old;
403 : int x,y;
404 0 : int smallh = (h+1)/2;
405 :
406 0 : small.height = small.width = smallh;
407 0 : GDrawPushClip(gw,size,&old);
408 0 : for ( y=0; y<2; ++y ) {
409 0 : small.y = y*smallh;
410 0 : for ( x=size->x/smallh; x<=(size->x+size->width)/smallh; ++x ) {
411 0 : small.x = x*smallh;
412 0 : GDrawFillRect(gw,&small,((x+y)&1)?dark : light);
413 : }
414 : }
415 0 : GDrawPopClip(gw,&old);
416 : }
417 0 : }
418 :
419 0 : static int col_e_h(GWindow gw, GEvent *event) {
420 : GRect size, r;
421 0 : if ( event->type==et_expose ) {
422 0 : struct gcol_data *d = GDrawGetUserData(gw);
423 0 : GDrawGetSize(d->colw,&size);
424 0 : r = event->u.expose.rect;
425 0 : if ( r.x<size.width/2 ) {
426 0 : int col = (((int) rint(255*d->origcol.r))<<16) |
427 0 : (((int) rint(255*d->origcol.g))<<8 ) |
428 0 : (((int) rint(255*d->origcol.b)) );
429 0 : if ( r.x+r.width>size.width/2 )
430 0 : r.width = size.width/2-r.x;
431 0 : TranslucentRect(gw,&r,col,d->origcol.alpha,size.height);
432 0 : r.width = event->u.expose.rect.width;
433 : }
434 0 : if ( r.x+r.width>size.width/2 ) {
435 0 : r.width = r.x+r.width - size.width/2;
436 0 : r.x = size.width/2;
437 0 : if ( d->col.rgb ) {
438 0 : int col = (((int) rint(255*d->col.r))<<16) |
439 0 : (((int) rint(255*d->col.g))<<8 ) |
440 0 : (((int) rint(255*d->col.b)) );
441 0 : TranslucentRect(gw,&r,col,d->col.alpha,size.height);
442 : } else {
443 0 : GDrawSetStippled(gw,2,0,0);
444 0 : GDrawSetBackground(gw,0xffff00);
445 0 : GDrawFillRect(gw,&r,0x000000);
446 0 : GDrawSetStippled(gw,0,0,0);
447 : }
448 : }
449 0 : } else if ( event->type == et_mousedown ) {
450 0 : struct gcol_data *d = GDrawGetUserData(gw);
451 0 : GDrawGetSize(d->colw,&size);
452 0 : if ( event->u.mouse.x<size.width/2 ) {
453 0 : d->col = d->origcol;
454 0 : GCol_ShowTexts(d);
455 0 : GDrawRequestExpose(d->wheelw,NULL,false);
456 0 : GDrawRequestExpose(d->colw,NULL,false);
457 0 : GDrawRequestExpose(d->gradw,NULL,false);
458 : }
459 0 : } else if ( event->type==et_resize ) {
460 0 : GDrawRequestExpose(gw,NULL,false);
461 0 : } else if ( event->type == et_char ) {
462 0 : return( false );
463 : }
464 0 : return( true );
465 : }
466 :
467 0 : static void do_popup_color(GWindow gw,struct gmenuitem *mi,GEvent *e) {
468 0 : struct gcol_data *d = GDrawGetUserData(gw);
469 0 : const struct hslrgba *col = mi->ti.userdata;
470 :
471 0 : d->col = *col;
472 0 : GCol_ShowTexts(d);
473 0 : GDrawRequestExpose(d->wheelw,NULL,false);
474 0 : GDrawRequestExpose(d->colw,NULL,false);
475 0 : GDrawRequestExpose(d->gradw,NULL,false);
476 0 : }
477 :
478 0 : static int popup_e_h(GWindow gw, GEvent *event) {
479 0 : struct gcol_data *d = GDrawGetUserData(gw);
480 0 : if ( recent_cols[0].hsv || d->user_cols[0].hsv ) {
481 0 : if ( event->type==et_expose ) {
482 0 : GDrawDrawLine(gw,1,1,GRAD_WIDTH-2,1,0x000000);
483 0 : GDrawDrawLine(gw,1,1,GRAD_WIDTH/2-1,GRAD_WIDTH-2,0x000000);
484 0 : GDrawDrawLine(gw,GRAD_WIDTH/2-1,GRAD_WIDTH-2,GRAD_WIDTH-2,1,0x000000);
485 0 : } else if ( event->type == et_mousedown ) {
486 : GMenuItem menu[2*USEFUL_MAX+2];
487 : int i,j,k;
488 :
489 0 : memset(menu,0,sizeof(menu));
490 0 : for ( i=0; i<USEFUL_MAX && recent_cols[i].hsv; ++i ) {
491 0 : menu[i].ti.image = &blanks[i];
492 0 : cluts[i].clut[1] = (((int) rint(255.*recent_cols[i].r))<<16 ) |
493 0 : (((int) rint(255.*recent_cols[i].g))<<8 ) |
494 0 : (((int) rint(255.*recent_cols[i].b)) );
495 0 : menu[i].ti.fg = menu[i].ti.bg = COLOR_DEFAULT;
496 0 : menu[i].ti.userdata = &recent_cols[i];
497 0 : menu[i].invoke = do_popup_color;
498 : }
499 0 : j=i;
500 0 : if ( i!=0 && d->user_cols[0].hsv ) {
501 0 : menu[i].ti.line = true;
502 0 : menu[i].ti.fg = menu[i].ti.bg = COLOR_DEFAULT;
503 0 : ++i;
504 : }
505 0 : for ( k=0; k<USEFUL_MAX && d->user_cols[k].hsv; ++k, ++i, ++j ) {
506 0 : menu[i].ti.image = &blanks[j];
507 0 : cluts[j].clut[1] = (((int) rint(255.*d->user_cols[k].r))<<16 ) |
508 0 : (((int) rint(255.*d->user_cols[k].g))<<8 ) |
509 0 : (((int) rint(255.*d->user_cols[k].b)) );
510 0 : menu[i].ti.fg = menu[i].ti.bg = COLOR_DEFAULT;
511 0 : menu[i].ti.userdata = &d->user_cols[k];
512 0 : menu[i].invoke = do_popup_color;
513 : }
514 0 : GMenuCreatePopupMenu(gw,event, menu);
515 : }
516 : }
517 :
518 0 : if ( event->type == et_char )
519 0 : return( false );
520 :
521 0 : return( true );
522 : }
523 :
524 0 : static int e_h(GWindow gw, GEvent *event) {
525 0 : if ( event->type==et_close ) {
526 0 : struct gcol_data *d = GDrawGetUserData(gw);
527 0 : d->col.rgb = d->col.hsv = false;
528 0 : d->done = true;
529 0 : } else if ( event->type == et_char ) {
530 0 : return( false );
531 : }
532 0 : return( true );
533 : }
534 :
535 0 : struct hslrgba GWidgetColorA(const char *title,struct hslrgba *defcol,struct hslrgba *usercols) {
536 : GRect pos;
537 : GWindow gw;
538 : GWindowAttrs wattrs;
539 : GGadgetCreateData gcd[23], boxes[6], *txarray[9][3], *wheelarray[3][3], *barray[8], *hvarray[3][3];
540 : GTextInfo label[21];
541 : struct gcol_data d;
542 : int k, i;
543 0 : double *offs[7] = { &d.col.h, &d.col.s, &d.col.v, &d.col.r, &d.col.g, &d.col.b, &d.col.alpha };
544 : char values[7][40];
545 :
546 0 : GProgressPauseTimer();
547 0 : memset(&d,0,sizeof(d));
548 0 : memset(&wattrs,0,sizeof(wattrs));
549 0 : wattrs.mask = wam_events|wam_cursor|wam_utf8_wtitle|wam_undercursor|wam_restrict|wam_isdlg;
550 0 : wattrs.event_masks = ~(1<<et_charup);
551 0 : wattrs.restrict_input_to_me = 1;
552 0 : wattrs.undercursor = 1;
553 0 : wattrs.is_dlg = true;
554 0 : wattrs.cursor = ct_pointer;
555 0 : wattrs.utf8_window_title = title;
556 0 : pos.x = pos.y = 0;
557 0 : pos.width = pos.height = 200;
558 0 : d.gw = gw = GDrawCreateTopWindow(NULL,&pos,e_h,&d,&wattrs);
559 :
560 0 : if ( defcol!=NULL && (defcol->rgb || defcol->hsv || defcol->hsl ))
561 0 : d.col = *defcol;
562 0 : else if ( recent_cols[0].hsv ) {
563 0 : d.col = recent_cols[0];
564 0 : d.col.has_alpha = true;
565 0 : } else if ( usercols!=NULL && (usercols[0].rgb || usercols[0].hsv || usercols[0].hsl )) {
566 0 : d.col = usercols[0];
567 0 : d.col.has_alpha = true;
568 : } else {
569 0 : d.col.rgb = true;
570 0 : d.col.r = d.col.g = d.col.b = 1.0;
571 0 : d.col.alpha = 1.0;
572 0 : d.col.has_alpha = true;
573 : }
574 0 : if ( d.col.rgb ) {
575 0 : if ( !d.col.hsv )
576 0 : gRGB2HSV((struct hslrgb *) &d.col);
577 0 : } else if ( d.col.hsv )
578 0 : gHSV2RGB((struct hslrgb *) &d.col);
579 : else {
580 0 : gHSL2RGB((struct hslrgb *) &d.col);
581 0 : gRGB2HSV((struct hslrgb *) &d.col);
582 : }
583 0 : d.origcol = d.col;
584 0 : if ( usercols!=NULL ) {
585 0 : for ( i=0; i<6 && (usercols[i].rgb || usercols[i].hsv || usercols[i].hsl ); ++i ) {
586 0 : d.user_cols[i] = usercols[i];
587 0 : if ( d.user_cols[i].rgb ) {
588 0 : if ( !d.user_cols[i].hsv )
589 0 : gRGB2HSV((struct hslrgb *) &d.user_cols[i]);
590 0 : } else if ( d.user_cols[i].hsv )
591 0 : gHSV2RGB((struct hslrgb *) &d.user_cols[i]);
592 : else {
593 0 : gHSL2RGB((struct hslrgb *) &d.user_cols[i]);
594 0 : gRGB2HSV((struct hslrgb *) &d.user_cols[i]);
595 : }
596 : }
597 : }
598 :
599 0 : k=0;
600 0 : memset(&gcd,0,sizeof(gcd));
601 0 : memset(&label,0,sizeof(label));
602 0 : memset(&boxes,0,sizeof(boxes));
603 :
604 0 : gcd[k].gd.pos.height = gcd[k].gd.pos.width = 150;
605 0 : if ( d.col.has_alpha )
606 0 : gcd[k].gd.pos.height = gcd[k].gd.pos.width = 170;
607 0 : gcd[k].gd.flags = gg_visible | gg_enabled;
608 0 : gcd[k].gd.u.drawable_e_h = wheel_e_h;
609 0 : gcd[k].gd.cid = CID_Wheel;
610 0 : gcd[k].creator = GDrawableCreate;
611 0 : wheelarray[0][0] = &gcd[k++];
612 :
613 0 : gcd[k].gd.pos.height = 150; gcd[k].gd.pos.width = GRAD_WIDTH;
614 0 : gcd[k].gd.flags = gg_visible | gg_enabled;
615 0 : gcd[k].gd.u.drawable_e_h = grad_e_h;
616 0 : gcd[k].gd.cid = CID_Grad;
617 0 : gcd[k].creator = GDrawableCreate;
618 0 : wheelarray[0][1] = &gcd[k++]; wheelarray[0][2] = NULL;
619 :
620 0 : gcd[k].gd.pos.width = 150; gcd[k].gd.pos.height = GRAD_WIDTH;
621 0 : gcd[k].gd.flags = gg_visible | gg_enabled;
622 0 : gcd[k].gd.u.drawable_e_h = col_e_h;
623 0 : gcd[k].gd.cid = CID_Color;
624 0 : gcd[k].creator = GDrawableCreate;
625 0 : wheelarray[1][0] = &gcd[k++];
626 :
627 0 : gcd[k].gd.pos.width = GRAD_WIDTH; gcd[k].gd.pos.height = GRAD_WIDTH;
628 0 : gcd[k].gd.flags = gg_visible | gg_enabled;
629 0 : gcd[k].gd.u.drawable_e_h = popup_e_h;
630 0 : gcd[k].creator = GDrawableCreate;
631 0 : wheelarray[1][1] = &gcd[k++]; wheelarray[1][2] = NULL;
632 0 : wheelarray[2][0] = NULL;
633 :
634 0 : boxes[2].gd.flags = gg_enabled|gg_visible;
635 0 : boxes[2].gd.u.boxelements = wheelarray[0];
636 0 : boxes[2].creator = GHVBoxCreate;
637 :
638 0 : for ( i=0; i<7; ++i ) {
639 0 : label[k].text = (unichar_t *) _(labnames[i]);
640 0 : label[k].text_is_1byte = true;
641 0 : label[k].text_in_resource = true;
642 0 : gcd[k].gd.label = &label[k];
643 0 : gcd[k].gd.flags = gg_visible | gg_enabled ;
644 0 : gcd[k++].creator = GLabelCreate;
645 0 : txarray[i][0] = &gcd[k-1];
646 :
647 0 : if ( i==0 )
648 0 : sprintf( values[0], "%3.0f", *offs[0]);
649 : else
650 0 : sprintf( values[i], "%.2f", *offs[i]);
651 0 : label[k].text = (unichar_t *) values[i];
652 0 : label[k].text_is_1byte = true;
653 0 : gcd[k].gd.label = &label[k];
654 0 : gcd[k].gd.pos.width = 60;
655 0 : gcd[k].gd.flags = gg_visible | gg_enabled;
656 0 : gcd[k].gd.cid = cids[i];
657 0 : gcd[k].gd.handle_controlevent = GCol_TextChanged;
658 0 : gcd[k++].creator = i==0 ? GNumericFieldCreate : GTextFieldCreate;
659 0 : txarray[i][1] = &gcd[k-1]; txarray[i][2] = NULL;
660 : }
661 0 : if ( !d.col.has_alpha ) {
662 0 : gcd[k-1].gd.flags &= ~gg_visible;
663 0 : gcd[k-2].gd.flags &= ~gg_visible;
664 : }
665 0 : txarray[i][0] = txarray[i][1] = GCD_Glue; txarray[i][2] = NULL;
666 0 : txarray[i+1][0] = NULL;
667 :
668 0 : boxes[3].gd.flags = gg_enabled|gg_visible;
669 0 : boxes[3].gd.u.boxelements = txarray[0];
670 0 : boxes[3].creator = GHVBoxCreate;
671 :
672 0 : gcd[k].gd.flags = gg_visible | gg_enabled | gg_but_default;
673 0 : label[k].text = (unichar_t *) _("_OK");
674 0 : label[k].text_is_1byte = true;
675 0 : label[k].text_in_resource = true;
676 0 : gcd[k].gd.label = &label[k];
677 0 : gcd[k].gd.handle_controlevent = GCol_OK;
678 0 : gcd[k++].creator = GButtonCreate;
679 0 : barray[0] = GCD_Glue; barray[1] = &gcd[k-1]; barray[2] = GCD_Glue;
680 :
681 0 : gcd[k].gd.flags = gg_visible | gg_enabled | gg_but_cancel;
682 0 : label[k].text = (unichar_t *) _("_Cancel");
683 0 : label[k].text_is_1byte = true;
684 0 : label[k].text_in_resource = true;
685 0 : gcd[k].gd.label = &label[k];
686 0 : gcd[k].gd.handle_controlevent = GCol_Cancel;
687 0 : gcd[k].creator = GButtonCreate;
688 0 : barray[3] = GCD_Glue; barray[4] = &gcd[k]; barray[5] = GCD_Glue;
689 0 : barray[6] = NULL;
690 :
691 0 : boxes[4].gd.flags = gg_enabled|gg_visible;
692 0 : boxes[4].gd.u.boxelements = barray;
693 0 : boxes[4].creator = GHBoxCreate;
694 :
695 0 : hvarray[0][0] = &boxes[2];
696 0 : hvarray[0][1] = &boxes[3];
697 0 : hvarray[0][2] = NULL;
698 0 : hvarray[1][0] = &boxes[4];
699 0 : hvarray[1][1] = GCD_ColSpan;
700 0 : hvarray[1][2] = NULL;
701 0 : hvarray[2][0] = NULL;
702 :
703 0 : boxes[0].gd.pos.x = boxes[0].gd.pos.y = 2;
704 0 : boxes[0].gd.flags = gg_enabled|gg_visible;
705 0 : boxes[0].gd.u.boxelements = hvarray[0];
706 0 : boxes[0].creator = GHVGroupCreate;
707 0 : GGadgetsCreate(gw,boxes);
708 0 : GHVBoxSetExpandableRow(boxes[0].ret,0);
709 0 : GHVBoxSetExpandableCol(boxes[0].ret,0);
710 0 : GHVBoxSetExpandableRow(boxes[2].ret,0);
711 0 : GHVBoxSetExpandableCol(boxes[2].ret,0);
712 0 : GHVBoxSetExpandableRow(boxes[3].ret,gb_expandglue);
713 0 : GHVBoxSetExpandableCol(boxes[4].ret,gb_expandgluesame);
714 0 : GHVBoxFitWindow(boxes[0].ret);
715 0 : d.wheelw = GDrawableGetWindow(GWidgetGetControl(gw,CID_Wheel));
716 0 : d.gradw = GDrawableGetWindow(GWidgetGetControl(gw,CID_Grad));
717 0 : d.colw = GDrawableGetWindow(GWidgetGetControl(gw,CID_Color));
718 0 : GDrawSetVisible(gw,true);
719 :
720 0 : while ( !d.done )
721 0 : GDrawProcessOneEvent(NULL);
722 0 : GDrawDestroyWindow(gw);
723 0 : if ( d.grad!=NULL )
724 0 : GImageDestroy(d.grad);
725 0 : if ( d.wheel!=NULL )
726 0 : GImageDestroy(d.wheel);
727 0 : if ( d.col.hsv || d.col.rgb ) {
728 : int j;
729 0 : for ( j=0; j<USEFUL_MAX; ++j )
730 0 : if ( d.col.r==recent_cols[j].r && d.col.g==recent_cols[j].g &&
731 0 : d.col.b==recent_cols[j].b &&
732 0 : (!d.col.has_alpha || d.col.alpha==recent_cols[j].alpha))
733 : break;
734 0 : if ( j==USEFUL_MAX )
735 0 : --j;
736 0 : for ( ; j>0; --j )
737 0 : recent_cols[j] = recent_cols[j-1];
738 0 : recent_cols[0] = d.col;
739 : }
740 0 : return( d.col );
741 : }
742 :
743 0 : struct hslrgb GWidgetColor(const char *title,struct hslrgb *defcol,struct hslrgb *usercols) {
744 : struct hslrgba def, users[USEFUL_MAX+1], *d, *u, temp;
745 : struct hslrgb ret;
746 : int i;
747 0 : if ( usercols==NULL )
748 0 : u = NULL;
749 : else {
750 0 : for ( i=0; i<6 && (usercols[i].rgb || usercols[i].hsv || usercols[i].hsl ); ++i ) {
751 0 : memcpy(&users[i],&usercols[i],sizeof(struct hslrgb));
752 0 : users[i].has_alpha = 0;
753 0 : users[i].alpha = 1.0;
754 : }
755 0 : u = users;
756 : }
757 :
758 0 : if ( defcol!=NULL )
759 0 : memcpy(&def,defcol,sizeof(*defcol));
760 0 : else if ( recent_cols[0].hsv )
761 0 : def = recent_cols[0];
762 0 : else if ( u!=NULL && (u[0].rgb || u[0].hsv || u[0].hsl ))
763 0 : def = u[0];
764 : else {
765 0 : def.rgb = true;
766 0 : def.r = def.g = def.b = 1.0;
767 : }
768 0 : def.has_alpha = false;
769 0 : def.alpha = 1.0;
770 0 : d = &def;
771 0 : temp = GWidgetColorA(title,d,u);
772 0 : memcpy(&ret,&temp,sizeof(ret));
773 0 : return( ret );
774 : }
|