1 /**
2  * ae.ui.app.application
3  *
4  * License:
5  *   This Source Code Form is subject to the terms of
6  *   the Mozilla Public License, v. 2.0. If a copy of
7  *   the MPL was not distributed with this file, You
8  *   can obtain one at http://mozilla.org/MPL/2.0/.
9  *
10  * Authors:
11  *   Vladimir Panteleev <ae@cy.md>
12  */
13 
14 module ae.ui.app.application;
15 
16 import ae.sys.desktop;
17 import ae.sys.config;
18 import ae.ui.shell.shell;
19 import ae.ui.shell.events;
20 import ae.ui.video.renderer;
21 
22 /// The purpose of this class is to allow the application to provide app-specific information to the framework.
23 // This class could theoretically be split up into more layers (ShellApplication, etc.)
24 class Application
25 {
26 	Config config; ///
27 
28 	this()
29 	{
30 		config = new Config(getName(), getCompanyName());
31 	} ///
32 
33 	// ************************** Application information **************************
34 
35 	/// Returns a string containing the application name, as visible in the window caption and taskbar, and used in filesystem/registry paths.
36 	abstract string getName();
37 
38 	/// Returns the company name (used for Windows registry paths).
39 	abstract string getCompanyName();
40 
41 	// TODO: getIcon
42 
43 	// ******************************** Entry point ********************************
44 
45 	/// The application "main" function. The application can create a shell here.
46 	abstract int run(string[] args);
47 
48 	// ************************** Default screen settings **************************
49 
50 	ShellSettings getDefaultShellSettings()
51 	{
52 		ShellSettings settings;
53 		static if (is(typeof(getDesktopResolution)))
54 			getDesktopResolution(settings.fullScreenX, settings.fullScreenY);
55 		return settings;
56 	} ///
57 
58 	/// Override these to customize application properties and requirements.
59 	ShellSettings getShellSettings() { return config.read("ShellSettings", getDefaultShellSettings()); }
60 	void setShellSettings(ShellSettings settings) { config.write("ShellSettings", settings); } /// ditto
61 
62 	bool isResizable() { return true; } /// ditto
63 	bool needSound() { return false; } /// ditto
64 	bool needJoystick() { return false; } /// ditto
65 
66 	// ****************************** Event handlers *******************************
67 
68 	//void handleMouseEnter() {}
69 	//void handleMouseLeave() {}
70 	//void handleKeyboardFocus() {}
71 	//void handleKeyboardBlur() {}
72 	//void handleMinimize() {}
73 	//void handleRestore() {}
74 
75 	/// Called after video initialization.
76 	/// Video initialization currently also happens when the window is resized.
77 	/// The window size can be accessed via shell.video.getScreenSize.
78 	void handleInit() {}
79 
80 	/// Override these to handle input.
81 	void handleKeyDown(Key key/*, modifiers? */, dchar character) {} /// ditto
82 	void handleKeyUp(Key key/*, modifiers? */) {} /// ditto
83 
84 	void handleMouseDown(uint x, uint y, MouseButton button) {} /// ditto
85 	void handleMouseUp(uint x, uint y, MouseButton button) {} /// ditto
86 	void handleMouseMove(uint x, uint y, MouseButtons buttons) {} /// ditto
87 	//void handleMouseRelMove(int dx, int dy) {} /// when cursor is clipped
88 
89 	void handleJoyAxisMotion(int axis, short value) {} /// ditto
90 	void handleJoyHatMotion (int hat, JoystickHatState state) {} /// ditto
91 	void handleJoyButtonDown(int button) {} /// ditto
92 	void handleJoyButtonUp  (int button) {} /// ditto
93 
94 	//void handleResize(uint w, uint h) {}
95 	void handleQuit() {} /// ditto
96 
97 	// ********************************* Rendering *********************************
98 
99 	void render(Renderer r) {} /// Override to implement rendering.
100 }
101 
102 private __gshared Application application;
103 
104 /// The application must call this function with its own Application implementation in a static constructor.
105 void createApplication(A : Application)()
106 {
107 	assert(application is null, "Application already set");
108 	application = new A;
109 }
110 
111 // for use in ae.ui.app.*
112 int runApplication(string[] args)
113 {
114 	assert(application !is null, "Application object not set");
115 	return application.run(args);
116 } ///
117 
118 /// Wraps a delegate that is to be called only from the application thread context.
119 struct AppCallbackEx(A...)
120 {
121 	private void delegate(A) f;
122 
123 	void bind(void delegate(A) f)
124 	{
125 		this.f = f;
126 	} ///
127 
128 	/// Blocks.
129 	void call(A args)
130 	{
131 		assert(f, "Attempting to call unbound AppCallback");
132 		synchronized(application)
133 		{
134 			f(args);
135 		}
136 	}
137 
138 	bool opCast(T)()
139 		if (is(T == bool))
140 	{
141 		return f !is null;
142 	} ///
143 }
144 
145 alias AppCallbackEx!() AppCallback; ///