aboutsummaryrefslogtreecommitdiff
path: root/SrcUnix/EmDlgFltk.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'SrcUnix/EmDlgFltk.cpp')
-rw-r--r--SrcUnix/EmDlgFltk.cpp2497
1 files changed, 2497 insertions, 0 deletions
diff --git a/SrcUnix/EmDlgFltk.cpp b/SrcUnix/EmDlgFltk.cpp
new file mode 100644
index 0000000..c7e7dc1
--- /dev/null
+++ b/SrcUnix/EmDlgFltk.cpp
@@ -0,0 +1,2497 @@
+/* -*- mode: C++; tab-width: 4 -*- */
+/* ===================================================================== *\
+ Copyright (c) 2000-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 "EmDlgFltk.h"
+
+#include "ErrorHandling.h" // ParamList
+#include "Miscellaneous.h" // ReplaceString, FormatString
+#include "Platform.h" // Platform::GetString
+#include "Strings.r.h" // kStr_
+
+#include <FL/Enumerations.H>
+#include <FL/Fl.H>
+#include <FL/Fl_Adjuster.H>
+#include <FL/Fl_Bitmap.H>
+#include <FL/Fl_Box.H>
+#include <FL/Fl_Browser.H>
+#include <FL/Fl_Browser_.H>
+#include <FL/Fl_Button.H>
+#include <FL/Fl_Chart.H>
+#include <FL/Fl_Check_Button.H>
+#include <FL/Fl_Choice.H>
+#include <FL/Fl_Clock.H>
+#include <FL/Fl_Color_Chooser.H>
+#include <FL/Fl_Counter.H>
+#include <FL/Fl_Dial.H>
+#include <FL/Fl_Double_Window.H>
+#include <FL/Fl_Fill_Dial.H>
+#include <FL/Fl_Fill_Slider.H>
+#include <FL/Fl_Float_Input.H>
+#include <FL/Fl_FormsBitmap.H>
+#include <FL/Fl_FormsPixmap.H>
+#include <FL/Fl_Free.H>
+#include <FL/Fl_Gl_Window.H>
+#include <FL/Fl_Group.H>
+#include <FL/Fl_Hold_Browser.H>
+#include <FL/Fl_Hor_Fill_Slider.H>
+#include <FL/Fl_Hor_Nice_Slider.H>
+#include <FL/Fl_Hor_Slider.H>
+#include <FL/Fl_Hor_Value_Slider.H>
+#include <FL/Fl_Image.H>
+#include <FL/Fl_Input.H>
+#include <FL/Fl_Input_.H>
+#include <FL/Fl_Int_Input.H>
+#include <FL/Fl_Light_Button.H>
+#include <FL/Fl_Line_Dial.H>
+#include <FL/Fl_Menu.H>
+#include <FL/Fl_Menu_.H>
+#include <FL/Fl_Menu_Bar.H>
+#include <FL/Fl_Menu_Button.H>
+#include <FL/Fl_Menu_Item.H>
+#include <FL/Fl_Menu_Window.H>
+#include <FL/Fl_Multi_Browser.H>
+#include <FL/Fl_Multi_Label.H>
+#include <FL/Fl_Multiline_Input.H>
+#include <FL/Fl_Multiline_Output.H>
+#include <FL/Fl_Nice_Slider.H>
+#include <FL/Fl_Object.H>
+#include <FL/Fl_Output.H>
+#include <FL/Fl_Overlay_Window.H>
+#include <FL/Fl_Pack.H>
+#include <FL/Fl_Pixmap.H>
+#include <FL/Fl_Positioner.H>
+#include <FL/Fl_Radio_Button.H>
+#include <FL/Fl_Radio_Light_Button.H>
+#include <FL/Fl_Radio_Round_Button.H>
+#include <FL/Fl_Repeat_Button.H>
+#include <FL/Fl_Return_Button.H>
+#include <FL/Fl_Roller.H>
+#include <FL/Fl_Round_Button.H>
+#include <FL/Fl_Round_Clock.H>
+#include <FL/Fl_Scroll.H>
+#include <FL/Fl_Scrollbar.H>
+#include <FL/Fl_Secret_Input.H>
+#include <FL/Fl_Select_Browser.H>
+#include <FL/Fl_Simple_Counter.H>
+#include <FL/Fl_Single_Window.H>
+#include <FL/Fl_Slider.H>
+#include <FL/Fl_Tabs.H>
+#include <FL/Fl_Tile.H>
+#include <FL/Fl_Timer.H>
+#include <FL/Fl_Toggle_Button.H>
+#include <FL/Fl_Toggle_Light_Button.H>
+#include <FL/Fl_Toggle_Round_Button.H>
+#include <FL/Fl_Valuator.H>
+#include <FL/Fl_Value_Input.H>
+#include <FL/Fl_Value_Output.H>
+#include <FL/Fl_Value_Slider.H>
+#include <FL/Fl_Widget.H>
+#include <FL/Fl_Window.H>
+#include <FL/fl_ask.H>
+#include <FL/fl_draw.H>
+#include <FL/fl_file_chooser.H>
+#include <FL/fl_message.H>
+#include <FL/fl_show_colormap.H>
+#include <FL/fl_show_input.H>
+
+#include "EmDlgFltkFactory.h"
+
+#include "espws-2.0/FileChooser.h"
+
+#include <algorithm> // find
+#include <list>
+#include <map>
+#include <string>
+#include <utility> // pair
+#include <queue>
+
+#if FL_MAJOR_VERSION == 1 && FL_MINOR_VERSION == 0
+// FLTK 1.0.x had a different layout for the undocumented Fl_Label structure.
+#define HAVE_LEGACY_FL_LABEL
+#endif
+
+typedef string FilterList;
+
+static FilterList PrvConvertTypeList (const EmFileTypeList&);
+static void PrvAddFilter (FilterList& filter, const char* pattern);
+static Fl_Window* PrvMakeDialog (EmDlgID);
+static Bool PrvInitializeDialog (EmDlgFn, void* data, EmDlgID, Fl_Window*);
+static void PrvIdleCallback (void* data);
+static string PrvBreakLine (Fl_Input_*, const char*);
+
+
+// -----------------------------------------------------------------------------
+// helper routines for establishing z-order independent ids for widgets.
+
+typedef map<EmDlgItemID, Fl_Widget*> ID2WidgetType;
+typedef map<Fl_Widget*, EmDlgItemID> Widget2IDType;
+
+ID2WidgetType gID2Widget;
+Widget2IDType gWidget2ID;
+
+Fl_Widget* PrvFindWidgetByID (EmDlgItemID id)
+{
+ ID2WidgetType::iterator iter = gID2Widget.find (id);
+ if (iter == gID2Widget.end ())
+ return NULL;
+
+ return iter->second;
+}
+
+EmDlgItemID PrvFindIDByWidget (Fl_Widget* o)
+{
+ Widget2IDType::iterator iter = gWidget2ID.find (o);
+ if (iter == gWidget2ID.end ())
+ return kDlgItemNone;
+
+ return iter->second;
+}
+
+void PrvSetWidgetID (Fl_Widget* o, EmDlgItemID id)
+{
+ gID2Widget[id] = o;
+ gWidget2ID[o] = id;
+}
+
+void PrvClearWidgetID (EmDlgItemID id)
+{
+ Fl_Widget* o = ::PrvFindWidgetByID (id);
+
+ if (o != NULL)
+ {
+ gID2Widget.erase (id);
+ gWidget2ID.erase (o);
+ }
+}
+
+void PrvClearWidgetID (Fl_Widget* o)
+{
+ EmDlgItemID id = ::PrvFindIDByWidget (o);
+
+ if (id != kDlgItemNone)
+ {
+ gID2Widget.erase (id);
+ gWidget2ID.erase (o);
+ }
+}
+
+void PrvClearAllWidgetIDs (void)
+{
+ gID2Widget.clear ();
+ gWidget2ID.clear ();
+}
+
+void PrvClearDlgWidgetIDs (Fl_Group* w)
+{
+ // Clear self.
+ ::PrvClearWidgetID (w);
+
+ // Clear children.
+ for (int ii = 0; ii < w->children (); ++ii)
+ {
+ Fl_Widget* child = w->child (ii);
+
+ Fl_Group* g = dynamic_cast<Fl_Group*>(child);
+ if (g)
+ {
+ ::PrvClearDlgWidgetIDs (g);
+ }
+ else
+ {
+ ::PrvClearWidgetID (child);
+ }
+ }
+}
+
+// Define data structures and routines for keeping track of
+// strings that are associated with widgets. We need to keep
+// track of what strings have been assigned to which widgets
+// because FLTK widgets don't *own* the labels assigned to
+// them. They expect the caller to own the storage. However,
+// that's not the model EmDlg uses; it assumes that the widgets
+// own the storage (as is the case in PowerPlant and with
+// Windows).
+//
+// So when we set the label of a widget, we keep ownership
+// of the string by storing it in a private collection. This
+// collection is a "list" object. I chose that one so that
+// strings currently in the collection are undisturbed when
+// new strings are added. Widgets keep a pointer to the
+// characters owned by the string object. If that object
+// moves around as the result of adding new string objects,
+// it might invalidate the pointer owned by the widget.
+
+typedef pair<Fl_Widget*, string> WidgetString;
+typedef list<WidgetString> WidgetStringList;
+
+WidgetStringList gWidgetStrings;
+
+const char* PrvSetWidgetString (Fl_Widget* o, const string& s)
+{
+ // First see if there's already an entry for this widget.
+
+ WidgetStringList::iterator iter = gWidgetStrings.end ();
+ while (iter != gWidgetStrings.end ())
+ {
+ if (iter->first == o)
+ {
+ // Widget is already in the collection.
+ // Replace the string it owns.
+
+ iter->second = s;
+ return iter->second.c_str ();
+ }
+
+ ++iter;
+ }
+
+ // Widget is not in the collection, so add an entry for it.
+
+ gWidgetStrings.push_back (WidgetString (o, s));
+ return (--(gWidgetStrings.end()))->second.c_str ();
+}
+
+void PrvClearWidgetString (Fl_Widget* o)
+{
+ WidgetStringList::iterator iter = gWidgetStrings.end ();
+ while (iter != gWidgetStrings.end ())
+ {
+ if (iter->first == o)
+ {
+ gWidgetStrings.erase (iter);
+ return;
+ }
+
+ ++iter;
+ }
+}
+
+void PrvClearAllWidgetStrings (void)
+{
+ gWidgetStrings.clear ();
+}
+
+void PrvClearDlgWidgetStrings (Fl_Group* w)
+{
+ for (int ii = 0; ii < w->children (); ++ii)
+ {
+ Fl_Widget* child = w->child (ii);
+ ::PrvClearWidgetString (child);
+
+ Fl_Group* g = dynamic_cast<Fl_Group*>(child);
+ if (g)
+ {
+ ::PrvClearDlgWidgetStrings (g);
+ }
+ }
+}
+
+typedef pair<EmDlgContext*, EmDlgItemID> EmWidget;
+
+typedef vector<EmWidget> EmWidgetList;
+EmWidgetList gWidgetList;
+
+typedef vector<Fl_Window*> Fl_Window_List;
+Fl_Window_List gDialogList;
+
+
+EmWidget PrvPopWidget (void)
+{
+ EmWidget result ((EmDlgContext*) NULL, kDlgItemNone);
+
+ if (!gWidgetList.empty ())
+ {
+ result = gWidgetList.front (); // Note, this is "top()" on Windows, maybe others...
+ gWidgetList.erase (gWidgetList.begin ());
+ }
+
+ return result;
+}
+
+
+void PrvPushWidget (EmDlgContext* context, EmDlgItemID itemID)
+{
+ EmWidget widget (context, itemID);
+ gWidgetList.push_back (widget);
+}
+
+
+void PrvClearQueue (EmDlgContext* context)
+{
+ if (!context)
+ {
+ gWidgetList.clear ();
+ }
+ else
+ {
+ EmWidgetList::iterator iter = gWidgetList.begin ();
+
+ while (iter != gWidgetList.end ())
+ {
+ if (context == iter->first)
+ {
+ EmWidgetList::size_type delta = iter - gWidgetList.begin ();
+ gWidgetList.erase (iter);
+ iter = gWidgetList.begin () + delta;
+
+ continue;
+ }
+
+ ++iter;
+ }
+ }
+}
+
+
+EmDlgItemID PrvFindCancelItem (Fl_Group* w)
+{
+ EmDlgItemID result = kDlgItemNone;
+
+ for (int ii = 0; result == kDlgItemNone && ii < w->children (); ++ii)
+ {
+ Fl_Widget* child = w->child (ii);
+
+ Fl_Group* g = dynamic_cast<Fl_Group*>(child);
+ Fl_Button* b = dynamic_cast<Fl_Button*>(child);
+ if (g)
+ {
+ result = ::PrvFindCancelItem (g);
+ }
+ else if (b)
+ {
+ if (b->shortcut () == FL_Escape)
+ {
+ result = ::PrvFindIDByWidget (b);
+ }
+ }
+ }
+
+ return result;
+}
+
+
+void PrvWidgetCallback (Fl_Widget* w, void* c)
+{
+// EmDlgItemID id = ::PrvFindIDByWidget (w);
+// printf ("PrvWidgetCallback: id = 0x%08lX\n", (long) id);
+
+ EmDlgContext* context = (EmDlgContext*) c;
+ EmAssert (context);
+
+ EmDlgItemID itemID = ::PrvFindIDByWidget (w);
+ EmAssert (itemID != kDlgItemNone);
+
+ ::PrvPushWidget (context, itemID);
+}
+
+
+void PrvWindowCallback (Fl_Widget* w, void* c)
+{
+ EmDlgContext* context = (EmDlgContext*) c;
+ EmAssert (context);
+
+ Fl_Window* dlg = (Fl_Window*) context->fDlg;
+ EmAssert (dlg);
+
+ // Look for the item with the Escape shortcut.
+ EmDlgItemID itemID = ::PrvFindCancelItem (dlg);
+
+ // If one couldn't be found, for the kDlgItemCancel item
+ if (itemID == kDlgItemNone)
+ {
+ itemID = kDlgItemCancel;
+ }
+
+ ::PrvPushWidget (context, itemID);
+}
+
+
+void PrvInstallCallback (Fl_Widget* o, void* data)
+{
+ // Install callbacks only for our widgets. We shouldn't
+ // mess up any other callbacks -- they may do something
+ // important (such as the callback installed into scrollbars
+ // in an Fl_Scroll pane).
+
+ if (::PrvFindIDByWidget (o) != kDlgItemNone)
+ {
+ o->callback (&::PrvWidgetCallback, data);
+ }
+
+ // Set the callback for the topmost window, too, so that we
+ // get notification when it's closed.
+
+ else
+ {
+ Fl_Window* w = dynamic_cast<Fl_Window*> (o);
+
+ if (w)
+ {
+ o->callback (&::PrvWindowCallback, data);
+ }
+ }
+}
+
+
+void PrvInstallCallbacks (Fl_Group* w, EmDlgContext* context)
+{
+ // Set self.
+ ::PrvInstallCallback (w, context);
+
+ // Set children.
+ for (int ii = 0; ii < w->children (); ++ii)
+ {
+ Fl_Widget* child = w->child (ii);
+
+ Fl_Group* g = dynamic_cast<Fl_Group*>(child);
+ if (g)
+ {
+ ::PrvInstallCallbacks (g, context);
+ }
+ else
+ {
+ ::PrvInstallCallback (child, context);
+ }
+ }
+}
+
+
+void PrvAddDialog (Fl_Window* dlg)
+{
+ gDialogList.push_back (dlg);
+}
+
+
+void PrvRemoveDialog (Fl_Window* dlg)
+{
+ Fl_Window_List::iterator iter = find (gDialogList.begin (), gDialogList.end (), dlg);
+ EmAssert (iter != gDialogList.end ());
+ gDialogList.erase (iter);
+}
+
+
+void PrvDestroyDialog (EmDlgContext* context)
+{
+ EmAssert (context);
+
+ Fl_Window* dlg = reinterpret_cast<Fl_Window*>(context->fDlg);
+ EmAssert (dlg);
+
+ context->Destroy ();
+ EmDlg::HostStopIdling (*context);
+
+ dlg->hide ();
+
+ ::PrvRemoveDialog (dlg);
+ ::PrvClearDlgWidgetIDs (dlg);
+ ::PrvClearDlgWidgetStrings (dlg);
+ ::PrvClearQueue (context);
+
+ delete dlg;
+ delete context;
+}
+
+
+// Process all events on our dialog widgets. If dlg is non-NULL,
+// look for events that close that dialog. If the dialog is closed,
+// return true and fill in dismissingItemID with the ID of the item
+// that closed the dialog.
+
+Bool PrvHandleDialogEvents (Fl_Window* dlg, EmDlgItemID& dismissingItemID)
+{
+ // Loop, getting dialog items that have been manipulated in some way.
+
+ EmWidget w = ::PrvPopWidget ();
+
+ EmDlgContext* context = w.first;
+ EmDlgItemID itemID = w.second;
+
+ while (context != NULL && itemID != kDlgItemNone)
+ {
+ // Handle the event on the dialog item, checking to see if the
+ // dialog should be closed.
+
+ if (context->Event (itemID) == kDlgResultClose)
+ {
+ // The dialog is closing.
+
+ Fl_Window* closingDlg = reinterpret_cast<Fl_Window*>(context->fDlg);
+
+ // See if we're interested that this dialog closed.
+
+ Bool interested = dlg && (closingDlg == dlg);
+
+ // Destroy the dialog.
+
+ ::PrvDestroyDialog (context);
+
+ // If we're interested that this dialog closed, record the
+ // item that closed it and return TRUE.
+
+ if (interested)
+ {
+ dismissingItemID = itemID;
+
+ return true;
+ }
+ }
+
+ w = ::PrvPopWidget ();
+ context = w.first;
+ itemID = w.second;
+ }
+
+ return false;
+}
+
+
+void HandleDialogs (void)
+{
+ EmDlgItemID dummyItemID;
+ (void) ::PrvHandleDialogEvents (NULL, dummyItemID);
+}
+
+
+void HandleModalDialog (Fl_Window* dlg, EmDlgItemID& itemID)
+{
+ while (1)
+ {
+ // Handle any queued events.
+
+ if (::PrvHandleDialogEvents (dlg, itemID))
+ break;
+
+ // Process any system events.
+
+ Fl::wait ();
+
+ // Check to see if an idle handler has asked to close the window.
+
+ EmDlgContext* context = (EmDlgContext*) dlg->user_data ();
+ EmAssert (context);
+
+ if (context->fFnResult == kDlgResultClose)
+ {
+ ::PrvDestroyDialog (context);
+ break;
+ }
+ }
+}
+
+
+void CloseAllDialogs (void)
+{
+ Fl_Window_List::iterator iter = gDialogList.begin ();
+
+ while (iter != gDialogList.end ())
+ {
+ EmDlgContext* context = (EmDlgContext*) (*iter)->user_data ();
+ EmAssert (context);
+
+ ::PrvDestroyDialog (context);
+ ++iter;
+ }
+
+ gDialogList.clear ();
+}
+
+
+// -----------------------------------------------------------------------------
+// callback used to close modal dialogs. modalResult is < 0 if not yet completed.
+// set modalResult to be >=0 to complete dialog. Typically 0=cancel, 1=ok
+
+static long modalResult;
+void modalCallback(Fl_Return_Button*, void* result)
+{
+ modalResult = (long) result;
+}
+
+
+// -----------------------------------------------------------------------------
+// modal dialog control loop
+
+static int postModalDialog (Fl_Window* dlg)
+{
+ modalResult = -9999;
+ dlg->show();
+
+ // run our own event loop so that we have total control
+ // of the UI thread
+ for (;;)
+ {
+ Fl::wait ();
+ if (modalResult != -9999)
+ break;
+
+ if (!dlg->shown ())
+ {
+ // user hit escape (cancel)
+ modalResult = 0;
+ break;
+ }
+ }
+
+ // Clear out the default item queue. Stuff that we clicked on
+ // that didn't have a callback function will be in here. The
+ // items in that queue will be invalid after we close the window
+ // if we don't clear it out.
+
+ while (Fl::readqueue ())
+ ;
+
+ dlg->hide ();
+
+ return modalResult;
+}
+
+
+// -----------------------------------------------------------------------------
+// URL handler callback. This works whether netscape is currently running or
+// not.
+//!TODO: work with other browsers
+
+void openURL (Fl_Button* box, void*)
+{
+ char buffer[PATH_MAX];
+ char url[PATH_MAX];
+
+ box->labelcolor (FL_RED);
+
+ // get the label, trim the opening '<' and closing '>'
+ strcpy (url, &(box->label()[1]));
+ url [strlen (url) - 1] = '\0';
+
+#ifdef __QNXNTO__
+ sprintf (buffer, "voyager -u %s &", url);
+#else
+ sprintf (buffer, "netscape -remote 'openURL(%s,new-window)' || netscape '%s' &", url, url);
+#endif
+
+ system (buffer);
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmDlg::HostRunGetFile
+ *
+ * DESCRIPTION: Platform-specific routine for getting the name of a
+ * file from the user. This file name is used to load
+ * the file.
+ *
+ * PARAMETERS: typeList - types of files user is allowed to select.
+ * ref - selected file is returned here. Valid only if
+ * function result is kDlgItemOK.
+ *
+ * RETURNED: ID of dialog item that dismissed the dialog.
+ *
+ ***********************************************************************/
+
+EmDlgItemID EmDlg::HostRunGetFile (const void* parameters)
+{
+ EmAssert (parameters);
+ DoGetFileParameters& data = *(DoGetFileParameters*) parameters;
+
+ FilterList filter = ::PrvConvertTypeList (data.fFilterList);
+
+ FileChooser chooser (data.fDefaultPath.IsSpecified () ? data.fDefaultPath.GetFullPath ().c_str () : NULL,
+ filter.c_str (), FileChooser::SINGLE, data.fPrompt.c_str ());
+
+ chooser.show ();
+
+ while (chooser.shown ())
+ Fl::wait ();
+
+ long count = chooser.count ();
+ if (count == 0)
+ return kDlgItemCancel;
+
+ // Get a EmFileRef to the given file
+
+ data.fResult = EmFileRef (chooser.value(1));
+
+ return kDlgItemOK;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmDlg::HostRunGetFileList
+ *
+ * DESCRIPTION: Platform-specific routine for getting the name of a
+ * file from the user. This file name is used to load
+ * the file.
+ *
+ * PARAMETERS: typeList - types of files user is allowed to select.
+ * ref - selected file is returned here. Valid only if
+ * function result is kDlgItemOK.
+ *
+ * RETURNED: ID of dialog item that dismissed the dialog.
+ *
+ ***********************************************************************/
+
+EmDlgItemID EmDlg::HostRunGetFileList (const void* parameters)
+{
+ EmAssert (parameters);
+ DoGetFileListParameters& data = *(DoGetFileListParameters*) parameters;
+
+ FilterList filter = ::PrvConvertTypeList (data.fFilterList);
+
+ FileChooser chooser (data.fDefaultPath.IsSpecified () ? data.fDefaultPath.GetFullPath ().c_str () : NULL,
+ filter.c_str (), FileChooser::MULTI, data.fPrompt.c_str ());
+
+ chooser.show ();
+
+ while (chooser.shown ())
+ Fl::wait ();
+
+ long count = chooser.count ();
+ if (count == 0)
+ return kDlgItemCancel;
+
+ for (long ii = 1; ii <= count; ++ii)
+ {
+ data.fResults.push_back (EmFileRef (chooser.value (ii)));
+ }
+
+ return kDlgItemOK;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmDlg::HostRunPutFile
+ *
+ * DESCRIPTION: Platform-specific routine for getting the name of a
+ * file from the user. This file name is used to save
+ * the file.
+ *
+ * PARAMETERS: defName - default name for the file to be saved.
+ * ref - selected file is returned here. Valid only if
+ * function result is kDlgItemOK.
+ *
+ * RETURNED: ID of dialog item that dismissed the dialog.
+ *
+ ***********************************************************************/
+
+EmDlgItemID EmDlg::HostRunPutFile (const void* parameters)
+{
+ EmAssert (parameters);
+ DoPutFileParameters& data = *(DoPutFileParameters*) parameters;
+
+ FilterList filter = ::PrvConvertTypeList (data.fFilterList);
+
+ FileChooser chooser (data.fDefaultPath.IsSpecified () ? data.fDefaultPath.GetFullPath ().c_str () : NULL,
+ filter.c_str (), FileChooser::CREATE, data.fPrompt.c_str ());
+
+ chooser.show ();
+
+ while (chooser.shown ())
+ Fl::wait ();
+
+ long count = chooser.count ();
+ if (count == 0)
+ return kDlgItemCancel;
+
+ // Get a EmFileRef to the given file
+
+ data.fResult = EmFileRef (chooser.value (1));
+
+ return kDlgItemOK;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmDlg::HostRunGetDirectory
+ *
+ * DESCRIPTION: Platform-specific routine for getting the name of a
+ * file from the user. This file name is used to load
+ * the file.
+ *
+ * PARAMETERS: typeList - types of files user is allowed to select.
+ * ref - selected file is returned here. Valid only if
+ * function result is kDlgItemOK.
+ *
+ * RETURNED: ID of dialog item that dismissed the dialog.
+ *
+ ***********************************************************************/
+
+EmDlgItemID EmDlg::HostRunGetDirectory (const void* parameters)
+{
+ EmAssert (parameters);
+ DoGetDirectoryParameters& data = *(DoGetDirectoryParameters*) parameters;
+
+ FileChooser chooser (data.fDefaultPath.IsSpecified () ? data.fDefaultPath.GetFullPath ().c_str () : NULL,
+ "nEveRmAtCh*", FileChooser::DIRECTORY, data.fPrompt.c_str ());
+
+ chooser.show ();
+
+ while (chooser.shown ())
+ Fl::wait ();
+
+ long count = chooser.count ();
+ if (count == 0)
+ return kDlgItemCancel;
+
+ // Get a EmFileRef to the given file
+
+ data.fResult = EmDirRef (chooser.value (1));
+
+ return kDlgItemOK;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: HostRunSessionSave
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+EmDlgItemID EmDlg::HostRunSessionSave (const void* parameters)
+{
+ EmAssert (parameters);
+ DoSessionSaveParameters& data = *(DoSessionSaveParameters*) parameters;
+
+ string saveChanges (Platform::GetString (kStr_SaveBeforeClosing));
+
+ ParamList paramList;
+ paramList.push_back (string ("%AppName"));
+ paramList.push_back (data.fAppName);
+ paramList.push_back (string ("%DocName"));
+ paramList.push_back (data.fDocName);
+
+ string msg = Errors::ReplaceParameters (saveChanges, paramList);
+
+ int result = fl_choice (msg.c_str(),
+ Platform::GetString (kStr_Cancel).c_str(),
+ Platform::GetString (kStr_Yes).c_str(),
+ Platform::GetString (kStr_No).c_str() );
+
+ if (result == 1) // yes
+ return kDlgItemYes;
+
+ else if (result == 2) // no
+ return kDlgItemNo;
+
+ // result == 0
+ return kDlgItemCancel;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: HostRunAboutBox
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+EmDlgItemID EmDlg::HostRunAboutBox (const void* parameters)
+{
+ Fl_Window* aboutWin = ::PrvMakeDialog (kDlgAboutBox);
+ postModalDialog (aboutWin);
+ delete aboutWin;
+
+ return kDlgItemOK;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: HostRunDialog
+ *
+ * DESCRIPTION: Common routine that handles the creation of a dialog,
+ * initializes it (via the dialog handler), fetches events,
+ * handles events (via the dialog handler), and closes
+ * 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::HostRunDialog (const void* parameters)
+{
+ EmAssert (parameters);
+ RunDialogParameters& data = *(RunDialogParameters*) parameters;
+
+ // Create the dialog.
+ Fl_Window* dlg = ::PrvMakeDialog (data.fDlgID);
+ if (!dlg)
+ return kDlgItemNone;
+
+ // Initialize the dialog.
+ if (!::PrvInitializeDialog (data.fFn, data.fUserData, data.fDlgID, dlg))
+ return kDlgItemNone;
+
+ // Handle the dialog.
+ EmDlgItemID itemID;
+
+ ::HandleModalDialog (dlg, itemID);
+
+ // Return the item that dismissed the dialog.
+ return itemID;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: HostDialogOpen
+ *
+ * DESCRIPTION: .
+ *
+ * PARAMETERS: .
+ *
+ * RETURNED: .
+ *
+ ***********************************************************************/
+
+EmDlgRef EmDlg::HostDialogOpen (EmDlgFn fn, void* data, EmDlgID dlgID)
+{
+ // Create the dialog.
+ Fl_Window* dlg = ::PrvMakeDialog (dlgID);
+ if (!dlg)
+ return (EmDlgRef) NULL;
+
+ // Initialize the dialog.
+ if (!::PrvInitializeDialog (fn, data, dlgID, dlg))
+ return (EmDlgRef) NULL;
+
+ // Return the dialog.
+ return (EmDlgRef) dlg;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: HostDialogClose
+ *
+ * DESCRIPTION: .
+ *
+ * PARAMETERS: .
+ *
+ * RETURNED: .
+ *
+ ***********************************************************************/
+
+void EmDlg::HostDialogClose (EmDlgRef dlg)
+{
+ Fl_Window* o = reinterpret_cast<Fl_Window*>(dlg);
+ if (!o)
+ return;
+
+ EmDlgContext* context = (EmDlgContext*) o->user_data ();
+ EmAssert (context);
+
+ ::PrvDestroyDialog (context);
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: HostStartIdling
+ *
+ * DESCRIPTION: Queue up our idle callback function with FLTK.
+ *
+ * PARAMETERS: context - context data to be provided to the callback
+ * function.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void EmDlg::HostStartIdling (EmDlgContext& context)
+{
+ Fl::add_timeout (.01, &::PrvIdleCallback, &context);
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: HostStopIdling
+ *
+ * DESCRIPTION: Remove our idle callback function from FLTK.
+ *
+ * PARAMETERS: context - context data to be provided to the callback
+ * function.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void EmDlg::HostStopIdling (EmDlgContext& context)
+{
+ Fl::remove_timeout (&::PrvIdleCallback, &context);
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmDlg::SetDlgBounds
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmDlg::SetDlgBounds (EmDlgRef dlg, const EmRect& bounds)
+{
+ Fl_Window* o = reinterpret_cast<Fl_Window*>(dlg);
+ if (!o)
+ return;
+
+ EmRect oldBounds = EmDlg::GetDlgBounds (dlg);
+
+ if (oldBounds != bounds)
+ {
+ o->resize (bounds.fLeft, bounds.fTop,
+ bounds.Width (), bounds.Height ());
+ }
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmDlg::CenterDlg
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmDlg::CenterDlg (EmDlgRef dlg)
+{
+ Fl_Window* o = reinterpret_cast<Fl_Window*>(dlg);
+ if (!o)
+ return;
+
+ o->position (
+ (Fl::w () - o->w ()) / 2,
+ (Fl::h () - o->h ()) / 3);
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmDlg::GetDlgBounds
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+EmRect EmDlg::GetDlgBounds (EmDlgRef dlg)
+{
+ EmRect result (0, 0, 0, 0);
+
+ Fl_Window* o = reinterpret_cast<Fl_Window*>(dlg);
+ if (!o)
+ return result;
+
+ result.Set (o->x(), o->y(), o->x() + o->w(), o->y() + o->h());
+
+ return result;
+}
+
+
+void EmDlg::SetDlgDefaultButton (EmDlgContext& context, EmDlgItemID item)
+{
+ Fl_Widget* o = ::PrvFindWidgetByID (item);
+ if (!o)
+ return;
+
+ Fl_Push_Button* b = dynamic_cast<Fl_Push_Button*>(o);
+ if (!b)
+ return;
+
+ b->SetDefaultButton ();
+}
+
+
+void EmDlg::SetDlgCancelButton (EmDlgContext& context, EmDlgItemID item)
+{
+ Fl_Widget* o = ::PrvFindWidgetByID (item);
+ if (!o)
+ return;
+
+ Fl_Push_Button* b = dynamic_cast<Fl_Push_Button*>(o);
+ if (!b)
+ return;
+
+ b->SetCancelButton ();
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmDlg::SetItemMin
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmDlg::SetItemMin (EmDlgRef dlg, EmDlgItemID item, long minValue)
+{
+ Fl_Widget* o = ::PrvFindWidgetByID (item);
+ if (!o)
+ return;
+
+ Fl_Valuator* valuator = dynamic_cast<Fl_Valuator*> (o);
+ if (valuator)
+ valuator->minimum (minValue);
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmDlg::SetItemValue
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmDlg::SetItemValue (EmDlgRef dlg, EmDlgItemID item, long value)
+{
+ Fl_Widget* o = ::PrvFindWidgetByID (item);
+ if (!o)
+ return;
+
+ // ...............................................................
+ // Includes: Fl_Button, Fl_Light_Button, Fl_Check_Button,
+ // Fl_Radio_Light_Button, Fl_Round_Button, Fl_Radio_Round_Button,
+ // Fl_Repeat_Button, Fl_Radio_Buttion, Fl_Toggle_Button
+ // ...............................................................
+
+ Fl_Button* button = dynamic_cast<Fl_Button*> (o);
+ if (button)
+ button->value (value);
+
+ // ...............................................................
+ // Includes: Fl_Choice, Fl_Menu_Bar, Fl_Menu_Button
+ // ...............................................................
+
+ Fl_Menu_* menu = dynamic_cast<Fl_Menu_*> (o);
+ if (menu)
+ {
+ // Prevent out-of-range values.
+
+ if (!menu->menu ())
+ return;
+
+ if (value > menu->size () - 1)
+ value = menu->size () - 1;
+ else if (value < 0)
+ value = 0;
+
+ // Adjust for the fact that FLTK treats divider lines as
+ // an attribute of the preceding menu item, while our model
+ // is to treat them as seperate menu items.
+
+ for (int ii = 0; ii < value; ++ii)
+ {
+ if (menu->menu ()[ii].flags & FL_MENU_DIVIDER)
+ {
+ --value;
+ }
+ }
+
+ menu->value (value);
+ menu->redraw ();
+ }
+
+ // ...............................................................
+ // Includes: Fl_Browser, Fl_Hold_Browser, Fl_Multi_Browser,
+ // Fl_Select_Browser (but not Fl_Browser_)
+ // ...............................................................
+
+ Fl_Browser* browser = dynamic_cast<Fl_Browser*> (o);
+ if (browser)
+ browser->value (value);
+
+ // ...............................................................
+ // Includes: Fl_Adjuster, Fl_Counter, Fl_Dial, Fl_Roller,
+ // Fl_Scrollber, Fl_Slider, Fl_Value_Input, Fl_Value_Slider,
+ // Fl_Value_Output
+ // ...............................................................
+
+ Fl_Valuator* valuator = dynamic_cast<Fl_Valuator*> (o);
+ if (valuator)
+ valuator->value (value);
+
+ // ...............................................................
+ // Includes: Fl_Input_, Fl_Input, Fl_Float_Input, Fl_Int_Input,
+ // Fl_Multiline_Input, Fl_Secret_Input, Fl_Output and
+ // Fl_Multiline_Output
+ // ...............................................................
+
+ Fl_Input_* input = dynamic_cast<Fl_Input_*> (o);
+ if (input)
+ {
+ char buffer[20];
+ sprintf (buffer, "%ld", (long) value);
+ EmDlg::SetItemText (dlg, item, buffer);
+ }
+
+ // ...............................................................
+ // Includes: Fl_Box
+ // ...............................................................
+
+ Fl_Box* box = dynamic_cast<Fl_Box*> (o);
+ if (box)
+ {
+ char buffer[20];
+ ::FormatInteger (buffer, value);
+ EmDlg::SetItemText (dlg, item, buffer);
+ }
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmDlg::SetItemMax
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmDlg::SetItemMax (EmDlgRef dlg, EmDlgItemID item, long maxValue)
+{
+ Fl_Widget* o = ::PrvFindWidgetByID (item);
+ if (!o)
+ return;
+
+ // ...............................................................
+ // Includes: Fl_Adjuster, Fl_Counter, Fl_Dial, Fl_Roller,
+ // Fl_Scrollber, Fl_Slider, Fl_Value_Input, Fl_Value_Slider,
+ // Fl_Value_Output
+ // ...............................................................
+
+ Fl_Valuator* valuator = dynamic_cast<Fl_Valuator*> (o);
+ if (valuator)
+ valuator->maximum (maxValue);
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmDlg::SetItemBounds
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmDlg::SetItemBounds (EmDlgRef dlg, EmDlgItemID item, const EmRect& bounds)
+{
+ Fl_Widget* o = ::PrvFindWidgetByID (item);
+ if (!o)
+ return;
+
+ EmRect oldBounds = EmDlg::GetItemBounds (dlg, item);
+
+ if (oldBounds != bounds)
+ {
+ o->resize (bounds.fLeft, bounds.fTop,
+ bounds.Width (), bounds.Height ());
+ }
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmDlg::SetItemText
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmDlg::SetItemText (EmDlgRef dlg, EmDlgItemID item, string str)
+{
+ Fl_Widget* o = ::PrvFindWidgetByID (item);
+ if (!o)
+ return;
+
+ Fl_Input_* in = dynamic_cast<Fl_Input_*> (o);
+ if (in)
+ {
+ // Can you believe it: Fl_Input_ doesn't do word wrap!
+ // So we have to do it ourself...
+ str = ::PrvBreakLine (in, str.c_str ());
+ in->value (str.c_str ());
+ }
+ else
+ {
+ // Setting the text of other items is tricky. That would be
+ // done by calling Fl_Widget::label. However, that function
+ // does not copy the text -- just the text pointer. That
+ // means the string object (or whatever is holding the storage)
+ // must exist after this function is called.
+
+ // Additionally, it appears that we have to hide and then show
+ // the widget in order to get it to update properly. Merely
+ // calling redraw will not erase the old text in boxes like
+ // the file counter in the "Import Database" dialog.
+
+ const char* s = ::PrvSetWidgetString (o, str);
+
+ if (o->visible_r ())
+ {
+ o->hide ();
+ o->label (s);
+ o->show ();
+ }
+ else
+ {
+ o->label (s);
+ }
+ }
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmDlg::GetItemValue
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+long EmDlg::GetItemValue (EmDlgRef dlg, EmDlgItemID item)
+{
+ Fl_Widget* o = ::PrvFindWidgetByID (item);
+ if (!o)
+ return 0;
+
+ // ...............................................................
+ // Includes: Fl_Button, Fl_Light_Button, Fl_Check_Button,
+ // Fl_Radio_Light_Button, Fl_Round_Button, Fl_Radio_Round_Button,
+ // Fl_Repeat_Button, Fl_Radio_Buttion, Fl_Toggle_Button
+ // ...............................................................
+
+ Fl_Button* button = dynamic_cast<Fl_Button*> (o);
+ if (button)
+ return button->value ();
+
+ // ...............................................................
+ // Includes: Fl_Choice, Fl_Menu_Bar, Fl_Menu_Button
+ // ...............................................................
+
+ Fl_Menu_* menu = dynamic_cast<Fl_Menu_*> (o);
+ if (menu)
+ {
+ if (menu->mvalue () == NULL)
+ return -1;
+
+ long result = menu->value();
+ long add = 0;
+
+ // Adjust for the fact that FLTK treats divider lines as
+ // an attribute of the preceding menu item, while our model
+ // is to treat them as seperate menu items.
+
+ for (int ii = 0; ii < result; ++ii)
+ {
+ if (menu->menu()[ii].flags & FL_MENU_DIVIDER)
+ {
+ add++;
+ }
+ }
+
+ return result + add;
+ }
+
+ // ...............................................................
+ // Includes: Fl_Browser (but not Fl_Browser_)
+ // ...............................................................
+
+ Fl_Browser* browser = dynamic_cast<Fl_Browser*> (o);
+ if (browser)
+ return browser->value ();
+
+ // ...............................................................
+ // Includes: Fl_Adjuster, Fl_Counter, Fl_Dial, Fl_Roller,
+ // Fl_Scrollber, Fl_Slider, Fl_Value_Input, Fl_Value_Slider,
+ // Fl_Value_Output
+ // ...............................................................
+
+ Fl_Valuator* valuator = dynamic_cast<Fl_Valuator*> (o);
+ if (valuator)
+ return (long) valuator->value (); // !!! Really is a "double"!
+
+ // ...............................................................
+ // Includes: Fl_Input_, Fl_Input, Fl_Float_Input, Fl_Int_Input,
+ // Fl_Multiline_Input, Fl_Secret_Input, Fl_Output and
+ // Fl_Multiline_Output
+ // ...............................................................
+
+ Fl_Input_* input = dynamic_cast<Fl_Input_*> (o);
+ if (input)
+ {
+ const char* text = input->value ();
+ long value = 0;
+ sscanf (text, "%ld", &value);
+ return value;
+ }
+
+ return 0;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmDlg::GetItemBounds
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+EmRect EmDlg::GetItemBounds (EmDlgRef dlg, EmDlgItemID item)
+{
+ EmRect result (0, 0, 0, 0);
+
+ Fl_Widget* o = ::PrvFindWidgetByID (item);
+ if (!o)
+ return result;
+
+ result.Set (o->x(), o->y(), o->x() + o->w(), o->y() + o->h());
+
+ return result;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmDlg::GetItemText
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+string EmDlg::GetItemText (EmDlgRef dlg, EmDlgItemID item)
+{
+ Fl_Widget* o = ::PrvFindWidgetByID (item);
+ if (!o)
+ return string ();
+
+ Fl_Input_* in = dynamic_cast<Fl_Input_*> (o);
+ if (in)
+ return string (in->value ());
+
+ return string (o->label ());
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmDlg::EnableItem
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmDlg::EnableItem (EmDlgRef dlg, EmDlgItemID item)
+{
+ Fl_Widget* o = ::PrvFindWidgetByID (item);
+ if (!o)
+ return;
+
+ o->activate ();
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmDlg::DisableItem
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmDlg::DisableItem (EmDlgRef dlg, EmDlgItemID item)
+{
+ Fl_Widget* o = ::PrvFindWidgetByID (item);
+ if (!o)
+ return;
+
+ o->deactivate ();
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmDlg::ShowItem
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmDlg::ShowItem (EmDlgRef dlg, EmDlgItemID item)
+{
+ Fl_Widget* o = ::PrvFindWidgetByID (item);
+ if (!o)
+ return;
+
+ o->show ();
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmDlg::HideItem
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmDlg::HideItem (EmDlgRef dlg, EmDlgItemID item)
+{
+ Fl_Widget* o = ::PrvFindWidgetByID (item);
+ if (!o)
+ return;
+
+ o->hide ();
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmDlg::ClearMenu
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmDlg::ClearMenu (EmDlgRef dlg, EmDlgItemID item)
+{
+ Fl_Widget* o = ::PrvFindWidgetByID (item);
+ if (!o)
+ return;
+
+ Fl_Menu_* menu = dynamic_cast<Fl_Menu_*> (o);
+ EmAssert (menu);
+
+ menu->clear ();
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmDlg::AppendToMenu
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmDlg::AppendToMenu (EmDlgRef dlg, EmDlgItemID item, const StringList& strList)
+{
+ Fl_Widget* o = ::PrvFindWidgetByID (item);
+ if (!o)
+ return;
+
+ Fl_Menu_* menu = dynamic_cast<Fl_Menu_*> (o);
+ EmAssert (menu);
+
+ StringList::const_iterator iter = strList.begin ();
+ while (iter != strList.end ())
+ {
+ if (iter->empty ())
+ {
+ menu->mode (menu->size () - 2, FL_MENU_DIVIDER);
+ }
+ else
+ {
+ menu->add (iter->c_str (), 0, NULL, NULL, 0);
+ }
+
+ ++iter;
+ }
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmDlg::ClearList
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmDlg::ClearList (EmDlgRef dlg, EmDlgItemID item)
+{
+ Fl_Widget* o = ::PrvFindWidgetByID (item);
+ if (!o)
+ return;
+
+ Fl_Browser* b = dynamic_cast<Fl_Browser*> (o);
+ EmAssert (b);
+
+ b->clear ();
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmDlg::EnableMenuItem
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmDlg::EnableMenuItem (EmDlgRef dlg, EmDlgItemID item, long menuItem)
+{
+ Fl_Widget* o = ::PrvFindWidgetByID (item);
+ if (!o)
+ return;
+
+ Fl_Menu_* menu = dynamic_cast<Fl_Menu_*> (o);
+ EmAssert (menu);
+ EmAssert (menu->menu ());
+ EmAssert (menuItem >= 0);
+ EmAssert (menuItem < menu->size ());
+
+ // Adjust for the fact that FLTK treats divider lines as
+ // an attribute of the preceding menu item, while our model
+ // is to treat them as seperate menu items.
+
+ for (int ii = 0; ii < menuItem; ++ii)
+ {
+ if (menu->menu () [ii].flags & FL_MENU_DIVIDER)
+ {
+ --menuItem;
+ }
+ }
+
+ /* DOLATER - kja: This won't work properly if we try to change a divider */
+ menu->mode (menuItem, 0);
+ menu->redraw ();
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmDlg::DisableMenuItem
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmDlg::DisableMenuItem (EmDlgRef dlg, EmDlgItemID item, long menuItem)
+{
+ Fl_Widget* o = ::PrvFindWidgetByID (item);
+ if (!o)
+ return;
+
+ Fl_Menu_* menu = dynamic_cast<Fl_Menu_*> (o);
+ EmAssert (menu);
+ EmAssert (menu->menu ());
+ EmAssert (menuItem >= 0);
+ EmAssert (menuItem < menu->value ());
+
+ // Adjust for the fact that FLTK treats divider lines as
+ // an attribute of the preceding menu item, while our model
+ // is to treat them as seperate menu items.
+
+ for (int ii = 0; ii < menuItem; ++ii)
+ {
+ if (menu->menu () [ii].flags & FL_MENU_DIVIDER)
+ {
+ --menuItem;
+ }
+ }
+
+ /* DOLATER - kja: This won't work properly if we try to change a divider */
+ menu->mode (menuItem, FL_MENU_INACTIVE);
+ menu->redraw ();
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmDlg::AppendToList
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmDlg::AppendToList (EmDlgRef dlg, EmDlgItemID item, const StringList& strList)
+{
+ Fl_Widget* o = ::PrvFindWidgetByID (item);
+ if (!o)
+ return;
+
+ Fl_Browser* b = dynamic_cast<Fl_Browser*> (o);
+ EmAssert (b);
+
+ StringList::const_iterator iter = strList.begin ();
+ while (iter != strList.end ())
+ {
+ b->add (iter->c_str (), NULL);
+ ++iter;
+ }
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmDlg::SelectListItems
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmDlg::SelectListItems (EmDlgRef dlg, EmDlgItemID item, const EmDlgItemIndexList& itemList)
+{
+ Fl_Widget* o = ::PrvFindWidgetByID (item);
+ if (!o)
+ return;
+
+ Fl_Browser* b = dynamic_cast<Fl_Browser*> (o);
+ EmAssert (b);
+
+ EmDlgItemIndexList::const_iterator iter = itemList.begin ();
+ while (iter != itemList.end ())
+ {
+ b->select (*iter + 1, 1);
+ ++iter;
+ }
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmDlg::UnselectListItems
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmDlg::UnselectListItems (EmDlgRef dlg, EmDlgItemID item, const EmDlgListIndexList& itemList)
+{
+ Fl_Widget* o = ::PrvFindWidgetByID (item);
+ if (!o)
+ return;
+
+ Fl_Browser* b = dynamic_cast<Fl_Browser*> (o);
+ EmAssert (b);
+
+ EmDlgItemIndexList::const_iterator iter = itemList.begin ();
+ while (iter != itemList.end ())
+ {
+ b->select (*iter + 1, 0);
+ ++iter;
+ }
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmDlg::GetSelectedItems
+ *
+ * DESCRIPTION:
+ *
+ * PARAMETERS: None
+ *
+ * RETURNED: Nothing
+ *
+ ***********************************************************************/
+
+void EmDlg::GetSelectedItems (EmDlgRef dlg, EmDlgItemID item, EmDlgItemIndexList& itemList)
+{
+ Fl_Widget* o = ::PrvFindWidgetByID (item);
+ if (!o)
+ return;
+
+ Fl_Browser* b = dynamic_cast<Fl_Browser*> (o);
+ EmAssert (b);
+
+ for (int ii = 1; ii <= b->size (); ++ii)
+ {
+ if (b->selected (ii))
+ {
+ itemList.push_back (ii - 1);
+ }
+ }
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: EmDlg::GetTextHeight
+ *
+ * DESCRIPTION: Determine the height the text would be if fitted into
+ * the given item.
+ *
+ * PARAMETERS: none
+ *
+ * RETURNED: New text height
+ *
+ ***********************************************************************/
+
+int EmDlg::GetTextHeight (EmDlgRef dlg, EmDlgItemID item, const string& s)
+{
+ int result = 0;
+
+ Fl_Widget* o = ::PrvFindWidgetByID (item);
+ if (!o)
+ return result;
+
+ EmRect bounds = EmDlg::GetItemBounds (dlg, item);
+ int width = bounds.Width ();
+
+ Fl_Input_* i = dynamic_cast<Fl_Input_*>(o);
+
+ if (i)
+ {
+ // Note that Fl_Output::draw insets the width of the widget
+ // area when drawing. We need to account for that here if we want
+ // our text to be measured the same way it's laid out.
+
+ Fl_Boxtype b = i->box () ? i->box () : FL_DOWN_BOX;
+ width -= Fl::box_dw (b) + 6;
+
+ // FIXME: The Fl_Label structure is not documented, and its layout
+ // has changed in the past. These two measurements should be
+ // rewritten to use fl_measure or perhaps o->measure_label somehow.
+
+ Fl_Label label =
+ {
+ s.c_str (),
+#ifndef HAVE_LEGACY_FL_LABEL
+ NULL,
+ NULL,
+#endif
+ FL_NORMAL_LABEL,
+ i->textfont (),
+ i->textsize (),
+ i->textcolor ()
+ };
+
+ label.measure (width, result);
+
+ result += Fl::box_dh (b);
+ }
+ else
+ {
+ // Note that Fl_Widget::draw_label insets the width of the widget
+ // area when drawing. We need to account for that here if we want
+ // our text to be measured the same way it's laid out.
+
+ width -= Fl::box_dw (o->box ());
+
+ if ((o->w () > 11) && (o->align () & (FL_ALIGN_LEFT | FL_ALIGN_RIGHT)))
+ {
+ width -= 6;
+ }
+
+ Fl_Label label =
+ {
+ s.c_str (),
+#ifndef HAVE_LEGACY_FL_LABEL
+ NULL,
+ NULL,
+#endif
+ o->labeltype (),
+ o->labelfont (),
+ o->labelsize (),
+ o->labelcolor ()
+ };
+
+ label.measure (width, result);
+ }
+
+ return result;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: PrvConvertTypeList
+ *
+ * DESCRIPTION: .
+ *
+ * PARAMETERS: None.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+FilterList PrvConvertTypeList (const EmFileTypeList& typeList)
+{
+ FilterList filter;
+
+ filter += "{";
+
+ EmFileTypeList::const_iterator iter = typeList.begin ();
+
+ while (iter != typeList.end ())
+ {
+ switch (*iter)
+ {
+ case kFileTypeNone:
+ break;
+
+ case kFileTypeApplication:
+ break;
+
+ case kFileTypeROM:
+ ::PrvAddFilter (filter, "*.[Rr][Oo][Mm]");
+ break;
+
+ case kFileTypeSession:
+ ::PrvAddFilter (filter, "*.[Pp][Ss][Ff]");
+ break;
+
+ case kFileTypeEvents:
+ ::PrvAddFilter (filter, "*.[Pp][Ee][Vv]");
+ break;
+
+ case kFileTypePreference:
+ break;
+
+ case kFileTypePalmApp:
+ ::PrvAddFilter (filter, "*.[Pp][Rr][Cc]");
+ break;
+
+ case kFileTypePalmDB:
+ ::PrvAddFilter (filter, "*.[Pp][Dd][Bb]");
+ break;
+
+ case kFileTypePalmQA:
+ ::PrvAddFilter (filter, "*.[Pp][Qq][Aa]");
+ break;
+
+ case kFileTypeText:
+ ::PrvAddFilter (filter, "*.[Tt][Xx][Tt]");
+ break;
+
+ case kFileTypePicture:
+ ::PrvAddFilter (filter, "*.[Pp][Pp][Mm]");
+ break;
+
+ case kFileTypeSkin:
+ ::PrvAddFilter (filter, "*.[Ss][Kk][Ii][Nn]");
+ break;
+
+ case kFileTypeProfile:
+ break;
+
+ case kFileTypePalmAll:
+ ::PrvAddFilter (filter, "*.[Pp][Rr][Cc]|*.[Pp][Dd][Bb]|*.[Pp][Qq][Aa]");
+ break;
+
+ case kFileTypeAll:
+ ::PrvAddFilter (filter, "*");
+ break;
+
+ case kFileTypeLast:
+ EmAssert (false);
+ break;
+ }
+
+ ++iter;
+ }
+
+ filter += "}";
+
+ return filter;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: PrvAddFilter
+ *
+ * DESCRIPTION: .
+ *
+ * PARAMETERS: None.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void PrvAddFilter (FilterList& filter, const char* pattern)
+{
+ if (filter.size() != 1)
+ {
+ filter += "|";
+ }
+
+ filter += pattern;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: PrvMakeDialog
+ *
+ * DESCRIPTION: .
+ *
+ * PARAMETERS: None.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+Fl_Window* PrvMakeDialog (EmDlgID id)
+{
+ Fl_Window* w = NULL;
+
+ switch (id)
+ {
+ case kDlgNone:
+ break;
+
+ case kDlgAboutBox:
+ w = ::PrvMakeAboutDialog ();
+ break;
+
+ case kDlgSessionNew:
+ w = ::PrvMakeSessionNewDialog ();
+ break;
+
+ case kDlgSessionSave:
+ break;
+
+ case kDlgHordeNew:
+ w = ::PrvMakeNewHordeDialog ();
+ break;
+
+ case kDlgDatabaseImport:
+ w = ::PrvMakeDatabaseImportDialog ();
+ break;
+
+ case kDlgDatabaseExport:
+ w = ::PrvMakeDatabaseExportDialog ();
+ break;
+
+ case kDlgROMTransferQuery:
+ w = ::PrvMakeROMTransferQueryDialog ();
+ break;
+
+ case kDlgROMTransferProgress:
+ w = ::PrvMakeROMTransferProgressDialog ();
+ break;
+
+ case kDlgGremlinControl:
+ w = ::PrvMakeGremlinControlDialog ();
+ break;
+
+ case kDlgEditPreferences:
+ w = ::PrvMakeEditPreferencesDialog ();
+ break;
+
+ case kDlgEditLogging:
+ w = ::PrvMakeEditLoggingOptionsDialog ();
+ break;
+
+ case kDlgEditDebugging:
+ w = ::PrvMakeEditDebuggingOptionsDialog ();
+ break;
+
+ case kDlgEditSkins:
+ w = ::PrvMakeEditSkinsDialog ();
+ break;
+
+ case kDlgEditHostFS:
+ w = ::PrvMakeHostFSOptionsDialog ();
+ break;
+
+ case kDlgCommonDialog:
+ w = ::PrvMakeCommonDialog ();
+ break;
+
+ case kDlgSaveBound:
+ break;
+
+ case kDlgEditBreakpoints:
+ w = ::PrvMakeEditBreakpointsDialog ();
+ break;
+
+ case kDlgEditCodeBreakpoint:
+ w = ::PrvMakeEditCodeBreakpointDialog ();
+ break;
+
+ case kDlgEditTracingOptions:
+ w = ::PrvMakeEditTracingOptionsDialog ();
+ break;
+
+ case kDlgEditPreferencesFullyBound:
+ break;
+
+ case kDlgReset:
+ w = ::PrvMakeResetDialog ();
+ break;
+
+ case kDlgSessionInfo:
+ w = ::PrvMakeSessionInfoDialog ();
+ break;
+
+ case kDlgGetSocketAddress:
+// w = ::PrvMakeGetSocketAddressDialog ();
+ break;
+
+ case kDlgEditErrorHandling:
+ w = ::PrvMakeEditErrorHandlingDialog ();
+ break;
+
+ case kDlgMinimizeProgress:
+ w = ::PrvMakeMinimizeDialog ();
+ break;
+ }
+
+ return w;
+}
+
+
+Bool PrvInitializeDialog (EmDlgFn fn, void* data, EmDlgID dlgID, Fl_Window* dlg)
+{
+ EmDlgContext* context = new EmDlgContext;
+ if (!context)
+ {
+ delete dlg;
+ return false;
+ }
+
+ context->fFn = fn;
+// context->fFnResult = filled in after fFn is called;
+ context->fDlg = (EmDlgRef) dlg;
+ context->fDlgID = dlgID;
+// context->fPanelID = filled in by subroutines;
+// context->fItemID = filled in by subroutines;
+// context->fCommandID = filled in by subroutines;
+// context->fNeedsIdle = filled in by c'tor to false;
+ context->fUserData = data;
+
+ // Center the dialog.
+ EmDlg::CenterDlg (context->fDlg);
+
+ // Install callbacks for all the items we handle.
+ ::PrvInstallCallbacks (dlg, context);
+
+ // Show the dialog. Note that the positioning of this call is
+ // important. The call to EmDlgContext::Init may result in the
+ // dialog's init handler trying to position the dialog. If it
+ // does that *before* the dialog is shown, some FLTK/X interaction
+ // causes the window to appear down and to the right by an amount
+ // equal to the top and left margins of the window frame. Showing
+ // the dialog first appears to fix that problem.
+ dlg->show();
+
+ // Initialize the dialog. Delete the dialog if
+ // initialization fails.
+ if (context->Init () == kDlgResultClose)
+ {
+ ::PrvDestroyDialog (context);
+ return false;
+ }
+
+ // Add this dialog to our internal list.
+ ::PrvAddDialog (dlg);
+
+ return true;
+}
+
+
+/***********************************************************************
+ *
+ * FUNCTION: PrvIdleCallback
+ *
+ * DESCRIPTION: Function called by FLTK when our timeout function has
+ * timed out. Here we call the custom dialog handler. If
+ * it doesn't indicate that it's time to close the dialog,
+ * requeue the timeout function.
+ *
+ * PARAMETERS: data - callback data. We store the pointer to the
+ * current dialog context here.
+ *
+ * RETURNED: Nothing.
+ *
+ ***********************************************************************/
+
+void PrvIdleCallback (void* data)
+{
+ EmAssert (data);
+ EmDlgContext& context = *(EmDlgContext*) data;
+
+ // Call the idle function. The result is stored in context.fFnResult
+ // as well as returned from the function. If we need to continue,
+ // then requeue the idle function.
+
+ if (context.Idle () != kDlgResultClose && context.fNeedsIdle)
+ {
+ EmDlg::HostStartIdling (context);
+ }
+}
+
+
+// Copied from fl_draw.cxx, since they don't let us get to it directly.
+
+#define MAXBUF 1024
+
+// Copy p to buf, replacing unprintable characters with ^X and \nnn
+// Stop at a newline of if MAXBUF characters written to buffer.
+// Also word-wrap if width exceeds maxw.
+// Returns a pointer to the start of the next line of caharcters.
+// Sets n to the number of characters put into the buffer.
+// Sets width to the width of the string in the current font.
+
+static const char*
+expand(const char* from, char* buf, double maxw, int& n, double &width, int wrap) {
+
+ char* o = buf;
+ char* e = buf+(MAXBUF-4);
+// underline_at = 0;
+ char* word_end = o;
+ const char* word_start = from;
+ double w = 0;
+
+ const char* p = from;
+ for (;; p++) {
+
+ int c = *p & 255;
+
+ if (!c || c == ' ' || c == '\n') {
+ // test for word-wrap:
+ if (word_start < p && wrap) {
+ double newwidth = w + fl_width(word_end, o-word_end);
+ if (word_end > buf && newwidth > maxw) { // break before this word
+ o = word_end;
+ p = word_start;
+ break;
+ }
+ word_end = o;
+ w = newwidth;
+ }
+ if (!c) break;
+ else if (c == '\n') {p++; break;}
+ word_start = p+1;
+ }
+
+ if (o > e) break; // don't overflow buffer
+
+ if (c == '\t') {
+ for (c = (o-buf)%8; c<8 && o<e; c++) *o++ = ' ';
+
+#if 0
+ } else if (c == '&' && fl_draw_shortcut && *(p+1)) {
+ if (*(p+1) == '&') {p++; *o++ = '&';}
+ else if (fl_draw_shortcut != 2) underline_at = o;
+#endif
+ } else if (c < ' ' || c == 127) { // ^X
+ *o++ = '^';
+ *o++ = c ^ 0x40;
+
+ /*
+ * mike@easysw.com - The following escaping code causes problems when
+ * using the PostScript ISOLatin1 and WinANSI encodings, because these
+ * map to I18N characters...
+ */
+#if 0
+ } else if (c >= 128 && c < 0xA0) { // \nnn
+ *o++ = '\\';
+ *o++ = (c>>6)+'0';
+ *o++ = ((c>>3)&7)+'0';
+ *o++ = (c&7)+'0';
+#endif /* 0 */
+
+ } else if (c == 0xA0) { // non-breaking space
+ *o++ = ' ';
+
+ } else {
+ *o++ = c;
+
+ }
+ }
+
+ width = w + fl_width(word_end, o-word_end);
+ *o = 0;
+ n = o-buf;
+ return p;
+}
+
+string PrvBreakLine (Fl_Input_* in, const char* str)
+{
+ string result;
+
+ // This function follows the outline of fl_measure.
+
+ // Set the font so that we can measure the text's width.
+
+ fl_font (in->textfont (), in->textsize ());
+
+ // Get the width of the box in which the text will be
+ // laid out. Fl_Output fudge by box_dw() + 6, so we
+ // must do that, too.
+
+ int max_width = in->w ();
+ Fl_Boxtype b = in->box () ? in->box () : FL_DOWN_BOX;
+
+ max_width -= Fl::box_dw (b) + 6;
+
+ // Break up the string, adding it back together in
+ // "result", with the lines seperated by CR's.
+
+ if (str)
+ {
+ const char* p;
+ const char* e;
+ char buf[MAXBUF];
+ int buflen;
+ double width;
+
+ for (p = str; *p; p = e)
+ {
+ e = expand (p, buf, max_width, buflen, width, true);
+ result += buf;
+ if (*e)
+ result += '\n';
+ }
+ }
+
+ return result;
+}
+
+void Fl_Push_Button::draw (void)
+{
+ if (fType == kDefault)
+ {
+ Fl_Return_Button::draw ();
+ }
+ else
+ {
+ Fl_Button::draw ();
+ }
+}
+
+
+int Fl_Push_Button::handle (int event)
+{
+ if (fType == kDefault)
+ {
+ return Fl_Return_Button::handle (event);
+ }
+
+ if (event == FL_SHORTCUT)
+ {
+ if (fType == kCancel && Fl::event_key () == FL_Escape)
+ {
+ do_callback ();
+ return 1;
+ }
+ }
+
+ return Fl_Button::handle (event);
+}