update source for tizen_2.1
[sdk/emulator/qemu.git] / tizen / src / skin / client / src / org / tizen / emulator / skin / layout / PhoneShapeSkinComposer.java
1 /**
2  * 
3  *
4  * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact:
7  * GiWoong Kim <giwoong.kim@samsung.com>
8  * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
23  *
24  * Contributors:
25  * - S-Core Co., Ltd
26  *
27  */
28
29 package org.tizen.emulator.skin.layout;
30
31 import java.util.logging.Logger;
32
33 import org.eclipse.swt.SWT;
34 import org.eclipse.swt.events.MouseEvent;
35 import org.eclipse.swt.events.MouseListener;
36 import org.eclipse.swt.events.MouseMoveListener;
37 import org.eclipse.swt.events.MouseTrackAdapter;
38 import org.eclipse.swt.events.MouseTrackListener;
39 import org.eclipse.swt.events.PaintEvent;
40 import org.eclipse.swt.events.PaintListener;
41 import org.eclipse.swt.graphics.Color;
42 import org.eclipse.swt.graphics.GC;
43 import org.eclipse.swt.graphics.Image;
44 import org.eclipse.swt.graphics.ImageData;
45 import org.eclipse.swt.graphics.Point;
46 import org.eclipse.swt.graphics.RGB;
47 import org.eclipse.swt.graphics.Rectangle;
48 import org.eclipse.swt.widgets.Canvas;
49 import org.eclipse.swt.widgets.Shell;
50 import org.tizen.emulator.skin.EmulatorSkin;
51 import org.tizen.emulator.skin.EmulatorSkinState;
52 import org.tizen.emulator.skin.comm.ICommunicator.KeyEventType;
53 import org.tizen.emulator.skin.comm.ICommunicator.SendCommand;
54 import org.tizen.emulator.skin.comm.sock.SocketCommunicator;
55 import org.tizen.emulator.skin.comm.sock.data.KeyEventData;
56 import org.tizen.emulator.skin.config.EmulatorConfig;
57 import org.tizen.emulator.skin.config.EmulatorConfig.ArgsConstants;
58 import org.tizen.emulator.skin.config.EmulatorConfig.SkinPropertiesConstants;
59 import org.tizen.emulator.skin.custom.CustomProgressBar;
60 import org.tizen.emulator.skin.dbi.LcdType;
61 import org.tizen.emulator.skin.dbi.RegionType;
62 import org.tizen.emulator.skin.dbi.RotationType;
63 import org.tizen.emulator.skin.image.ImageRegistry;
64 import org.tizen.emulator.skin.image.ImageRegistry.IconName;
65 import org.tizen.emulator.skin.image.ImageRegistry.ImageType;
66 import org.tizen.emulator.skin.log.SkinLogger;
67 import org.tizen.emulator.skin.util.SkinRotation;
68 import org.tizen.emulator.skin.util.SkinUtil;
69 import org.tizen.emulator.skin.util.SwtUtil;
70
71 public class PhoneShapeSkinComposer implements ISkinComposer {
72         private Logger logger = SkinLogger.getSkinLogger(
73                         PhoneShapeSkinComposer.class).getLogger();
74
75         private EmulatorConfig config;
76         private EmulatorSkin skin;
77         private Shell shell;
78         private Canvas lcdCanvas;
79         private EmulatorSkinState currentState;
80         private ImageRegistry imageRegistry;
81         private SocketCommunicator communicator;
82
83         private PaintListener shellPaintListener;
84         private MouseTrackListener shellMouseTrackListener;
85         private MouseMoveListener shellMouseMoveListener;
86         private MouseListener shellMouseListener;
87
88         private boolean isGrabbedShell;
89         private Point grabPosition;
90
91         public PhoneShapeSkinComposer(EmulatorConfig config, EmulatorSkin skin,
92                         Shell shell, EmulatorSkinState currentState,
93                         ImageRegistry imageRegistry, SocketCommunicator communicator) {
94                 this.config = config;
95                 this.skin = skin;
96                 this.shell = shell;
97                 this.currentState = currentState;
98                 this.imageRegistry = imageRegistry;
99                 this.communicator = communicator;
100                 this.isGrabbedShell= false;
101                 this.grabPosition = new Point(0, 0);
102         }
103
104         @Override
105         public Canvas compose(int style) {
106                 lcdCanvas = new Canvas(shell, style);
107
108                 int x = config.getSkinPropertyInt(SkinPropertiesConstants.WINDOW_X,
109                                 EmulatorConfig.DEFAULT_WINDOW_X);
110                 int y = config.getSkinPropertyInt(SkinPropertiesConstants.WINDOW_Y,
111                                 EmulatorConfig.DEFAULT_WINDOW_Y);
112
113                 currentState.setCurrentResolutionWidth(
114                                 config.getArgInt(ArgsConstants.RESOLUTION_WIDTH));
115                 currentState.setCurrentResolutionHeight(
116                                 config.getArgInt(ArgsConstants.RESOLUTION_HEIGHT));
117
118                 int scale = SkinUtil.getValidScale(config);
119 //              int rotationId = config.getPropertyShort( PropertiesConstants.WINDOW_ROTATION,
120 //                              EmulatorConfig.DEFAULT_WINDOW_ROTATION );
121                 // has to be portrait mode at first booting time
122                 short rotationId = EmulatorConfig.DEFAULT_WINDOW_ROTATION;
123
124                 composeInternal(lcdCanvas, x, y, scale, rotationId);
125                 logger.info("resolution : " + currentState.getCurrentResolution() +
126                                 ", scale : " + scale);
127
128                 return lcdCanvas;
129         }
130
131         @Override
132         public void composeInternal(Canvas lcdCanvas,
133                         int x, int y, int scale, short rotationId) {
134
135                 //shell.setBackground(shell.getDisplay().getSystemColor(SWT.COLOR_BLACK));
136                 shell.setLocation(x, y);
137
138                 String emulatorName = SkinUtil.makeEmulatorName(config);
139                 shell.setText("Emulator - " + emulatorName);
140
141                 lcdCanvas.setBackground(shell.getDisplay().getSystemColor(SWT.COLOR_BLACK));
142
143                 if (SwtUtil.isWindowsPlatform()) {
144                         shell.setImage(imageRegistry.getIcon(IconName.EMULATOR_TITLE_ICO));
145                 } else {
146                         shell.setImage(imageRegistry.getIcon(IconName.EMULATOR_TITLE));
147                 }
148
149                 /* create a progress bar for booting status */
150                 skin.bootingProgress = new CustomProgressBar(shell, SWT.NONE);
151                 skin.bootingProgress.setBackground(
152                                 new Color(shell.getDisplay(), new RGB(38, 38, 38)));
153
154                 arrangeSkin(scale, rotationId);
155
156                 if (currentState.getCurrentImage() == null) {
157                         logger.severe("Failed to load initial skin image file. Kill this skin process.");
158                         SkinUtil.openMessage(shell, null,
159                                         "Failed to load Skin image file.", SWT.ICON_ERROR, config);
160                         System.exit(-1);
161                 }
162         }
163
164         @Override
165         public void arrangeSkin(int scale, short rotationId) {
166                 currentState.setCurrentScale(scale);
167                 currentState.setCurrentRotationId(rotationId);
168                 currentState.setCurrentAngle(SkinRotation.getAngle(rotationId));
169
170                 /* arrange the display */
171                 Rectangle lcdBounds = adjustLcdGeometry(lcdCanvas,
172                                 currentState.getCurrentResolutionWidth(),
173                                 currentState.getCurrentResolutionHeight(), scale, rotationId);
174
175                 if (lcdBounds == null) {
176                         logger.severe("Failed to lcd information for phone shape skin.");
177                         SkinUtil.openMessage(shell, null,
178                                         "Failed to read lcd information for phone shape skin.\n" +
179                                         "Check the contents of skin dbi file.",
180                                         SWT.ICON_ERROR, config);
181                         System.exit(-1);
182                 }
183                 logger.info("lcd bounds : " + lcdBounds);
184
185                 currentState.setDisplayBounds(lcdBounds);
186                 currentState.setUpdateDisplayBounds(true);
187                 //lcdCanvas.setBounds(lcdBounds);
188
189                 /* arrange the skin image */
190                 Image tempImage = null;
191                 Image tempKeyPressedImage = null;
192
193                 if (currentState.getCurrentImage() != null) {
194                         tempImage = currentState.getCurrentImage();
195                 }
196                 if (currentState.getCurrentKeyPressedImage() != null) {
197                         tempKeyPressedImage = currentState.getCurrentKeyPressedImage();
198                 }
199
200                 currentState.setCurrentImage(SkinUtil.createScaledImage(
201                                 imageRegistry, shell, rotationId, scale, ImageType.IMG_TYPE_MAIN));
202                 currentState.setCurrentKeyPressedImag(SkinUtil.createScaledImage(
203                                 imageRegistry, shell, rotationId, scale, ImageType.IMG_TYPE_PRESSED));
204
205                 if (tempImage != null) {
206                         tempImage.dispose();
207                 }
208                 if (tempKeyPressedImage != null) {
209                         tempKeyPressedImage.dispose();
210                 }
211
212                 /* arrange the progress bar */
213                 if (skin.bootingProgress != null) {
214                         skin.bootingProgress.setBounds(lcdBounds.x,
215                                         lcdBounds.y + lcdBounds.height + 1, lcdBounds.width, 2);
216                 }
217
218                 /* set window size */
219                 if (currentState.getCurrentImage() != null) {
220                         ImageData imageData = currentState.getCurrentImage().getImageData();
221                         shell.setMinimumSize(imageData.width, imageData.height);
222                 }
223
224                 shell.pack();
225
226                 /* set window size */
227                 if (currentState.getCurrentImage() != null) {
228                         ImageData imageData = currentState.getCurrentImage().getImageData();
229                         shell.setSize(imageData.width, imageData.height);
230                 }
231
232                 /* custom window shape */
233                 SkinUtil.trimShell(shell, currentState.getCurrentImage());
234
235                 shell.redraw();
236         }
237
238         @Override
239         public Rectangle adjustLcdGeometry(
240                         Canvas lcdCanvas, int resolutionW, int resolutionH,
241                         int scale, short rotationId) {
242                 Rectangle lcdBounds = new Rectangle(0, 0, 0, 0);
243
244                 float convertedScale = SkinUtil.convertScale(scale);
245                 RotationType rotation = SkinRotation.getRotation(rotationId);
246
247                 LcdType lcd = rotation.getLcd(); /* from dbi */
248                 if (lcd == null) {
249                         return null;
250                 }
251
252                 RegionType region = lcd.getRegion();
253                 if (region == null) {
254                         return null;
255                 }
256
257                 Integer left = region.getLeft();
258                 Integer top = region.getTop();
259                 Integer width = region.getWidth();
260                 Integer height = region.getHeight();
261
262                 lcdBounds.x = (int) (left * convertedScale);
263                 lcdBounds.y = (int) (top * convertedScale);
264                 lcdBounds.width = (int) (width * convertedScale);
265                 lcdBounds.height = (int) (height * convertedScale);
266
267                 return lcdBounds;
268         }
269
270         public void addPhoneShapeListener(final Shell shell) {
271                 shellPaintListener = new PaintListener() {
272                         @Override
273                         public void paintControl(final PaintEvent e) {
274                                 if (currentState.isUpdateDisplayBounds() == true) {
275                                         currentState.setUpdateDisplayBounds(false);
276                                         lcdCanvas.setBounds(currentState.getDisplayBounds());
277                                 }
278
279                                 /* general shell does not support native transparency,
280                                  * so draw image with GC. */
281                                 if (currentState.getCurrentImage() != null) {
282                                         e.gc.drawImage(currentState.getCurrentImage(), 0, 0);
283                                 }
284
285                         }
286                 };
287
288                 shell.addPaintListener(shellPaintListener);
289
290                 shellMouseTrackListener = new MouseTrackAdapter() {
291                         @Override
292                         public void mouseExit(MouseEvent e) {
293                                 /* shell does not receive event only with MouseMoveListener
294                                  * in case that : hover hardkey -> mouse move into LCD area */
295                                 HWKey hoveredHWKey = currentState.getCurrentHoveredHWKey();
296
297                                 if (hoveredHWKey != null) {
298                                         shell.redraw(hoveredHWKey.getRegion().x,
299                                                         hoveredHWKey.getRegion().y,
300                                                         hoveredHWKey.getRegion().width,
301                                                         hoveredHWKey.getRegion().height, false);
302
303                                         currentState.setCurrentHoveredHWKey(null);
304                                         shell.setToolTipText(null);
305                                 }
306                         }
307                 };
308
309                 shell.addMouseTrackListener(shellMouseTrackListener);
310
311                 shellMouseMoveListener = new MouseMoveListener() {
312                         @Override
313                         public void mouseMove(MouseEvent e) {
314                                 if (isGrabbedShell == true && e.button == 0/* left button */ &&
315                                                 currentState.getCurrentPressedHWKey() == null) {
316                                         /* move a window */
317                                         Point previousLocation = shell.getLocation();
318                                         int x = previousLocation.x + (e.x - grabPosition.x);
319                                         int y = previousLocation.y + (e.y - grabPosition.y);
320
321                                         shell.setLocation(x, y);
322                                         return;
323                                 }
324
325                                 final HWKey hwKey = SkinUtil.getHWKey(e.x, e.y,
326                                                 currentState.getCurrentRotationId(), currentState.getCurrentScale());
327                                 if (hwKey == null) {
328                                         /* remove hover */
329                                         HWKey hoveredHWKey = currentState.getCurrentHoveredHWKey();
330
331                                         if (hoveredHWKey != null) {
332                                                 shell.redraw(hoveredHWKey.getRegion().x,
333                                                                 hoveredHWKey.getRegion().y,
334                                                                 hoveredHWKey.getRegion().width,
335                                                                 hoveredHWKey.getRegion().height, false);
336
337                                                 currentState.setCurrentHoveredHWKey(null);
338                                                 shell.setToolTipText(null);
339                                         }
340
341                                         return;
342                                 }
343
344                                 /* register a tooltip */
345                                 if (currentState.getCurrentHoveredHWKey() == null &&
346                                                 hwKey.getTooltip().isEmpty() == false) {
347                                         shell.setToolTipText(hwKey.getTooltip());
348                                 }
349
350                                 /* draw hover */
351                                 shell.getDisplay().syncExec(new Runnable() {
352                                         public void run() {
353                                                 if (hwKey.getRegion().width != 0 && hwKey.getRegion().height != 0) {
354                                                         GC gc = new GC(shell);
355                                                         if (gc != null) {
356                                                                 gc.setLineWidth(1);
357                                                                 gc.setForeground(currentState.getHoverColor());
358                                                                 gc.drawRectangle(hwKey.getRegion().x, hwKey.getRegion().y,
359                                                                                 hwKey.getRegion().width - 1, hwKey.getRegion().height - 1);
360
361                                                                 gc.dispose();
362
363                                                                 currentState.setCurrentHoveredHWKey(hwKey);
364                                                         }
365                                                 }
366                                         }
367                                 });
368
369                         }
370                 };
371
372                 shell.addMouseMoveListener(shellMouseMoveListener);
373
374                 shellMouseListener = new MouseListener() {
375                         @Override
376                         public void mouseUp(MouseEvent e) {
377                                 if (e.button == 1) { /* left button */
378                                         logger.info("mouseUp in Skin");
379
380                                         isGrabbedShell = false;
381                                         grabPosition.x = grabPosition.y = 0;
382
383                                         HWKey pressedHWKey = currentState.getCurrentPressedHWKey();
384                                         if (pressedHWKey == null) {
385                                                 return;
386                                         }
387
388                                         if (pressedHWKey.getKeyCode() != SkinUtil.UNKNOWN_KEYCODE) {
389                                                 /* send event */
390                                                 KeyEventData keyEventData = new KeyEventData(
391                                                                 KeyEventType.RELEASED.value(), pressedHWKey.getKeyCode(), 0, 0);
392                                                 communicator.sendToQEMU(SendCommand.SEND_HARD_KEY_EVENT, keyEventData);
393
394                                                 currentState.setCurrentPressedHWKey(null);
395
396                                                 /* roll back a keyPressed image region */
397                                                 shell.redraw(pressedHWKey.getRegion().x, pressedHWKey.getRegion().y,
398                                                                 pressedHWKey.getRegion().width, pressedHWKey.getRegion().height, false);
399
400                                                 if (pressedHWKey.getKeyCode() != 101) { // TODO: not necessary for home key
401                                                         SkinUtil.trimShell(shell, currentState.getCurrentImage(),
402                                                                         pressedHWKey.getRegion().x, pressedHWKey.getRegion().y,
403                                                                         pressedHWKey.getRegion().width, pressedHWKey.getRegion().height);
404                                                 }
405                                         }
406                                 }
407                         }
408
409                         @Override
410                         public void mouseDown(MouseEvent e) {
411                                 if (1 == e.button) { /* left button */
412                                         logger.info("mouseDown in Skin");
413
414                                         isGrabbedShell = true;
415                                         grabPosition.x = e.x;
416                                         grabPosition.y = e.y;
417
418                                         final HWKey hwKey = SkinUtil.getHWKey(e.x, e.y,
419                                                         currentState.getCurrentRotationId(), currentState.getCurrentScale());
420                                         if (hwKey == null) {
421                                                 return;
422                                         }
423
424                                         if (hwKey.getKeyCode() != SkinUtil.UNKNOWN_KEYCODE) {
425                                                 /* send event */
426                                                 KeyEventData keyEventData = new KeyEventData(
427                                                                 KeyEventType.PRESSED.value(), hwKey.getKeyCode(), 0, 0);
428                                                 communicator.sendToQEMU(SendCommand.SEND_HARD_KEY_EVENT, keyEventData);
429
430                                                 currentState.setCurrentPressedHWKey(hwKey);
431
432                                                 shell.setToolTipText(null);
433
434                                                 /* draw the HW key region as the cropped keyPressed image area */
435                                                 if (hwKey.getRegion() != null &&
436                                                                 hwKey.getRegion().width != 0 && hwKey.getRegion().height != 0) {
437                                                         shell.getDisplay().syncExec(new Runnable() {
438                                                                 public void run() {
439                                                                         if (currentState.getCurrentKeyPressedImage() != null) {
440                                                                                 GC gc = new GC(shell);
441                                                                                 if (gc != null) {
442                                                                                         gc.drawImage(currentState.getCurrentKeyPressedImage(),
443                                                                                                         hwKey.getRegion().x, hwKey.getRegion().y,
444                                                                                                         hwKey.getRegion().width, hwKey.getRegion().height, //src
445                                                                                                         hwKey.getRegion().x, hwKey.getRegion().y,
446                                                                                                         hwKey.getRegion().width, hwKey.getRegion().height); //dst
447
448                                                                                         gc.dispose();
449
450                                                                                         if (hwKey.getKeyCode() != 101) { // TODO: not necessary for home key
451                                                                                                 SkinUtil.trimShell(shell, currentState.getCurrentKeyPressedImage(),
452                                                                                                                 hwKey.getRegion().x, hwKey.getRegion().y,
453                                                                                                                 hwKey.getRegion().width, hwKey.getRegion().height);
454                                                                                         }
455
456                                                                                 }
457                                                                         }
458                                                                 } /* end of run */
459                                                         });
460                                                 }
461
462                                         }
463                                 }
464                         }
465
466                         @Override
467                         public void mouseDoubleClick(MouseEvent e) {
468                                 /* do nothing */
469                         }
470                 };
471
472                 shell.addMouseListener(shellMouseListener);
473         }
474
475         @Override
476         public void composerFinalize() {
477                 if (null != shellPaintListener) {
478                         shell.removePaintListener(shellPaintListener);
479                 }
480
481                 if (null != shellMouseTrackListener) {
482                         shell.removeMouseTrackListener(shellMouseTrackListener);
483                 }
484
485                 if (null != shellMouseMoveListener) {
486                         shell.removeMouseMoveListener(shellMouseMoveListener);
487                 }
488
489                 if (null != shellMouseListener) {
490                         shell.removeMouseListener(shellMouseListener);
491                 }
492         }
493 }