Added File and Help menus.
authorspixx <spixx>
Sun, 26 Nov 2006 14:02:15 +0000 (14:02 +0000)
committerspixx <spixx>
Sun, 26 Nov 2006 14:02:15 +0000 (14:02 +0000)
Added Usage help dialog.
Removed Help button.
Minor clean up.

src/gui.cpp

index 1a8ca9e6af2ed058ea11bdf9f3c4204e2fb0b7c2..0b5d0276c6369e426341ff47f670a545599f48d6 100644 (file)
@@ -38,8 +38,13 @@ using namespace std;
 // message map
 FXDEFMAP(GUI) GUIMap[] =
 {
-    FXMAPFUNC(SEL_COMMAND, GUI::ID_GENERATE, GUI::onGenerateButtonPressed),
-    FXMAPFUNC(SEL_COMMAND, GUI::ID_HELP,     GUI::onHelpButtonPressed)
+    FXMAPFUNC(SEL_COMMAND, GUI::ID_GENERATE,   GUI::onGenerate),
+    FXMAPFUNC(SEL_COMMAND, GUI::ID_LOAD,       GUI::onLoad),
+    FXMAPFUNC(SEL_COMMAND, GUI::ID_SAVE,       GUI::onSave),
+    FXMAPFUNC(SEL_COMMAND, GUI::ID_QUIT,       GUI::onQuit),
+    FXMAPFUNC(SEL_COMMAND, GUI::ID_HELP_USAGE, GUI::onHelpUsage),
+    FXMAPFUNC(SEL_COMMAND, GUI::ID_HELP_RULES, GUI::onHelpRules),
+    FXMAPFUNC(SEL_CLOSE,   0,                  GUI::onQuit)
 };
 
 // macro to set up class implementation
