FileDocCategorySizeDatePackage
SpeedScaleShell.javaAPI DocAzureus 3.0.3.416481Fri Aug 24 18:16:32 BST 2007org.gudy.azureus2.ui.swt.shells

SpeedScaleShell

public class SpeedScaleShell extends Object
Cheap ugly slider shell
author
TuxPaper
created
Jul 5, 2007

Fields Summary
private static final boolean
MOUSE_ONLY_UP_EXITS
private static final int
OPTION_HEIGHT
private static final int
TEXT_HEIGHT
private static final int
SCALER_HEIGHT
private int
HEIGHT
private static final int
WIDTH
private static final int
PADDING_X0
private static final int
PADDING_X1
private static final int
WIDTH_NO_PADDING
private static final int
TYPED_TEXT_ALPHA
private static final long
CLOSE_DELAY
private int
value
private boolean
cancelled
private int
minValue
private int
maxValue
private int
maxTextValue
private int
pageIncrement
private int
bigPageIncrement
private org.eclipse.swt.widgets.Shell
shell
private LinkedHashMap
mapOptions
private String
sValue
private org.eclipse.swt.widgets.Composite
composite
private boolean
menuChosen
protected boolean
lastMoveHadMouseDown
private boolean
assumeInitiallyDown
Constructors Summary
public SpeedScaleShell()

		minValue = 0;
		maxValue = -1;
		maxTextValue = -1;
		pageIncrement = 10;
		bigPageIncrement = 100;
		cancelled = true;
		menuChosen = false;
	
Methods Summary
public java.lang.String_getStringValue()

		String name = (String) mapOptions.get(new Integer(value));
		return getStringValue(value, name);
	
public voidaddOption(java.lang.String id, int value)

		mapOptions.put(new Integer(value), id);
		HEIGHT += OPTION_HEIGHT;
	
private intgetBaselinePos()

		return HEIGHT - (SCALER_HEIGHT / 2);
	
public intgetMaxTextValue()

		return maxTextValue;
	
public intgetMaxValue()

		return maxValue;
	
public intgetMinValue()

		return minValue;
	
public java.lang.StringgetStringValue(int value, java.lang.String sValue)

		if (sValue != null) {
			return sValue;
		}
		return "" + value;
	
public intgetValue()

		return value;
	
protected intgetValueFromMousePos(int x)

param
x
return
since
3.0.1.7

		int x0 = x + 1;
		if (x < PADDING_X0) {
			x0 = PADDING_X0;
		} else if (x > PADDING_X0 + WIDTH_NO_PADDING) {
			x0 = PADDING_X0 + WIDTH_NO_PADDING;
		}

		return (x0 - PADDING_X0) * maxValue / WIDTH_NO_PADDING;
	
public booleanisCancelled()

		return cancelled;
	
public static voidmain(java.lang.String[] args)


	     
		SpeedScaleShell speedScaleWidget = new SpeedScaleShell() {
			public String getStringValue() {
				return getValue() + "b/s";
			}
		};
		speedScaleWidget.setMaxValue(10000);
		speedScaleWidget.setMaxTextValue(15000);
		speedScaleWidget.addOption("AutoSpeed", -1);
		speedScaleWidget.addOption("Preset: 10b/s", 10);
		speedScaleWidget.addOption("Preset: 20b/s", 20);
		speedScaleWidget.addOption("Preset: 1b/s", 1);
		speedScaleWidget.addOption("Preset: 1000b/s", 1000);
		speedScaleWidget.addOption("Preset: A really long preset", 2000);
		System.out.println("returns "
				+ speedScaleWidget.open(1000, Constants.isWindows) + " w/"
				+ speedScaleWidget.getValue());
	
public booleanopen(int startValue, boolean _assumeInitiallyDown)
Borks with 0 or -1 maxValue

