mirror of
https://gitea.nishi.boats/pyrite-dev/milsko
synced 2025-12-31 06:30:52 +00:00
git-svn-id: http://svn2.nishi.boats/svn/milsko/trunk@585 b9cfdab3-6d41-4d17-bbe4-086880011989
379 lines
10 KiB
C
379 lines
10 KiB
C
/* $Id$ */
|
|
#include <Mw/Milsko.h>
|
|
|
|
#define WIN_SIZE 464
|
|
#define PICKER_SIZE 360
|
|
#define IMG_POS_X(w) ((w - PICKER_SIZE) / 2)
|
|
#define IMG_POS_Y(h) ((h - PICKER_SIZE) / 2)
|
|
#define SCROLL_BAR_WIDTH 16
|
|
#define MARGIN (PICKER_SIZE / 32)
|
|
#define COLOR_DISPLAY_HEIGHT 12
|
|
|
|
#define HSV_HUE_SEXTANT 256.
|
|
#define HSV_HUE_STEPS (6. * HSV_HUE_SEXTANT)
|
|
|
|
#define HSV_HUE_MIN 0.
|
|
#define HSV_HUE_MAX (HSV_HUE_STEPS - 1.)
|
|
#define HSV_SAT_MIN 0.
|
|
#define HSV_SAT_MAX 255.
|
|
#define HSV_VAL_MIN 0.
|
|
#define HSV_VAL_MAX 255.
|
|
|
|
typedef struct _MwHSV {
|
|
MwBool generated : 1;
|
|
MwU16 h : 11;
|
|
MwU8 s;
|
|
MwU8 v;
|
|
} MwHSV;
|
|
|
|
typedef struct color_picker {
|
|
MwWidget parent;
|
|
MwWidget color_picker_img;
|
|
MwWidget value_slider;
|
|
MwWidget color_display;
|
|
MwWidget color_display_text;
|
|
MwWidget finish;
|
|
MwLLPixmap color_picker_pixmap;
|
|
double value;
|
|
MwRGB chosen_color;
|
|
unsigned char color_picker_image_data[PICKER_SIZE * PICKER_SIZE * 4];
|
|
MwHSV hue_table[101753];
|
|
MwU8 doUpdate;
|
|
} color_picker_t;
|
|
|
|
static void hsv2rgb(MwU32 h, MwU32 s, MwU32 v, MwU16* r, MwU16* g, MwU16* b) {
|
|
MwU8 sextant = h >> 8;
|
|
MwU16 ww;
|
|
MwU32 h_fraction, d;
|
|
|
|
#define HSV_SWAPPTR(a, b) \
|
|
do { \
|
|
MwU16* tmp = a; \
|
|
a = b; \
|
|
b = tmp; \
|
|
} while(0)
|
|
|
|
if(sextant & 2) {
|
|
HSV_SWAPPTR(r, b);
|
|
}
|
|
if(sextant & 4) {
|
|
HSV_SWAPPTR(g, b);
|
|
}
|
|
if(!(sextant & 6)) {
|
|
if(!(sextant & 1)) {
|
|
HSV_SWAPPTR(r, g);
|
|
}
|
|
} else {
|
|
if(sextant & 1) {
|
|
HSV_SWAPPTR(r, g);
|
|
}
|
|
}
|
|
|
|
*g = v; /* Top level */
|
|
|
|
/* Perform actual calculations */
|
|
|
|
/**
|
|
* Bottom level: v * (1.0 - s)
|
|
* --> (v * (255 - s) + error_corr + 1) / 256
|
|
*/
|
|
ww = v * (255 - (s)); /* We don't use ~s to prevent size-promotion side effects */
|
|
ww += 1; /* Error correction */
|
|
ww += ww >> 8; /* Error correction */
|
|
*b = ww >> 8;
|
|
|
|
h_fraction = h & 0xff; /* 0...255 */
|
|
|
|
if(!(sextant & 1)) {
|
|
/* *r = ...slope_up...; */
|
|
d = v * (MwU32)((0xff << 8) - (MwU16)(s * (0xff - h_fraction)));
|
|
*r = d >> 16;
|
|
} else {
|
|
/* *r = ...slope_down...; */
|
|
d = v * (MwU32)((0xff << 8) - (MwU16)(s * h_fraction));
|
|
*r = d >> 16;
|
|
}
|
|
return;
|
|
}
|
|
|
|
static void color_picker_image_update(color_picker_t* picker) {
|
|
MwU16 y, x;
|
|
int n = 0;
|
|
for(y = 0; y < PICKER_SIZE; y++) {
|
|
for(x = 0; x < PICKER_SIZE; x++) {
|
|
int i = ((y * PICKER_SIZE) + x) * 4;
|
|
int _x = x - (PICKER_SIZE / 2);
|
|
int _y = y - (PICKER_SIZE / 2);
|
|
double dist = sqrt(_x * _x + _y * _y);
|
|
|
|
if(dist >= 180.) {
|
|
picker->color_picker_image_data[i] = 0;
|
|
picker->color_picker_image_data[i + 1] = 0;
|
|
picker->color_picker_image_data[i + 2] = 0;
|
|
picker->color_picker_image_data[i + 3] = 0;
|
|
} else {
|
|
MwHSV hsv_v;
|
|
MwRGB color;
|
|
if(picker->hue_table[n].generated == 0) {
|
|
double xd = (M_PI / 180.) * ((double)_x);
|
|
double yd = (M_PI / 180.) * ((double)_y);
|
|
|
|
float angle = atan2(yd, xd) - M_PI;
|
|
float hue = (angle * 180.) / M_PI;
|
|
|
|
if(hue < 0.0) {
|
|
hue += 360;
|
|
}
|
|
hsv_v.h = (hue) * (HSV_HUE_STEPS / 360.);
|
|
hsv_v.s = (dist) * (HSV_SAT_MAX / 180.);
|
|
picker->hue_table[n] = hsv_v;
|
|
picker->hue_table[n].generated = 1;
|
|
}
|
|
|
|
hsv_v = picker->hue_table[n];
|
|
hsv_v.v = HSV_VAL_MAX - (picker->value * HSV_VAL_MAX);
|
|
|
|
hsv2rgb(hsv_v.h, hsv_v.s, hsv_v.v, &color.red, &color.green, &color.blue);
|
|
|
|
picker->color_picker_image_data[i] = color.red;
|
|
picker->color_picker_image_data[i + 1] = color.green;
|
|
picker->color_picker_image_data[i + 2] = color.blue;
|
|
|
|
picker->color_picker_image_data[i + 3] = 255;
|
|
n++;
|
|
}
|
|
}
|
|
}
|
|
if(picker->color_picker_pixmap == NULL) {
|
|
picker->color_picker_pixmap = MwLoadRaw(
|
|
picker->parent, picker->color_picker_image_data, PICKER_SIZE, PICKER_SIZE);
|
|
} else {
|
|
MwReloadRaw(
|
|
picker->parent, picker->color_picker_image_data, PICKER_SIZE, PICKER_SIZE, picker->color_picker_pixmap);
|
|
}
|
|
MwVaApply(picker->color_picker_img, MwNpixmap, picker->color_picker_pixmap, NULL);
|
|
// printf("%d\n", n);
|
|
}
|
|
|
|
static void color_picker_click(MwWidget handle, void* user, void* call) {
|
|
color_picker_t* picker = user;
|
|
MwLLMouse* mouse = call;
|
|
char hexColor[8];
|
|
int i;
|
|
char fgColor[8];
|
|
int fr, fg, fb;
|
|
|
|
(void)handle;
|
|
(void)user;
|
|
(void)call;
|
|
|
|
// color_picker_image_update(picker);
|
|
|
|
i = ((mouse->point.y * PICKER_SIZE) + mouse->point.x) * 4;
|
|
|
|
picker->chosen_color.red = picker->color_picker_image_data[i];
|
|
picker->chosen_color.green = picker->color_picker_image_data[i + 1];
|
|
picker->chosen_color.blue = picker->color_picker_image_data[i + 2];
|
|
|
|
sprintf(hexColor, "#%02X%02X%02X", picker->chosen_color.red, picker->chosen_color.green, picker->chosen_color.blue);
|
|
|
|
fr = picker->chosen_color.red > 128 ? 0 : 255;
|
|
fg = picker->chosen_color.green > 128 ? 0 : 255;
|
|
fb = picker->chosen_color.blue > 128 ? 0 : 255;
|
|
|
|
sprintf(fgColor, "#%02X%02X%02X", fr, fg, fb);
|
|
MwSetText(picker->color_display, MwNbackground, hexColor);
|
|
MwSetText(picker->color_display_text, MwNforeground, fgColor);
|
|
|
|
MwSetText(picker->color_display_text, MwNbackground, hexColor);
|
|
MwSetText(picker->color_display_text, MwNtext, hexColor);
|
|
}
|
|
static void color_picker_on_change_value(MwWidget handle, void* user,
|
|
void* call) {
|
|
color_picker_t* picker = user;
|
|
|
|
int value = MwGetInteger(handle, MwNvalue);
|
|
int diff = MwGetInteger(handle, MwNchangedBy);
|
|
|
|
(void)diff;
|
|
(void)call;
|
|
|
|
picker->value = ((double)value / 1024.);
|
|
|
|
picker->doUpdate = 1;
|
|
// color_picker_image_update(picker);
|
|
}
|
|
|
|
static void color_picker_tick(MwWidget handle, void* user,
|
|
void* call) {
|
|
color_picker_t* picker = user;
|
|
|
|
(void)call;
|
|
|
|
if(picker->doUpdate == 1) {
|
|
color_picker_image_update(picker);
|
|
picker->doUpdate = 0;
|
|
}
|
|
}
|
|
|
|
static void color_picker_destroy(color_picker_t* picker) {
|
|
MwLLDestroyPixmap(picker->color_picker_pixmap);
|
|
free(picker);
|
|
}
|
|
|
|
static void color_picker_close(MwWidget handle, void* user,
|
|
void* call) {
|
|
color_picker_t* picker = user;
|
|
|
|
(void)call;
|
|
|
|
color_picker_destroy(picker);
|
|
MwDestroyWidget(handle);
|
|
}
|
|
|
|
static void color_display_text_change(MwWidget handle, void* user,
|
|
void* call) {
|
|
color_picker_t* picker = user;
|
|
char hexColor[9];
|
|
char fgColor[9];
|
|
MwLLColor color;
|
|
int fr, fg, fb;
|
|
|
|
(void)call;
|
|
|
|
memcpy(&hexColor, MwGetText(handle, MwNtext), 8);
|
|
|
|
color = MwParseColor(handle, hexColor);
|
|
|
|
fr = color->red > 128 ? 0 : 255;
|
|
fg = color->green > 128 ? 0 : 255;
|
|
fb = color->blue > 128 ? 0 : 255;
|
|
|
|
sprintf(fgColor, "#%02X%02X%02X", fr, fg, fb);
|
|
MwSetText(picker->color_display, MwNbackground, hexColor);
|
|
MwSetText(picker->color_display_text, MwNforeground, fgColor);
|
|
|
|
MwSetText(picker->color_display_text, MwNbackground, hexColor);
|
|
MwSetText(picker->color_display_text, MwNtext, hexColor);
|
|
|
|
picker->chosen_color.red = color->red;
|
|
picker->chosen_color.green = color->green;
|
|
picker->chosen_color.blue = color->blue;
|
|
|
|
MwLLFreeColor(color);
|
|
}
|
|
|
|
static void color_picker_finish(MwWidget handle, void* user,
|
|
void* call) {
|
|
color_picker_t* picker = user;
|
|
|
|
(void)call;
|
|
|
|
MwDispatchUserHandler(picker->parent, MwNcolorChosenHandler, &picker->chosen_color);
|
|
|
|
color_picker_destroy(picker);
|
|
MwDestroyWidget(handle->parent);
|
|
}
|
|
|
|
color_picker_t* color_picker_setup(MwWidget parent, int w, int h) {
|
|
color_picker_t* picker = malloc(sizeof(*picker));
|
|
memset(picker, 0, sizeof(*picker));
|
|
|
|
picker->parent = parent;
|
|
|
|
picker->color_picker_img =
|
|
MwVaCreateWidget(MwImageClass, "image", picker->parent, IMG_POS_X(w), IMG_POS_Y(h),
|
|
PICKER_SIZE, PICKER_SIZE, NULL);
|
|
|
|
// picker->color_picker_image_data = malloc(PICKER_SIZE * PICKER_SIZE * 4);
|
|
|
|
picker->color_picker_pixmap = NULL;
|
|
picker->value = 0;
|
|
|
|
// color_picker_image_update(picker);
|
|
picker->doUpdate = 1;
|
|
|
|
MwAddUserHandler(picker->color_picker_img, MwNmouseDownHandler,
|
|
color_picker_click, picker);
|
|
|
|
picker->color_display = MwCreateWidget(
|
|
MwFrameClass, "colorDisplayFrame", picker->parent, IMG_POS_X(w) + (PICKER_SIZE / 2) - ((PICKER_SIZE / 4) / 2),
|
|
IMG_POS_Y(h) - (PICKER_SIZE / 16) - MARGIN, (PICKER_SIZE / 4), PICKER_SIZE / 16);
|
|
MwSetText(picker->color_display, MwNbackground, "#FFFFFF");
|
|
MwSetInteger(picker->color_display, MwnhasBorder, 1);
|
|
MwSetInteger(picker->color_display, MwNinverted, 1);
|
|
|
|
picker->color_display_text = MwCreateWidget(
|
|
MwEntryClass, "colorDisplayFrameText", picker->color_display,
|
|
MwDefaultBorderWidth(parent), MwDefaultBorderWidth(parent),
|
|
(PICKER_SIZE / 4) - MwDefaultBorderWidth(parent),
|
|
(PICKER_SIZE / 16) - (MwDefaultBorderWidth(parent) * 2));
|
|
|
|
MwSetText(picker->color_display_text, MwNtext, "#FFFFFF");
|
|
// MwSetInteger(picker->color_display_text, Mwnali, MwALIGNMENT_CENTER);
|
|
|
|
MwAddUserHandler(picker->color_display_text, MwNactivateHandler,
|
|
color_display_text_change, picker);
|
|
picker->value_slider = MwVaCreateWidget(
|
|
MwScrollBarClass, "value-slider", picker->parent,
|
|
/* x */
|
|
IMG_POS_X(w) + PICKER_SIZE + MARGIN,
|
|
|
|
/* y */
|
|
IMG_POS_Y(h),
|
|
|
|
/* width */
|
|
SCROLL_BAR_WIDTH,
|
|
|
|
/* height */
|
|
PICKER_SIZE,
|
|
|
|
MwNorientation, MwVERTICAL, MwNminValue, 0, MwNmaxValue, 1024, NULL);
|
|
|
|
MwAddUserHandler(picker->value_slider, MwNchangedHandler,
|
|
color_picker_on_change_value, picker);
|
|
|
|
picker->finish = MwCreateWidget(
|
|
MwButtonClass, "colorPickerFinish", picker->parent, IMG_POS_X(w),
|
|
IMG_POS_Y(h) + PICKER_SIZE + MARGIN, PICKER_SIZE, (WIN_SIZE - PICKER_SIZE - MARGIN * 4) / 2);
|
|
MwSetText(picker->finish, MwNtext, "Select");
|
|
MwSetInteger(picker->finish, MwnhasBorder, 1);
|
|
MwSetInteger(picker->finish, MwNinverted, 1);
|
|
|
|
MwAddUserHandler(picker->finish, MwNactivateHandler,
|
|
color_picker_finish, picker);
|
|
|
|
memset(picker->hue_table, 0, sizeof(picker->hue_table));
|
|
|
|
return picker;
|
|
}
|
|
|
|
MwWidget MwColorPicker(MwWidget handle, const char* title) {
|
|
MwPoint p;
|
|
color_picker_t* wheel;
|
|
MwWidget window;
|
|
MwSizeHints sh;
|
|
|
|
p.x = p.y = 0;
|
|
|
|
sh.min_width = sh.max_width = WIN_SIZE;
|
|
sh.min_height = sh.max_height = WIN_SIZE;
|
|
|
|
window = MwVaCreateWidget(MwWindowClass, "main", handle, MwDEFAULT, MwDEFAULT,
|
|
WIN_SIZE, WIN_SIZE,
|
|
MwNtitle, title,
|
|
MwNsizeHints, &sh,
|
|
NULL);
|
|
|
|
wheel = color_picker_setup(window, WIN_SIZE, WIN_SIZE);
|
|
|
|
MwAddUserHandler(window, MwNcloseHandler, color_picker_close, wheel);
|
|
MwAddUserHandler(window, MwNtickHandler, color_picker_tick, wheel);
|
|
MwAddTickList(window);
|
|
|
|
MwLLDetach(window->lowlevel, &p);
|
|
MwLLMakePopup(window->lowlevel, handle->lowlevel);
|
|
|
|
return window;
|
|
}
|