Tizen 2.1 base
[sdk/emulator/qemu.git] / tizen / src / skin / client / src / org / tizen / emulator / skin / layout / GeneralPurposeSkinComposer.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.PaintEvent;
38 import org.eclipse.swt.events.PaintListener;
39 import org.eclipse.swt.graphics.Color;
40 import org.eclipse.swt.graphics.Image;
41 import org.eclipse.swt.graphics.ImageData;
42 import org.eclipse.swt.graphics.Point;
43 import org.eclipse.swt.graphics.RGB;
44 import org.eclipse.swt.graphics.Rectangle;
45 import org.eclipse.swt.graphics.Region;
46 import org.eclipse.swt.widgets.Canvas;
47 import org.eclipse.swt.widgets.Shell;
48 import org.tizen.emulator.skin.EmulatorSkin;
49 import org.tizen.emulator.skin.EmulatorSkinState;
50 import org.tizen.emulator.skin.comm.ICommunicator.RotationInfo;
51 import org.tizen.emulator.skin.config.EmulatorConfig;
52 import org.tizen.emulator.skin.config.EmulatorConfig.ArgsConstants;
53 import org.tizen.emulator.skin.config.EmulatorConfig.SkinPropertiesConstants;
54 import org.tizen.emulator.skin.custom.CustomButton;
55 import org.tizen.emulator.skin.custom.CustomProgressBar;
56 import org.tizen.emulator.skin.image.ImageRegistry;
57 import org.tizen.emulator.skin.image.ImageRegistry.IconName;
58 import org.tizen.emulator.skin.log.SkinLogger;
59 import org.tizen.emulator.skin.util.SkinRotation;
60 import org.tizen.emulator.skin.util.SkinUtil;
61 import org.tizen.emulator.skin.util.SwtUtil;
62
63 public class GeneralPurposeSkinComposer implements ISkinComposer {
64         private static final String PATCH_IMAGES_PATH = "images/emul-window/";
65         private static final String TOGGLE_BUTTON_NORMAL_IMG = "arrow_nml.png";
66         private static final String TOGGLE_BUTTON_HOVER_IMG = "arrow_hover.png";
67         private static final String TOGGLE_BUTTON_PUSHED_IMG = "arrow_pushed.png";
68
69         private static final int PAIR_TAG_POSITION_X = 26;
70         private static final int PAIR_TAG_POSITION_Y = 13;
71         private static final int PAIR_TAG_POSITION_WIDTH = 8;
72         private static final int PAIR_TAG_POSITION_HEIGHT = 8;
73
74         private Logger logger = SkinLogger.getSkinLogger(
75                         GeneralPurposeSkinComposer.class).getLogger();
76
77         private EmulatorConfig config;
78         private EmulatorSkin skin;
79         private Shell shell;
80         private Canvas displayCanvas;
81         private Color backgroundColor;
82         private CustomButton toggleButton;
83         private EmulatorSkinState currentState;
84
85         private ImageRegistry imageRegistry;
86         private SkinPatches frameMaker;
87
88         private PaintListener shellPaintListener;
89         private MouseMoveListener shellMouseMoveListener;
90         private MouseListener shellMouseListener;
91
92         private boolean isGrabbedShell;
93         private Point grabPosition;
94
95         public GeneralPurposeSkinComposer(EmulatorConfig config, EmulatorSkin skin,
96                         Shell shell, EmulatorSkinState currentState,
97                         ImageRegistry imageRegistry) {
98                 this.config = config;
99                 this.skin = skin;
100                 this.shell = shell;
101                 this.currentState = currentState;
102                 this.imageRegistry = imageRegistry;
103                 this.isGrabbedShell= false;
104                 this.grabPosition = new Point(0, 0);
105
106                 this.frameMaker = new SkinPatches(PATCH_IMAGES_PATH);
107                 this.backgroundColor = new Color(shell.getDisplay(), new RGB(38, 38, 38));
108         }
109
110         @Override
111         public Canvas compose(int style) {
112                 displayCanvas = new Canvas(shell, style);
113
114                 int vmIndex = config.getArgInt(ArgsConstants.NET_BASE_PORT) % 100;
115
116                 int x = config.getSkinPropertyInt(SkinPropertiesConstants.WINDOW_X,
117                                 EmulatorConfig.DEFAULT_WINDOW_X + vmIndex);
118                 int y = config.getSkinPropertyInt(SkinPropertiesConstants.WINDOW_Y,
119                                 EmulatorConfig.DEFAULT_WINDOW_Y + vmIndex);
120
121                 currentState.setCurrentResolutionWidth(
122                                 config.getArgInt(ArgsConstants.RESOLUTION_WIDTH));
123                 currentState.setCurrentResolutionHeight(
124                                 config.getArgInt(ArgsConstants.RESOLUTION_HEIGHT));
125
126                 int scale = SkinUtil.getValidScale(config);
127                 short rotationId = EmulatorConfig.DEFAULT_WINDOW_ROTATION;
128
129                 composeInternal(displayCanvas, x, y, scale, rotationId);
130                 logger.info("resolution : " + currentState.getCurrentResolution() +
131                                 ", scale : " + scale);
132
133                 return displayCanvas;
134         }
135
136         @Override
137         public void composeInternal(Canvas displayCanvas,
138                         final int x, final int y, int scale, short rotationId) {
139
140                 //shell.setBackground(shell.getDisplay().getSystemColor(SWT.COLOR_BLACK));
141                 shell.setLocation(x, y);
142
143                 String emulatorName = SkinUtil.makeEmulatorName(config);
144                 shell.setText(emulatorName);
145
146                 displayCanvas.setBackground(
147                                 shell.getDisplay().getSystemColor(SWT.COLOR_BLACK));
148
149                 if (SwtUtil.isWindowsPlatform()) {
150                         shell.setImage(imageRegistry.getIcon(IconName.EMULATOR_TITLE_ICO));
151                 } else {
152                         shell.setImage(imageRegistry.getIcon(IconName.EMULATOR_TITLE));
153                 }
154
155                 /* load image for toggle button of key window */
156                 ClassLoader loader = this.getClass().getClassLoader();
157                 Image imageNormal = new Image(shell.getDisplay(),
158                                 loader.getResourceAsStream(PATCH_IMAGES_PATH + TOGGLE_BUTTON_NORMAL_IMG));
159                 Image imageHover = new Image(shell.getDisplay(),
160                                 loader.getResourceAsStream(PATCH_IMAGES_PATH + TOGGLE_BUTTON_HOVER_IMG));
161                 Image imagePushed = new Image(shell.getDisplay(),
162                                 loader.getResourceAsStream(PATCH_IMAGES_PATH + TOGGLE_BUTTON_PUSHED_IMG));
163
164                 /* create a toggle button of key window */
165                 toggleButton = new CustomButton(shell, SWT.DRAW_TRANSPARENT | SWT.NO_FOCUS,
166                                 imageNormal, imageHover, imagePushed);
167                 toggleButton.setBackground(backgroundColor);
168
169                 toggleButton.addMouseListener(new MouseListener() {
170                         @Override
171                         public void mouseDown(MouseEvent e) {
172                                 if (skin.isSelectKeyWindow() == true) {
173                                         skin.closeKeyWindow();
174                                         skin.recentlyDocked = SWT.RIGHT | SWT.CENTER;
175                                 } else {
176                                         skin.openKeyWindow(SWT.RIGHT | SWT.CENTER, true);
177                                 }
178                         }
179
180                         @Override
181                         public void mouseUp(MouseEvent e) {
182                                 /* do nothing */
183                         }
184
185                         @Override
186                         public void mouseDoubleClick(MouseEvent e) {
187                                 /* do nothing */
188                         }
189                 });
190
191                 /* make a pair tag circle */
192                 skin.pairTagCanvas = new Canvas(shell, SWT.NO_FOCUS);
193                 skin.pairTagCanvas.setBackground(backgroundColor);
194
195                 skin.pairTagCanvas.addPaintListener(new PaintListener() {
196                         @Override
197                         public void paintControl(PaintEvent e) {
198                                 if (skin.colorPairTag != null) {
199                                         e.gc.setBackground(skin.colorPairTag);
200                                         e.gc.setAntialias(SWT.ON);
201                                         e.gc.fillOval(
202                                                         0, 0, PAIR_TAG_POSITION_WIDTH, PAIR_TAG_POSITION_HEIGHT);
203                                 }
204                         }
205                 });
206                 skin.pairTagCanvas.setVisible(false);
207
208                 /* create a progress bar for booting status */
209                 skin.bootingProgress = new CustomProgressBar(shell, SWT.NONE);
210                 skin.bootingProgress.setBackground(backgroundColor);
211
212                 arrangeSkin(scale, rotationId);
213
214                 /* open the key window */
215                 shell.getDisplay().asyncExec(new Runnable() {
216                         @Override
217                         public void run() {
218                                 skin.openKeyWindow(SWT.RIGHT | SWT.CENTER, false);
219                         }
220                 });
221         }
222
223         @Override
224         public void arrangeSkin(int scale, short rotationId) {
225                 currentState.setCurrentScale(scale);
226                 currentState.setCurrentRotationId(rotationId);
227                 currentState.setCurrentAngle(SkinRotation.getAngle(rotationId));
228
229                 /* arrange the display */
230                 Rectangle displayBounds = adjustLcdGeometry(displayCanvas,
231                                 currentState.getCurrentResolutionWidth(),
232                                 currentState.getCurrentResolutionHeight(), scale, rotationId);
233
234                 if (displayBounds == null) {
235                         logger.severe("Failed to lcd information for phone shape skin.");
236                         SkinUtil.openMessage(shell, null,
237                                         "Failed to read lcd information for phone shape skin.\n" +
238                                         "Check the contents of skin dbi file.",
239                                         SWT.ICON_ERROR, config);
240                         System.exit(-1);
241                 }
242                 logger.info("display bounds : " + displayBounds);
243
244                 currentState.setDisplayBounds(displayBounds);
245                 displayCanvas.setBounds(displayBounds);
246
247                 /* arrange the skin image */
248                 Image tempImage = null;
249
250                 if (currentState.getCurrentImage() != null) {
251                         tempImage = currentState.getCurrentImage();
252                 }
253
254                 currentState.setCurrentImage(
255                                 frameMaker.getPatchedImage(displayBounds.width, displayBounds.height));
256
257                 if (tempImage != null) {
258                         tempImage.dispose();
259                 }
260
261                 /* arrange the toggle button of key window */
262                 toggleButton.setBounds(displayBounds.x + displayBounds.width,
263                                 displayBounds.y + (displayBounds.height / 2) - (toggleButton.getImageSize().y / 2),
264                                 toggleButton.getImageSize().x, toggleButton.getImageSize().y);
265
266                 /* arrange the progress bar */
267                 if (skin.bootingProgress != null) {
268                         skin.bootingProgress.setBounds(displayBounds.x,
269                                         displayBounds.y + displayBounds.height + 1, displayBounds.width, 2);
270                 }
271
272                 /* arrange the pair tag */
273                 skin.pairTagCanvas.setBounds(
274                                 PAIR_TAG_POSITION_X, PAIR_TAG_POSITION_Y,
275                                 PAIR_TAG_POSITION_WIDTH, PAIR_TAG_POSITION_HEIGHT);
276
277                 /* set window size */
278                 if (currentState.getCurrentImage() != null) {
279                         ImageData imageData = currentState.getCurrentImage().getImageData();
280                         shell.setMinimumSize(imageData.width, imageData.height);
281                 }
282
283                 shell.pack();
284
285                 if (currentState.getCurrentImage() != null) {
286                         ImageData imageData = currentState.getCurrentImage().getImageData();
287                         shell.setSize(imageData.width, imageData.height);
288                 }
289
290                 /* custom window shape */
291                 trimPatchedShell(shell, currentState.getCurrentImage());
292
293                 shell.redraw();
294         }
295
296         @Override
297         public Rectangle adjustLcdGeometry(
298                         Canvas displayCanvas, int resolutionW, int resolutionH,
299                         int scale, short rotationId) {
300
301                 Rectangle lcdBounds = new Rectangle(
302                                 frameMaker.getPatchWidth(), frameMaker.getPatchHeight(), 0, 0);
303
304                 float convertedScale = SkinUtil.convertScale(scale);
305                 RotationInfo rotation = RotationInfo.getValue(rotationId);
306
307                 /* resoultion, that is lcd size in general skin mode */
308                 if (RotationInfo.LANDSCAPE == rotation ||
309                                 RotationInfo.REVERSE_LANDSCAPE == rotation) {
310                         lcdBounds.width = (int)(resolutionH * convertedScale);
311                         lcdBounds.height = (int)(resolutionW * convertedScale);
312                 } else {
313                         lcdBounds.width = (int)(resolutionW * convertedScale);
314                         lcdBounds.height = (int)(resolutionH * convertedScale);
315                 }
316
317                 return lcdBounds;
318         }
319
320         public static void trimPatchedShell(Shell shell, Image image) {
321                 if (null == image) {
322                         return;
323                 }
324                 ImageData imageData = image.getImageData();
325
326                 int width = imageData.width;
327                 int height = imageData.height;
328
329                 Region region = new Region();
330                 region.add(new Rectangle(0, 0, width, height));
331
332                 int r = shell.getDisplay().getSystemColor(SWT.COLOR_MAGENTA).getRed();
333                 int g = shell.getDisplay().getSystemColor(SWT.COLOR_MAGENTA).getGreen();
334                 int b = shell.getDisplay().getSystemColor(SWT.COLOR_MAGENTA).getBlue();
335                 int colorKey = 0;
336
337                 if (SwtUtil.isWindowsPlatform()) {
338                         colorKey = r << 24 | g << 16 | b << 8;
339                 } else {
340                         colorKey = r << 16 | g << 8 | b;
341                 }
342
343                 for (int i = 0; i < width; i++) {
344                         for (int j = 0; j < height; j++) {
345                                 int colorPixel = imageData.getPixel(i, j);
346                                 if (colorPixel == colorKey /* magenta */) {
347                                         region.subtract(i, j, 1, 1);
348                                 }
349                         }
350                 }
351
352                 shell.setRegion(region);
353         }
354
355         public void addGeneralPurposeListener(final Shell shell) {
356                 shellPaintListener = new PaintListener() {
357                         @Override
358                         public void paintControl(final PaintEvent e) {
359                                 /* general shell does not support native transparency,
360                                  * so draw image with GC. */
361                                 if (currentState.getCurrentImage() != null) {
362                                         e.gc.drawImage(currentState.getCurrentImage(), 0, 0);
363                                 }
364
365                                 if (skin.keyWindow != null &&
366                                                 skin.keyWindow.getDockPosition() != SWT.NONE) {
367                                         skin.keyWindow.dock(
368                                                         skin.keyWindow.getDockPosition(), false, false);
369                                 }
370                         }
371                 };
372
373                 shell.addPaintListener(shellPaintListener);
374
375                 shellMouseMoveListener = new MouseMoveListener() {
376                         @Override
377                         public void mouseMove(MouseEvent e) {
378                                 if (isGrabbedShell == true && e.button == 0/* left button */) {
379                                         /* move a window */
380                                         Point previousLocation = shell.getLocation();
381                                         int x = previousLocation.x + (e.x - grabPosition.x);
382                                         int y = previousLocation.y + (e.y - grabPosition.y);
383
384                                         shell.setLocation(x, y);
385
386                                         if (skin.keyWindow != null &&
387                                                         skin.keyWindow.getDockPosition() != SWT.NONE) {
388                                                 skin.keyWindow.dock(
389                                                                 skin.keyWindow.getDockPosition(), false, false);
390                                         }
391                                 }
392                         }
393                 };
394
395                 shell.addMouseMoveListener(shellMouseMoveListener);
396
397                 shellMouseListener = new MouseListener() {
398                         @Override
399                         public void mouseUp(MouseEvent e) {
400                                 if (e.button == 1) { /* left button */
401                                         logger.info("mouseUp in Skin");
402
403                                         isGrabbedShell = false;
404                                         grabPosition.x = grabPosition.y = 0;
405
406                                         if (skin.keyWindow != null &&
407                                                         skin.keyWindow.getDockPosition() != SWT.NONE) {
408                                                 skin.keyWindow.dock(
409                                                                 skin.keyWindow.getDockPosition(), false, true);
410                                         }
411                                 }
412                         }
413
414                         @Override
415                         public void mouseDown(MouseEvent e) {
416                                 if (1 == e.button) { /* left button */
417                                         logger.info("mouseDown in Skin");
418
419                                         isGrabbedShell = true;
420                                         grabPosition.x = e.x;
421                                         grabPosition.y = e.y;
422                                 }
423                         }
424
425                         @Override
426                         public void mouseDoubleClick(MouseEvent e) {
427                                 /* do nothing */
428                         }
429                 };
430
431                 shell.addMouseListener(shellMouseListener);
432         }
433
434 //      private void createHWKeyRegion() {
435 //              if (compositeBase != null) {
436 //                      compositeBase.dispose();
437 //                      compositeBase = null;
438 //              }
439 //
440 //              List<KeyMapType> keyMapList =
441 //                              SkinUtil.getHWKeyMapList(currentState.getCurrentRotationId());
442 //
443 //              if (keyMapList != null && keyMapList.isEmpty() == false) {
444 //                      compositeBase = new Composite(shell, SWT.NONE);
445 //                      compositeBase.setLayout(new GridLayout(1, true));
446 //
447 //                      for (KeyMapType keyEntry : keyMapList) {
448 //                              Button hardKeyButton = new Button(compositeBase, SWT.FLAT);
449 //                              hardKeyButton.setText(keyEntry.getEventInfo().getKeyName());
450 //                              hardKeyButton.setToolTipText(keyEntry.getTooltip());
451 //
452 //                              hardKeyButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
453 //
454 //                              final int keycode = keyEntry.getEventInfo().getKeyCode();
455 //                              hardKeyButton.addMouseListener(new MouseListener() {
456 //                                      @Override
457 //                                      public void mouseDown(MouseEvent e) {
458 //                                              KeyEventData keyEventData = new KeyEventData(
459 //                                                              KeyEventType.PRESSED.value(), keycode, 0, 0);
460 //                                              communicator.sendToQEMU(SendCommand.SEND_HARD_KEY_EVENT, keyEventData);
461 //                                      }
462 //
463 //                                      @Override
464 //                                      public void mouseUp(MouseEvent e) {
465 //                                              KeyEventData keyEventData = new KeyEventData(
466 //                                                              KeyEventType.RELEASED.value(), keycode, 0, 0);
467 //                                              communicator.sendToQEMU(SendCommand.SEND_HARD_KEY_EVENT, keyEventData);
468 //                                      }
469 //
470 //                                      @Override
471 //                                      public void mouseDoubleClick(MouseEvent e) {
472 //                                              /* do nothing */
473 //                                      }
474 //                              });
475 //                      }
476 //
477 //                      FormData dataComposite = new FormData();
478 //                      dataComposite.left = new FormAttachment(displayCanvas, 0);
479 //                      dataComposite.top = new FormAttachment(0, 0);
480 //                      compositeBase.setLayoutData(dataComposite);
481 //              }
482 //      }
483
484         @Override
485         public void composerFinalize() {
486                 if (null != shellPaintListener) {
487                         shell.removePaintListener(shellPaintListener);
488                 }
489
490                 if (null != shellMouseMoveListener) {
491                         shell.removeMouseMoveListener(shellMouseMoveListener);
492                 }
493
494                 if (null != shellMouseListener) {
495                         shell.removeMouseListener(shellMouseListener);
496                 }
497
498                 if (toggleButton != null) {
499                         toggleButton.dispose();
500                 }
501
502                 if (skin.pairTagCanvas != null) {
503                         skin.pairTagCanvas.dispose();
504                 }
505
506                 if (backgroundColor != null) {
507                         backgroundColor.dispose();
508                 }
509
510                 frameMaker.freePatches();
511         }
512 }