4 * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
7 * GiWoong Kim <giwoong.kim@samsung.com>
8 * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
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.
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.
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.
29 package org.tizen.emulator.skin.layout;
31 import java.util.logging.Logger;
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;
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";
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;
74 private Logger logger = SkinLogger.getSkinLogger(
75 GeneralPurposeSkinComposer.class).getLogger();
77 private EmulatorConfig config;
78 private EmulatorSkin skin;
80 private Canvas displayCanvas;
81 private Color backgroundColor;
82 private CustomButton toggleButton;
83 private EmulatorSkinState currentState;
85 private ImageRegistry imageRegistry;
86 private SkinPatches frameMaker;
88 private PaintListener shellPaintListener;
89 private MouseMoveListener shellMouseMoveListener;
90 private MouseListener shellMouseListener;
92 private boolean isGrabbedShell;
93 private Point grabPosition;
95 public GeneralPurposeSkinComposer(EmulatorConfig config, EmulatorSkin skin,
96 Shell shell, EmulatorSkinState currentState,
97 ImageRegistry imageRegistry) {
101 this.currentState = currentState;
102 this.imageRegistry = imageRegistry;
103 this.isGrabbedShell= false;
104 this.grabPosition = new Point(0, 0);
106 this.frameMaker = new SkinPatches(PATCH_IMAGES_PATH);
107 this.backgroundColor = new Color(shell.getDisplay(), new RGB(38, 38, 38));
111 public Canvas compose(int style) {
112 displayCanvas = new Canvas(shell, style);
114 int vmIndex = config.getArgInt(ArgsConstants.NET_BASE_PORT) % 100;
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);
121 currentState.setCurrentResolutionWidth(
122 config.getArgInt(ArgsConstants.RESOLUTION_WIDTH));
123 currentState.setCurrentResolutionHeight(
124 config.getArgInt(ArgsConstants.RESOLUTION_HEIGHT));
126 int scale = SkinUtil.getValidScale(config);
127 short rotationId = EmulatorConfig.DEFAULT_WINDOW_ROTATION;
129 composeInternal(displayCanvas, x, y, scale, rotationId);
130 logger.info("resolution : " + currentState.getCurrentResolution() +
131 ", scale : " + scale);
133 return displayCanvas;
137 public void composeInternal(Canvas displayCanvas,
138 final int x, final int y, int scale, short rotationId) {
140 //shell.setBackground(shell.getDisplay().getSystemColor(SWT.COLOR_BLACK));
141 shell.setLocation(x, y);
143 String emulatorName = SkinUtil.makeEmulatorName(config);
144 shell.setText(emulatorName);
146 displayCanvas.setBackground(
147 shell.getDisplay().getSystemColor(SWT.COLOR_BLACK));
149 if (SwtUtil.isWindowsPlatform()) {
150 shell.setImage(imageRegistry.getIcon(IconName.EMULATOR_TITLE_ICO));
152 shell.setImage(imageRegistry.getIcon(IconName.EMULATOR_TITLE));
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));
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);
169 toggleButton.addMouseListener(new MouseListener() {
171 public void mouseDown(MouseEvent e) {
172 if (skin.isSelectKeyWindow() == true) {
173 skin.closeKeyWindow();
174 skin.recentlyDocked = SWT.RIGHT | SWT.CENTER;
176 skin.openKeyWindow(SWT.RIGHT | SWT.CENTER, true);
181 public void mouseUp(MouseEvent e) {
186 public void mouseDoubleClick(MouseEvent e) {
191 /* make a pair tag circle */
192 skin.pairTagCanvas = new Canvas(shell, SWT.NO_FOCUS);
193 skin.pairTagCanvas.setBackground(backgroundColor);
195 skin.pairTagCanvas.addPaintListener(new PaintListener() {
197 public void paintControl(PaintEvent e) {
198 if (skin.colorPairTag != null) {
199 e.gc.setBackground(skin.colorPairTag);
200 e.gc.setAntialias(SWT.ON);
202 0, 0, PAIR_TAG_POSITION_WIDTH, PAIR_TAG_POSITION_HEIGHT);
206 skin.pairTagCanvas.setVisible(false);
208 /* create a progress bar for booting status */
209 skin.bootingProgress = new CustomProgressBar(shell, SWT.NONE);
210 skin.bootingProgress.setBackground(backgroundColor);
212 arrangeSkin(scale, rotationId);
214 /* open the key window */
215 shell.getDisplay().asyncExec(new Runnable() {
218 skin.openKeyWindow(SWT.RIGHT | SWT.CENTER, false);
224 public void arrangeSkin(int scale, short rotationId) {
225 currentState.setCurrentScale(scale);
226 currentState.setCurrentRotationId(rotationId);
227 currentState.setCurrentAngle(SkinRotation.getAngle(rotationId));
229 /* arrange the display */
230 Rectangle displayBounds = adjustLcdGeometry(displayCanvas,
231 currentState.getCurrentResolutionWidth(),
232 currentState.getCurrentResolutionHeight(), scale, rotationId);
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);
242 logger.info("display bounds : " + displayBounds);
244 currentState.setDisplayBounds(displayBounds);
245 displayCanvas.setBounds(displayBounds);
247 /* arrange the skin image */
248 Image tempImage = null;
250 if (currentState.getCurrentImage() != null) {
251 tempImage = currentState.getCurrentImage();
254 currentState.setCurrentImage(
255 frameMaker.getPatchedImage(displayBounds.width, displayBounds.height));
257 if (tempImage != null) {
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);
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);
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);
277 /* set window size */
278 if (currentState.getCurrentImage() != null) {
279 ImageData imageData = currentState.getCurrentImage().getImageData();
280 shell.setMinimumSize(imageData.width, imageData.height);
285 if (currentState.getCurrentImage() != null) {
286 ImageData imageData = currentState.getCurrentImage().getImageData();
287 shell.setSize(imageData.width, imageData.height);
290 /* custom window shape */
291 trimPatchedShell(shell, currentState.getCurrentImage());
297 public Rectangle adjustLcdGeometry(
298 Canvas displayCanvas, int resolutionW, int resolutionH,
299 int scale, short rotationId) {
301 Rectangle lcdBounds = new Rectangle(
302 frameMaker.getPatchWidth(), frameMaker.getPatchHeight(), 0, 0);
304 float convertedScale = SkinUtil.convertScale(scale);
305 RotationInfo rotation = RotationInfo.getValue(rotationId);
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);
313 lcdBounds.width = (int)(resolutionW * convertedScale);
314 lcdBounds.height = (int)(resolutionH * convertedScale);
320 public static void trimPatchedShell(Shell shell, Image image) {
324 ImageData imageData = image.getImageData();
326 int width = imageData.width;
327 int height = imageData.height;
329 Region region = new Region();
330 region.add(new Rectangle(0, 0, width, height));
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();
337 if (SwtUtil.isWindowsPlatform()) {
338 colorKey = r << 24 | g << 16 | b << 8;
340 colorKey = r << 16 | g << 8 | b;
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);
352 shell.setRegion(region);
355 public void addGeneralPurposeListener(final Shell shell) {
356 shellPaintListener = new PaintListener() {
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);
365 if (skin.keyWindow != null &&
366 skin.keyWindow.getDockPosition() != SWT.NONE) {
368 skin.keyWindow.getDockPosition(), false, false);
373 shell.addPaintListener(shellPaintListener);
375 shellMouseMoveListener = new MouseMoveListener() {
377 public void mouseMove(MouseEvent e) {
378 if (isGrabbedShell == true && e.button == 0/* left button */) {
380 Point previousLocation = shell.getLocation();
381 int x = previousLocation.x + (e.x - grabPosition.x);
382 int y = previousLocation.y + (e.y - grabPosition.y);
384 shell.setLocation(x, y);
386 if (skin.keyWindow != null &&
387 skin.keyWindow.getDockPosition() != SWT.NONE) {
389 skin.keyWindow.getDockPosition(), false, false);
395 shell.addMouseMoveListener(shellMouseMoveListener);
397 shellMouseListener = new MouseListener() {
399 public void mouseUp(MouseEvent e) {
400 if (e.button == 1) { /* left button */
401 logger.info("mouseUp in Skin");
403 isGrabbedShell = false;
404 grabPosition.x = grabPosition.y = 0;
406 if (skin.keyWindow != null &&
407 skin.keyWindow.getDockPosition() != SWT.NONE) {
409 skin.keyWindow.getDockPosition(), false, true);
415 public void mouseDown(MouseEvent e) {
416 if (1 == e.button) { /* left button */
417 logger.info("mouseDown in Skin");
419 isGrabbedShell = true;
420 grabPosition.x = e.x;
421 grabPosition.y = e.y;
426 public void mouseDoubleClick(MouseEvent e) {
431 shell.addMouseListener(shellMouseListener);
434 // private void createHWKeyRegion() {
435 // if (compositeBase != null) {
436 // compositeBase.dispose();
437 // compositeBase = null;
440 // List<KeyMapType> keyMapList =
441 // SkinUtil.getHWKeyMapList(currentState.getCurrentRotationId());
443 // if (keyMapList != null && keyMapList.isEmpty() == false) {
444 // compositeBase = new Composite(shell, SWT.NONE);
445 // compositeBase.setLayout(new GridLayout(1, true));
447 // for (KeyMapType keyEntry : keyMapList) {
448 // Button hardKeyButton = new Button(compositeBase, SWT.FLAT);
449 // hardKeyButton.setText(keyEntry.getEventInfo().getKeyName());
450 // hardKeyButton.setToolTipText(keyEntry.getTooltip());
452 // hardKeyButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
454 // final int keycode = keyEntry.getEventInfo().getKeyCode();
455 // hardKeyButton.addMouseListener(new MouseListener() {
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);
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);
471 // public void mouseDoubleClick(MouseEvent e) {
477 // FormData dataComposite = new FormData();
478 // dataComposite.left = new FormAttachment(displayCanvas, 0);
479 // dataComposite.top = new FormAttachment(0, 0);
480 // compositeBase.setLayoutData(dataComposite);
485 public void composerFinalize() {
486 if (null != shellPaintListener) {
487 shell.removePaintListener(shellPaintListener);
490 if (null != shellMouseMoveListener) {
491 shell.removeMouseMoveListener(shellMouseMoveListener);
494 if (null != shellMouseListener) {
495 shell.removeMouseListener(shellMouseListener);
498 if (toggleButton != null) {
499 toggleButton.dispose();
502 if (skin.pairTagCanvas != null) {
503 skin.pairTagCanvas.dispose();
506 if (backgroundColor != null) {
507 backgroundColor.dispose();
510 frameMaker.freePatches();