update source for tizen_2.1
[sdk/emulator/qemu.git] / tizen / src / skin / client / src / org / tizen / emulator / skin / custom / KeyWindow.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.custom;
30
31 import java.util.List;
32
33 import org.eclipse.swt.SWT;
34 import org.eclipse.swt.custom.ScrolledComposite;
35 import org.eclipse.swt.events.MouseEvent;
36 import org.eclipse.swt.events.MouseListener;
37 import org.eclipse.swt.events.MouseMoveListener;
38 import org.eclipse.swt.events.PaintEvent;
39 import org.eclipse.swt.events.PaintListener;
40 import org.eclipse.swt.events.ShellEvent;
41 import org.eclipse.swt.events.ShellListener;
42 import org.eclipse.swt.graphics.Color;
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.graphics.Region;
49 import org.eclipse.swt.layout.GridData;
50 import org.eclipse.swt.layout.GridLayout;
51 import org.eclipse.swt.widgets.Composite;
52 import org.eclipse.swt.widgets.Display;
53 import org.eclipse.swt.widgets.Shell;
54 import org.tizen.emulator.skin.EmulatorSkin;
55 import org.tizen.emulator.skin.comm.ICommunicator.KeyEventType;
56 import org.tizen.emulator.skin.comm.ICommunicator.SendCommand;
57 import org.tizen.emulator.skin.comm.sock.SocketCommunicator;
58 import org.tizen.emulator.skin.comm.sock.data.KeyEventData;
59 import org.tizen.emulator.skin.dbi.KeyMapType;
60 import org.tizen.emulator.skin.image.ImageRegistry.KeyWindowImageName;
61 import org.tizen.emulator.skin.layout.SkinPatches;
62 import org.tizen.emulator.skin.util.SwtUtil;
63
64 public class KeyWindow extends SkinWindow {
65         private static final String PATCH_IMAGES_PATH = "images/key-window/";
66         private static final int SHELL_MARGIN_BOTTOM = 3;
67         private static final int PAIRTAG_CIRCLE_SIZE = 8;
68         private static final int PAIRTAG_MARGIN_BOTTOM = 6;
69         private static final int BUTTON_DEFAULT_CNT = 4;
70         private static final int BUTTON_VERTICAL_SPACING = 7;
71         private static final int SCROLLBAR_HORIZONTAL_SPACING = 4;
72         private static final int SCROLLBAR_SIZE_WIDTH = 14;
73
74         private EmulatorSkin skin;
75         private SkinPatches frameMaker;
76
77         private int widthBase;
78         private int heightBase;
79         private int widthScrollbar;
80         private int cntHiddenButton;
81
82         private Image imageNormal; /* ImageButton image */
83         private Image imageHover; /* hovered ImageButton image */
84         private Image imagePushed; /* pushed ImageButton image */
85         private Image imageFrame; /* nine-patch image */
86
87         private Color colorFrame;
88         private SocketCommunicator communicator;
89         private List<KeyMapType> keyMapList;
90
91         private ShellListener shellListener;
92         private PaintListener shellPaintListener;
93         private MouseMoveListener shellMouseMoveListener;
94         private MouseListener shellMouseListener;
95
96         private boolean isGrabbedShell;
97         private Point grabPosition;
98
99         public KeyWindow(EmulatorSkin skin, Shell parent,
100                         SocketCommunicator communicator, List<KeyMapType> keyMapList) {
101                 super(parent, SWT.RIGHT | SWT.CENTER);
102
103                 this.skin = skin;
104                 this.shell = new Shell(Display.getDefault(),
105                                 SWT.NO_TRIM | SWT.RESIZE | SWT.TOOL);
106                 this.frameMaker = new SkinPatches(PATCH_IMAGES_PATH);
107
108                 this.keyMapList = keyMapList; //TODO: null
109                 this.communicator = communicator;
110                 this.grabPosition = new Point(0, 0);
111
112                 shell.setText(parent.getText());
113                 shell.setImage(parent.getImage());
114
115                 /* load image for HW key button */
116                 imageNormal = skin.getImageRegistry().getKeyWindowImageData(
117                                 KeyWindowImageName.KEYBUTTON_NORMAL);
118                 imageHover = skin.getImageRegistry().getKeyWindowImageData(
119                                 KeyWindowImageName.KEYBUTTON_HOVER);
120                 imagePushed = skin.getImageRegistry().getKeyWindowImageData(
121                                 KeyWindowImageName.KEYBUTTON_PUSHED);
122
123                 /* calculate the key window size */
124                 widthBase = imageNormal.getImageData().width;
125                 heightBase = (imageNormal.getImageData().height * BUTTON_DEFAULT_CNT) +
126                                 (BUTTON_VERTICAL_SPACING * (BUTTON_DEFAULT_CNT - 1));
127
128                 widthScrollbar = SCROLLBAR_SIZE_WIDTH + SCROLLBAR_HORIZONTAL_SPACING;
129                 int heightHeaderPart = (PAIRTAG_CIRCLE_SIZE + PAIRTAG_MARGIN_BOTTOM);
130                 int heightTailPart = SHELL_MARGIN_BOTTOM;
131
132                 /* make a frame image */
133                 this.cntHiddenButton = 0; //keyMapList.size() - BUTTON_DEFAULT_CNT;
134
135                 this.imageFrame = frameMaker.getPatchedImage(
136                                 widthBase + ((cntHiddenButton > 0) ? widthScrollbar : 0),
137                                 heightBase + heightHeaderPart + heightTailPart);
138                 this.colorFrame = new Color(shell.getDisplay(), new RGB(38, 38, 38));
139
140                 shell.setBackground(colorFrame);
141
142                 createContents();
143                 trimPatchedShell(shell, imageFrame);
144
145                 addKeyWindowListener();
146
147                 shell.setSize(imageFrame.getImageData().width,
148                                 imageFrame.getImageData().height);
149         }
150
151         protected void createContents() {
152                 GridLayout shellGridLayout = new GridLayout(1, false);
153                 shellGridLayout.marginLeft = shellGridLayout.marginRight = frameMaker.getPatchWidth();
154                 shellGridLayout.marginTop = frameMaker.getPatchHeight();
155                 shellGridLayout.marginBottom = frameMaker.getPatchHeight() + SHELL_MARGIN_BOTTOM;
156                 shellGridLayout.marginWidth = shellGridLayout.marginHeight = 0;
157                 shellGridLayout.horizontalSpacing = shellGridLayout.verticalSpacing = 0;
158
159                 shell.setLayout(shellGridLayout);
160
161                 /* make a pair tag circle */
162                 ColorTag pairTagCanvas = new ColorTag(shell, SWT.NONE, skin.getColorVM());
163                 pairTagCanvas.setLayoutData(new GridData(PAIRTAG_CIRCLE_SIZE,
164                                 PAIRTAG_CIRCLE_SIZE + PAIRTAG_MARGIN_BOTTOM));
165
166                 /* make a region of HW keys */
167                 if (cntHiddenButton > 0) {
168                         /* added custom scrollbar */
169
170                         Image imagesScrollArrowUp[] = new Image[3];
171                         Image imagesScrollArrowDown[] = new Image[3];
172
173                         imagesScrollArrowUp[0] = skin.getImageRegistry().getKeyWindowImageData(
174                                         KeyWindowImageName.SCROLL_UPBUTTON_NORMAL);
175                         imagesScrollArrowUp[1] = skin.getImageRegistry().getKeyWindowImageData(
176                                         KeyWindowImageName.SCROLL_UPBUTTON_HOVER);
177                         imagesScrollArrowUp[2] = skin.getImageRegistry().getKeyWindowImageData(
178                                         KeyWindowImageName.SCROLL_UPBUTTON_PUSHED);
179
180                         imagesScrollArrowDown[0] = skin.getImageRegistry().getKeyWindowImageData(
181                                         KeyWindowImageName.SCROLL_DOWNBUTTON_NORMAL);
182                         imagesScrollArrowDown[1] = skin.getImageRegistry().getKeyWindowImageData(
183                                         KeyWindowImageName.SCROLL_DOWNBUTTON_HOVER);
184                         imagesScrollArrowDown[2] = skin.getImageRegistry().getKeyWindowImageData(
185                                         KeyWindowImageName.SCROLL_DOWNBUTTON_PUSHED);
186
187                         CustomScrolledComposite compositeScroll =
188                                         new CustomScrolledComposite(shell, SWT.NONE,
189                                                         imagesScrollArrowUp, imagesScrollArrowDown,
190                                                         skin.getImageRegistry().getKeyWindowImageData(
191                                                                         KeyWindowImageName.SCROLL_THUMB),
192                                                         skin.getImageRegistry().getKeyWindowImageData(
193                                                                         KeyWindowImageName.SCROLL_SHAFT));
194                         compositeScroll.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, true, 1, 1));
195
196                         Composite compositeBase = new Composite(compositeScroll, SWT.NONE);
197
198                         createHwKeys(compositeBase);
199
200                         Point sizeContent = compositeBase.computeSize(
201                                         widthBase + widthScrollbar, heightBase);
202                         compositeScroll.setContent(compositeBase, sizeContent);
203                         compositeScroll.setExpandHorizontal(true);
204                         compositeScroll.setExpandVertical(true);
205
206                         sizeContent.y += (imageNormal.getImageData().height * cntHiddenButton) +
207                                         (BUTTON_VERTICAL_SPACING * cntHiddenButton);
208                         compositeScroll.setMinSize(sizeContent);
209                 } else {
210                         ScrolledComposite compositeScroll = new ScrolledComposite(shell, SWT.V_SCROLL);
211                         compositeScroll.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, true, 1, 1));
212
213                         Composite compositeBase = new Composite(compositeScroll, SWT.NONE);
214                         createHwKeys(compositeBase);
215
216                         compositeScroll.setContent(compositeBase);
217                         compositeScroll.setExpandHorizontal(true);
218                         compositeScroll.setExpandVertical(true);
219                         compositeScroll.setMinSize(compositeBase.computeSize(SWT.DEFAULT, SWT.DEFAULT));
220                 }
221         }
222
223         protected void createHwKeys(Composite composite) {
224                 composite.setBackground(colorFrame);
225
226                 GridLayout compositeGridLayout = new GridLayout(1, false);
227                 compositeGridLayout.marginLeft = compositeGridLayout.marginRight = 0;
228                 compositeGridLayout.marginTop = compositeGridLayout.marginBottom = 0;
229                 compositeGridLayout.marginWidth = compositeGridLayout.marginHeight = 0;
230                 compositeGridLayout.horizontalSpacing = 0;
231                 compositeGridLayout.verticalSpacing = BUTTON_VERTICAL_SPACING;
232                 composite.setLayout(compositeGridLayout);
233
234                 /* attach HW keys */
235                 if (keyMapList != null && keyMapList.isEmpty() == false) {
236                         for (KeyMapType keyEntry : keyMapList) {
237                                 CustomButton HWKeyButton = new CustomButton(composite,
238                                                 SWT.NO_FOCUS, imageNormal, imageHover, imagePushed);
239                                 HWKeyButton.setText(keyEntry.getEventInfo().getKeyName());
240                                 HWKeyButton.setToolTipText(keyEntry.getTooltip());
241                                 HWKeyButton.setBackground(colorFrame);
242                                 HWKeyButton.setLayoutData(new GridData(imageNormal.getImageData().width,
243                                                                 imageNormal.getImageData().height));
244
245                                 final int keycode = keyEntry.getEventInfo().getKeyCode();
246                                 HWKeyButton.addMouseListener(new MouseListener() {
247                                         @Override
248                                         public void mouseDown(MouseEvent e) {
249                                                 KeyEventData keyEventData = new KeyEventData(
250                                                                 KeyEventType.PRESSED.value(), keycode, 0, 0);
251                                                 communicator.sendToQEMU(SendCommand.SEND_HARD_KEY_EVENT, keyEventData);
252                                         }
253
254                                         @Override
255                                         public void mouseUp(MouseEvent e) {
256                                                 KeyEventData keyEventData = new KeyEventData(
257                                                                 KeyEventType.RELEASED.value(), keycode, 0, 0);
258                                                 communicator.sendToQEMU(SendCommand.SEND_HARD_KEY_EVENT, keyEventData);
259                                         }
260
261                                         @Override
262                                         public void mouseDoubleClick(MouseEvent e) {
263                                                 /* do nothing */
264                                         }
265                                 });
266                         }
267                 }
268         }
269
270         public static void trimPatchedShell(Shell shell, Image image) {
271                 if (null == image) {
272                         return;
273                 }
274                 ImageData imageData = image.getImageData();
275
276                 int width = imageData.width;
277                 int height = imageData.height;
278
279                 Region region = new Region();
280                 region.add(new Rectangle(0, 0, width, height));
281
282                 int r = shell.getDisplay().getSystemColor(SWT.COLOR_MAGENTA).getRed();
283                 int g = shell.getDisplay().getSystemColor(SWT.COLOR_MAGENTA).getGreen();
284                 int b = shell.getDisplay().getSystemColor(SWT.COLOR_MAGENTA).getBlue();
285                 int colorKey;
286
287                 if (SwtUtil.isWindowsPlatform()) {
288                         colorKey = r << 24 | g << 16 | b << 8;
289                 } else {
290                         colorKey = r << 16 | g << 8 | b;
291                 }
292
293                 for (int i = 0; i < width; i++) {
294                         for (int j = 0; j < height; j++) {
295                                 int colorPixel = imageData.getPixel(i, j);
296                                 if (colorPixel == colorKey /* magenta */) {
297                                         region.subtract(i, j, 1, 1);
298                                 }
299                         }
300                 }
301
302                 shell.setRegion(region);
303         }
304
305         private void addKeyWindowListener() {
306                 shellPaintListener = new PaintListener() {
307                         @Override
308                         public void paintControl(final PaintEvent e) {
309                                 if (imageFrame != null) {
310                                         e.gc.drawImage(imageFrame, 0, 0);
311                                 }
312                         }
313                 };
314
315                 shell.addPaintListener(shellPaintListener);
316
317                 shellListener = new ShellListener() {
318                         @Override
319                         public void shellClosed(ShellEvent event) {
320                                 logger.info("Key Window is closed");
321
322                                 if (skin.pairTag != null) {
323                                         skin.pairTag.setVisible(false);
324                                 }
325                                 skin.keyWindow = null;
326
327                                 if (null != shellPaintListener) {
328                                         shell.removePaintListener(shellPaintListener);
329                                 }
330
331                                 if (null != shellListener) {
332                                         shell.removeShellListener(shellListener);
333                                 }
334
335                                 if (null != shellMouseMoveListener) {
336                                         shell.removeMouseMoveListener(shellMouseMoveListener);
337                                 }
338
339                                 if (null != shellMouseListener) {
340                                         shell.removeMouseListener(shellMouseListener);
341                                 }
342
343                                 colorFrame.dispose();
344
345                                 frameMaker.freePatches();
346                         }
347
348                         @Override
349                         public void shellActivated(ShellEvent event) {
350                                 logger.info("activate");
351
352                                 if (SwtUtil.isMacPlatform() == true) {
353                                         parent.moveAbove(shell);
354                                 } else {
355                                         shell.getDisplay().asyncExec(new Runnable() {
356                                                 @Override
357                                                 public void run() {
358                                                         parent.setActive();
359                                                 }
360                                         });
361                                 }
362                         }
363
364                         @Override
365                         public void shellDeactivated(ShellEvent event) {
366                                 logger.info("deactivate");
367
368                                 /* do nothing */
369                         }
370
371                         @Override
372                         public void shellIconified(ShellEvent event) {
373                                 /* do nothing */
374                         }
375
376                         @Override
377                         public void shellDeiconified(ShellEvent event) {
378                                 logger.info("deiconified");
379
380                                 shell.getDisplay().asyncExec(new Runnable() {
381                                         @Override
382                                         public void run() {
383                                                 if (parent.getMinimized() == true) {
384                                                         parent.setMinimized(false);
385                                                 }
386                                         }
387                                 });
388                         }
389                 };
390
391                 shell.addShellListener(shellListener);
392
393                 shellMouseMoveListener = new MouseMoveListener() {
394                         @Override
395                         public void mouseMove(MouseEvent e) {
396                                 if (isGrabbedShell == true && e.button == 0/* left button */) {
397                                         if (getDockPosition() != SWT.NONE) {
398                                                 dock(SWT.NONE, false, false);
399                                                 shell.moveAbove(parent);
400                                         }
401
402                                         /* move a window */
403                                         Point previousLocation = shell.getLocation();
404                                         int x = previousLocation.x + (e.x - grabPosition.x);
405                                         int y = previousLocation.y + (e.y - grabPosition.y);
406
407                                         shell.setLocation(x, y);
408                                         return;
409                                 }
410                         }
411                 };
412
413                 shell.addMouseMoveListener(shellMouseMoveListener);
414
415                 shellMouseListener = new MouseListener() {
416                         @Override
417                         public void mouseUp(MouseEvent e) {
418                                 if (e.button == 1) { /* left button */
419                                         isGrabbedShell = false;
420                                         grabPosition.x = grabPosition.y = 0;
421
422                                         /* Let me check whether the key window was landed
423                                          * on docking area. */
424                                         Rectangle parentBounds = parent.getBounds();
425                                         Rectangle childBounds = shell.getBounds();
426
427                                         int heightOneThird = parentBounds.height / 3;
428
429                                         /* right-middle */
430                                         Rectangle attachBounds1 = new Rectangle(
431                                                         (parentBounds.x + parentBounds.width) - 5,
432                                                         parentBounds.y + heightOneThird,
433                                                         30, heightOneThird);
434                                         /* right-top */
435                                         Rectangle attachBounds2 = new Rectangle(
436                                                         (parentBounds.x + parentBounds.width) - 5,
437                                                         parentBounds.y,
438                                                         30, heightOneThird);
439                                         /* right-bottom */
440                                         Rectangle attachBounds3 = new Rectangle(
441                                                         (parentBounds.x + parentBounds.width) - 5,
442                                                         parentBounds.y + (heightOneThird * 2),
443                                                         30, heightOneThird);
444
445                                         if (childBounds.intersects(attachBounds1) == true) {
446                                                 dock(SWT.RIGHT | SWT.CENTER, false, true);
447                                         } else if (childBounds.intersects(attachBounds2) == true) {
448                                                 dock(SWT.RIGHT | SWT.TOP, false, true);
449                                         } else if (childBounds.intersects(attachBounds3) == true) {
450                                                 dock(SWT.RIGHT | SWT.BOTTOM, false, true);
451                                         } else {
452                                                 dock(SWT.NONE, false, true);
453                                         }
454                                 }
455                         }
456
457                         @Override
458                         public void mouseDown(MouseEvent e) {
459                                 if (1 == e.button) { /* left button */
460                                         isGrabbedShell = true;
461                                         grabPosition.x = e.x;
462                                         grabPosition.y = e.y;
463                                 }
464                         }
465
466                         @Override
467                         public void mouseDoubleClick(MouseEvent e) {
468                                 /* do nothing */
469                         }
470                 };
471
472                 shell.addMouseListener(shellMouseListener);
473         }
474 }