2021-11-23 18:50:09 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2021-11-26 21:30:41 +00:00
|
|
|
#include <stdarg.h>
|
2021-11-23 18:50:09 +00:00
|
|
|
#include <string.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <SIOUX.h>
|
|
|
|
|
2021-12-01 19:23:36 +00:00
|
|
|
#include <Menus.h>
|
2021-11-23 18:50:09 +00:00
|
|
|
#include <Windows.h>
|
|
|
|
#include <Quickdraw.h>
|
|
|
|
|
2021-12-01 19:23:36 +00:00
|
|
|
#include "TrapAvail.h"
|
2021-11-26 21:30:41 +00:00
|
|
|
#include "pstring.h"
|
|
|
|
#include "LaunchLib.h"
|
2021-11-25 23:54:59 +00:00
|
|
|
#include "mac_vol.h"
|
2021-11-29 18:53:38 +00:00
|
|
|
#include "text_box.h"
|
2021-11-23 18:50:09 +00:00
|
|
|
#include "tip.h"
|
2021-12-01 04:02:28 +00:00
|
|
|
#include "command_line.h"
|
2021-11-23 18:50:09 +00:00
|
|
|
|
2021-11-29 18:53:38 +00:00
|
|
|
enum TipPage {
|
|
|
|
kTestingPage,
|
|
|
|
kExplainPage,
|
|
|
|
} page;
|
2021-11-23 18:50:09 +00:00
|
|
|
|
2021-11-29 18:53:38 +00:00
|
|
|
static int gDone;
|
|
|
|
static bool allowColor;
|
|
|
|
static bool inited = false;
|
|
|
|
static bool timerEnabled = false;
|
|
|
|
static WindowPtr tipWindow;
|
2021-12-01 04:02:28 +00:00
|
|
|
static MenuHandle tipMenu;
|
2021-11-29 18:53:38 +00:00
|
|
|
static TBHandle richText;
|
|
|
|
static const char *textFileName;
|
2021-11-23 18:50:09 +00:00
|
|
|
|
|
|
|
void NewTipWindow();
|
2021-11-29 18:53:38 +00:00
|
|
|
void DisposeTipWindow();
|
2021-12-01 04:02:28 +00:00
|
|
|
void AddTipMenus();
|
|
|
|
void RunCommandLine();
|
2021-11-23 18:50:09 +00:00
|
|
|
void DoEvent(EventRecord &event, RgnHandle *cursorRgn);
|
2021-12-01 19:23:36 +00:00
|
|
|
void DoMenuEventPostSIOUX(EventRecord &event);
|
|
|
|
bool DoMenuSelection(long choice);
|
2021-11-23 18:50:09 +00:00
|
|
|
void DoUpdate(WindowPtr window);
|
|
|
|
void DoMouseDown(EventRecord &event);
|
|
|
|
void DoMouseMove(EventRecord &event, RgnHandle *cursorRegion);
|
2021-11-25 23:54:59 +00:00
|
|
|
void DoDiskEvent(EventRecord &event);
|
2021-11-29 18:53:38 +00:00
|
|
|
void SetPage(TipPage page);
|
|
|
|
ControlHandle FindControl(int id);
|
|
|
|
OSErr GetExplanationFSSpec(const char *name, FSSpec *docSpec);
|
|
|
|
void OpenExplanationInSimpleText();
|
|
|
|
|
|
|
|
#define SET_POINT(x,y) {y,x};
|
|
|
|
|
|
|
|
const Point mainWndOrigin = SET_POINT(0, 40);
|
2021-11-23 18:50:09 +00:00
|
|
|
|
2021-12-01 01:56:51 +00:00
|
|
|
void run_tip() {
|
2021-12-01 04:02:28 +00:00
|
|
|
AddTipMenus();
|
|
|
|
|
2021-11-24 15:55:06 +00:00
|
|
|
RgnHandle cursorRgn = NewRgn();
|
|
|
|
|
2021-11-23 18:50:09 +00:00
|
|
|
NewTipWindow();
|
2021-11-26 21:30:41 +00:00
|
|
|
EnableWindow(hTestButton, false);
|
2021-11-29 18:53:38 +00:00
|
|
|
SetRichEditText(szInstructions);
|
2021-11-26 21:30:41 +00:00
|
|
|
|
2021-11-23 18:50:09 +00:00
|
|
|
gDone = false;
|
|
|
|
do {
|
2021-11-24 15:55:06 +00:00
|
|
|
EventRecord event;
|
|
|
|
if (WaitNextEvent(everyEvent, &event, GetCaretTime(), cursorRgn)) {
|
|
|
|
DoEvent(event, &cursorRgn);
|
2021-11-29 18:53:38 +00:00
|
|
|
if(!inited && page == kTestingPage) {
|
|
|
|
printf("Starting tip\n");
|
|
|
|
// Start TIP as soon as the user dismisses the intro screen
|
|
|
|
inited = true;
|
2021-12-01 01:56:51 +00:00
|
|
|
uint8_t drivesSkipped;
|
|
|
|
WinMain(&drivesSkipped);
|
|
|
|
if(drivesSkipped) {
|
|
|
|
const char *s = drivesSkipped > 1 ? "s" : "";
|
|
|
|
if(ShowAlert(YN_DLG,
|
|
|
|
"Found media in %d drive%s. If you wish to test that "
|
|
|
|
"media, you must quit to the Finder and eject it "
|
|
|
|
"prior to running TIP. Would you like to do so?",
|
|
|
|
drivesSkipped, s
|
|
|
|
) == 1) {
|
|
|
|
gDone = true;
|
|
|
|
}
|
|
|
|
}
|
2021-11-29 18:53:38 +00:00
|
|
|
}
|
2021-11-24 15:55:06 +00:00
|
|
|
}
|
2021-11-24 19:05:11 +00:00
|
|
|
if(timerEnabled) {
|
|
|
|
ApplicationTimerProc();
|
|
|
|
}
|
2021-11-23 18:50:09 +00:00
|
|
|
} while (!gDone);
|
|
|
|
|
2021-11-29 18:53:38 +00:00
|
|
|
DisposeTipWindow();
|
2021-11-23 18:50:09 +00:00
|
|
|
DisposeRgn(cursorRgn);
|
|
|
|
}
|
|
|
|
|
|
|
|
void NewTipWindow() {
|
|
|
|
OSErr error;
|
|
|
|
SysEnvRec theWorld;
|
|
|
|
|
|
|
|
error = SysEnvirons(1, &theWorld);
|
2021-11-29 18:53:38 +00:00
|
|
|
allowColor = theWorld.hasColorQD;
|
|
|
|
|
|
|
|
const int wndHeight = 336 - 35;
|
|
|
|
const int wndWidth = 467;
|
2021-11-23 18:50:09 +00:00
|
|
|
|
|
|
|
Rect rect = qd.screenBits.bounds;
|
2021-11-25 23:54:59 +00:00
|
|
|
rect.left = 8;
|
|
|
|
rect.top = GetMBarHeight() + rect.left + 16;
|
2021-11-29 18:53:38 +00:00
|
|
|
rect.bottom = rect.top + wndHeight;
|
|
|
|
rect.right = rect.left + wndWidth;
|
2021-11-23 18:50:09 +00:00
|
|
|
|
2021-11-24 15:55:06 +00:00
|
|
|
Str255 title;
|
|
|
|
StrToPascal(title, szWindowTitle);
|
2021-11-29 18:53:38 +00:00
|
|
|
tipWindow = allowColor ?
|
2021-11-25 05:12:37 +00:00
|
|
|
NewCWindow(NULL,&rect, title, true, 0, (WindowPtr)-1, true, 0) :
|
|
|
|
NewWindow(NULL,&rect, title, true, 0, (WindowPtr)-1, true, 0);
|
2021-11-23 18:50:09 +00:00
|
|
|
|
2021-12-01 01:56:51 +00:00
|
|
|
SetPort(tipWindow);
|
|
|
|
SetBackColor(BACK_COLOR);
|
|
|
|
EraseRect(&tipWindow->portRect);
|
2021-11-24 15:55:06 +00:00
|
|
|
|
2021-11-23 18:50:09 +00:00
|
|
|
TextSize(10);
|
2021-11-24 15:55:06 +00:00
|
|
|
|
2021-11-29 18:53:38 +00:00
|
|
|
// Create the controls
|
|
|
|
|
2021-11-24 15:55:06 +00:00
|
|
|
for(int i = 0; tipBtns[i].name; i++) {
|
|
|
|
SetRect(&rect,
|
|
|
|
tipBtns[i].x,
|
2021-11-29 18:53:38 +00:00
|
|
|
tipBtns[i].y - mainWndOrigin.v,
|
2021-11-24 15:55:06 +00:00
|
|
|
tipBtns[i].x + tipBtns[i].w,
|
2021-11-29 18:53:38 +00:00
|
|
|
tipBtns[i].y + tipBtns[i].h - mainWndOrigin.v
|
2021-11-24 15:55:06 +00:00
|
|
|
);
|
|
|
|
StrToPascal(title, tipBtns[i].name);
|
2021-12-01 01:56:51 +00:00
|
|
|
tipBtns[i].hndl = NewControl(tipWindow, &rect, title, false, 0, 0, 0, 0, tipBtns[i].id);
|
2021-11-23 18:50:09 +00:00
|
|
|
}
|
2021-11-29 18:53:38 +00:00
|
|
|
|
|
|
|
page = kExplainPage;
|
|
|
|
GetDC(hExplainWnd);
|
|
|
|
|
|
|
|
// Create the text edit widget
|
|
|
|
SetRect(&rect, 15, 15, 447, 250);
|
|
|
|
richText = TBNew(tipWindow, &rect);
|
|
|
|
|
|
|
|
ReleaseDC(hExplainWnd);
|
|
|
|
|
|
|
|
SetPage(kTestingPage);
|
2021-11-23 18:50:09 +00:00
|
|
|
}
|
|
|
|
|
2021-12-01 04:02:28 +00:00
|
|
|
void AddTipMenus() {
|
2021-12-01 19:23:36 +00:00
|
|
|
if(!TrapAvailable(0xAA66)) {
|
|
|
|
// If MenuChoice is available, we can let SIOUX handle the menus,
|
|
|
|
// otherwise we have to handle it ourselves
|
|
|
|
SIOUXSettings.setupmenus = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add our menu
|
2021-12-01 04:02:28 +00:00
|
|
|
tipMenu = GetMenu(128);
|
|
|
|
InsertMenu(tipMenu, 0);
|
|
|
|
DrawMenuBar();
|
|
|
|
}
|
|
|
|
|
|
|
|
void RunCommandLine() {
|
|
|
|
HideWindow(tipWindow);
|
|
|
|
DisableItem(tipMenu, 0);
|
|
|
|
DrawMenuBar();
|
|
|
|
command_line_event_loop();
|
|
|
|
EnableItem(tipMenu, 0);
|
|
|
|
DrawMenuBar();
|
|
|
|
ShowWindow(tipWindow);
|
|
|
|
SelectWindow(tipWindow);
|
|
|
|
InitCursor();
|
|
|
|
}
|
|
|
|
|
2021-11-29 18:53:38 +00:00
|
|
|
void DisposeTipWindow() {
|
|
|
|
TBDispose(richText);
|
2021-11-23 18:50:09 +00:00
|
|
|
DisposeWindow(tipWindow);
|
|
|
|
}
|
|
|
|
|
2021-11-29 18:53:38 +00:00
|
|
|
ControlHandle FindControl(int id) {
|
|
|
|
for(int i = 0; tipBtns[i].name; i++) {
|
|
|
|
if (tipBtns[i].id == id)
|
|
|
|
return tipBtns[i].hndl;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool PrepareDC(int which) {
|
|
|
|
SetPort(tipWindow);
|
|
|
|
switch(which) {
|
|
|
|
case hExplainWnd:
|
|
|
|
if(page != kExplainPage) return false;
|
|
|
|
break;
|
|
|
|
case hTestMonitor:
|
|
|
|
if(page != kTestingPage) return false;
|
|
|
|
SetOrigin(-20, -10);
|
|
|
|
break;
|
|
|
|
case hMainWnd:
|
|
|
|
SetOrigin(mainWndOrigin.h, mainWndOrigin.v);
|
|
|
|
break;
|
2021-12-01 01:56:51 +00:00
|
|
|
case hDefault:
|
|
|
|
SetOrigin(0, 0);
|
|
|
|
break;
|
2021-11-29 18:53:38 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-11-23 18:50:09 +00:00
|
|
|
void DoEvent(EventRecord &event, RgnHandle *cursorRgn) {
|
|
|
|
if(!SIOUXHandleOneEvent(&event)) {
|
2021-11-24 15:55:06 +00:00
|
|
|
// If SIOUX didn't handle the event, then handle it ourselves
|
2021-11-23 18:50:09 +00:00
|
|
|
switch(event.what) {
|
2021-11-24 15:55:06 +00:00
|
|
|
case mouseDown: DoMouseDown(event); break;
|
2021-11-23 18:50:09 +00:00
|
|
|
case updateEvt: DoUpdate((WindowPtr)event.message); break;
|
2021-11-25 23:54:59 +00:00
|
|
|
case diskEvt: DoDiskEvent(event); break;
|
|
|
|
case osEvt: DoMouseMove(event, cursorRgn); break;
|
2021-11-23 18:50:09 +00:00
|
|
|
}
|
2021-12-01 04:02:28 +00:00
|
|
|
} else { // Trap unhandled SIOUX menu events
|
2021-12-01 19:23:36 +00:00
|
|
|
DoMenuEventPostSIOUX(event);
|
2021-12-01 04:02:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-01 19:23:36 +00:00
|
|
|
void DoMenuEventPostSIOUX(EventRecord &event) {
|
|
|
|
if(!SIOUXSettings.setupmenus) return;
|
|
|
|
|
|
|
|
/* If MenuChoice is available, it is best to let SIOUX handle the menu
|
|
|
|
* event so Copy and Paste will work. We can check after the fact
|
|
|
|
* to see whether the user selected one of our menus using MenuChoice.
|
|
|
|
* However, if that trap is not available, we must handle the menu
|
|
|
|
* ourselves and certain menu items will not work
|
|
|
|
*/
|
2021-12-01 04:02:28 +00:00
|
|
|
|
|
|
|
WindowPtr thisWindow;
|
2021-12-01 19:23:36 +00:00
|
|
|
if((event.what == mouseDown) && (FindWindow(event.where, &thisWindow) == inMenuBar)) {
|
|
|
|
DoMenuSelection(MenuChoice());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DoMenuSelection(long choice) {
|
|
|
|
bool handled = false;
|
|
|
|
int menuId = HiWord(choice);
|
|
|
|
int itemId = LoWord(choice);
|
|
|
|
//printf("Menu choice: %d, %d\n", menuId, itemId);
|
|
|
|
switch(menuId) {
|
|
|
|
case 32000: // Apple menu SysBeep(10);
|
|
|
|
break;
|
|
|
|
case 32001: // File menu
|
|
|
|
if (itemId == 9) { // Quit
|
|
|
|
WndProc(WM_COMMAND, IDB_QUIT);
|
|
|
|
handled = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 32002: // Edit menu
|
|
|
|
break;
|
|
|
|
case 128: // TIP menu
|
|
|
|
switch(itemId) {
|
|
|
|
case 1: // Run Command Line...
|
|
|
|
HiliteMenu(0);
|
|
|
|
RunCommandLine();
|
|
|
|
handled = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2021-11-23 18:50:09 +00:00
|
|
|
}
|
2021-12-01 04:02:28 +00:00
|
|
|
HiliteMenu(0);
|
2021-12-01 19:23:36 +00:00
|
|
|
return handled;
|
2021-11-23 18:50:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DoUpdate(WindowPtr window) {
|
|
|
|
BeginUpdate(window);
|
|
|
|
SetPort(window);
|
2021-11-29 18:53:38 +00:00
|
|
|
SetColor(BACK_COLOR);
|
|
|
|
PaintRect(&window->portRect);
|
2021-11-24 15:55:06 +00:00
|
|
|
|
|
|
|
GetDC(hMainWnd);
|
2021-11-23 18:50:09 +00:00
|
|
|
WndProc(WM_PAINT, 0);
|
|
|
|
ReleaseDC(hMainWnd);
|
2021-11-24 15:55:06 +00:00
|
|
|
|
2021-11-23 18:50:09 +00:00
|
|
|
GetDC(hTestMonitor);
|
|
|
|
TestMonitorWndProc();
|
|
|
|
ReleaseDC(hTestMonitor);
|
2021-11-24 15:55:06 +00:00
|
|
|
|
2021-11-29 18:53:38 +00:00
|
|
|
GetDC(hExplainWnd);
|
|
|
|
SetColor(BLACK_COLOR);
|
|
|
|
EraseRect(&(*richText)->frame);
|
|
|
|
TBUpdate(richText);
|
|
|
|
DrawEdge(&(*richText)->frame, BDR_SUNKENOUTER, BF_RECT);
|
|
|
|
ReleaseDC(hExplainWnd);
|
|
|
|
|
2021-12-01 19:23:36 +00:00
|
|
|
SetColor(BLACK_COLOR);
|
2021-11-29 18:53:38 +00:00
|
|
|
UpdateControls(window, window->visRgn);
|
|
|
|
|
2021-11-23 18:50:09 +00:00
|
|
|
EndUpdate(window);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DoMouseDown(EventRecord &event) {
|
|
|
|
WindowPtr thisWindow;
|
|
|
|
ControlHandle thisControl;
|
|
|
|
int part = FindWindow(event.where, &thisWindow);
|
|
|
|
switch(part) {
|
|
|
|
case inSysWindow:
|
|
|
|
SystemClick(&event, thisWindow);
|
|
|
|
break;
|
|
|
|
case inContent:
|
|
|
|
if(thisWindow != FrontWindow()) {
|
|
|
|
SelectWindow(thisWindow);
|
|
|
|
}
|
|
|
|
else if(thisWindow == tipWindow) {
|
2021-11-24 15:55:06 +00:00
|
|
|
Point mouse = event.where;
|
2021-11-29 18:53:38 +00:00
|
|
|
GrafPtr oldPort;
|
|
|
|
GetPort(&oldPort);
|
|
|
|
SetPort(thisWindow);
|
2021-11-24 15:55:06 +00:00
|
|
|
GlobalToLocal(&mouse);
|
2021-11-29 18:53:38 +00:00
|
|
|
const bool hitButton = (!TBMouseDown(richText, mouse, thisWindow)) &&
|
|
|
|
(FindControl(mouse, thisWindow, &thisControl) == inButton) &&
|
|
|
|
(TrackControl(thisControl, mouse, 0) == inButton);
|
|
|
|
SetPort(oldPort);
|
|
|
|
if(hitButton) {
|
|
|
|
int id = GetControlReference(thisControl);
|
|
|
|
switch(id) {
|
|
|
|
case IDB_OKAY:
|
|
|
|
SetPage(kTestingPage);
|
|
|
|
break;
|
|
|
|
case IDB_EXPL:
|
|
|
|
SetPage(kExplainPage);
|
|
|
|
break;
|
|
|
|
case IDB_READ:
|
|
|
|
OpenExplanationInSimpleText();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
WndProc(WM_COMMAND, id);
|
|
|
|
break;
|
2021-11-24 15:55:06 +00:00
|
|
|
}
|
|
|
|
}
|
2021-11-23 18:50:09 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case inGrow:
|
|
|
|
//DoGrowWindow(thisWindow, event);
|
|
|
|
break;
|
|
|
|
case inGoAway:
|
|
|
|
if (TrackGoAway(thisWindow, event.where)) {
|
|
|
|
gDone = true;
|
|
|
|
}
|
|
|
|
break;
|
2021-12-01 19:23:36 +00:00
|
|
|
case inMenuBar:
|
|
|
|
if(!DoMenuSelection(MenuSelect(event.where))) {
|
|
|
|
SysBeep(10);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case inDrag:
|
|
|
|
DragWindow(thisWindow, event.where, &(*GetGrayRgn())->rgnBBox);
|
|
|
|
break;
|
2021-11-23 18:50:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DoMouseMove(EventRecord &event, RgnHandle *cursorRgn) {
|
|
|
|
WindowPtr thisWindow;
|
|
|
|
int part = FindWindow(event.where, &thisWindow);
|
2021-11-24 15:55:06 +00:00
|
|
|
if (thisWindow == tipWindow) {
|
|
|
|
InitCursor();
|
|
|
|
// Set the cursorRegion to everything inside our window
|
|
|
|
if(cursorRgn) {
|
|
|
|
CopyRgn(((WindowPeek)tipWindow)->contRgn, *cursorRgn);
|
|
|
|
}
|
|
|
|
}
|
2021-11-23 18:50:09 +00:00
|
|
|
}
|
|
|
|
|
2021-11-25 23:54:59 +00:00
|
|
|
void DoDiskEvent(EventRecord &event) {
|
|
|
|
OSErr mountErr = HiWord(event.message);
|
|
|
|
short driveNum = LoWord(event.message);
|
|
|
|
|
|
|
|
if (mountErr == noErr) {
|
|
|
|
// Get the volume name of recently mounted drive
|
|
|
|
Str255 volumes;
|
|
|
|
mac_get_drive_volumes(driveNum, volumes);
|
|
|
|
|
|
|
|
// Ask the user whether they want to unmount the disk
|
2021-11-27 00:26:56 +00:00
|
|
|
ParamText(volumes, "\p", "\p", "\p");
|
2021-11-25 23:54:59 +00:00
|
|
|
if (CautionAlert(128, NULL) == 1) {
|
|
|
|
// The user wishes to unmount the disk
|
|
|
|
OSErr err = mac_unmount_drive(driveNum);
|
|
|
|
if(err != noErr) {
|
|
|
|
if(err == fBsyErr) {
|
2021-11-26 21:30:41 +00:00
|
|
|
ShowAlert(ERR_DLG, "Failed to unmount. One or more files are open.");
|
2021-11-25 23:54:59 +00:00
|
|
|
} else {
|
2021-11-26 21:30:41 +00:00
|
|
|
ShowAlert(ERR_DLG, "Failed to unmount. Error Code: %d", err);
|
2021-11-25 23:54:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-23 18:50:09 +00:00
|
|
|
void StrToPascal(Str255 pStr, const char *str) {
|
|
|
|
size_t len = strlen(str);
|
|
|
|
pStr[0] = (len > 255) ? 255 : len;
|
|
|
|
strncpy((char*)pStr + 1, str, 255);
|
|
|
|
}
|
|
|
|
|
2021-11-29 18:53:38 +00:00
|
|
|
void SetPage(TipPage newPage) {
|
|
|
|
if(page == newPage) return;
|
|
|
|
page = newPage;
|
|
|
|
switch(page) {
|
|
|
|
case kTestingPage:
|
2021-12-01 01:56:51 +00:00
|
|
|
ShowWindow((*richText)->scroll, SW_HIDE);
|
2021-11-29 18:53:38 +00:00
|
|
|
ShowWindow(IDB_BACK, SW_HIDE);
|
|
|
|
ShowWindow(IDB_NEXT, SW_HIDE);
|
|
|
|
ShowWindow(IDB_OKAY, SW_HIDE);
|
|
|
|
ShowWindow(IDB_READ, SW_HIDE);
|
2021-12-01 01:56:51 +00:00
|
|
|
ShowWindow(IDB_TEST, SW_SHOW);
|
|
|
|
ShowWindow(IDB_EXPL, SW_SHOW);
|
|
|
|
ShowWindow(IDB_QUIT, SW_SHOW);
|
2021-11-29 18:53:38 +00:00
|
|
|
break;
|
|
|
|
case kExplainPage:
|
|
|
|
ShowWindow(IDB_TEST, SW_HIDE);
|
|
|
|
ShowWindow(IDB_BACK, SW_HIDE);
|
|
|
|
ShowWindow(IDB_NEXT, SW_HIDE);
|
|
|
|
ShowWindow(IDB_EXPL, SW_HIDE);
|
|
|
|
ShowWindow(IDB_QUIT, SW_HIDE);
|
2021-12-01 01:56:51 +00:00
|
|
|
ShowWindow(IDB_OKAY, SW_SHOW);
|
2021-11-29 18:53:38 +00:00
|
|
|
ShowWindow(IDB_READ, SW_SHOW);
|
2021-12-01 01:56:51 +00:00
|
|
|
ShowWindow((*richText)->scroll, SW_SHOW);
|
2021-11-29 18:53:38 +00:00
|
|
|
TBSetScroll(richText, 0);
|
|
|
|
break;
|
|
|
|
}
|
2021-12-01 01:56:51 +00:00
|
|
|
InvalidateRect(hDefault);
|
2021-11-29 18:53:38 +00:00
|
|
|
}
|
|
|
|
|
2021-11-26 21:30:41 +00:00
|
|
|
/*******************************************************************************
|
|
|
|
* SHOW ALERT BOX
|
|
|
|
*******************************************************************************/
|
|
|
|
|
|
|
|
int ShowAlert(AlertTypes type, const char* format, ...) {
|
|
|
|
Str255 pStr;
|
|
|
|
va_list argptr;
|
|
|
|
va_start(argptr, format);
|
|
|
|
vsprintf((char*)pStr + 1, format, argptr);
|
|
|
|
va_end(argptr);
|
|
|
|
pStr[0] = strlen((char*)pStr + 1);
|
|
|
|
ParamText(pStr, "\p", "\p", "\p");
|
|
|
|
switch(type) {
|
|
|
|
case ERR_DLG: return StopAlert(129, NULL);
|
|
|
|
case YN_DLG: return NoteAlert(130, NULL);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
2021-11-29 18:53:38 +00:00
|
|
|
* GET EXPLANATION FSSPEC
|
2021-11-26 21:30:41 +00:00
|
|
|
*
|
2021-11-29 18:53:38 +00:00
|
|
|
* Returns the FSSpec for an explanation file
|
2021-11-26 21:30:41 +00:00
|
|
|
*******************************************************************************/
|
2021-11-29 18:53:38 +00:00
|
|
|
OSErr GetExplanationFSSpec(const char *name, FSSpec *docSpec) {
|
2021-11-26 21:30:41 +00:00
|
|
|
Str255 docName;
|
|
|
|
StrToPascal(docName, name);
|
|
|
|
|
|
|
|
Str255 pathName;
|
|
|
|
pstrcpy(pathName, "\p:tip-doc:");
|
|
|
|
pstrcat(pathName, docName);
|
|
|
|
|
2021-11-29 18:53:38 +00:00
|
|
|
OSErr err = FSMakeFSSpec(0, 0, pathName, docSpec);
|
2021-11-26 21:30:41 +00:00
|
|
|
if(err) {
|
|
|
|
ShowAlert(ERR_DLG, "Can't find the \"%s\" file. Make sure it is inside the \"tip-doc\" folder.", name);
|
|
|
|
}
|
2021-11-29 18:53:38 +00:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
* OPEN EXPLANATION IN SIMPLE TEXT
|
|
|
|
*
|
|
|
|
* Opens the currently selected TIP explanation file using SimpleText
|
|
|
|
*
|
|
|
|
* This uses code from Thomas Tempelmann's C libraries
|
|
|
|
*
|
|
|
|
* http://www.tempel.org/macdev/index.html
|
|
|
|
*******************************************************************************/
|
|
|
|
void OpenExplanationInSimpleText() {
|
|
|
|
FSSpec docSpec;
|
|
|
|
FSSpec appSpec;
|
|
|
|
|
|
|
|
OSErr err = GetExplanationFSSpec(textFileName, &docSpec);
|
|
|
|
if(err != noErr) return;
|
2021-11-26 21:30:41 +00:00
|
|
|
|
|
|
|
err = FindApplicationFromDocument(&docSpec, &appSpec);
|
|
|
|
if(err) {
|
2021-11-29 18:53:38 +00:00
|
|
|
ShowAlert(ERR_DLG, "Can't find an application to open \"%s\". Is \"SimpleText\" installed?", textFileName);
|
2021-11-26 21:30:41 +00:00
|
|
|
return;
|
|
|
|
}
|
2021-11-29 18:53:38 +00:00
|
|
|
|
2021-11-26 21:30:41 +00:00
|
|
|
err = LaunchApplicationWithDocument(&appSpec, &docSpec, false);
|
|
|
|
if(err) {
|
2021-11-29 18:53:38 +00:00
|
|
|
ShowAlert(ERR_DLG, "Can't open \"%s\". If \"%#s\" is already running, please close it.", textFileName, appSpec.name);
|
2021-11-26 21:30:41 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-29 18:53:38 +00:00
|
|
|
/*******************************************************************************
|
|
|
|
* SET RICH EDIT TEXT
|
|
|
|
*
|
|
|
|
* This routine will open one of the TIP explanation files using SimpleText
|
|
|
|
*
|
|
|
|
* This uses code from Thomas Tempelmann's C libraries
|
|
|
|
*
|
|
|
|
* http://www.tempel.org/macdev/index.html
|
|
|
|
*******************************************************************************/
|
|
|
|
|
|
|
|
void SetRichEditText(const char *name) {
|
|
|
|
// Don't reload a file that is already loaded
|
|
|
|
|
|
|
|
if(textFileName == name) return;
|
|
|
|
textFileName = name;
|
|
|
|
|
|
|
|
// Get the specification for the explanation file
|
|
|
|
|
|
|
|
FSSpec docSpec;
|
|
|
|
OSErr err = GetExplanationFSSpec(textFileName, &docSpec);
|
|
|
|
if(err != noErr) return;
|
|
|
|
|
2021-12-01 01:56:51 +00:00
|
|
|
// Load the text from the file
|
|
|
|
|
|
|
|
TBReadSimpleText(richText, &docSpec);
|
2021-11-29 18:53:38 +00:00
|
|
|
|
|
|
|
if (name != szRunning && name != szNotRunning) {
|
|
|
|
SetPage(kExplainPage);
|
2021-12-01 01:56:51 +00:00
|
|
|
} else {
|
|
|
|
InvalidateRect(hDefault);
|
2021-11-29 18:53:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-23 18:50:09 +00:00
|
|
|
/*******************************************************************************
|
|
|
|
* SET COLOR
|
|
|
|
*******************************************************************************/
|
|
|
|
|
2021-12-01 01:56:51 +00:00
|
|
|
void SetRGBColor(long color, RGBColor *rgbColor) {
|
|
|
|
if(color == BACK_COLOR) color = LTGRAY_COLOR;
|
|
|
|
// Use colors when available
|
|
|
|
rgbColor->red = (color & 0xFF0000) >> 8;
|
|
|
|
rgbColor->green = (color & 0x00FF00) >> 0;
|
|
|
|
rgbColor->blue = (color & 0x0000FF) << 8;
|
|
|
|
}
|
|
|
|
|
2021-11-23 18:50:09 +00:00
|
|
|
void SetColor(long color) {
|
2021-11-29 18:53:38 +00:00
|
|
|
if (allowColor) {
|
2021-11-23 18:50:09 +00:00
|
|
|
RGBColor rgbColor;
|
2021-12-01 01:56:51 +00:00
|
|
|
SetRGBColor(color, &rgbColor);
|
2021-11-23 18:50:09 +00:00
|
|
|
RGBForeColor(&rgbColor);
|
|
|
|
} else {
|
|
|
|
// Use patterns for B&W Macs
|
|
|
|
TextMode(srcCopy);
|
|
|
|
switch(color) {
|
|
|
|
case BACK_COLOR:
|
|
|
|
case WHITE_COLOR:
|
|
|
|
PenPat(&qd.white);
|
|
|
|
TextMode(srcBic);
|
|
|
|
break;
|
|
|
|
case BLACK_COLOR:
|
|
|
|
case GRAY_COLOR:
|
2021-11-24 15:55:06 +00:00
|
|
|
PenPat(&qd.black);
|
|
|
|
break;
|
2021-11-23 18:50:09 +00:00
|
|
|
case RED_COLOR:
|
|
|
|
case BLUE_COLOR:
|
|
|
|
PenPat(&qd.ltGray);
|
|
|
|
break;
|
|
|
|
case LTGRAY_COLOR:
|
|
|
|
case GREEN_COLOR:
|
|
|
|
PenPat(&qd.gray);
|
2021-11-24 15:55:06 +00:00
|
|
|
break;
|
2021-11-23 18:50:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetColor(long color, long monoColor) {
|
2021-11-29 18:53:38 +00:00
|
|
|
if (allowColor) {
|
2021-11-24 15:55:06 +00:00
|
|
|
SetColor(color);
|
|
|
|
} else {
|
|
|
|
SetColor(monoColor);
|
|
|
|
}
|
2021-11-23 18:50:09 +00:00
|
|
|
}
|
|
|
|
|
2021-12-01 01:56:51 +00:00
|
|
|
void SetBackColor(long color) {
|
|
|
|
if (allowColor) {
|
|
|
|
RGBColor rgbColor;
|
|
|
|
SetRGBColor(color, &rgbColor);
|
|
|
|
RGBBackColor(&rgbColor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-23 18:50:09 +00:00
|
|
|
/*******************************************************************************
|
|
|
|
* DRAW LED
|
|
|
|
*******************************************************************************/
|
|
|
|
|
|
|
|
void DrawLed(int x, int y, long color) {
|
|
|
|
Rect ledRect;
|
|
|
|
SetRect(&ledRect, x, y, x + 12, y + 12);
|
|
|
|
// Draw the LED
|
|
|
|
SetColor(color);
|
|
|
|
PaintOval(&ledRect);
|
2021-11-29 18:53:38 +00:00
|
|
|
if (allowColor) {
|
2021-11-23 18:50:09 +00:00
|
|
|
// Draw a recessed outline
|
|
|
|
SetColor(BLACK_COLOR);
|
|
|
|
FrameOval(&ledRect);
|
|
|
|
SetColor(WHITE_COLOR);
|
|
|
|
FrameArc(&ledRect,45,180);
|
|
|
|
} else {
|
|
|
|
// Draw a non-recessed outline
|
|
|
|
SetColor(BLACK_COLOR);
|
|
|
|
FrameOval(&ledRect);
|
|
|
|
SetColor(WHITE_COLOR);
|
|
|
|
}
|
|
|
|
// Draw the reflection
|
|
|
|
if(color != BACK_COLOR) {
|
|
|
|
ledRect.left += 3;
|
|
|
|
ledRect.top += 3;
|
|
|
|
ledRect.right -= 7;
|
|
|
|
ledRect.bottom -= 7;
|
|
|
|
OffsetRect(&ledRect,0,1);
|
|
|
|
PaintRect(&ledRect);
|
|
|
|
OffsetRect(&ledRect,1,-1);
|
|
|
|
PaintRect(&ledRect);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
* DRAW EDGE
|
|
|
|
*******************************************************************************/
|
|
|
|
|
|
|
|
void DrawEdge(Rect *qrc, int edge, int grfFlags) {
|
2021-11-29 18:53:38 +00:00
|
|
|
if(edge == BDR_SUNKENOUTER && allowColor) {
|
2021-11-23 18:50:09 +00:00
|
|
|
// Draw a sunken rectangle
|
|
|
|
SetColor(GRAY_COLOR);
|
|
|
|
MoveTo(qrc->left,qrc->bottom-1);
|
|
|
|
LineTo(qrc->left,qrc->top);
|
|
|
|
LineTo(qrc->right-1,qrc->top);
|
|
|
|
SetColor(WHITE_COLOR);
|
|
|
|
MoveTo(qrc->left,qrc->bottom-1);
|
|
|
|
LineTo(qrc->right-1,qrc->bottom-1);
|
|
|
|
LineTo(qrc->right-1,qrc->top);
|
|
|
|
} else {
|
|
|
|
// Draw a non-recessed rectangle
|
|
|
|
SetColor(LTGRAY_COLOR);
|
|
|
|
FrameRect(qrc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
* RECTANGLE
|
|
|
|
*******************************************************************************/
|
|
|
|
|
|
|
|
void Rectangle(int left, int top, int right, int bottom) {
|
|
|
|
Rect rect;
|
|
|
|
SetRect(&rect, left, top, right, bottom);
|
|
|
|
PaintRect(&rect);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
* TEXT OUT
|
|
|
|
*******************************************************************************/
|
|
|
|
|
|
|
|
void TextOut(int x, int y, Str255 pStr) {
|
|
|
|
FontInfo info;
|
|
|
|
GetFontInfo(&info);
|
|
|
|
MoveTo(x, y + info.ascent + info.descent);
|
|
|
|
DrawString(pStr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextOut(int x, int y, const char *str) {
|
|
|
|
Str255 pStr;
|
|
|
|
StrToPascal(pStr, str);
|
|
|
|
TextOut(x, y, pStr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TextOutCentered(int x, int y, int w, int h, const char *str) {
|
|
|
|
// convert to Pascal string
|
|
|
|
Str255 pStr;
|
|
|
|
StrToPascal(pStr, str);
|
|
|
|
// now place the floating string in the middle
|
|
|
|
const int width = TextWidth(pStr, 0, strlen(str));
|
|
|
|
if(width < w) {
|
|
|
|
TextOut(x + w/2 - width/2, y, pStr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
* GET TEXT EXTENT
|
|
|
|
*******************************************************************************/
|
|
|
|
long GetTextExtent(const char *str, unsigned long len) {
|
|
|
|
// convert to Pascal string
|
|
|
|
Str255 pStr;
|
|
|
|
StrToPascal(pStr, str);
|
|
|
|
// now place the floating string in the middle
|
|
|
|
return TextWidth(pStr, 0, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
* GET SYSTEM TIME
|
|
|
|
*******************************************************************************/
|
|
|
|
unsigned long GetSystemTime() {
|
|
|
|
unsigned long time;
|
|
|
|
GetDateTime (&time);
|
|
|
|
return time;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
2021-11-24 19:05:11 +00:00
|
|
|
* SET WINDOW TEXT
|
2021-11-23 18:50:09 +00:00
|
|
|
*******************************************************************************/
|
2021-11-24 19:05:11 +00:00
|
|
|
void SetWindowText(int id, const char *str) {
|
2021-11-24 15:55:06 +00:00
|
|
|
Str255 pStr;
|
|
|
|
StrToPascal(pStr, str);
|
2021-11-29 18:53:38 +00:00
|
|
|
ControlHandle hCntl = FindControl(id);
|
|
|
|
if(hCntl) {
|
2021-12-01 01:56:51 +00:00
|
|
|
GetDC(hDefault);
|
2021-11-29 18:53:38 +00:00
|
|
|
SetCTitle(hCntl, pStr);
|
2021-12-01 01:56:51 +00:00
|
|
|
ReleaseDC(hDefault);
|
2021-11-24 15:55:06 +00:00
|
|
|
}
|
2021-11-23 18:50:09 +00:00
|
|
|
}
|
|
|
|
|
2021-11-24 19:05:11 +00:00
|
|
|
/*******************************************************************************
|
|
|
|
* ENABLE WINDOW
|
|
|
|
*******************************************************************************/
|
|
|
|
void EnableWindow(int id, bool enabled) {
|
2021-11-29 18:53:38 +00:00
|
|
|
ControlHandle hCntl = FindControl(id);
|
2021-11-24 19:05:11 +00:00
|
|
|
if(hCntl) {
|
2021-12-01 01:56:51 +00:00
|
|
|
GetDC(hDefault);
|
2021-11-24 19:05:11 +00:00
|
|
|
HiliteControl(hCntl, enabled ? 0 : 255);
|
2021-12-01 01:56:51 +00:00
|
|
|
ReleaseDC(hDefault);
|
2021-11-24 19:05:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-29 18:53:38 +00:00
|
|
|
/*******************************************************************************
|
|
|
|
* SHOW WINDOW
|
|
|
|
*******************************************************************************/
|
2021-12-01 01:56:51 +00:00
|
|
|
void ShowWindow(ControlHandle hCntl, int state) {
|
|
|
|
// Show/hide a control by invalidating, rather than drawing it
|
|
|
|
(*hCntl)->contrlVis = (state == SW_SHOW) ? 255 : 0;
|
|
|
|
InvalRect(&(*hCntl)->contrlRect);
|
|
|
|
}
|
|
|
|
|
2021-11-29 18:53:38 +00:00
|
|
|
void ShowWindow(int id, int state) {
|
|
|
|
ControlHandle hCntl = FindControl(id);
|
|
|
|
if(hCntl) {
|
2021-12-01 01:56:51 +00:00
|
|
|
GetDC(hDefault);
|
|
|
|
ShowWindow(hCntl, state);
|
|
|
|
ReleaseDC(hDefault);
|
2021-11-29 18:53:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-24 19:05:11 +00:00
|
|
|
/*******************************************************************************
|
|
|
|
* INVALIDATE RECT
|
|
|
|
*******************************************************************************/
|
|
|
|
void InvalidateRect(int id) {
|
|
|
|
GetDC(id);
|
|
|
|
InvalRect(&qd.thePort->portRect);
|
|
|
|
ReleaseDC(id);
|
|
|
|
}
|
|
|
|
|
2021-11-23 18:50:09 +00:00
|
|
|
/*******************************************************************************
|
|
|
|
* POST QUIT MESSAGE
|
|
|
|
*******************************************************************************/
|
|
|
|
void PostQuitMessage() {
|
2021-11-24 15:55:06 +00:00
|
|
|
gDone = true;
|
2021-11-23 18:50:09 +00:00
|
|
|
}
|
|
|
|
|
2021-11-24 19:05:11 +00:00
|
|
|
/*******************************************************************************
|
|
|
|
* START APPLICATION TIMER
|
|
|
|
*******************************************************************************/
|
|
|
|
void StartApplicationTimer() {
|
|
|
|
timerEnabled = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
* STOP APPLICATION TIMER
|
|
|
|
*******************************************************************************/
|
|
|
|
void StopApplicationTimer() {
|
|
|
|
timerEnabled = false;
|
|
|
|
}
|
|
|
|
|
2021-11-23 18:50:09 +00:00
|
|
|
/*******************************************************************************
|
|
|
|
* PROCESS PENDING MESSAGES
|
|
|
|
*******************************************************************************/
|
|
|
|
void ProcessPendingMessages() {
|
2021-11-24 15:55:06 +00:00
|
|
|
EventRecord event;
|
|
|
|
if (GetNextEvent(everyEvent, &event)) {
|
|
|
|
DoEvent(event,NULL);
|
|
|
|
}
|
2021-11-27 16:03:57 +00:00
|
|
|
SystemTask();
|
2021-11-24 16:24:02 +00:00
|
|
|
}
|