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