package net.suncrescent.clicker.ui;
import java.awt.AWTException;
import java.awt.Dimension;
import net.suncrescent.clicker.Options;
import net.suncrescent.clicker.Options.Keys;
import net.suncrescent.clicker.robot.Robot;
import net.suncrescent.clicker.robot.RobotInteractionProvider.RobotEventListener;
import net.suncrescent.clicker.robot.RobotInteractionProvider.RobotStatus;
import net.suncrescent.clicker.robot.action.ActionSource;
import net.suncrescent.clicker.util.Environment;
import org.apache.log4j.Logger;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Spinner;
public class ControlFrame {
private final static Logger log = Logger.getLogger(ControlFrame.class);
private final Display display = new Display();
private final Shell window;
private Spinner quantityField;
private Label statusLabel;
private Button startButton;
private Button pauseButton;
private Button stopButton;
private final StartAction startAction = new StartAction();
private final PauseAction pauseAction = new PauseAction();
private final StopAction stopAction = new StopAction();
private CursorLocationWindow locationToolTip;
private Robot robot;
private Options options;
public ControlFrame(final Options options) throws AWTException {
ControlFrame.log.debug("Constructor");
this.setOptions(options);
ControlFrame.log.debug("Creating shell");
this.window = new Shell(SWT.ON_TOP | SWT.NONE);
this.initRobot();
this.initLayout();
if (!this.options.getOption(Keys.NO_TOOLTIP)) {
this.initLocationToolTip();
}
ControlFrame.log.debug("Shell ready");
}
public void setOptions(final Options options) {
ControlFrame.log.debug(options.toString());
this.options = options;
}
private void initLocationToolTip() {
this.locationToolTip = new CursorLocationWindow();
}
private void initLayout() {
this.window.setLayout(new GridLayout(3, false));
// start/pause/stop button
this.startButton = new Button(this.window, SWT.PUSH);
this.startButton.setText("Start");
this.startButton.addSelectionListener(this.startAction);
this.startButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
this.startAction.updateButtonState();
this.pauseButton = new Button(this.window, SWT.PUSH);
this.pauseButton.setText("Pause");
this.pauseButton.addSelectionListener(this.pauseAction);
this.pauseButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
this.pauseAction.updateButtonState();
this.stopButton = new Button(this.window, SWT.PUSH);
this.stopButton.setText("Stop");
this.stopButton.addSelectionListener(this.stopAction);
this.stopButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
this.stopAction.updateButtonState();
// qty
this.quantityField = new Spinner(this.window, SWT.NONE);
this.quantityField.setMinimum(1);
this.quantityField.setMaximum(Integer.MAX_VALUE);
this.quantityField.setSelection(1);
this.quantityField.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
// label
this.statusLabel = new Label(this.window, SWT.CENTER);
this.statusLabel.setText(this.robot.getStatusProvider().getStatus().toString());
this.statusLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
// exit button
final Button exitButton = new Button(this.window, SWT.PUSH);
exitButton.setText("Exit");
exitButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
exitButton.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(final SelectionEvent paramSelectionEvent) {
ControlFrame.this.robot.getControlProvider().stop();
ControlFrame.this.window.setVisible(false);
ControlFrame.this.window.dispose();
}
@Override
public void widgetDefaultSelected(final SelectionEvent paramSelectionEvent) {
this.widgetSelected(paramSelectionEvent);
}
});
// size
this.window.setSize(230, 60);
final Dimension screenSize = Environment.getScreenSize();
this.window.setLocation(screenSize.width - this.window.getSize().x - 20, screenSize.height - this.window.getSize().y - 40);
}
private void initRobot() throws AWTException {
this.robot = new Robot();
this.robot.getEventProvider().addEventListener(new RobotListener());
}
public void setActionSource(final ActionSource sequence) {
ControlFrame.log.debug("Changing action sequence");
this.robot.setActionSequence(sequence.getActionList());
}
public void display() {
ControlFrame.log.debug("Displaying shell");
this.window.open(); // open shell for user access
ControlFrame.log.debug("Main UI loop");
// process all user input events
while (!this.window.isDisposed()) {
// process the next event, wait when none available
if (!this.display.readAndDispatch()) {
this.display.sleep();
}
}
ControlFrame.log.debug("Shell closed");
this.display.dispose(); // must always clean up
this.locationToolTip.dispose();
ControlFrame.log.debug("SWT resources disposed");
}
class RobotListener implements RobotEventListener {
@Override
public void statusChanged(final RobotStatus oldStatus, final RobotStatus newStatus) {
// must be run in SWT thread
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
if (!ControlFrame.this.window.isDisposed()) {
if (newStatus == RobotStatus.IDLE) {
ControlFrame.this.quantityField.setEnabled(true);
} else {
ControlFrame.this.quantityField.setEnabled(false);
}
ControlFrame.this.startAction.updateButtonState();
ControlFrame.this.stopAction.updateButtonState();
ControlFrame.this.pauseAction.updateButtonState();
ControlFrame.this.statusLabel.setText(newStatus.toString());
}
}
});
}
@Override
public void repeatCountChanged(final int repeatCount) {
// must be run in SWT thread
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
if (!ControlFrame.this.window.isDisposed()) {
ControlFrame.this.quantityField.setSelection(repeatCount + 1);
}
}
});
}
}
class StartAction implements SelectionListener {
@Override
public void widgetSelected(final SelectionEvent paramSelectionEvent) {
ControlFrame.this.robot.setRepeatCount(ControlFrame.this.quantityField.getSelection());
ControlFrame.this.robot.getControlProvider().start();
}
protected void updateButtonState() {
final RobotStatus status = ControlFrame.this.robot.getStatusProvider().getStatus();
ControlFrame.this.startButton.setEnabled(status == RobotStatus.IDLE);
}
@Override
public void widgetDefaultSelected(final SelectionEvent paramSelectionEvent) {
this.widgetSelected(paramSelectionEvent);
}
}
class PauseAction implements SelectionListener {
@Override
public void widgetSelected(final SelectionEvent paramSelectionEvent) {
final RobotStatus status = ControlFrame.this.robot.getStatusProvider().getStatus();
if (status == RobotStatus.PAUSED) {
ControlFrame.this.robot.getControlProvider().resume();
} else {
ControlFrame.this.robot.getControlProvider().pause();
}
}
protected void updateButtonState() {
final RobotStatus status = ControlFrame.this.robot.getStatusProvider().getStatus();
ControlFrame.this.pauseButton.setEnabled(status == RobotStatus.RUNNING || status == RobotStatus.PAUSED);
}
@Override
public void widgetDefaultSelected(final SelectionEvent paramSelectionEvent) {
this.widgetSelected(paramSelectionEvent);
}
}
class StopAction implements SelectionListener {
@Override
public void widgetSelected(final SelectionEvent paramSelectionEvent) {
ControlFrame.this.robot.getControlProvider().stop();
}
protected void updateButtonState() {
final RobotStatus status = ControlFrame.this.robot.getStatusProvider().getStatus();
ControlFrame.this.stopButton.setEnabled(status == RobotStatus.RUNNING || status == RobotStatus.PAUSED);
}
@Override
public void widgetDefaultSelected(final SelectionEvent paramSelectionEvent) {
this.widgetSelected(paramSelectionEvent);
}
}
}