1 /**
2 * Module for core application handling.
3 *
4 * Authors:
5 *   Jacob Jensen
6 * License:
7 *   https://github.com/PoisonEngine/poison-ui/blob/master/LICENSE
8 */
9 module poison.core.application;
10 
11 import std.concurrency : thisTid;
12 import core.thread : Thread, dur;
13 
14 import poison.ui : Window;
15 import poison.core.threading : _uiTid, receiveMessages;
16 
17 /// A wrapper around the core application.
18 class Application {
19   private:
20   /// The running application.
21   static Application _app;
22 
23   /// The name of the application.
24   string _name;
25 
26   /// Collection of windows.
27   Window[string] _windows;
28 
29   /// Windows that can be removed.
30   string[] _removableWindows;
31 
32   /// Boolean determining whether the application is cycling or not.
33   bool _cycling;
34 
35   /// Boolean determining whether the application is open or not.
36   bool _open;
37 
38   public:
39   /**
40   * Creates a new application.
41   * Params:
42   *   name =  The name of the application.
43   */
44   this(string name) {
45     _name = name;
46     _uiTid = thisTid;
47   }
48 
49   @property {
50     /// Gets the name of the application.
51     string name() { return _name; }
52   }
53 
54   /// Updates all styles for each window.
55   void updateStyles() {
56     if (_windows) {
57       foreach (window; _windows) {
58         foreach (component; window._windowComponents) {
59           component.updateStyles();
60         }
61       }
62     }
63   }
64 
65   /**
66   * Adds a window to the application.
67   * Params:
68   *   window =  The window to add.
69   */
70   void add(Window window) {
71     assert(window !is null);
72     assert(_windows.get(window.name, null) is null);
73 
74     _windows[window.name] = window;
75 
76     foreach (component; window._windowComponents) {
77       component.updateStyles();
78     }
79   }
80 
81   /**
82   * Removes a window from the application.
83   * Params:
84   *   window =  The window to remove.
85   */
86   void remove(Window window) {
87     assert(window !is null);
88 
89     remove(window.name);
90   }
91 
92   /**
93   * Removes a window from the application.
94   * Params:
95   *   name =  The name of the window to remove.
96   */
97   void remove(string name) {
98     assert(_windows.get(name, null) !is null);
99 
100     if (_cycling) {
101       _removableWindows ~= name;
102     }
103     else {
104       auto windowToRemove = _windows.get(name, null);
105 
106       if (!windowToRemove) {
107         return;
108       }
109 
110       if (windowToRemove.isOpen) {
111         windowToRemove.close();
112       }
113 
114       _windows.remove(name);
115     }
116   }
117 
118   private:
119   /// Processes the application.
120   void process() {
121     assert(_app !is null);
122 
123     _open = true;
124 
125     while (_open) {
126       _removableWindows = [];
127       _cycling = true;
128 
129       receiveMessages();
130 
131       processWindows();
132 
133       _cycling = false;
134 
135       foreach (removableWindow; _removableWindows) {
136         remove(removableWindow);
137       }
138     }
139   }
140 
141   /// Processes all windows.
142   void processWindows() {
143     _open = false;
144 
145     foreach (window; _windows) {
146       if (window.isOpen) {
147         _open = true;
148 
149         window.process();
150       }
151     }
152   }
153 
154   public:
155   static:
156   /**
157   * Initializes a application and then processes it.
158   * Params:
159   *   application = The application to initialize and process.
160   */
161   void initialize(Application application) {
162     assert(_app is null);
163 
164     _app = application;
165 
166     _app.updateStyles();
167     _app.process();
168   }
169 
170   @property {
171     /// Gets the app.
172     Application app() { return _app; }
173   }
174 }