#include "Settings.h" #include #include #include #include "WindowManager.h" /* Display Manager code copied from Apple's DisplayVideo example */ /* I HATE THE DISPLAY MANAGER!! */ struct DepthInfo { VDSwitchInfoRec depthSwitchInfo; // This is the switch mode to choose this timing/depth VPBlock depthVPBlock; // VPBlock (including size, depth and format) }; typedef struct DepthInfo DepthInfo; struct ListIteratorDataRec { unsigned long displayModeFlags; VDSwitchInfoRec displayModeSwitchInfo; VDResolutionInfoRec displayModeResolutionInfo; VDTimingInfoRec displayModeTimingInfo; // Contains timing flags and such unsigned long depthBlockCount; // How many depths available for a particular timing DepthInfo * depthBlocks; // Array of DepthInfo Str255 displayModeName; // name of the timing mode }; typedef struct ListIteratorDataRec ListIteratorDataRec; static pascal void ModeListIterator(void * userData, DMListIndexType itemIndex, DMDisplayModeListEntryPtr displaymodeInfo) { #pragma unused(itemIndex) unsigned long depthCount; short iCount; ListIteratorDataRec * myIterateData = (ListIteratorDataRec *) userData; DepthInfo * myDepthInfo; myIterateData->displayModeFlags = displaymodeInfo->displayModeFlags; // Info on this particular display mode myIterateData->displayModeSwitchInfo = *displaymodeInfo->displayModeSwitchInfo; // not needed - depth info has this per depth myIterateData->displayModeResolutionInfo = *displaymodeInfo->displayModeResolutionInfo; // refresh rate, pixels/lines at max depth myIterateData->displayModeTimingInfo = *displaymodeInfo->displayModeTimingInfo; // to get the flags on timing mode myIterateData->displayModeName[0] = sprintf((char *) &myIterateData->displayModeName[1], "%.*s", displaymodeInfo->displayModeName[0], &displaymodeInfo->displayModeName[1]); // the name of the mode // now get the DMDepthInfo into memory we own depthCount = displaymodeInfo->displayModeDepthBlockInfo->depthBlockCount; myDepthInfo = (DepthInfo *) NewPtrClear(depthCount * sizeof(DepthInfo)); // set the info for the caller myIterateData->depthBlockCount = depthCount; myIterateData->depthBlocks = myDepthInfo; // and fill out all the entries for (iCount = 0; iCount < depthCount; iCount++) { myDepthInfo[iCount].depthSwitchInfo = *displaymodeInfo->displayModeDepthBlockInfo->depthVPBlock[iCount].depthSwitchInfo; myDepthInfo[iCount].depthVPBlock = *displaymodeInfo->displayModeDepthBlockInfo->depthVPBlock[iCount].depthVPBlock; } } static void SquashDisplayModeList(VSettings * s) { ScreenResolution * current, * target, * previous; current = s->Resolutions; while (current != NULL) { target = current->next; previous = current; while (target != NULL) { if (target->Width == current->Width && target->Height == current->Height && target->RefreshRate == current->RefreshRate) { previous->next = target->next; DisposePtr((Ptr) target); target = previous->next; continue; } previous = target; target = target->next; } current = current->next; } } static void GetDisplayCapabilities(VSettings * s) { GDHandle device; DisplayIDType displayID; DMListIndexType displayModeCount; DMListType displayModeList; ListIteratorDataRec searchData; short wDisplayMode, wDepth; DMDisplayModeListIteratorUPP iteratorProc; OSErr error; ScreenResolution ** currentScreenResHandle; s->NumberOfResolutions = 0; device = DMGetFirstScreenDevice(dmOnlyActiveDisplays); error = DMGetDisplayIDByGDevice(device, &displayID, 0); if (error != noErr) return; displayModeCount = 0; error = DMNewDisplayModeList(displayID, 0, 0, &displayModeCount, &displayModeList); if (error != noErr) return; currentScreenResHandle = &s->Resolutions; searchData.depthBlocks = NULL; iteratorProc = NewDMDisplayModeListIteratorUPP(ModeListIterator); for (wDisplayMode = 0; wDisplayMode < displayModeCount; wDisplayMode++) { DMGetIndexedDisplayModeFromList(displayModeList, wDisplayMode, 0, iteratorProc, &searchData); for (wDepth = 0; wDepth < searchData.depthBlockCount; wDepth++) { *currentScreenResHandle = (ScreenResolution *) NewPtr(sizeof(ScreenResolution)); if (*currentScreenResHandle == NULL) continue; s->NumberOfResolutions++; (**currentScreenResHandle).Width = searchData.depthBlocks[wDepth].depthVPBlock.vpBounds.right; (**currentScreenResHandle).Height = searchData.depthBlocks[wDepth].depthVPBlock.vpBounds.bottom; (**currentScreenResHandle).RefreshRate = (searchData.displayModeResolutionInfo.csRefreshRate >> 16); (**currentScreenResHandle).ColorDepth = searchData.depthBlocks[wDepth].depthVPBlock.vpPixelSize; (**currentScreenResHandle).next = NULL; currentScreenResHandle = &(**currentScreenResHandle).next; } if (searchData.depthBlocks != NULL) { DisposePtr((Ptr) searchData.depthBlocks); searchData.depthBlocks = NULL; } } DisposeDMDisplayModeListIteratorUPP(iteratorProc); SquashDisplayModeList(s); DMDisposeList(displayModeList); } static void ReadSettingsFromDisk(VSettings * s) { FSSpec file; short refNum; OSErr error; char line[255]; int temp; error = FindFolder(kOnSystemDisk, kPreferencesFolderType, 1, &file.vRefNum, &file.parID); if (error != noErr) return; error = FSMakeFSSpec(file.vRefNum, file.parID, "\pInfiltration preferences", &file); if (error != noErr) return; error = FSpOpenDF(&file, fsRdPerm, &refNum); if (error != noErr) return; while (ReadLn(refNum, line)) { if (!memcmp(line, "FullScreenResolution:", 21)) { sscanf(line, "FullScreenResolution: %d", &temp); s->FullScreenResolution = temp; } else if (!memcmp(line, "SoundEnabled:", 13)) { sscanf(line, "SoundEnabled: %d", &temp); s->SoundEnabled = temp; } else if (!memcmp(line, "NoFilledPolys:", 14)) { sscanf(line, "NoFilledPolys: %d", &temp); s->NoFilledPolys = temp; } else if (!memcmp(line, "StartInFullScreen:", 18)) { sscanf(line, "StartInFullScreen: %d", &temp); s->StartInFullScreen = temp; } else if (!memcmp(line, "Left:", 5)) sscanf(line, "Left: %hd", &s->Left); else if (!memcmp(line, "Right:", 6)) sscanf(line, "Right: %hd", &s->Right); else if (!memcmp(line, "Up:", 3)) sscanf(line, "Up: %hd", &s->Up); else if (!memcmp(line, "Down:", 5)) sscanf(line, "Down: %hd", &s->Down); else if (!memcmp(line, "Forward:", 8)) sscanf(line, "Forward: %hd", &s->Forward); else if (!memcmp(line, "Backward:", 9)) sscanf(line, "Backward: %hd", &s->Backward); else if (!memcmp(line, "Bullet:", 7)) sscanf(line, "Bullet: %hd", &s->Bullet); else if (!memcmp(line, "RocketTarget:", 13)) sscanf(line, "RocketTarget: %hd", &s->RocketTarget); else if (!memcmp(line, "Rocket:", 7)) sscanf(line, "Rocket: %hd", &s->Rocket); else if (!memcmp(line, "Brake:", 6)) sscanf(line, "Brake: %hd", &s->Brake); else if (!memcmp(line, "Pause:", 6)) sscanf(line, "Pause: %hd", &s->Pause); } FSClose(refNum); } static void SaveSettingsToDisk(VSettings * s) { FSSpec file; long length; short refNum; OSErr error; char line[255]; error = FindFolder(kOnSystemDisk, kPreferencesFolderType, 1, &file.vRefNum, &file.parID); if (error != noErr) return; error = FSMakeFSSpec(file.vRefNum, file.parID, "\pInfiltration preferences", &file); if (error == fnfErr) error = FSpCreate(&file, 'Vect', 'Pref', smRoman); if (error != noErr) return; error = FSpOpenDF(&file, fsWrPerm, &refNum); if (error != noErr) return; SetEOF(refNum, 0); length = sprintf(line, "FullScreenResolution: %d\n", s->FullScreenResolution); FSWrite(refNum, &length, line); length = sprintf(line, "SoundEnabled: %d\n", s->SoundEnabled); FSWrite(refNum, &length, line); length = sprintf(line, "NoFilledPolys: %d\n", s->NoFilledPolys); FSWrite(refNum, &length, line); length = sprintf(line, "StartInFullScreen: %d\n", s->StartInFullScreen); FSWrite(refNum, &length, line); length = sprintf(line, "Left: %d\n", s->Left); FSWrite(refNum, &length, line); length = sprintf(line, "Right: %d\n", s->Right); FSWrite(refNum, &length, line); length = sprintf(line, "Up: %d\n", s->Up); FSWrite(refNum, &length, line); length = sprintf(line, "Down: %d\n", s->Down); FSWrite(refNum, &length, line); length = sprintf(line, "Forward: %d\n", s->Forward); FSWrite(refNum, &length, line); length = sprintf(line, "Backward: %d\n", s->Backward); FSWrite(refNum, &length, line); length = sprintf(line, "Bullet: %d\n", s->Bullet); FSWrite(refNum, &length, line); length = sprintf(line, "RocketTarget: %d\n", s->RocketTarget); FSWrite(refNum, &length, line); length = sprintf(line, "Rocket: %d\n", s->Rocket); FSWrite(refNum, &length, line); length = sprintf(line, "Brake: %d\n", s->Brake); FSWrite(refNum, &length, line); length = sprintf(line, "Pause: %d\n", s->Pause); FSWrite(refNum, &length, line); FSClose(refNum); } void InitSettings(VSettings * s) { SetSettings(s); s->Left = 28; s->Right = 29; s->Up = 30; s->Down = 31; s->Forward = ' '; s->Backward = (' ' | shiftKey); s->Bullet = 'f'; s->RocketTarget = '\t'; s->Rocket = 'r'; s->Brake = 'b'; s->Pause = 'p'; s->KeyBeingSet = NULL; s->SoundEnabled = 1; s->NoFilledPolys = 0; s->StartInFullScreen = 0; s->FullScreenResolution = FULLSCREENRESNOCHANGE; s->Resolutions = NULL; s->NumberOfResolutions = 0; GetDisplayCapabilities(s); s->Window = NULL; ReadSettingsFromDisk(s); } void CleanUpSettings(VSettings * s) { ScreenResolution * res; while (s->Resolutions != NULL) { res = s->Resolutions->next; DisposePtr((Ptr) s->Resolutions); s->Resolutions = res; } if (s->Window != NULL) { DisposeWindow(s->Window); s->Window = NULL; } SaveSettingsToDisk(s); } static int GetKeyDescription(UInt16 key, char * string) { unsigned char charCode; int length = 0; if (key & optionKey) length += sprintf((string + length), "Option + "); if (key & cmdKey) length += sprintf((string + length), "Cmd + "); if (key & shiftKey) length += sprintf((string + length), "Shift + "); if (key & controlKey) length += sprintf((string + length), "Ctrl + "); charCode = (key & 0x00FF); switch (charCode) { case 3: length += sprintf((string + length), "Enter"); break; case 8: length += sprintf((string + length), "Backspace"); break; case 9: length += sprintf((string + length), "Tab"); break; case 10: case 13: length += sprintf((string + length), "Return"); break; case 27: length += sprintf((string + length), "Escape"); break; case 28: length += sprintf((string + length), "Left arrow"); break; case 29: length += sprintf((string + length), "Right arrow"); break; case 30: length += sprintf((string + length), "Up arrow"); break; case 31: length += sprintf((string + length), "Down arrow"); break; case ' ': /* Normal space */ case ' ': /* Non-breaking space */ length += sprintf((string + length), "Space"); break; case 127: length += sprintf((string + length), "Forward delete"); break; default: length += sprintf((string + length), "%c", charCode); break; } return length; } SInt16 KeyWithModifiers(unsigned char charCode, UInt32 modifiers) { switch (charCode) { case 3: case 8: case 9: case 10: case 13: case 27: case 28: case 29: case 30: case 31: case ' ': /* Space */ case ' ': /* Non-breaking space */ case 127: /* Char code is not visibly affected by modifiers */ return ((SInt16) charCode | modifiers); default: /* Char code is visibly affected by modifiers; don't bother displaying Shift + or Option + */ return ((SInt16) charCode | (modifiers & ~(shiftKey | optionKey))); } } static void UpdateKeySettingDisplay(VSettings * s, UInt16 * theKey) { ControlRef theControl = NULL; char string[256]; ControlID controlID; int length; controlID.signature = 'idsi'; if (theKey == &s->Left) { controlID.id = LOOKLEFTKEYDISPLAY; GetControlByID(s->Window, &controlID, &theControl); } else if (theKey == &s->Right) { controlID.id = LOOKRIGHTKEYDISPLAY; GetControlByID(s->Window, &controlID, &theControl); } else if (theKey == &s->Down) { controlID.id = LOOKDOWNKEYDISPLAY; GetControlByID(s->Window, &controlID, &theControl); } else if (theKey == &s->Up) { controlID.id = LOOKUPKEYDISPLAY; GetControlByID(s->Window, &controlID, &theControl); } else if (theKey == &s->Forward) { controlID.id = MOVEFORWARDKEYDISPLAY; GetControlByID(s->Window, &controlID, &theControl); } else if (theKey == &s->Backward) { controlID.id = MOVEBACKWARDKEYDISPLAY; GetControlByID(s->Window, &controlID, &theControl); } else if (theKey == &s->Bullet) { controlID.id = BULLETKEYDISPLAY; GetControlByID(s->Window, &controlID, &theControl); } else if (theKey == &s->Rocket) { controlID.id = ROCKETKEYDISPLAY; GetControlByID(s->Window, &controlID, &theControl); } else if (theKey == &s->RocketTarget) { controlID.id = ROCKETTARGETKEYDISPLAY; GetControlByID(s->Window, &controlID, &theControl); } else if (theKey == &s->Brake) { controlID.id = BRAKEKEYDISPLAY; GetControlByID(s->Window, &controlID, &theControl); } else if (theKey == &s->Pause) { controlID.id = PAUSEKEYDISPLAY; GetControlByID(s->Window, &controlID, &theControl); } if (theControl != NULL) { length = GetKeyDescription(*theKey, string); SetControlData(theControl, kControlEditTextPart, kControlEditTextTextTag, length, string); Draw1Control(theControl); } } static void ClearKeyDisplayStyles(VSettings * s) { ControlRef theControl = NULL; ControlID controlID; ControlFontStyleRec fontStyle; controlID.signature = 'idsi'; if (s->KeyBeingSet == &s->Left) { controlID.id = LOOKLEFTKEYDISPLAY; GetControlByID(s->Window, &controlID, &theControl); } else if (s->KeyBeingSet == &s->Right) { controlID.id = LOOKRIGHTKEYDISPLAY; GetControlByID(s->Window, &controlID, &theControl); } else if (s->KeyBeingSet == &s->Down) { controlID.id = LOOKDOWNKEYDISPLAY; GetControlByID(s->Window, &controlID, &theControl); } else if (s->KeyBeingSet == &s->Up) { controlID.id = LOOKUPKEYDISPLAY; GetControlByID(s->Window, &controlID, &theControl); } else if (s->KeyBeingSet == &s->Forward) { controlID.id = MOVEFORWARDKEYDISPLAY; GetControlByID(s->Window, &controlID, &theControl); } else if (s->KeyBeingSet == &s->Backward) { controlID.id = MOVEBACKWARDKEYDISPLAY; GetControlByID(s->Window, &controlID, &theControl); } else if (s->KeyBeingSet == &s->Bullet) { controlID.id = BULLETKEYDISPLAY; GetControlByID(s->Window, &controlID, &theControl); } else if (s->KeyBeingSet == &s->Rocket) { controlID.id = ROCKETKEYDISPLAY; GetControlByID(s->Window, &controlID, &theControl); } else if (s->KeyBeingSet == &s->RocketTarget) { controlID.id = ROCKETTARGETKEYDISPLAY; GetControlByID(s->Window, &controlID, &theControl); } else if (s->KeyBeingSet == &s->Brake) { controlID.id = BRAKEKEYDISPLAY; GetControlByID(s->Window, &controlID, &theControl); } else if (s->KeyBeingSet == &s->Pause) { controlID.id = PAUSEKEYDISPLAY; GetControlByID(s->Window, &controlID, &theControl); } if (theControl != NULL) { fontStyle.flags = (kControlUseSizeMask | kControlUseFontMask); fontStyle.size = 12; fontStyle.font = systemFont; SetControlFontStyle(theControl, &fontStyle); Draw1Control(theControl); } } static void HiliteKeySettingDisplay(ControlRef control) { ControlFontStyleRec fontStyle; fontStyle.flags = (kControlUseForeColorMask | kControlUseSizeMask | kControlUseFontMask | kControlUseFaceMask); fontStyle.foreColor.red = fontStyle.foreColor.green = 0x0000; fontStyle.foreColor.blue = 0x7FFF; fontStyle.size = 12; fontStyle.font = systemFont; fontStyle.style = italic; SetControlFontStyle(control, &fontStyle); Draw1Control(control); } static void DefaultSettings(VSettings * s) { ControlRef theControl = NULL; ControlID controlID; s->Left = 28; s->Right = 29; s->Up = 30; s->Down = 31; s->Forward = ' '; s->Backward = (' ' | shiftKey); s->Bullet = 'f'; s->RocketTarget = '\t'; s->Rocket = 'r'; s->Brake = 'b'; s->Pause = 'p'; UpdateKeySettingDisplay(s, &s->Left); UpdateKeySettingDisplay(s, &s->Right); UpdateKeySettingDisplay(s, &s->Up); UpdateKeySettingDisplay(s, &s->Down); UpdateKeySettingDisplay(s, &s->Forward); UpdateKeySettingDisplay(s, &s->Backward); UpdateKeySettingDisplay(s, &s->Bullet); UpdateKeySettingDisplay(s, &s->RocketTarget); UpdateKeySettingDisplay(s, &s->Rocket); UpdateKeySettingDisplay(s, &s->Brake); UpdateKeySettingDisplay(s, &s->Pause); ClearKeyDisplayStyles(s); s->KeyBeingSet = NULL; controlID.signature = 'idsi'; s->SoundEnabled = 1; /* controlID.id = SOUNDENABLEDCHECKBOX; GetControlByID(s->Window, &controlID, &theControl); SetControlValue(theControl, s->SoundEnabled); */ s->NoFilledPolys = 0; controlID.id = NOPOLYGONFILLCHECKBOX; GetControlByID(s->Window, &controlID, &theControl); SetControlValue(theControl, s->NoFilledPolys); s->StartInFullScreen = 0; controlID.id = STARTINFULLSCREENCHECKBOX; GetControlByID(s->Window, &controlID, &theControl); SetControlValue(theControl, s->StartInFullScreen); s->SoundEnabled = 1; controlID.id = SOUNDENABLEDCHECKBOX; GetControlByID(s->Window, &controlID, &theControl); SetControlValue(theControl, s->SoundEnabled); s->FullScreenResolution = FULLSCREENRESNOCHANGE; controlID.id = FULLSCREENRESMENU; GetControlByID(s->Window, &controlID, &theControl); SetControlValue(theControl, s->FullScreenResolution); } /* Settings window code copied from Life */ static pascal OSStatus SettingsWindowEventHandler(EventHandlerCallRef nextEvent, EventRef theEvent, void * userData) { #pragma unused(nextEvent, theEvent, userData) short controlValue; ControlRef control; Rect bounds; VSettings * s; SInt32 controlReference; unsigned char charCode; UInt32 modifiers; ControlID controlID; s = (VSettings *) userData; switch (GetEventClass(theEvent)) { case kEventClassWindow: switch (GetEventKind(theEvent)) { case kEventWindowClose: TransWindow(s->Window, 0); DisposeWindow(s->Window); s->Window = NULL; return noErr; case kEventWindowDrawContent: GetWindowPortBounds(s->Window, &bounds); EraseRect(&bounds); DrawControls(s->Window); return eventNotHandledErr; } break; case kEventClassControl: switch (GetEventKind(theEvent)) { case kEventControlHit: GetEventParameter(theEvent, kEventParamDirectObject, typeControlRef, NULL, sizeof(ControlRef), NULL, &control); controlReference = GetControlReference(control); switch (controlReference) { case FULLSCREENRESMENU: controlValue = GetControlValue(control); if (controlValue < 3) s->FullScreenResolution = FULLSCREENRESNOCHANGE; else s->FullScreenResolution = (controlValue - 3); break; case STARTINFULLSCREENCHECKBOX: controlValue = !GetControlValue(control); SetControlValue(control, controlValue); s->StartInFullScreen = controlValue; break; case NOPOLYGONFILLCHECKBOX: controlValue = !GetControlValue(control); SetControlValue(control, controlValue); s->NoFilledPolys = controlValue; break; case SOUNDENABLEDCHECKBOX: controlValue = !GetControlValue(control); SetControlValue(control, controlValue); s->SoundEnabled = controlValue; break; case SETLOOKLEFTKEYBUTTON: if (s->KeyBeingSet != NULL) ClearKeyDisplayStyles(s); s->KeyBeingSet = &s->Left; controlID.signature = 'idsi'; controlID.id = LOOKLEFTKEYDISPLAY; GetControlByID(s->Window, &controlID, &control); HiliteKeySettingDisplay(control); break; case SETLOOKRIGHTKEYBUTTON: if (s->KeyBeingSet != NULL) ClearKeyDisplayStyles(s); s->KeyBeingSet = &s->Right; controlID.signature = 'idsi'; controlID.id = LOOKRIGHTKEYDISPLAY; GetControlByID(s->Window, &controlID, &control); HiliteKeySettingDisplay(control); break; case SETLOOKDOWNKEYBUTTON: if (s->KeyBeingSet != NULL) ClearKeyDisplayStyles(s); s->KeyBeingSet = &s->Down; controlID.signature = 'idsi'; controlID.id = LOOKDOWNKEYDISPLAY; GetControlByID(s->Window, &controlID, &control); HiliteKeySettingDisplay(control); break; case SETLOOKUPKEYBUTTON: if (s->KeyBeingSet != NULL) ClearKeyDisplayStyles(s); s->KeyBeingSet = &s->Up; controlID.signature = 'idsi'; controlID.id = LOOKUPKEYDISPLAY; GetControlByID(s->Window, &controlID, &control); HiliteKeySettingDisplay(control); break; case SETMOVEFORWARDKEYBUTTON: if (s->KeyBeingSet != NULL) ClearKeyDisplayStyles(s); s->KeyBeingSet = &s->Forward; controlID.signature = 'idsi'; controlID.id = MOVEFORWARDKEYDISPLAY; GetControlByID(s->Window, &controlID, &control); HiliteKeySettingDisplay(control); break; case SETMOVEBACKWARDKEYBUTTON: if (s->KeyBeingSet != NULL) ClearKeyDisplayStyles(s); s->KeyBeingSet = &s->Backward; controlID.signature = 'idsi'; controlID.id = MOVEBACKWARDKEYDISPLAY; GetControlByID(s->Window, &controlID, &control); HiliteKeySettingDisplay(control); break; case SETBULLETKEYBUTTON: if (s->KeyBeingSet != NULL) ClearKeyDisplayStyles(s); s->KeyBeingSet = &s->Bullet; controlID.signature = 'idsi'; controlID.id = BULLETKEYDISPLAY; GetControlByID(s->Window, &controlID, &control); HiliteKeySettingDisplay(control); break; case SETROCKETKEYBUTTON: if (s->KeyBeingSet != NULL) ClearKeyDisplayStyles(s); s->KeyBeingSet = &s->Rocket; controlID.signature = 'idsi'; controlID.id = ROCKETKEYDISPLAY; GetControlByID(s->Window, &controlID, &control); HiliteKeySettingDisplay(control); break; case SETROCKETTARGETKEYBUTTON: if (s->KeyBeingSet != NULL) ClearKeyDisplayStyles(s); s->KeyBeingSet = &s->RocketTarget; controlID.signature = 'idsi'; controlID.id = ROCKETTARGETKEYDISPLAY; GetControlByID(s->Window, &controlID, &control); HiliteKeySettingDisplay(control); break; case SETBRAKEKEYBUTTON: if (s->KeyBeingSet != NULL) ClearKeyDisplayStyles(s); s->KeyBeingSet = &s->Brake; controlID.signature = 'idsi'; controlID.id = BRAKEKEYDISPLAY; GetControlByID(s->Window, &controlID, &control); HiliteKeySettingDisplay(control); break; case SETPAUSEKEYBUTTON: if (s->KeyBeingSet != NULL) ClearKeyDisplayStyles(s); s->KeyBeingSet = &s->Pause; controlID.signature = 'idsi'; controlID.id = PAUSEKEYDISPLAY; GetControlByID(s->Window, &controlID, &control); HiliteKeySettingDisplay(control); break; case DEFAULTSBUTTON: DefaultSettings(s); break; } break; } break; case kEventClassKeyboard: switch (GetEventKind(theEvent)) { case kEventRawKeyDown: if (s->KeyBeingSet != NULL) { GetEventParameter(theEvent, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(char), NULL, &charCode); GetEventParameter(theEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers); if (charCode != 27) { *s->KeyBeingSet = KeyWithModifiers(charCode, modifiers); UpdateKeySettingDisplay(s, s->KeyBeingSet); } ClearKeyDisplayStyles(s); s->KeyBeingSet = NULL; return noErr; } break; } break; } return eventNotHandledErr; } /* Sorry for the scary code... I guess that's what I get for not using nibs. :/ */ void OpenSettingsWindow(VSettings * s) { Rect bounds; GWorldPtr origGWorld; GDHandle origGDevice, mainDevice; Point screenSize; EventTypeSpec windowEventTypes[] = {{kEventClassWindow, kEventWindowClose}, {kEventClassWindow, kEventWindowDrawContent}, {kEventClassKeyboard, kEventRawKeyDown}}, controlEventTypes[] = {{kEventClassControl, kEventControlHit}}; ControlRef theControl; EventHandlerUPP eventHandlerUPP; MenuRef screenResMenu; ScreenResolution * screenRes; Str255 itemName; int currentItemNumber; ControlFontStyleRec controlFontStyle; CFStringRef string; Boolean locked = 1; char keyDescription[256]; ControlID controlID; if (s->Window != NULL) { BringToFront(s->Window); SelectWindow(s->Window); return; } mainDevice = GetMainDevice(); screenSize.h = (**mainDevice).gdRect.right; screenSize.v = (**mainDevice).gdRect.bottom; SetRect(&bounds, ((screenSize.h / 2) - 200), ((screenSize.v / 2) - 238), ((screenSize.h / 2) + 200), ((screenSize.v / 2) + 238)); s->Window = NewCWindow(NULL, &bounds, "\pSettings", 0, noGrowDocProc, (WindowPtr) -1, 1, 0); if (s->Window == NULL) return; GetGWorld(&origGWorld, &origGDevice); SetPortWindowPort(s->Window); SetThemeBackground(kThemeBrushDialogBackgroundActive, 32, 1); OffsetRect(&bounds, -bounds.left, -bounds.top); EraseRect(&bounds); InstallStandardEventHandler(GetWindowEventTarget(s->Window)); eventHandlerUPP = NewEventHandlerUPP(SettingsWindowEventHandler); InstallWindowEventHandler(s->Window, eventHandlerUPP, 3, windowEventTypes, s, NULL); CreateRootControl(s->Window, &theControl); screenResMenu = GetMenuHandle(140); if (screenResMenu == NULL) { screenResMenu = NewMenu(140, "\p"); AppendMenu(screenResMenu, "\pNo change"); if (s->NumberOfResolutions > 0) AppendMenu(screenResMenu, "\p(-"); currentItemNumber = 3; for (screenRes = s->Resolutions; screenRes != NULL; screenRes = screenRes->next) { itemName[0] = sprintf((char *) &itemName[1], "%d x %d, %dHz", screenRes->Width, screenRes->Height, screenRes->RefreshRate); AppendMenu(screenResMenu, "\pN"); SetMenuItemText(screenResMenu, currentItemNumber, itemName); currentItemNumber++; } InsertMenu(screenResMenu, kInsertHierarchicalMenu); } SetRect(&bounds, 10, 10, 390, 30); CreatePopupButtonControl(s->Window, &bounds, CFSTR("Fullscreen resolution"), 140, 0, 150, 0, 0, &theControl); if (s->FullScreenResolution == FULLSCREENRESNOCHANGE) SetControlValue(theControl, 1); else SetControlValue(theControl, (s->FullScreenResolution + 3)); SetControlReference(theControl, FULLSCREENRESMENU); controlID.signature = 'idsi'; controlID.id = FULLSCREENRESMENU; SetControlID(theControl, &controlID); InstallControlEventHandler(theControl, eventHandlerUPP, 1, controlEventTypes, s, NULL); SetRect(&bounds, 50, 40, 390, 54); CreateCheckBoxControl(s->Window, &bounds, CFSTR("Start in full screen mode"), s->StartInFullScreen, 0, &theControl); SetControlReference(theControl, STARTINFULLSCREENCHECKBOX); controlID.signature = 'idsi'; controlID.id = STARTINFULLSCREENCHECKBOX; SetControlID(theControl, &controlID); InstallControlEventHandler(theControl, eventHandlerUPP, 1, controlEventTypes, s, NULL); SetRect(&bounds, 50, 60, 390, 74); CreateCheckBoxControl(s->Window, &bounds, CFSTR("Don't fill polygons"), s->NoFilledPolys, 0, &theControl); SetControlReference(theControl, NOPOLYGONFILLCHECKBOX); controlID.signature = 'idsi'; controlID.id = NOPOLYGONFILLCHECKBOX; SetControlID(theControl, &controlID); InstallControlEventHandler(theControl, eventHandlerUPP, 1, controlEventTypes, s, NULL); SetRect(&bounds, 50, 80, 390, 94); CreateCheckBoxControl(s->Window, &bounds, CFSTR("Play sounds"), s->SoundEnabled, 0, &theControl); SetControlReference(theControl, SOUNDENABLEDCHECKBOX); controlID.signature = 'idsi'; controlID.id = SOUNDENABLEDCHECKBOX; SetControlID(theControl, &controlID); InstallControlEventHandler(theControl, eventHandlerUPP, 1, controlEventTypes, s, NULL); controlFontStyle.flags = kControlUseJustMask; controlFontStyle.just = teCenter; SetRect(&bounds, 10, 108, 390, 124); CreateStaticTextControl(s->Window, &bounds, CFSTR("Keys"), &controlFontStyle, &theControl); controlFontStyle.flags = kControlUseJustMask; controlFontStyle.just = teFlushRight; SetRect(&bounds, 10, 134, 100, 150); CreateStaticTextControl(s->Window, &bounds, CFSTR("Look left:"), &controlFontStyle, &theControl); SetRect(&bounds, 110, 134, 290, 150); GetKeyDescription(s->Left, keyDescription); string = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), keyDescription); controlFontStyle.flags = (kControlUseSizeMask | kControlUseFontMask); controlFontStyle.size = 12; controlFontStyle.font = systemFont; CreateEditTextControl(s->Window, &bounds, string, 0, 0, &controlFontStyle, &theControl); CFRelease(string); SetControlData(theControl, kControlEditTextPart, kControlEditTextLockedTag, sizeof(Boolean), &locked); controlID.signature = 'idsi'; controlID.id = LOOKLEFTKEYDISPLAY; SetControlID(theControl, &controlID); SetRect(&bounds, 300, 132, 390, 152); CreatePushButtonControl(s->Window, &bounds, CFSTR("Set"), &theControl); SetControlReference(theControl, SETLOOKLEFTKEYBUTTON); InstallControlEventHandler(theControl, eventHandlerUPP, 1, controlEventTypes, s, NULL); controlFontStyle.flags = kControlUseJustMask; controlFontStyle.just = teFlushRight; SetRect(&bounds, 10, 162, 100, 178); CreateStaticTextControl(s->Window, &bounds, CFSTR("Look right:"), &controlFontStyle, &theControl); SetRect(&bounds, 110, 162, 290, 178); GetKeyDescription(s->Right, keyDescription); string = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), keyDescription); controlFontStyle.flags = (kControlUseSizeMask | kControlUseFontMask); controlFontStyle.size = 12; controlFontStyle.font = systemFont; CreateEditTextControl(s->Window, &bounds, string, 0, 0, &controlFontStyle, &theControl); CFRelease(string); SetControlData(theControl, kControlEditTextPart, kControlEditTextLockedTag, sizeof(Boolean), &locked); controlID.signature = 'idsi'; controlID.id = LOOKRIGHTKEYDISPLAY; SetControlID(theControl, &controlID); SetRect(&bounds, 300, 160, 390, 180); CreatePushButtonControl(s->Window, &bounds, CFSTR("Set"), &theControl); SetControlReference(theControl, SETLOOKRIGHTKEYBUTTON); InstallControlEventHandler(theControl, eventHandlerUPP, 1, controlEventTypes, s, NULL); controlFontStyle.flags = kControlUseJustMask; controlFontStyle.just = teFlushRight; SetRect(&bounds, 10, 190, 100, 206); CreateStaticTextControl(s->Window, &bounds, CFSTR("Look down:"), &controlFontStyle, &theControl); SetRect(&bounds, 110, 190, 290, 206); GetKeyDescription(s->Down, keyDescription); string = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), keyDescription); controlFontStyle.flags = (kControlUseSizeMask | kControlUseFontMask); controlFontStyle.size = 12; controlFontStyle.font = systemFont; CreateEditTextControl(s->Window, &bounds, string, 0, 0, &controlFontStyle, &theControl); CFRelease(string); SetControlData(theControl, kControlEditTextPart, kControlEditTextLockedTag, sizeof(Boolean), &locked); controlID.signature = 'idsi'; controlID.id = LOOKDOWNKEYDISPLAY; SetControlID(theControl, &controlID); SetRect(&bounds, 300, 188, 390, 208); CreatePushButtonControl(s->Window, &bounds, CFSTR("Set"), &theControl); SetControlReference(theControl, SETLOOKDOWNKEYBUTTON); InstallControlEventHandler(theControl, eventHandlerUPP, 1, controlEventTypes, s, NULL); controlFontStyle.flags = kControlUseJustMask; controlFontStyle.just = teFlushRight; SetRect(&bounds, 10, 218, 100, 234); CreateStaticTextControl(s->Window, &bounds, CFSTR("Look up:"), &controlFontStyle, &theControl); SetRect(&bounds, 110, 218, 290, 234); GetKeyDescription(s->Up, keyDescription); string = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), keyDescription); controlFontStyle.flags = (kControlUseSizeMask | kControlUseFontMask); controlFontStyle.size = 12; controlFontStyle.font = systemFont; CreateEditTextControl(s->Window, &bounds, string, 0, 0, &controlFontStyle, &theControl); CFRelease(string); SetControlData(theControl, kControlEditTextPart, kControlEditTextLockedTag, sizeof(Boolean), &locked); controlID.signature = 'idsi'; controlID.id = LOOKUPKEYDISPLAY; SetControlID(theControl, &controlID); SetRect(&bounds, 300, 216, 390, 236); CreatePushButtonControl(s->Window, &bounds, CFSTR("Set"), &theControl); SetControlReference(theControl, SETLOOKUPKEYBUTTON); InstallControlEventHandler(theControl, eventHandlerUPP, 1, controlEventTypes, s, NULL); controlFontStyle.flags = kControlUseJustMask; controlFontStyle.just = teFlushRight; SetRect(&bounds, 10, 246, 100, 262); CreateStaticTextControl(s->Window, &bounds, CFSTR("Accelerate:"), &controlFontStyle, &theControl); SetRect(&bounds, 110, 246, 290, 262); GetKeyDescription(s->Forward, keyDescription); string = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), keyDescription); controlFontStyle.flags = (kControlUseSizeMask | kControlUseFontMask); controlFontStyle.size = 12; controlFontStyle.font = systemFont; CreateEditTextControl(s->Window, &bounds, string, 0, 0, &controlFontStyle, &theControl); CFRelease(string); SetControlData(theControl, kControlEditTextPart, kControlEditTextLockedTag, sizeof(Boolean), &locked); controlID.signature = 'idsi'; controlID.id = MOVEFORWARDKEYDISPLAY; SetControlID(theControl, &controlID); SetRect(&bounds, 300, 244, 390, 264); CreatePushButtonControl(s->Window, &bounds, CFSTR("Set"), &theControl); SetControlReference(theControl, SETMOVEFORWARDKEYBUTTON); InstallControlEventHandler(theControl, eventHandlerUPP, 1, controlEventTypes, s, NULL); controlFontStyle.flags = kControlUseJustMask; controlFontStyle.just = teFlushRight; SetRect(&bounds, 10, 274, 100, 290); CreateStaticTextControl(s->Window, &bounds, CFSTR("Reverse:"), &controlFontStyle, &theControl); SetRect(&bounds, 110, 274, 290, 290); GetKeyDescription(s->Backward, keyDescription); string = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), keyDescription); controlFontStyle.flags = (kControlUseSizeMask | kControlUseFontMask); controlFontStyle.size = 12; controlFontStyle.font = systemFont; CreateEditTextControl(s->Window, &bounds, string, 0, 0, &controlFontStyle, &theControl); CFRelease(string); SetControlData(theControl, kControlEditTextPart, kControlEditTextLockedTag, sizeof(Boolean), &locked); controlID.signature = 'idsi'; controlID.id = MOVEBACKWARDKEYDISPLAY; SetControlID(theControl, &controlID); SetRect(&bounds, 300, 272, 390, 292); CreatePushButtonControl(s->Window, &bounds, CFSTR("Set"), &theControl); SetControlReference(theControl, SETMOVEBACKWARDKEYBUTTON); InstallControlEventHandler(theControl, eventHandlerUPP, 1, controlEventTypes, s, NULL); controlFontStyle.flags = kControlUseJustMask; controlFontStyle.just = teFlushRight; SetRect(&bounds, 10, 302, 100, 318); CreateStaticTextControl(s->Window, &bounds, CFSTR("Fire:"), &controlFontStyle, &theControl); SetRect(&bounds, 110, 302, 290, 318); GetKeyDescription(s->Bullet, keyDescription); string = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), keyDescription); controlFontStyle.flags = (kControlUseSizeMask | kControlUseFontMask); controlFontStyle.size = 12; controlFontStyle.font = systemFont; CreateEditTextControl(s->Window, &bounds, string, 0, 0, &controlFontStyle, &theControl); CFRelease(string); SetControlData(theControl, kControlEditTextPart, kControlEditTextLockedTag, sizeof(Boolean), &locked); controlID.signature = 'idsi'; controlID.id = BULLETKEYDISPLAY; SetControlID(theControl, &controlID); SetRect(&bounds, 300, 300, 390, 320); CreatePushButtonControl(s->Window, &bounds, CFSTR("Set"), &theControl); SetControlReference(theControl, SETBULLETKEYBUTTON); InstallControlEventHandler(theControl, eventHandlerUPP, 1, controlEventTypes, s, NULL); controlFontStyle.flags = kControlUseJustMask; controlFontStyle.just = teFlushRight; SetRect(&bounds, 10, 330, 100, 346); CreateStaticTextControl(s->Window, &bounds, CFSTR("Rocket:"), &controlFontStyle, &theControl); SetRect(&bounds, 110, 330, 290, 346); GetKeyDescription(s->Rocket, keyDescription); string = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), keyDescription); controlFontStyle.flags = (kControlUseSizeMask | kControlUseFontMask); controlFontStyle.size = 12; controlFontStyle.font = systemFont; CreateEditTextControl(s->Window, &bounds, string, 0, 0, &controlFontStyle, &theControl); CFRelease(string); SetControlData(theControl, kControlEditTextPart, kControlEditTextLockedTag, sizeof(Boolean), &locked); controlID.signature = 'idsi'; controlID.id = ROCKETKEYDISPLAY; SetControlID(theControl, &controlID); SetRect(&bounds, 300, 328, 390, 348); CreatePushButtonControl(s->Window, &bounds, CFSTR("Set"), &theControl); SetControlReference(theControl, SETROCKETKEYBUTTON); InstallControlEventHandler(theControl, eventHandlerUPP, 1, controlEventTypes, s, NULL); controlFontStyle.flags = kControlUseJustMask; controlFontStyle.just = teFlushRight; SetRect(&bounds, 10, 358, 100, 374); CreateStaticTextControl(s->Window, &bounds, CFSTR("Rocket target:"), &controlFontStyle, &theControl); SetRect(&bounds, 110, 358, 290, 374); GetKeyDescription(s->RocketTarget, keyDescription); string = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), keyDescription); controlFontStyle.flags = (kControlUseSizeMask | kControlUseFontMask); controlFontStyle.size = 12; controlFontStyle.font = systemFont; CreateEditTextControl(s->Window, &bounds, string, 0, 0, &controlFontStyle, &theControl); CFRelease(string); SetControlData(theControl, kControlEditTextPart, kControlEditTextLockedTag, sizeof(Boolean), &locked); controlID.signature = 'idsi'; controlID.id = ROCKETTARGETKEYDISPLAY; SetControlID(theControl, &controlID); SetRect(&bounds, 300, 356, 390, 376); CreatePushButtonControl(s->Window, &bounds, CFSTR("Set"), &theControl); SetControlReference(theControl, SETROCKETTARGETKEYBUTTON); InstallControlEventHandler(theControl, eventHandlerUPP, 1, controlEventTypes, s, NULL); controlFontStyle.flags = kControlUseJustMask; controlFontStyle.just = teFlushRight; SetRect(&bounds, 10, 386, 100, 402); CreateStaticTextControl(s->Window, &bounds, CFSTR("Brake:"), &controlFontStyle, &theControl); SetRect(&bounds, 110, 386, 290, 402); GetKeyDescription(s->Brake, keyDescription); string = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), keyDescription); controlFontStyle.flags = (kControlUseSizeMask | kControlUseFontMask); controlFontStyle.size = 12; controlFontStyle.font = systemFont; CreateEditTextControl(s->Window, &bounds, string, 0, 0, &controlFontStyle, &theControl); CFRelease(string); SetControlData(theControl, kControlEditTextPart, kControlEditTextLockedTag, sizeof(Boolean), &locked); controlID.signature = 'idsi'; controlID.id = BRAKEKEYDISPLAY; SetControlID(theControl, &controlID); SetRect(&bounds, 300, 384, 390, 404); CreatePushButtonControl(s->Window, &bounds, CFSTR("Set"), &theControl); SetControlReference(theControl, SETBRAKEKEYBUTTON); InstallControlEventHandler(theControl, eventHandlerUPP, 1, controlEventTypes, s, NULL); controlFontStyle.flags = kControlUseJustMask; controlFontStyle.just = teFlushRight; SetRect(&bounds, 10, 414, 100, 430); CreateStaticTextControl(s->Window, &bounds, CFSTR("Pause:"), &controlFontStyle, &theControl); SetRect(&bounds, 110, 414, 290, 430); GetKeyDescription(s->Pause, keyDescription); string = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), keyDescription); controlFontStyle.flags = (kControlUseSizeMask | kControlUseFontMask); controlFontStyle.size = 12; controlFontStyle.font = systemFont; CreateEditTextControl(s->Window, &bounds, string, 0, 0, &controlFontStyle, &theControl); CFRelease(string); SetControlData(theControl, kControlEditTextPart, kControlEditTextLockedTag, sizeof(Boolean), &locked); controlID.signature = 'idsi'; controlID.id = PAUSEKEYDISPLAY; SetControlID(theControl, &controlID); SetRect(&bounds, 300, 412, 390, 432); CreatePushButtonControl(s->Window, &bounds, CFSTR("Set"), &theControl); SetControlReference(theControl, SETPAUSEKEYBUTTON); InstallControlEventHandler(theControl, eventHandlerUPP, 1, controlEventTypes, s, NULL); SetRect(&bounds, 155, 448, 245, 468); CreatePushButtonControl(s->Window, &bounds, CFSTR("Defaults"), &theControl); SetControlReference(theControl, DEFAULTSBUTTON); InstallControlEventHandler(theControl, eventHandlerUPP, 1, controlEventTypes, s, NULL); SetGWorld(origGWorld, origGDevice); TransWindow(s->Window, 1); } /* Silly function written to avoid using a global variable */ VSettings * SettingsAccessor(VSettings * s) { static VSettings * settings = NULL; if (s != NULL) settings = s; return settings; } void GetFullscreenSettings(VSettings * s, int * Width, int * Height, int * RefreshRate) { int count; if (s->FullScreenResolution == FULLSCREENRESNOCHANGE) { GDHandle mainDevice; mainDevice = GetMainDevice(); *Width = (**mainDevice).gdRect.right; *Height = (**mainDevice).gdRect.bottom; *RefreshRate = 0; } else { ScreenResolution * res = s->Resolutions; for (count = 0; count < s->FullScreenResolution && res != NULL; count++) { res = res->next; } if (res == NULL) { GDHandle mainDevice; mainDevice = GetMainDevice(); *Width = (**mainDevice).gdRect.right; *Height = (**mainDevice).gdRect.bottom; *RefreshRate = 0; return; } *Width = res->Width; *Height = res->Height; *RefreshRate = res->RefreshRate; } } /* This function takes a key being pressed (KeyWithModifiers(charCode, modifiers)), and a key from the VSettings struct, and determines whether or not pressedKey can be considerered to be equivalent to setKey. The keys are equivalent if: 1. Their char codes are the same, 2. If there is no other key in the settings with the same modifiers as setKey, (pressedKey's modifiers & setKey's modifiers) >= setKey's modifiers, 3. If there is another key in the settings with the same modifiers as setKey, pressedKey's modifiers == setKey's modifiers. This code uses tolower to ignore case (the shift key). This is "good enough", but to work for all keys and modifiers, it would need to do such translations as ! -> 1, å -> a,  -> k, etc. */ Boolean SettingsIsEquivalentKey(VSettings * s, SInt16 pressedKey, SInt16 setKey) { Boolean strict; if ((s->Left != setKey && (s->Left & 0xFF) == (setKey & 0xFF) && (s->Left & 0x7F00)) || (s->Right != setKey && (s->Right & 0xFF) == (setKey & 0xFF) && (s->Right & 0x7F00)) || (s->Down != setKey && (s->Down & 0xFF) == (setKey & 0xFF) && (s->Down & 0x7F00)) || (s->Up != setKey && (s->Up & 0xFF) == (setKey & 0xFF) && (s->Up & 0x7F00)) || (s->Forward != setKey && (s->Forward & 0xFF) == (setKey & 0xFF) && (s->Forward & 0x7F00)) || (s->Backward != setKey && (s->Backward & 0xFF) == (setKey & 0xFF) && (s->Backward & 0x7F00)) || (s->Bullet != setKey && (s->Bullet & 0xFF) == (setKey & 0xFF) && (s->Bullet & 0x7F00)) || (s->Rocket != setKey && (s->Rocket & 0xFF) == (setKey & 0xFF) && (s->Rocket & 0x7F00)) || (s->Brake != setKey && (s->Brake & 0xFF) == (setKey & 0xFF) && (s->Brake & 0x7F00)) || (s->Pause != setKey && (s->Pause & 0xFF) == (setKey & 0xFF) && (s->Pause & 0x7F00))) strict = 1; else strict = 0; if (strict && pressedKey != setKey) return 0; if (!strict) { pressedKey = (tolower(pressedKey & 0xFF) | (pressedKey & 0xFF00)); setKey = (tolower(setKey & 0xFF) | (setKey & 0xFF00)); } if ((pressedKey & (0xFF | (setKey & 0xFF00))) != setKey) return 0; return 1; }