348 lines
8.2 KiB
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;
|
|
}
|