executor/src/system_error.c

348 lines
8.2 KiB
C

/* Copyright 1995 by Abacus Research and
* Development, Inc. All rights reserved.
*/
#if !defined (OMIT_RCSID_STRINGS)
char ROMlib_rcsid_system_error[] =
"$Id: system_error.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/system_error.h"
#include "rsys/redrawscreen.h"
#include "rsys/cquick.h"
#include "rsys/osevent.h"
#include "rsys/options.h"
#define N_BUTTONS (3)
/* 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; \
})
struct button
{
ControlHandle ctl;
const char *text;
system_error_callback_t func;
boolean_t hilite_p;
Rect hilite_rect;
int oval;
int index;
};
static struct button buttons[3];
static WindowPtr msg_window;
static const char *message;
static int default_button;
static Rect message_rect;
static struct button *
event_loop (void)
{
EventRecord evt;
Point where;
for (;;)
{
GetNextEvent (( mDownMask | updateMask
| keyDownMask | autoKeyMask), &evt);
where = SWAP_POINT (evt.where);
switch (CW (evt.what))
{
case mouseDown:
{
Point local_pt;
boolean_t control_p;
ControlHandle c;
local_pt = evt.where;
GlobalToLocal (&local_pt);
local_pt = SWAP_POINT (local_pt);
control_p = _FindControl (local_pt, msg_window, &c);
if (control_p)
{
int release_part;
release_part = TrackControl (c, local_pt, (ProcPtr) -1);
if (release_part == inButton)
{
int i;
for (i = 0; i < N_BUTTONS; i ++)
if (c == buttons[i].ctl)
return &buttons[i];
}
}
}
case updateEvt:
{
int i;
BeginUpdate (msg_window);
DrawControls (msg_window);
PenSize (3, 3);
for (i = 0; i < N_BUTTONS; i ++)
if (buttons[i].hilite_p)
{
if (!(ROMlib_options & ROMLIB_RECT_SCREEN_BIT))
FrameRoundRect (&buttons[i].hilite_rect,
buttons[i].oval,
buttons[i].oval);
else
FrameRect (&buttons[i].hilite_rect);
}
/* ### `TextBox ()' should be const */
TextBox ((Ptr) message, strlen (message), &message_rect,
teFlushLeft);
EndUpdate (msg_window);
break;
}
case keyDown:
case autoKey:
{
char ch;
ch = CL (evt.message) & 0xFF;
if (ch == '\r' || ch == NUMPAD_ENTER)
{
int i;
for (i = 0; i < N_BUTTONS; i ++)
if (buttons[i].hilite_p)
return &buttons[i];
}
break;
}
}
}
}
static int
int_sqrt (int x)
{
int i;
gui_assert (x >= 0);
for (i = 0; i * i <= x; i++)
;
return i - 1;
}
int
system_error (const char *_message, int _default_button,
const char *button0, const char *button1, const char *button2,
system_error_callback_t func0,
system_error_callback_t func1,
system_error_callback_t func2)
{
static Rect dummy_rect;
struct button *retval;
message = _message;
default_button = _default_button;
buttons[0].text = button0;
buttons[0].func = func0;
buttons[0].index = 0;
buttons[1].text = button1;
buttons[1].func = func1;
buttons[1].index = 1;
buttons[2].text = button2;
buttons[2].func = func2;
buttons[2].index = 2;
#if 1
/* NOTE: when system_error() is called from InitWindows() the colors are
messed up. I don't know what the proper solution is, but this works
for now. */
redraw_screen ();
/* NOTE: initializing the cursor here is real rude, and makes it so that
we really can't call system_error at random times (but then again, we
never really could). But since system_error is primarily used to
print messages from InitWindows(), it's important that we somehow
manage to get the cursor visible, since people are given the option of
exiting but with no way to click on the button. */
InitCursor ();
#endif
/* allocate the message window with a bogus size; the text settings
for this window will determine it's eventual size, at which point
it will be resized and made visible */
msg_window = _NewCWindow (NULL, &dummy_rect,
/* no title */
NULL,
/* invisible */
FALSE,
dBoxProc,
(WindowPtr) -1,
FALSE, /* dummy */ -1);
THEPORT_SAVE_EXCURSION
(msg_window,
{
FontInfo font_info;
int total_message_width;
int text_height;
int line_count;
int message_width;
int message_height;
int button_span;
int width;
int height;
int max_button_width;
int i;
/* compute the geometry of the various dialog components so we
can determine the dialog's size */
total_message_width = TextWidth ((Ptr) &message[0],
0, strlen (message));
GetFontInfo (&font_info);
text_height = ( CW (font_info.ascent)
+ CW (font_info.descent)
+ CW (font_info.leading));
line_count
/* must be at least one line of text, otherwise we'll get hit
with a div by zero below */
= MAX (int_sqrt (total_message_width / (4 * text_height)), 1);
max_button_width = -1;
for (i = 0; i < N_BUTTONS; i ++)
if (buttons[i].text != NULL)
max_button_width = MAX (max_button_width,
/* ### `TextWidth ()' should be const */
TextWidth ((Ptr) buttons[i].text, 0,
strlen (buttons[i].text)));
/* padding for button outline, etc */
max_button_width += 16;
message_width = total_message_width / line_count;
message_height = (line_count + 2) * text_height;
button_span = (max_button_width + 13) * N_BUTTONS - 13;
if (message_width < button_span)
message_width = button_span;
width = message_width + 20;
height = message_height + 20 + 20 + 13;
SizeWindow (msg_window, width, height, FALSE);
/* compute top/left based on screen dimensions */
{
Rect *gd_rect;
int gd_width;
int gd_height;
int top;
int left;
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;
MoveWindow (msg_window, left, top, TRUE);
}
ShowWindow (msg_window);
message_rect.top = CWC (10);
message_rect.left = CWC (10);
message_rect.bottom = CW (message_height + 10);
message_rect.right = CW (message_width + 10);
for (i = 0; i < N_BUTTONS; i ++)
if (buttons[i].text != NULL)
{
Rect ctl_rect;
unsigned char buf[256];
ctl_rect.top = CW (height - 10 - 20);
ctl_rect.bottom = CW (height - 10);
ctl_rect.right = CW ( width - 10 - i * (max_button_width + 13));
ctl_rect.left = CW ( width - 10 - i * (max_button_width + 13)
- max_button_width);
*buf = (unsigned char) strlen (buttons[i].text);
strcpy ((char *) &buf[1], buttons[i].text);
buttons[i].ctl = NewControl (msg_window, &ctl_rect,
/* ### `NewControl ()'
should be const */
buf,
/* visible */
TRUE,
0, 0, 1, pushButProc,
/* dummy */ -1);
if (i == default_button)
{
buttons[i].hilite_rect = ctl_rect;
InsetRect (&buttons[i].hilite_rect, -4, -4);
buttons[i].oval
= RECT_HEIGHT (&buttons[i].hilite_rect) / 2 - 4;
buttons[i].hilite_p = TRUE;
}
else
buttons[i].hilite_p = FALSE;
}
retval = event_loop ();
});
DisposeWindow (msg_window);
if (retval->func)
(*retval->func) ();
return retval->index;
}