param
startValue
param
assumeInitiallyDown
return
since
3.0.1.7

		value = startValue;
		this.assumeInitiallyDown = _assumeInitiallyDown;
		cancelled = true;

		shell = new Shell(Utils.findAnyShell(), SWT.DOUBLE_BUFFERED | SWT.ON_TOP);
		shell.setLayout(new FillLayout());
		final Display display = shell.getDisplay();

		composite = new Composite(shell, SWT.DOUBLE_BUFFERED);

		final Point firstMousePos = display.getCursorLocation();

		composite.addTraverseListener(new TraverseListener() {
			public void keyTraversed(TraverseEvent e) {
				if (e.detail == SWT.TRAVERSE_ESCAPE) {
					setCancelled(true);
					shell.dispose();
				} else if (e.detail == SWT.TRAVERSE_ARROW_NEXT) {
					setValue(value + 1);
				} else if (e.detail == SWT.TRAVERSE_ARROW_PREVIOUS) {
					setValue(value - 1);
				} else if (e.detail == SWT.TRAVERSE_PAGE_NEXT) {
					setValue(value + bigPageIncrement);
				} else if (e.detail == SWT.TRAVERSE_PAGE_PREVIOUS) {
					setValue(value - bigPageIncrement);
				} else if (e.detail == SWT.TRAVERSE_RETURN) {
					setCancelled(false);
					shell.dispose();
				}
			}
		});

		composite.addKeyListener(new KeyListener() {
			public void keyReleased(KeyEvent e) {
			}

			public void keyPressed(KeyEvent e) {
				if (e.keyCode == SWT.PAGE_DOWN && e.stateMask == 0) {
					setValue(value + pageIncrement);
				} else if (e.keyCode == SWT.PAGE_UP && e.stateMask == 0) {
					setValue(value - pageIncrement);
				} else if (e.keyCode == SWT.HOME) {
					setValue(minValue);
				} else if (e.keyCode == SWT.END) {
					if (maxValue != -1) {
						setValue(maxValue);
					}
				}
			}
		});

		composite.addMouseMoveListener(new MouseMoveListener() {
			public void mouseMove(MouseEvent e) {
				lastMoveHadMouseDown = false;
				boolean hasButtonDown = (e.stateMask & SWT.BUTTON_MASK) > 0
						|| assumeInitiallyDown;
				if (hasButtonDown) {
					if (e.y > HEIGHT - SCALER_HEIGHT) {
						lastMoveHadMouseDown = true;
						setValue(getValueFromMousePos(e.x));
					}
					composite.redraw();
				} else {
					composite.redraw();
				}
			}
		});

		composite.addMouseTrackListener(new MouseTrackListener() {
			boolean mouseIsOut = false;

			private boolean exitCancelled = false;

			public void mouseHover(MouseEvent e) {
			}

			public void mouseExit(MouseEvent e) {
				mouseIsOut = true;
				SimpleTimer.addEvent("close scaler",
						SystemTime.getOffsetTime(CLOSE_DELAY), new TimerEventPerformer() {
							public void perform(TimerEvent event) {
								Utils.execSWTThread(new AERunnable() {
									public void runSupport() {
										if (!exitCancelled) {
											shell.dispose();
										} else {
											exitCancelled = false;
										}
									}
								});
							}
						});
			}

			public void mouseEnter(MouseEvent e) {
				if (mouseIsOut) {
					exitCancelled = true;
				}
				mouseIsOut = false;
			}
		});

		composite.addMouseListener(new MouseListener() {
			boolean bMouseDown = false;

			public void mouseUp(MouseEvent e) {
				if (assumeInitiallyDown) {
					assumeInitiallyDown = false;
				}
				if (MOUSE_ONLY_UP_EXITS) {
					if (lastMoveHadMouseDown) {
						Point mousePos = display.getCursorLocation();
						if (mousePos.equals(firstMousePos)) {
							lastMoveHadMouseDown = false;
							return;
						}
					}
					bMouseDown = true;
				}
				if (bMouseDown) {
					if (e.y > HEIGHT - SCALER_HEIGHT) {
						setValue(getValueFromMousePos(e.x));
						setCancelled(false);
						if (lastMoveHadMouseDown) {
							shell.dispose();
						}
					} else if (e.y > TEXT_HEIGHT) {
						int idx = (e.y - TEXT_HEIGHT) / OPTION_HEIGHT;
						Iterator iterator = mapOptions.keySet().iterator();
						int newValue;
						do {
							newValue = ((Integer) iterator.next()).intValue();
							idx--;
						} while (idx >= 0);
						value = newValue; // ignore min/max
						setCancelled(false);
						setMenuChosen(true);
						shell.dispose();
					}
				}
			}

			public void mouseDown(MouseEvent e) {
				if (e.count > 1) {
					lastMoveHadMouseDown = true;
					return;
				}
				Point mousePos = display.getCursorLocation();
				if (e.y > HEIGHT - SCALER_HEIGHT) {
					bMouseDown = true;
					setValue(getValueFromMousePos(e.x));
				}
			}

			public void mouseDoubleClick(MouseEvent e) {
			}

		});

		composite.addPaintListener(new PaintListener() {
			public void paintControl(PaintEvent e) {
				int x = WIDTH_NO_PADDING * value / maxValue;
				if (x < 0) {
					x = 0;
				} else if (x > WIDTH_NO_PADDING) {
					x = WIDTH_NO_PADDING;
				}
				int startX = WIDTH_NO_PADDING * startValue / maxValue;
				if (startX < 0) {
					startX = 0;
				} else if (startX > WIDTH_NO_PADDING) {
					startX = WIDTH_NO_PADDING;
				}
				int baseLinePos = getBaselinePos();

				try {
					e.gc.setAdvanced(true);
					e.gc.setAntialias(SWT.ON);
				} catch (Exception ex) {
					// aw
				}

				e.gc.setForeground(display.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW));
				// left
				e.gc.drawLine(PADDING_X0, baseLinePos - 6, PADDING_X0, baseLinePos + 6);
				// right
				e.gc.drawLine(PADDING_X0 + WIDTH_NO_PADDING, baseLinePos - 6,
						PADDING_X0 + WIDTH_NO_PADDING, baseLinePos + 6);
				// baseline
				e.gc.drawLine(PADDING_X0, baseLinePos, PADDING_X0 + WIDTH_NO_PADDING,
						baseLinePos);

				e.gc.setForeground(display.getSystemColor(SWT.COLOR_WIDGET_FOREGROUND));
				e.gc.setBackground(display.getSystemColor(SWT.COLOR_WIDGET_FOREGROUND));
				// start value marker
				e.gc.drawLine(PADDING_X0 + startX, baseLinePos - 5,
						PADDING_X0 + startX, baseLinePos + 5);
				// current value marker
				e.gc.fillRoundRectangle(PADDING_X0 + x - 2, baseLinePos - 5, 5, 10, 10,
						10);

				// Current Value Text
				e.gc.setForeground(display.getSystemColor(SWT.COLOR_INFO_FOREGROUND));
				e.gc.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));

				e.gc.fillRectangle(0, 0, WIDTH, TEXT_HEIGHT);

				GCStringPrinter.printString(e.gc, _getStringValue(), new Rectangle(0,
						0, WIDTH, HEIGHT), true, false, SWT.CENTER | SWT.TOP | SWT.WRAP);

				e.gc.drawLine(0, TEXT_HEIGHT - 1, WIDTH, TEXT_HEIGHT - 1);

				// options list
				int y = TEXT_HEIGHT;
				Point mousePos = composite.toControl(display.getCursorLocation());
				for (Iterator iter = mapOptions.keySet().iterator(); iter.hasNext();) {
					Integer value = (Integer) iter.next();
					String text = (String) mapOptions.get(value);

					Rectangle area = new Rectangle(0, y, WIDTH, OPTION_HEIGHT);
					Color bg;
					if (area.contains(mousePos)) {
						bg = display.getSystemColor(SWT.COLOR_LIST_SELECTION);
						e.gc.setBackground(bg);
						e.gc.setForeground(display.getSystemColor(SWT.COLOR_LIST_SELECTION_TEXT));
						e.gc.fillRectangle(area);
					} else {
						bg = display.getSystemColor(SWT.COLOR_LIST_BACKGROUND);
						e.gc.setBackground(bg);
						e.gc.setForeground(display.getSystemColor(SWT.COLOR_LIST_FOREGROUND));
					}

					int ovalSize = OPTION_HEIGHT - 6;
					if (getValue() == value.intValue()) {
						Color saveColor = e.gc.getBackground();
						e.gc.setBackground(e.gc.getForeground());
						e.gc.fillOval(4, y + 5, ovalSize - 3, ovalSize - 3);
						e.gc.setBackground(saveColor);
					}
					if (Constants.isLinux) {
						// Hack: on linux, drawing oval seems to draw a line from last pos
						// to start of oval.. drawing a point (anywhere) seems to clear the
						// path
						Color saveColor = e.gc.getForeground();
						e.gc.setForeground(bg);
						e.gc.drawPoint(2, y + 3);
						e.gc.setForeground(saveColor);
					}
					e.gc.drawOval(2, y + 3, ovalSize, ovalSize);

					GCStringPrinter.printString(e.gc, text, new Rectangle(OPTION_HEIGHT,
							y, WIDTH - OPTION_HEIGHT, OPTION_HEIGHT), true, false, SWT.LEFT);
					y += OPTION_HEIGHT;
				}

				// typed value
				if (sValue.length() > 0) {
					Point extent = e.gc.textExtent(sValue);
					if (extent.x > WIDTH - 10) {
						extent.x = WIDTH - 10;
					}
					Rectangle rect = new Rectangle(WIDTH - 8 - extent.x, 14,
							extent.x + 5, extent.y + 4 + 14 > TEXT_HEIGHT ? TEXT_HEIGHT - 15
									: extent.y + 4);
					e.gc.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
					e.gc.fillRectangle(rect);

					try {
						e.gc.setAlpha(TYPED_TEXT_ALPHA);
					} catch (Exception ex) {
					}
					e.gc.setBackground(display.getSystemColor(SWT.COLOR_LIST_BACKGROUND));
					e.gc.setForeground(display.getSystemColor(SWT.COLOR_LIST_FOREGROUND));
					//e.gc.drawRectangle(rect);

					GCStringPrinter.printString(e.gc, sValue, new Rectangle(rect.x + 2,
							rect.y + 2, WIDTH - 5, OPTION_HEIGHT), true, false, SWT.LEFT
							| SWT.BOTTOM);
				}
			}
		});

		// blinking cursor so people know they can type
		SimpleTimer.addPeriodicEvent("BlinkingCursor", 500,
				new TimerEventPerformer() {
					boolean on = false;

					public void perform(final TimerEvent event) {
						Utils.execSWTThread(new AERunnable() {
							public void runSupport() {
								if (composite.isDisposed()) {
									event.cancel();
									return;
								}

								on = !on;

								GC gc = new GC(composite);
								try {
									gc.setLineWidth(2);
									if (!on) {
										gc.setForeground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
									} else {
										try {
											gc.setAlpha(TYPED_TEXT_ALPHA);
										} catch (Exception e) {
										}
									}
									int y = 15;
									gc.drawLine(WIDTH - 5, y + 1, WIDTH - 5, y + OPTION_HEIGHT);
								} finally {
									gc.dispose();
								}

							}
						});
					}
				});

		composite.addKeyListener(new KeyListener() {
			public void keyReleased(KeyEvent e) {
			}

			public void keyPressed(KeyEvent e) {
				if (Character.isDigit(e.character)) {
					sValue += e.character;
				} else if (e.keyCode == SWT.BS && sValue.length() > 0) {
					sValue = sValue.substring(0, sValue.length() - 1);
				} else {
					return;
				}
				try {
					int newValue = Integer.parseInt(sValue);
					if (maxTextValue == -1) {
						setValue(newValue);
					} else {
						if (minValue > 0 && newValue < minValue) {
							newValue = minValue;
						}
						if (newValue > maxTextValue) {
							newValue = maxTextValue;
						}
						value = newValue;
						composite.redraw();
					}
				} catch (Exception ex) {
					setValue(startValue);
				}
			}
		});

		Point location = display.getCursorLocation();

		location.y -= getBaselinePos();
		int x = WIDTH_NO_PADDING * value / maxValue;
		location.x -= PADDING_X0 + x;

		Rectangle bounds = new Rectangle(location.x, location.y, WIDTH, HEIGHT);
		Rectangle monitorBounds = shell.getMonitor().getBounds();
		Rectangle intersection = monitorBounds.intersection(bounds);
		if (intersection.width != bounds.width) {
			bounds.x -= WIDTH - intersection.width;
			bounds.width = WIDTH;
		}
		if (intersection.height != bounds.height) {
			bounds.y -= HEIGHT - intersection.height;
			bounds.height = HEIGHT;
		}

		shell.setBounds(bounds);

		shell.open();
		// must be after, for OSX
		composite.setFocus();

		try {
			while (!shell.isDisposed()) {
				if (!display.readAndDispatch()) {
					display.sleep();
				}
			}
		} catch (Throwable t) {
			Debug.out(t);
		}

		return !cancelled;
	
public voidsetCancelled(boolean cancelled)

		this.cancelled = cancelled;
	
public voidsetMaxTextValue(int maxTextValue)

		this.maxTextValue = maxTextValue;
	
public voidsetMaxValue(int maxValue)

		this.maxValue = maxValue;
	
public voidsetMenuChosen(boolean menuChosen)

		this.menuChosen = menuChosen;
	
public voidsetMinValue(int minValue)

		this.minValue = minValue;
	
public voidsetValue(int value)

		//System.out.println("sv " + value + ";" + Debug.getCompressedStackTrace());
		if (value > maxValue) {
			value = maxValue;
		} else if (value < minValue) {
			value = minValue;
		}
		this.value = value;
		if (composite != null && !composite.isDisposed()) {
			composite.redraw();
		}
	
public booleanwasMenuChosen()

		return menuChosen;