1 jls.loader.provide('jls.win32.WindowElement');
  2 
  3 jls.loader.require('jls.win32.Window');
  4 jls.loader.require('jls.gui.Element');
  5 jls.loader.require('jls.gui.Event');
  6 jls.loader.require('jls.io.File');
  7 
  8 jls.win32.WindowElement = jls.lang.Class.create(jls.gui.Element,
  9 {
 10     initialize : function($super, parameters, parent) {
 11         this._window = null;
 12         this._windowId = null;
 13         this._windowUid = 1;
 14         this._bounds = [null, null, null, null];
 15         this._icon = null;
 16         this._menu = null;
 17         this._popupMenu = null;
 18         
 19         $super(parameters, parent);
 20         if (this._icon) {
 21             this.setIcon(this._icon);
 22         }
 23         jls.logger.trace('parent: "' + parent + '"');
 24         if ((typeof parent == 'undefined') || (parent == null)) {
 25             jls.win32.WindowElement._onCreateTopLevelWindow(this);
 26             this.observe('unload', jls.win32.WindowElement._onDestroyTopLevelWindow);
 27         }
 28         // TODO Remove
 29         //this._window.show(jls.win32.Window.SW_SHOW);
 30         //this.observe('load', this._window.update.bind(this));
 31         //this._window.update();
 32     },
 33     onCreate : jls.lang.Class.abstractMethod,
 34     onStyleChange : function(key, oldValue, newValue) {
 35         if (this._window == null) {
 36             return;
 37         }
 38         switch (key) {
 39         case 'fontFamily':
 40         case 'fontSize':
 41             var font = jls.win32.WindowElement.getFont(this.getStyle().getPropertyValue('fontFamily'),
 42             		this.getStyle().getPropertyValue('fontSize'));
 43             this._window.sendMessage(jls.win32.Window.WM_SETFONT, font, 1 /* force redraw */);
 44             break;
 45         case 'visibility':
 46         	//this._element._window.isWindowVisible() ? 'visible' : 'hidden';
 47     		//jls.lang.System.out.println('onStyleChange(' + key + ', ' + oldValue + ', ' + newValue + ')');
 48             this._window.show(newValue == 'visible' ? jls.win32.Window.SW_SHOW : jls.win32.Window.SW_HIDE);
 49             break;
 50         default:
 51             return;
 52         }
 53     },
 54     addChild : function($super, child) {
 55     	/*if ((typeof child == 'object') &&
 56     			(child instanceof jls.win32.WindowElement) &&
 57     			(child.getWindowStyle() & jls.win32.Window.WS_CHILD == jls.win32.Window.WS_CHILD)) {
 58     		return;
 59     	}*/
 60     	if ((typeof child == 'object') && (child instanceof jls.win32.Frame)) {
 61     		return child;
 62     	}
 63     	return $super(child);
 64     },
 65     onDestroy : function() {
 66         this._window.close();
 67     },
 68     getParentWindow : function(native) {
 69         var parent = this.getParent();
 70         // Looking for the first window type parent
 71         while (parent) {
 72             if (parent instanceof jls.win32.WindowElement) {
 73             	if (native) {
 74                     return parent._window;
 75             	} else {
 76                     return parent;
 77             	}
 78             }
 79             parent = parent.getParent();
 80         }
 81         return null;
 82     },
 83     getWindowOffset : function() {
 84         var parent = this.getParent();
 85         var x = 0;
 86         var y = 0;
 87         // Looking for the first window type parent
 88         while (parent) {
 89         	var cOffset = parent.getClientOffset();
 90             x += cOffset[0];
 91             y += cOffset[1];
 92             if (parent instanceof jls.win32.WindowElement) {
 93                 return [x, y];
 94             }
 95             x += parent._x;
 96             y += parent._y;
 97             parent = parent.getParent();
 98         }
 99         throw new jls.lang.Exception('No WindowElement parent found');
100     },
101     getOwnedWindows : function() {
102         return [];
103     },
104     observe: function($super, type, handler) {
105     	$super(type, handler);
106     	if (type == 'mouseout') {
107     		//this._window.trackMouseEvent(jls.win32.Window.TME_LEAVE);
108     		this._window.setCapture();
109     	}
110     },
111     unobserve: function($super, type, handler) {
112     	$super(type, handler);
113     	if (type == 'mouseout') {
114         	//jls.logger.warn('releaseCapture()');
115     		jls.win32.Window.releaseCapture();
116     	}
117     },
118     onWindowMessage: function(message, wParam, lParam) {
119     	//jls.logger.warn('onWindowMessage(' + jls.win32.Window.getMessageName(message) + ', ' + wParam + ', ' + lParam + ')');
120         switch(message) {
121         case jls.win32.Window.WM_CREATE:
122             this.dispatch(new jls.gui.Event('load', this));
123             break;
124         case jls.win32.Window.WM_DESTROY:
125             this.dispatch(new jls.gui.Event('unload', this));
126             break;
127         case jls.win32.Window.WM_INITMENU: // a menu is about to become active.
128             // wParam: A handle to the menu to be initialized.
129             var menu = null;
130             if ((this._popupMenu != null) && (this._popupMenu._menu.handle() == wParam)) {
131             	menu = this._popupMenu;
132             }
133             if ((this._menu != null) && (this._menu._menu.handle() == wParam)) {
134             	menu = this._menu;
135             }
136             if (menu != null) {
137             	menu.dispatch(new jls.gui.Event('init', this));
138             }
139             break;
140         case jls.win32.Window.WM_INITMENUPOPUP: // a drop-down menu or submenu is about to become active
141             break;
142         case jls.win32.Window.WM_COMMAND:
143         	var src = jls.win32.Window.hiWord(wParam);
144         	var id = jls.win32.Window.loWord(wParam);
145         	//jls.logger.warn('WM_COMMAND wParam: ' + wParam + ' (src: ' + src + ', id: ' + id + '), lParam: ' + lParam);
146         	if (src == 0) { // Menu
147         		var item = null;
148                 if (this._menu != null) {
149                 	item = this._menu.getItemById(id);
150                 }
151                 if ((item == null) && (this._popupMenu != null)) {
152                 	item = this._popupMenu.getItemById(id);
153                 }
154         		if ((item != null) && (item._event != null)) {
155         	        var event = new jls.gui.Event(item._event, this);
156         	        event.menuItem = item;
157         	        item.getRootMenu().dispatch(event);
158         		}
159         	} else if (src == 1) { // Accelerator
160         	}/* else { // Control
161         		// lParam contains the control handle
162                 var childCount = this.getChildCount();
163                 for (var i = 0; i < childCount; i++) {
164                     var child = this.getChild(i);
165                     if ((child instanceof jls.win32.WindowElement) &&
166                     		((child._windowId == id) || (child._window.handle() == lParam)) &&
167                     		('onWindowCommand' in child))
168                     {
169                         child.onWindowCommand(src);
170                         break;
171                     }
172                 }
173         	}*/ // Control notifications are routed natively on the control window via WM_CTLNOTIFY
174             break;
175         case jls.win32.Window.WM_SIZE:
176             var event = new jls.gui.Event('resize', this);
177             event.width = jls.win32.Window.loWord(lParam);
178             event.height = jls.win32.Window.hiWord(lParam);
179             //jls.logger.trace('WM_SIZE - wParam: ' + wParam + ', lParam: ' + lParam + ' (' + event.width + 'x' + event.height + ')');
180             this.dispatch(event);
181             break;
182         case jls.win32.Window.WM_SETFOCUS:
183             this.dispatch(new jls.gui.Event('focus', this));
184             break;
185         case jls.win32.Window.WM_LBUTTONDOWN:
186             this.dispatch(jls.win32.WindowElement.createMouseEvent('mousedown', this, jls.gui.Event.MOUSE_BUTTON_LEFT, wParam, lParam));
187             break;
188         case jls.win32.Window.WM_LBUTTONUP:
189             this.dispatch(jls.win32.WindowElement.createMouseEvent('mouseup', this, jls.gui.Event.MOUSE_BUTTON_LEFT, wParam, lParam));
190             this.dispatch(jls.win32.WindowElement.createMouseEvent('click', this, jls.gui.Event.MOUSE_BUTTON_LEFT, wParam, lParam));
191             break;
192         case jls.win32.Window.WM_LBUTTONDBLCLK:
193             this.dispatch(jls.win32.WindowElement.createMouseEvent('dblclick', this, jls.gui.Event.MOUSE_BUTTON_LEFT, wParam, lParam));
194             break;
195         case jls.win32.Window.WM_MBUTTONDOWN:
196             this.dispatch(jls.win32.WindowElement.createMouseEvent('mousedown', this, jls.gui.Event.MOUSE_BUTTON_MIDDLE, wParam, lParam));
197             break;
198         case jls.win32.Window.WM_MBUTTONUP:
199             this.dispatch(jls.win32.WindowElement.createMouseEvent('mouseup', this, jls.gui.Event.MOUSE_BUTTON_MIDDLE, wParam, lParam));
200             this.dispatch(jls.win32.WindowElement.createMouseEvent('click', this, jls.gui.Event.MOUSE_BUTTON_MIDDLE, wParam, lParam));
201             break;
202         case jls.win32.Window.WM_MBUTTONDBLCLK:
203             this.dispatch(jls.win32.WindowElement.createMouseEvent('dblclick', this, jls.gui.Event.MOUSE_BUTTON_MIDDLE, wParam, lParam));
204             break;
205         case jls.win32.Window.WM_RBUTTONDOWN:
206             this.dispatch(jls.win32.WindowElement.createMouseEvent('mousedown', this, jls.gui.Event.MOUSE_BUTTON_RIGHT, wParam, lParam));
207             break;
208         case jls.win32.Window.WM_RBUTTONUP:
209             this.dispatch(jls.win32.WindowElement.createMouseEvent('mouseup', this, jls.gui.Event.MOUSE_BUTTON_RIGHT, wParam, lParam));
210             this.dispatch(jls.win32.WindowElement.createMouseEvent('click', this, jls.gui.Event.MOUSE_BUTTON_RIGHT, wParam, lParam));
211             break;
212         case jls.win32.Window.WM_RBUTTONDBLCLK:
213             this.dispatch(jls.win32.WindowElement.createMouseEvent('dblclick', this, jls.gui.Event.MOUSE_BUTTON_RIGHT, wParam, lParam));
214             break;
215         // TODO mouseover
216         case jls.win32.Window.WM_MOUSEMOVE:
217             this.dispatch(jls.win32.WindowElement.createMouseEvent('mousemove', this, -1, wParam, lParam));
218             break;
219         case jls.win32.Window.WM_MOUSELEAVE: // TODO Remove
220         case jls.win32.Window.WM_CAPTURECHANGED:
221             this.dispatch(jls.gui.Event.createKeyEvent('mouseout', this, ' '));
222             break;
223         case jls.win32.Window.WM_KEYDOWN:
224             this.dispatch(jls.gui.Event.createKeyEvent('keydown', this, ' '));
225             break;
226         case jls.win32.Window.WM_KEYUP:
227             this.dispatch(jls.gui.Event.createKeyEvent('keyup', this, ' '));
228             break;
229         }
230     },
231     onStartObserving: function() {
232         this._window.setWindowFunction(this.onWindowMessage.bind(this));
233     },
234     onStopObserving: function() {
235         this._window.setWindowFunction(null);
236     },
237     setMenu : function(menu) {
238     	if (! (menu instanceof jls.win32.MenuItem)) {
239     		throw new jls.lang.Exception('Invalid menu argument');
240     	}
241         this._menu = menu;
242         this._window.setMenu(menu._menu);
243     },
244     trackPopup : function(popupMenu, x, y) {
245     	if (! (popupMenu instanceof jls.win32.MenuItem)) {
246     		throw new jls.lang.Exception('Invalid popupMenu argument');
247     	}
248         this._popupMenu = popupMenu;
249         return popupMenu._menu.trackPopup(this._window, x, y);
250     },
251     getWindowExStyle : function() {
252         var exs = 0;
253         // TODO 
254     	/*if (this.getStyle().getPropertyValue('border') != null) {
255             exs |= jls.win32.Window.WS_EX_CLIENTEDGE
256         }*/
257         return exs;
258     },
259     getWindowStyle : function() {
260     	var ws = jls.win32.Window.WS_CHILD;
261     	if (this.getStyle().getPropertyValue('visibility') == 'visible') {
262     		ws |= jls.win32.Window.WS_VISIBLE;
263     	}
264         // TODO Fix
265     	if (this.getStyle().getPropertyValue('border') != null) {
266     		ws |= jls.win32.Window.WS_BORDER;
267     	}
268     	if (this.getStyle().getPropertyValue('overflow') == 'scroll') {
269     		ws |= jls.win32.Window.WS_HSCROLL | jls.win32.Window.WS_VSCROLL;
270     	}
271         return ws;
272     },
273     getWindowId : function(create) {
274     	if (create) {
275     		var pw = this.getParentWindow();
276     		if ((pw != null)) {
277     			this._windowId = pw._windowUid++;
278     		}
279     	}
280         return this._windowId;
281     },
282     setWindowId : function(id) {
283         this._windowId = id;
284         return this;
285     },
286     /*setWindowExStyle : function(exStyle) {
287         this._windowExStyle = exStyle;
288         return this;
289     },
290     setWindowStyle : function(style) {
291         this._windowStyle = style;
292         return this;
293     },*/
294     // TODO setWindowIcon ?
295     getIcon : function() {
296         return this._icon;
297     },
298     setIcon : function(name) {
299         var icon = jls.win32.WindowElement.getIcon(name);
300         if (icon) {
301             this._icon = name;
302             if (this._window) {
303                 this._window.setIcon(icon);
304             }
305         }
306         return this;
307     },
308     /*setWindowFont : function(font) {
309         this.sendMessage(jls.win32.Window.WM_SETFONT, font, 0);
310         return this;
311     },*/
312     onWindowUpdate : function() {
313     	var offset = this.getWindowOffset();
314         var bounds = this.getBounds();
315         var locationChange = (offset[0] + bounds[0] != this._bounds[0]) || (offset[1] + bounds[1] != this._bounds[1]);
316         var sizeChange = (bounds[2] != this._bounds[2]) || (bounds[3] != this._bounds[3]);
317         if (locationChange || sizeChange) {
318             this._setPos(locationChange == sizeChange ? 0 : (locationChange ? jls.win32.Window.SWP_NOSIZE : jls.win32.Window.SWP_NOMOVE));
319         }
320     },
321     update : function($super) {
322     	this.onWindowUpdate();
323         $super();
324         return this;
325     },
326     _setPos : function(flag, offset) {
327         if (this._window) {
328         	offset = offset || this.getWindowOffset();
329             this._window.setPosition(offset[0] + this.getX(), offset[1] + this.getY(), this.getW(), this.getH(), flag || 0);
330             this._bounds = [offset[0] + this.getX(), offset[1] + this.getY(), this.getW(), this.getH()];
331         }
332     },
333     _getBounds : function() {
334         var rect = this._window.rect(true);
335         return [rect[0], rect[1], rect[2] - rect[0], rect[3] - rect[1]];
336     },
337     _getClientRect : function() {
338         return this._window.rect(true);
339     }
340 });
341 
342 Object.extend(jls.win32.WindowElement,
343 {
344     _topLevelWindowCount : 0,
345     _topLevelWindows : [],
346     _fontCache : {},
347     _iconCache : {},
348     getFont : function(family, size) {
349         var key = family + '#' + size;
350         //jls.logger.warn('key: "' + key + '"');
351         if (! (key in jls.win32.WindowElement._fontCache)) {
352             jls.win32.WindowElement._fontCache[key] = new jls.win32.Font(family, size);
353         }
354         return jls.win32.WindowElement._fontCache[key];
355     },
356     getIcon : function(iconFilename) {
357         if (! (iconFilename in jls.win32.WindowElement._iconCache)) {
358             if (new jls.io.File(iconFilename).exists()) {
359                 jls.win32.WindowElement._iconCache[iconFilename] = new jls.win32.Image(iconFilename, jls.win32.Image.IMAGE_ICON);
360             } else {
361                 jls.logger.debug('File not found ' + iconFilename);
362                 //throw new jls.lang.Exception('File not found ' + iconFilename);
363             }
364         }
365         return jls.win32.WindowElement._iconCache[iconFilename];
366     },
367     createMouseEvent : function(type, target, button, wParam, lParam) {
368         var event = new jls.gui.Event(type, target);
369         event.setMouse(button, jls.win32.Window.loWord(lParam), jls.win32.Window.hiWord(lParam), 0, 0);
370         event.control = (wParam & jls.win32.Window.MK_CONTROL) != 0;
371         event.shift = (wParam & jls.win32.Window.MK_SHIFT) != 0;
372         return event;
373     },
374     getWindows : function() {
375         // TODO make a copy
376         return jls.win32.WindowElement._topLevelWindows;
377     },
378     _onCreateTopLevelWindow : function(wnd) {
379         jls.win32.WindowElement._topLevelWindowCount++;
380         jls.logger.trace('add top-level window (' + jls.win32.WindowElement._topLevelWindowCount + ')');
381     },
382     _onDestroyTopLevelWindow : function(event) {
383         
384         jls.win32.WindowElement._topLevelWindowCount--;
385         jls.logger.trace('remove top-level window (' + jls.win32.WindowElement._topLevelWindowCount + ')');
386         if (jls.win32.WindowElement._topLevelWindowCount == 0) {
387             jls.win32.Window.destroyThreadWindow();
388         }
389     }
390 });
391 
392