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