4 * Copyright (C) 2011 - 2013 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.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;
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";
70 private static final int PAIR_TAG_POSITION_X = 26;
71 private static final int PAIR_TAG_POSITION_Y = 13;
73 private Logger logger = SkinLogger.getSkinLogger(
74 GeneralPurposeSkinComposer.class).getLogger();
76 private EmulatorConfig config;
77 private EmulatorSkin skin;
79 private Canvas displayCanvas;
80 private Color backgroundColor;
81 private CustomButton toggleButton;
82 private EmulatorSkinState currentState;
84 private ImageRegistry imageRegistry;
85 private SkinPatches frameMaker;
87 private PaintListener shellPaintListener;
88 private MouseMoveListener shellMouseMoveListener;
89 private MouseListener shellMouseListener;
91 private boolean isGrabbedShell;
92 private Point grabPosition;
94 public GeneralPurposeSkinComposer(EmulatorConfig config, EmulatorSkin skin,
95 Shell shell, EmulatorSkinState currentState,
96 ImageRegistry imageRegistry) {
100 this.currentState = currentState;
101 this.imageRegistry = imageRegistry;
102 this.isGrabbedShell= false;
103 this.grabPosition = new Point(0, 0);
105 this.frameMaker = new SkinPatches(PATCH_IMAGES_PATH);
106 this.backgroundColor = new Color(shell.getDisplay(), new RGB(38, 38, 38));
110 public Canvas compose(int style) {
111 shell.setBackground(backgroundColor);
113 displayCanvas = new Canvas(shell, style);
115 int vmIndex = config.getArgInt(ArgsConstants.NET_BASE_PORT) % 100;
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);
122 currentState.setCurrentResolutionWidth(
123 config.getArgInt(ArgsConstants.RESOLUTION_WIDTH));
124 currentState.setCurrentResolutionHeight(
125 config.getArgInt(ArgsConstants.RESOLUTION_HEIGHT));
127 int scale = SkinUtil.getValidScale(config);
128 short rotationId = EmulatorConfig.DEFAULT_WINDOW_ROTATION;
130 composeInternal(displayCanvas, x, y, scale, rotationId);
131 logger.info("resolution : " + currentState.getCurrentResolution() +
132 ", scale : " + scale);
134 return displayCanvas;
138 public void composeInternal(Canvas displayCanvas,
139 final int x, final int y, int scale, short rotationId) {
141 //shell.setBackground(shell.getDisplay().getSystemColor(SWT.COLOR_BLACK));
142 shell.setLocation(x, y);
144 String emulatorName = SkinUtil.makeEmulatorName(config);
145 shell.setText("Emulator - " + emulatorName);
147 displayCanvas.setBackground(
148 shell.getDisplay().getSystemColor(SWT.COLOR_BLACK));
150 if (SwtUtil.isWindowsPlatform()) {
151 shell.setImage(imageRegistry.getIcon(IconName.EMULATOR_TITLE_ICO));
153 shell.setImage(imageRegistry.getIcon(IconName.EMULATOR_TITLE));
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));
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);
170 toggleButton.addMouseListener(new MouseListener() {
172 public void mouseDown(MouseEvent e) {
173 if (skin.isSelectKeyWindow() == true) {
174 skin.closeKeyWindow();
175 skin.recentlyDocked = SWT.RIGHT | SWT.CENTER;
177 skin.openKeyWindow(SWT.RIGHT | SWT.CENTER, true);
182 public void mouseUp(MouseEvent e) {
187 public void mouseDoubleClick(MouseEvent e) {
192 /* make a pair tag circle */
194 new ColorTag(shell, SWT.NO_FOCUS, skin.getColorVM());
195 skin.pairTag.setVisible(false);
197 /* create a progress bar for booting status */
198 skin.bootingProgress = new CustomProgressBar(shell, SWT.NONE);
199 skin.bootingProgress.setBackground(backgroundColor);
201 arrangeSkin(scale, rotationId);
203 /* open the key window */
204 shell.getDisplay().asyncExec(new Runnable() {
207 skin.openKeyWindow(SWT.RIGHT | SWT.CENTER, false);
213 public void arrangeSkin(int scale, short rotationId) {
214 currentState.setCurrentScale(scale);
215 currentState.setCurrentRotationId(rotationId);
216 currentState.setCurrentAngle(SkinRotation.getAngle(rotationId));
218 /* arrange the display */
219 Rectangle displayBounds = adjustLcdGeometry(displayCanvas,
220 currentState.getCurrentResolutionWidth(),
221 currentState.getCurrentResolutionHeight(), scale, rotationId);
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);
231 logger.info("display bounds : " + displayBounds);
233 currentState.setDisplayBounds(displayBounds);
234 displayCanvas.setBounds(displayBounds);
236 /* arrange the skin image */
237 Image tempImage = null;
239 if (currentState.getCurrentImage() != null) {
240 tempImage = currentState.getCurrentImage();
243 currentState.setCurrentImage(
244 frameMaker.getPatchedImage(displayBounds.width, displayBounds.height));
246 if (tempImage != null) {
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);
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);
261 /* set window size */
262 if (currentState.getCurrentImage() != null) {
263 ImageData imageData = currentState.getCurrentImage().getImageData();
264 shell.setMinimumSize(imageData.width, imageData.height);
269 if (currentState.getCurrentImage() != null) {
270 ImageData imageData = currentState.getCurrentImage().getImageData();
271 shell.setSize(imageData.width, imageData.height);
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(
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(),
294 skin.pairTag.getWidth(), skin.pairTag.getHeight());
297 /* custom window shape */
298 trimPatchedShell(shell, currentState.getCurrentImage());
304 public Rectangle adjustLcdGeometry(
305 Canvas displayCanvas, int resolutionW, int resolutionH,
306 int scale, short rotationId) {
308 Rectangle lcdBounds = new Rectangle(
309 frameMaker.getPatchWidth(), frameMaker.getPatchHeight(), 0, 0);
311 float convertedScale = SkinUtil.convertScale(scale);
312 RotationInfo rotation = RotationInfo.getValue(rotationId);
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);
320 lcdBounds.width = (int)(resolutionW * convertedScale);
321 lcdBounds.height = (int)(resolutionH * convertedScale);
327 public static void trimPatchedShell(Shell shell, Image image) {
331 ImageData imageData = image.getImageData();
333 int width = imageData.width;
334 int height = imageData.height;
336 Region region = new Region();
337 region.add(new Rectangle(0, 0, width, height));
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();
344 if (SwtUtil.isWindowsPlatform()) {
345 colorKey = r << 24 | g << 16 | b << 8;
347 colorKey = r << 16 | g << 8 | b;
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);
359 shell.setRegion(region);
362 public void addGeneralPurposeListener(final Shell shell) {
363 shellPaintListener = new PaintListener() {
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);
372 if (skin.keyWindow != null &&
373 skin.keyWindow.getDockPosition() != SWT.NONE) {
375 skin.keyWindow.getDockPosition(), false, false);
380 shell.addPaintListener(shellPaintListener);
382 shellMouseMoveListener = new MouseMoveListener() {
384 public void mouseMove(MouseEvent e) {
385 if (isGrabbedShell == true && e.button == 0/* left button */) {
387 Point previousLocation = shell.getLocation();
388 int x = previousLocation.x + (e.x - grabPosition.x);
389 int y = previousLocation.y + (e.y - grabPosition.y);
391 shell.setLocation(x, y);
393 if (skin.keyWindow != null &&
394 skin.keyWindow.getDockPosition() != SWT.NONE) {
396 skin.keyWindow.getDockPosition(), false, false);
402 shell.addMouseMoveListener(shellMouseMoveListener);
404 shellMouseListener = new MouseListener() {
406 public void mouseUp(MouseEvent e) {
407 if (e.button == 1) { /* left button */
408 logger.info("mouseUp in Skin");
410 isGrabbedShell = false;
411 grabPosition.x = grabPosition.y = 0;
413 if (skin.keyWindow != null &&
414 skin.keyWindow.getDockPosition() != SWT.NONE) {
416 skin.keyWindow.getDockPosition(), false, true);
422 public void mouseDown(MouseEvent e) {
423 if (1 == e.button) { /* left button */
424 logger.info("mouseDown in Skin");
426 isGrabbedShell = true;
427 grabPosition.x = e.x;
428 grabPosition.y = e.y;
433 public void mouseDoubleClick(MouseEvent e) {
438 shell.addMouseListener(shellMouseListener);
441 // private void createHWKeyRegion() {
442 // if (compositeBase != null) {
443 // compositeBase.dispose();
444 // compositeBase = null;
447 // List<KeyMapType> keyMapList =
448 // SkinUtil.getHWKeyMapList(currentState.getCurrentRotationId());
450 // if (keyMapList != null && keyMapList.isEmpty() == false) {
451 // compositeBase = new Composite(shell, SWT.NONE);
452 // compositeBase.setLayout(new GridLayout(1, true));
454 // for (KeyMapType keyEntry : keyMapList) {
455 // Button hardKeyButton = new Button(compositeBase, SWT.FLAT);
456 // hardKeyButton.setText(keyEntry.getEventInfo().getKeyName());
457 // hardKeyButton.setToolTipText(keyEntry.getTooltip());
459 // hardKeyButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
461 // final int keycode = keyEntry.getEventInfo().getKeyCode();
462 // hardKeyButton.addMouseListener(new MouseListener() {
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);
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);
478 // public void mouseDoubleClick(MouseEvent e) {
484 // FormData dataComposite = new FormData();
485 // dataComposite.left = new FormAttachment(displayCanvas, 0);
486 // dataComposite.top = new FormAttachment(0, 0);
487 // compositeBase.setLayoutData(dataComposite);
492 public void composerFinalize() {
493 if (null != shellPaintListener) {
494 shell.removePaintListener(shellPaintListener);
497 if (null != shellMouseMoveListener) {
498 shell.removeMouseMoveListener(shellMouseMoveListener);
501 if (null != shellMouseListener) {
502 shell.removeMouseListener(shellMouseListener);
505 if (toggleButton != null) {
506 toggleButton.dispose();
509 if (skin.pairTag != null) {
510 skin.pairTag.dispose();
513 if (backgroundColor != null) {
514 backgroundColor.dispose();
517 frameMaker.freePatches();