diff options
Diffstat (limited to 'SrcShared/EmDlg.cpp')
-rw-r--r-- | SrcShared/EmDlg.cpp | 6319 |
1 files changed, 6319 insertions, 0 deletions
diff --git a/SrcShared/EmDlg.cpp b/SrcShared/EmDlg.cpp new file mode 100644 index 0000000..d6fa5ed --- /dev/null +++ b/SrcShared/EmDlg.cpp @@ -0,0 +1,6319 @@ +/* -*- mode: C++; tab-width: 4 -*- */ +/* ===================================================================== *\ + Copyright (c) 1999-2001 Palm, Inc. or its subsidiaries. + All rights reserved. + + This file is part of the Palm OS Emulator. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. +\* ===================================================================== */ + +#include "EmCommon.h" +#include "EmDlg.h" + +#include "DebugMgr.h" // gDebuggerGlobals +#include "EmApplication.h" // gApplication, BindPoser +#include "EmBankDRAM.h" // EmBankDRAM::ValidAddress +#include "EmBankROM.h" // EmBankROM::ValidAddress +#include "EmBankSRAM.h" // EmBankSRAM::ValidAddress +#include "EmEventPlayback.h" // GetCurrentEvent, GetNumEvents +#include "EmFileImport.h" // EmFileImport +#include "EmMinimize.h" // EmMinimize::Stop +#include "EmPatchState.h" // EmPatchState::UIInitialized +#include "EmROMTransfer.h" // EmROMTransfer +#include "EmROMReader.h" // EmROMReader +#include "EmSession.h" // gSession +#include "EmStreamFile.h" // EmStreamFile +#include "EmTransportSerial.h" // PortNameList, GetSerialPortNameList, etc. +#include "EmTransportSocket.h" // PortNameList, GetPortNameList, etc. +#include "EmTransportUSB.h" // EmTransportUSB +#include "ErrorHandling.h" // Errors::SetParameter +#include "Hordes.h" // Hordes::New +#include "LoadApplication.h" // SavePalmFile +#include "Logging.h" // FOR_EACH_LOG_PREF +#include "Miscellaneous.h" // MemoryTextList, GetMemoryTextList +#include "Platform.h" // GetString, GetMilliseconds, Beep, CopyToClipboard +#include "PreferenceMgr.h" // Preference, gEmuPrefs +#include "ROMStubs.h" // FSCustomControl, SysLibFind, IntlSetStrictChecks +#include "Strings.r.h" // kStr_AppName +#include "Skins.h" // SkinNameList + +#if HAS_TRACER +#include "TracerPlatform.h" // gTracer +#endif + +#include "algorithm" // find, remove_if, unary_function<> + + +#if !PLATFORM_UNIX +static void PrvAppendDescriptors (EmTransportDescriptorList& menuItems, + const EmTransportDescriptorList& rawItems); +static void PrvAppendDescriptors (EmTransportDescriptorList& menuItems, + const string& rawItem); +static string PrvGetMenuItemText (EmDlgID whichMenu, + const EmTransportDescriptor& item); +static void PrvAppendMenuItems (EmDlgRef dlg, EmDlgItemID dlgItem, + const EmTransportDescriptorList& menuItems, + const EmTransportDescriptor& pref, + const string& socketAddr = string()); +#endif // !PLATFORM_UNIX + + +/*********************************************************************** + * + * FUNCTION: DoGetFile + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +EmDlgItemID EmDlg::DoGetFile ( EmFileRef& result, + const string& prompt, + const EmDirRef& defaultPath, + const EmFileTypeList& filterList) +{ + DoGetFileParameters parameters (result, prompt, defaultPath, filterList); + + return EmDlg::RunDialog (EmDlg::HostRunGetFile, ¶meters); +} + + +/*********************************************************************** + * + * FUNCTION: DoGetFileList + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +EmDlgItemID EmDlg::DoGetFileList ( EmFileRefList& results, + const string& prompt, + const EmDirRef& defaultPath, + const EmFileTypeList& filterList) +{ + DoGetFileListParameters parameters (results, prompt, defaultPath, filterList); + + return EmDlg::RunDialog (EmDlg::HostRunGetFileList, ¶meters); +} + + +/*********************************************************************** + * + * FUNCTION: DoPutFile + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +EmDlgItemID EmDlg::DoPutFile ( EmFileRef& result, + const string& prompt, + const EmDirRef& defaultPath, + const EmFileTypeList& filterList, + const string& defaultName) +{ + DoPutFileParameters parameters (result, prompt, defaultPath, filterList, defaultName); + + return EmDlg::RunDialog (EmDlg::HostRunPutFile, ¶meters); +} + + +/*********************************************************************** + * + * FUNCTION: DoGetDirectory + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +EmDlgItemID EmDlg::DoGetDirectory ( EmDirRef& result, + const string& prompt, + const EmDirRef& defaultPath) +{ + DoGetDirectoryParameters parameters (result, prompt, defaultPath); + + return EmDlg::RunDialog (EmDlg::HostRunGetDirectory, ¶meters); +} + + +#pragma mark - + +/*********************************************************************** + * + * FUNCTION: DoAboutBox + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +EmDlgItemID EmDlg::DoAboutBox (void) +{ + return EmDlg::RunDialog (EmDlg::HostRunAboutBox, NULL); +} + + +#pragma mark - + +/*********************************************************************** + * + * FUNCTION: DoSessionNew + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +struct SessionNewData +{ + Configuration* cfg; + Configuration fWorkingCfg; + EmDeviceList fDevices; +}; + + +void EmDlg::PrvBuildROMMenu (const EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + SessionNewData& data = *(SessionNewData*) context.fUserData; + Configuration& cfg = data.fWorkingCfg; + + EmDlg::ClearMenu (dlg, kDlgItemNewROM); + + EmDlg::AppendToMenu (dlg, kDlgItemNewROM, Platform::GetString (kStr_OtherMRU)); + EmDlg::AppendToMenu (dlg, kDlgItemNewROM, std::string()); + + EmFileRefList romList; + gEmuPrefs->GetROMMRU (romList); + + if (romList.size () == 0) + { + EmDlg::AppendToMenu (dlg, kDlgItemNewROM, Platform::GetString (kStr_EmptyMRU)); + EmDlg::DisableMenuItem (dlg, kDlgItemNewROM, 2); + EmDlg::SetItemValue (dlg, kDlgItemNewROM, 2); + cfg.fROMFile = EmFileRef (); + } + else + { + int menuID = 2; + Bool selected = false; + + EmFileRefList::iterator iter = romList.begin (); + while (iter != romList.end ()) + { + EmDlg::AppendToMenu (dlg, kDlgItemNewROM, iter->GetName()); + + if (cfg.fROMFile == *iter) + { + EmDlg::SetItemValue (dlg, kDlgItemNewROM, menuID); + selected = true; + } + + ++iter; + ++menuID; + } + + // + // If we couldn't find the last-used ROM, try to find + // one that we can use. + // + + if (!selected) + { + EmFileRefList::iterator iter = romList.begin (); + while (iter != romList.end ()) + { + if (EmDlg::PrvCanUseROMFile (*iter) != kROMFileUnknown) + { + EmDlg::SetItemValue (dlg, kDlgItemNewROM, 2 + (iter - romList.begin ())); + cfg.fROMFile = *iter; + return; + } + + ++iter; + } + + // + // If we *still* can't find a ROM image to use, just + // zap the whole list and try again with an empty one. + // + + Preference<EmFileRefList> pref (kPrefKeyROM_MRU); + pref = EmFileRefList (); + EmDlg::PrvBuildROMMenu (context); + } + } +} + + +struct PrvSupportsROM : unary_function<EmDevice&, bool> +{ + PrvSupportsROM(EmROMReader& inROM) : ROM(inROM) {} + bool operator()(EmDevice& item) + { + return !item.SupportsROM(ROM); + } + +private: + const EmROMReader& ROM; +}; + + +void EmDlg::PrvBuildDeviceMenu (const EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + SessionNewData& data = *(SessionNewData*) context.fUserData; + Configuration& cfg = data.fWorkingCfg; + + EmDeviceList devices = EmDevice::GetDeviceList (); + + EmDeviceList::iterator iter = devices.begin(); + EmDeviceList::iterator devices_end = devices.end(); + int menuID = 0; + Bool selected = false; + unsigned int version = 0; + + PrvFilterDeviceList(cfg.fROMFile, devices, devices_end, version); + iter = devices.begin(); + + if (iter == devices_end) + { + /* We filtered out too many things, so reset to displaying all */ + devices_end = devices.end(); + } + + data.fDevices = EmDeviceList(iter, devices_end); + + EmDlg::ClearMenu (dlg, kDlgItemNewDevice); + + while (iter != devices_end) + { + EmDlg::AppendToMenu (dlg, kDlgItemNewDevice, iter->GetMenuString ()); + + if (cfg.fDevice == *iter) + { + EmDlg::SetItemValue (dlg, kDlgItemNewDevice, menuID); + selected = true; + } + + ++iter; + ++menuID; + } + + if (!selected) + { + EmDlg::SetItemValue (dlg, kDlgItemNewDevice, menuID-1); + cfg.fDevice = data.fDevices [menuID-1]; + + /* Rely on caller to (always) invoke PrvBuildSkinMenu */ + } +} + + +void EmDlg::PrvBuildSkinMenu (const EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + SessionNewData& data = *(SessionNewData*) context.fUserData; + Configuration& cfg = data.fWorkingCfg; + + SkinNameList skins; + ::SkinGetSkinNames (cfg.fDevice, skins); + SkinName chosenSkin = ::SkinGetSkinName (cfg.fDevice); + + SkinNameList::iterator iter = skins.begin (); + int menuID = 0; + + EmDlg::ClearMenu (dlg, kDlgItemNewSkin); + + while (iter != skins.end()) + { + EmDlg::AppendToMenu (dlg, kDlgItemNewSkin, *iter); + + if (chosenSkin == *iter) + { + EmDlg::SetItemValue (dlg, kDlgItemNewSkin, menuID); + } + + ++iter; + ++menuID; + } +} + + +void EmDlg::PrvBuildMemorySizeMenu (const EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + SessionNewData& data = *(SessionNewData*) context.fUserData; + Configuration& cfg = data.fWorkingCfg; + + MemoryTextList sizes; + ::GetMemoryTextList (sizes); + EmDlg::PrvFilterMemorySizes (sizes, cfg); + + MemoryTextList::iterator iter = sizes.begin(); + int menuID = 0; + Bool selected = false; + + EmDlg::ClearMenu (dlg, kDlgItemNewMemorySize); + + while (iter != sizes.end()) + { + EmDlg::AppendToMenu (dlg, kDlgItemNewMemorySize, iter->second); + + if (cfg.fRAMSize == iter->first) + { + EmDlg::SetItemValue (dlg, kDlgItemNewMemorySize, menuID); + selected = true; + } + + ++iter; + ++menuID; + } + + if (!selected) + { + EmDlg::SetItemValue (dlg, kDlgItemNewMemorySize, 0); + cfg.fRAMSize = sizes[0].first; + } +} + + +void EmDlg::PrvNewSessionSetOKButton (const EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + SessionNewData& data = *(SessionNewData*) context.fUserData; + Configuration& cfg = data.fWorkingCfg; + EmFileRef& rom = cfg.fROMFile; + + EmDlg::EnableDisableItem (dlg, kDlgItemOK, rom.IsSpecified ()); +} + + +void EmDlg::PrvFilterDeviceList(const EmFileRef& romFile, EmDeviceList& devices, + EmDeviceList::iterator& devices_end, unsigned int& version) +{ + devices_end = devices.end (); + version = 0; + + if (romFile.IsSpecified ()) + { + try + { + EmStreamFile hROM(romFile, kOpenExistingForRead); + StMemory romImage (hROM.GetLength ()); + + hROM.GetBytes (romImage.Get (), hROM.GetLength ()); + + EmROMReader ROM(romImage.Get (), hROM.GetLength ()); + + if (ROM.AcquireCardHeader ()) + { + version = ROM.GetCardVersion (); + + if (version < 5) + { + ROM.AcquireROMHeap (); + ROM.AcquireDatabases (); + ROM.AcquireFeatures (); + ROM.AcquireSplashDB (); + } + } + + devices_end = remove_if (devices.begin (), devices.end (), + PrvSupportsROM (ROM)); + } + catch (ErrCode) + { + /* On any of our errors, don't remove any devices */ + } + } +} + + +void EmDlg::PrvFilterMemorySizes (MemoryTextList& sizes, const Configuration& cfg) +{ + RAMSizeType minSize = cfg.fDevice.MinRAMSize (); + MemoryTextList::iterator iter = sizes.begin(); + + while (iter != sizes.end()) + { + if (iter->first < minSize) + { + sizes.erase (iter); + iter = sizes.begin (); + continue; + } + + ++iter; + } +} + + +// +// Check out a ROM, and see if we can find any devices for it. If +// so, return TRUE. If not and the card header is < 5, warn the +// user but return TRUE anyway. Otherwise, if we can't identify +// the ROM and it has a v5 card header or greater, show an error +// message and return FALSE. +// + +EmROMFileStatus EmDlg::PrvCanUseROMFile (EmFileRef& testRef) +{ + if (!testRef.Exists ()) + return kROMFileUnknown; + + EmDeviceList devices = EmDevice::GetDeviceList (); + EmDeviceList::iterator devices_end; + unsigned int version; + + EmDlg::PrvFilterDeviceList (testRef, devices, devices_end, version); + + if (devices_end == devices.begin ()) + { + // No devices matched + + if (version < 5) + { + return kROMFileDubious; + } + + return kROMFileUnknown; + } + + return kROMFileOK; +} + + +EmDlgFnResult EmDlg::PrvSessionNew (EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + SessionNewData& data = *(SessionNewData*) context.fUserData; + Configuration& cfg = data.fWorkingCfg; + + switch (context.fCommandID) + { + case kDlgCmdInit: + { + // + // Make a copy of the configuration that we update as the + // user makes dialog selections. + // + + cfg = *(data.cfg); + + // + // If a file is usable, make sure it is in the MRU list. + // + + if (EmDlg::PrvCanUseROMFile (cfg.fROMFile) != kROMFileUnknown) + { + gEmuPrefs->UpdateROMMRU (cfg.fROMFile); + } + + // If a file is not usable, then zap our reference to it. + // PrvBuildROMMenu will then try to find an alternate. + // + + else + { + cfg.fROMFile = EmFileRef (); + } + + // + // Build our menus. + // + + EmDlg::PrvBuildROMMenu (context); + EmDlg::PrvBuildDeviceMenu (context); + EmDlg::PrvBuildSkinMenu (context); + EmDlg::PrvBuildMemorySizeMenu (context); + EmDlg::PrvNewSessionSetOKButton (context); + break; + } + + case kDlgCmdIdle: + { + break; + } + + case kDlgCmdItemSelected: + { + switch (context.fItemID) + { + case kDlgItemOK: + { + *(data.cfg) = cfg; + + SkinNameList skins; + ::SkinGetSkinNames (cfg.fDevice, skins); + long menuID = EmDlg::GetItemValue (dlg, kDlgItemNewSkin); + + ::SkinSetSkinName (cfg.fDevice, skins[menuID]); + + // Fall thru... + } + + case kDlgItemCancel: + { + return kDlgResultClose; + } + + case kDlgItemNewDevice: + { + EmDeviceList::size_type index = EmDlg::GetItemValue (dlg, kDlgItemNewDevice); + + cfg.fDevice = data.fDevices [index]; + + EmDlg::PrvBuildSkinMenu (context); + EmDlg::PrvBuildMemorySizeMenu (context); + break; + } + + case kDlgItemNewSkin: + { + break; + } + + case kDlgItemNewMemorySize: + { + MemoryTextList sizes; + ::GetMemoryTextList (sizes); + EmDlg::PrvFilterMemorySizes (sizes, cfg); + + MemoryTextList::size_type index = EmDlg::GetItemValue (dlg, kDlgItemNewMemorySize); + + cfg.fRAMSize = sizes [index].first; + break; + } + + case kDlgItemNewROMBrowse: + break; + + case kDlgItemNewROM: + { + EmFileTypeList typeList; + typeList.push_back (kFileTypeROM); + + int romStatus = kROMFileUnknown; + EmFileRef romFileRef; + EmDirRef romDirRef (cfg.fROMFile.GetParent ()); + + // + // See what menu item was selected: "Other..." or a + // ROM from the MRU list. + // + + int index = EmDlg::GetItemValue (dlg, kDlgItemNewROM); + + // + // User selected from MRU list. + // + + if (index >= 2) + { + romFileRef = gEmuPrefs->GetIndROMMRU (index - 2); + } + + // + // Ask user for new ROM. + // + + else + { + if (EmDlg::DoGetFile (romFileRef, "Choose ROM file:", + romDirRef, typeList) == kDlgItemOK) + { + } + + // If the user cancelled from the dialog, restore the + // previously selected ROM. + + else + { + romFileRef = cfg.fROMFile; + } + } + + // Respond to the ROM selection. + + romStatus = EmDlg::PrvCanUseROMFile (romFileRef); + + if (romStatus == kROMFileDubious) + { + Errors::DoDialog (kStr_UnknownDeviceWarning, kDlgFlags_OK); + } + else if (romStatus == kROMFileUnknown) + { + Errors::DoDialog (kStr_UnknownDeviceError, kDlgFlags_OK); + } + + // + // If we can identify the ROM or we want to go ahead and + // use it anyway, update our dialog items. + // + + if (romStatus != kROMFileUnknown) + { + cfg.fROMFile = romFileRef; + gEmuPrefs->UpdateROMMRU (cfg.fROMFile); + } + + EmDlg::PrvNewSessionSetOKButton (context); + + EmDlg::PrvBuildROMMenu (context); + EmDlg::PrvBuildDeviceMenu (context); + EmDlg::PrvBuildSkinMenu (context); + EmDlg::PrvBuildMemorySizeMenu (context); + + break; + } + + default: + EmAssert (false); + } // switch (context.fItemID) + + break; + } // case kDlgCmdItemSelected + + case kDlgCmdDestroy: + break; + + case kDlgCmdPanelEnter: + case kDlgCmdPanelExit: + case kDlgCmdNone: + EmAssert (false); + break; + } // switch (command) + + return kDlgResultContinue; +} + + +EmDlgItemID EmDlg::DoSessionNew (Configuration& cfg) +{ + SessionNewData data; + data.cfg = &cfg; + + return EmDlg::RunDialog (EmDlg::PrvSessionNew, &data, kDlgSessionNew); +} + + +#pragma mark - + +/*********************************************************************** + * + * FUNCTION: DoSessionSave + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +EmDlgItemID EmDlg::DoSessionSave (const string& docName, Bool quitting) +{ + string appName = Platform::GetString (kStr_AppName); + string docName2 (docName); + + if (docName2.empty ()) + docName2 = Platform::GetString (kStr_Untitled); + + DoSessionSaveParameters parameters (appName, docName2, quitting); + + EmDlgItemID result = EmDlg::RunDialog (EmDlg::HostRunSessionSave, ¶meters); + + EmAssert (result == kDlgItemYes || result == kDlgItemNo || result == kDlgItemCancel); + + return result; +} + + +#pragma mark - + +/*********************************************************************** + * + * FUNCTION: DoHordeNew + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +struct HordeNewData +{ + HordeInfo info; + EmDatabaseList appList; +}; + + +UInt32 EmDlg::PrvSelectedAppNameToIndex (EmDatabaseList list, const string& appName) +{ + if (appName.empty ()) + return 0; + + uint32 index = 0; + + EmDatabaseList::iterator iter = list.begin (); + + while (iter != list.end ()) + { + if (strcmp ((*iter).name, appName.c_str ()) == 0) + return index; + + index += 1; + iter++; + } + + return 0; +} + + +DatabaseInfo EmDlg::PrvSelectedIndexToApp (EmDatabaseList appList, uint32 index) +{ + return appList[index]; +} + + +void EmDlg::PrvSelectedList (EmDatabaseList selectedApps, StringList &selectedAppStrings) +{ + selectedAppStrings.clear (); + + EmDatabaseList::iterator iter = selectedApps.begin (); + + while (iter != selectedApps.end ()) + { + selectedAppStrings.push_back ((*iter).name); + + ++iter; + } +} + + +EmDlgFnResult EmDlg::PrvHordeNew (EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + HordeNewData& data = *(HordeNewData*) context.fUserData; + HordeInfo& info = data.info; + + // These variables and iterators are used in multiple case statements, + // so I'm putting them here both so that the compiler will not complain, + // and so that they can be declared once, so that their names won't be + // confusing. + + Bool selected; + EmDatabaseList selectedApps; + StringList selectedAppStrings; + EmDlgListIndexList items; + EmDlgListIndexList::iterator iter1; + EmDatabaseList::iterator iter2; + UInt32 currentSelection; + + // Initialize + + selectedApps.clear (); + + switch (context.fCommandID) + { + case kDlgCmdInit: + { + // Get Horde preference settings. + + Preference<HordeInfo> pref (kPrefKeyHordeInfo); + info = *pref; + + // Install the settings into the dialog box items. + + EmDlg::SetItemValue (dlg, kDlgItemHrdStart, info.fStartNumber); + EmDlg::SetItemValue (dlg, kDlgItemHrdStop, info.fStopNumber); + EmDlg::SetItemValue (dlg, kDlgItemHrdDepthSwitch, info.fDepthSwitch); + EmDlg::SetItemValue (dlg, kDlgItemHrdDepthSave, info.fDepthSave); + EmDlg::SetItemValue (dlg, kDlgItemHrdDepthStop, info.fDepthStop); + EmDlg::SetItemValue (dlg, kDlgItemHrdCheckSwitch, info.fCanSwitch); + EmDlg::SetItemValue (dlg, kDlgItemHrdCheckSave, info.fCanSave); + EmDlg::SetItemValue (dlg, kDlgItemHrdCheckStop, info.fCanStop); + + // Get the list of applications. + + ::GetDatabases (data.appList, kApplicationsOnly); + + // Insert the names of the applications into the list. + + selected = false; + EmDatabaseList::iterator iter = data.appList.begin(); + while (iter != data.appList.end()) + { + DatabaseInfo& thisDB = *iter; + + // Add the current item. + + EmDlg::AppendToList (dlg, kDlgItemHrdAppList, thisDB.name); + + // If the item we just added is in our "selected" list, + // then select it, and add it to our list of selected + // apps (from which the first to be run will be selected + // by the user). + + EmDatabaseList::iterator begin = info.fAppList.begin (); + EmDatabaseList::iterator end = info.fAppList.end (); + + if (find (begin, end, thisDB) != end) + { + selected = true; + int index = iter - data.appList.begin(); + EmDlg::SelectListItem (dlg, kDlgItemHrdAppList, index); + selectedApps.push_back (thisDB); + } + + ++iter; + } + + // If nothing's selected, then select something (the first item). + + if (!selected) + { + EmDlg::SelectListItem (dlg, kDlgItemHrdAppList, 0); + } + + // Set up the selected apps menu from the string list we populated + // above. Default to the first app on the list (as was done previously, + // before this menu existed. + + EmDlg::PrvSelectedList (selectedApps, selectedAppStrings); + currentSelection = EmDlg::PrvSelectedAppNameToIndex (selectedApps, info.fFirstLaunchedAppName); + EmDlg::ClearMenu (dlg, kDlgItemHrdFirstLaunchedApp); + EmDlg::AppendToMenu (dlg, kDlgItemHrdFirstLaunchedApp, selectedAppStrings); + EmDlg::SetItemValue (dlg, kDlgItemHrdFirstLaunchedApp, currentSelection); + + break; + } + + case kDlgCmdIdle: + { + break; + } + + case kDlgCmdItemSelected: + { + switch (context.fItemID) + { + case kDlgItemOK: + { + info.fStartNumber = EmDlg::GetItemValue (dlg, kDlgItemHrdStart); + info.fStopNumber = EmDlg::GetItemValue (dlg, kDlgItemHrdStop); + info.fDepthSwitch = EmDlg::GetItemValue (dlg, kDlgItemHrdDepthSwitch); + info.fDepthSave = EmDlg::GetItemValue (dlg, kDlgItemHrdDepthSave); + info.fDepthStop = EmDlg::GetItemValue (dlg, kDlgItemHrdDepthStop); + info.fCanSwitch = EmDlg::GetItemValue (dlg, kDlgItemHrdCheckSwitch); + info.fCanSave = EmDlg::GetItemValue (dlg, kDlgItemHrdCheckSave); + info.fCanStop = EmDlg::GetItemValue (dlg, kDlgItemHrdCheckStop); + + // Get the indexes for the selected items. + + EmDlg::GetSelectedItems (dlg, kDlgItemHrdAppList, items); + + // first make a dummy app list, unordered, so that we can figure out + // which application was selected. + + DatabaseInfoList dummyAppList; + dummyAppList.clear (); + EmDlgListIndexList::iterator dummyIter = items.begin (); + + while (dummyIter != items.end ()) + { + DatabaseInfo dummyDbInfo = data.appList[*dummyIter]; + + dummyAppList.push_back (dummyDbInfo); + + ++dummyIter; + } + + DatabaseInfo dbInfoStartApp = EmDlg::PrvSelectedIndexToApp (dummyAppList, + EmDlg::GetItemValue (dlg, kDlgItemHrdFirstLaunchedApp)); + info.fFirstLaunchedAppName = dbInfoStartApp.name; + + // push the app to be launched first onto the stack then + // use the indexes to get the actual items, and add those + // items to the "result" container. + + info.fAppList.clear (); + info.fAppList.push_back (dbInfoStartApp); + + EmDlgListIndexList::iterator iter = items.begin (); + + while (iter != items.end ()) + { + DatabaseInfo dbInfo = data.appList[*iter]; + + // don't add the starting app twice, however harmless that may be + + if (strcmp (dbInfo.name, dbInfoStartApp.name) != 0) + { + info.fAppList.push_back (dbInfo); + } + + ++iter; + } + + // Transfer the new fields to the old fields for Hordes to use. + + info.NewToOld (); + + // Save the preferences + + Preference<HordeInfo> pref (kPrefKeyHordeInfo); + pref = info; + + // Startup up the gremlin sub-system. + + Hordes::New (info); + + // Fall thru... + } + + case kDlgItemCancel: + { + return kDlgResultClose; + } + + case kDlgItemHrdAppList: + case kDlgItemHrdFirstLaunchedApp: + + // First, clean out the list of selected applications, + // or, alternately, the list of applications that will + // be run. + + info.fAppList.clear (); + + // Get the indices of the selected items. + + EmDlg::GetSelectedItems (dlg, kDlgItemHrdAppList, items); + + // Use the indices to get the actual items, and add those + // items to the "result" container. + + iter1 = items.begin (); + while (iter1 != items.end()) + { + DatabaseInfo dbInfo = data.appList[*iter1]; + info.fAppList.push_back (dbInfo); + ++iter1; + } + + // Now that we have a current fAppList, let's update our popup + // menu for selecting the first launched app. + + // Initialize the string list that the pop-up menu will use + // to populate itself, then iterate through the list of applications. + + selectedApps.clear (); + + selected = false; + iter2 = data.appList.begin(); + while (iter2 != data.appList.end()) + { + DatabaseInfo& thisDB = *iter2; + + // If the item we just looked at is in our "selected" list, + // then select it, and add it to our list of selected + // apps (from which the first to be run will be selected + // by the user). + + EmDatabaseList::iterator begin = info.fAppList.begin (); + EmDatabaseList::iterator end = info.fAppList.end (); + + int index = iter2 - data.appList.begin(); + + if (find (begin, end, thisDB) != end) + { + selected = true; + EmDlg::SelectListItem (dlg, kDlgItemHrdAppList, index); + selectedApps.push_back (thisDB); + } + + ++iter2; + } + + // Set up the selected apps menu from the string list we populated + // above. Default to the first app on the list (as was done previously, + // before this menu existed. + + EmDlg::PrvSelectedList (selectedApps, selectedAppStrings); + + if (context.fItemID == kDlgItemHrdFirstLaunchedApp) + { + info.fFirstLaunchedAppName = selectedAppStrings + [EmDlg::GetItemValue (dlg, kDlgItemHrdFirstLaunchedApp)]; + } + else // kDlgItemHrdAppList + { + currentSelection = EmDlg::PrvSelectedAppNameToIndex (selectedApps, info.fFirstLaunchedAppName); + EmDlg::ClearMenu (dlg, kDlgItemHrdFirstLaunchedApp); + EmDlg::AppendToMenu (dlg, kDlgItemHrdFirstLaunchedApp, selectedAppStrings); + EmDlg::SetItemValue (dlg, kDlgItemHrdFirstLaunchedApp, currentSelection); + } + + break; + + case kDlgItemHrdStart: + case kDlgItemHrdStop: + case kDlgItemHrdCheckSwitch: + case kDlgItemHrdCheckSave: + case kDlgItemHrdCheckStop: + case kDlgItemHrdDepthSwitch: + case kDlgItemHrdDepthSave: + case kDlgItemHrdDepthStop: + break; + + case kDlgItemHrdSelectAll: + + // Initialize the app list that the pop-up menu will use + // to populate itself, then iterate through the list of applications. + + selectedApps.clear (); + + selected = false; + iter2 = data.appList.begin (); + while (iter2 != data.appList.end ()) + { + DatabaseInfo& thisDB = *iter2; + + // Regardless of whether this item is really selected or + // not, select it, since we are Selecting All here. + + int index = iter2 - data.appList.begin (); + + selected = true; + EmDlg::SelectListItem (dlg, kDlgItemHrdAppList, index); + selectedApps.push_back (thisDB); + + ++iter2; + } + + // Set up the selected apps menu from the string list we populated + // above. Default to the first app on the list (as was done previously, + // before this menu existed. + + EmDlg::PrvSelectedList (selectedApps, selectedAppStrings); + currentSelection = EmDlg::PrvSelectedAppNameToIndex (selectedApps, info.fFirstLaunchedAppName); + EmDlg::ClearMenu (dlg, kDlgItemHrdFirstLaunchedApp); + EmDlg::AppendToMenu (dlg, kDlgItemHrdFirstLaunchedApp, selectedAppStrings); + EmDlg::SetItemValue (dlg, kDlgItemHrdFirstLaunchedApp, currentSelection); + break; + + case kDlgItemHrdSelectNone: + + // Initialize the app list that the pop-up menu will use + // to populate itself, then iterate through the list of applications. + + selectedApps.clear (); + + iter2 = data.appList.begin (); + while (iter2 != data.appList.end ()) + { + // Regardless of whether this item is really selected or + // not, unselect it, since we are Selecting None here. + + int index = iter2 - data.appList.begin (); + selected = false; + EmDlg::UnselectListItem (dlg, kDlgItemHrdAppList, index); + + ++iter2; + } + + EmDlg::SelectListItem (dlg, kDlgItemHrdAppList, 0); + + // This set of braces is here to keep the compiler from complaining + // about initializing within a case + + { + DatabaseInfo& thisDB = *(data.appList.begin ()); + selectedApps.push_back (thisDB); + } + + // Set up the selected apps menu from the string list we populated + // above. Default to the first app on the list (as was done previously, + // before this menu existed. + + EmDlg::PrvSelectedList (selectedApps, selectedAppStrings); + + // Update our first launched app pref + + info.fFirstLaunchedAppName = selectedAppStrings[0]; + + EmDlg::ClearMenu (dlg, kDlgItemHrdFirstLaunchedApp); + EmDlg::AppendToMenu (dlg, kDlgItemHrdFirstLaunchedApp, selectedAppStrings); + EmDlg::SetItemValue (dlg, kDlgItemHrdFirstLaunchedApp, 0); + + break; + + case kDlgItemHrdLogging: + EmDlg::DoEditLoggingOptions (kGremlinLogging); + break; + + default: + EmAssert (false); + } + + break; + } + + case kDlgCmdDestroy: + break; + + case kDlgCmdPanelEnter: + case kDlgCmdPanelExit: + case kDlgCmdNone: + EmAssert (false); + break; + } + + return kDlgResultContinue; +} + + +EmDlgItemID EmDlg::DoHordeNew (void) +{ + HordeNewData data; + + return EmDlg::RunDialog (EmDlg::PrvHordeNew, &data, kDlgHordeNew); +} + + +#pragma mark - + +/*********************************************************************** + * + * FUNCTION: DoDatabaseImport + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +struct DatabaseImportData +{ + EmFileRefList fFiles; + EmFileImportMethod fMethod; + EmStreamFile* fStream; + EmFileImport* fImporter; + long fProgressCurrent; // Progress into the current file + long fProgressBase; // Progress accumulated by previous files + long fProgressMax; // Progress max value. + long fCurrentFile; // Current file we're installing. + long fDoneStart; +}; + + +EmDlgFnResult EmDlg::PrvDatabaseImport (EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + DatabaseImportData& data = *(DatabaseImportData*) context.fUserData; + + switch (context.fCommandID) + { + case kDlgCmdInit: + { + data.fStream = NULL; + data.fImporter = NULL; + + try + { + data.fCurrentFile = 0; + data.fStream = new EmStreamFile (data.fFiles[data.fCurrentFile], kOpenExistingForRead); + data.fImporter = new EmFileImport (*data.fStream, data.fMethod); + data.fProgressCurrent = -1; + data.fProgressBase = 0; + data.fProgressMax = EmFileImport::CalculateProgressMax (data.fFiles, data.fMethod); + data.fDoneStart = 0; + + long remainingFiles = data.fFiles.size () - data.fCurrentFile; + string curAppName = data.fFiles[data.fCurrentFile].GetName (); + + EmDlg::SetItemValue (dlg, kDlgItemImpNumFiles, remainingFiles); +// EmDlg::SetItemText (dlg, kDlgItemImpCurAppName, curAppName); + } + catch (...) + { + delete data.fImporter; + delete data.fStream; + + data.fStream = NULL; + data.fImporter = NULL; + } + + context.fNeedsIdle = true; + break; + } + + case kDlgCmdIdle: + { + if (data.fImporter) + { + // Prevent against recursion (can occur if we need to display an error dialog). + + static Bool inIdle; + if (inIdle) + break; + + inIdle = true; + + // Install a little bit of the file. + + ErrCode err = data.fImporter->Continue (); + + // If an error occurred, display a dialog. + + if (err) + { + string curAppName = data.fFiles[data.fCurrentFile].GetName (); + Errors::SetParameter ("%filename", curAppName); + Errors::ReportIfError (kStr_CmdInstall, err, 0, false); + } + + // Everything went OK. Get the current progress amount. + // If it changed, update the dialog. + else + { + long progressCurrent = data.fImporter->GetProgress (); + long progressMax = data.fProgressMax; + + if (data.fProgressCurrent != progressCurrent) + { + data.fProgressCurrent = progressCurrent; + + progressCurrent += data.fProgressBase; + + // Scale progressMax to < 32K (progress control on Windows + // prefers it that way). + + long divider = progressMax / (32 * 1024L) + 1; + + progressMax /= divider; + progressCurrent /= divider; + + long remainingFiles = data.fFiles.size () - data.fCurrentFile; + string curAppName = data.fFiles[data.fCurrentFile].GetName (); + + EmDlg::SetItemValue (dlg, kDlgItemImpNumFiles, remainingFiles); +// EmDlg::SetItemText (dlg, kDlgItemImpCurAppName, curAppName); + EmDlg::SetItemMax (dlg, kDlgItemImpProgress, progressMax); + EmDlg::SetItemValue (dlg, kDlgItemImpProgress, progressCurrent); + } + } + + // If we're done with this file, clean up, and prepare for any + // subsequent files. + + if (data.fImporter->Done ()) + { + gEmuPrefs->UpdatePRCMRU (data.fFiles[data.fCurrentFile]); + + data.fProgressCurrent = -1; + data.fProgressBase += data.fImporter->GetProgress (); + + delete data.fImporter; + data.fImporter = NULL; + + delete data.fStream; + data.fStream = NULL; + + data.fCurrentFile++; + if (data.fCurrentFile < (long) data.fFiles.size ()) + { + try + { + data.fStream = new EmStreamFile (data.fFiles[data.fCurrentFile], kOpenExistingForRead); + data.fImporter = new EmFileImport (*data.fStream, data.fMethod); + } + catch (...) + { + delete data.fImporter; + delete data.fStream; + + data.fStream = NULL; + data.fImporter = NULL; + } + } + else + { + // There are no more files to install. Initialize our + // counter used to delay the closing of the dialog. + + data.fDoneStart = Platform::GetMilliseconds (); + } + } + + inIdle = false; + } + + // After we're done installing all files, wait a little bit in order to + // see the completed progress dialog. + + else if (Platform::GetMilliseconds () - data.fDoneStart > 500) + { + return kDlgResultClose; + } + + break; + } + + case kDlgCmdItemSelected: + { + switch (context.fItemID) + { + case kDlgItemOK: + { + // Fall thru... + } + + case kDlgItemCancel: + { + if (context.fItemID == kDlgItemCancel) + data.fImporter->Cancel (); + + delete data.fImporter; + data.fImporter = NULL; + + return kDlgResultClose; + } + + case kDlgItemImpNumFiles: +// case kDlgItemImpCurAppName: + case kDlgItemImpProgress: + break; + + default: + EmAssert (false); + } + + break; + } + + case kDlgCmdDestroy: + break; + + case kDlgCmdPanelEnter: + case kDlgCmdPanelExit: + case kDlgCmdNone: + EmAssert (false); + break; + } + + return kDlgResultContinue; +} + + +EmDlgItemID EmDlg::DoDatabaseImport (const EmFileRefList& files, EmFileImportMethod method) +{ + // Validate the list of files. + + EmFileRefList newFileList; + EmFileRefList::const_iterator iter = files.begin (); + + while (iter != files.end ()) + { + if (iter->IsSpecified () && iter->Exists ()) + { + newFileList.push_back (*iter); + } + else + { + // !!! Report that the file doesn't exist. + } + + ++iter; + } + + if (newFileList.size () <= 0) + { + return kDlgItemOK; + } + + // Stop the session so that the files can be safely loaded. + + EmAssert (gSession); + EmSessionStopper stopper (gSession, kStopOnSysCall); + if (!stopper.Stopped ()) + return kDlgItemCancel; + + DatabaseImportData data; + + data.fFiles = newFileList; + data.fMethod = method; + + return EmDlg::RunDialog (EmDlg::PrvDatabaseImport, &data, kDlgDatabaseImport); +} + + +#pragma mark - + +/*********************************************************************** + * + * FUNCTION: DoDatabaseExport + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +struct ExportDatbaseData +{ + EmDatabaseList fAllDatabases; +}; + + +Bool EmDlg::PrvExportFile (const DatabaseInfo& db) +{ + UInt16 dbAttributes; + UInt32 dbType; + UInt32 dbCreator; + ErrCode err = ::DmDatabaseInfo (db.cardNo, db.dbID, NULL, + &dbAttributes, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, &dbType, &dbCreator); + Errors::ThrowIfPalmError (err); + + // Figure out the file type. + + EmFileType type = kFileTypeNone; + + if ((dbAttributes & dmHdrAttrResDB) != 0) + { + type = kFileTypePalmApp; + } + else + { + if (dbCreator == sysFileCClipper) + type = kFileTypePalmQA; + else + type = kFileTypePalmDB; + } + + EmFileRef result; + string prompt ("Save as..."); + EmDirRef defaultPath; + EmFileTypeList filterList; + string defaultName (db.dbName); + + string extension = type == kFileTypePalmApp ? ".prc" : + type == kFileTypePalmQA ? ".pqa" : ".pdb"; + + if (!::EndsWith (defaultName.c_str (), extension.c_str ())) + { + defaultName += extension; + } + + filterList.push_back (type); + filterList.push_back (kFileTypePalmAll); + filterList.push_back (kFileTypeAll); + + EmDlgItemID item = EmDlg::DoPutFile ( result, + prompt, + defaultPath, + filterList, + defaultName); + + if (item == kDlgItemOK) + { + EmStreamFile stream (result, kCreateOrEraseForUpdate, + kFileCreatorInstaller, type); + + ::SavePalmFile (stream, db.cardNo, db.dbName); + } + + return (item == kDlgItemOK); +} + + +EmDlgFnResult EmDlg::PrvDatabaseExport (EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + ExportDatbaseData& data = *(ExportDatbaseData*) context.fUserData; + + switch (context.fCommandID) + { + case kDlgCmdInit: + { + // Get the list of installed databases. + + ::GetDatabases (data.fAllDatabases, kAllDatabases); + + // Add then names of the databases to the list. + + EmDatabaseList::iterator iter = data.fAllDatabases.begin(); + while (iter != data.fAllDatabases.end()) + { + string itemText (iter->dbName); + + // If the database name is different from any user-visible + // name, then use both of them. + + if (strcmp (iter->dbName, iter->name) != 0) + { + itemText += " ("; + itemText += iter->name; + itemText += ")"; + } + + EmDlg::AppendToList (dlg, kDlgItemExpDbList, itemText.c_str ()); + ++iter; + } + break; + } + + case kDlgCmdIdle: + { + break; + } + + case kDlgCmdItemSelected: + { + switch (context.fItemID) + { + case kDlgItemOK: + { + // Get the indexes for the selected items. + + EmDlgListIndexList items; + EmDlg::GetSelectedItems(dlg, kDlgItemExpDbList, items); + + // Export each item. + + Bool cancel = false; + EmDlgListIndexList::iterator iter = items.begin (); + while (!cancel && iter != items.end ()) + { + DatabaseInfo& db = data.fAllDatabases[*iter]; + + cancel = !EmDlg::PrvExportFile (db); + + ++iter; + } + + if (cancel) + break; + + // Fall thru... + } + + case kDlgItemCancel: + { + return kDlgResultClose; + } + + case kDlgItemExpDbList: + break; + + default: + EmAssert (false); + } + + break; + } + + case kDlgCmdDestroy: + break; + + case kDlgCmdPanelEnter: + case kDlgCmdPanelExit: + case kDlgCmdNone: + EmAssert (false); + break; + } + + return kDlgResultContinue; +} + + +EmDlgItemID EmDlg::DoDatabaseExport (void) +{ + ExportDatbaseData data; + + return EmDlg::RunDialog (EmDlg::PrvDatabaseExport, &data, kDlgDatabaseExport); +} + + +#pragma mark - + +/*********************************************************************** + * + * FUNCTION: DoReset + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +EmDlgFnResult EmDlg::PrvReset (EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + EmResetType& choice = *(EmResetType*) context.fUserData; + + switch (context.fCommandID) + { + case kDlgCmdInit: + { + EmDlg::SetItemValue (dlg, kDlgItemRstSoft, 1); + break; + } + + case kDlgCmdIdle: + { + break; + } + + case kDlgCmdItemSelected: + { + switch (context.fItemID) + { + case kDlgItemOK: + { + if (EmDlg::GetItemValue (dlg, kDlgItemRstSoft)) + { + choice = kResetSoft; + } + else if (EmDlg::GetItemValue (dlg, kDlgItemRstHard)) + { + choice = kResetHard; + } + else + { + EmAssert (EmDlg::GetItemValue (dlg, kDlgItemRstDebug)); + choice = kResetDebug; + } + + if (EmDlg::GetItemValue (dlg, kDlgItemRstNoExt) != 0) + { + choice = (EmResetType) ((int) choice | kResetNoExt); + } + // Fall thru... + } + + case kDlgItemCancel: + { + return kDlgResultClose; + } + + case kDlgItemRstSoft: + case kDlgItemRstHard: + case kDlgItemRstDebug: + case kDlgItemRstNoExt: + break; + + default: + EmAssert (false); + } + + break; + } + + case kDlgCmdDestroy: + break; + + case kDlgCmdPanelEnter: + case kDlgCmdPanelExit: + case kDlgCmdNone: + EmAssert (false); + break; + } + + return kDlgResultContinue; +} + + +EmDlgItemID EmDlg::DoReset (EmResetType& type) +{ + return EmDlg::RunDialog (EmDlg::PrvReset, &type, kDlgReset); +} + + +#pragma mark - + +/*********************************************************************** + * + * FUNCTION: DoROMTransferQuery + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +struct ROMTransferQueryData +{ +#if !PLATFORM_UNIX + EmTransportDescriptorList fPortNameList; +#endif + EmTransport::Config** fConfig; +}; + + +#if !PLATFORM_UNIX +void EmDlg::PrvGetDlqPortItemList (EmTransportDescriptorList& menuItems) +{ + EmTransportDescriptorList descListSerial; + EmTransportDescriptorList descListUSB; + + EmTransportSerial::GetDescriptorList (descListSerial); + EmTransportUSB::GetDescriptorList (descListUSB); + + ::PrvAppendDescriptors (menuItems, descListSerial); + ::PrvAppendDescriptors (menuItems, descListUSB); +} +#endif + + +void EmDlg::PrvConvertBaudListToStrings (const EmTransportSerial::BaudList& baudList, + StringList& baudStrList) +{ + EmTransportSerial::BaudList::const_iterator iter = baudList.begin(); + while (iter != baudList.end()) + { + char buffer[20]; + ::FormatInteger (buffer, *iter); + strcat (buffer, " bps"); + baudStrList.push_back (buffer); + ++iter; + } +} + +EmDlgFnResult EmDlg::PrvROMTransferQuery (EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + ROMTransferQueryData& data = *(ROMTransferQueryData*) context.fUserData; + + switch (context.fCommandID) + { + case kDlgCmdInit: + { + // On Unix, the port is specified in an edit text item. + // On other platforms, we present a list of ports in a menu. + + // !!! TBD: restore port setting from a preference. + +#if PLATFORM_UNIX + EmDlg::SetItemText (dlg, kDlgItemDlqPortList, "/dev/ttyS0"); +#else + Preference<string> pref (kPrefKeyPortDownload); + ::PrvAppendMenuItems (dlg, kDlgItemDlqPortList, data.fPortNameList, *pref); +#endif + + EmTransportSerial::BaudList baudList; + EmTransportSerial::GetSerialBaudList (baudList); + + StringList baudStrList; + EmDlg::PrvConvertBaudListToStrings (baudList, baudStrList); + + EmDlg::AppendToMenu (dlg, kDlgItemDlqBaudList, baudStrList); + EmDlg::SetItemValue (dlg, kDlgItemDlqBaudList, 0); // 115K baud + + // Load the instructions string. Load it in 9 parts, + // as the entire string is greater than: + // + // Rez can handle on the Mac. + // MSDev's string editor on Windows. + // The ANSI-allowed string length (for Unix). + + string ins; + for (int ii = 0; ii < 9; ++ii) + { + string temp = Platform::GetString (kStr_ROMTransferInstructions + ii); + ins += temp; + } + + EmDlg::SetItemText (dlg, kDlgItemDlqInstructions, ins); + + break; + } + + case kDlgCmdIdle: + { + break; + } + + case kDlgCmdItemSelected: + { + switch (context.fItemID) + { + case kDlgItemOK: + { + // Get the selected settings. + +#if PLATFORM_UNIX + string portName = EmDlg::GetItemText (dlg, kDlgItemDlqPortList); + EmTransportDescriptor portDesc (portName); +#else + long portNum = EmDlg::GetItemValue (dlg, kDlgItemDlqPortList); + EmTransportDescriptor portDesc = data.fPortNameList [portNum]; + string portName = portDesc.GetSchemeSpecific (); +#endif + + EmTransportType transportType; + transportType = portDesc.GetType (); + + switch (transportType) + { + case kTransportSerial: + { + long baudNum = EmDlg::GetItemValue (dlg, kDlgItemDlqBaudList); + + EmTransportSerial::BaudList baudList; + EmTransportSerial::GetSerialBaudList (baudList); + + EmTransportSerial::ConfigSerial* serConfig = new EmTransportSerial::ConfigSerial; + + serConfig->fPort = portName; + serConfig->fBaud = baudList [baudNum]; + serConfig->fParity = EmTransportSerial::kNoParity; + serConfig->fStopBits = 1; + serConfig->fDataBits = 8; + serConfig->fHwrHandshake = true; + + *data.fConfig = serConfig; + + break; + } + + case kTransportUSB: + { + EmTransportUSB::ConfigUSB* usbConfig = new EmTransportUSB::ConfigUSB; + + *data.fConfig = usbConfig; + + break; + } + + case kTransportSocket: + case kTransportNull: + break; + + case kTransportUnknown: + EmAssert (false); + break; + } + + // Fall thru... + } + + case kDlgItemCancel: + { + return kDlgResultClose; + } + + case kDlgItemDlqInstructions: + case kDlgItemDlqPortList: + case kDlgItemDlqBaudList: + break; + + default: + EmAssert (false); + } + + break; + } + + case kDlgCmdDestroy: + break; + + case kDlgCmdPanelEnter: + case kDlgCmdPanelExit: + case kDlgCmdNone: + EmAssert (false); + break; + } + + return kDlgResultContinue; +} + + +EmDlgItemID EmDlg::DoROMTransferQuery (EmTransport::Config*& config) +{ + config = NULL; + + ROMTransferQueryData data; + data.fConfig = &config; + +#if !PLATFORM_UNIX + // Generate the list here, and do it just once. It's important to + // do it just once, as the list of ports could possibly change between + // the time they're added to the menu and the time one is chosen to + // be returned. This could happen, for example, on the Mac where + // opening a USB connection creates a new "virtual" serial port. + + EmDlg::PrvGetDlqPortItemList (data.fPortNameList); +#endif + + return EmDlg::RunDialog (EmDlg::PrvROMTransferQuery, &data, kDlgROMTransferQuery); +} + + +#pragma mark - + +/*********************************************************************** + * + * FUNCTION: DoROMTransferProgress + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +EmDlgFnResult EmDlg::PrvROMTransferProgress (EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + EmROMTransfer& transferer = *(EmROMTransfer*) context.fUserData; + + switch (context.fCommandID) + { + case kDlgCmdInit: + { + context.fNeedsIdle = true; + break; + } + + case kDlgCmdIdle: + { + try + { + if (!transferer.Continue (dlg)) + return kDlgResultClose; + } + catch (ErrCode /*err*/) + { + // !!! Should report error code? + return kDlgResultClose; + } + + break; + } + + case kDlgCmdItemSelected: + { + switch (context.fItemID) + { + case kDlgItemOK: + { + // Fall thru... + } + + case kDlgItemCancel: + { + transferer.Abort (dlg); + return kDlgResultClose; + } + + default: + EmAssert (false); + } + + break; + } + + case kDlgCmdDestroy: + break; + + case kDlgCmdPanelEnter: + case kDlgCmdPanelExit: + case kDlgCmdNone: + EmAssert (false); + break; + } + + return kDlgResultContinue; +} + + +EmDlgItemID EmDlg::DoROMTransferProgress (EmROMTransfer& transferer) +{ + return EmDlg::RunDialog (EmDlg::PrvROMTransferProgress, &transferer, kDlgROMTransferProgress); +} + + +#pragma mark - + +/*********************************************************************** + * + * FUNCTION: DoEditPreferences + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +struct EditPreferencesData +{ + EmTransportDescriptor prefPortSerial; // Selected menu item for serial + EmTransportDescriptor prefPortIR; // Selected menu item for IR + EmTransportDescriptor prefPortMystery; // Selected menu item for Mystery + bool prefRedirectNetLib; + bool prefEnableSounds; + CloseActionType prefCloseAction; + string prefUserName; + +#if !PLATFORM_UNIX + string prefPortSerialSocket; // Socket address for serial + string prefPortIRSocket; // Socket address for serial + + EmTransportDescriptorList menuItemsSerial; // Built-up menu for serial + EmTransportDescriptorList menuItemsIR; // Built-up menu for IR + EmTransportDescriptorList menuItemsMystery; // Built-up menu for Mystery +#endif +}; + + +void EmDlg::PrvEditPrefToDialog (EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + EditPreferencesData& data = *(EditPreferencesData*) context.fUserData; + +#if !PLATFORM_UNIX + + // ------------------------------------------------------------ + // Set up the port menus. + // ------------------------------------------------------------ + + EmDlg::ClearMenu (dlg, kDlgItemPrfRedirectSerial); + EmDlg::ClearMenu (dlg, kDlgItemPrfRedirectIR); + EmDlg::ClearMenu (dlg, kDlgItemPrfRedirectMystery); + + ::PrvAppendMenuItems (dlg, kDlgItemPrfRedirectSerial, data.menuItemsSerial, data.prefPortSerial, data.prefPortSerialSocket); + ::PrvAppendMenuItems (dlg, kDlgItemPrfRedirectIR, data.menuItemsIR, data.prefPortIR, data.prefPortIRSocket); + ::PrvAppendMenuItems (dlg, kDlgItemPrfRedirectMystery, data.menuItemsMystery, data.prefPortMystery); + + // IR emulation appears to be consistantly flaky no matter what's + // used for the underlying transport (local TCP, serial, etc.). + // So always disable it for now, until we can figure out why it's + // flakey and can work around it. + + EmDlg::DisableItem (dlg, kDlgItemPrfRedirectIR); + +#else + + // ------------------------------------------------------------ + // Set up the port text items. + // ------------------------------------------------------------ + + EmDlg::SetItemText (dlg, kDlgItemPrfRedirectSerial, data.prefPortSerial.GetMenuName ()); + EmDlg::SetItemText (dlg, kDlgItemPrfRedirectIR, data.prefPortIR.GetMenuName ()); + EmDlg::SetItemText (dlg, kDlgItemPrfRedirectMystery, data.prefPortMystery.GetMenuName ()); + +#endif + + // ------------------------------------------------------------ + // Set up the Redirect NetLib and Enable Sounds checkboxes. + // ------------------------------------------------------------ + + EmDlg::SetItemValue (dlg, kDlgItemPrfRedirectNetLib, data.prefRedirectNetLib); + EmDlg::SetItemValue (dlg, kDlgItemPrfEnableSound, data.prefEnableSounds); + + // ------------------------------------------------------------ + // Set up the Close Action radio buttons. + // ------------------------------------------------------------ + + if (data.prefCloseAction == kSaveAlways) + { + EmDlg::SetItemValue (dlg, kDlgItemPrfSaveAlways, 1); + } + else if (data.prefCloseAction == kSaveAsk) + { + EmDlg::SetItemValue (dlg, kDlgItemPrfSaveAsk, 1); + } + else + { + EmDlg::SetItemValue (dlg, kDlgItemPrfSaveNever, 1); + } + + // ------------------------------------------------------------ + // Set up the HotSync User Name edit text item. + // ------------------------------------------------------------ + + EmDlg::SetItemText (dlg, kDlgItemPrfUserName, data.prefUserName); +} + + +void EmDlg::PrvEditPrefFromDialog (EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + EditPreferencesData& data = *(EditPreferencesData*) context.fUserData; + +#if !PLATFORM_UNIX + + // ------------------------------------------------------------ + // Save the port settings. + // ------------------------------------------------------------ + + data.prefPortSerial = data.menuItemsSerial [EmDlg::GetItemValue (dlg, kDlgItemPrfRedirectSerial)]; + data.prefPortIR = data.menuItemsIR [EmDlg::GetItemValue (dlg, kDlgItemPrfRedirectIR)]; + data.prefPortMystery = data.menuItemsMystery [EmDlg::GetItemValue (dlg, kDlgItemPrfRedirectMystery)]; + +#else + + // ------------------------------------------------------------ + // Save the port settings. + // ------------------------------------------------------------ + + data.prefPortSerial = EmDlg::GetItemText (dlg, kDlgItemPrfRedirectSerial); + data.prefPortIR = EmDlg::GetItemText (dlg, kDlgItemPrfRedirectIR); + data.prefPortMystery = EmDlg::GetItemText (dlg, kDlgItemPrfRedirectMystery); + +#endif + + // ------------------------------------------------------------ + // Save the Redirect NetLib and Enable Sounds settings. + // ------------------------------------------------------------ + + data.prefRedirectNetLib = EmDlg::GetItemValue (dlg, kDlgItemPrfRedirectNetLib) != 0; + data.prefEnableSounds = EmDlg::GetItemValue (dlg, kDlgItemPrfEnableSound) != 0; + + // ------------------------------------------------------------ + // Save the Close Action settings. + // ------------------------------------------------------------ + + if (EmDlg::GetItemValue (dlg, kDlgItemPrfSaveAlways) != 0) + { + data.prefCloseAction = kSaveAlways; + } + else if (EmDlg::GetItemValue (dlg, kDlgItemPrfSaveAsk) != 0) + { + data.prefCloseAction = kSaveAsk; + } + else + { + data.prefCloseAction = kSaveNever; + } + + // ------------------------------------------------------------ + // Save the HotSync User Name setting. + // ------------------------------------------------------------ + + data.prefUserName = EmDlg::GetItemText (dlg, kDlgItemPrfUserName); +} + + +#if !PLATFORM_UNIX + +// Build up descriptors lists for each menu. + +void EmDlg::PrvBuildDescriptorLists (EmDlgContext& context) +{ + EditPreferencesData& data = *(EditPreferencesData*) context.fUserData; + + EmTransportDescriptorList descListNull; + EmTransportDescriptorList descListSerial; + EmTransportDescriptorList descListSocket; + + EmTransportNull::GetDescriptorList (descListNull); + EmTransportSerial::GetDescriptorList (descListSerial); + EmTransportSocket::GetDescriptorList (descListSocket); + + data.menuItemsSerial.clear (); + data.menuItemsIR.clear (); + data.menuItemsMystery.clear (); + + ::PrvAppendDescriptors (data.menuItemsSerial, descListNull); + ::PrvAppendDescriptors (data.menuItemsSerial, descListSerial); + ::PrvAppendDescriptors (data.menuItemsSerial, descListSocket); + + ::PrvAppendDescriptors (data.menuItemsIR, descListNull); + ::PrvAppendDescriptors (data.menuItemsIR, descListSerial); + ::PrvAppendDescriptors (data.menuItemsIR, descListSocket); + + ::PrvAppendDescriptors (data.menuItemsMystery, descListNull); + ::PrvAppendDescriptors (data.menuItemsMystery, descListSerial); + + // Find the socket descriptors, and add the socket-specific information. + + { + EmTransportDescriptorList::iterator iter = data.menuItemsSerial.begin (); + while (iter != data.menuItemsSerial.end ()) + { + if (iter->GetType () == kTransportSocket) + { + *iter = EmTransportDescriptor (iter->GetScheme () + ":" + data.prefPortSerialSocket); + break; + } + + ++iter; + } + } + + { + EmTransportDescriptorList::iterator iter = data.menuItemsIR.begin (); + while (iter != data.menuItemsIR.end ()) + { + if (iter->GetType () == kTransportSocket) + { + *iter = EmTransportDescriptor (iter->GetScheme () + ":" + data.prefPortIRSocket); + break; + } + + ++iter; + } + } +} + +#endif // !UNIX + + +// Transfer the preferences into local variables so that we can +// change them with impunity. Also build up some menu lists. + +void EmDlg::PrvGetEditPreferences (EmDlgContext& context) +{ + EditPreferencesData& data = *(EditPreferencesData*) context.fUserData; + + Preference<EmTransportDescriptor> prefPortSerial (kPrefKeyPortSerial); + Preference<EmTransportDescriptor> prefPortIR (kPrefKeyPortIR); + Preference<EmTransportDescriptor> prefPortMystery (kPrefKeyPortMystery); + Preference<bool> prefRedirectNetLib (kPrefKeyRedirectNetLib); + Preference<bool> prefEnableSounds (kPrefKeyEnableSounds); + Preference<CloseActionType> prefCloseAction (kPrefKeyCloseAction); + Preference<string> prefUserName (kPrefKeyUserName); + + Preference<string> prefPortSerialSocket(kPrefKeyPortSerialSocket); + Preference<string> prefPortIRSocket (kPrefKeyPortIRSocket); + + data.prefPortSerial = *prefPortSerial; + data.prefPortIR = *prefPortIR; + data.prefPortMystery = *prefPortMystery; + data.prefRedirectNetLib = *prefRedirectNetLib; + data.prefEnableSounds = *prefEnableSounds; + data.prefCloseAction = *prefCloseAction; + data.prefUserName = *prefUserName; + +#if !PLATFORM_UNIX + data.prefPortSerialSocket = *prefPortSerialSocket; + data.prefPortIRSocket = *prefPortIRSocket; + + EmDlg::PrvBuildDescriptorLists (context); +#endif +} + + +// Transfer our update preferences back to the Preferences system. + +void EmDlg::PrvPutEditPreferences (EmDlgContext& context) +{ + EditPreferencesData& data = *(EditPreferencesData*) context.fUserData; + + Preference<EmTransportDescriptor> prefPortSerial (kPrefKeyPortSerial); + Preference<EmTransportDescriptor> prefPortIR (kPrefKeyPortIR); + Preference<EmTransportDescriptor> prefPortMystery (kPrefKeyPortMystery); + Preference<bool> prefRedirectNetLib (kPrefKeyRedirectNetLib); + Preference<bool> prefEnableSounds (kPrefKeyEnableSounds); + Preference<CloseActionType> prefCloseAction (kPrefKeyCloseAction); + Preference<string> prefUserName (kPrefKeyUserName); + + Preference<string> prefPortSerialSocket(kPrefKeyPortSerialSocket); + Preference<string> prefPortIRSocket (kPrefKeyPortIRSocket); + + prefPortSerial = data.prefPortSerial; + prefPortIR = data.prefPortIR; + prefPortMystery = data.prefPortMystery; + prefRedirectNetLib = data.prefRedirectNetLib; + prefEnableSounds = data.prefEnableSounds; + prefCloseAction = data.prefCloseAction; + prefUserName = data.prefUserName; + +#if !PLATFORM_UNIX + prefPortSerialSocket = data.prefPortSerialSocket; + prefPortIRSocket = data.prefPortIRSocket; +#endif +} + + +Bool EmDlg::PrvEditPreferencesValidate (EmDlgContext& context) +{ + EditPreferencesData& data = *(EditPreferencesData*) context.fUserData; + + if (data.prefUserName.size () > dlkMaxUserNameLength) + { + EmDlg::DoCommonDialog (kStr_UserNameTooLong, kDlgFlags_OK); + return false; + } + + return true; +} + + +#if !PLATFORM_UNIX +// Fetch an IP address from the user, store it in the appropriate +// field, and rebuild the menus. + +void EmDlg::PrvGetPrefSocketAddress (EmDlgContext& context) +{ + EmAssert ((context.fItemID == kDlgItemPrfRedirectSerial) || + (context.fItemID == kDlgItemPrfRedirectIR)); + + EmDlgRef dlg = context.fDlg; + EditPreferencesData& data = *(EditPreferencesData*) context.fUserData; + + // Move current settings into our local data. + + EmDlg::PrvEditPrefFromDialog (context); + + // Figure out which descriptor was selected. + + string address; + EmTransportDescriptor selectedDesc; + + if (context.fItemID == kDlgItemPrfRedirectSerial) + { + address = data.prefPortSerialSocket; + selectedDesc = data.menuItemsSerial [EmDlg::GetItemValue (dlg, context.fItemID)]; + } + else if (context.fItemID == kDlgItemPrfRedirectIR) + { + address = data.prefPortIRSocket; + selectedDesc = data.menuItemsIR [EmDlg::GetItemValue (dlg, context.fItemID)]; + } + + // If it was for the socket menu item, get the address. + + if (selectedDesc.GetType () == kTransportSocket) + { + EmDlgItemID item = EmDlg::DoGetSocketAddress (address); + + if (item == kDlgItemOK) + { + EmTransportDescriptor prefDesc = EmTransportDescriptor ( + selectedDesc.GetScheme () + ":" + address); + + if (context.fItemID == kDlgItemPrfRedirectSerial) + { + data.prefPortSerial = prefDesc; + data.prefPortSerialSocket = address; + } + else if (context.fItemID == kDlgItemPrfRedirectIR) + { + data.prefPortIR = prefDesc; + data.prefPortIRSocket = address; + } + + EmDlg::PrvBuildDescriptorLists (context); + EmDlg::PrvEditPrefToDialog (context); + } + } +} +#endif + +EmDlgFnResult EmDlg::PrvEditPreferences (EmDlgContext& context) +{ + switch (context.fCommandID) + { + case kDlgCmdInit: + { + EmDlg::PrvGetEditPreferences (context); + EmDlg::PrvEditPrefToDialog (context); + break; + } + + case kDlgCmdIdle: + { + break; + } + + case kDlgCmdItemSelected: + { + switch (context.fItemID) + { + case kDlgItemOK: + { + // Make sure all the preferences are something we can live with. + + EmDlg::PrvEditPrefFromDialog (context); + if (!EmDlg::PrvEditPreferencesValidate (context)) + break; + + // Save the preferences. + + EmDlg::PrvPutEditPreferences (context); + + // Update the emulated environment with the + // new preferences. + + if (gSession && EmPatchState::UIInitialized ()) + { + EmSessionStopper stopper (gSession, kStopOnSysCall); + if (stopper.Stopped ()) + { + EditPreferencesData& data = *(EditPreferencesData*) context.fUserData; + ::SetHotSyncUserName (data.prefUserName.c_str ()); + + // Update the transports used for UART emulation. + + gEmuPrefs->SetTransports (); + } + } + + // Fall thru... + } + + case kDlgItemCancel: + { + return kDlgResultClose; + } + + case kDlgItemPrfRedirectSerial: + case kDlgItemPrfRedirectIR: +#if !PLATFORM_UNIX + EmDlg::PrvGetPrefSocketAddress (context); +#endif + break; + + case kDlgItemPrfRedirectMystery: + case kDlgItemPrfRedirectNetLib: + case kDlgItemPrfEnableSound: + case kDlgItemPrfSaveAlways: + case kDlgItemPrfSaveAsk: + case kDlgItemPrfSaveNever: + case kDlgItemPrfUserName: + break; + + default: + EmAssert (false); + } + + break; + } + + case kDlgCmdDestroy: + break; + + case kDlgCmdPanelEnter: + case kDlgCmdPanelExit: + case kDlgCmdNone: + EmAssert (false); + break; + } + + return kDlgResultContinue; +} + + +EmDlgItemID EmDlg::DoEditPreferences (void) +{ + EditPreferencesData data; + + EmDlgID dlgID = gApplication->IsBoundFully () + ? kDlgEditPreferencesFullyBound + : kDlgEditPreferences; + + return EmDlg::RunDialog (EmDlg::PrvEditPreferences, &data, dlgID); +} + + +#pragma mark - + +/*********************************************************************** + * + * FUNCTION: DoEditLoggingOptions + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +struct EditLoggingOptionsData +{ + LoggingType fActiveSet; + + // Define a "uint8" variable for each of the logging options we + // support. The name of each variable is of the form "f<name>", + // where "<name>" is what appear in the FOR_EACH_LOG_PREF macro. + +#undef DEFINE_STORAGE +#define DEFINE_STORAGE(name) uint8 f##name; + FOR_EACH_LOG_PREF (DEFINE_STORAGE) +}; + + +void EmDlg::PrvFetchLoggingPrefs (EmDlgContext& context) +{ + // Transfer all of the logging values from the preferences + // to our local storage. + + EditLoggingOptionsData& data = *(EditLoggingOptionsData*) context.fUserData; + + #undef GET_PREF + #define GET_PREF(name) \ + { \ + Preference<uint8> pref(kPrefKey##name); \ + data.f##name = *pref; \ + } + + FOR_EACH_LOG_PREF (GET_PREF) +} + + +void EmDlg::PrvInstallLoggingPrefs (EmDlgContext& context) +{ + EmSessionStopper stopper (gSession, kStopNow); + + // Transfer all of the logging values from our local + // storages to the preferences system. + + EditLoggingOptionsData& data = *(EditLoggingOptionsData*) context.fUserData; + + #undef SET_PREF + #define SET_PREF(name) \ + { \ + Preference<uint8> pref(kPrefKey##name); \ + pref = data.f##name; \ + } + + FOR_EACH_LOG_PREF (SET_PREF) +} + + +void EmDlg::PrvLoggingPrefsToButtons (EmDlgContext& context) +{ + // Set the buttons in the current panel. + + EditLoggingOptionsData& data = *(EditLoggingOptionsData*) context.fUserData; + int bitmask = data.fActiveSet; + + #undef TO_BUTTON + #define TO_BUTTON(name) \ + EmDlg::SetItemValue (context.fDlg, kDlgItemLog##name, (data.f##name & bitmask) != 0); + + FOR_EACH_LOG_PREF (TO_BUTTON) +} + + +void EmDlg::PrvLoggingPrefsFromButtons (EmDlgContext& context) +{ + // Update our local preference values from the buttons in the current panel. + + EditLoggingOptionsData& data = *(EditLoggingOptionsData*) context.fUserData; + int bitmask = data.fActiveSet; + + #undef FROM_BUTTON + #define FROM_BUTTON(name) \ + if (EmDlg::GetItemValue (context.fDlg, kDlgItemLog##name) != 0) \ + data.f##name |= bitmask; \ + else \ + data.f##name &= ~bitmask; + + FOR_EACH_LOG_PREF (FROM_BUTTON) +} + + +EmDlgFnResult EmDlg::PrvEditLoggingOptions (EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + EditLoggingOptionsData& data = *(EditLoggingOptionsData*) context.fUserData; + + switch (context.fCommandID) + { + case kDlgCmdInit: + { + EmDlg::PrvFetchLoggingPrefs (context); + EmDlg::PrvLoggingPrefsToButtons (context); + + if (data.fActiveSet == kNormalLogging) + EmDlg::SetItemValue (dlg, kDlgItemLogNormal, 1); + else + EmDlg::SetItemValue (dlg, kDlgItemLogGremlins, 1); + + // Disable unsupported options. + + EmDlg::DisableItem (dlg, kDlgItemLogLogCPUOpcodes); + EmDlg::DisableItem (dlg, kDlgItemLogLogApplicationCalls); + + break; + } + + case kDlgCmdIdle: + { + break; + } + + case kDlgCmdItemSelected: + { + switch (context.fItemID) + { + case kDlgItemOK: + { + EmDlg::PrvLoggingPrefsFromButtons (context); + EmDlg::PrvInstallLoggingPrefs (context); + + // Fall thru... + } + + case kDlgItemCancel: + { + return kDlgResultClose; + } + + case kDlgItemLogNormal: + case kDlgItemLogGremlins: + EmDlg::PrvLoggingPrefsFromButtons (context); + if (context.fItemID == kDlgItemLogNormal) + data.fActiveSet = kNormalLogging; + else + data.fActiveSet = kGremlinLogging; + EmDlg::PrvLoggingPrefsToButtons (context); + break; + + #undef DUMMY_CASE + #define DUMMY_CASE(name) case kDlgItemLog##name: + FOR_EACH_LOG_PREF (DUMMY_CASE) + break; + + default: + EmAssert (false); + } + + break; + } + + case kDlgCmdDestroy: + break; + + case kDlgCmdPanelEnter: + case kDlgCmdPanelExit: + case kDlgCmdNone: + EmAssert (false); + break; + } + + return kDlgResultContinue; +} + + +EmDlgItemID EmDlg::DoEditLoggingOptions (LoggingType initialSet) +{ + EditLoggingOptionsData data; + + data.fActiveSet = initialSet; + + return EmDlg::RunDialog (EmDlg::PrvEditLoggingOptions, &data, kDlgEditLogging); +} + + +#pragma mark - + +/*********************************************************************** + * + * FUNCTION: DoEditDebuggingOptions + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +struct EditDebuggingOptionsData +{ + // Define a "Bool" variable for each of the debugging options we + // support. The name of each variable is of the form "f<name>", + // where "<name>" is what appear in the FOR_EACH_REPORT_PREF macro. + +#undef DEFINE_STORAGE +#define DEFINE_STORAGE(name) Bool f##name; + FOR_EACH_REPORT_PREF (DEFINE_STORAGE) + + DEFINE_STORAGE(DialogBeep) +}; + + +void EmDlg::PrvFetchDebuggingPrefs (EmDlgContext& context) +{ + // Transfer all of the debugging values from the preferences + // to our local storage. + + EditDebuggingOptionsData& data = *(EditDebuggingOptionsData*) context.fUserData; + + #undef GET_PREF + #define GET_PREF(name) \ + { \ + Preference<Bool> pref(kPrefKey##name); \ + data.f##name = *pref; \ + } + + FOR_EACH_REPORT_PREF (GET_PREF) + + GET_PREF(DialogBeep) +} + + +void EmDlg::PrvInstallDebuggingPrefs (EmDlgContext& context) +{ + EmSessionStopper stopper (gSession, kStopNow); + + // Transfer all of the debugging values from our local + // storages to the preferences system. + + EditDebuggingOptionsData& data = *(EditDebuggingOptionsData*) context.fUserData; + + #undef SET_PREF + #define SET_PREF(name) \ + { \ + Preference<Bool> pref(kPrefKey##name); \ + pref = data.f##name; \ + } + + FOR_EACH_REPORT_PREF (SET_PREF) + + + SET_PREF(DialogBeep) +} + + +void EmDlg::PrvDebuggingPrefsToButtons (EmDlgContext& context) +{ + // Set the buttons in the current panel. + + EditDebuggingOptionsData& data = *(EditDebuggingOptionsData*) context.fUserData; + + #undef TO_BUTTON + #define TO_BUTTON(name) \ + EmDlg::SetItemValue (context.fDlg, kDlgItemDbg##name, data.f##name); + + FOR_EACH_REPORT_PREF (TO_BUTTON) + + TO_BUTTON(DialogBeep) +} + + +void EmDlg::PrvDebuggingPrefsFromButtons (EmDlgContext& context) +{ + // Update our local preference values from the buttons in the current panel. + + EditDebuggingOptionsData& data = *(EditDebuggingOptionsData*) context.fUserData; + + #undef FROM_BUTTON + #define FROM_BUTTON(name) \ + data.f##name = EmDlg::GetItemValue (context.fDlg, kDlgItemDbg##name) != 0; + + FOR_EACH_REPORT_PREF (FROM_BUTTON) + + FROM_BUTTON(DialogBeep) +} + + +EmDlgFnResult EmDlg::PrvEditDebuggingOptions (EmDlgContext& context) +{ +// EmDlgRef dlg = context.fDlg; +// EditDebuggingOptionsData& data = *(EditDebuggingOptionsData*) context.fUserData; + + switch (context.fCommandID) + { + case kDlgCmdInit: + { + EmDlg::PrvFetchDebuggingPrefs (context); + EmDlg::PrvDebuggingPrefsToButtons (context); + break; + } + + case kDlgCmdIdle: + { + break; + } + + case kDlgCmdItemSelected: + { + switch (context.fItemID) + { + case kDlgItemOK: + { + EmDlg::PrvDebuggingPrefsFromButtons (context); + EmDlg::PrvInstallDebuggingPrefs (context); + + // Fall thru... + } + + case kDlgItemCancel: + { + return kDlgResultClose; + } + + #undef DUMMY_CASE + #define DUMMY_CASE(name) case kDlgItemDbg##name: + FOR_EACH_REPORT_PREF (DUMMY_CASE) + + DUMMY_CASE(DialogBeep) + break; + + default: + EmAssert (false); + } + + break; + } + + case kDlgCmdDestroy: + break; + + case kDlgCmdPanelEnter: + case kDlgCmdPanelExit: + case kDlgCmdNone: + EmAssert (false); + break; + } + + return kDlgResultContinue; +} + + +EmDlgItemID EmDlg::DoEditDebuggingOptions (void) +{ + EditDebuggingOptionsData data; + + return EmDlg::RunDialog (EmDlg::PrvEditDebuggingOptions, &data, kDlgEditDebugging); +} + + +#pragma mark - + +/*********************************************************************** + * + * FUNCTION: DoEditDebuggingOptions + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +// Map from an EmErrorHandlingOption to the menu string for it. + +struct +{ + EmErrorHandlingOption fOption; + StrCode fString; +} kMenuItemText[] = +{ + { kShow, kStr_ShowInDialog }, + { kContinue, kStr_AutomaticallyContinue }, + { kQuit, kStr_AutomaticallyQuit }, + { kSwitch, kStr_NextGremlin } +}; + + +// Struct representing a single menu item. + +struct EmErrorHandlingMenuItemBundle +{ + EmErrorHandlingOption fOption; +}; + + +// Menu items for the four menus in the dialog box. + +EmErrorHandlingMenuItemBundle kMenuItems1[] = +{ + { kShow }, + { kContinue } +}; + + +EmErrorHandlingMenuItemBundle kMenuItems2[] = +{ + { kShow }, + { kQuit } +}; + + +EmErrorHandlingMenuItemBundle kMenuItems3[] = +{ + { kShow }, + { kContinue }, + { kSwitch } +}; + + +EmErrorHandlingMenuItemBundle kMenuItems4[] = +{ + { kShow }, + { kQuit }, + { kSwitch } +}; + + +// Struct containing all information for a single menu in the dialog box. + +struct EmErrorHandlingMenuBundle +{ + EmErrorHandlingMenuItemBundle* fMenuItems; // Menu items + size_t fNumItems; // Number of menu items + EmDlgItemID fDlgItem; // Dialog item to get these items + PrefKeyType fPrefKey; // Preference to get selected option + PrefKeyType fLogPrefKey; // Logging option to turn on + LoggingType fLogType; // Flag in the logging option to turn on + Bool fEnableLogging; // True if logging option should be turned on +}; + +// Information for the Gremlins Off / On Warning menu. + +EmErrorHandlingMenuBundle gMenu1 = +{ + kMenuItems1, + countof (kMenuItems1), + kDlgItemErrWarningOff, + kPrefKeyWarningOff, + kPrefKeyLogWarningMessages, + kNormalLogging +}; + +// Information for the Gremlins Off / On Error menu. + +EmErrorHandlingMenuBundle gMenu2 = +{ + kMenuItems2, + countof (kMenuItems2), + kDlgItemErrErrorOff, + kPrefKeyErrorOff, + kPrefKeyLogErrorMessages, + kNormalLogging +}; + +// Information for the Gremlins On / On Warning menu. + +EmErrorHandlingMenuBundle gMenu3 = +{ + kMenuItems3, + countof (kMenuItems3), + kDlgItemErrWarningOn, + kPrefKeyWarningOn, + kPrefKeyLogWarningMessages, + kGremlinLogging +}; + +// Information for the Gremlins On / On Error menu. + +EmErrorHandlingMenuBundle gMenu4 = +{ + kMenuItems4, + countof (kMenuItems4), + kDlgItemErrErrorOn, + kPrefKeyErrorOn, + kPrefKeyLogErrorMessages, + kGremlinLogging +}; + + +// Return the text of the menu item for the given error handling option. +// Makes use of the kMenuItemText map above. + +string EmDlg::PrvMenuItemText (EmErrorHandlingOption item) +{ + for (size_t ii = 0; ii < countof (kMenuItemText); ++ii) + { + if (kMenuItemText[ii].fOption == item) + { + return Platform::GetString (kMenuItemText[ii].fString); + } + } + + EmAssert (false); + + return string(); +} + + +// Build up the menu items in the dialog, based on the information in +// the given EmErrorHandlingMenuBundle. Results are stored in "items". + +void EmDlg::PrvBuildMenu ( EmErrorHandlingMenuBundle& menu, + StringList& items) +{ + size_t numItems = menu.fNumItems; + + for (size_t ii = 0; ii < numItems; ++ii) + { + items.push_back (EmDlg::PrvMenuItemText (menu.fMenuItems[ii].fOption)); + } +}; + + +// Find the menu item index in the given menu corresponding to the +// given EmErrorHandlingOption. This function is used when selecting +// the initial menu item based on the current preference settings. + +long EmDlg::PrvFindIndex ( EmErrorHandlingMenuBundle& menu, + EmErrorHandlingOption toFind) +{ + size_t numItems = menu.fNumItems; + + for (size_t ii = 0; ii < numItems; ++ii) + { + if (menu.fMenuItems[ii].fOption == toFind) + return (long) ii; + } + + return -1; +} + + +// Build up the menu items in the dialog for the given menu, and select +// the initial menu item based on the current preference setting. + +void EmDlg::PrvErrorHandlingToDialog ( EmDlgContext& context, + EmErrorHandlingMenuBundle& menu) +{ + EmDlgRef dlg = context.fDlg; + + StringList menuItemsText; + EmDlg::PrvBuildMenu (menu, menuItemsText); + + Preference<EmErrorHandlingOption> pref (menu.fPrefKey); + long index = EmDlg::PrvFindIndex (menu, *pref); + if (index < 0) + index = 0; + + EmDlg::AppendToMenu (dlg, menu.fDlgItem, menuItemsText); + EmDlg::SetItemValue (dlg, menu.fDlgItem, index); +} + + +// Take the currently selected item and use it to establish a new +// preference setting. + +void EmDlg::PrvErrorHandlingFromDialog (EmDlgContext& context, + EmErrorHandlingMenuBundle& menu) +{ + EmDlgRef dlg = context.fDlg; + long index = EmDlg::GetItemValue (dlg, menu.fDlgItem); + + EmAssert (index >= 0); + EmAssert (index < (long) menu.fNumItems); + + Preference<EmErrorHandlingOption> pref (menu.fPrefKey); + pref = menu.fMenuItems[index].fOption; +} + + +// Ask the user if they'd like us to change the Logging Option settings +// for them as appropriate. + +EmDlgItemID EmDlg::PrvAskChangeLogging (void) +{ + string msg = Platform::GetString (kStr_MustTurnOnLogging); + EmDlgItemID result = EmDlg::DoCommonDialog (msg, kDlgFlags_YES_No); + + return result; +} + + +// Check a single menu item selection, seeing if a corresponding change +// in the logging options needs to be made. + +void EmDlg::PrvCheckSetting ( EmDlgContext& context, + EmErrorHandlingMenuBundle& menu) +{ + Preference<uint8> pref (menu.fLogPrefKey); + + EmDlgRef dlg = context.fDlg; + long index = EmDlg::GetItemValue (dlg, menu.fDlgItem); + EmErrorHandlingOption option = menu.fMenuItems[index].fOption; + + Bool needLogging = option != kShow; + Bool haveLogging = (*pref & menu.fLogType) != 0; + + menu.fEnableLogging = needLogging && !haveLogging; +} + + +// Check all menus to see if any of them require a change in the logging options. + +Bool EmDlg::PrvCheckSettings (EmDlgContext& context) +{ + EmDlg::PrvCheckSetting (context, gMenu1); + EmDlg::PrvCheckSetting (context, gMenu2); + EmDlg::PrvCheckSetting (context, gMenu3); + EmDlg::PrvCheckSetting (context, gMenu4); + + return + gMenu1.fEnableLogging || + gMenu2.fEnableLogging || + gMenu3.fEnableLogging || + gMenu4.fEnableLogging; +} + + +// Enable a single logging option corresponding to the given menu, +// if appropriate. + +void EmDlg::PrvEnableLoggingOption (EmErrorHandlingMenuBundle& menu) +{ + if (menu.fEnableLogging) + { + Preference<uint8> pref (menu.fLogPrefKey); + pref = *pref | menu.fLogType; + } +} + + +// Enable all necessary logging options. + +void EmDlg::PrvEnableLoggingOptions (void) +{ + EmSessionStopper stopper (gSession, kStopNow); + + EmDlg::PrvEnableLoggingOption (gMenu1); + EmDlg::PrvEnableLoggingOption (gMenu2); + EmDlg::PrvEnableLoggingOption (gMenu3); + EmDlg::PrvEnableLoggingOption (gMenu4); +} + + +EmDlgFnResult EmDlg::PrvErrorHandling (EmDlgContext& context) +{ + switch (context.fCommandID) + { + case kDlgCmdInit: + { + EmDlg::PrvErrorHandlingToDialog (context, gMenu1); + EmDlg::PrvErrorHandlingToDialog (context, gMenu2); + EmDlg::PrvErrorHandlingToDialog (context, gMenu3); + EmDlg::PrvErrorHandlingToDialog (context, gMenu4); + + break; + } + + case kDlgCmdIdle: + { + break; + } + + case kDlgCmdItemSelected: + { + switch (context.fItemID) + { + case kDlgItemOK: + { + if (EmDlg::PrvCheckSettings (context)) + { + if (EmDlg::PrvAskChangeLogging () == kDlgItemNo) + { + // Don't commit the changes; don't close the dialog. + return kDlgResultContinue; + } + + EmDlg::PrvEnableLoggingOptions (); + } + + EmSessionStopper stopper (gSession, kStopNow); + + EmDlg::PrvErrorHandlingFromDialog (context, gMenu1); + EmDlg::PrvErrorHandlingFromDialog (context, gMenu2); + EmDlg::PrvErrorHandlingFromDialog (context, gMenu3); + EmDlg::PrvErrorHandlingFromDialog (context, gMenu4); + } + + case kDlgItemCancel: + { + return kDlgResultClose; + } + + case kDlgItemErrWarningOff: + case kDlgItemErrErrorOff: + case kDlgItemErrWarningOn: + case kDlgItemErrErrorOn: + break; + + default: + EmAssert (false); + } + + break; + } + + case kDlgCmdDestroy: + break; + + case kDlgCmdPanelEnter: + case kDlgCmdPanelExit: + case kDlgCmdNone: + EmAssert (false); + break; + } + + return kDlgResultContinue; +} + + +EmDlgItemID EmDlg::DoEditErrorHandling (void) +{ + return EmDlg::RunDialog (EmDlg::PrvErrorHandling, NULL, kDlgEditErrorHandling); +} + + +#pragma mark - + +/*********************************************************************** + * + * FUNCTION: DoEditSkins + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +struct EditSkinsData +{ + EmDevice fDevice; + SkinNameList fSkins; +}; + + +EmDlgFnResult EmDlg::PrvEditSkins (EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + EditSkinsData& data = *(EditSkinsData*) context.fUserData; + + switch (context.fCommandID) + { + case kDlgCmdInit: + { + // Get the skin the user has chosen. + + SkinName prefSkin = ::SkinGetSkinName (data.fDevice); + + // Add each skin in the list to the UI element. + + Bool selected = false; + int index = 0; + SkinNameList::iterator skinIter = data.fSkins.begin(); + + while (skinIter != data.fSkins.end()) + { + EmDlg::AppendToList (dlg, kDlgItemSknSkinList, *skinIter); + + // Select the currently-used skin. + + if (*skinIter == prefSkin) + { + EmDlg::SelectListItem (dlg, kDlgItemSknSkinList, index); + selected = true; + } + + ++index; + ++skinIter; + } + + // Ensure that *something* was selected. + + if (!selected) + { + EmDlg::SelectListItem (dlg, kDlgItemSknSkinList, 0); + } + + // Set up the checkboxes + + { + Preference<ScaleType> pref (kPrefKeyScale); + EmDlg::SetItemValue (dlg, kDlgItemSknDoubleScale, (*pref == 2) ? 1 : 0); + } + + { + Preference<RGBType> pref (kPrefKeyBackgroundColor); + EmDlg::SetItemValue (dlg, kDlgItemSknWhiteBackground, pref.Loaded () ? 1 : 0); + } + + { + Preference<bool> pref (kPrefKeyDimWhenInactive); + EmDlg::SetItemValue (dlg, kDlgItemSknDim, *pref ? 1 : 0); + } + + { + Preference<bool> pref (kPrefKeyShowDebugMode); + EmDlg::SetItemValue (dlg, kDlgItemSknRed, *pref ? 1 : 0); + } + + { + Preference<bool> pref (kPrefKeyShowGremlinMode); + EmDlg::SetItemValue (dlg, kDlgItemSknGreen, *pref ? 1 : 0); + } + + { + Preference<bool> pref (kPrefKeyStayOnTop); + EmDlg::SetItemValue (dlg, kDlgItemSknStayOnTop, *pref ? 1 : 0); + } + + break; + } + + case kDlgCmdIdle: + { + break; + } + + case kDlgCmdItemSelected: + { + switch (context.fItemID) + { + case kDlgItemOK: + { + // Update the skin choice. + + // Get the selected skin. + + EmDlgListIndex index = EmDlg::GetSelectedItem (dlg, kDlgItemSknSkinList); + EmAssert (index != kDlgItemListNone); + + // Update the preferences. + + ::SkinSetSkinName (data.fDevice, data.fSkins[index]); + + // Update the scale. + + Preference<ScaleType> prefScale (kPrefKeyScale); + prefScale = (GetItemValue (dlg, kDlgItemSknDoubleScale) != 0) ? 2 : 1; + + // Update the background color. + + if (EmDlg::GetItemValue (dlg, kDlgItemSknWhiteBackground) != 0) + { + RGBType color (0xFF, 0xFF, 0xFF); + Preference<RGBType> prefBackgroundColor (kPrefKeyBackgroundColor); + prefBackgroundColor = color; + } + else + { + gPrefs->DeletePref (kPrefKeyBackgroundColor); + } + + // Update "Dim When Inactive" setting. + + { + Preference<bool> pref (kPrefKeyDimWhenInactive); + pref = (GetItemValue (dlg, kDlgItemSknDim) != 0) ? true : false; + } + + // Update "Show Debug Mode" setting. + + { + Preference<bool> pref (kPrefKeyShowDebugMode); + pref = (GetItemValue (dlg, kDlgItemSknRed) != 0) ? true : false; + } + + // Update "Show Gremlin Mode" setting. + + { + Preference<bool> pref (kPrefKeyShowGremlinMode); + pref = (GetItemValue (dlg, kDlgItemSknGreen) != 0) ? true : false; + } + + // Update the stay on top setting. + + { + Preference<bool> pref (kPrefKeyStayOnTop); + pref = (GetItemValue (dlg, kDlgItemSknStayOnTop) != 0) ? true : false; + } + + // Fall thru... + } + + case kDlgItemCancel: + { + return kDlgResultClose; + } + + case kDlgItemSknSkinList: + case kDlgItemSknDoubleScale: + case kDlgItemSknWhiteBackground: + case kDlgItemSknDim: + case kDlgItemSknRed: + case kDlgItemSknGreen: + case kDlgItemSknStayOnTop: + break; + + default: + EmAssert (false); + } + + break; + } + + case kDlgCmdDestroy: + break; + + case kDlgCmdPanelEnter: + case kDlgCmdPanelExit: + case kDlgCmdNone: + EmAssert (false); + break; + } + + return kDlgResultContinue; +} + + +EmDlgItemID EmDlg::DoEditSkins (void) +{ + Preference<Configuration> prefConfiguration (kPrefKeyLastConfiguration); + Configuration cfg = *prefConfiguration; + + EditSkinsData data; + data.fDevice = cfg.fDevice; + + ::SkinGetSkinNames (data.fDevice, data.fSkins); + + return EmDlg::RunDialog (EmDlg::PrvEditSkins, &data, kDlgEditSkins); +} + + +#pragma mark - + +/*********************************************************************** + * + * FUNCTION: DoEditHostFSOptions + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +struct EditHostFSOptionsData +{ + SlotInfoList fWorkingInfo; +}; + +const int kMaxVolumes = 8; + +void EmDlg::PrvEditHostFSOptionsOK (EmDlgContext& context) +{ + EditHostFSOptionsData& data = *(EditHostFSOptionsData*) context.fUserData; + + EmSessionStopper stopper (gSession, kStopOnSysCall); + + Preference<SlotInfoList> pref (kPrefKeySlotList); + SlotInfoList origList = *pref; + pref = data.fWorkingInfo; + + // For any that changed, mount/unmount the cards. + + UInt16 refNum; + Err err = ::SysLibFind ("HostFS Library", &refNum); + + if (err != errNone || refNum == sysInvalidRefNum) + { + EmDlg::DoCommonDialog (kStr_NeedHostFS, kDlgFlags_OK); + return; + } + + // We've made sure that we have the HostFS library, + // so it's OK to try to notify it about changes. + + // Iterate over all the items before the user changed + // them in the Options dialog. + + SlotInfoList::iterator iter1 = origList.begin (); + while (iter1 != origList.end ()) + { + // Iterate over all the items *after* the user changed + // them in the dialog. + + SlotInfoList::iterator iter2 = data.fWorkingInfo.begin (); + while (iter2 != data.fWorkingInfo.end ()) + { + // Compare one item from the "before" list to one item + // in the "after" list. If they're for the same volume, + // we will want to compare them further. + + if (iter1->fSlotNumber == iter2->fSlotNumber) + { + // The volume in this slot either used to be mounted + // and now is not, or didn't used to be mounted but + // now is. We'll need to tell the HostFS library. + + if (iter1->fSlotOccupied != iter2->fSlotOccupied) + { + const UInt32 kCreator = 'pose'; + const UInt16 kMounted = 1; + const UInt16 kUnmounted = 0; + + UInt16 selector = iter2->fSlotOccupied ? kMounted : kUnmounted; + void* cardNum = (void*) iter1->fSlotNumber; + + // Note, in order to make this call, the CPU should be stopped + // in the UI task. That's because mounting and unmounting can + // send out notification. If the notification is sent out while + // the current Palm OS task is not the UI task, then the + // notification manager calls SysTaskWait. This will switch + // to another task if it can, and prime a timer to re-awake + // the background task if not. However, this timer is based + // on an interrupt going off, and while we're calling into the + // ROM, interrupts are turned off, leading to a hang. + // Therefore, is is imperative that we call this function + // while the UI task is the current task. + + ::FSCustomControl (refNum, kCreator, selector, cardNum, NULL); + } + + break; + } + + ++iter2; + } + + ++iter1; + } +} + + +EmDlgFnResult EmDlg::PrvEditHostFSOptions (EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + EditHostFSOptionsData& data = *(EditHostFSOptionsData*) context.fUserData; + + switch (context.fCommandID) + { + case kDlgCmdInit: + { + // Get the current preferences. + + Preference<SlotInfoList> pref (kPrefKeySlotList); + data.fWorkingInfo = *pref; + + // Make sure there are at least kMaxVolume entries. If not, then + // fill in the missing ones. + + long curSize = data.fWorkingInfo.size (); + while (curSize < kMaxVolumes) + { + SlotInfoType info; + info.fSlotNumber = curSize + 1; + info.fSlotOccupied = false; + data.fWorkingInfo.push_back (info); + + curSize++; + } + + // Install the volumes into the list. + + EmDlg::ClearList (dlg, kDlgItemHfsList); + + for (int ii = 0; ii < kMaxVolumes; ++ii) + { + EmDlg::AppendToList (dlg, kDlgItemHfsList, string (1, (char) ('1' + ii))); + } + + // Select one of the volumes. + + EmDlg::SelectListItem (dlg, kDlgItemHfsList, 0); + + // Call ourselves to make sure that the other dialog + // items are properly initialized in light of the + // currently selected item. + + EmDlgContext subContext (context); + subContext.fCommandID = kDlgCmdItemSelected; + subContext.fItemID = kDlgItemHfsList; + EmDlg::PrvEditHostFSOptions (subContext); + + break; + } + + case kDlgCmdIdle: + { + break; + } + + case kDlgCmdItemSelected: + { + switch (context.fItemID) + { + case kDlgItemOK: + { + // User pressed OK, save the changes. + + EmDlg::PrvEditHostFSOptionsOK (context); + + // Fall thru... + } + + case kDlgItemCancel: + { + return kDlgResultClose; + } + + case kDlgItemHfsList: + { + // User changed the currently selected card. + + EmDlgListIndex item = EmDlg::GetSelectedItem (dlg, kDlgItemHfsList); + if (item >= 0) + { + SlotInfoType& info = data.fWorkingInfo[item]; + + // Get the path to the card's root. If empty, display + // a default message so that the user doesn't just see + // a blank pane. + + string fullPath (info.fSlotRoot.GetFullPath ()); + if (fullPath.empty ()) + fullPath = "<Not selected>"; + + // Set the root path text and the button that says if + // it's mounted or not. + + EmDlg::SetItemText (dlg, kDlgItemHfsPath, fullPath); + EmDlg::SetItemValue (dlg, kDlgItemHfsMounted, info.fSlotOccupied); + } + break; + } + + case kDlgItemHfsPath: + break; + + case kDlgItemHfsMounted: + { + // User toggled the checkbox that says whether or not the + // card is mounted. Save the new setting. + + EmDlgListIndex item = EmDlg::GetSelectedItem (dlg, kDlgItemHfsList); + if (item >= 0) + { + SlotInfoType& info = data.fWorkingInfo[item]; + + info.fSlotOccupied = EmDlg::GetItemValue (dlg, kDlgItemHfsMounted); + } + break; + } + + case kDlgItemHfsBrowse: + { + // User clicked on the Browse button. Bring up a + // "Get Directory" dialog. + + EmDlgListIndex item = EmDlg::GetSelectedItem (dlg, kDlgItemHfsList); + if (item >= 0) + { + SlotInfoType& info = data.fWorkingInfo[item]; + + EmDirRef result; + string prompt ("Select a directory:"); + EmDirRef defaultPath (info.fSlotRoot); + + if (EmDlg::DoGetDirectory (result, prompt, defaultPath) == kDlgItemOK) + { + info.fSlotRoot = result; + EmDlg::SetItemText (dlg, kDlgItemHfsPath, result.GetFullPath ()); + } + } + break; + } + + default: + EmAssert (false); + } + + break; + } + + case kDlgCmdDestroy: + break; + + case kDlgCmdPanelEnter: + case kDlgCmdPanelExit: + case kDlgCmdNone: + EmAssert (false); + break; + } + + return kDlgResultContinue; +} + + +EmDlgItemID EmDlg::DoEditHostFSOptions (void) +{ + EditHostFSOptionsData data; + + return EmDlg::RunDialog (EmDlg::PrvEditHostFSOptions, &data, kDlgEditHostFS); +} + + +#pragma mark - + +/*********************************************************************** + * + * FUNCTION: DoEditBreakpoints + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +struct EditCodeBreakpointData +{ + Bool fEnabled; + emuptr fAddress; + string fCondition; +}; + + +struct EditBreakpointsData +{ + EditCodeBreakpointData fCodeBreakpoints[dbgTotalBreakpoints]; +}; + + +// Enable or disable the Edit and Clear buttons. + +void EmDlg::PrvEnableCodeBreakpointControls (EmDlgContext& context, bool enable) +{ + EmDlgRef dlg = context.fDlg; + + EmDlg::EnableDisableItem (dlg, kDlgItemBrkButtonEdit, enable); + EmDlg::EnableDisableItem (dlg, kDlgItemBrkButtonClear, enable); +} + + +// Enable or disable the Start Address and Number Of Bytes edit items. + +void EmDlg::PrvEnableDataBreakpointControls (EmDlgContext& context, bool enable) +{ + EmDlgRef dlg = context.fDlg; + + EmDlg::EnableDisableItem (dlg, kDlgItemBrkStartAddress, enable); + EmDlg::EnableDisableItem (dlg, kDlgItemBrkNumberOfBytes, enable); +} + + +// Install the current set of code breakpoints into the list item. + +void EmDlg::PrvRefreshCodeBreakpointList (EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + EditBreakpointsData& data = *(EditBreakpointsData*) context.fUserData; + + EmDlgListIndex selected = EmDlg::GetSelectedItem (dlg, kDlgItemBrkList); + + EmDlg::ClearList (dlg, kDlgItemBrkList); + + for (int ii = 0; ii < dbgTotalBreakpoints; ++ii) + { + char text[256]; + + if (data.fCodeBreakpoints[ii].fEnabled) + { + sprintf (text, "at 0x%08lX", data.fCodeBreakpoints[ii].fAddress); + string condition = data.fCodeBreakpoints[ii].fCondition; + if (!condition.empty ()) + { + strcat (text, " when "); + strcat (text, condition.c_str ()); + } + } + else + { + sprintf (text, "(#%d - not set)", ii); + } + + EmDlg::AppendToList (dlg, kDlgItemBrkList, text); + } + + if (selected != kDlgItemListNone) + { + EmDlg::SelectListItem (dlg, kDlgItemBrkList, selected); + } +} + + +// Copy the breakpoint information from the Debugger globals. + +void EmDlg::PrvGetCodeBreakpoints (EmDlgContext& context) +{ + EditBreakpointsData& data = *(EditBreakpointsData*) context.fUserData; + + for (int ii = 0; ii < dbgTotalBreakpoints; ++ii) + { + data.fCodeBreakpoints[ii].fEnabled = gDebuggerGlobals.bp[ii].enabled; + data.fCodeBreakpoints[ii].fAddress = (emuptr) gDebuggerGlobals.bp[ii].addr; + data.fCodeBreakpoints[ii].fCondition = ""; + + BreakpointCondition* c = gDebuggerGlobals.bpCondition[ii]; + if (c) + { + data.fCodeBreakpoints[ii].fCondition = c->source; + } + } +} + + +// Install the breakpoint information into the Debugger globals. + +void EmDlg::PrvSetCodeBreakpoints (EmDlgContext& context) +{ + EditBreakpointsData& data = *(EditBreakpointsData*) context.fUserData; + + for (int ii = 0; ii < dbgTotalBreakpoints; ++ii) + { + if (data.fCodeBreakpoints[ii].fEnabled) + { + BreakpointCondition* c = NULL; + + string condition = data.fCodeBreakpoints[ii].fCondition; + if (!condition.empty ()) + { + c = Debug::NewBreakpointCondition (condition.c_str ()); + } + + Debug::SetBreakpoint (ii, data.fCodeBreakpoints[ii].fAddress, c); + } + else + { + Debug::ClearBreakpoint (ii); + } + } +} + + +EmDlgFnResult EmDlg::PrvEditBreakpoints (EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + EditBreakpointsData& data = *(EditBreakpointsData*) context.fUserData; + + switch (context.fCommandID) + { + case kDlgCmdInit: + { + // Set up the list of code breakpoints. + + EmDlg::PrvGetCodeBreakpoints (context); + EmDlg::PrvRefreshCodeBreakpointList (context); + + // Initially no breakpoint is selected in the list, so the "edit" and + // "clear" buttons should be disabled. + + EmDlg::PrvEnableCodeBreakpointControls (context, false); + + // Set up the data breakpoint items + + char text[256]; + + EmDlg::SetItemValue (dlg, kDlgItemBrkCheckEnabled, + gDebuggerGlobals.watchEnabled ? 1 : 0); + + sprintf (text, "0x%08lX", gDebuggerGlobals.watchAddr); + EmDlg::SetItemText (dlg, kDlgItemBrkStartAddress, text); + + sprintf (text, "0x%08lX", gDebuggerGlobals.watchBytes); + EmDlg::SetItemText (dlg, kDlgItemBrkNumberOfBytes, text); + + EmDlg::PrvEnableDataBreakpointControls (context, gDebuggerGlobals.watchEnabled); + + break; + } + + case kDlgCmdIdle: + { + break; + } + + case kDlgCmdItemSelected: + { + switch (context.fItemID) + { + case kDlgItemOK: + { + // User pressed OK, save the changes. + + EmSessionStopper stopper (gSession, kStopNow); + + // Set the code breakpoints + + EmDlg::PrvSetCodeBreakpoints (context); + + + // Set data breakpoint + + gDebuggerGlobals.watchEnabled = EmDlg::GetItemValue (dlg, kDlgItemBrkCheckEnabled) != 0; + + if (gDebuggerGlobals.watchEnabled) + { + gDebuggerGlobals.watchAddr = EmDlg::GetItemValue (dlg, kDlgItemBrkStartAddress); + gDebuggerGlobals.watchBytes = EmDlg::GetItemValue (dlg, kDlgItemBrkNumberOfBytes); + } + + // Fall thru... + } + + case kDlgItemCancel: + { + return kDlgResultClose; + } + + case kDlgItemBrkList: + { + EmDlgListIndex selected = EmDlg::GetSelectedItem (dlg, kDlgItemBrkList); + EmDlg::PrvEnableCodeBreakpointControls (context, selected != kDlgItemListNone); + break; + } + + case kDlgItemBrkButtonEdit: + { + EmDlgListIndex selected = EmDlg::GetSelectedItem (dlg, kDlgItemBrkList); + if (selected != kDlgItemListNone) + { + EmDlg::DoEditCodeBreakpoint (data.fCodeBreakpoints[selected]); + EmDlg::PrvRefreshCodeBreakpointList (context); + } + break; + } + + case kDlgItemBrkButtonClear: + { + EmDlgListIndex selected = EmDlg::GetSelectedItem (dlg, kDlgItemBrkList); + if (selected != kDlgItemListNone) + { + data.fCodeBreakpoints[selected].fEnabled = false; + EmDlg::PrvRefreshCodeBreakpointList (context); + } + break; + } + + case kDlgItemBrkCheckEnabled: + { + long enabled = EmDlg::GetItemValue (dlg, kDlgItemBrkCheckEnabled); + EmDlg::PrvEnableDataBreakpointControls (context, enabled != 0); + break; + } + + case kDlgItemBrkStartAddress: + { + break; + } + + case kDlgItemBrkNumberOfBytes: + { + break; + } + + default: + EmAssert (false); + } + + break; + } + + case kDlgCmdDestroy: + break; + + case kDlgCmdPanelEnter: + case kDlgCmdPanelExit: + case kDlgCmdNone: + EmAssert (false); + break; + } + + return kDlgResultContinue; +} + + +EmDlgItemID EmDlg::DoEditBreakpoints (void) +{ + EditBreakpointsData data; + + return EmDlg::RunDialog (EmDlg::PrvEditBreakpoints, &data, kDlgEditBreakpoints); +} + + +#pragma mark - + +/*********************************************************************** + * + * FUNCTION: DoEditCodeBreakpoint + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +EmDlgFnResult EmDlg::PrvEditCodeBreakpoint (EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + EditCodeBreakpointData& data = *(EditCodeBreakpointData*) context.fUserData; + + switch (context.fCommandID) + { + case kDlgCmdInit: + { + char text[256]; + + sprintf (text, "0x%08lX", data.fAddress); + EmDlg::SetItemText (dlg, kDlgItemBrkAddress, text); + + EmDlg::SetItemText (dlg, kDlgItemBrkCondition, data.fCondition); + + break; + } + + case kDlgCmdIdle: + { + break; + } + + case kDlgCmdItemSelected: + { + switch (context.fItemID) + { + case kDlgItemOK: + { + // User pressed OK, save the changes. + char text[256]; + + data.fAddress = EmDlg::GetItemValue (dlg, kDlgItemBrkAddress); + data.fCondition = EmDlg::GetItemText (dlg, kDlgItemBrkCondition); + + if (data.fAddress & 1) + { + string formatStr = Platform::GetString (kStr_InvalidAddressNotEven); + string addressStr = EmDlg::GetItemText (dlg, kDlgItemBrkAddress); + sprintf (text, formatStr.c_str (), addressStr.c_str ()); + EmDlg::DoCommonDialog (text, kDlgFlags_OK); + break; + } + + if (!EmBankROM::ValidAddress (data.fAddress, 2) && + !EmBankSRAM::ValidAddress (data.fAddress, 2) && + !EmBankDRAM::ValidAddress (data.fAddress, 2)) + { + string formatStr = Platform::GetString (kStr_InvalidAddressNotInROMOrRAM); + string addressStr = EmDlg::GetItemText (dlg, kDlgItemBrkAddress); + sprintf (text, formatStr.c_str (), addressStr.c_str ()); + EmDlg::DoCommonDialog (text, kDlgFlags_OK); + break; + } + + if (!data.fCondition.empty ()) + { + BreakpointCondition* c = NULL; + + c = Debug::NewBreakpointCondition (data.fCondition.c_str ()); + if (!c) + { + string formatStr = Platform::GetString (kStr_CannotParseCondition); + sprintf (text, formatStr.c_str (), data.fCondition.c_str ()); + EmDlg::DoCommonDialog (text, kDlgFlags_OK); + break; + } + + delete c; + } + + data.fEnabled = true; + + // Fall thru... + } + + case kDlgItemCancel: + { + return kDlgResultClose; + } + + case kDlgItemBrkAddress: + case kDlgItemBrkCondition: + { + break; + } + + default: + EmAssert (false); + } + + break; + } + + case kDlgCmdDestroy: + break; + + case kDlgCmdPanelEnter: + case kDlgCmdPanelExit: + case kDlgCmdNone: + EmAssert (false); + break; + } + + return kDlgResultContinue; +} + + +EmDlgItemID EmDlg::DoEditCodeBreakpoint (EditCodeBreakpointData& data) +{ + return EmDlg::RunDialog (EmDlg::PrvEditCodeBreakpoint, &data, kDlgEditCodeBreakpoint); +} + + +#pragma mark - + +/*********************************************************************** + * + * FUNCTION: DoEditCodeBreakpoint + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +#if HAS_TRACER +struct EditTracingOptionsData +{ + unsigned short fTracerType; +}; + + +void EmDlg::PrvPopTracerSettings (EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + EditTracingOptionsData& data = *(EditTracingOptionsData*) context.fUserData; + + // Propagate settings from controls to internal table + + if (data.fTracerType) + { + TracerTypeInfo* info = gTracer.GetTracerTypeInfo (data.fTracerType); + EmAssert (info); + + string value = EmDlg::GetItemText (dlg, kDlgItemTrcTargetValue); + value = value.substr (0, sizeof (info->paramTmpVal) - 1); + strcpy (info->paramTmpVal, value.c_str ()); + + info->autoConnectTmpState = EmDlg::GetItemValue (dlg, kDlgItemTrcAutoConnect) != 0; + } +} + + +void EmDlg::PrvPushTracerSettings (EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + EditTracingOptionsData& data = *(EditTracingOptionsData*) context.fUserData; + + // Propagate settings from internal table to controls + if (data.fTracerType == 0) + { + EmDlg::SetItemText (dlg, kDlgItemTrcTargetValue, ""); + EmDlg::SetItemText (dlg, kDlgItemTrcTargetText, ""); + + EmDlg::DisableItem (dlg, kDlgItemTrcTargetValue); + EmDlg::DisableItem (dlg, kDlgItemTrcTargetText); + + EmDlg::SetItemValue (dlg, kDlgItemTrcAutoConnect, 0); + EmDlg::DisableItem (dlg, kDlgItemTrcAutoConnect); + } + else + { + TracerTypeInfo* info = gTracer.GetTracerTypeInfo (data.fTracerType); + + EmDlg::SetItemText (dlg, kDlgItemTrcTargetValue, info->paramTmpVal); + EmDlg::SetItemText (dlg, kDlgItemTrcTargetText, info->paramDescr); + + EmDlg::EnableItem (dlg, kDlgItemTrcTargetValue); + EmDlg::EnableItem (dlg, kDlgItemTrcTargetText); + + if (info->autoConnectSupport) + { + EmDlg::SetItemValue (dlg, kDlgItemTrcAutoConnect, info->autoConnectTmpState); + EmDlg::EnableItem (dlg, kDlgItemTrcAutoConnect); + } + else + { + EmDlg::SetItemValue (dlg, kDlgItemTrcAutoConnect, 0); + EmDlg::DisableItem (dlg, kDlgItemTrcAutoConnect); + } + } +} + + +EmDlgFnResult EmDlg::PrvEditTracingOptions (EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + EditTracingOptionsData& data = *(EditTracingOptionsData*) context.fUserData; + + switch (context.fCommandID) + { + case kDlgCmdInit: + { + // Copy prefs states to internal states + + unsigned short ii; + + for (ii = 1; ii <= gTracer.GetTracerTypeCount (); ++ii) + { + TracerTypeInfo* info = gTracer.GetTracerTypeInfo (ii); + EmAssert(info); + + strcpy (info->paramTmpVal, info->paramCurVal); + info->autoConnectTmpState = info->autoConnectCurState; + } + + // Get the currently selected tracer type. + + data.fTracerType = gTracer.GetCurrentTracerTypeIndex (); + + // Build up the menu of tracer types and select the current one. + + EmDlg::AppendToMenu (dlg, kDlgItemTrcOutput, "None (discards traces)"); + + for (ii = 1; ii <= gTracer.GetTracerTypeCount (); ++ii) + { + TracerTypeInfo* info = gTracer.GetTracerTypeInfo (ii); + EmAssert (info); + + EmDlg::AppendToMenu (dlg, kDlgItemTrcOutput, info->friendlyName); + } + + EmDlg::SetItemValue (dlg, kDlgItemTrcOutput, data.fTracerType); + + // Install settings for this tracer type. + + EmDlg::PrvPushTracerSettings (context); + + // Show the version information. + + char version[100]; + gTracer.GetLibraryVersionString(version, 100); + EmDlg::SetItemText (dlg, kDlgItemTrcInfo, version); + + break; + } + + case kDlgCmdIdle: + { + break; + } + + case kDlgCmdItemSelected: + { + switch (context.fItemID) + { + case kDlgItemOK: + { + Bool parameterValueChanged = false; + + // If the user made a selection... + + if (data.fTracerType) + { + // Commit the current settings for the current tracer type. + + EmDlg::PrvPopTracerSettings (context); + + // Get the pointer to the current tracer info. + + TracerTypeInfo* info = gTracer.GetTracerTypeInfo (data.fTracerType); + EmAssert (info); + + // If the tracer data changed, make it permanent. + + if (strcmp (info->paramCurVal, info->paramTmpVal) != 0) + { + parameterValueChanged = true; + strcpy (info->paramCurVal, info->paramTmpVal); + } + + info->autoConnectCurState = info->autoConnectTmpState; + } + + // Make the selected tracer the current one. + + gTracer.SetCurrentTracerTypeIndex (data.fTracerType, parameterValueChanged); + + // Fall thru... + } + + case kDlgItemCancel: + { + return kDlgResultClose; + } + + case kDlgItemTrcOutput: + { + // Save the current settings for the old tracer type. + EmDlg::PrvPopTracerSettings (context); + + // Get the new tracer type. + data.fTracerType = EmDlg::GetItemValue (dlg, kDlgItemTrcOutput); + + // Install the settings for the new tracer type. + EmDlg::PrvPushTracerSettings (context); + + break; + } + + case kDlgItemTrcTargetText: + case kDlgItemTrcTargetValue: + case kDlgItemTrcInfo: + { + break; + } + + default: + EmAssert (false); + } + + break; + } + + case kDlgCmdDestroy: + break; + + case kDlgCmdPanelEnter: + case kDlgCmdPanelExit: + case kDlgCmdNone: + EmAssert (false); + break; + } + + return kDlgResultContinue; +} + + +EmDlgItemID EmDlg::DoEditTracingOptions (void) +{ + EditTracingOptionsData data; + + return EmDlg::RunDialog (EmDlg::PrvEditTracingOptions, &data, kDlgEditTracingOptions); +} +#endif + + +#pragma mark - + +/*********************************************************************** + * + * FUNCTION: DoCommonDialog + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +struct EditCommonDialogData +{ + const char* fMessage; + EmCommonDialogFlags fFlags; + uint32 fFirstBeepTime; + uint32 fLastBeepTime; +}; + + +struct ButtonState +{ + ButtonState (void) : + fTextID (0), + fDefault (false), + fCancel (false), + fEnabled (false) + { + } + + ButtonState (StrCode textID, Bool def, Bool cancel, Bool enabled) : + fTextID (textID), + fDefault (def), + fCancel (cancel), + fEnabled (enabled) + { + } + + StrCode fTextID; + Bool fDefault; + Bool fCancel; + Bool fEnabled; +}; + + +EmDlgFnResult EmDlg::PrvCommonDialog (EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + EditCommonDialogData& data = *(EditCommonDialogData*) context.fUserData; + + switch (context.fCommandID) + { + case kDlgCmdInit: + { + // Get the right icon. They all start out as invisible, so + // show the right one. + + EmDlgItemID iconID = kDlgItemCmnIconCaution; + +#if 0 +#pragma message ("Fix me") + { + switch (data.fFlags & kAlertMask) + { + case kNoteAlert: iconID = kDlgItemCmnIconNote; break; + case kCautionAlert: iconID = kDlgItemCmnIconCaution; break; + case kErrorAlert: iconID = kDlgItemCmnIconStop; break; + } + } +#endif + + EmDlg::ShowItem (dlg, iconID); + + // Sort out the button situation. + + // Determine what the buttons should say and how they should look. + + ButtonState buttons[3]; + { + for (int ii = 0, buttonIndex = 0; ii < 3; ++ii) + { + int flags = GET_BUTTON (ii, data.fFlags); + if (flags & kButtonVisible) + { + StrCode kStringCodes[] = + { + 0, + kStr_OK, + kStr_Cancel, + kStr_Yes, + kStr_No, + kStr_Continue, + kStr_Debug, + kStr_Reset, + 0, 0, 0, 0, 0, 0, 0, 0 + }; + + ButtonState newButton ( + kStringCodes[flags & kButtonMask], + (flags & kButtonDefault) != 0, + (flags & kButtonEscape) != 0, + (flags & kButtonEnabled) != 0); + + buttons[buttonIndex] = newButton; + + ++buttonIndex; + } + } + } + + // Make the UI elements match what we determined above. + + for (int ii = 0; ii < 3; ++ii) + { + EmDlgItemID itemID = (EmDlgItemID) (kDlgItemCmnButton1 + ii); + + if (buttons[ii].fTextID) + { + // The button is visible. Set its text and enable/disable it. + + EmDlg::SetItemText (dlg, itemID, buttons[ii].fTextID); + EmDlg::EnableDisableItem (dlg, itemID, buttons[ii].fEnabled); + + if (buttons[ii].fDefault) + { + EmDlg::SetDlgDefaultButton (context, itemID); + } + + if (buttons[ii].fCancel) + { + EmDlg::SetDlgCancelButton (context, itemID); + } + } + else + { + // The button is invisible. Hide it, and move the others over. + + EmDlg::HideItem (dlg, itemID); + } + } + + // Measure the text, resize the box it goes into, and set the text. + + EmRect r = EmDlg::GetItemBounds (dlg, kDlgItemCmnText); + int height = EmDlg::GetTextHeight (dlg, kDlgItemCmnText, data.fMessage); + int delta = height - r.Height (); + + if (delta > 0) + { +#if PLATFORM_WINDOWS + // With PowerPlant and FLTK, resizing the window will resize + // and move around the elements for us. + + r.fBottom += delta; + EmDlg::SetItemBounds (dlg, kDlgItemCmnText, r); +#endif + + r = EmDlg::GetDlgBounds (dlg); + r.fBottom += delta; + EmDlg::SetDlgBounds (dlg, r); + } + + EmDlg::SetItemText (dlg, kDlgItemCmnText, data.fMessage); + + // Set us up to idle so that we can beep. + + Preference<Bool> pref (kPrefKeyDialogBeep); + + if (*pref) + { + context.fNeedsIdle = true; + data.fFirstBeepTime = data.fLastBeepTime = Platform::GetMilliseconds (); + } + + break; + } + + case kDlgCmdIdle: + { + const uint32 kBeepTimeout = 60 * 1024L; // 60 seconds + const uint32 kBeepInterval = 2 * 1024L; // 2 seconds + uint32 curTime = Platform::GetMilliseconds (); + uint32 delta1 = curTime - data.fFirstBeepTime; + uint32 delta2 = curTime - data.fLastBeepTime; + + if (delta1 < kBeepTimeout && delta2 > kBeepInterval) + { + data.fLastBeepTime = curTime; + Platform::Beep (); + } + + break; + } + + case kDlgCmdItemSelected: + { + switch (context.fItemID) + { + case kDlgItemCmnButton1: + case kDlgItemCmnButton2: + case kDlgItemCmnButton3: + { + return kDlgResultClose; + } + + case kDlgItemCmnButtonCopy: + { + string text = EmDlg::GetItemText (context.fDlg, kDlgItemCmnText); + ByteList hostChars; + ByteList palmChars; + + copy (text.begin (), text.end (), back_inserter (hostChars)); + + Platform::CopyToClipboard (palmChars, hostChars); + break; + } + + case kDlgItemCmnText: + case kDlgItemCmnIconStop: + case kDlgItemCmnIconCaution: + case kDlgItemCmnIconNote: + break; + + case kDlgItemOK: + EmAssert (false); + break; + + case kDlgItemCancel: + break; + + default: + EmAssert (false); + } + + break; + } + + case kDlgCmdDestroy: + break; + + case kDlgCmdPanelEnter: + case kDlgCmdPanelExit: + case kDlgCmdNone: + EmAssert (false); + break; + } + + return kDlgResultContinue; +} + + +EmDlgItemID EmDlg::DoCommonDialog (StrCode msg, + EmCommonDialogFlags flags) +{ + string str (Platform::GetString (msg)); + return EmDlg::DoCommonDialog (str, flags); +} + + +EmDlgItemID EmDlg::DoCommonDialog (const char* msg, + EmCommonDialogFlags flags) +{ + EditCommonDialogData data; + + data.fMessage = msg; + data.fFlags = flags; + + EmDlgItemID result; + EmDlgItemID button = EmDlg::RunDialog (EmDlg::PrvCommonDialog, &data, kDlgCommonDialog); + + switch (button) + { + case kDlgItemCmnButton1: + result = (EmDlgItemID) (GET_BUTTON (0, flags) & kButtonMask); + break; + + case kDlgItemCmnButton2: + result = (EmDlgItemID) (GET_BUTTON (1, flags) & kButtonMask); + break; + + case kDlgItemCmnButton3: + result = (EmDlgItemID) (GET_BUTTON (2, flags) & kButtonMask); + break; + + default: + EmAssert (false); + result = (EmDlgItemID) 0; // prevent compiler warnings. + } + + return result; +} + + +EmDlgItemID EmDlg::DoCommonDialog (const string& msg, + EmCommonDialogFlags flags) +{ + return EmDlg::DoCommonDialog (msg.c_str (), flags); +} + + +#pragma mark - + +/*********************************************************************** + * + * FUNCTION: DoSaveBound + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +EmDlgFnResult EmDlg::PrvSaveBound (EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + + switch (context.fCommandID) + { + case kDlgCmdInit: + { + EmDlg::DisableItem (dlg, kDlgItemOK); + break; + } + + case kDlgCmdIdle: + { + break; + } + + case kDlgCmdItemSelected: + { + switch (context.fItemID) + { + case kDlgItemOK: + { + Bool fullSave = EmDlg::GetItemValue (dlg, kDlgItemBndSaveRAM) != 0; + EmFileRef destFile; + EmFileTypeList filterList (1, kFileTypeApplication); + +#if PLATFORM_MAC + string newName ("Emulator_Bound"); +#elif PLATFORM_UNIX + string newName ("pose_bound"); +#elif PLATFORM_WINDOWS + string newName ("Emulator_Bound.exe"); +#else +#error "Unsupported platform" +#endif + + if (EmDlg::DoPutFile (destFile, "Save new emulator", + EmDirRef::GetEmulatorDirectory (), filterList, newName) == kDlgItemOK) + { + EmAssert (gApplication); + gApplication->BindPoser (fullSave, destFile); + } + // Fall thru... + } + + case kDlgItemCancel: + { + return kDlgResultClose; + } + + case kDlgItemBndSaveROM: + case kDlgItemBndSaveRAM: + EmDlg::EnableItem (dlg, kDlgItemOK); + break; + + default: + EmAssert (false); + } + + break; + } + + case kDlgCmdDestroy: + break; + + case kDlgCmdPanelEnter: + case kDlgCmdPanelExit: + case kDlgCmdNone: + EmAssert (false); + break; + } + + return kDlgResultContinue; +} + + +EmDlgItemID EmDlg::DoSaveBound (void) +{ + return EmDlg::RunDialog (EmDlg::PrvSaveBound, NULL, kDlgSaveBound); +} + + +#pragma mark - + +/*********************************************************************** + * + * FUNCTION: EmDlgContext::SessionInfo + * + * DESCRIPTION: Called when the Session Info menu item is selected. + * + * PARAMETERS: None + * + * RETURNED: nothing + * + ***********************************************************************/ + +EmDlgFnResult EmDlg::PrvSessionInfo (EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + + switch (context.fCommandID) + { + case kDlgCmdInit: + { + Preference<Configuration> pref1 (kPrefKeyLastConfiguration); + Preference<EmFileRef> pref2 (kPrefKeyLastPSF); + + Configuration cfg = *pref1; + EmDevice device = cfg.fDevice; + string deviceStr = device.GetMenuString (); + RAMSizeType ramSize = cfg.fRAMSize; + EmFileRef romFile = cfg.fROMFile; + string romFileStr = romFile.GetFullPath (); + EmFileRef sessionRef = *pref2; + string sessionPath = sessionRef.GetFullPath (); + + if (sessionPath.empty ()) + sessionPath = "<Not selected>"; + + EmDlg::SetItemText (dlg, kDlgItemInfDeviceFld, deviceStr); + EmDlg::SetItemValue (dlg, kDlgItemInfRAMFld, ramSize); + EmDlg::SetItemText (dlg, kDlgItemInfROMFld, romFileStr); + EmDlg::SetItemText (dlg, kDlgItemInfSessionFld, sessionPath); + + break; + } + + case kDlgCmdIdle: + { + break; + } + + case kDlgCmdItemSelected: + { + switch (context.fItemID) + { + case kDlgItemOK: + case kDlgItemCancel: + return kDlgResultClose; + + case kDlgItemInfDeviceFld: + case kDlgItemInfRAMFld: + case kDlgItemInfROMFld: + case kDlgItemInfSessionFld: + break; + + default: + EmAssert (false); + } + + break; + } + + case kDlgCmdDestroy: + break; + + case kDlgCmdPanelEnter: + case kDlgCmdPanelExit: + case kDlgCmdNone: + EmAssert (false); + break; + } + + return kDlgResultContinue; +} + + +EmDlgItemID EmDlg::DoSessionInfo (void) +{ + return EmDlg::RunDialog (EmDlg::PrvSessionInfo, NULL, kDlgSessionInfo); +} + + +#pragma mark - + +/*********************************************************************** + * + * FUNCTION: DoGetSocketAddress + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +EmDlgFnResult EmDlg::PrvGetSocketAddress (EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + + switch (context.fCommandID) + { + case kDlgCmdInit: + { + EmDlg::SetItemText (dlg, kDlgItemSocketAddress, *(string*) context.fUserData); + break; + } + + case kDlgCmdIdle: + { + break; + } + + case kDlgCmdItemSelected: + { + switch (context.fItemID) + { + case kDlgItemOK: + { + *(string*) context.fUserData = EmDlg::GetItemText (dlg, kDlgItemSocketAddress); + // Fall thru... + } + + case kDlgItemCancel: + { + return kDlgResultClose; + } + + case kDlgItemSocketAddress: + break; + + default: + EmAssert (false); + } + + break; + } + + case kDlgCmdDestroy: + break; + + case kDlgCmdPanelEnter: + case kDlgCmdPanelExit: + case kDlgCmdNone: + EmAssert (false); + break; + } + + return kDlgResultContinue; +} + + +EmDlgItemID EmDlg::DoGetSocketAddress (string& addr) +{ + return EmDlg::RunDialog (EmDlg::PrvGetSocketAddress, &addr, kDlgGetSocketAddress); +} + + +#pragma mark - + +/*********************************************************************** + * + * FUNCTION: GremlinControl + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +EmDlgRef gGremlinControl; + +// Update the message "Gremlin #%gremlin_number". + +void EmDlg::PrvGrmUpdateGremlinNumber (EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + + int32 number = Hordes::GremlinNumber (); + string numberStr = ::FormatInteger (number); + + Errors::ClearAllParameters (); + Errors::SetParameter ("%gremlin_number", numberStr); + + string text = Errors::ReplaceParameters (kStr_GremlinNumber); + EmDlg::SetItemText (dlg, kDlgItemGrmNumber, text); +} + + +// Update the message "Event %current_event of %last_event" or +// "Event %current_event". + +void EmDlg::PrvGrmUpdateEventNumber (EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + + // Update the "Event #: xxx of yyy" message. + + int32 counter = Hordes::EventCounter (); + int32 limit = Hordes::EventLimit (); + + string counterStr = ::FormatInteger (counter); + string limitStr = ::FormatInteger (limit); + + Errors::ClearAllParameters (); + Errors::SetParameter ("%current_event", counterStr); + Errors::SetParameter ("%last_event", limitStr); + + // If there is a max event number (indicated by a non -1 value + // for Hordes::EventLimit), display a string including that + // value. Otherwise, the number of events to post is unlimited. + // In that case, we just show the current event number. + + string text = Errors::ReplaceParameters ( + limit > 0 + ? kStr_GremlinXofYEvents + : kStr_GremlinXEvents); + EmDlg::SetItemText (dlg, kDlgItemGrmEventNumber, text); +} + + +// Update the message "Elapsed Time: %elapsed_time" + +void EmDlg::PrvGrmUpdateElapsedTime (EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + + uint32 elapsed = Hordes::ElapsedMilliseconds (); + string elapsedStr = ::FormatElapsedTime (elapsed); + + Errors::ClearAllParameters (); + Errors::SetParameter ("%elapsed_time", elapsedStr); + + string text = Errors::ReplaceParameters (kStr_GremlinElapsedTime); + EmDlg::SetItemText (dlg, kDlgItemGrmElapsedTime, text); +} + + +void EmDlg::PrvGrmUpdateAll (EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + + EmDlg::PrvGrmUpdateGremlinNumber (context); + EmDlg::PrvGrmUpdateEventNumber (context); + EmDlg::PrvGrmUpdateElapsedTime (context); + + // Update the buttons. + + EmDlg::EnableDisableItem (dlg, kDlgItemGrmStop, Hordes::CanStop ()); + EmDlg::EnableDisableItem (dlg, kDlgItemGrmResume, Hordes::CanResume ()); + EmDlg::EnableDisableItem (dlg, kDlgItemGrmStep, Hordes::CanStep ()); +} + + +EmDlgFnResult EmDlg::PrvGremlinControl (EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + + switch (context.fCommandID) + { + case kDlgCmdInit: + { + Preference<PointType> pref (kPrefKeyGCWLocation); + + if (pref.Loaded ()) + { + EmDlg::MoveDlgTo (dlg, pref->x, pref->y); + EmDlg::EnsureDlgOnscreen (dlg); + } + else + { + EmDlg::CenterDlg (dlg); + } + + // Set a timer so that we can periodically update the displayed values. + + context.fNeedsIdle = true; + + // Set the initial contents of the dialog. + + EmDlg::PrvGrmUpdateAll (context); + + break; + } + + case kDlgCmdIdle: + { + static UInt32 lastIdle = 0; + + UInt32 curIdle = Platform::GetMilliseconds (); + + if (curIdle - lastIdle > 500) + { + lastIdle = curIdle; + + EmDlg::PrvGrmUpdateAll (context); + } + + break; + } + + case kDlgCmdItemSelected: + { + switch (context.fItemID) + { + case kDlgItemCancel: + { + return kDlgResultClose; + } + + case kDlgItemGrmStop: + { + EmSessionStopper stopper (gSession, kStopNow); + if (stopper.Stopped()) + { + Hordes::Stop (); + } + break; + } + + case kDlgItemGrmResume: + { + // Resuming attempts to make Palm OS calls (for instance, + // to reset the pen calibration), so make sure we're stopped + // at a good place. + + EmSessionStopper stopper (gSession, kStopOnSysCall); + if (stopper.Stopped()) + { + Hordes::Resume (); + } + break; + } + + case kDlgItemGrmStep: + { + EmSessionStopper stopper (gSession, kStopOnSysCall); + if (stopper.Stopped()) + { + Hordes::Step (); + } + break; + } + + case kDlgItemGrmNumber: + case kDlgItemGrmEventNumber: + case kDlgItemGrmElapsedTime: + + default: + EmAssert (false); + } + + break; + } + + case kDlgCmdDestroy: + { + EmRect bounds = EmDlg::GetDlgBounds (dlg); + + Preference<EmPoint> pref (kPrefKeyGCWLocation); + pref = bounds.TopLeft (); + + gGremlinControl = NULL; + + break; // Return value is ignored for destroy + } + + case kDlgCmdPanelEnter: + case kDlgCmdPanelExit: + case kDlgCmdNone: + EmAssert (false); + break; + } + + return kDlgResultContinue; +} + + +void EmDlg::GremlinControlOpen (void) +{ + if (!gGremlinControl) + { + gGremlinControl = EmDlg::DialogOpen (EmDlg::PrvGremlinControl, NULL, kDlgGremlinControl); + } + else + { + // !!! Bring to front + } +} + + +void EmDlg::GremlinControlClose (void) +{ + if (gGremlinControl) + { + EmDlg::DialogClose (gGremlinControl); + } +} + + +#pragma mark - + +/*********************************************************************** + * + * FUNCTION: MinimizeControl + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +EmDlgRef gMinimizeProgress; + + +// Update the message "Pass #%pass_number". + +void EmDlg::PrvMinUpdatePassNumber (EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + + uint32 pass = EmMinimize::GetPassNumber (); + string passStr = ::FormatInteger (pass); + + if (pass == 0) + { + passStr = "LAST"; + } + + Errors::ClearAllParameters (); + Errors::SetParameter ("%pass_number", passStr); + + string text = Errors::ReplaceParameters (kStr_MinimizePassNumber); + EmDlg::SetItemText (dlg, kDlgItemMinPassNumber, text); +} + + +// Update the message "Event %current_event of %last_event". +// +// "last_event" is the last event number of the current pass. +// "current_event" is between one and that number, inclusive. + +void EmDlg::PrvMinUpdateEventNumber (EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + + uint32 current = EmEventPlayback::GetCurrentEvent (); + string currentStr = ::FormatInteger (current); + + uint32 total = EmEventPlayback::GetNumEvents (); + string totalStr = ::FormatInteger (total); + + Errors::ClearAllParameters (); + Errors::SetParameter ("%current_event", currentStr); + Errors::SetParameter ("%last_event", totalStr); + + string text = Errors::ReplaceParameters (kStr_MinimizeXofYEvents); + EmDlg::SetItemText (dlg, kDlgItemMinEventNumber, text); +} + + +// Update the message "Elapsed Time: %elapsed_time". + +void EmDlg::PrvMinUpdateElapsed (EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + + uint32 elapsed = EmMinimize::GetElapsedTime (); + string elapsedStr = ::FormatElapsedTime (elapsed); + + Errors::ClearAllParameters (); + Errors::SetParameter ("%elapsed_time", elapsedStr); + + string text = Errors::ReplaceParameters (kStr_MinimizeElapsedTime); + EmDlg::SetItemText (dlg, kDlgItemMinElapsed, text); +} + + +// Update the message "Excluding range %first_event to %last_event". +// +// When formatting the last event number, subtract one to hide the +// fact that we work on a half-open interval. Then add one to both +// the begin and end to convert a 0-based range to a 1-based range +// (so that the first event is reported as 1 instead of zero). + +void EmDlg::PrvMinUpdateRange (EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + + uint32 begin, end; + EmMinimize::GetCurrentRange (begin, end); + + string beginStr = ::FormatInteger (begin + 1); + string endStr = ::FormatInteger (end); + + Errors::ClearAllParameters (); + Errors::SetParameter ("%first_event", beginStr); + Errors::SetParameter ("%last_event", endStr); + + string text = Errors::ReplaceParameters (kStr_MinimizeRange); + EmDlg::SetItemText (dlg, kDlgItemMinRange, text); +} + + +// Update the message "Discarded %num_discarded_events of %num_total_events events". +// +// "num_total_events" is the initial number of events at pass 1. +// "num_discarded_events" is between zero and that number. + +void EmDlg::PrvMinUpdateDiscarded (EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + + uint32 discarded = EmMinimize::GetNumDiscardedEvents (); + string discardedStr = ::FormatInteger (discarded); + + uint32 total = EmMinimize::GetNumInitialEvents (); + string totalStr = ::FormatInteger (total); + + Errors::ClearAllParameters (); + Errors::SetParameter ("%num_discarded_events", discardedStr); + Errors::SetParameter ("%num_total_events", totalStr); + + string text = Errors::ReplaceParameters (kStr_MinimizeDiscarded); + EmDlg::SetItemText (dlg, kDlgItemMinDiscarded, text); +} + + +// Update the progress bar. +// +// Max value of the progress bar is the current maximum event for this pass. +// Current value of the bar is the lower end of the range we are currently +// examining for exclusion. Given the way we walk through the ranges of +// events to exclude, this will give a jerky yet increasing progress bar. + +void EmDlg::PrvMinUpdateProgress (EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + + uint32 begin, end; + EmMinimize::GetCurrentRange (begin, end); + + uint32 total = EmEventPlayback::GetNumEvents (); + + // Make sure "total" is less than 32K (that's the most that the standard + // Win32 progress bar can handle). + + int divider = (total / 32768) + 1; + + total /= divider; + begin /= divider; + end /= divider; + + EmDlg::SetItemMax (dlg, kDlgItemMinProgress, total); + EmDlg::SetItemValue (dlg, kDlgItemMinProgress, begin); +} + + +// Update all elements of the dialog box. + +void EmDlg::PrvMinUpdateAll (EmDlgContext& context) +{ + EmDlg::PrvMinUpdatePassNumber (context); + EmDlg::PrvMinUpdateEventNumber (context); + EmDlg::PrvMinUpdateElapsed (context); + EmDlg::PrvMinUpdateRange (context); + EmDlg::PrvMinUpdateDiscarded (context); + EmDlg::PrvMinUpdateProgress (context); +} + + +EmDlgFnResult EmDlg::PrvMinimizeProgress (EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + + switch (context.fCommandID) + { + case kDlgCmdInit: + { + Preference<PointType> pref (kPrefKeyMPWLocation); + + if (pref.Loaded ()) + { + EmDlg::MoveDlgTo (dlg, pref->x, pref->y); + EmDlg::EnsureDlgOnscreen (dlg); + } + else + { + EmDlg::CenterDlg (dlg); + } + + // Set a timer so that we can periodically update the displayed values. + + context.fNeedsIdle = true; + + // Set the initial contents of the dialog. + + EmDlg::PrvMinUpdateAll (context); + + break; + } + + case kDlgCmdIdle: + { + if (!EmMinimize::IsOn ()) + { + return kDlgResultClose; + } + + static UInt32 lastIdle = 0; + + UInt32 curIdle = Platform::GetMilliseconds (); + + if (curIdle - lastIdle > 500) + { + lastIdle = curIdle; + + EmDlg::PrvMinUpdateAll (context); + } + + break; + } + + case kDlgCmdItemSelected: + { + switch (context.fItemID) + { + case kDlgItemCancel: + { + EmMinimize::Stop (); + return kDlgResultClose; + } + + case kDlgItemMinRange: + case kDlgItemMinElapsed: + case kDlgItemMinDiscarded: + case kDlgItemMinProgress: + + default: + EmAssert (false); + } + + break; + } + + case kDlgCmdDestroy: + { + EmRect bounds = EmDlg::GetDlgBounds (dlg); + + Preference<EmPoint> pref (kPrefKeyMPWLocation); + pref = bounds.TopLeft (); + + gMinimizeProgress = NULL; + + break; // Return value is ignored for destroy + } + + case kDlgCmdPanelEnter: + case kDlgCmdPanelExit: + case kDlgCmdNone: + EmAssert (false); + break; + } + + return kDlgResultContinue; +} + + +void EmDlg::MinimizeProgressOpen (void) +{ + if (!gMinimizeProgress) + { + gMinimizeProgress = EmDlg::DialogOpen (EmDlg::PrvMinimizeProgress, NULL, kDlgMinimizeProgress); + } + else + { + // !!! Bring to front + } +} + + +void EmDlg::MinimizeProgressClose (void) +{ + if (gMinimizeProgress) + { + EmDlg::DialogClose (gMinimizeProgress); + } +} + + +#pragma mark - + +/*********************************************************************** + * + * FUNCTION: RunDialog + * + * DESCRIPTION: Common routine that all dialog clients go through. + * This function checks to see if we are in the UI thread + * or not. If not, it forwards the call to the session + * so that it can block and wait for the UI thread to + * pick up and handle the call. If we are already in the + * UI thread, then call the Host routine that displays + * and drives the dialog. + * + * PARAMETERS: fn - the custom dialog handler + * userData - custom data passed back to the dialog handler. + * dlgID - ID of dialog to create. + * + * RETURNED: ID of dialog item that dismissed the dialog. + * + ***********************************************************************/ + +EmDlgItemID EmDlg::RunDialog (EmDlgFn fn, void* userData, EmDlgID dlgID) +{ + RunDialogParameters parameters (fn, userData, dlgID); + return EmDlg::RunDialog (EmDlg::HostRunDialog, ¶meters); +} + + +/*********************************************************************** + * + * FUNCTION: RunDialog + * + * DESCRIPTION: Common routine that all dialog clients go through. + * This function checks to see if we are in the UI thread + * or not. If not, it forwards the call to the session + * so that it can block and wait for the UI thread to + * pick up and handle the call. If we are already in the + * UI thread, then call the Host routine that displays + * and drives the dialog. + * + * PARAMETERS: fn - the custom dialog handler + * userData - custom data passed back to the dialog handler. + * dlgID - ID of dialog to create. + * + * RETURNED: ID of dialog item that dismissed the dialog. + * + ***********************************************************************/ + +EmDlgItemID EmDlg::RunDialog (EmDlgThreadFn fn, const void* parameters) +{ +#if HAS_OMNI_THREAD + if (gSession && gSession->InCPUThread ()) + { + return gSession->BlockOnDialog (fn, parameters); + } +#else + if (gSession && gSession->GetSessionState () == kRunning) + { + return gSession->BlockOnDialog (fn, parameters); + } +#endif + + return fn (parameters); +} + + +/*********************************************************************** + * + * FUNCTION: DialogOpen + * + * DESCRIPTION: . + * + * PARAMETERS: fn - the custom dialog handler + * userData - custom data passed back to the dialog handler. + * dlgID - ID of dialog to create. + * + * RETURNED: . + * + ***********************************************************************/ + +EmDlgRef EmDlg::DialogOpen (EmDlgFn fn, void* data, EmDlgID dlgID) +{ + return EmDlg::HostDialogOpen (fn, data, dlgID); +} + + +/*********************************************************************** + * + * FUNCTION: DialogClose + * + * DESCRIPTION: . + * + * PARAMETERS: . + * + * RETURNED: . + * + ***********************************************************************/ + +void EmDlg::DialogClose (EmDlgRef dlg) +{ + EmDlg::HostDialogClose (dlg); +} + + +#pragma mark - + +/*********************************************************************** + * + * FUNCTION: EmDlg::MoveDlgTo + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +void EmDlg::MoveDlgTo (EmDlgRef dlg, EmCoord x, EmCoord y) +{ + EmDlg::MoveDlgTo (dlg, EmPoint (x, y)); +} + + +void EmDlg::MoveDlgTo (EmDlgRef dlg, const EmPoint& pt) +{ + EmRect bounds = EmDlg::GetDlgBounds (dlg); + bounds += (pt - bounds.TopLeft ()); + EmDlg::SetDlgBounds (dlg, bounds); +} + + +/*********************************************************************** + * + * FUNCTION: EmDlg::EnsureDlgOnscreen + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +void EmDlg::EnsureDlgOnscreen (EmDlgRef dlg) +{ + EmRect bounds = EmDlg::GetDlgBounds (dlg); + + if (Platform::PinToScreen (bounds)) + { + EmDlg::SetDlgBounds (dlg, bounds); + } +} + + +/*********************************************************************** + * + * FUNCTION: EmDlg::SetItemText + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +void EmDlg::SetItemText (EmDlgRef dlg, EmDlgItemID item, StrCode strCode) +{ + string str = Platform::GetString (strCode); + EmDlg::SetItemText (dlg, item, str); +} + + +/*********************************************************************** + * + * FUNCTION: EmDlg::SetItemText + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +void EmDlg::SetItemText (EmDlgRef dlg, EmDlgItemID item, const char* str) +{ + EmDlg::SetItemText (dlg, item, string (str)); +} + + +/*********************************************************************** + * + * FUNCTION: EmDlg::EnableDisableItem + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +void EmDlg::EnableDisableItem (EmDlgRef dlg, EmDlgItemID item, Bool enable) +{ + if (enable) + EmDlg::EnableItem (dlg, item); + else + EmDlg::DisableItem (dlg, item); +} + + +/*********************************************************************** + * + * FUNCTION: EmDlg::ShowHideItem + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +void EmDlg::ShowHideItem (EmDlgRef dlg, EmDlgItemID item, Bool show) +{ + if (show) + EmDlg::ShowItem (dlg, item); + else + EmDlg::HideItem (dlg, item); +} + + +/*********************************************************************** + * + * FUNCTION: EmDlg::AppendToMenu + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +void EmDlg::AppendToMenu (EmDlgRef dlg, EmDlgItemID item, const string& text) +{ + StringList strList; + strList.push_back (text); + + EmDlg::AppendToMenu (dlg, item, strList); +} + + +/*********************************************************************** + * + * FUNCTION: EmDlg::AppendToList + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +void EmDlg::AppendToList (EmDlgRef dlg, EmDlgItemID item, const string& text) +{ + StringList strList; + strList.push_back (text); + + EmDlg::AppendToList (dlg, item, strList); +} + + +/*********************************************************************** + * + * FUNCTION: EmDlg::SelectListItem + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +void EmDlg::SelectListItem (EmDlgRef dlg, EmDlgItemID item, EmDlgListIndex listItem) +{ + EmDlgListIndexList itemList; + itemList.push_back (listItem); + + EmDlg::SelectListItems (dlg, item, itemList); +} + + +/*********************************************************************** + * + * FUNCTION: EmDlg::UnselectListItem + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +void EmDlg::UnselectListItem (EmDlgRef dlg, EmDlgItemID item, EmDlgListIndex listItem) +{ + EmDlgListIndexList itemList; + itemList.push_back (listItem); + + EmDlg::UnselectListItems (dlg, item, itemList); +} + + +/*********************************************************************** + * + * FUNCTION: EmDlg::GetSelectedItem + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +EmDlgListIndex EmDlg::GetSelectedItem (EmDlgRef dlg, EmDlgItemID item) +{ + EmDlgListIndexList itemList; + EmDlg::GetSelectedItems (dlg, item, itemList); + + if (itemList.size () > 0) + { + return itemList[0]; + } + + return kDlgItemListNone; +} + + +/*********************************************************************** + * + * FUNCTION: EmDlg::StringToLong + * + * DESCRIPTION: + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +Bool EmDlg::StringToLong (const char* s, long* num) +{ + if (sscanf(s, "%li", num) == 1) + return true; + + return false; +} + + +#pragma mark - + +/*********************************************************************** + * + * FUNCTION: EmDlgContext c'tor + * + * DESCRIPTION: Constructor. Initialize our data members. + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +EmDlgContext::EmDlgContext (void) : + fFn (NULL), + fFnResult (kDlgResultNone), + fDlg (NULL), + fDlgID (kDlgNone), + fPanelID (kDlgPanelNone), + fItemID (kDlgItemNone), + fCommandID (kDlgCmdNone), + fNeedsIdle (false), + fUserData (NULL), + fDefaultItem (kDlgItemNone), + fCancelItem (kDlgItemNone) +{ +} + + +/*********************************************************************** + * + * FUNCTION: EmDlgContext c'tor + * + * DESCRIPTION: Constructor. Initialize our data members. + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +EmDlgContext::EmDlgContext (const EmDlgContext& other) : + fFn (other.fFn), + fFnResult (other.fFnResult), + fDlg (other.fDlg), + fDlgID (other.fDlgID), + fPanelID (other.fPanelID), + fItemID (other.fItemID), + fCommandID (other.fCommandID), + fNeedsIdle (other.fNeedsIdle), + fUserData (other.fUserData), + fDefaultItem (other.fDefaultItem), + fCancelItem (other.fCancelItem) +{ +} + + +/*********************************************************************** + * + * FUNCTION: EmDlgContext::Init + * + * DESCRIPTION: Call the custom dialog handler to initialize the dialog. + * If the dialog says that it wants idle time, then start + * idleing it. + * + * PARAMETERS: None + * + * RETURNED: The result returned by the dialog handler. + * + ***********************************************************************/ + +EmDlgFnResult EmDlgContext::Init (void) +{ + fFnResult = kDlgResultNone; + + if (fFn) + { + fItemID = kDlgItemNone; + fCommandID = kDlgCmdInit; + + fFnResult = fFn (*this); + + if (fNeedsIdle) + EmDlg::HostStartIdling (*this); + } + + return fFnResult; +} + + +/*********************************************************************** + * + * FUNCTION: EmDlgContext::Idle + * + * DESCRIPTION: Call the custom dialog handler to idle. + * + * PARAMETERS: None + * + * RETURNED: The result returned by the dialog handler. + * + ***********************************************************************/ + +EmDlgFnResult EmDlgContext::Idle (void) +{ + fFnResult = kDlgResultNone; + + if (fFn) + { + fItemID = kDlgItemNone; + fCommandID = kDlgCmdIdle; + + fFnResult = fFn (*this); + } + + return fFnResult; +} + + +/*********************************************************************** + * + * FUNCTION: EmDlgContext::Event + * + * DESCRIPTION: Call the custom dialog handler to handle an event. + * + * PARAMETERS: item - dialog item that was selected. + * + * RETURNED: The result returned by the dialog handler. + * + ***********************************************************************/ + +EmDlgFnResult EmDlgContext::Event (EmDlgItemID itemID) +{ + fFnResult = kDlgResultNone; + + if (fFn) + { + fItemID = itemID; + fCommandID = kDlgCmdItemSelected; + + fFnResult = fFn (*this); + } + + return fFnResult; +} + + +/*********************************************************************** + * + * FUNCTION: EmDlgContext::Destroy + * + * DESCRIPTION: Call the custom dialog handler to tell it that the + * dialog is being destroyed. + * + * PARAMETERS: None. + * + * RETURNED: Nothing. + * + ***********************************************************************/ + +void EmDlgContext::Destroy (void) +{ + if (fFn) + { + fItemID = kDlgItemNone; + fCommandID = kDlgCmdDestroy; + + fFnResult = fFn (*this); + } +} + + +/*********************************************************************** + * + * FUNCTION: EmDlgContext::PanelEnter + * + * DESCRIPTION: Call the custom dialog handler to idle. + * + * PARAMETERS: None + * + * RETURNED: The result returned by the dialog handler. + * + ***********************************************************************/ + +EmDlgFnResult EmDlgContext::PanelEnter (void) +{ + fItemID = kDlgItemNone; + fCommandID = kDlgCmdPanelEnter; + + fFnResult = fFn (*this); + return fFnResult; +} + + +/*********************************************************************** + * + * FUNCTION: EmDlgContext::PanelExit + * + * DESCRIPTION: Call the custom dialog handler to idle. + * + * PARAMETERS: None + * + * RETURNED: The result returned by the dialog handler. + * + ***********************************************************************/ + +EmDlgFnResult EmDlgContext::PanelExit (void) +{ + fItemID = kDlgItemNone; + fCommandID = kDlgCmdPanelExit; + + fFnResult = fFn (*this); + return fFnResult; +} + + +#pragma mark - + +#if !PLATFORM_UNIX +// Append one set of descriptors to another set, separating them if +// necessary with an empty descriptor. + +static void PrvAppendDescriptors (EmTransportDescriptorList& menuItems, + const EmTransportDescriptorList& rawItems) +{ + // If there are items to be added and items already added, + // insert a divider first. + + if (menuItems.size () > 0 && rawItems.size () > 0) + { + menuItems.push_back (EmTransportDescriptor ()); + } + + // Add the menu items to the menu. + + std::copy (rawItems.begin (), rawItems.end (), back_inserter (menuItems)); +} + + +// Append one descriptors to a set, separating it if +// necessary with an empty descriptor. + +static void PrvAppendDescriptors (EmTransportDescriptorList& menuItems, + const string& rawItem) +{ + EmTransportDescriptorList rawItems; + rawItems.push_back (EmTransportDescriptor (rawItem)); + + ::PrvAppendDescriptors (rawItems, menuItems); +} + + +// Return the text that should be put into the menu item. + +static string PrvGetMenuItemText (EmDlgItemID whichMenu, + const EmTransportDescriptor& item, + const string& socketAddr) +{ + // Get the text to add to the menu. + + string itemText = item.GetMenuName (); + + // If this menu item is for a socket, see if we'd like to + // augment the text for it with socket/port info. + + if (item.GetType () == kTransportSocket) + { + if (whichMenu == kDlgItemPrfRedirectSerial || whichMenu == kDlgItemPrfRedirectSerial) + { + // If the user has selected a socket for their serial or IR + // port, then add the socket address/port, as well as a "..." + // so that they can bring up a dialog allowing them to specify + // that information. + + if (socketAddr.size () > 0) + { + itemText += " (" + socketAddr + ")"; + } + + itemText += "..."; + } + } + + return itemText; +} + + +// Append the given descriptors to the indicated menu. Empty descriptors +// are turned into divider menu items. If the descriptor in "pref" is +// found, then select that descriptor in the menu. Otherwise, select the +// first item in the menu. + +static void PrvAppendMenuItems (EmDlgRef dlg, EmDlgItemID dlgItem, + const EmTransportDescriptorList& menuItems, + const EmTransportDescriptor& pref, + const string& socketAddr) +{ + Bool selected = false; + + // Iterate over all the items in "menuItems". + + EmTransportDescriptorList::const_iterator iter = menuItems.begin (); + while (iter != menuItems.end ()) + { + // If this is descriptor is of a known type, add it to the menu as an item. + + if (iter->GetType () != kTransportUnknown) + { + // Add the menu item to the menu. + + string itemText = ::PrvGetMenuItemText (dlgItem, *iter, socketAddr); + EmDlg::AppendToMenu (dlg, dlgItem, itemText); + + // If this is the item the user has selected, then select it + // in the menu. + + if (iter->GetType () == kTransportSocket) + { + if (pref.GetType () == kTransportSocket) + { + EmDlg::SetItemValue (dlg, dlgItem, iter - menuItems.begin ()); + selected = true; + } + } + else if (*iter == pref) + { + EmDlg::SetItemValue (dlg, dlgItem, iter - menuItems.begin ()); + selected = true; + } + } + + // If this descriptor is not of a known type, add it as a menu divider. + + else + { + EmDlg::AppendToMenu (dlg, dlgItem, ""); + } + + ++iter; + } + + // If we couldn't find a menu item to select, + // pick a default. + + if (!selected) + { + EmDlg::SetItemValue (dlg, dlgItem, 0); + } +} +#endif // !PLATFORM_UNIX + + +#pragma mark - + +#if 0 + // Template for callback function + +EmDlgFnResult EmDlg::PrvCallback (EmDlgContext& context) +{ + EmDlgRef dlg = context.fDlg; + <type>& data = *(<type>*) context.fUserData; + + switch (context.fCommandID) + { + case kDlgCmdInit: + { + break; + } + + case kDlgCmdIdle: + { + break; + } + + case kDlgCmdItemSelected: + { + switch (context.fItemID) + { + case kDlgItemOK: + { + // Fall thru... + } + + case kDlgItemCancel: + { + return kDlgResultClose; + } + + default: + EmAssert (false); + } + + break; + } + + case kDlgCmdDestroy: + break; + + case kDlgCmdPanelEnter: + case kDlgCmdPanelExit: + case kDlgCmdNone: + EmAssert (false); + break; + } + + return kDlgResultContinue; +} +#endif |