1 /**
2  * Handles the creation and life cycle of UI objects and webview textures
3  */
4 module dash.components.userinterface;
5 import dash, dash.utility.bindings.awesomium;
6 
7 import std..string;
8 
9 /**
10  * User interface objects handle drawing/updating an AwesomiumView over the screen
11  */
12 class UserInterface
13 {
14 private:
15     uint _height;
16     uint _width;
17     mat4f _scaleMat;
18     AwesomiumView _view;
19     // TODO: Handle JS
20 
21 public:
22     /// WebView to be drawn
23     mixin( Property!(_view, AccessModifier.Public) );
24     /// Scale of the UI
25     mixin( Property!(_scaleMat, AccessModifier.Public) );
26 
27     /**
28      * Create UI object
29      *
30      * Params:
31      *  w =         Width (in pixels) of UI
32      *  h =         Height (in pixels) of UI
33      *  filePath =  Absolute file path to UI file
34      */
35     this( uint w, uint h, string filePath )
36     {
37         _scaleMat = mat4f.identity;
38         _scaleMat[0][0] = cast(float)w/2.0f;
39         _scaleMat[1][1] = cast(float)h/2.0f;
40         _height = h;
41         _width = w;
42         version(Windows)
43         {
44             _view = new AwesomiumView( w, h, filePath, null );
45         }
46         tracef( "UI File: %s", filePath );
47     }
48 
49     /**
50      * Update UI view
51      */
52     void update()
53     {
54         /// TODO: Check for mouse & keyboard input
55         version(Windows)
56         {
57             // Send mouse pos to awesomium
58             auto mousePos = Input.mousePos();
59             awe_webview_inject_mouse_move( _view.webView, cast(int)mousePos.x,cast(int)( Graphics.height - mousePos.y ) );
60 
61 			auto mouseUp = Mouse.isButtonUp(Mouse.Buttons.Left, true);
62 			if( mouseUp ) awe_webview_inject_mouse_up( _view.webView, awe_mousebutton.AWE_MB_LEFT );
63 
64             _view.update();
65         }
66     }
67 
68     /**
69      * Cleanup UI memory
70      */
71     void shutdown()
72     {
73         version(Windows)
74         // Try to clean up gl buffers
75         _view.shutdown();
76         // Clean up mesh, material, and view
77     }
78 
79     /*
80      * Call a JS Function on this UI
81      *
82      * Params:
83      *  funcName =          Name of the function to call
84      *  args =              Array of integer args to send to the function
85      *  object =            Name of the js object containing the function. Blank for global function.
86      */
87     void callJSFunction( string funcName, int[] args, string object = "" )
88     {
89         version(Windows)
90         {
91             // Convert params to awe_js objects
92             awe_string* funcStr = awe_string_create_from_ascii( funcName.toStringz(), funcName.length );
93             awe_string* objectStr = awe_string_create_from_ascii( object.toStringz(), object.length );
94             awe_string* frameStr = awe_string_create_from_ascii( "".toStringz(), 1 );
95 
96             // Build array of js ints
97             awe_jsvalue*[] jsArgs = new awe_jsvalue*[ args.length ];
98 
99             for( int i = 0; i < args.length; i++ )
100             {
101                 jsArgs[i] = awe_jsvalue_create_integer_value( args[i] );
102             }
103 
104             awe_jsarray* argArr = awe_jsarray_create( jsArgs.ptr, args.length );
105 
106 
107 
108             // Execute call
109             awe_webview_call_javascript_function( _view.webView, objectStr, funcStr, argArr, frameStr );
110 
111 
112             // Clean up js objects
113             for( int i = 0; i < args.length; i++ )
114             {
115                 awe_jsvalue_destroy( jsArgs[i] );
116             }
117             awe_jsarray_destroy( argArr );
118         }
119 
120     }
121 
122     /**
123      * Initializes Awesomium singleton
124      */
125     static void initializeAwesomium()
126     {
127         version( Windows )
128         {
129             // Webcore setup
130             awe_webcore_initialize_default();
131             string baseDir = Resources.UI;
132             awe_string* aweBaseDir = awe_string_create_from_ascii( baseDir.toStringz(), baseDir.length );
133             awe_webcore_set_base_directory( aweBaseDir );
134             awe_string_destroy( aweBaseDir );
135         }
136     }
137 
138     /**
139      * Updates Awesomium singleton
140      */
141     static void updateAwesomium()
142     {
143         version( Windows )
144         awe_webcore_update();
145     }
146 
147     /**
148      * Shutdowns Awesomium singleton
149      */
150     static void shutdownAwesomium()
151     {
152         version( Windows )
153         awe_webcore_shutdown();
154     }
155 }
156 
157 
158 /**
159  * Creates an Awesomium web view texture
160  */
161 class AwesomiumView : TextureAsset
162 {
163 private:
164     version( Windows )
165     const(awe_renderbuffer)* renderBuffer;
166 
167 public:
168 //package(dash):
169     version( Windows )
170     awe_webview* webView;
171     ubyte[] glBuffer;
172 
173     this( uint w, uint h, string filePath, GameObject owner, bool localFilePath = true )
174     {
175         _width = w;
176         _height = h;
177         glBuffer = new ubyte[_width*_height*4];
178 
179         super( cast(ubyte*)null, internalResource );
180 
181         version( Windows )
182         {
183             webView = awe_webcore_create_webview( _width, _height, false );
184             webView.awe_webview_set_transparent( true );
185             awe_string* urlString = awe_string_create_from_ascii( filePath.toStringz(), filePath.length );
186 
187             if ( localFilePath )
188                 webView.awe_webview_load_file( urlString,
189                                        awe_string_empty());
190             else
191                 webView.awe_webview_load_url( urlString,
192                                       awe_string_empty(),
193                                       awe_string_empty(),
194                                       awe_string_empty());
195 
196             // Wait for WebView to finish loading the page
197             // JK DON'T
198             //while(awe_webview_is_loading_page(cast(awe_webview*)webView))
199                 //awe_webcore_update();
200 
201             // Destroy our URL string
202             urlString.awe_string_destroy();
203         }
204     }
205 
206     override void update()
207     {
208         // No webview? No update.
209         version( Windows )
210         if ( webView && webView.awe_webview_is_dirty() )
211         {
212             renderBuffer = webView.awe_webview_render();
213 
214             // Ensure the buffer exists
215 			if ( renderBuffer !is null ) {
216 
217 				renderBuffer.awe_renderbuffer_copy_to( glBuffer.ptr, awe_renderbuffer_get_rowspan( renderBuffer ), 4, false, true );
218 
219                 updateBuffer( glBuffer.ptr );
220             }
221 
222         }
223     }
224 
225     override void shutdown()
226     {
227         destroy( glBuffer );
228         version( Windows )
229         webView.awe_webview_destroy();
230     }
231 }