mirror of
https://github.com/ctm/executor.git
synced 2024-11-15 13:05:51 +00:00
1411 lines
35 KiB
C
1411 lines
35 KiB
C
|
/* Copyright 1995, 1996 by Abacus Research and
|
||
|
* Development, Inc. All rights reserved.
|
||
|
*/
|
||
|
|
||
|
#if !defined (OMIT_RCSID_STRINGS)
|
||
|
char ROMlib_rcsid_qColorPicker[] =
|
||
|
"$Id: qColorPicker.c 88 2005-05-25 03:59:37Z ctm $";
|
||
|
#endif
|
||
|
|
||
|
#include "rsys/common.h"
|
||
|
|
||
|
#include "WindowMgr.h"
|
||
|
#include "ControlMgr.h"
|
||
|
#include "QuickDraw.h"
|
||
|
#include "CQuickDraw.h"
|
||
|
#include "TextEdit.h"
|
||
|
#include "EventMgr.h"
|
||
|
#include "ToolboxEvent.h"
|
||
|
#include "OSEvent.h"
|
||
|
|
||
|
#include "rsys/cquick.h"
|
||
|
#include "rsys/ctl.h"
|
||
|
|
||
|
/* ### hack for `image_bits ()' */
|
||
|
#include "rsys/menu.h"
|
||
|
#include "rsys/color_wheel_bits.h"
|
||
|
#include "rsys/osevent.h"
|
||
|
#include "rsys/options.h"
|
||
|
|
||
|
#include <ctype.h>
|
||
|
#include <math.h>
|
||
|
|
||
|
/* sanity defines */
|
||
|
|
||
|
#define _NewCWindow(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \
|
||
|
((WindowPtr) NewCWindow (arg0, arg1, arg2, arg3, arg4, \
|
||
|
(CWindowPtr) (arg5), arg6, arg7))
|
||
|
|
||
|
#define _FindControl(arg0, arg1, arg2) \
|
||
|
({ \
|
||
|
int16 retval; \
|
||
|
HIDDEN_ControlHandle bogo_c; \
|
||
|
\
|
||
|
retval = FindControl (arg0, arg1, &bogo_c); \
|
||
|
*(arg2) = MR (bogo_c.p); \
|
||
|
\
|
||
|
retval; \
|
||
|
})
|
||
|
|
||
|
#define sqr(v) ({ typeof (v) _v = (v); _v * _v; })
|
||
|
|
||
|
#define color_picker_window_bounds (_bounds)
|
||
|
#define ok_button_bounds (&_bounds[1])
|
||
|
#define cancel_button_bounds (&_bounds[2])
|
||
|
|
||
|
#define template_text_box_bounds (&_bounds[3])
|
||
|
|
||
|
#define template_compare_box_bounds (&_bounds[9])
|
||
|
|
||
|
#define prompt_bounds (&_bounds[12])
|
||
|
#define template_color_wheel_bounds (&_bounds[13])
|
||
|
|
||
|
static Rect _bounds[] =
|
||
|
{
|
||
|
/* top, left, bottom, right */
|
||
|
|
||
|
/* color picker window bounds; filled in by `compute_bounds' */
|
||
|
{ CWC (-1), CWC (-1), CWC (-1), CWC (-1) },
|
||
|
|
||
|
/* ok button bounds */
|
||
|
{ CWC (330), CWC (410), CWC (350), CWC (470) },
|
||
|
/* cancel button bounds */
|
||
|
{ CWC (330), CWC (337), CWC (350), CWC (397) },
|
||
|
|
||
|
/* text entry box rects */
|
||
|
{ CWC (324), CWC (10), CWC (350), CWC (90) },
|
||
|
{ CWC (299), CWC (10), CWC (325), CWC (90) },
|
||
|
{ CWC (274), CWC (10), CWC (300), CWC (90) },
|
||
|
|
||
|
{ CWC (228), CWC (10), CWC (254), CWC (90) },
|
||
|
{ CWC (203), CWC (10), CWC (229), CWC (90) },
|
||
|
{ CWC (178), CWC (10), CWC (204), CWC (90) },
|
||
|
|
||
|
/* rectangle for the color comparison boxes */
|
||
|
/* frame */
|
||
|
{ CWC (78), CWC (0), CWC (138), CWC (100) },
|
||
|
/* orig, current */
|
||
|
{ CWC (108), CWC (2), CWC (136), CWC (98) },
|
||
|
{ CWC (80), CWC (2), CWC (108), CWC (98) },
|
||
|
|
||
|
/* prompt bounds */
|
||
|
{ CWC (10), CWC (10), CWC (60), CWC (240) },
|
||
|
|
||
|
/* color wheel bounds */
|
||
|
{ CWC (20), CWC (268), CWC (212), CWC (460) },
|
||
|
};
|
||
|
|
||
|
#define compare_box_frame_bounds (compare_box_bounds)
|
||
|
#define orig_compare_box_bounds (&compare_box_bounds[1])
|
||
|
#define current_compare_box_bounds (&compare_box_bounds[2])
|
||
|
|
||
|
static Rect compare_box_bounds[3];
|
||
|
|
||
|
static Rect color_wheel_bounds[1];
|
||
|
|
||
|
static int color_wheel_center_x, color_wheel_center_y;
|
||
|
|
||
|
#define N_TEXT_BOXES (6)
|
||
|
|
||
|
struct text_box
|
||
|
{
|
||
|
Point title_pt;
|
||
|
StringPtr title;
|
||
|
|
||
|
Point label_pt;
|
||
|
StringPtr label;
|
||
|
|
||
|
Rect frame_rect;
|
||
|
Rect te_rect;
|
||
|
Rect miniarrow_rect;
|
||
|
|
||
|
/* ### maintaining seperate integer/factional portions is way too
|
||
|
complicated nad messy. i did this because originally i wanted to
|
||
|
avoid using floating point (but that became necessary to
|
||
|
generate/interpret the color wheel target location), and having
|
||
|
all the color values stored in 16bit quanities resulted in
|
||
|
roundoff when converting to text and back again */
|
||
|
int integer, fractional;
|
||
|
|
||
|
int *value;
|
||
|
int max;
|
||
|
int continuous_p;
|
||
|
|
||
|
int i;
|
||
|
} text_boxes[N_TEXT_BOXES];
|
||
|
|
||
|
TEHandle te;
|
||
|
|
||
|
/* index into `text_boxes' which `te' currently represents */
|
||
|
static struct text_box *te_box;
|
||
|
|
||
|
static WindowPtr color_picker_window;
|
||
|
|
||
|
static ControlHandle cancel_button, ok_button;
|
||
|
|
||
|
static StringPtr prompt_text;
|
||
|
|
||
|
static int font_height, font_ascent;
|
||
|
static int space_width;
|
||
|
|
||
|
static void
|
||
|
text_box_update_value (struct text_box *box, int newval,
|
||
|
boolean_t update_if_p);
|
||
|
static void
|
||
|
text_box_update_value_1 (struct text_box *box, int newval,
|
||
|
boolean_t update_if_p,
|
||
|
boolean_t update_color_wheel_target_p);
|
||
|
|
||
|
static void
|
||
|
text_box_update_if_value (struct text_box *box,
|
||
|
int new_integer, int new_fractional);
|
||
|
static void
|
||
|
text_box_update_if_value_1 (struct text_box *box,
|
||
|
int new_integer, int new_fractional);
|
||
|
|
||
|
static void val_if (int val, int max,
|
||
|
int *integer_return, int *fractional_return);
|
||
|
static int if_val (int max, int integer, int fractional);
|
||
|
|
||
|
static void color_wheel_update (void);
|
||
|
static void color_wheel_notice_lightness_change (void);
|
||
|
static void color_wheel_target_update (boolean_t short_cut_p);
|
||
|
|
||
|
#define red_index (0)
|
||
|
#define green_index (1)
|
||
|
#define blue_index (2)
|
||
|
#define hue_index (3)
|
||
|
#define saturation_index (4)
|
||
|
#define lightness_index (5)
|
||
|
|
||
|
static int red;
|
||
|
static int green;
|
||
|
static int blue;
|
||
|
|
||
|
static int hue;
|
||
|
static int saturation;
|
||
|
static int lightness;
|
||
|
|
||
|
static RGBColor current_color;
|
||
|
static RGBColor orig_color;
|
||
|
|
||
|
static void
|
||
|
compute_bounds (Point maybe_top_left)
|
||
|
{
|
||
|
int width, height;
|
||
|
int top, left;
|
||
|
|
||
|
/* note: must match width/height for `color_picker_window_bounds' */
|
||
|
width = 480;
|
||
|
height = 360;
|
||
|
|
||
|
if ((! maybe_top_left.v && ! maybe_top_left.h)
|
||
|
/* #### ignore the application suggestion, and always center the
|
||
|
color picker sanely
|
||
|
|
||
|
for some reason, Tex-Edit passes in `-1, -1' as the suggested
|
||
|
location */
|
||
|
|| 1)
|
||
|
{
|
||
|
Rect *gd_rect;
|
||
|
int gd_width;
|
||
|
int gd_height;
|
||
|
|
||
|
gd_rect = &GD_RECT (MR (MainDevice));
|
||
|
gd_width = RECT_WIDTH (gd_rect);
|
||
|
gd_height = RECT_HEIGHT (gd_rect);
|
||
|
|
||
|
/* centered horizontally, with a third of the space above the
|
||
|
window, and two-thirds below */
|
||
|
top = CW (gd_rect->top) + (gd_height - height) / 3;
|
||
|
left = CW (gd_rect->left) + (gd_width - width) / 2;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
top = maybe_top_left.v;
|
||
|
left = maybe_top_left.h;
|
||
|
}
|
||
|
|
||
|
color_picker_window_bounds->top = CW (top);
|
||
|
color_picker_window_bounds->left = CW (left);
|
||
|
color_picker_window_bounds->bottom = CW (top + height);
|
||
|
color_picker_window_bounds->right = CW (left + width);
|
||
|
}
|
||
|
|
||
|
typedef enum miniarrow_hilite
|
||
|
{
|
||
|
miniarrow_no_hilite,
|
||
|
miniarrow_up_hilite,
|
||
|
miniarrow_down_hilite,
|
||
|
} miniarrow_hilite_t;
|
||
|
|
||
|
static boolean_t integer_increment_p;
|
||
|
static int track_kount;
|
||
|
|
||
|
static void
|
||
|
miniarrow_track (struct text_box *box, miniarrow_hilite_t _hilite)
|
||
|
{
|
||
|
int integer, fractional, max;
|
||
|
boolean_t continuous_p;
|
||
|
|
||
|
integer = box->integer;
|
||
|
fractional = box->fractional;
|
||
|
max = box->max;
|
||
|
continuous_p = box->continuous_p;
|
||
|
|
||
|
switch (_hilite)
|
||
|
{
|
||
|
case miniarrow_up_hilite:
|
||
|
if (integer_increment_p)
|
||
|
{
|
||
|
if (integer == max)
|
||
|
{
|
||
|
if (continuous_p)
|
||
|
integer = 0;
|
||
|
}
|
||
|
else
|
||
|
integer ++;
|
||
|
}
|
||
|
else if (fractional == 0
|
||
|
&& integer == max)
|
||
|
{
|
||
|
if (continuous_p)
|
||
|
integer = 0;
|
||
|
}
|
||
|
else if (fractional == 9)
|
||
|
{
|
||
|
if (track_kount > 5)
|
||
|
integer_increment_p = TRUE;
|
||
|
|
||
|
integer ++;
|
||
|
fractional = 0;
|
||
|
}
|
||
|
else
|
||
|
fractional ++;
|
||
|
break;
|
||
|
case miniarrow_down_hilite:
|
||
|
if (integer_increment_p)
|
||
|
{
|
||
|
if (integer == 0)
|
||
|
{
|
||
|
if (continuous_p)
|
||
|
integer = max;
|
||
|
}
|
||
|
else
|
||
|
integer --;
|
||
|
}
|
||
|
else if (fractional == 0
|
||
|
&& integer == 0)
|
||
|
{
|
||
|
if (continuous_p)
|
||
|
integer = max;
|
||
|
}
|
||
|
else if (fractional == 0)
|
||
|
{
|
||
|
integer --;
|
||
|
|
||
|
if (track_kount > 5)
|
||
|
integer_increment_p = TRUE;
|
||
|
else
|
||
|
fractional = 9;
|
||
|
}
|
||
|
else
|
||
|
fractional --;
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* note that the integer and/or fractional values have changed */
|
||
|
text_box_update_if_value (box, integer, fractional);
|
||
|
|
||
|
track_kount ++;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
text_box_init (void)
|
||
|
{
|
||
|
static StringPtr titles[N_TEXT_BOXES] =
|
||
|
{
|
||
|
(StringPtr) "\005Red: ",
|
||
|
(StringPtr) "\007Green: ",
|
||
|
(StringPtr) "\006Blue: ",
|
||
|
(StringPtr) "\013Hue Angle: ",
|
||
|
(StringPtr) "\014Saturation: ",
|
||
|
(StringPtr) "\013Lightness: ",
|
||
|
};
|
||
|
static StringPtr labels[N_TEXT_BOXES] =
|
||
|
{
|
||
|
(StringPtr) "\001%",
|
||
|
(StringPtr) "\001%",
|
||
|
(StringPtr) "\001%",
|
||
|
(StringPtr) "\001\241", /* degree symbol? */
|
||
|
(StringPtr) "\001%",
|
||
|
(StringPtr) "\001%",
|
||
|
};
|
||
|
int *values[N_TEXT_BOXES] =
|
||
|
{
|
||
|
&red, &green, &blue, &hue, &saturation, &lightness,
|
||
|
};
|
||
|
int maxi[N_TEXT_BOXES] = { 100, 100, 100, 360, 100, 100 };
|
||
|
int offset, label_width;
|
||
|
int i;
|
||
|
|
||
|
/* compute the text box offset caused by the titles */
|
||
|
offset = -1;
|
||
|
label_width = -1;
|
||
|
for (i = 0; i < (int) NELEM (titles); i ++)
|
||
|
{
|
||
|
StringPtr title, label;
|
||
|
|
||
|
title = titles[i];
|
||
|
label = labels[i];
|
||
|
offset = MAX (offset, StringWidth (title));
|
||
|
label_width = MAX (label_width, StringWidth (label));
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < N_TEXT_BOXES; i ++)
|
||
|
{
|
||
|
struct text_box *box;
|
||
|
Rect *template_bounds, *frame_bounds, *te_bounds;
|
||
|
Rect *miniarrow_bounds;
|
||
|
int baseline;
|
||
|
Point *title_pt, *label_pt;
|
||
|
StringPtr title, label;
|
||
|
|
||
|
template_bounds = &template_text_box_bounds[i];
|
||
|
title = titles[i];
|
||
|
label = labels[i];
|
||
|
|
||
|
box = &text_boxes[i];
|
||
|
|
||
|
box->i = i;
|
||
|
box->title = title;
|
||
|
box->label = label;
|
||
|
box->max = maxi[i];
|
||
|
box->value = values[i];
|
||
|
box->continuous_p = (i == hue_index);
|
||
|
|
||
|
/* set up the default integer/factional values based on the
|
||
|
default value */
|
||
|
val_if (*(box->value), box->max, &box->integer, &box->fractional);
|
||
|
|
||
|
frame_bounds = &box->frame_rect;
|
||
|
te_bounds = &box->te_rect;
|
||
|
|
||
|
*frame_bounds = *template_bounds;
|
||
|
OffsetRect (frame_bounds, offset, 0);
|
||
|
|
||
|
*te_bounds = *frame_bounds;
|
||
|
InsetRect (te_bounds, 4, 4);
|
||
|
|
||
|
baseline = ( ( CW (frame_bounds->top)
|
||
|
+ CW (frame_bounds->bottom)) / 2
|
||
|
- font_height / 2 + font_ascent);
|
||
|
|
||
|
title_pt = &box->title_pt;
|
||
|
label_pt = &box->label_pt;
|
||
|
|
||
|
title_pt->v = label_pt->v = baseline;
|
||
|
title_pt->h = CW (template_bounds->left) + offset - StringWidth (title);
|
||
|
label_pt->h = CW (frame_bounds->right) + space_width / 2;
|
||
|
|
||
|
miniarrow_bounds = &box->miniarrow_rect;
|
||
|
|
||
|
*miniarrow_bounds = *frame_bounds;
|
||
|
miniarrow_bounds->left = CW ( label_pt->h
|
||
|
+ label_width
|
||
|
+ space_width / 2);
|
||
|
miniarrow_bounds->right = CW ( label_pt->h
|
||
|
+ label_width
|
||
|
+ space_width / 2
|
||
|
+ 22);
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < 3; i ++)
|
||
|
{
|
||
|
Rect *template_bounds, *bounds;
|
||
|
|
||
|
bounds = &compare_box_bounds[i];
|
||
|
template_bounds = &template_compare_box_bounds[i];
|
||
|
|
||
|
*bounds = *template_bounds;
|
||
|
OffsetRect (bounds, offset, 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
str_if (char *text, int len,
|
||
|
int *return_integer, int *return_fractional)
|
||
|
{
|
||
|
char intbuf[16], fractbuf[16];
|
||
|
int i;
|
||
|
|
||
|
for (i = 0; i < 15 && i < len && isdigit (text[i]); i ++)
|
||
|
intbuf[i] = text[i];
|
||
|
intbuf[i] = '\000';
|
||
|
|
||
|
if (i < 16 && i < len && text[i] == '.' && isdigit (text[i + 1]))
|
||
|
{
|
||
|
fractbuf[0] = text[i + 1];
|
||
|
fractbuf[1] = '\000';
|
||
|
}
|
||
|
else
|
||
|
*fractbuf = '\000';
|
||
|
|
||
|
*return_integer = atoi (intbuf);
|
||
|
*return_fractional = atoi (fractbuf);
|
||
|
}
|
||
|
|
||
|
static char normal_bits[] =
|
||
|
{
|
||
|
image_bits (00000000), image_bits (00000000),
|
||
|
image_bits (00011111), image_bits (11000000),
|
||
|
image_bits (00100000), image_bits (00100000),
|
||
|
image_bits (01000000), image_bits (00010000),
|
||
|
image_bits (01000010), image_bits (00010000),
|
||
|
image_bits (01000111), image_bits (00010000),
|
||
|
image_bits (01001111), image_bits (10010000),
|
||
|
image_bits (01011111), image_bits (11010000),
|
||
|
image_bits (01000111), image_bits (00010000),
|
||
|
image_bits (01000111), image_bits (00010000),
|
||
|
image_bits (01000000), image_bits (00010000),
|
||
|
image_bits (01000000), image_bits (00010000),
|
||
|
image_bits (01000111), image_bits (00010000),
|
||
|
image_bits (01000111), image_bits (00010000),
|
||
|
image_bits (01011111), image_bits (11010000),
|
||
|
image_bits (01001111), image_bits (10010000),
|
||
|
image_bits (01000111), image_bits (00010000),
|
||
|
image_bits (01000010), image_bits (00010000),
|
||
|
image_bits (01000000), image_bits (00010000),
|
||
|
image_bits (00100000), image_bits (00100000),
|
||
|
image_bits (00011111), image_bits (11000000),
|
||
|
image_bits (00000000), image_bits (00000000),
|
||
|
};
|
||
|
|
||
|
static char lower_highlighted_bits[] =
|
||
|
{
|
||
|
image_bits (00000000), image_bits (00000000),
|
||
|
image_bits (00011111), image_bits (11000000),
|
||
|
image_bits (00100000), image_bits (00100000),
|
||
|
image_bits (01000000), image_bits (00010000),
|
||
|
image_bits (01000010), image_bits (00010000),
|
||
|
image_bits (01000111), image_bits (00010000),
|
||
|
image_bits (01001111), image_bits (10010000),
|
||
|
image_bits (01011111), image_bits (11010000),
|
||
|
image_bits (01000111), image_bits (00010000),
|
||
|
image_bits (01000111), image_bits (00010000),
|
||
|
image_bits (01000000), image_bits (00010000),
|
||
|
image_bits (01111111), image_bits (11110000),
|
||
|
image_bits (01111000), image_bits (11110000),
|
||
|
image_bits (01111000), image_bits (11110000),
|
||
|
image_bits (01100000), image_bits (00110000),
|
||
|
image_bits (01110000), image_bits (01110000),
|
||
|
image_bits (01111000), image_bits (11110000),
|
||
|
image_bits (01111101), image_bits (11110000),
|
||
|
image_bits (01111111), image_bits (11110000),
|
||
|
image_bits (00111111), image_bits (11100000),
|
||
|
image_bits (00011111), image_bits (11000000),
|
||
|
image_bits (00000000), image_bits (00000000),
|
||
|
};
|
||
|
|
||
|
static char upper_highlighted_bits[] =
|
||
|
{
|
||
|
image_bits (00000000), image_bits (00000000),
|
||
|
image_bits (00011111), image_bits (11000000),
|
||
|
image_bits (00111111), image_bits (11100000),
|
||
|
image_bits (01111111), image_bits (11110000),
|
||
|
image_bits (01111101), image_bits (11110000),
|
||
|
image_bits (01111000), image_bits (11110000),
|
||
|
image_bits (01110000), image_bits (01110000),
|
||
|
image_bits (01100000), image_bits (00110000),
|
||
|
image_bits (01111000), image_bits (11110000),
|
||
|
image_bits (01111000), image_bits (11110000),
|
||
|
image_bits (01111111), image_bits (11110000),
|
||
|
image_bits (01000000), image_bits (00010000),
|
||
|
image_bits (01000111), image_bits (00010000),
|
||
|
image_bits (01000111), image_bits (00010000),
|
||
|
image_bits (01011111), image_bits (11010000),
|
||
|
image_bits (01001111), image_bits (10010000),
|
||
|
image_bits (01000111), image_bits (00010000),
|
||
|
image_bits (01000010), image_bits (00010000),
|
||
|
image_bits (01000000), image_bits (00010000),
|
||
|
image_bits (00100000), image_bits (00100000),
|
||
|
image_bits (00011111), image_bits (11000000),
|
||
|
image_bits (00000000), image_bits (00000000),
|
||
|
};
|
||
|
|
||
|
static void
|
||
|
text_box_miniarrow_update (struct text_box *box,
|
||
|
miniarrow_hilite_t _hilite)
|
||
|
{
|
||
|
Rect dst_rect, *miniarrow_rect;
|
||
|
BitMap miniarrow_bitmap;
|
||
|
int center_x, center_y;
|
||
|
char *bits = NULL;
|
||
|
|
||
|
switch (_hilite)
|
||
|
{
|
||
|
case miniarrow_no_hilite:
|
||
|
bits = normal_bits;
|
||
|
break;
|
||
|
case miniarrow_up_hilite:
|
||
|
bits = upper_highlighted_bits;
|
||
|
break;
|
||
|
case miniarrow_down_hilite:
|
||
|
bits = lower_highlighted_bits;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
miniarrow_bitmap.baseAddr = RM ((Ptr) bits);
|
||
|
miniarrow_bitmap.rowBytes = CWC (2);
|
||
|
SetRect (&miniarrow_bitmap.bounds, 0, 0, 13, 22);
|
||
|
|
||
|
miniarrow_rect = &box->miniarrow_rect;
|
||
|
|
||
|
center_x = (CW (miniarrow_rect->left) + CW (miniarrow_rect->right)) / 2;
|
||
|
center_y = (CW (miniarrow_rect->top) + CW (miniarrow_rect->bottom)) / 2;
|
||
|
|
||
|
SetRect (&dst_rect,
|
||
|
center_x - 13 / 2, center_y - 22 / 2,
|
||
|
center_x - 13 / 2 + 13, center_y - 22 / 2 + 22);
|
||
|
|
||
|
CopyBits (&miniarrow_bitmap, PORT_BITS_FOR_COPY (thePort),
|
||
|
&miniarrow_bitmap.bounds, &dst_rect, srcCopy, NULL);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
text_box_update (struct text_box *box, boolean_t update_text_p)
|
||
|
{
|
||
|
char buf[16];
|
||
|
|
||
|
MoveTo (box->title_pt.h, box->title_pt.v);
|
||
|
DrawString (box->title);
|
||
|
|
||
|
sprintf (buf, "%d.%d", box->integer, box->fractional);
|
||
|
if (te_box == box)
|
||
|
{
|
||
|
if (update_text_p)
|
||
|
{
|
||
|
Rect dummy_rect;
|
||
|
|
||
|
te_box = NULL;
|
||
|
|
||
|
TEDeactivate (te);
|
||
|
|
||
|
memset (&dummy_rect, '\000', sizeof dummy_rect);
|
||
|
TE_DEST_RECT (te) = dummy_rect;
|
||
|
TE_VIEW_RECT (te) = dummy_rect;
|
||
|
|
||
|
TextBox ((Ptr) buf, strlen (buf), &box->te_rect, teFlushRight);
|
||
|
}
|
||
|
else
|
||
|
TEUpdate (&box->te_rect, te);
|
||
|
}
|
||
|
else
|
||
|
TextBox ((Ptr) buf, strlen (buf), &box->te_rect, teFlushRight);
|
||
|
|
||
|
PenSize (1, 1);
|
||
|
FrameRect (&box->frame_rect);
|
||
|
|
||
|
MoveTo (box->label_pt.h, box->label_pt.v);
|
||
|
DrawString (box->label);
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
if_val (int max, int integer, int fractional)
|
||
|
{
|
||
|
return ((integer * 0xFFFF) + (fractional * 0x1999)) / max;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
val_if (int val, int max,
|
||
|
int *integer_return, int *fractional_return)
|
||
|
{
|
||
|
*integer_return = (val * max) / 0xFFFF;
|
||
|
*fractional_return = (((val * max) - (*integer_return * 0xFFFF)) * 10) / 0xFFFF;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
text_box_update_value_1 (struct text_box *box, int newval,
|
||
|
boolean_t update_if_p,
|
||
|
boolean_t update_color_wheel_target_p)
|
||
|
{
|
||
|
int *value;
|
||
|
|
||
|
value = box->value;
|
||
|
if (*value == newval)
|
||
|
{
|
||
|
/* redisplay even if the values are same, so the display always
|
||
|
appears `cannonical' (even if, say, the user sets the text
|
||
|
box to `' (whic defaults to zero), and `*value' is zero) */
|
||
|
text_box_update (box, TRUE);
|
||
|
return;
|
||
|
}
|
||
|
*value = newval;
|
||
|
|
||
|
if (update_if_p)
|
||
|
{
|
||
|
int integer, fractional;
|
||
|
|
||
|
val_if (newval, box->max, &integer, &fractional);
|
||
|
text_box_update_if_value_1 (box, integer, fractional);
|
||
|
}
|
||
|
|
||
|
switch (box->i)
|
||
|
{
|
||
|
case red_index:
|
||
|
current_color.red = CW (red);
|
||
|
break;
|
||
|
case green_index:
|
||
|
current_color.green = CW (green);
|
||
|
break;
|
||
|
case blue_index:
|
||
|
current_color.blue = CW (blue);
|
||
|
break;
|
||
|
case hue_index:
|
||
|
case saturation_index:
|
||
|
if (update_color_wheel_target_p)
|
||
|
color_wheel_target_update (TRUE);
|
||
|
case lightness_index:
|
||
|
color_wheel_notice_lightness_change ();
|
||
|
}
|
||
|
|
||
|
/* redraw the box with the `cannonicalized' value */
|
||
|
text_box_update (box, TRUE);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
compare_box_update (void)
|
||
|
{
|
||
|
/* ### titles? */
|
||
|
/* draw the color comparison box */
|
||
|
|
||
|
RGBForeColor (&orig_color);
|
||
|
FillRect (orig_compare_box_bounds, black);
|
||
|
|
||
|
RGBForeColor (¤t_color);
|
||
|
FillRect (current_compare_box_bounds, black);
|
||
|
|
||
|
PenSize (2, 2);
|
||
|
ForeColor (blackColor);
|
||
|
FrameRect (compare_box_frame_bounds);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
hue_saturation_update (int new_hue, int new_saturation,
|
||
|
boolean_t full_update_p)
|
||
|
{
|
||
|
RGBColor rgb_color;
|
||
|
HSLColor hsl_color;
|
||
|
|
||
|
if (hue == new_hue && saturation == new_saturation)
|
||
|
return;
|
||
|
|
||
|
text_box_update_value_1 (&text_boxes[hue_index], new_hue,
|
||
|
TRUE, FALSE);
|
||
|
text_box_update_value_1 (&text_boxes[saturation_index], new_saturation,
|
||
|
TRUE, FALSE);
|
||
|
|
||
|
if (full_update_p)
|
||
|
{
|
||
|
hsl_color.hue = CW (hue);
|
||
|
hsl_color.saturation = CW (saturation);
|
||
|
hsl_color.lightness = CW (lightness);
|
||
|
|
||
|
HSL2RGB (&hsl_color, &rgb_color);
|
||
|
|
||
|
text_box_update_value_1 (&text_boxes[red_index],
|
||
|
CW (rgb_color.red), TRUE, TRUE);
|
||
|
text_box_update_value_1 (&text_boxes[green_index],
|
||
|
CW (rgb_color.green), TRUE, TRUE);
|
||
|
text_box_update_value_1 (&text_boxes[blue_index],
|
||
|
CW (rgb_color.blue), TRUE, TRUE);
|
||
|
|
||
|
compare_box_update ();
|
||
|
}
|
||
|
color_wheel_target_update (TRUE);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
text_box_update_if_value_1 (struct text_box *box,
|
||
|
int new_integer, int new_fractional)
|
||
|
{
|
||
|
box->integer = new_integer;
|
||
|
box->fractional = new_fractional;
|
||
|
|
||
|
text_box_update (box, TRUE);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
text_box_update_if_value (struct text_box *box,
|
||
|
int new_integer, int new_fractional)
|
||
|
{
|
||
|
if (box->integer == new_integer
|
||
|
&& box->fractional == new_fractional)
|
||
|
{
|
||
|
/* to keep the box `cannonical' */
|
||
|
text_box_update (box, TRUE);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
text_box_update_if_value_1 (box, new_integer, new_fractional);
|
||
|
text_box_update_value (box, if_val (box->max, new_integer, new_fractional),
|
||
|
FALSE);
|
||
|
}
|
||
|
|
||
|
/* the value of `box' has changed, and we need to recompute the
|
||
|
values for the `dual' color because of it */
|
||
|
|
||
|
static void
|
||
|
text_box_update_value (struct text_box *box, int newval,
|
||
|
boolean_t update_if_p)
|
||
|
{
|
||
|
RGBColor rgb_color;
|
||
|
HSLColor hsl_color;
|
||
|
|
||
|
switch (box->i)
|
||
|
{
|
||
|
case red_index:
|
||
|
case green_index:
|
||
|
case blue_index:
|
||
|
{
|
||
|
text_box_update_value_1 (box, newval, update_if_p, TRUE);
|
||
|
|
||
|
rgb_color.red = CW (red);
|
||
|
rgb_color.green = CW (green);
|
||
|
rgb_color.blue = CW (blue);
|
||
|
|
||
|
RGB2HSL (&rgb_color, &hsl_color);
|
||
|
|
||
|
hue_saturation_update (CW (hsl_color.hue), CW (hsl_color.saturation),
|
||
|
FALSE);
|
||
|
|
||
|
text_box_update_value_1 (&text_boxes[lightness_index],
|
||
|
CW (hsl_color.lightness), TRUE, TRUE);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case hue_index:
|
||
|
case saturation_index:
|
||
|
case lightness_index:
|
||
|
{
|
||
|
text_box_update_value_1 (box, newval, update_if_p, TRUE);
|
||
|
|
||
|
hsl_color.hue = CW (hue);
|
||
|
hsl_color.saturation = CW (saturation);
|
||
|
hsl_color.lightness = CW (lightness);
|
||
|
|
||
|
HSL2RGB (&hsl_color, &rgb_color);
|
||
|
|
||
|
text_box_update_value_1 (&text_boxes[red_index],
|
||
|
CW (rgb_color.red), TRUE, TRUE);
|
||
|
text_box_update_value_1 (&text_boxes[green_index],
|
||
|
CW (rgb_color.green), TRUE, TRUE);
|
||
|
text_box_update_value_1 (&text_boxes[blue_index],
|
||
|
CW (rgb_color.blue), TRUE, TRUE);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
compare_box_update ();
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
text_box_set_te (struct text_box *box)
|
||
|
{
|
||
|
struct text_box *orig_te_box;
|
||
|
char buf[16], *text;
|
||
|
Handle texth;
|
||
|
|
||
|
if (box == te_box)
|
||
|
return;
|
||
|
|
||
|
orig_te_box = te_box;
|
||
|
te_box = box;
|
||
|
|
||
|
TEDeactivate (te);
|
||
|
|
||
|
if (orig_te_box)
|
||
|
{
|
||
|
int integer, fractional;
|
||
|
int max;
|
||
|
|
||
|
texth = TE_HTEXT (te);
|
||
|
text = (char *) STARH (texth);
|
||
|
|
||
|
str_if (text, TE_LENGTH (te), &integer, &fractional);
|
||
|
max = orig_te_box->max;
|
||
|
if (integer > max
|
||
|
|| (integer == max && fractional))
|
||
|
{
|
||
|
integer = max;
|
||
|
fractional = 0;
|
||
|
}
|
||
|
text_box_update_if_value (orig_te_box, integer, fractional);
|
||
|
}
|
||
|
|
||
|
/* slimy */
|
||
|
TE_DEST_RECT (te) = box->te_rect;
|
||
|
TE_VIEW_RECT (te) = box->te_rect;
|
||
|
|
||
|
sprintf (buf, "%d.%d", box->integer, box->fractional);
|
||
|
TESetText ((Ptr) buf, strlen (buf), te);
|
||
|
TESetSelect (0, TE_LENGTH (te), te);
|
||
|
|
||
|
TEActivate (te);
|
||
|
}
|
||
|
|
||
|
static boolean_t
|
||
|
event_loop (void)
|
||
|
{
|
||
|
EventRecord evt;
|
||
|
|
||
|
for (;;)
|
||
|
{
|
||
|
GetNextEvent (( mDownMask | mUpMask
|
||
|
| keyDownMask | keyUpMask | autoKeyMask
|
||
|
| updateMask | activMask), &evt);
|
||
|
|
||
|
TEIdle (te);
|
||
|
|
||
|
switch (CW (evt.what))
|
||
|
{
|
||
|
case mouseDown:
|
||
|
{
|
||
|
Point local_pt;
|
||
|
boolean_t control_p;
|
||
|
ControlHandle c;
|
||
|
int16 release_part;
|
||
|
int i;
|
||
|
|
||
|
/* ### beep if the mousedown is not in
|
||
|
`color_picker_window' */
|
||
|
|
||
|
local_pt = evt.where;
|
||
|
GlobalToLocal (&local_pt);
|
||
|
local_pt = SWAP_POINT (local_pt);
|
||
|
|
||
|
control_p = _FindControl (local_pt, color_picker_window, &c);
|
||
|
if (control_p)
|
||
|
{
|
||
|
release_part = TrackControl (c, local_pt, (ProcPtr) -1);
|
||
|
if (release_part == inButton && c == ok_button)
|
||
|
return TRUE;
|
||
|
if (release_part == inButton && c == cancel_button)
|
||
|
return FALSE;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < N_TEXT_BOXES; i ++)
|
||
|
{
|
||
|
struct text_box *box;
|
||
|
|
||
|
box = &text_boxes[i];
|
||
|
if (PtInRect (local_pt, &box->te_rect))
|
||
|
{
|
||
|
text_box_set_te (box);
|
||
|
TEClick (local_pt, ((evt.modifiers & CWC (shiftKey))
|
||
|
? TRUE
|
||
|
: FALSE),
|
||
|
te);
|
||
|
break;
|
||
|
}
|
||
|
else if (PtInRect (local_pt, &box->miniarrow_rect))
|
||
|
{
|
||
|
int center_y;
|
||
|
|
||
|
center_y = ( CW (box->miniarrow_rect.top)
|
||
|
+ CW (box->miniarrow_rect.bottom)) / 2;
|
||
|
|
||
|
integer_increment_p = FALSE;
|
||
|
track_kount = 0;
|
||
|
|
||
|
goto handle_pt_1;
|
||
|
|
||
|
while (! GetOSEvent (mUpMask, &evt))
|
||
|
{
|
||
|
miniarrow_hilite_t _hilite;
|
||
|
|
||
|
local_pt = evt.where;
|
||
|
GlobalToLocal (&local_pt);
|
||
|
local_pt = SWAP_POINT (local_pt);
|
||
|
|
||
|
handle_pt_1:
|
||
|
if (PtInRect (local_pt, &box->miniarrow_rect))
|
||
|
{
|
||
|
if (local_pt.v < center_y)
|
||
|
_hilite = miniarrow_up_hilite;
|
||
|
else
|
||
|
_hilite = miniarrow_down_hilite;
|
||
|
}
|
||
|
else
|
||
|
_hilite = miniarrow_no_hilite;
|
||
|
|
||
|
text_box_miniarrow_update (box, _hilite);
|
||
|
miniarrow_track (box, _hilite);
|
||
|
}
|
||
|
text_box_miniarrow_update (box, miniarrow_no_hilite);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (PtInRect (local_pt, color_wheel_bounds))
|
||
|
{
|
||
|
goto handle_pt_2;
|
||
|
|
||
|
while (! GetOSEvent (mUpMask, &evt))
|
||
|
{
|
||
|
int x, y;
|
||
|
double saturation_fp;
|
||
|
|
||
|
local_pt = evt.where;
|
||
|
GlobalToLocal (&local_pt);
|
||
|
local_pt = SWAP_POINT (local_pt);
|
||
|
|
||
|
handle_pt_2:
|
||
|
x = local_pt.h - color_wheel_center_x;
|
||
|
y = local_pt.v - color_wheel_center_y;
|
||
|
|
||
|
saturation_fp = sqrt (sqr (x) + sqr (y));
|
||
|
if (saturation_fp < (192 / 2))
|
||
|
{
|
||
|
int hue, saturation;
|
||
|
|
||
|
hue = (atan2 (y, -x) + M_PI) / M_PI / 2 * 0xFFFF;
|
||
|
saturation = saturation_fp / (192 / 2) * 0xFFFF;
|
||
|
|
||
|
hue_saturation_update (hue, saturation, TRUE);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case mouseUp:
|
||
|
break;
|
||
|
|
||
|
case updateEvt:
|
||
|
{
|
||
|
BeginUpdate (color_picker_window);
|
||
|
|
||
|
DrawControls (color_picker_window);
|
||
|
|
||
|
{
|
||
|
/* draw bold border around the default button */
|
||
|
Rect r = *ok_button_bounds;
|
||
|
int oval;
|
||
|
|
||
|
InsetRect (&r, -4, -4);
|
||
|
PenSize (3, 3);
|
||
|
oval = RECT_HEIGHT (&r) / 2 - 4;
|
||
|
/* ### frame in the frame color for the `ok_button'
|
||
|
control */
|
||
|
if (!(ROMlib_options & ROMLIB_RECT_SCREEN_BIT))
|
||
|
FrameRoundRect (&r, oval, oval);
|
||
|
else
|
||
|
FrameRect (&r);
|
||
|
}
|
||
|
|
||
|
/* update the text boxes */
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
for (i = 0; i < N_TEXT_BOXES; i ++)
|
||
|
{
|
||
|
struct text_box *box;
|
||
|
|
||
|
box = &text_boxes[i];
|
||
|
text_box_update (box, FALSE);
|
||
|
|
||
|
text_box_miniarrow_update (box, miniarrow_no_hilite);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* draw the compare box */
|
||
|
compare_box_update ();
|
||
|
|
||
|
/* draw the prompt */
|
||
|
TextBox ((Ptr) &prompt_text[1], *prompt_text,
|
||
|
prompt_bounds, teFlushLeft);
|
||
|
|
||
|
color_wheel_update ();
|
||
|
|
||
|
/* compare box labels */
|
||
|
#define orig_compare_box_label ((StringPtr) "\012Original: ")
|
||
|
#define current_compare_box_label ((StringPtr) "\005New: ")
|
||
|
|
||
|
|
||
|
MoveTo (( CW (orig_compare_box_bounds->left)
|
||
|
- StringWidth (orig_compare_box_label)),
|
||
|
( ( CW (orig_compare_box_bounds->top)
|
||
|
+ CW (orig_compare_box_bounds->bottom)) / 2
|
||
|
- font_height / 2 + font_ascent));
|
||
|
DrawString (orig_compare_box_label);
|
||
|
|
||
|
MoveTo (( CW (current_compare_box_bounds->left)
|
||
|
- StringWidth (current_compare_box_label)),
|
||
|
( ( CW (current_compare_box_bounds->top)
|
||
|
+ CW (current_compare_box_bounds->bottom)) / 2
|
||
|
- font_height / 2 + font_ascent));
|
||
|
DrawString (current_compare_box_label);
|
||
|
|
||
|
EndUpdate (color_picker_window);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case keyDown:
|
||
|
case autoKey:
|
||
|
{
|
||
|
char ch;
|
||
|
|
||
|
ch = CL (evt.message) & 0xFF;
|
||
|
switch (ch)
|
||
|
{
|
||
|
case '\r':
|
||
|
case NUMPAD_ENTER:
|
||
|
return TRUE;
|
||
|
/* ESC */
|
||
|
case '\033':
|
||
|
return FALSE;
|
||
|
default:
|
||
|
if (te_box)
|
||
|
{
|
||
|
if (ch == '\t')
|
||
|
text_box_set_te (&text_boxes[((te_box->i + 5)
|
||
|
% N_TEXT_BOXES)]);
|
||
|
else
|
||
|
TEKey (ch, te);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case activateEvt:
|
||
|
case keyUp:
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
warning_unexpected ("unknown event.what `%d'",
|
||
|
CW (evt.what));
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static PixMap color_wheel_pixmap;
|
||
|
|
||
|
static CTabHandle color_wheel_color_table;
|
||
|
static ColorSpec *color_wheel_colors;
|
||
|
|
||
|
static int current_target_x, current_target_y;
|
||
|
|
||
|
static StringPtr label_0_degs = (StringPtr) "\0020\241";
|
||
|
static StringPtr label_90_degs = (StringPtr) "\00390\241";
|
||
|
static StringPtr label_180_degs = (StringPtr) "\004180\241";
|
||
|
static StringPtr label_270_degs = (StringPtr) "\004270\241";
|
||
|
|
||
|
static void
|
||
|
color_wheel_init (void)
|
||
|
{
|
||
|
int bpp;
|
||
|
|
||
|
*color_wheel_bounds = *template_color_wheel_bounds;
|
||
|
OffsetRect (color_wheel_bounds, - StringWidth (label_0_degs), font_height);
|
||
|
|
||
|
color_wheel_center_y = ( CW (color_wheel_bounds->top)
|
||
|
+ CW (color_wheel_bounds->bottom)) / 2;
|
||
|
color_wheel_center_x = ( CW (color_wheel_bounds->left)
|
||
|
+ CW (color_wheel_bounds->right)) / 2;
|
||
|
|
||
|
/* the colorwheel appears to be 192 pixels on a side, but it is
|
||
|
really 208 pixels to handle target overlap */
|
||
|
InsetRect (color_wheel_bounds, -8, -8);
|
||
|
|
||
|
bpp = PIXMAP_PIXEL_SIZE (GD_PMAP (MR (MainDevice)));
|
||
|
color_wheel_pixmap.baseAddr = RM ((bpp == 8)
|
||
|
? (Ptr) color_wheel_bits_8
|
||
|
: (bpp == 4
|
||
|
? (Ptr) color_wheel_bits_4
|
||
|
: (gui_abort (), NULL)));
|
||
|
color_wheel_pixmap.rowBytes = CW ((bpp == 8)
|
||
|
? 0x80D0
|
||
|
: (bpp == 4
|
||
|
? 0x8068
|
||
|
: (gui_abort (), -1)));
|
||
|
SetRect (&color_wheel_pixmap.bounds, 0, 0, 208, 208);
|
||
|
pixmap_set_pixel_fields (&color_wheel_pixmap, bpp);
|
||
|
color_wheel_pixmap.pmTable = RM (no_stdbits_color_conversion_color_table);
|
||
|
|
||
|
current_target_x = color_wheel_center_x;
|
||
|
current_target_y = color_wheel_center_y;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
color_wheel_target_update (boolean_t short_cut_p)
|
||
|
{
|
||
|
double dist, angle;
|
||
|
Rect src_rect, dst_rect;
|
||
|
|
||
|
int x, y;
|
||
|
|
||
|
/* draw the target at point corresponding to the current
|
||
|
hue/saturation */
|
||
|
|
||
|
angle = (double) hue / 0xFFFF * 2 * M_PI;
|
||
|
dist = (double) saturation / 0xFFFF * 96.0;
|
||
|
|
||
|
x = color_wheel_center_x + dist * cos (angle);
|
||
|
y = color_wheel_center_y - dist * sin (angle);
|
||
|
|
||
|
if (short_cut_p
|
||
|
&& x == current_target_x
|
||
|
&& y == current_target_y)
|
||
|
return;
|
||
|
|
||
|
/* erase the current target */
|
||
|
dst_rect.top = CW (current_target_y - 7);
|
||
|
dst_rect.left = CW (current_target_x - 7);
|
||
|
dst_rect.bottom = CW (current_target_y + 9);
|
||
|
dst_rect.right = CW (current_target_x + 9);
|
||
|
|
||
|
src_rect = dst_rect;
|
||
|
OffsetRect (&src_rect, - CW (color_wheel_bounds->left),
|
||
|
- CW (color_wheel_bounds->top));
|
||
|
|
||
|
CopyBits ((BitMap *) &color_wheel_pixmap, PORT_BITS_FOR_COPY (thePort),
|
||
|
&src_rect, &dst_rect, srcCopy, NULL);
|
||
|
|
||
|
PenSize (1, 1);
|
||
|
|
||
|
ForeColor (whiteColor);
|
||
|
MoveTo (x - 7, y); Line (6, 0);
|
||
|
MoveTo (x + 1, y); Line (6, 0);
|
||
|
MoveTo (x, y - 7); Line (0, 6);
|
||
|
MoveTo (x, y + 1); Line (0, 6);
|
||
|
|
||
|
ForeColor (blackColor);
|
||
|
MoveTo (x - 6, y + 1); Line (6, 0);
|
||
|
MoveTo (x + 2, y + 1); Line (6, 0);
|
||
|
MoveTo (x + 1, y - 6); Line (0, 6);
|
||
|
MoveTo (x + 1, y + 2); Line (0, 6);
|
||
|
|
||
|
current_target_x = x;
|
||
|
current_target_y = y;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
color_wheel_update (void)
|
||
|
{
|
||
|
CopyBits ((BitMap *) &color_wheel_pixmap, PORT_BITS_FOR_COPY (thePort),
|
||
|
&color_wheel_pixmap.bounds, color_wheel_bounds, srcCopy, NULL);
|
||
|
|
||
|
MoveTo (470 - StringWidth (label_0_degs),
|
||
|
color_wheel_center_y - font_height / 2 + font_ascent);
|
||
|
DrawString (label_0_degs);
|
||
|
|
||
|
MoveTo (color_wheel_center_x - StringWidth (label_90_degs) / 2,
|
||
|
10 + font_ascent);
|
||
|
DrawString (label_90_degs);
|
||
|
|
||
|
MoveTo ( 470 - StringWidth (label_0_degs) - 10
|
||
|
- 192
|
||
|
- 10 - StringWidth (label_180_degs),
|
||
|
color_wheel_center_y - font_height / 2 + font_ascent);
|
||
|
DrawString (label_180_degs);
|
||
|
|
||
|
MoveTo (color_wheel_center_x - StringWidth (label_270_degs) / 2,
|
||
|
10 + font_height + 10 + 192 + 10 + font_ascent);
|
||
|
DrawString (label_270_degs);
|
||
|
|
||
|
color_wheel_target_update (FALSE);
|
||
|
}
|
||
|
|
||
|
static int color_wheel_noticed_lightness;
|
||
|
|
||
|
static void
|
||
|
color_wheel_notice_lightness_change (void)
|
||
|
{
|
||
|
struct { double angle; double dist; } color_desc[13] =
|
||
|
{
|
||
|
{ 0.0, 0.9375 },
|
||
|
{ 60.0, 0.9375 },
|
||
|
{ 120.0, 0.9375 },
|
||
|
{ 180.0, 0.9375 },
|
||
|
{ 240.0, 0.9375 },
|
||
|
{ 300.0, 0.9375 },
|
||
|
|
||
|
{ 30.0, 0.625, },
|
||
|
{ 90.0, 0.625, },
|
||
|
{ 150.0, 0.625, },
|
||
|
{ 210.0, 0.625, },
|
||
|
{ 270.0, 0.625, },
|
||
|
{ 330.0, 0.625, },
|
||
|
|
||
|
{ 0.0, 0.0 }
|
||
|
};
|
||
|
HSLColor hsl_color;
|
||
|
RGBColor rgb_color;
|
||
|
int i;
|
||
|
|
||
|
if (color_wheel_noticed_lightness == lightness)
|
||
|
return;
|
||
|
|
||
|
color_wheel_noticed_lightness = lightness;
|
||
|
|
||
|
for (i = 0; i < (int) NELEM (color_desc); i ++)
|
||
|
{
|
||
|
/* one half */
|
||
|
hsl_color.lightness = CW (lightness);
|
||
|
hsl_color.hue = CW ( color_desc[i].angle
|
||
|
* 0xFFFF
|
||
|
/ 360.0);
|
||
|
hsl_color.saturation = CW ( color_desc[i].dist
|
||
|
* 0xFFFF);
|
||
|
|
||
|
HSL2RGB (&hsl_color, &rgb_color);
|
||
|
|
||
|
color_wheel_colors[i].rgb = rgb_color;
|
||
|
}
|
||
|
AnimatePalette (color_picker_window, color_wheel_color_table,
|
||
|
0, 1, 13);
|
||
|
}
|
||
|
|
||
|
/* color picker entry point */
|
||
|
|
||
|
P4 (PUBLIC pascal trap, BOOLEAN, GetColor,
|
||
|
Point, where,
|
||
|
Str255, prompt,
|
||
|
RGBColor *, in_color,
|
||
|
RGBColor *, out_color)
|
||
|
{
|
||
|
PaletteHandle palette;
|
||
|
boolean_t retval;
|
||
|
|
||
|
/* compute relevent font information */
|
||
|
|
||
|
{
|
||
|
FontInfo font_info;
|
||
|
|
||
|
GetFontInfo (&font_info);
|
||
|
|
||
|
font_height = ( CW (font_info.ascent)
|
||
|
+ CW (font_info.descent)
|
||
|
+ CW (font_info.leading));
|
||
|
font_ascent = CW (font_info.ascent);
|
||
|
|
||
|
space_width = CharWidth (' ');
|
||
|
}
|
||
|
|
||
|
{
|
||
|
HSLColor *hsl_color = alloca (sizeof *hsl_color);
|
||
|
|
||
|
red = CW (in_color->red);
|
||
|
green = CW (in_color->green);
|
||
|
blue = CW (in_color->blue);
|
||
|
|
||
|
RGB2HSL (in_color, hsl_color);
|
||
|
|
||
|
hue = CW (hsl_color->hue);
|
||
|
saturation = CW (hsl_color->saturation);
|
||
|
lightness = CW (hsl_color->lightness);
|
||
|
|
||
|
color_wheel_noticed_lightness = -1;
|
||
|
|
||
|
orig_color = *in_color;
|
||
|
current_color = *in_color;
|
||
|
}
|
||
|
|
||
|
prompt_text = prompt;
|
||
|
|
||
|
compute_bounds (where);
|
||
|
color_wheel_init ();
|
||
|
|
||
|
color_picker_window = _NewCWindow (NULL, color_picker_window_bounds,
|
||
|
/* no title */
|
||
|
NULL,
|
||
|
/* visible */
|
||
|
TRUE,
|
||
|
dBoxProc,
|
||
|
(WindowPtr) -1,
|
||
|
FALSE, /* dummy */ -1);
|
||
|
|
||
|
/* #### the correct thing to do is have a 24bpp color wheel, and
|
||
|
draw it to the screen dithered, with a reasonable colormap
|
||
|
guaranteed by a reasonable palette.
|
||
|
|
||
|
instead, we are going to use an animated palette and a constant
|
||
|
dither pattern, which won't work on non-clut devices (palette
|
||
|
manager will probably just eat flaming death)
|
||
|
|
||
|
it also won't work very well on 16bpp devices (which the mac does
|
||
|
reasonably well)
|
||
|
|
||
|
of course, even the mac doesn't try it on 4bpp or b/w devices */
|
||
|
|
||
|
palette = NewPalette (16, NULL, pmAnimated | pmExplicit, -1);
|
||
|
NSetPalette (color_picker_window, palette, pmAllUpdates);
|
||
|
|
||
|
SetEntryUsage (palette, 0, pmCourteous, -1);
|
||
|
SetEntryColor (palette, 0, &ROMlib_white_rgb_color);
|
||
|
SetEntryUsage (palette, 15, pmCourteous, -1);
|
||
|
SetEntryColor (palette, 15, &ROMlib_black_rgb_color);
|
||
|
|
||
|
/* sometimes the animated palette entries suck up the hilite color */
|
||
|
SetEntryUsage (palette, 14, pmTolerant, 1);
|
||
|
SetEntryColor (palette, 14, &HiliteRGB);
|
||
|
|
||
|
/* #### add palette entries for the {current, orig}_colors? */
|
||
|
|
||
|
color_wheel_color_table = (CTabHandle) NewHandle (CTAB_STORAGE_FOR_SIZE (23));
|
||
|
LOCK_HANDLE_EXCURSION_1
|
||
|
(color_wheel_color_table,
|
||
|
{
|
||
|
CTAB_SIZE_X (color_wheel_color_table) = CW (23);
|
||
|
color_wheel_colors = CTAB_TABLE (color_wheel_color_table);
|
||
|
|
||
|
color_wheel_notice_lightness_change ();
|
||
|
|
||
|
ActivatePalette (color_picker_window);
|
||
|
|
||
|
THEPORT_SAVE_EXCURSION
|
||
|
(color_picker_window,
|
||
|
{
|
||
|
Rect *dummy_rect = alloca (sizeof *dummy_rect);
|
||
|
memset (dummy_rect, '\000', sizeof *dummy_rect);
|
||
|
|
||
|
ok_button = NewControl (color_picker_window,
|
||
|
ok_button_bounds, (StringPtr) "\002OK",
|
||
|
/* visible */
|
||
|
TRUE,
|
||
|
0, 0, 1, pushButProc, -1);
|
||
|
cancel_button = NewControl (color_picker_window,
|
||
|
cancel_button_bounds,
|
||
|
(StringPtr) "\006Cancel",
|
||
|
/* visible */
|
||
|
TRUE,
|
||
|
0, 0, 1, pushButProc, -1);
|
||
|
|
||
|
te = TENew (dummy_rect, dummy_rect);
|
||
|
TESetJust (teFlushRight, te);
|
||
|
text_box_init ();
|
||
|
|
||
|
/* event loop exits when one of `Cancel' (returning zero) or
|
||
|
`OK' (returning one) are clicked */
|
||
|
retval = event_loop ();
|
||
|
|
||
|
TEDispose (te);
|
||
|
te_box = NULL;
|
||
|
});
|
||
|
});
|
||
|
|
||
|
DisposHandle ((Handle) color_wheel_color_table);
|
||
|
|
||
|
DisposePalette (palette);
|
||
|
|
||
|
DisposeWindow (color_picker_window);
|
||
|
|
||
|
*out_color = retval ? current_color : orig_color;
|
||
|
return retval;
|
||
|
}
|