blob: c5a4561fa2a926bd1744450594fd35e14a7912c5 [file] [log] [blame]
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.motorola.studio.android.emulator.ui.controls.maindisplay;
import static com.motorola.studio.android.common.log.StudioLogger.info;
import java.util.Properties;
import org.eclipse.core.runtime.Platform;
import org.eclipse.sequoyah.vnc.vncviewer.graphics.IRemoteDisplay;
import org.eclipse.sequoyah.vnc.vncviewer.graphics.swt.SWTRemoteDisplay;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.events.MouseWheelListener;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import com.motorola.studio.android.adt.DDMSFacade;
import com.motorola.studio.android.emulator.core.model.IAndroidEmulatorInstance;
import com.motorola.studio.android.emulator.core.model.IInputLogic;
import com.motorola.studio.android.emulator.logic.AndroidLogicUtils;
import com.motorola.studio.android.emulator.skin.android.AndroidSkinTranslator;
import com.motorola.studio.android.emulator.ui.controls.IAndroidComposite;
import com.motorola.studio.android.emulator.ui.controls.UIHelper;
import com.motorola.studio.android.emulator.ui.handlers.IHandlerConstants;
import com.motorola.studio.android.nativeos.NativeUIUtils;
/**
* This class is the composite that holds the main display and it is shown by
* the Emulator Main Display View.
*/
public class MainDisplayComposite extends Composite implements IAndroidComposite
{
/**
* The zoom factor whose default value is 1.0 (100%)
*/
private double zoomFactor = 1.0;
private double fitZoomfactor;
// Minimum value to be used as zoom factor. This is necessary to avoid
// divisions to zero
private static final double MINIMUM_ZOOM_FACTOR = 0.0001;
private static final double ZOOM_FIT = 0.0;
/**
* The flag indicating that Ctrl key is pressed
*/
private boolean ctrlPressed = false;
/**
* SWT key pressed/released events listener.
*/
private KeyListener keyListener;
private MouseListener mouseListener;
private MouseMoveListener mouseMoveListener;
private IInputLogic androidInput;
private boolean isMouseLeftButtonPressed;
private boolean isFitToWindow;
private IAndroidEmulatorInstance androidInstance;
private Properties keyMap;
/**
* Constructor
*
* @param parent
* composite
* @param style
* style
* @param baseWidth
* the default main display width
* @param baseHeight
* the default main display height
*/
public MainDisplayComposite(Composite parent, int style, int baseWidth, int baseHeight,
IAndroidEmulatorInstance instance)
{
super(parent, style);
androidInput = instance.getInputLogic();
androidInstance = instance;
isMouseLeftButtonPressed = false;
keyMap = AndroidSkinTranslator.getQwertyKeyMap();
addListener();
if (!Platform.getOS().equals(Platform.OS_MACOSX))
{
hideEmulatorWindow();
}
}
private void hideEmulatorWindow()
{
int port =
AndroidLogicUtils.getEmulatorPort(DDMSFacade.getSerialNumberByName(androidInstance
.getName()));
long windowHandle = NativeUIUtils.getWindowHandle(androidInstance.getName(), port);
androidInstance.setWindowHandle(windowHandle);
NativeUIUtils.hideWindow(windowHandle);
}
/*
* (non-Javadoc)
* @see org.eclipse.swt.widgets.Widget#dispose()
*/
@Override
public void dispose()
{
if (androidInput != null)
{
androidInput.dispose();
}
keyListener = null;
mouseListener = null;
mouseMoveListener = null;
if (!Platform.getOS().equals(Platform.OS_MACOSX))
{
long hnd = androidInstance.getWindowHandle();
if (hnd > 0)
{
NativeUIUtils.showWindow(hnd);
NativeUIUtils.restoreWindow(hnd);
}
//Force update on redrawing
androidInstance.setWindowHandle(0);
}
super.dispose();
}
/**
* Updates the composite size when zoom is changed.
*
* @param zoom
* the zoom factor
*/
public void setZoomFactor(double zoomFactor)
{
info("Update detached view composite size");
if (zoomFactor == ZOOM_FIT)
{
isFitToWindow = true;
}
else
{
isFitToWindow = false;
}
this.zoomFactor = zoomFactor;
}
/**
* Gets the zoom factor.
*
* @return zoom the zoom factor.
*/
public double getZoomFactor()
{
return zoomFactor;
}
/**
* Applies the zoom factor to the components of the composite, updating the
* composite size to hold totally the main display.
*/
public void applyZoomFactor()
{
SWTRemoteDisplay mainDisplay = UIHelper.getRemoteDisplayAssociatedToControl(this);
IRemoteDisplay.Rotation rotation = mainDisplay.getRotation();
int baseHeight;
int baseWidth;
switch (rotation)
{
case ROTATION_90DEG_COUNTERCLOCKWISE:
baseHeight = mainDisplay.getScreenWidth();
baseWidth = mainDisplay.getScreenHeight();
break;
default:
baseHeight = mainDisplay.getScreenHeight();
baseWidth = mainDisplay.getScreenWidth();
}
int width;
int height;
if (isFitToWindow)
{
Rectangle clientArea = getParent().getClientArea();
if ((clientArea.width == 0) || (clientArea.height == 0))
{
// zoom factor cannot be zero, otherwise an
// IllegalArgumentException
// is raised in some SWT methods
fitZoomfactor = MINIMUM_ZOOM_FACTOR;
}
else
{
double widthRatio = (double) (clientArea.width) / baseWidth;
double heightRatio = (double) (clientArea.height) / baseHeight;
fitZoomfactor = Math.min(widthRatio, heightRatio);
}
width = new Double(baseWidth * fitZoomfactor).intValue();
height = new Double(baseHeight * fitZoomfactor).intValue();
if (mainDisplay != null)
{
mainDisplay.setZoomFactor(fitZoomfactor);
}
}
else
{
width = new Double(baseWidth * zoomFactor).intValue();
height = new Double(baseHeight * zoomFactor).intValue();
if (mainDisplay != null)
{
mainDisplay.setZoomFactor(zoomFactor);
}
}
setSize(width, height);
}
/**
* Adds listener for SWT events.
*/
private void addListener()
{
// add listener to handle keyboard key pressing
keyListener = new KeyListener()
{
public void keyPressed(KeyEvent arg0)
{
int keyCode = arg0.keyCode;
if (keyCode == SWT.CTRL)
{
ctrlPressed = true;
}
else
{
// send message to emulator
androidInput.sendKey(arg0.character, keyCode, keyMap);
}
}
public void keyReleased(KeyEvent arg0)
{
int keyCode = arg0.keyCode;
if (keyCode == SWT.CTRL)
{
ctrlPressed = false;
}
}
};
// listener to change the zoom factor using Ctrl + Mouse Wheel
addMouseWheelListener(new MouseWheelListener()
{
public void mouseScrolled(MouseEvent event)
{
if (ctrlPressed)
{
if ((event.count > 0) && (zoomFactor < IHandlerConstants.MAXIMUM_ZOOM))
{
// increase zoom factor
setZoomFactor(zoomFactor + IHandlerConstants.STEP_ZOOM);
applyZoomFactor();
}
else if ((event.count < 0) && (zoomFactor > IHandlerConstants.MINIMUM_ZOOM))
{
// decrease zoom factor
setZoomFactor(zoomFactor - IHandlerConstants.STEP_ZOOM);
applyZoomFactor();
}
}
}
});
mouseListener = new MouseAdapter()
{
/**
* @see org.eclipse.swt.events.MouseListener#mouseUp(MouseEvent)
*/
@Override
public void mouseUp(MouseEvent e)
{
handleMouseUp(e);
}
/**
* @see org.eclipse.swt.events.MouseListener#mouseDown(MouseEvent)
*/
@Override
public void mouseDown(MouseEvent e)
{
setFocus();
handleMouseDown(e);
}
};
mouseMoveListener = new MouseMoveListener()
{
/**
* @see org.eclipse.swt.events.MouseMoveListener#mouseMove(MouseEvent)
*/
public void mouseMove(MouseEvent e)
{
handleMouseMove(e);
}
};
getParent().addControlListener(new ControlAdapter()
{
/*
* (non-Javadoc)
* @see org.eclipse.swt.events.ControlAdapter#controlResized(org.eclipse.swt.events.ControlEvent)
*/
@Override
public void controlResized(ControlEvent event)
{
if (isFitToWindow)
{
applyZoomFactor();
}
}
});
}
/*
* (non-Javadoc)
* @see com.motorola.studio.android.emulator.ui.controls.IAndroidComposite#applyLayout(java.lang.String)
*/
public void applyLayout(String layoutName)
{
//do nothing
}
/**
* Gets the listener that handles SWT key pressing and releasing events.
*
* @return the KeyListener object
*/
public KeyListener getKeyListener()
{
return keyListener;
}
/**
* Gets the listener that handles SWT mouse clicking events.
*
* @return the MouseListener object
*/
public MouseListener getMouseListener()
{
return mouseListener;
}
/**
* Gets the listener that handles SWT mouse moving events.
*
* @return the MouseMoveListener object
*/
public MouseMoveListener getMouseMoveListener()
{
return mouseMoveListener;
}
/**
* Handles the mouse up event on the skin composite
*
* @param e
* The mouse up event
*/
private void handleMouseUp(MouseEvent e)
{
if (e.button == 1)
{
isMouseLeftButtonPressed = false;
UIHelper.ajustCoordinates(e, this);
androidInput.sendMouseUp(e.x, e.y);
}
}
/**
* Handles the mouse down event on the skin composite
*
* @param e
* The mouse down event
*/
private void handleMouseDown(MouseEvent e)
{
if (e.button == 1)
{
UIHelper.ajustCoordinates(e, this);
androidInput.sendMouseDown(e.x, e.y);
isMouseLeftButtonPressed = true;
}
}
/**
* Handles the mouse move event on the skin composite
*
* @param e
* The mouse move event
*/
private void handleMouseMove(MouseEvent e)
{
if (isMouseLeftButtonPressed)
{
UIHelper.ajustCoordinates(e, this);
androidInput.sendMouseMove(e.x, e.y);
}
}
public boolean isFitToWindowSelected()
{
return isFitToWindow;
}
}