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 <vladimir@thecybershadow.net>
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 	ShellSettings getShellSettings() { return config.read("ShellSettings", getDefaultShellSettings()); }
59 	void setShellSettings(ShellSettings settings) { config.write("ShellSettings", settings); }
60 
61 	bool isResizable() { return true; }
62 	bool needSound() { return false; }
63 	bool needJoystick() { return false; }
64 
65 	// ****************************** Event handlers *******************************
66 
67 	//void handleMouseEnter() {}
68 	//void handleMouseLeave() {}
69 	//void handleKeyboardFocus() {}
70 	//void handleKeyboardBlur() {}
71 	//void handleMinimize() {}
72 	//void handleRestore() {}
73 
74 	/// Called after video initialization.
75 	/// Video initialization currently also happens when the window is resized.
76 	/// The window size can be accessed via shell.video.getScreenSize.
77 	void handleInit() {}
78 
79 	void handleKeyDown(Key key/*, modifiers? */, dchar character) {}
80 	void handleKeyUp(Key key/*, modifiers? */) {}
81 
82 	void handleMouseDown(uint x, uint y, MouseButton button) {}
83 	void handleMouseUp(uint x, uint y, MouseButton button) {}
84 	void handleMouseMove(uint x, uint y, MouseButtons buttons) {}
85 	//void handleMouseRelMove(int dx, int dy) {} /// when cursor is clipped
86 
87 	void handleJoyAxisMotion(int axis, short value) {}
88 	void handleJoyHatMotion (int hat, JoystickHatState state) {}
89 	void handleJoyButtonDown(int button) {}
90 	void handleJoyButtonUp  (int button) {}
91 
92 	//void handleResize(uint w, uint h) {}
93 	void handleQuit() {}
94 
95 	// ********************************* Rendering *********************************
96 
97 	void render(Renderer r) {}
98 }
99 
100 private __gshared Application application;
101 
102 /// The application must call this function with its own Application implementation in a static constructor.
103 void createApplication(A : Application)()
104 {
105 	assert(application is null, "Application already set");
106 	application = new A;
107 }
108 
109 // for use in ae.ui.app.*
110 int runApplication(string[] args)
111 {
112 	assert(application !is null, "Application object not set");
113 	return application.run(args);
114 }
115 
116 /// Wraps a delegate that is to be called only from the application thread context.
117 struct AppCallbackEx(A...)
118 {
119 	private void delegate(A) f;
120 
121 	void bind(void delegate(A) f)
122 	{
123 		this.f = f;
124 	}
125 
126 	/// Blocks.
127 	void call(A args)
128 	{
129 		assert(f, "Attempting to call unbound AppCallback");
130 		synchronized(application)
131 		{
132 			f(args);
133 		}
134 	}
135 
136 	bool opCast(T)()
137 		if (is(T == bool))
138 	{
139 		return f !is null;
140 	}
141 }
142 
143 alias AppCallbackEx!() AppCallback;