titler fixes, auto paste bug, resize popup hang, focus policy fix, chk lang
[goodguy/history.git] / cinelerra-5.1 / cinelerra / colorpicker.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 1997-2011 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "bcbutton.h"
23 #include "bccapture.h"
24 #include "bcdisplayinfo.h"
25 #include "colorpicker.h"
26 #include "condition.h"
27 #include "keys.h"
28 #include "language.h"
29 #include "mutex.h"
30 #include "mwindow.h"
31 #include "cicolors.h"
32 #include "vframe.h"
33
34 #include <string.h>
35 #include <unistd.h>
36
37 #define PALETTE_DATA "palette.dat"
38
39 ColorThread::ColorThread(int do_alpha, const char *title)
40  : BC_DialogThread()
41 {
42         this->title = title;
43         this->do_alpha = do_alpha;
44         this->do_okcancel = 0;
45         this->output = BLACK;
46         this->alpha = 255;
47 }
48
49 ColorThread::~ColorThread()
50 {
51         close_window();
52 }
53
54 void ColorThread::start_window(int output, int alpha, int do_okcancel)
55 {
56         if( running() ) {
57                 ColorWindow *gui = (ColorWindow *)get_gui();
58                 if( gui ) {
59                         gui->lock_window("ColorThread::start_window");
60                         gui->raise_window(1);
61                         gui->unlock_window();
62                 }
63                 return;
64         }
65         this->output = output;
66         this->alpha = alpha;
67         this->do_okcancel = do_okcancel;
68         start();
69 }
70
71 BC_Window* ColorThread::new_gui()
72 {
73         char window_title[BCTEXTLEN];
74         strcpy(window_title, _(PROGRAM_NAME ": "));
75         strcat(window_title, title ? title : _("Color Picker"));
76         BC_DisplayInfo display_info;
77         int x = display_info.get_abs_cursor_x() + 25;
78         int y = display_info.get_abs_cursor_y() - 100;
79         int w = 540, h = 330;
80         if( do_okcancel )
81                 h += bmax(BC_OKButton::calculate_h(),BC_CancelButton::calculate_h());
82         int root_w = display_info.get_root_w(), root_h = display_info.get_root_h();
83         if( x+w > root_w ) x = root_w - w;
84         if( y+h > root_h ) y = root_h - h;
85         if( x < 0 ) x = 0;
86         if( y < 0 ) y = 0;
87         ColorWindow *gui = new ColorWindow(this, x, y, w, h, window_title);
88         gui->create_objects();
89         return gui;
90 }
91
92 void ColorThread::update_gui(int output, int alpha)
93 {
94         ColorWindow *gui = (ColorWindow *)get_gui();
95         if( !gui ) return;
96         gui->lock_window();
97         this->output = output;
98         this->alpha = alpha;
99         gui->change_values();
100         gui->update_display();
101         gui->unlock_window();
102 }
103
104 int ColorThread::handle_new_color(int output, int alpha)
105 {
106         printf("ColorThread::handle_new_color undefined.\n");
107         return 0;
108 }
109
110
111 ColorWindow::ColorWindow(ColorThread *thread, int x, int y, int w, int h, const char *title)
112  : BC_Window(title, x, y, w, h, w, h, 0, 0, 1)
113 {
114         this->thread = thread;
115         wheel = 0;
116         wheel_value = 0;
117         output = 0;
118
119         hue = 0; sat = 0; val = 0;
120         red = 0; grn = 0; blu = 0;
121         lum = 0; c_r = 0; c_b = 0;
122         alpha = 0;
123
124         hsv_h = 0;  hsv_s = 0;  hsv_v = 0;
125         rgb_r = 0;  rgb_g = 0;  rgb_b = 0;
126         yuv_y = 0;  yuv_u = 0;  yuv_v = 0;
127         aph_a = 0;
128
129         button_grabbed = 0;
130 }
131 ColorWindow::~ColorWindow()
132 {
133         delete hsv_h;  delete hsv_s;  delete hsv_v;
134         delete rgb_r;  delete rgb_g;  delete rgb_b;
135         delete yuv_y;  delete yuv_u;  delete yuv_v;
136         delete aph_a;
137
138         if( button_grabbed ) {
139                 ungrab_buttons();
140                 ungrab_cursor();
141         }
142         update_history(rgb888());
143         save_history();
144 }
145
146 void ColorWindow::create_objects()
147 {
148         int x0 = 10, y0 = 10;
149         lock_window("ColorWindow::create_objects");
150         change_values();
151
152         int x = x0, y = y0;
153         add_tool(wheel = new PaletteWheel(this, x, y));
154         wheel->create_objects();
155
156         x += 180;  add_tool(wheel_value = new PaletteWheelValue(this, x, y));
157         wheel_value->create_objects();
158         x = x0;
159         y += 180;  add_tool(output = new PaletteOutput(this, x, y));
160         output->create_objects();
161         y += output->get_h() + 20;
162
163         load_history();  int x1 = x;
164         add_tool(hex_btn = new PaletteHexButton(this, x1, y));
165         char hex[BCSTRLEN];  sprintf(hex,"%06x",thread->output);
166         x1 += hex_btn->get_w() + 5;
167         add_tool(hex_box = new PaletteHex(this, x1, y, hex));
168         x1 += hex_box->get_w() + 15;
169         add_tool(grab_btn = new PaletteGrabButton(this, x1, y));
170         y += hex_box->get_h() + 15;
171         add_tool(history = new PaletteHistory(this, 10, y));
172
173         x += 240;
174         add_tool(new BC_Title(x, y =y0, _("H:"), SMALLFONT));
175         add_tool(new BC_Title(x, y+=25, _("S:"), SMALLFONT));
176         add_tool(new BC_Title(x, y+=25, _("V:"), SMALLFONT));
177         add_tool(new BC_Title(x, y+=40, _("R:"), SMALLFONT));
178         add_tool(new BC_Title(x, y+=25, _("G:"), SMALLFONT));
179         add_tool(new BC_Title(x, y+=25, _("B:"), SMALLFONT));
180         add_tool(new BC_Title(x, y+=40, _("Y:"), SMALLFONT));
181         add_tool(new BC_Title(x, y+=25, _("U:"), SMALLFONT));
182         add_tool(new BC_Title(x, y+=25, _("V:"), SMALLFONT));
183         if( thread->do_alpha )
184                 add_tool(new BC_Title(x, y+=40, _("A:"), SMALLFONT));
185         x += 24;
186         add_tool(hue = new PaletteHue(this, x, y= y0));
187         add_tool(sat = new PaletteSat(this, x, y+=25));
188         add_tool(val = new PaletteVal(this, x, y+=25));
189         add_tool(red = new PaletteRed(this, x, y+=40));
190         add_tool(grn = new PaletteGrn(this, x, y+=25));
191         add_tool(blu = new PaletteBlu(this, x, y+=25));
192         add_tool(lum = new PaletteLum(this, x, y+=40));
193         add_tool(c_r = new PaletteCr (this, x, y+=25));
194         add_tool(c_b = new PaletteCb (this, x, y+=25));
195         if( thread->do_alpha )
196                 add_tool(alpha = new PaletteAlpha(this, x, y+=40));
197
198         x += hue->get_w() + 10;
199         hsv_h = new PaletteHSV(this, x,y= y0, hsv.h, 0, 360);
200         hsv_h->create_objects();  hsv_h->set_tooltip(_("Hue"));
201         hsv_s = new PaletteHSV(this, x,y+=25, hsv.s, 0, 1);
202         hsv_s->create_objects();  hsv_s->set_tooltip(_("Saturation"));
203         hsv_v = new PaletteHSV(this, x,y+=25, hsv.v, 0, 1);
204         hsv_v->create_objects();  hsv_v->set_tooltip(_("Value"));
205         rgb_r = new PaletteRGB(this, x,y+=40, rgb.r, 0, 1);
206         rgb_r->create_objects();  rgb_r->set_tooltip(_("Red"));
207         rgb_g = new PaletteRGB(this, x,y+=25, rgb.g, 0, 1);
208         rgb_g->create_objects();  rgb_g->set_tooltip(_("Green"));
209         rgb_b = new PaletteRGB(this, x,y+=25, rgb.b, 0, 1);
210         rgb_b->create_objects();  rgb_b->set_tooltip(_("Blue"));
211         yuv_y = new PaletteYUV(this, x,y+=40, yuv.y, 0, 1);
212         yuv_y->create_objects();  yuv_y->set_tooltip(_("Luminance"));
213         yuv_u = new PaletteYUV(this, x,y+=25, yuv.u, 0, 1);
214         yuv_u->create_objects();  yuv_u->set_tooltip(_("Complement Blue"));
215         yuv_v = new PaletteYUV(this, x,y+=25, yuv.v, 0, 1);
216         yuv_v->create_objects();  yuv_v->set_tooltip(_("Complement Red"));
217         if( thread->do_alpha ) {
218                 aph_a = new PaletteAPH(this, x,y+=40, aph, 0, 1);
219                 aph_a->create_objects();  aph_a->set_tooltip(_("Alpha"));
220         }
221         if( thread->do_okcancel ) {
222                 add_tool(new BC_OKButton(this));
223                 add_tool(new BC_CancelButton(this));
224         }
225
226         update_display();
227         update_history();
228         show_window(1);
229         unlock_window();
230 }
231
232
233 void ColorWindow::change_values()
234 {
235         float r = ((thread->output>>16) & 0xff) / 255.;
236         float g = ((thread->output>>8)  & 0xff) / 255.;
237         float b = ((thread->output>>0)  & 0xff) / 255.;
238         rgb.r = r;  rgb.g = g;  rgb.b = b;
239         aph = (float)thread->alpha / 255;
240         update_rgb(rgb.r, rgb.g, rgb.b);
241 }
242
243
244 int ColorWindow::close_event()
245 {
246         set_done(thread->do_okcancel ? 1 : 0);
247         return 1;
248 }
249
250
251 void ColorWindow::update_rgb()
252 {
253         update_rgb(rgb.r, rgb.g, rgb.b);
254         update_display();
255 }
256 void ColorWindow::update_hsv()
257 {
258         update_hsv(hsv.h, hsv.s, hsv.v);
259         update_display();
260 }
261 void ColorWindow::update_yuv()
262 {
263         update_yuv(yuv.y, yuv.u, yuv.v);
264         update_display();
265 }
266
267 void ColorWindow::update_display()
268 {
269         wheel->draw(wheel->oldhue, wheel->oldsaturation);
270         wheel->oldhue = hsv.h;
271         wheel->oldsaturation = hsv.s;
272         wheel->draw(hsv.h, hsv.s);
273         wheel->flash();
274         wheel_value->draw(hsv.h, hsv.s, hsv.v);
275         wheel_value->flash();
276         output->draw();
277         output->flash();
278
279         hue->update((int)hsv.h);
280         sat->update(hsv.s);
281         val->update(hsv.v);
282
283         red->update(rgb.r);
284         grn->update(rgb.g);
285         blu->update(rgb.b);
286
287         lum->update(yuv.y);
288         c_r->update(yuv.u);
289         c_b->update(yuv.v);
290
291         hsv_h->update(hsv.h);
292         hsv_s->update(hsv.s);
293         hsv_v->update(hsv.v);
294         rgb_r->update(rgb.r);
295         rgb_g->update(rgb.g);
296         rgb_b->update(rgb.b);
297         yuv_y->update(yuv.y);
298         yuv_u->update(yuv.u);
299         yuv_v->update(yuv.v);
300         hex_box->update();
301
302         if( thread->do_alpha )
303                 aph_a->update(aph);
304 }
305
306 int ColorWindow::handle_event()
307 {
308         thread->handle_new_color(rgb888(), (int)(255*aph + 0.5));
309         return 1;
310 }
311
312 int ColorWindow::button_press_event()
313 {
314         if( button_grabbed ) {
315                 grab_cursor();
316         }
317         return 0;
318 }
319 int ColorWindow::button_release_event()
320 {
321         if( button_grabbed ) {
322                 grab_btn->disable();
323                 grab_btn->enable();
324                 ungrab_buttons();
325                 ungrab_cursor();
326                 button_grabbed = 0;
327                 int cx, cy;
328                 get_abs_cursor_xy(cx, cy);
329 //printf("grabbed button %d,%d\n",cx,cy);
330                 BC_Capture capture_bitmap(1, 1, 0);
331                 VFrame vframe(1,1,BC_RGB888);
332                 capture_bitmap.capture_frame(&vframe, cx,cy);
333                 unsigned char *data = vframe.get_data();
334                 rgb.r = data[0]/255.;  rgb.g = data[1]/255.;  rgb.b = data[2]/255.;
335                 update_rgb();
336                 update_display();
337                 update_history();
338                 return handle_event();
339         }
340         return 0;
341 }
342
343 void ColorWindow::update_rgb_hex(const char *hex)
344 {
345         int color;
346         if( sscanf(hex,"%x",&color) == 1 ) {
347                 float r = ((color>>16) & 0xff) / 255.;
348                 float g = ((color>>8)  & 0xff) / 255.;
349                 float b = ((color>>0)  & 0xff) / 255.;
350                 rgb.r = r;  rgb.g = g;  rgb.b = b;
351                 update_rgb();
352                 update_display();
353                 update_history();
354                 handle_event();
355         }
356 }
357
358
359 PaletteWheel::PaletteWheel(ColorWindow *window, int x, int y)
360  : BC_SubWindow(x, y, 170, 170)
361 {
362         this->window = window;
363         oldhue = 0;
364         oldsaturation = 0;
365         button_down = 0;
366 }
367
368 PaletteWheel::~PaletteWheel()
369 {
370 }
371
372 int PaletteWheel::button_press_event()
373 {
374         if( get_cursor_x() >= 0 && get_cursor_x() < get_w() &&
375                 get_cursor_y() >= 0 && get_cursor_y() < get_h() &&
376                 is_event_win() ) {
377                 button_down = 1;
378                 cursor_motion_event();
379                 return 1;
380         }
381         return 0;
382 }
383
384 int PaletteWheel::cursor_motion_event()
385 {
386         int x1, y1, distance;
387         if( button_down && is_event_win() ) {
388                 float h = get_angle(get_w()/2, get_h()/2, get_cursor_x(), get_cursor_y());
389                 bclamp(h, 0, 359.999);  window->hsv.h = h;
390                 x1 = get_w() / 2 - get_cursor_x();
391                 y1 = get_h() / 2 - get_cursor_y();
392                 distance = (int)sqrt(x1 * x1 + y1 * y1);
393                 float s = (float)distance / (get_w() / 2);
394                 bclamp(s, 0, 1);  window->hsv.s = s;
395                 window->update_hsv();
396                 window->update_display();
397                 window->handle_event();
398                 return 1;
399         }
400         return 0;
401 }
402
403 int PaletteWheel::button_release_event()
404 {
405         if( button_down ) {
406                 button_down = 0;
407                 return 1;
408         }
409         return 0;
410 }
411
412 void PaletteWheel::create_objects()
413 {
414 // Upper right
415 //printf("PaletteWheel::create_objects 1\n");
416         float h, s, v = 1;
417         float r, g, b;
418         float x1, y1, x2, y2;
419         float distance;
420         int default_r, default_g, default_b;
421         VFrame frame(0, -1, get_w(), get_h(), BC_RGBA8888, -1);
422         x1 = get_w() / 2;
423         y1 = get_h() / 2;
424         default_r = (get_resources()->get_bg_color() & 0xff0000) >> 16;
425         default_g = (get_resources()->get_bg_color() & 0xff00) >> 8;
426         default_b = (get_resources()->get_bg_color() & 0xff);
427 //printf("PaletteWheel::create_objects 1\n");
428
429         int highlight_r = (get_resources()->button_light & 0xff0000) >> 16;
430         int highlight_g = (get_resources()->button_light & 0xff00) >> 8;
431         int highlight_b = (get_resources()->button_light & 0xff);
432
433         for( y2 = 0; y2 < get_h(); y2++ ) {
434                 unsigned char *row = (unsigned char*)frame.get_rows()[(int)y2];
435                 for( x2 = 0; x2 < get_w(); x2++ ) {
436                         distance = sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
437                         if( distance > x1 ) {
438                                 row[(int)x2 * 4] = default_r;
439                                 row[(int)x2 * 4 + 1] = default_g;
440                                 row[(int)x2 * 4 + 2] = default_b;
441                                 row[(int)x2 * 4 + 3] = 0;
442                         }
443                         else
444                         if( distance > x1 - 1 ) {
445                                 int r_i, g_i, b_i;
446                                 if( get_h() - y2 < x2 ) {
447                                         r_i = highlight_r;
448                                         g_i = highlight_g;
449                                         b_i = highlight_b;
450                                 }
451                                 else {
452                                         r_i = 0;
453                                         g_i = 0;
454                                         b_i = 0;
455                                 }
456
457                                 row[(int)x2 * 4] = r_i;
458                                 row[(int)x2 * 4 + 1] = g_i;
459                                 row[(int)x2 * 4 + 2] = b_i;
460                                 row[(int)x2 * 4 + 3] = 255;
461                         }
462                         else {
463                                 h = get_angle(x1, y1, x2, y2);
464                                 s = distance / x1;
465                                 HSV::hsv_to_rgb(r, g, b, h, s, v);
466                                 row[(int)x2 * 4] = (int)(r * 255);
467                                 row[(int)x2 * 4 + 1] = (int)(g * 255);
468                                 row[(int)x2 * 4 + 2] = (int)(b * 255);
469                                 row[(int)x2 * 4 + 3] = 255;
470                         }
471                 }
472         }
473 //printf("PaletteWheel::create_objects 1\n");
474
475         draw_vframe(&frame,
476                 0,
477                 0,
478                 get_w(),
479                 get_h(),
480                 0,
481                 0,
482                 get_w(),
483                 get_h(),
484                 0);
485 //printf("PaletteWheel::create_objects 1\n");
486
487         oldhue = window->hsv.h;
488         oldsaturation = window->hsv.s;
489 //printf("PaletteWheel::create_objects 1\n");
490         draw(oldhue, oldsaturation);
491 //printf("PaletteWheel::create_objects 1\n");
492         flash();
493 //printf("PaletteWheel::create_objects 2\n");
494 }
495
496 float PaletteWheel::torads(float angle)
497 {
498         return (float)angle / 360 * 2 * M_PI;
499 }
500
501
502 int PaletteWheel::draw(float hue, float saturation)
503 {
504         int x, y, w, h;
505         x = w = get_w() / 2;
506         y = h = get_h() / 2;
507
508         if( hue > 0 && hue < 90 ) {
509                 x = (int)(w - w * cos(torads(90 - hue)) * saturation);
510                 y = (int)(h - h * sin(torads(90 - hue)) * saturation);
511         }
512         else if( hue > 90 && hue < 180 ) {
513                 x = (int)(w - w * cos(torads(hue - 90)) * saturation);
514                 y = (int)(h + h * sin(torads(hue - 90)) * saturation);
515         }
516         else if( hue > 180 && hue < 270 ) {
517                 x = (int)(w + w * cos(torads(270 - hue)) * saturation);
518                 y = (int)(h + h * sin(torads(270 - hue)) * saturation);
519         }
520         else if( hue > 270 && hue < 360 ) {
521                 x = (int)(w + w * cos(torads(hue - 270)) * saturation);
522                 y = (int)(h - w * sin(torads(hue - 270)) * saturation);
523         }
524         else if( hue == 0 ) {
525                 x = w;
526                 y = (int)(h - h * saturation);
527         }
528         else if( hue == 90 ) {
529                 x = (int)(w - w * saturation);
530                 y = h;
531         }
532         else if( hue == 180 ) {
533                 x = w;
534                 y = (int)(h + h * saturation);
535         }
536         else if( hue == 270 ) {
537                 x = (int)(w + w * saturation);
538                 y = h;
539         }
540
541         set_inverse();
542         set_color(WHITE);
543         draw_circle(x - 5, y - 5, 10, 10);
544         set_opaque();
545         return 0;
546 }
547
548 int PaletteWheel::get_angle(float x1, float y1, float x2, float y2)
549 {
550         float result = -atan2(x2 - x1, y1 - y2) * (360 / M_PI / 2);
551         if( result < 0 )
552                 result += 360;
553         return (int)result;
554 }
555
556 PaletteWheelValue::PaletteWheelValue(ColorWindow *window, int x, int y)
557  : BC_SubWindow(x, y, 40, 170, BLACK)
558 {
559         this->window = window;
560         button_down = 0;
561 }
562 PaletteWheelValue::~PaletteWheelValue()
563 {
564         delete frame;
565 }
566
567 void PaletteWheelValue::create_objects()
568 {
569         frame = new VFrame(0, -1, get_w(), get_h(), BC_RGB888, -1);
570         draw(window->hsv.h, window->hsv.s, window->hsv.v);
571         flash();
572 }
573
574 int PaletteWheelValue::button_press_event()
575 {
576 //printf("PaletteWheelValue::button_press 1 %d\n", is_event_win());
577         if( get_cursor_x() >= 0 && get_cursor_x() < get_w() &&
578                 get_cursor_y() >= 0 && get_cursor_y() < get_h() &&
579                 is_event_win() ) {
580 //printf("PaletteWheelValue::button_press 2\n");
581                 button_down = 1;
582                 cursor_motion_event();
583                 return 1;
584         }
585         return 0;
586 }
587
588 int PaletteWheelValue::cursor_motion_event()
589 {
590         if( button_down && is_event_win() ) {
591 //printf("PaletteWheelValue::cursor_motion 1\n");
592                 float v = 1.0 - (float)(get_cursor_y() - 2) / (get_h() - 4);
593                 bclamp(v, 0, 1);  window->hsv.v = v;
594                 window->update_hsv();
595                 window->update_display();
596                 window->handle_event();
597                 return 1;
598         }
599         return 0;
600 }
601
602 int PaletteWheelValue::button_release_event()
603 {
604         if( button_down ) {
605 //printf("PaletteWheelValue::button_release 1\n");
606                 button_down = 0;
607                 return 1;
608         }
609         return 0;
610 }
611
612 int PaletteWheelValue::draw(float hue, float saturation, float value)
613 {
614         float r_f, g_f, b_f;
615         int i, j, r, g, b;
616
617         for( i = get_h() - 3; i >= 2; i-- ) {
618                 unsigned char *row = (unsigned char*)frame->get_rows()[i];
619                 HSV::hsv_to_rgb(r_f, g_f, b_f, hue, saturation,
620                         1.0 - (float)(i - 2) / (get_h() - 4));
621                 r = (int)(r_f * 255);
622                 g = (int)(g_f * 255);
623                 b = (int)(b_f * 255);
624                 for( j = 0; j < get_w(); j++ ) {
625                         row[j * 3] = r;
626                         row[j * 3 + 1] = g;
627                         row[j * 3 + 2] = b;
628                 }
629         }
630
631         draw_3d_border(0, 0, get_w(), get_h(), 1);
632         draw_vframe(frame, 2, 2, get_w() - 4, get_h() - 4,
633                 2, 2, get_w() - 4, get_h() - 4, 0);
634         set_color(BLACK);
635         draw_line(2, get_h() - 3 - (int)(value * (get_h() - 5)),
636                   get_w() - 3, get_h() - 3 - (int)(value * (get_h() - 5)));
637 //printf("PaletteWheelValue::draw %d %f\n", __LINE__, value);
638
639         return 0;
640 }
641
642 PaletteOutput::PaletteOutput(ColorWindow *window, int x, int y)
643  : BC_SubWindow(x, y, 180, 30, BLACK)
644 {
645         this->window = window;
646 }
647 PaletteOutput::~PaletteOutput()
648 {
649 }
650
651
652 void PaletteOutput::create_objects()
653 {
654         draw();
655         flash();
656 }
657
658 int PaletteOutput::handle_event()
659 {
660         return 1;
661 }
662
663 int PaletteOutput::draw()
664 {
665         set_color(window->rgb888());
666         draw_box(2, 2, get_w() - 4, get_h() - 4);
667         draw_3d_border(0, 0, get_w(), get_h(), 1);
668         return 0;
669 }
670
671 PaletteHue::PaletteHue(ColorWindow *window, int x, int y)
672  : BC_ISlider(x, y, 0, 150, 200, 0, 359, (int)(window->hsv.h), 0)
673 {
674         this->window = window;
675 }
676 PaletteHue::~PaletteHue()
677 {
678 }
679
680 int PaletteHue::handle_event()
681 {
682         window->hsv.h = get_value();
683         window->update_hsv();
684         window->handle_event();
685         return 1;
686 }
687
688 PaletteSat::PaletteSat(ColorWindow *window, int x, int y)
689  : BC_FSlider(x, y, 0, 150, 200, 0, 1.0, window->hsv.s, 0)
690 {
691         this->window = window;
692         set_precision(0.01);
693 }
694 PaletteSat::~PaletteSat()
695 {
696 }
697
698 int PaletteSat::handle_event()
699 {
700         window->hsv.s = get_value();
701         window->update_hsv();
702         window->handle_event();
703         return 1;
704 }
705
706
707 PaletteVal::PaletteVal(ColorWindow *window, int x, int y)
708  : BC_FSlider(x, y, 0, 150, 200, 0, 1.0, window->hsv.v, 0)
709 {
710         this->window = window;
711         set_precision(0.01);
712 }
713 PaletteVal::~PaletteVal()
714 {
715 }
716
717 int PaletteVal::handle_event()
718 {
719         window->hsv.v = get_value();
720         window->update_hsv();
721         window->handle_event();
722         return 1;
723 }
724
725
726 PaletteRed::PaletteRed(ColorWindow *window, int x, int y)
727  : BC_FSlider(x, y, 0, 150, 200, 0, 1, window->rgb.r, 0)
728 {
729         this->window = window;
730         set_precision(0.01);
731 }
732 PaletteRed::~PaletteRed()
733 {
734 }
735
736 int PaletteRed::handle_event()
737 {
738         window->rgb.r = get_value();
739         window->update_rgb();
740         window->handle_event();
741         return 1;
742 }
743
744 PaletteGrn::PaletteGrn(ColorWindow *window, int x, int y)
745  : BC_FSlider(x, y, 0, 150, 200, 0, 1, window->rgb.g, 0)
746 {
747         this->window = window;
748         set_precision(0.01);
749 }
750 PaletteGrn::~PaletteGrn()
751 {
752 }
753
754 int PaletteGrn::handle_event()
755 {
756         window->rgb.g = get_value();
757         window->update_rgb();
758         window->handle_event();
759         return 1;
760 }
761
762 PaletteBlu::PaletteBlu(ColorWindow *window, int x, int y)
763  : BC_FSlider(x, y, 0, 150, 200, 0, 1, window->rgb.b, 0)
764 {
765         this->window = window;
766         set_precision(0.01);
767 }
768 PaletteBlu::~PaletteBlu()
769 {
770 }
771
772 int PaletteBlu::handle_event()
773 {
774         window->rgb.b = get_value();
775         window->update_rgb();
776         window->handle_event();
777         return 1;
778 }
779
780 PaletteAlpha::PaletteAlpha(ColorWindow *window, int x, int y)
781  : BC_FSlider(x, y, 0, 150, 200, 0, 1, window->aph, 0)
782 {
783         this->window = window;
784         set_precision(0.01);
785 }
786 PaletteAlpha::~PaletteAlpha()
787 {
788 }
789
790 int PaletteAlpha::handle_event()
791 {
792         window->aph = get_value();
793         window->handle_event();
794         return 1;
795 }
796
797 PaletteLum::PaletteLum(ColorWindow *window, int x, int y)
798  : BC_FSlider(x, y, 0, 150, 200, 0, 1, window->yuv.y, 0)
799 {
800         this->window = window;
801         set_precision(0.01);
802 }
803 PaletteLum::~PaletteLum()
804 {
805 }
806
807 int PaletteLum::handle_event()
808 {
809         window->yuv.y = get_value();
810         window->update_yuv();
811         window->handle_event();
812         return 1;
813 }
814
815 PaletteCr::PaletteCr(ColorWindow *window, int x, int y)
816  : BC_FSlider(x, y, 0, 150, 200, 0, 1, window->yuv.u, 0)
817 {
818         this->window = window;
819         set_precision(0.01);
820 }
821 PaletteCr::~PaletteCr()
822 {
823 }
824
825 int PaletteCr::handle_event()
826 {
827         window->yuv.u = get_value();
828         window->update_yuv();
829         window->handle_event();
830         return 1;
831 }
832
833 PaletteCb::PaletteCb(ColorWindow *window, int x, int y)
834  : BC_FSlider(x, y, 0, 150, 200, 0, 1, window->yuv.v, 0)
835 {
836         this->window = window;
837         set_precision(0.01);
838 }
839 PaletteCb::~PaletteCb()
840 {
841 }
842
843 int PaletteCb::handle_event()
844 {
845         window->yuv.v = get_value();
846         window->update_yuv();
847         window->handle_event();
848         return 1;
849 }
850
851 void ColorWindow::update_rgb(float r, float g, float b)
852 {
853         { float y, u, v;
854         YUV::rgb_to_yuv_f(r, g, b, y, u, v);
855         u += 0.5;  v += 0.5;
856         bclamp(y, 0, 1);    yuv.y = y;
857         bclamp(u, 0, 1);    yuv.u = u;
858         bclamp(v, 0, 1);    yuv.v = v; }
859         { float h, s, v;
860         HSV::rgb_to_hsv(r,g,b, h,s,v);
861         bclamp(h, 0, 360);  hsv.h = h;
862         bclamp(s, 0, 1);    hsv.s = s;
863         bclamp(v, 0, 1);    hsv.v = v; }
864 }
865
866 void ColorWindow::update_yuv(float y, float u, float v)
867 {
868         u -= 0.5;  v -= 0.5;
869         { float r, g, b;
870         YUV::yuv_to_rgb_f(r, g, b, y, u, v);
871         bclamp(r, 0, 1);   rgb.r = r;
872         bclamp(g, 0, 1);   rgb.g = g;
873         bclamp(b, 0, 1);   rgb.b = b;
874         float h, s, v;
875         HSV::rgb_to_hsv(r,g,b, h, s, v);
876         bclamp(h, 0, 360); hsv.h = h;
877         bclamp(s, 0, 1);   hsv.s = s;
878         bclamp(v, 0, 1);   hsv.v = v; }
879 }
880
881 void ColorWindow::update_hsv(float h, float s, float v)
882 {
883         { float r, g, b;
884         HSV::hsv_to_rgb(r,g,b, h,s,v);
885         bclamp(r, 0, 1);   rgb.r = r;
886         bclamp(g, 0, 1);   rgb.g = g;
887         bclamp(b, 0, 1);   rgb.b = b;
888         float y, u, v;
889         YUV::rgb_to_yuv_f(r, g, b, y, u, v);
890         u += 0.5;  v += 0.5;
891         bclamp(y, 0, 1);   yuv.y = y;
892         bclamp(u, 0, 1);   yuv.u = u;
893         bclamp(v, 0, 1);   yuv.v = v; }
894 }
895
896 void ColorWindow::load_history()
897 {
898         char history_path[BCTEXTLEN];
899         MWindow::create_defaults_path(history_path,PALETTE_DATA);
900         FILE *fp = fopen(history_path,"r");
901         int i=0;
902         if( fp ) {
903                 while( i < PALLETTE_HISTORY_SIZE ) {
904                         char line[BCSTRLEN];
905                         if( !fgets(line,sizeof(line)-1,fp) ) break;
906                         line[sizeof(line)-1] = 0;
907                         if( sscanf(line, "%x",&palette_history[i]) != 1 ) break;
908                         ++i;
909                 }
910                 fclose(fp);
911         }
912         int r = 0, g = 0, b = 0;
913         float v0 = 0, v1 = 1;
914         while( i < PALLETTE_HISTORY_SIZE ) {
915                 int grey_code = i ^ (i>>1);
916                 r = 255 * ((grey_code&4) ? v0 : v1);
917                 g = 255 * ((grey_code&2) ? v0 : v1);
918                 b = 255 * ((grey_code&1) ? v0 : v1);
919                 int color = (r<<16) | (g<<8) | (b<<0);
920                 palette_history[i++] = color;
921                 if( i & 7 ) continue;
922                 v0 = 0.5f * (v0+.5f);
923                 v1 = 0.5f * (v1+.5f);
924         }
925 }
926 void ColorWindow::save_history()
927 {
928         char history_path[BCTEXTLEN];
929         MWindow::create_defaults_path(history_path,PALETTE_DATA);
930         FILE *fp = fopen(history_path,"w");
931         if( fp ) {
932                 for( int i=0; i<PALLETTE_HISTORY_SIZE; ++i ) {
933                         fprintf(fp, "%06x\n", palette_history[i]);
934                 }
935                 fclose(fp);
936         }
937 }
938 void ColorWindow::update_history(int color)
939 {
940         int out = palette_history[0];
941         palette_history[0] = color;
942         for( int i=1; out != color && i<PALLETTE_HISTORY_SIZE; ++i ) {
943                 int in = out;
944                 out = palette_history[i];
945                 palette_history[i] = in;
946         }
947 }
948 void ColorWindow::update_history()
949 {
950         update_history(rgb888());
951         history->update(0);
952 }
953 int ColorWindow::rgb888()
954 {
955         int r = 255*rgb.r + 0.5, g = 255*rgb.g + 0.5, b = 255*rgb.b + 0.5;
956         bclamp(r, 0, 255);  bclamp(g, 0, 255);  bclamp(b, 0, 255);
957         return (r<<16) | (g<<8) | (b<<0);
958 }
959
960 PaletteNum::PaletteNum(ColorWindow *window, int x, int y,
961         float &output, float min, float max)
962  : BC_TumbleTextBox(window, output, min, max, x, y, 64)
963 {
964         this->window = window;
965         this->output = &output;
966         set_increment(0.01);
967         set_precision(2);
968 }
969
970 PaletteNum::~PaletteNum()
971 {
972 }
973
974
975 int PaletteHSV::handle_event()
976 {
977         update_output();
978         window->update_hsv();
979         window->update_display();
980         window->handle_event();
981         return 1;
982 }
983
984 int PaletteRGB::handle_event()
985 {
986         update_output();
987         window->update_rgb();
988         window->update_display();
989         window->handle_event();
990         return 1;
991 }
992
993 int PaletteYUV::handle_event()
994 {
995         update_output();
996         window->update_yuv();
997         window->update_display();
998         window->handle_event();
999         return 1;
1000 }
1001
1002 int PaletteAPH::handle_event()
1003 {
1004         update_output();
1005         window->update_display();
1006         window->handle_event();
1007         return 1;
1008 }
1009
1010 PaletteHexButton::PaletteHexButton(ColorWindow *window, int x, int y)
1011  : BC_GenericButton(x, y, 50, "#")
1012 {
1013         this->window = window;
1014         set_tooltip(_("hex rgb color"));
1015 }
1016 PaletteHexButton::~PaletteHexButton()
1017 {
1018 }
1019 int PaletteHexButton::handle_event()
1020 {
1021         const char *hex = window->hex_box->get_text();
1022         window->update_rgb_hex(hex);
1023         return 1;
1024 }
1025
1026 PaletteHex::PaletteHex(ColorWindow *window, int x, int y, const char *hex)
1027  : BC_TextBox(x, y, 100, 1, hex)
1028 {
1029         this->window = window;
1030 }
1031 PaletteHex::~PaletteHex()
1032 {
1033 }
1034 void PaletteHex::update()
1035 {
1036         char hex[BCSTRLEN];  sprintf(hex,"%06x",window->rgb888());
1037         BC_TextBox::update(hex);
1038 }
1039
1040 int PaletteHex::keypress_event()
1041 {
1042         if( get_keypress() != RETURN )
1043                 return BC_TextBox::keypress_event();
1044         window->update_rgb_hex(get_text());
1045         return 1;
1046 }
1047
1048 #include "grabpick_up_png.h"
1049 #include "grabpick_hi_png.h"
1050 #include "grabpick_dn_png.h"
1051
1052 PaletteGrabButton::PaletteGrabButton(ColorWindow *window, int x, int y)
1053  : BC_Button(x, y, vframes)
1054 {
1055         this->window = window;
1056         vframes[0] = new VFramePng(grabpick_up_png);
1057         vframes[1] = new VFramePng(grabpick_hi_png);
1058         vframes[2] = new VFramePng(grabpick_dn_png);
1059         set_tooltip(_("grab from anywhere picker"));
1060 }
1061 PaletteGrabButton::~PaletteGrabButton()
1062 {
1063         for( int i=0; i<3; ++i )
1064                 delete vframes[i];
1065 }
1066 int PaletteGrabButton::handle_event()
1067 {
1068         if( window->grab_buttons() ) {
1069                 window->button_grabbed = 1;
1070                 button_press_event(); // redraw face HI
1071         }
1072         return 1;
1073 }
1074
1075 PaletteHistory::PaletteHistory(ColorWindow *window, int x, int y)
1076  : BC_SubWindow(x,y, 200, 24)
1077 {
1078         this->window = window;
1079         button_down = 0;
1080         set_tooltip(_("color history"));
1081 }
1082 PaletteHistory::~PaletteHistory()
1083 {
1084 }
1085 void PaletteHistory::update(int flush)
1086 {
1087         int x1 = 0, x2 = 0;
1088         for( int i=0; i<PALLETTE_HISTORY_SIZE; x1=x2 ) {
1089                 int rgb = window->palette_history[i];
1090                 x2 = (++i * get_w())/PALLETTE_HISTORY_SIZE;
1091                 draw_3d_box(x1,0,x2-x1,get_h(),WHITE,BLACK,rgb,LTBLUE,DKBLUE);
1092         }
1093         flash(flush);
1094 }
1095
1096 int PaletteHistory::button_press_event()
1097 {
1098         if( button_down || !is_event_win() ) return 0;
1099         button_down =  1;
1100         cursor_motion_event();
1101         return 1;
1102 }
1103 int PaletteHistory::button_release_event()
1104 {
1105         if( !button_down || !is_event_win() ) return 0;
1106         cursor_motion_event();
1107         if( button_down > 0 ) {
1108                 window->handle_event();
1109                 window->update_display();
1110                 window->update_history();
1111         }
1112         button_down =  0;
1113         return 1;
1114 }
1115 int PaletteHistory::cursor_motion_event()
1116 {
1117         if( !button_down || !is_event_win() ) return 0;
1118         hide_tooltip();
1119         int pick = (PALLETTE_HISTORY_SIZE * get_cursor_x()) / get_w();
1120         bclamp(pick, 0, PALLETTE_HISTORY_SIZE-1);
1121         int color = window->palette_history[pick];
1122         float r = ((color>>16) & 0xff) / 255.;
1123         float g = ((color>>8)  & 0xff) / 255.;
1124         float b = ((color>>0)  & 0xff) / 255.;
1125         if( window->rgb.r != r || window->rgb.g != g || window->rgb.b != b ) {
1126                 window->rgb.r = r;  window->rgb.g = g;  window->rgb.b = b;
1127                 window->update_rgb();
1128                 window->update_display();
1129         }
1130         return 1;
1131 }
1132
1133 int PaletteHistory::cursor_leave_event()
1134 {
1135         hide_tooltip();
1136         return 0;
1137 }
1138 int PaletteHistory::repeat_event(int64_t duration)
1139 {
1140         int result = 0;
1141
1142         if( duration == get_resources()->tooltip_delay &&
1143             get_tooltip() && *get_tooltip() && cursor_above() ) {
1144                 show_tooltip();
1145                 result = 1;
1146         }
1147         return result;
1148 }
1149