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.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;
71 public class PhoneShapeSkinComposer implements ISkinComposer {
72 private Logger logger = SkinLogger.getSkinLogger(
73 PhoneShapeSkinComposer.class).getLogger();
75 private EmulatorConfig config;
76 private EmulatorSkin skin;
78 private Canvas lcdCanvas;
79 private EmulatorSkinState currentState;
80 private ImageRegistry imageRegistry;
81 private SocketCommunicator communicator;
83 private PaintListener shellPaintListener;
84 private MouseTrackListener shellMouseTrackListener;
85 private MouseMoveListener shellMouseMoveListener;
86 private MouseListener shellMouseListener;
88 private boolean isGrabbedShell;
89 private Point grabPosition;
91 public PhoneShapeSkinComposer(EmulatorConfig config, EmulatorSkin skin,
92 Shell shell, EmulatorSkinState currentState,
93 ImageRegistry imageRegistry, SocketCommunicator communicator) {
97 this.currentState = currentState;
98 this.imageRegistry = imageRegistry;
99 this.communicator = communicator;
100 this.isGrabbedShell= false;
101 this.grabPosition = new Point(0, 0);
105 public Canvas compose(int style) {
106 lcdCanvas = new Canvas(shell, style);
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);
113 currentState.setCurrentResolutionWidth(
114 config.getArgInt(ArgsConstants.RESOLUTION_WIDTH));
115 currentState.setCurrentResolutionHeight(
116 config.getArgInt(ArgsConstants.RESOLUTION_HEIGHT));
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;
124 composeInternal(lcdCanvas, x, y, scale, rotationId);
125 logger.info("resolution : " + currentState.getCurrentResolution() +
126 ", scale : " + scale);
132 public void composeInternal(Canvas lcdCanvas,
133 int x, int y, int scale, short rotationId) {
135 //shell.setBackground(shell.getDisplay().getSystemColor(SWT.COLOR_BLACK));
136 shell.setLocation(x, y);
138 String emulatorName = SkinUtil.makeEmulatorName(config);
139 shell.setText("Emulator - " + emulatorName);
141 lcdCanvas.setBackground(shell.getDisplay().getSystemColor(SWT.COLOR_BLACK));
143 if (SwtUtil.isWindowsPlatform()) {
144 shell.setImage(imageRegistry.getIcon(IconName.EMULATOR_TITLE_ICO));
146 shell.setImage(imageRegistry.getIcon(IconName.EMULATOR_TITLE));
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)));
154 arrangeSkin(scale, rotationId);
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);
165 public void arrangeSkin(int scale, short rotationId) {
166 currentState.setCurrentScale(scale);
167 currentState.setCurrentRotationId(rotationId);
168 currentState.setCurrentAngle(SkinRotation.getAngle(rotationId));
170 /* arrange the display */
171 Rectangle lcdBounds = adjustLcdGeometry(lcdCanvas,
172 currentState.getCurrentResolutionWidth(),
173 currentState.getCurrentResolutionHeight(), scale, rotationId);
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);
183 logger.info("lcd bounds : " + lcdBounds);
185 currentState.setDisplayBounds(lcdBounds);
186 currentState.setUpdateDisplayBounds(true);
187 //lcdCanvas.setBounds(lcdBounds);
189 /* arrange the skin image */
190 Image tempImage = null;
191 Image tempKeyPressedImage = null;
193 if (currentState.getCurrentImage() != null) {
194 tempImage = currentState.getCurrentImage();
196 if (currentState.getCurrentKeyPressedImage() != null) {
197 tempKeyPressedImage = currentState.getCurrentKeyPressedImage();
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));
205 if (tempImage != null) {
208 if (tempKeyPressedImage != null) {
209 tempKeyPressedImage.dispose();
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);
218 /* set window size */
219 if (currentState.getCurrentImage() != null) {
220 ImageData imageData = currentState.getCurrentImage().getImageData();
221 shell.setMinimumSize(imageData.width, imageData.height);
226 /* set window size */
227 if (currentState.getCurrentImage() != null) {
228 ImageData imageData = currentState.getCurrentImage().getImageData();
229 shell.setSize(imageData.width, imageData.height);
232 /* custom window shape */
233 SkinUtil.trimShell(shell, currentState.getCurrentImage());
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);
244 float convertedScale = SkinUtil.convertScale(scale);
245 RotationType rotation = SkinRotation.getRotation(rotationId);
247 LcdType lcd = rotation.getLcd(); /* from dbi */
252 RegionType region = lcd.getRegion();
253 if (region == null) {
257 Integer left = region.getLeft();
258 Integer top = region.getTop();
259 Integer width = region.getWidth();
260 Integer height = region.getHeight();
262 lcdBounds.x = (int) (left * convertedScale);
263 lcdBounds.y = (int) (top * convertedScale);
264 lcdBounds.width = (int) (width * convertedScale);
265 lcdBounds.height = (int) (height * convertedScale);
270 public void addPhoneShapeListener(final Shell shell) {
271 shellPaintListener = new PaintListener() {
273 public void paintControl(final PaintEvent e) {
274 if (currentState.isUpdateDisplayBounds() == true) {
275 currentState.setUpdateDisplayBounds(false);
276 lcdCanvas.setBounds(currentState.getDisplayBounds());
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);
288 shell.addPaintListener(shellPaintListener);
290 shellMouseTrackListener = new MouseTrackAdapter() {
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();
297 if (hoveredHWKey != null) {
298 shell.redraw(hoveredHWKey.getRegion().x,
299 hoveredHWKey.getRegion().y,
300 hoveredHWKey.getRegion().width,
301 hoveredHWKey.getRegion().height, false);
303 currentState.setCurrentHoveredHWKey(null);
304 shell.setToolTipText(null);
309 shell.addMouseTrackListener(shellMouseTrackListener);
311 shellMouseMoveListener = new MouseMoveListener() {
313 public void mouseMove(MouseEvent e) {
314 if (isGrabbedShell == true && e.button == 0/* left button */ &&
315 currentState.getCurrentPressedHWKey() == null) {
317 Point previousLocation = shell.getLocation();
318 int x = previousLocation.x + (e.x - grabPosition.x);
319 int y = previousLocation.y + (e.y - grabPosition.y);
321 shell.setLocation(x, y);
325 final HWKey hwKey = SkinUtil.getHWKey(e.x, e.y,
326 currentState.getCurrentRotationId(), currentState.getCurrentScale());
329 HWKey hoveredHWKey = currentState.getCurrentHoveredHWKey();
331 if (hoveredHWKey != null) {
332 shell.redraw(hoveredHWKey.getRegion().x,
333 hoveredHWKey.getRegion().y,
334 hoveredHWKey.getRegion().width,
335 hoveredHWKey.getRegion().height, false);
337 currentState.setCurrentHoveredHWKey(null);
338 shell.setToolTipText(null);
344 /* register a tooltip */
345 if (currentState.getCurrentHoveredHWKey() == null &&
346 hwKey.getTooltip().isEmpty() == false) {
347 shell.setToolTipText(hwKey.getTooltip());
351 shell.getDisplay().syncExec(new Runnable() {
353 if (hwKey.getRegion().width != 0 && hwKey.getRegion().height != 0) {
354 GC gc = new GC(shell);
357 gc.setForeground(currentState.getHoverColor());
358 gc.drawRectangle(hwKey.getRegion().x, hwKey.getRegion().y,
359 hwKey.getRegion().width - 1, hwKey.getRegion().height - 1);
363 currentState.setCurrentHoveredHWKey(hwKey);
372 shell.addMouseMoveListener(shellMouseMoveListener);
374 shellMouseListener = new MouseListener() {
376 public void mouseUp(MouseEvent e) {
377 if (e.button == 1) { /* left button */
378 logger.info("mouseUp in Skin");
380 isGrabbedShell = false;
381 grabPosition.x = grabPosition.y = 0;
383 HWKey pressedHWKey = currentState.getCurrentPressedHWKey();
384 if (pressedHWKey == null) {
388 if (pressedHWKey.getKeyCode() != SkinUtil.UNKNOWN_KEYCODE) {
390 KeyEventData keyEventData = new KeyEventData(
391 KeyEventType.RELEASED.value(), pressedHWKey.getKeyCode(), 0, 0);
392 communicator.sendToQEMU(SendCommand.SEND_HARD_KEY_EVENT, keyEventData);
394 currentState.setCurrentPressedHWKey(null);
396 /* roll back a keyPressed image region */
397 shell.redraw(pressedHWKey.getRegion().x, pressedHWKey.getRegion().y,
398 pressedHWKey.getRegion().width, pressedHWKey.getRegion().height, false);
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);
410 public void mouseDown(MouseEvent e) {
411 if (1 == e.button) { /* left button */
412 logger.info("mouseDown in Skin");
414 isGrabbedShell = true;
415 grabPosition.x = e.x;
416 grabPosition.y = e.y;
418 final HWKey hwKey = SkinUtil.getHWKey(e.x, e.y,
419 currentState.getCurrentRotationId(), currentState.getCurrentScale());
424 if (hwKey.getKeyCode() != SkinUtil.UNKNOWN_KEYCODE) {
426 KeyEventData keyEventData = new KeyEventData(
427 KeyEventType.PRESSED.value(), hwKey.getKeyCode(), 0, 0);
428 communicator.sendToQEMU(SendCommand.SEND_HARD_KEY_EVENT, keyEventData);
430 currentState.setCurrentPressedHWKey(hwKey);
432 shell.setToolTipText(null);
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() {
439 if (currentState.getCurrentKeyPressedImage() != null) {
440 GC gc = new GC(shell);
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
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);
467 public void mouseDoubleClick(MouseEvent e) {
472 shell.addMouseListener(shellMouseListener);
476 public void composerFinalize() {
477 if (null != shellPaintListener) {
478 shell.removePaintListener(shellPaintListener);
481 if (null != shellMouseTrackListener) {
482 shell.removeMouseTrackListener(shellMouseTrackListener);
485 if (null != shellMouseMoveListener) {
486 shell.removeMouseMoveListener(shellMouseMoveListener);
489 if (null != shellMouseListener) {
490 shell.removeMouseListener(shellMouseListener);