#include "colorchooser.h"
#include <Xm/XmAll.h>
#include <Xm/XmP.h>
#include <X11/Xft/Xft.h>
#include <inttypes.h>
#include <limits.h>
#define XNE_COLOR_DIALOG_TITLE "Select Color"
#define WIDGET_SPACING 5
#define WINDOW_SPACING 8
typedef struct {
Widget dialog;
Widget preview;
Widget textfield;
Widget selector;
GC gc;
GC selGC;
XftDraw *d;
uint8_t base_red;
uint8_t base_green;
uint8_t base_blue;
int base_sel_y;
float hue;
float saturation;
float value;
uint8_t selected_red;
uint8_t selected_green;
uint8_t selected_blue;
XftColor selected_color;
XImage *image1;
Dimension img1_width;
Dimension img1_height;
XImage *image2;
Dimension img2_width;
Dimension img2_height;
int has_selection;
Dimension img2_select_x;
Dimension img2_select_y;
int parse_textfield_input;
int status;
int end;
} cgData;
static XftDraw* create_xft_draw(Widget w);
static void selector_expose(Widget w, XtPointer u, XtPointer c);
static void selector_input(Widget w, XtPointer u, XtPointer c);
static void preview_color(Widget w, XtPointer u, XtPointer c);
static void textfield_changed(Widget w, XtPointer u, XtPointer c);
static void set_base_color(cgData *data,
int r,
int g,
int b);
static void select_color(cgData *data,
int r,
int g,
int b);
static void draw_img2(Display *dp, Window win, cgData *data);
static void okCB(Widget w, XtPointer u, XtPointer c);
static void cancelCB(Widget w, XtPointer u, XtPointer c);
int ColorChooser(Widget parent,
int *red,
int *green,
int *blue) {
Arg args[
32];
int n;
XmString str;
cgData data;
memset(&data,
0,
sizeof(data));
data.base_sel_y = -
1;
n =
0;
XtSetArg(args[n], XmNautoUnmanage, False); n++;
Widget form = XmCreateFormDialog(parent,
"ColorDialog", args, n);
Widget dialog = XtParent(form);
XtVaSetValues(dialog, XmNtitle,
XNE_COLOR_DIALOG_TITLE,
NULL);
XtManageChild(form);
n =
0;
XtSetArg(args[n], XmNshadowType, XmSHADOW_IN); n++;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNtopOffset,
WINDOW_SPACING); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNleftOffset,
WINDOW_SPACING); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
XtSetArg(args[n], XmNrightPosition,
30); n++;
data.preview = XmCreateDrawingArea(form,
"cgPreview", args, n);
XtManageChild(data.preview);
XtAddCallback(data.preview, XmNexposeCallback, preview_color, &data);
n =
0;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNtopOffset,
WINDOW_SPACING); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNrightOffset,
WINDOW_SPACING); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
XtSetArg(args[n], XmNleftPosition,
33); n++;
data.textfield = XmCreateTextField(form,
"cgText", args, n);
XtManageChild(data.textfield);
XtAddCallback(data.textfield, XmNvalueChangedCallback, textfield_changed, &data);
XtVaSetValues(data.preview, XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET, XmNbottomWidget, data.textfield,
NULL);
n =
0;
str = XmStringCreateSimple(
"OK");
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNbottomOffset,
WINDOW_SPACING); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
XtSetArg(args[n], XmNleftPosition,
12); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
XtSetArg(args[n], XmNrightPosition,
37); n++;
XtSetArg(args[n], XmNlabelString, str); n++;
Widget ok = XmCreatePushButton(form,
"cgOK", args, n);
XtManageChild(ok);
XmStringFree(str);
XtAddCallback(ok, XmNactivateCallback, okCB, &data);
n =
0;
str = XmStringCreateSimple(
"Cancel");
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNbottomOffset,
WINDOW_SPACING); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
XtSetArg(args[n], XmNleftPosition,
63); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
XtSetArg(args[n], XmNrightPosition,
88); n++;
XtSetArg(args[n], XmNlabelString, str); n++;
Widget cancel = XmCreatePushButton(form,
"cgOK", args, n);
XtManageChild(cancel);
XmStringFree(str);
XtAddCallback(cancel, XmNactivateCallback, cancelCB, &data);
XtVaSetValues(form, XmNdefaultButton, ok,
NULL);
XtVaSetValues(form, XmNcancelButton, cancel,
NULL);
static XtTranslations selectorTranslations =
NULL;
if(!selectorTranslations) {
selectorTranslations = XtParseTranslationTable(
"<Btn1Down>: DrawingAreaInput() ManagerGadgetArm()\n<Btn1Motion>: DrawingAreaInput() ManagerGadgetButtonMotion()");
}
n =
0;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
XtSetArg(args[n], XmNtopWidget, data.textfield); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNtopOffset,
WINDOW_SPACING); n++;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
XtSetArg(args[n], XmNbottomWidget, ok); n++;
XtSetArg(args[n], XmNbottomOffset,
WINDOW_SPACING); n++;
XtSetArg(args[n], XmNleftOffset,
WINDOW_SPACING); n++;
XtSetArg(args[n], XmNrightOffset,
WINDOW_SPACING); n++;
XtSetArg(args[n], XmNwidth,
500); n++;
XtSetArg(args[n], XmNheight,
400); n++;
XtSetArg(args[n], XmNtranslations, selectorTranslations); n++;
data.selector = XmCreateDrawingArea(form,
"cgSelector", args, n);
XtManageChild(data.selector);
XtAddCallback(data.selector, XmNexposeCallback, selector_expose, &data);
XtAddCallback(data.selector, XmNinputCallback, selector_input, &data);
XGCValues gcValues;
gcValues.background = data.selector->core.background_pixel;
gcValues.foreground = BlackPixelOfScreen(DefaultScreenOfDisplay(XtDisplay(data.selector)));
gcValues.graphics_exposures =
0;
data.gc = XtAllocateGC(data.selector,
0, GCForeground | GCBackground, &gcValues,
0,
0);
gcValues.background = data.selector->core.background_pixel;
gcValues.foreground = WhitePixelOfScreen(DefaultScreenOfDisplay(XtDisplay(data.selector)));
gcValues.graphics_exposures =
0;
data.selGC = XtAllocateGC(data.selector,
0, GCForeground | GCBackground, &gcValues,
0,
0);
select_color(&data, *red /
257, *green /
257, *blue /
257);
set_base_color(&data, (*red)/
257, (*green)/
257, (*blue)/
257);
XtManageChild(dialog);
data.parse_textfield_input =
1;
XtAppContext app = XtWidgetToApplicationContext(dialog);
while(!data.end && !XtAppGetExitFlag(app)) {
XEvent event;
XtAppNextEvent(app, &event);
XtDispatchEvent(&event);
}
XtReleaseGC(data.selector, data.gc);
XtReleaseGC(data.selector, data.selGC);
if(data.image1) XDestroyImage(data.image1);
if(data.image2) XDestroyImage(data.image2);
if(data.d) XftDrawDestroy(data.d);
XtDestroyWidget(dialog);
if(data.status ==
1) {
*red = data.selected_color.color.red;
*green = data.selected_color.color.green;
*blue = data.selected_color.color.blue;
}
return data.status;
}
static XftDraw* create_xft_draw(Widget w) {
XWindowAttributes attributes;
XGetWindowAttributes(XtDisplay(w), XtWindow(w), &attributes);
Screen *screen = w->core.screen;
Visual *visual = screen->root_visual;
for(
int i=
0;i<screen->ndepths;i++) {
Depth d = screen->depths[i];
if(d.depth == w->core.depth) {
visual = d.visuals;
break;
}
}
Display *dp = XtDisplay(w);
return XftDrawCreate(
dp,
XtWindow(w),
visual,
w->core.colormap);
}
static int get_shift(
unsigned long mask) {
if(mask ==
0) {
return 0;
}
int shift =
0;
while((mask &
1L) ==
0) {
shift++;
mask >>=
1;
}
return shift;
}
static int get_mask_len(
unsigned long mask) {
if(mask ==
0) {
return 0;
}
while((mask &
1L) ==
0) {
mask >>=
1;
}
int len =
0;
while((mask &
1L) ==
1) {
len++;
mask >>=
1;
}
return len;
}
static Visual* get_visual(Screen *screen,
int depth) {
Visual *visual =
NULL;
for(
int i=
0;i<screen->ndepths;i++) {
Depth d = screen->depths[i];
if(d.depth == depth) {
for(
int v=
0;v<d.nvisuals;v++) {
Visual *vs = &d.visuals[v];
if(get_mask_len(vs->red_mask) ==
8) {
visual = vs;
break;
}
}
}
}
return visual;
}
#define IMG1_WIDTH 20
#define IMG1_X_OFFSET 20
#define IMG1_Y_OFFSET 10
#define IMG2_X_OFFSET 10
#define IMG2_Y_OFFSET 10
static void init_pix1(cgData *data, Widget w) {
Display *dp = XtDisplay(w);
Dimension width =
IMG1_WIDTH;
Dimension height = w->core.height -
IMG1_Y_OFFSET*
2;
if(data->image1) {
if(height == data->img2_height)
return;
XDestroyImage(data->image1);
}
float height6 = ((
float)height)/
6.f;
float step = ((
float)
255.f)/height6;
Visual *visual = get_visual(w->core.screen, w->core.depth);
if(!visual) {
return;
}
int red_shift = get_shift(visual->red_mask);
int green_shift = get_shift(visual->green_mask);
int blue_shift = get_shift(visual->blue_mask);
uint32_t *imgdata = malloc(width * height *
4);
uint32_t pixel_init =
UINT32_MAX ^ (visual->red_mask ^ visual->green_mask ^ visual->blue_mask);
int m =
0;
float r = 0xFF;
float g =
0;
float b =
0;
for(
int i=
0;i<height;i++) {
if(r <
0) r =
0;
if(r >
255) r =
255;
if(g <
0) g =
0;
if(g >
255) g =
255;
if(b <
0) b =
0;
if(b >
255) b =
255;
uint8_t red = r;
uint8_t green = g;
uint8_t blue = b;
switch(m) {
case 0: {
g += step;
if(g >=
255) m++;
break;
}
case 1: {
r -= step;
if(r <=
0) m++;
break;
}
case 2: {
b += step;
if(b >=
255) m++;
break;
}
case 3: {
g -= step;
if(g <=
0) m++;
break;
}
case 4: {
r += step;
if(r >=
255) m++;
break;
}
case 5: {
b -= step;
if(b <=
0) m =
0;
break;
}
}
uint32_t out = pixel_init;
out ^= (red << red_shift);
out ^= (green << green_shift);
out ^= (blue << blue_shift);
for(
int j=
0;j<width;j++) {
imgdata[i*width + j] = out;
}
}
data->image1 = XCreateImage(dp, visual, w->core.depth, ZPixmap,
0, (
char*)imgdata, width, height,
32,
0);
data->img1_width = width;
data->img1_height = height;
}
static void init_pix2(cgData *data, Widget w) {
Display *dp = XtDisplay(w);
Dimension width = w->core.width -
IMG1_X_OFFSET -
IMG1_WIDTH -
2*
IMG2_X_OFFSET;
Dimension height = w->core.height -
2*
IMG2_Y_OFFSET;
if(data->image2) {
if(width == data->img2_width && height == data->img2_height)
return;
XDestroyImage(data->image2);
data->has_selection =
0;
}
if(!data->has_selection) {
data->img2_select_x = (
float)width * data->value -
1;
data->img2_select_y = height - ((
float)height * data->saturation);
data->has_selection =
1;
}
Visual *visual = get_visual(w->core.screen, w->core.depth);
if(!visual) {
return;
}
int red_shift = get_shift(visual->red_mask);
int green_shift = get_shift(visual->green_mask);
int blue_shift = get_shift(visual->blue_mask);
uint32_t *imgdata = malloc(width * height *
4);
uint32_t pixel_init =
UINT32_MAX ^ (visual->red_mask ^ visual->green_mask ^ visual->blue_mask);
float y_base_r = data->base_red;
float y_base_g = data->base_green;
float y_base_b = data->base_blue;
float y_step_r = (
255-data->base_red) / (
float)(height-
2*
IMG2_Y_OFFSET);
float y_step_g = (
255-data->base_green) / (
float)(height-
2*
IMG2_Y_OFFSET);
float y_step_b = (
255-data->base_blue) / (
float)(height-
2*
IMG2_Y_OFFSET);
for(
int y=
0;y<height;y++) {
float x_step_r = y_base_r / (
float)width;
float x_step_g = y_base_g / (
float)width;
float x_step_b = y_base_b / (
float)width;
float r = y_base_r;
float g = y_base_g;
float b = y_base_b;
y_base_r += y_step_r;
y_base_g += y_step_g;
y_base_b += y_step_b;
if(y_base_r >=
255) y_base_r =
255;
if(y_base_g >=
255) y_base_g =
255;
if(y_base_b >=
255) y_base_b =
255;
for(
int x=width-
1;x>=
0;x--) {
if(r <
0) r =
0;
if(g <
0) g =
0;
if(b <
0) b =
0;
uint8_t red = r;
uint8_t green = g;
uint8_t blue = b;
r -= x_step_r;
g -= x_step_g;
b -= x_step_b;
uint32_t out = pixel_init;
out ^= (red << red_shift);
out ^= (green << green_shift);
out ^= (blue << blue_shift);
imgdata[y*width + x] = out;
}
}
data->image2 = XCreateImage(dp, visual, w->core.depth, ZPixmap,
0, (
char*)imgdata, width, height,
32,
0);
data->img2_width = width;
data->img2_height = height;
}
static void draw_img2(Display *dp, Window win, cgData *data) {
int img2_x =
IMG1_X_OFFSET + data->img1_width +
IMG2_X_OFFSET;
int img2_y =
IMG2_Y_OFFSET;
XPutImage(dp, win, data->gc, data->image2,
0,
0, img2_x, img2_y, data->img2_width, data->img2_height);
if(data->has_selection) {
XDrawLine(dp, win, data->selGC,
img2_x, img2_y + data->img2_select_y,
img2_x + data->img2_width -
1, img2_y + data->img2_select_y);
XDrawLine(dp, win, data->selGC,
img2_x + data->img2_select_x, img2_y,
img2_x + data->img2_select_x, img2_y + data->img2_height -
1);
}
}
#define HUE_INDICATOR_SIZE 9
static void selector_expose(Widget w, XtPointer u, XtPointer c) {
cgData *data = u;
Dimension width = w->core.width;
Dimension height = w->core.height;
Display *dp = XtDisplay(w);
Window win = XtWindow(w);
init_pix1(data, w);
init_pix2(data, w);
if(data->base_sel_y <
0) {
float img1h = data->img1_height;
float deg2pix = img1h /
360.f;
data->base_sel_y = data->hue * deg2pix;
}
XClearArea(XtDisplay(w), XtWindow(w),
1,
1, width-
2,
IMG1_Y_OFFSET-
1, False);
XClearArea(XtDisplay(w), XtWindow(w),
1,
IMG1_Y_OFFSET + data->img1_height,
width-
2, height -
IMG1_Y_OFFSET - data->img1_height -
2, False);
XClearArea(XtDisplay(w), XtWindow(w),
1,
1,
IMG1_X_OFFSET-
1, height-
2, False);
XPoint indicator[
4];
indicator[
0].x =
IMG1_X_OFFSET-
1;
indicator[
0].y =
IMG1_Y_OFFSET + data->base_sel_y;
indicator[
1].x =
IMG1_X_OFFSET-
HUE_INDICATOR_SIZE -
1;
indicator[
1].y =
IMG1_Y_OFFSET + data->base_sel_y -
HUE_INDICATOR_SIZE;
indicator[
2].x =
IMG1_X_OFFSET-
HUE_INDICATOR_SIZE -
1;
indicator[
2].y =
IMG1_Y_OFFSET + data->base_sel_y +
HUE_INDICATOR_SIZE;
indicator[
3].x =
IMG1_X_OFFSET-
1;
indicator[
3].y =
IMG1_Y_OFFSET + data->base_sel_y;
XFillPolygon(dp, win, data->gc, indicator,
4, Convex, CoordModeOrigin);
XClearArea(XtDisplay(w), XtWindow(w),
IMG1_X_OFFSET + data->img1_width +
IMG2_X_OFFSET + data->img2_width,
1,
width -
1 -
IMG1_X_OFFSET - data->img1_width -
IMG2_X_OFFSET - data->img2_width, height-
2, False);
XClearArea(XtDisplay(w), XtWindow(w),
IMG1_X_OFFSET + data->img1_width,
1,
IMG2_X_OFFSET, height-
2, False);
if(data->image1) {
XPutImage(dp, win, data->gc, data->image1,
0,
0,
IMG1_X_OFFSET,
IMG1_Y_OFFSET, data->img1_width, data->img1_height);
}
if(data->image2) {
draw_img2(dp, win, data);
}
XDrawRectangle(dp, win, DefaultGC(dp,
0),
0,
0, width-
1, height-
1);
}
#define SELECT_MARGIN 5
static int translate_img1(cgData *data,
int x,
int y,
int *trans_x,
int *trans_y) {
if(x <
IMG1_X_OFFSET -
HUE_INDICATOR_SIZE)
return 0;
if(y <
IMG1_Y_OFFSET)
return 0;
int tx = x -
IMG1_X_OFFSET;
int ty = y -
IMG1_Y_OFFSET;
if(tx < data->img1_width && ty < data->img1_height) {
*trans_x = tx;
*trans_y = ty;
return 1;
}
return 0;
}
static int translate_img2(cgData *data,
int x,
int y,
int *trans_x,
int *trans_y) {
if(x <
IMG1_X_OFFSET +
IMG2_X_OFFSET + data->img1_width -
SELECT_MARGIN)
return 0;
if(y <
IMG1_Y_OFFSET)
return 0;
int tx = x - (
IMG1_X_OFFSET +
IMG2_X_OFFSET + data->img1_width);
int ty = y -
IMG2_Y_OFFSET;
if(tx < data->img2_width +
SELECT_MARGIN && ty < data->img2_height +
SELECT_MARGIN) {
if(tx <
0) tx =
0;
if(ty <
0) ty =
0;
if(tx >= data->img2_width) tx = data->img2_width-
1;
if(ty >= data->img2_height) ty = data->img2_height-
1;
*trans_x = tx;
*trans_y = ty;
return 1;
}
return 0;
}
static void selector_input(Widget w, XtPointer u, XtPointer c) {
XmDrawingAreaCallbackStruct *cb = (XmDrawingAreaCallbackStruct*)c;
cgData *data = u;
Display *dp = XtDisplay(w);
Window win = XtWindow(w);
Dimension x, y;
if(cb->event->type == MotionNotify) {
x = cb->event->xmotion.x;
y = cb->event->xmotion.y;
}
else {
x = cb->event->xbutton.x;
y = cb->event->xbutton.y;
}
int tx, ty;
if(translate_img1(data, x, y, &tx, &ty)) {
uint32_t color = XGetPixel(data->image1, tx, ty);
int red_shift = get_shift(data->image1->red_mask);
int green_shift = get_shift(data->image1->green_mask);
int blue_shift = get_shift(data->image1->blue_mask);
data->base_red = (color & data->image1->red_mask) >> red_shift;
data->base_green = (color & data->image1->green_mask) >> green_shift;
data->base_blue = (color & data->image1->blue_mask) >> blue_shift;
data->base_sel_y = ty;
XDestroyImage(data->image2);
data->image2 =
NULL;
init_pix2(data, w);
data->has_selection =
0;
selector_expose(w, u,
NULL);
}
if(translate_img2(data, x, y, &tx, &ty)) {
uint32_t color = XGetPixel(data->image2, tx, ty);
int red_shift = get_shift(data->image2->red_mask);
int green_shift = get_shift(data->image2->green_mask);
int blue_shift = get_shift(data->image2->blue_mask);
data->img2_select_x = tx;
data->img2_select_y = ty;
data->has_selection =
1;
select_color(data,
(color & data->image2->red_mask) >> red_shift,
(color & data->image2->green_mask) >> green_shift,
(color & data->image2->blue_mask) >> blue_shift);
preview_color(data->preview, data,
NULL);
draw_img2(dp, win, data);
}
}
static float max3(
float a,
float b,
float c) {
if(a > b) {
return a > c ? a : c;
}
else {
return b > c ? b : c;
}
}
static float min3(
float a,
float b,
float c) {
if(a < b) {
return a < c ? a : c;
}
else {
return b < c ? b : c;
}
}
static void rgbToHsv(
int red,
int green,
int blue,
float *hue,
float *saturation,
float *value) {
float r = red;
float g = green;
float b = blue;
r /=
255;
g /=
255;
b /=
255;
float rgbMax = max3(r, g, b);
float rgbMin = min3(r, g, b);
float mmDiff = rgbMax - rgbMin;
float h;
if(rgbMax == rgbMin) {
h =
0;
}
else if(rgbMax == r) {
h =
60.f * (g-b)/mmDiff;
}
else if(rgbMax == g) {
h =
60.f * (
2.f + (b-r)/mmDiff);
}
else {
h =
60.f * (
4.f + (r-g)/mmDiff);
}
if(h <
0) h +=
360;
float s = rgbMax ==
0 ?
0 : mmDiff/rgbMax;
float v = rgbMax;
*hue = h;
*saturation = s;
*value = v;
}
static void hsvToRgb(
float hue,
float saturation,
float value,
int *red,
int *green,
int *blue) {
int hi = hue/
60;
float f = (hue/
60) - hi;
float p = value * (
1-saturation);
float q = value * (
1-saturation * f);
float t = value * (
1-saturation * (
1-f));
float r, g, b;
switch(hi) {
case 1: {
r = q;
g = value;
b = p;
break;
}
case 2: {
r = p;
g = value;
b = t;
break;
}
case 3: {
r = p;
g = q;
b = value;
break;
}
case 4: {
r = t;
g = p;
b = value;
break;
}
case 5: {
r = value;
g = p;
b = q;
break;
}
default: {
r = value;
g = t;
b = p;
}
}
*red = r *
255;
*green = g *
255;
*blue = b *
255;
}
static void set_base_color(cgData *data,
int r,
int g,
int b) {
float h, s, v;
rgbToHsv(r, g, b, &h, &s, &v);
int red, green, blue;
hsvToRgb(h,
1,
1, &red, &green, &blue);
data->base_red = red;
data->base_green = green;
data->base_blue = blue;
data->hue = h;
data->saturation = s;
data->value = v;
data->base_sel_y = -
1;
}
static void select_color(cgData *data,
int r,
int g,
int b) {
XftColor color;
color.pixel =
0;
color.color.alpha = 0xFFFF;
color.color.red = r *
257;
color.color.green = g *
257;
color.color.blue = b *
257;
data->selected_color = color;
char buf[
8];
snprintf(buf,
8,
"#%02x%02x%02x", r, g, b);
data->parse_textfield_input =
0;
XmTextFieldSetString(data->textfield, buf);
data->parse_textfield_input =
1;
}
static void preview_color(Widget w, XtPointer u, XtPointer c) {
cgData *data = u;
if(!data->d) {
data->d = create_xft_draw(w);
}
XftDrawRect(data->d, &data->selected_color,
0,
0, w->core.width, w->core.height);
XDrawRectangle(XtDisplay(w), XtWindow(w), data->gc,
0,
0, w->core.width-
1, w->core.height-
1);
}
static void textfield_changed(Widget w, XtPointer u, XtPointer c) {
cgData *data = u;
if(!data->parse_textfield_input)
return;
char *colorStr = XmTextFieldGetString(w);
if(strlen(colorStr) !=
7) {
XtFree(colorStr);
return;
}
Display *dp = XtDisplay(w);
Colormap cmap = w->core.colormap;
XColor color;
if(XParseColor(dp, cmap, colorStr, &color)) {
XftColor c;
c.pixel =
0;
c.color.alpha = 0xFFFF;
c.color.red = color.red;
c.color.green = color.green;
c.color.blue = color.blue;
data->selected_color = c;
set_base_color(data, color.red/
257, color.green/
257, color.blue/
257);
XDestroyImage(data->image2);
data->image2 =
NULL;
init_pix2(data, w);
data->has_selection =
0;
selector_expose(data->selector, data,
NULL);
preview_color(data->preview, data,
NULL);
}
XtFree(colorStr);
}
static void okCB(Widget w, XtPointer u, XtPointer c) {
cgData *data = u;
data->status =
1;
data->end =
1;
}
static void cancelCB(Widget w, XtPointer u, XtPointer c) {
cgData *data = u;
data->status =
0;
data->end =
1;
}