+PaletteCb::PaletteCb(ColorWindow *window, int x, int y)
+ : BC_FSlider(x, y, 0, 150, 200, 0, 1, window->yuv.v, 0)
+{
+ this->window = window;
+ set_precision(0.01);
+}
+PaletteCb::~PaletteCb()
+{
+}
+
+int PaletteCb::handle_event()
+{
+ window->yuv.v = get_value();
+ window->update_yuv();
+ window->handle_event();
+ return 1;
+}
+
+void ColorWindow::update_rgb(float r, float g, float b)
+{
+ { float y, u, v;
+ YUV::yuv.rgb_to_yuv_f(r, g, b, y, u, v);
+ u += 0.5; v += 0.5;
+ bclamp(y, 0, 1); yuv.y = y;
+ bclamp(u, 0, 1); yuv.u = u;
+ bclamp(v, 0, 1); yuv.v = v; }
+ { float h, s, v;
+ HSV::rgb_to_hsv(r,g,b, h,s,v);
+ bclamp(h, 0, 360); hsv.h = h;
+ bclamp(s, 0, 1); hsv.s = s;
+ bclamp(v, 0, 1); hsv.v = v; }
+}
+
+void ColorWindow::update_yuv(float y, float u, float v)
+{
+ u -= 0.5; v -= 0.5;
+ { float r, g, b;
+ YUV::yuv.yuv_to_rgb_f(r, g, b, y, u, v);
+ bclamp(r, 0, 1); rgb.r = r;
+ bclamp(g, 0, 1); rgb.g = g;
+ bclamp(b, 0, 1); rgb.b = b;
+ float h, s, v;
+ HSV::rgb_to_hsv(r,g,b, h, s, v);
+ bclamp(h, 0, 360); hsv.h = h;
+ bclamp(s, 0, 1); hsv.s = s;
+ bclamp(v, 0, 1); hsv.v = v; }
+}
+
+void ColorWindow::update_hsv(float h, float s, float v)
+{
+ { float r, g, b;
+ HSV::hsv_to_rgb(r,g,b, h,s,v);
+ bclamp(r, 0, 1); rgb.r = r;
+ bclamp(g, 0, 1); rgb.g = g;
+ bclamp(b, 0, 1); rgb.b = b;
+ float y, u, v;
+ YUV::yuv.rgb_to_yuv_f(r, g, b, y, u, v);
+ u += 0.5; v += 0.5;
+ bclamp(y, 0, 1); yuv.y = y;
+ bclamp(u, 0, 1); yuv.u = u;
+ bclamp(v, 0, 1); yuv.v = v; }
+}
+
+void ColorWindow::load_history()
+{
+ char history_path[BCTEXTLEN];
+ MWindow::create_defaults_path(history_path,PALETTE_DATA);
+ FILE *fp = fopen(history_path,"r");
+ int i=0;
+ if( fp ) {
+ while( i < PALLETTE_HISTORY_SIZE ) {
+ char line[BCSTRLEN];
+ if( !fgets(line,sizeof(line)-1,fp) ) break;
+ line[sizeof(line)-1] = 0;
+ if( sscanf(line, "%x",&palette_history[i]) != 1 ) break;
+ ++i;
+ }
+ fclose(fp);
+ }
+ int r = 0, g = 0, b = 0;
+ float v0 = 0, v1 = 1;
+ while( i < PALLETTE_HISTORY_SIZE ) {
+ int grey_code = i ^ (i>>1);
+ r = 255 * ((grey_code&4) ? v0 : v1);
+ g = 255 * ((grey_code&2) ? v0 : v1);
+ b = 255 * ((grey_code&1) ? v0 : v1);
+ int color = (r<<16) | (g<<8) | (b<<0);
+ palette_history[i++] = color;
+ if( i & 7 ) continue;
+ v0 = 0.5f * (v0+.5f);
+ v1 = 0.5f * (v1+.5f);
+ }
+}
+void ColorWindow::save_history()
+{
+ char history_path[BCTEXTLEN];
+ MWindow::create_defaults_path(history_path,PALETTE_DATA);
+ FILE *fp = fopen(history_path,"w");
+ if( fp ) {
+ for( int i=0; i<PALLETTE_HISTORY_SIZE; ++i ) {
+ fprintf(fp, "%06x\n", palette_history[i]);
+ }
+ fclose(fp);
+ }
+}
+void ColorWindow::update_history(int color)
+{
+ int out = palette_history[0];
+ palette_history[0] = color;
+ for( int i=1; out != color && i<PALLETTE_HISTORY_SIZE; ++i ) {
+ int in = out;
+ out = palette_history[i];
+ palette_history[i] = in;
+ }
+}
+void ColorWindow::update_history()
+{
+ update_history(rgb888());
+ history->update(0);
+}
+int ColorWindow::rgb888()
+{
+ int r = 255*rgb.r + 0.5, g = 255*rgb.g + 0.5, b = 255*rgb.b + 0.5;
+ bclamp(r, 0, 255); bclamp(g, 0, 255); bclamp(b, 0, 255);
+ return (r<<16) | (g<<8) | (b<<0);
+}
+
+PaletteNum::PaletteNum(ColorWindow *window, int x, int y,
+ float &output, float min, float max)
+ : BC_TumbleTextBox(window, output, min, max, x, y, 64)
+{
+ this->window = window;
+ this->output = &output;
+ set_increment(0.01);
+ set_precision(2);
+}
+
+PaletteNum::~PaletteNum()
+{
+}
+
+
+int PaletteHSV::handle_event()
+{
+ update_output();
+ window->update_hsv();
+ window->handle_event();
+ return 1;
+}
+
+int PaletteRGB::handle_event()
+{
+ update_output();
+ window->update_rgb();
+ window->handle_event();
+ return 1;
+}
+
+int PaletteYUV::handle_event()
+{
+ update_output();
+ window->update_yuv();
+ window->handle_event();
+ return 1;
+}
+
+int PaletteAPH::handle_event()
+{
+ update_output();
+ window->update_display();
+ window->handle_event();
+ return 1;
+}
+
+PaletteHexButton::PaletteHexButton(ColorWindow *window, int x, int y)
+ : BC_GenericButton(x, y, 50, "#")
+{
+ this->window = window;
+ set_tooltip(_("hex rgb color"));
+}
+PaletteHexButton::~PaletteHexButton()
+{
+}
+int PaletteHexButton::handle_event()
+{
+ const char *hex = window->hex_box->get_text();
+ window->update_rgb_hex(hex);
+ return 1;
+}
+
+PaletteHex::PaletteHex(ColorWindow *window, int x, int y, const char *hex)
+ : BC_TextBox(x, y, 100, 1, hex)
+{
+ this->window = window;
+}
+PaletteHex::~PaletteHex()
+{
+}
+void PaletteHex::update()
+{
+ char hex[BCSTRLEN]; sprintf(hex,"%06x",window->rgb888());
+ BC_TextBox::update(hex);
+}
+
+int PaletteHex::keypress_event()
+{
+ if( get_keypress() != RETURN )
+ return BC_TextBox::keypress_event();
+ window->update_rgb_hex(get_text());
+ return 1;
+}
+
+#include "grabpick_up_png.h"
+#include "grabpick_hi_png.h"
+#include "grabpick_dn_png.h"
+
+PaletteGrabButton::PaletteGrabButton(ColorWindow *window, int x, int y)
+ : BC_Button(x, y, vframes)
+{
+ this->window = window;
+ vframes[0] = new VFramePng(grabpick_up_png);
+ vframes[1] = new VFramePng(grabpick_hi_png);
+ vframes[2] = new VFramePng(grabpick_dn_png);
+ set_tooltip(_("grab from anywhere picker"));
+}
+PaletteGrabButton::~PaletteGrabButton()
+{
+ for( int i=0; i<3; ++i )
+ delete vframes[i];
+}
+int PaletteGrabButton::handle_event()
+{
+ if( window->grab_buttons() ) {
+ grab_cursor();
+ window->button_grabbed = 1;
+ button_press_event(); // redraw face HI
+ }
+ return 1;
+}
+
+PaletteHistory::PaletteHistory(ColorWindow *window, int x, int y)
+ : BC_SubWindow(x,y, 200, 24)
+{
+ this->window = window;
+ button_down = 0;
+ set_tooltip(_("color history"));
+}
+PaletteHistory::~PaletteHistory()
+{
+}
+void PaletteHistory::update(int flush)
+{
+ int x1 = 0, x2 = 0;
+ for( int i=0; i<PALLETTE_HISTORY_SIZE; x1=x2 ) {
+ int rgb = window->palette_history[i];
+ x2 = (++i * get_w())/PALLETTE_HISTORY_SIZE;
+ draw_3d_box(x1,0,x2-x1,get_h(),WHITE,BLACK,rgb,LTBLUE,DKBLUE);
+ }
+ flash(flush);
+}
+
+int PaletteHistory::button_press_event()
+{
+ if( button_down || !is_event_win() ) return 0;
+ button_down = 1;
+ cursor_motion_event();
+ return 1;
+}
+int PaletteHistory::button_release_event()
+{
+ if( !button_down || !is_event_win() ) return 0;
+ cursor_motion_event();
+ if( button_down > 0 ) {
+ window->handle_event();
+ window->update_display();
+ window->update_history();
+ }
+ button_down = 0;
+ return 1;
+}
+int PaletteHistory::cursor_motion_event()
+{
+ if( !button_down || !is_event_win() ) return 0;
+ hide_tooltip();
+ int pick = (PALLETTE_HISTORY_SIZE * get_cursor_x()) / get_w();
+ bclamp(pick, 0, PALLETTE_HISTORY_SIZE-1);
+ int color = window->palette_history[pick];
+ float r = ((color>>16) & 0xff) / 255.;
+ float g = ((color>>8) & 0xff) / 255.;
+ float b = ((color>>0) & 0xff) / 255.;
+ if( window->rgb.r != r || window->rgb.g != g || window->rgb.b != b ) {
+ window->rgb.r = r; window->rgb.g = g; window->rgb.b = b;
+ window->update_rgb();
+ }
+ return 1;
+}
+
+int PaletteHistory::cursor_leave_event()
+{
+ hide_tooltip();
+ return 0;
+}
+int PaletteHistory::repeat_event(int64_t duration)
+{
+ int result = 0;
+
+ if( duration == get_resources()->tooltip_delay &&
+ get_tooltip() && *get_tooltip() && cursor_above() ) {
+ show_tooltip();
+ result = 1;
+ }
+ return result;
+}