1 // Copyright (C) 2006 Erik Dahlberg
3 // This file is part of LSystem3D.
5 // LSystem3D is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // LSystem3D is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with LSystem3D; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 #include "lindenmayersystem.h"
29 #include "lsystemparameters.h"
30 #include "renderingsurface.h"
39 FXDEFMAP(GUI
) GUIMap
[] =
41 FXMAPFUNC(SEL_COMMAND
, GUI::ID_GENERATE
, GUI::onGenerateButtonPressed
),
42 FXMAPFUNC(SEL_COMMAND
, GUI::ID_HELP
, GUI::onHelpButtonPressed
)
45 // macro to set up class implementation
46 FXIMPLEMENT(GUI
, FXMainWindow
, GUIMap
, ARRAYNUMBER(GUIMap
))
52 * @param application the FOX application object
53 * @param renderingSurface the rendering surface
54 * @param lsystem the Lindenmayer-system
56 GUI::GUI(FXApp
*application
, RenderingSurface
*renderingSurface
, LindenmayerSystem
*lsystem
) : FXMainWindow(application
, "LSystem3D" , NULL
, NULL
, DECOR_ALL
, 920, 100, 0, 0)
59 _renderingSurface
= renderingSurface
;
66 FXVerticalFrame
*mainFrame
= new FXVerticalFrame(this, LAYOUT_FILL_X
);
69 FXHorizontalFrame
*axiomFrame
= new FXHorizontalFrame(mainFrame
, LAYOUT_FILL_X
);
70 new FXLabel(axiomFrame
, "Axiom:");
71 _axiomTextField
= new FXTextField(axiomFrame
, 10, NULL
, 0, LAYOUT_FILL_X
);
73 // rules multiline text field
74 FXHorizontalFrame
*rulesFrame
= new FXHorizontalFrame(mainFrame
, LAYOUT_FILL_X
);
75 new FXLabel(rulesFrame
, "Rules:");
76 _rulesText
= new FXText(rulesFrame
, NULL
, 0, LAYOUT_FILL_X
);
77 _rulesText
->setVisibleColumns(30);
78 _rulesText
->setVisibleRows(10);
81 FXHorizontalFrame
*angleFrame
= new FXHorizontalFrame(mainFrame
);
82 new FXLabel(angleFrame
, "Angle:");
83 _angleRealSpinner
= new FXRealSpinner(angleFrame
, 5);
86 FXHorizontalFrame
*depthFrame
= new FXHorizontalFrame(mainFrame
);
87 new FXLabel(depthFrame
, "Depth:");
88 _depthSpinner
= new FXSpinner(depthFrame
, 5);
91 FXHorizontalFrame
*diameterFrame
= new FXHorizontalFrame(mainFrame
);
92 new FXLabel(diameterFrame
, "Diameter:");
93 _diameterRealSpinner
= new FXRealSpinner(diameterFrame
, 5);
94 _diameterRealSpinner
->setValue(0.2);
95 _diameterRealSpinner
->setIncrement(0.1);
97 // diameter factor spinner
98 new FXLabel(diameterFrame
, "Factor:");
99 _diameterFactorRealSpinner
= new FXRealSpinner(diameterFrame
, 5);
100 _diameterFactorRealSpinner
->setValue(0.9);
101 _diameterFactorRealSpinner
->setIncrement(0.01);
104 new FXHorizontalSeparator(mainFrame
, SEPARATOR_RIDGE
| LAYOUT_FILL_X
);
107 new FXButton(mainFrame
, "&Generate", NULL
, this, GUI::ID_GENERATE
);
110 new FXButton(mainFrame
, "&Help", NULL
, this, GUI::ID_HELP
);
113 stringstream helpText
;
114 helpText
<< "Mouse:" << endl
115 << "Left button: Move model in z-plane" << endl
116 << "Middle button: Zoom in/out" << endl
117 << "Right button: Rotate around y-axis" << endl
120 << "F : Walk forward, leaving a trace" << endl
121 << "A-Z : Replacement rule" << endl
122 << "A(0.33) : Probability factor 0.33 for rule \"A\"" << endl
123 << "= : Rule assignment" << endl
124 << "+ : Turn left" << endl
125 << "- : Turn right" << endl
126 << "&& : Pitch down" << endl
127 << "^ : Pitch up" << endl
128 << "\\ : Roll left" << endl
129 << "/ : Roll right" << endl
130 << "| : Turn around 180 degrees" << endl
131 << "[ : Save state to stack" << endl
132 << "] : Load state from stack" << endl
133 << "{ : Create a planar surface" << endl
134 << "} : Close a planar surface" << endl
135 << "f : One vertex in a planar surface, specified CCW" << endl
136 << "! : Decrement diameter of segment" << endl
137 << "\' : Increment current index to color table" << endl
138 << ", : Decrement current index to color table" << endl
140 << "Example:" << endl
141 << "F(0.33)=[+F/L]/F[-F&&L]F!" << endl
142 << "F(0.33)=F[+F+L]&&F!" << endl
143 << "F(0.34)=F[-F-L]/F!" << endl
144 << "L=,{-f++f-|-f++f-}'";
146 _helpMessageBox
= new FXMessageBox(getApp(), "Help", helpText
.str().c_str(), NULL
, MBOX_OK
);
150 // load L-system parameters from file and sync with GUI
152 _lsystemParameters
.load(_lsystem
, "lsystem.xml");
155 _axiomTextField
->setText(_lsystem
->getAxiom().getContent().c_str());
158 rulemap rules
= _lsystem
->getRules().getRules();
160 for (rulemap::iterator it
= rules
.begin(); it
!= rules
.end(); ++it
)
162 rulesString
+= it
->second
.toString();
165 _rulesText
->setText(rulesString
.c_str(), rulesString
.size());
168 _angleRealSpinner
->setValue(_lsystem
->getAngle());
171 _depthSpinner
->setValue(_lsystem
->getDepth());
177 * Create and initialize the window
181 // create the window and make it appear
182 FXMainWindow::create();
189 * Called by the system when the "Generate" button is pressed
190 * @param sender the sender object
191 * @param selector message type and id
192 * @param data event related data
195 long GUI::onGenerateButtonPressed(FXObject
*sender
, FXSelector selector
, void *data
)
201 // get user input form widgets
204 Rule
axiom("axiom", _axiomTextField
->getText().text(), 1.0);
205 _lsystem
->setAxiom(axiom
);
208 string ruleSet
= _rulesText
->getText().text();
210 for (int i
= 0; i
< ruleSet
.size(); i
++)
212 if (ruleSet
[i
] != '\n')
215 currentRule
+= ruleSet
[i
];
217 if (i
== ruleSet
.size() - 1)
219 // last char in whole rule string
220 _lsystem
->setRule(Rule(currentRule
));
226 // last char in current rule
227 _lsystem
->setRule(Rule(currentRule
));
233 _lsystem
->setAngle(_angleRealSpinner
->getValue());
236 _lsystem
->setDepth(_depthSpinner
->getValue());
239 _lsystem
->setDiameter(_diameterRealSpinner
->getValue());
242 _lsystem
->setDiameterFactor(_diameterFactorRealSpinner
->getValue());
245 // generate and render L-system to screen
246 _lsystem
->generate();
247 _renderingSurface
->draw();
253 * Called by the system when the "Help" button is pressed
254 * @param sender the sender object
255 * @param selector message type and id
256 * @param data event related data
259 long GUI::onHelpButtonPressed(FXObject
*sender
, FXSelector selector
, void *data
)
261 _helpMessageBox
->show(PLACEMENT_OWNER
);