@@ -49,22 +54,40 @@ FXIMPLEMENT(GUI, FXMainWindow, GUIMap, ARRAYNUMBER(GUIMap))
 
 /**
  * Constructor
- * @param application the FOX application object
+ * @param application the application object
  * @param renderingSurface the rendering surface
- * @param lsystem the Lindenmayer-system
+ * @param lsystem the Lindenmayer system generator
  */
 GUI::GUI(FXApp *application, RenderingSurface *renderingSurface, LindenmayerSystem *lsystem) : FXMainWindow(application, "LSystem3D" , NULL, NULL, DECOR_ALL, 920, 100, 0, 0)
 {
-    _lsystem = lsystem;
     _renderingSurface = renderingSurface;
+    _lsystem = lsystem;
     
-    
+        
     
     // create the widgets
     
+    // menu bar
+    FXMenuBar *menubar = new FXMenuBar(this, LAYOUT_FILL_X);
+    
+    // file menu
+    _fileMenuPane = new FXMenuPane(this);
+    new FXMenuTitle(menubar, "&File", NULL, _fileMenuPane);
+    new FXMenuCommand(_fileMenuPane, "&Load...", NULL, this, GUI::ID_LOAD);
+    new FXMenuCommand(_fileMenuPane, "&Save...", NULL, this, GUI::ID_SAVE);
+    new FXMenuCommand(_fileMenuPane, "&Quit",    NULL, this, GUI::ID_QUIT);
+    
+    // help menu
+    _helpMenuPane = new FXMenuPane(this);
+    new FXMenuTitle(menubar, "&Help", NULL, _helpMenuPane);
+    new FXMenuCommand(_helpMenuPane, "&Usage", NULL, this, GUI::ID_HELP_USAGE);
+    new FXMenuCommand(_helpMenuPane, "&Rules", NULL, this, GUI::ID_HELP_RULES);
+    
+    
     // the main frame
     FXVerticalFrame *mainFrame = new FXVerticalFrame(this, LAYOUT_FILL_X);
     
+    
     // axiom text field
     FXHorizontalFrame *axiomFrame = new FXHorizontalFrame(mainFrame, LAYOUT_FILL_X);
     new FXLabel(axiomFrame, "Axiom:");
@@ -91,84 +114,87 @@ GUI::GUI(FXApp *application, RenderingSurface *renderingSurface, LindenmayerSyst
     FXHorizontalFrame *diameterFrame = new FXHorizontalFrame(mainFrame);
     new FXLabel(diameterFrame, "Diameter:");
     _diameterRealSpinner = new FXRealSpinner(diameterFrame, 5);
-    _diameterRealSpinner->setValue(0.2);
-    _diameterRealSpinner->setIncrement(0.1);
+    _diameterRealSpinner->setValue(0.1);
+    _diameterRealSpinner->setIncrement(0.01);
     
     // diameter factor spinner
     new FXLabel(diameterFrame, "Factor:");
     _diameterFactorRealSpinner = new FXRealSpinner(diameterFrame, 5);
-    _diameterFactorRealSpinner->setValue(0.9);
+    _diameterFactorRealSpinner->setValue(1.0);
     _diameterFactorRealSpinner->setIncrement(0.01);
     
+    
     // separator
     new FXHorizontalSeparator(mainFrame, SEPARATOR_RIDGE | LAYOUT_FILL_X);
 
+    
     // generate button
     new FXButton(mainFrame, "&Generate", NULL, this, GUI::ID_GENERATE);
     
-    // help button
-    new FXButton(mainFrame, "&Help", NULL, this, GUI::ID_HELP);
-    
-    // help dialog
-    stringstream helpText;
-    helpText << "Mouse:" << endl
-             << "Left button: Move model in z-plane" << endl
-             << "Middle button: Zoom in/out" << endl
-             << "Right button: Rotate around y-axis" << endl
-             << endl
-             << "Rules:" << endl
-             << "F : Walk forward, leaving a trace" << endl
-             << "A-Z : Replacement rule" << endl
-             << "A(0.33) : Probability factor 0.33 for rule \"A\"" << endl
-             << "= : Rule assignment" << endl
-             << "+ : Turn left" << endl
-             << "- : Turn right" << endl
-             << "&& : Pitch down" << endl
-             << "^ : Pitch up" << endl
-             << "\\ : Roll left" << endl
-             << "/ : Roll right" << endl
-             << "| : Turn around 180 degrees" << endl
-             << "[ : Save state to stack" << endl
-             << "] : Load state from stack" << endl
-             << "{ : Create a planar surface" << endl
-             << "} : Close a planar surface" << endl
-             << "f : One vertex in a planar surface, specified CCW" << endl
-             << "! : Decrement diameter of segment" << endl
-             << "\' : Increment current index to color table" << endl
-             << ", : Decrement current index to color table" << endl
-             << endl
-             << "Example:" << endl
-             << "F(0.33)=[+F/L]/F[-F&&L]F!" << endl
-             << "F(0.33)=F[+F+L]&&F!" << endl
-             << "F(0.34)=F[-F-L]/F!" << endl
-             << "L=,{-f++f-|-f++f-}'";
-    
-    _helpMessageBox = new FXMessageBox(getApp(), "Help", helpText.str().c_str(), NULL, MBOX_OK);
-    
-    
-    
-    // load L-system parameters from file and sync with GUI
-    
-    _lsystemParameters.load(_lsystem, "lsystem.xml");
     
-    // axiom
-    _axiomTextField->setText(_lsystem->getAxiom().getContent().c_str());
+    // usage help dialog
+    stringstream usageHelpText;
+    usageHelpText << "Rendering window:" << endl
+                  << "Left mouse button: Move model in z-plane" << endl
+                  << "Middle mouse button: Zoom in/out" << endl
+                  << "Right mouse button: Rotate around y-axis" << endl
+                  << endl
+                  << "Controller window:" << endl
+                  << "Axiom: Initial rule" << endl
+                  << "Rules: The L-system rules" << endl
+                  << "Angle: Turn/pitch/roll angle" << endl
+                  << "Depth: Depth of recursion" << endl
+                  << "Diameter: Initial diameter of segment" << endl
+                  << "Factor: For each recursion level, multiply segment diameter with this value" << endl
+                  << "Generate: Generate the L-system";
     
-    // rules
-    rulemap rules = _lsystem->getRules().getRules();
-    string rulesString;    
-    for (rulemap::iterator it = rules.begin(); it != rules.end(); ++it)
-    {
-        rulesString += it->second.toString();
-        rulesString += '\n';
-    }
-    _rulesText->setText(rulesString.c_str(), rulesString.size());
+    _helpUsageMessageBox = new FXMessageBox(getApp(), "Usage", usageHelpText.str().c_str(), NULL, MBOX_OK);
     
-    // angle
-    _angleRealSpinner->setValue(_lsystem->getAngle());
     
-    // depth
-    _depthSpinner->setValue(_lsystem->getDepth());
+    // rules help dialog
+    stringstream rulesHelpText;
+    rulesHelpText << "Rules:" << endl
+                  << "F : Walk forward, creating a segment" << endl
+                  << "A-Z : Replacement rule" << endl
+                  << "A(0.33) : Probability factor 0.33 for rule \"A\"" << endl
+                  << "= : Rule assignment" << endl
+                  << "+ : Turn left" << endl
+                  << "- : Turn right" << endl
+                  << "&& : Pitch down" << endl
+                  << "^ : Pitch up" << endl
+                  << "\\ : Roll left" << endl
+                  << "/ : Roll right" << endl
+                  << "| : Turn around 180 degrees" << endl
+                  << "[ : Save state to stack" << endl
+                  << "] : Load state from stack" << endl
+                  << "{ : Create a planar surface" << endl
+                  << "} : Close a planar surface" << endl
+                  << "f : One vertex in a planar surface, specified CCW" << endl
+                  << "! : Decrement segment diameter" << endl
+                  << "\' : Increment current index to color table" << endl
+                  << ", : Decrement current index to color table" << endl
+                  << endl
+                  << "Example:" << endl
+                  << "F(0.33)=[+FL]F/[-FL]F!" << endl
+                  << "F(0.33)=F[&&FL]F!" << endl
+                  << "F(0.34)=F/[-FL]&&F!" << endl
+                  << "L={,-f++f-|-f++f-'}";
+    
+    _helpRulesMessageBox = new FXMessageBox(getApp(), "Rules", rulesHelpText.str().c_str(), NULL, MBOX_OK);
+    
+    
+    loadLSystem("lsystem.xml");
+}
+
+
+
+/**
+ * Destructor
+ */
+GUI::~GUI()
+{
+    delete _fileMenuPane;
+    delete _helpMenuPane;
 }
 
 
@@ -192,7 +218,7 @@ void GUI::create()
  * @param data event related data
  * @return 
  */
-long GUI::onGenerateButtonPressed(FXObject *sender, FXSelector selector, void *data)
+long GUI::onGenerate(FXObject *sender, FXSelector selector, void *data)
 {
     // clear L-system
     _lsystem->clear();
@@ -250,13 +276,133 @@ long GUI::onGenerateButtonPressed(FXObject *sender, FXSelector selector, void *d
 
 
 /**
- * Called by the system when the "Help" button is pressed
+ * Called by the system when the File->Load menu command is selected
+ * @param sender the sender object
+ * @param selector message type and id
+ * @param data event related data
+ * @return 
+ */
+long GUI::onLoad(FXObject *sender, FXSelector selector, void *data)
+{
+    FXString loadFilename = FXFileDialog::getOpenFilename(this, "Load file...", ".");
+    
+    if (!loadFilename.empty())
+    {
+        // load from disk
+        loadLSystem(loadFilename.text());
+    }
+}
+
+
+
+/**
+ * Called by the system when the File->Save menu command is selected
+ * @param sender the sender object
+ * @param selector message type and id
+ * @param data event related data
+ * @return 
+ */
+long GUI::onSave(FXObject *sender, FXSelector selector, void *data)
+{
+    FXString saveFilename = FXFileDialog::getSaveFilename(this, "Save file...", ".");
+    
+    if (FXStat::exists(saveFilename))
+    {
+        // the file already exists
+        
+        if (MBOX_CLICKED_YES == FXMessageBox::question(this, MBOX_YES_NO, "Overwrite file", "Overwrite existing file?"))
+        {
+            // overwrite file
+            _lsystemParameters.save(_lsystem, saveFilename.text());
+        }
+    }
+    else
+    {
+        // save to file
+        _lsystemParameters.save(_lsystem, saveFilename.text());
+    }
+}
+
+
+
+/**
+ * Called by the system when the close button or the File->Quit command item is selected
+ * @param sender the sender object
+ * @param selector message type and id
+ * @param data event related data
+ * @return 
+ */
+long GUI::onQuit(FXObject *sender, FXSelector selector, void *data)
+{
+    getApp()->exit(0);
+    
+    return 1;
+}
+
+
+
+/**
+ * Called by the system when the Help->Usage menu command is selected
+ * @param sender the sender object
+ * @param selector message type and id
+ * @param data event related data
+ * @return 
+ */
+long GUI::onHelpUsage(FXObject *sender, FXSelector selector, void *data)
+{
+    _helpUsageMessageBox->show(PLACEMENT_OWNER);
+}
+
+
+
+/**
+ * Called by the system when the Help->Rules menu command is selected
  * @param sender the sender object
  * @param selector message type and id
  * @param data event related data
  * @return 
  */
-long GUI::onHelpButtonPressed(FXObject *sender, FXSelector selector, void *data)
+long GUI::onHelpRules(FXObject *sender, FXSelector selector, void *data)
 {
-    _helpMessageBox->show(PLACEMENT_OWNER);
+    _helpRulesMessageBox->show(PLACEMENT_OWNER);
+}
+
+
+
+/**
+ * Load L-system from file and sync with GUI
+ * @param filename path of the L-system file
+ */
+void GUI::loadLSystem(string filename)
+{
+    // load from file
+    _lsystemParameters.load(_lsystem, filename);
+    
+    
+    // sync with GUI
+    
+    // axiom
+    _axiomTextField->setText(_lsystem->getAxiom().getContent().c_str());
+    
+    // rules
+    rulemap rules = _lsystem->getRules().getRules();
+    string rulesString;    
+    for (rulemap::iterator it = rules.begin(); it != rules.end(); ++it)
+    {
+        rulesString += it->second.toString();
+        rulesString += '\n';
+    }
+    _rulesText->setText(rulesString.c_str(), rulesString.size());
+    
+    // angle
+    _angleRealSpinner->setValue(_lsystem->getAngle());
+    
+    // depth
+    _depthSpinner->setValue(_lsystem->getDepth());
+    
+    // segment diameter
+    _diameterRealSpinner->setValue(_lsystem->getDiameter());
+    
+    // segment diameter factor
+    _diameterFactorRealSpinner->setValue(_lsystem->getDiameterFactor());
 }