1 /**************************************************************************/
2 /*  Copyright 2012 Tim Day                                                */
3 /*                                                                        */
4 /*  This file is part of Evolvotron                                       */
5 /*                                                                        */
6 /*  Evolvotron is free software: you can redistribute it and/or modify    */
7 /*  it under the terms of the GNU General Public License as published by  */
8 /*  the Free Software Foundation, either version 3 of the License, or     */
9 /*  (at your option) any later version.                                   */
10 /*                                                                        */
11 /*  Evolvotron is distributed in the hope that it will be useful,         */
12 /*  but WITHOUT ANY WARRANTY; without even the implied warranty of        */
13 /*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
14 /*  GNU General Public License for more details.                          */
15 /*                                                                        */
16 /*  You should have received a copy of the GNU General Public License     */
17 /*  along with Evolvotron.  If not, see <http://www.gnu.org/licenses/>.   */
18 /**************************************************************************/
19 
20 /*! \file
21   \brief Interface for class EvolvotronMain.
22 */
23 
24 #ifndef _evolvotron_main_h_
25 #define _evolvotron_main_h_
26 
27 #include "common.h"
28 
29 #include "function_registry.h"
30 #include "transform_factory.h"
31 
32 #include "mutatable_image.h"
33 #include "mutatable_image_display.h"
34 #include "mutatable_image_computer_farm.h"
35 #include "mutation_parameters_qobject.h"
36 #include "render_parameters.h"
37 
38 class DialogAbout;
39 class DialogHelp;
40 class DialogMutationParameters;
41 class DialogRenderParameters;
42 class DialogFunctions;
43 class DialogFavourite;
44 
45 //! Utility class to expand "restart with" menu picks
46 /*! A boost::bind kind of thing
47  */
48 class SignalExpanderRestartWith : public QObject
49 {
50  private:
51   Q_OBJECT
52 
53   const FunctionRegistration*const _fn;
54  public:
SignalExpanderRestartWith(QObject * parent,const FunctionRegistration * fn)55   SignalExpanderRestartWith(QObject* parent,const FunctionRegistration* fn)
56     :QObject(parent)
57     ,_fn(fn)
58     {}
59   public slots:
restart_with()60     void restart_with()
61     {
62       emit restart_with(_fn);
63     }
64  signals:
65   void restart_with(const FunctionRegistration*);
66 };
67 
68 //! Top level GUI component for evolvotron application
69 class EvolvotronMain : public QMainWindow
70 {
71  private:
72   Q_OBJECT
73 
74  protected:
75 
76   //! Class encapsulating everything needed for undo functionality.
77   /*! \todo This is too big to be a nested class.
78    */
79   class History
80     {
81     protected:
82       //! Pointer to main app.
83       EvolvotronMain*const _main;
84 
85       typedef std::map<MutatableImageDisplay*,boost::shared_ptr<const MutatableImage> > ArchiveRecordEntries;
86       typedef std::pair<std::string,ArchiveRecordEntries> ArchiveRecord;
87       typedef std::deque<ArchiveRecord> Archive;
88 
89       //! Each deque slot contains the collection of display-image pairs replaced by an single action (and a string naming that action).
90       /*! We use a deque rather than a stack because we want to clean up the tail end (limited number of Undos).
91        */
92       Archive _archive;
93 
94       //! Number of slots retained for history.
95       const uint max_slots;
96 
97       //! Clean up the last slot in the queue.
98       void purge();
99 
100       //! Write some info to std::clog.
101       void log_status() const;
102 
103     public:
104 
105       //! Constructor.
106       History(EvolvotronMain*);
107 
108       //! Destructor.
109       ~History();
110 
111       //! Eliminate any references to the display (and clean up any undo actions which are empty as a result).
112       void goodbye(MutatableImageDisplay*);
113 
114       //! Record that we are overwriting the given display.
115       void replacing(MutatableImageDisplay* display);
116 
117       //! Starts a new action slot
118       void begin_action(const std::string& action_name);
119 
120       //! Ends an action slot and updates the undoable state.
121       void end_action();
122 
123       //! Returns true if there is stuff to undo
124       bool undoable();
125 
126       //! Implements an undo.
127       void undo();
128     };
129 
130  protected:
131   //! Convenience typedef for pointer to member function implementing a kind of spawn.
132   typedef void (EvolvotronMain::* SpawnMemberFn)(const boost::shared_ptr<const MutatableImage>& image,MutatableImageDisplay* display,bool one_of_many);
133 
134   //! Instance of History object to track activity.
135   std::unique_ptr<History> _history;
136 
137   //! Sweep z linearly through animations
138   /*! \todo Move to mutation or render paraemeters ?
139    */
140   const bool _linear_zsweep;
141 
142   //! Generate spheremaps
143   /*! \todo Move to mutation or render paraemeters ?
144    */
145   const bool _spheremap;
146 
147   //! Name of files to load on a reset.
148   std::vector<std::string> _startup_filenames;
149 
150   //! Whether to shuffle startup files (if any).
151   const bool _startup_shuffle;
152 
153   //! Instance of mutation parameters for the app
154   /*! This used to be held by DialogMutationParameters, but now we want to share it around a bit
155     (although modifications should always be via the dialog slots, to keep the dialogs up to date)
156    */
157   MutationParametersQObject _mutation_parameters;
158 
159   //! Instance of render parameters for the app
160   RenderParameters _render_parameters;
161 
162   //! Somewhere to report what's going on
163   QStatusBar* _statusbar;
164 
165   //! Label for displaying number of tasks running (more permanent than StatusBar's message method).
166   QLabel* _statusbar_tasks_label;
167 
168   //! Number of main tasks the statusbar is currently reporting as active
169   /*! Cached to avoid unnecessarily regenerating message
170    */
171   uint _statusbar_tasks_main;
172 
173   //! Number of enlargement tasks the statusbar is currently reporting as active
174   /*! Cached to avoid unnecessarily regenerating message
175    */
176   uint _statusbar_tasks_enlargement;
177 
178   //! The "About" dialog widget.
179   DialogAbout* _dialog_about;
180 
181   //! The "Help" dialog widget (quick reference text)
182   DialogHelp* _dialog_help_short;
183 
184   //! The "Help" dialog widget (full manual text)
185   DialogHelp* _dialog_help_long;
186 
187   //! The dialog for adjusting MutationParameters.
188   DialogMutationParameters* _dialog_mutation_parameters;
189 
190   //! The dialog for adjusting RenderParameters.
191   DialogRenderParameters* _dialog_render_parameters;
192 
193   //! Dialog for controlling which functions are in use.
194   DialogFunctions* _dialog_functions;
195 
196   //! Dialog for selecting a favourite function (also holds the state for favourite stuff)
197   DialogFavourite* _dialog_favourite;
198 
199   //! The file menu.
200   QMenu* _popupmenu_file;
201 
202   //! The edit menu.
203   QMenu* _popupmenu_edit;
204 
205   //! ID for the undo item (so we can disable it).
206   QAction* _popupmenu_edit_undo_action;
207 
208   //! The settings menu
209   QMenu* _popupmenu_settings;
210 
211   //! Action for setting fullscreen
212   QAction* _menu_action_fullscreen;
213 
214   //! Action for hiding menubar
215   QAction* _menu_action_hide_menu;
216 
217   //! The help menu.
218   QMenu* _popupmenu_help;
219 
220   //! Select autocooling (also serves to reset the generation count).
221   QCheckBox* _checkbox_autocool_enable;
222 
223   //! Report number of generations.
224   QLabel* _label_autocool_enable;
225 
226   //! Button to reheat
227   QPushButton* _button_autocool_reheat;
228 
229   //! Grid for image display areas
230   QWidget* _grid;
231 
232   //! Timer to drive tick() slot
233   QTimer* _timer;
234 
235   //! Two farms of compute threads.  One for the main display, one for enlargements.
236   std::unique_ptr<MutatableImageComputerFarm> _farm[2];
237 
238   //! All the displays in the grid.
239   std::vector<MutatableImageDisplay*> _displays;
240 
241   //! Keeps track of which displays are still available for display (they might have been destroyed while an image was computing).
242   /*! Non-const because we might need to notify them about various things
243    */
244   std::set<MutatableImageDisplay*> _known_displays;
245 
246   //! Keeps track of which displays are still resizing
247   std::set<const MutatableImageDisplay*> _resizing;
248 
249   //! The last image spawned (used to regenerate single displays).
250   boost::shared_ptr<const MutatableImage> _last_spawned_image;
251 
252   //! Pointer to member function used for last spawn.
253   SpawnMemberFn _last_spawn_method;
254 
255   //! An owned pointer to the current transform factory (needed for Respawn).
256   std::unique_ptr<TransformFactory> _transform_factory;
257 
258   //! Accessor.
last_spawned_image()259   const boost::shared_ptr<const MutatableImage> last_spawned_image() const
260     {
261       return _last_spawned_image;
262     }
263 
264   //! Accessor.
last_spawn_method()265   SpawnMemberFn last_spawn_method() const
266     {
267       return _last_spawn_method;
268     }
269 
270   //! Not just an accessor.  Takes ownership of a deepclone of the image
271   void last_spawned_image(const boost::shared_ptr<const MutatableImage>& image,SpawnMemberFn method);
272 
273   //! Accessor
transform_factory()274   const TransformFactory& transform_factory() const
275     {
276       // We shouldn't be here unless transform_factory has been set to something.
277       assert(_transform_factory.get()!=0);
278 
279       return *_transform_factory;
280     }
281 
282   //! Not just an accessor.  Takes ownership of a deepclone of the argument.
transform_factory(const TransformFactory & tfactory)283   void transform_factory(const TransformFactory& tfactory)
284     {
285       _transform_factory=tfactory.clone();
286     }
287 
288   //@{
289   //! Perform a particular type of spawn from an individiual image to an individual display.  (Locking not checked).
290   void spawn_normal(const boost::shared_ptr<const MutatableImage>& image,MutatableImageDisplay* display,bool one_of_many);
291   void spawn_recoloured(const boost::shared_ptr<const MutatableImage>& image,MutatableImageDisplay* display,bool one_of_many);
292   void spawn_warped(const boost::shared_ptr<const MutatableImage>& image,MutatableImageDisplay* display,bool one_of_many);
293   //@}
294 
295   //! Spawn the specified display using the specified method.
296   void spawn_all(MutatableImageDisplay* display,SpawnMemberFn method,const std::string& action_name);
297 
298  public:
299   //! Constructor.
300   EvolvotronMain
301     (
302      QWidget* parent,
303      const QSize& grid_size,
304      uint frames,
305      uint framerate,
306      uint n_threads,
307      bool separate_farm_for_enlargements,
308      int niceness_grid,
309      int niceness_enlargements,
310      bool start_fullscreen,
311      bool start_menuhidden,
312      bool autocool,
313      bool jitter,
314      uint multisample_level,
315      bool function_debug_mode,
316      bool linear_zsweep,
317      bool spheremap,
318      const std::vector<std::string>& startup_filenames,
319      bool startup_shuffle
320      );
321 
322   //! Destructor.
323   ~EvolvotronMain();
324 
325   //! Accessor. Returns true if function name recognised.  Forwards to DialogFavourite.
326   bool favourite_function(const std::string& f);
327 
328   //! Accessor.  Forwards to DialogFavourite.
329   void favourite_function_unwrapped(bool v);
330 
331   //! Accessor.
displays()332   std::vector<MutatableImageDisplay*>& displays()
333     {
334       return _displays;
335     }
336 
337   //! Accessor.
338   /*! NB Only const version made available publicly as modifications should be through an appropriate dialog slot.
339    */
mutation_parameters()340   const MutationParameters& mutation_parameters() const
341     {
342       return _mutation_parameters;
343     }
344 
345   //! Accessor.
346   /*! NB Only const version made available publicly as modifications should be through an appropriate dialog slot.
347    */
render_parameters()348   const RenderParameters& render_parameters() const
349     {
350       return _render_parameters;
351     }
352 
353   //! Returns which farm to use for purpose.
farm(bool enlargement)354   MutatableImageComputerFarm& farm(bool enlargement)
355     {
356       return *_farm[enlargement && _farm[1].get()];
357     }
358 
359   //! Accessor.
history()360   History& history()
361     {
362       return *_history;
363     }
364 
365   //! Called by History when performing undo.
366   void restore(MutatableImageDisplay* display,const boost::shared_ptr<const MutatableImage>&,bool one_of_many);
367 
368   //! Called by History to change undo menu status.
369   void set_undoable(bool v,const std::string& name);
370 
371   //! Regenerates a single display using last spawn method and source.
372   void respawn(MutatableImageDisplay* display);
373 
374   //! Mutates the image held by the given display to all the other displays owned.
375   void spawn_normal(MutatableImageDisplay* spawning_display);
376 
377   //! Similar to spawn except just changes the colouration of the image.
378   void spawn_recoloured(MutatableImageDisplay* spawning_display);
379 
380   //! Similar to spawn except just changes the input co-ordinates to the image.
381   void spawn_warped(MutatableImageDisplay* spawning_display,const TransformFactory& tfactory);
382 
383   //! Called from display constructor to indicate the display is available for the disposal of its completed tasks.
384   void hello(MutatableImageDisplay*);
385 
386   //! Called from display destructor to indicate the display is no longer available for the disposal of its completed tasks.
387   void goodbye(MutatableImageDisplay*);
388 
389   //! Returns true if the display is known.
390   bool is_known(MutatableImageDisplay* disp) const;
391 
392   //! Write a list of known displays (for debugging)
393   void list_known(std::ostream& out) const;
394 
395  protected:
396   //! Handle key-presses
397   void keyPressEvent(QKeyEvent* e);
398 
399   //! Reset the specified display.
400   void reset(MutatableImageDisplay* display);
401 
402  protected slots:
403   //! Signalled by timer.
404   void tick();
405 
406   //! Signalled by menu item.  Forwards to History object.
407   void undo();
408 
409   //! Signalled by menu item.  Simplifies all functions.
410   void simplify_constants();
411  public slots:
412 
413   //! Signalled by menu item.
414   void toggle_hide_menu();
415 
416   //! Signalled by menu item
417   void toggle_fullscreen();
418 
419   //! Signalled by menu item.  Public because called from evolvotron app wrapper.
420   void reset(bool reset_mutation_parameters,bool reset_locks);
421 
422   //! Forwards to reset(false)
423   void reset_warm();
424 
425   //! Forwards to reset(true)
426   void reset_cold();
427 
428   //! Resets and randomizes function weightings
429   void reset_randomized();
430 
431   //! So we can update any exposed mutation parameters (e.g autocool enable, generation count)
432   void mutation_parameters_changed();
433 
434   //! So we can re-render when render parameters change
435   void render_parameters_changed();
436 };
437 
438 #endif
439 
440