/******************************************************************************* * Copyright (c) 2006 The Pampered Chef and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * The Pampered Chef - initial API and implementation ******************************************************************************/ package org.eclipse.swt.nebula.widgets.compositetable.day.internal; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import org.eclipse.swt.SWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.FocusListener; import org.eclipse.swt.events.KeyAdapter; 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.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.events.TraverseEvent; import org.eclipse.swt.events.TraverseListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.FontMetrics; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.widgets.Canvas; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; /** * Represents a particular range in time in a single day. * * @since 3.2 */ public class TimeSlot extends Canvas { private static final int FOCUS_LINE_WIDTH = 2; private boolean focusControl = false; private final Color WHITE; private final Color CELL_BACKGROUND_LIGHT; private final Color CELL_BACKGROUND_WHITE; private final Color CELL_BORDER_EMPHASIZED; private final Color CELL_BORDER_LIGHT; private final Color TIME_BAR_COLOR; private final Color FOCUS_RUBBERBAND; /** * Width of the bar between events */ public static final int TIME_BAR_WIDTH = 3; /** * Constructor EmptyTablePlaceholder. Construct an EmptyTablePlaceholder * control. * * @param parent * The parent control * @param style * Style bits. These are the same as what Canvas accepts. */ public TimeSlot(Composite parent, int style) { super(parent, style); addTraverseListener(traverseListener); addFocusListener(focusListener); addPaintListener(paintListener); addDisposeListener(disposeListener); addKeyListener(keyListener); addMouseListener(mouseListener); Display display = Display.getCurrent(); WHITE = display.getSystemColor(SWT.COLOR_WHITE); CELL_BACKGROUND_WHITE = display.getSystemColor(SWT.COLOR_WHITE); CELL_BORDER_EMPHASIZED = display.getSystemColor(SWT.COLOR_LIST_SELECTION); CELL_BACKGROUND_LIGHT = new Color(display, new RGB(248, 248, 248)); CELL_BORDER_LIGHT = new Color(display, saturate(CELL_BORDER_EMPHASIZED.getRGB(), .2f)); TIME_BAR_COLOR = new Color(display, saturate(CELL_BORDER_EMPHASIZED.getRGB(), .1f)); FOCUS_RUBBERBAND = new Color(display, lighten(saturate(display.getSystemColor(SWT.COLOR_TITLE_BACKGROUND).getRGB(), .85f), -.333f)); setBackground(CELL_BACKGROUND_LIGHT); } /** * Sets the color's saturation to the specified value. * * @param color The RGB of the color * @param saturation the new saturation (between 0 and 1) * @return a Color that is saturated by the specified amount */ private RGB saturate(RGB color, float saturation) { float[] hsb = color.getHSB(); return new RGB(hsb[0], saturation, hsb[2]); } /** * @param color The RGB of the color * @param amount The amount to lighten as a percentage expresssed as a float between -1 and 1. * @return The new RGB that is lightened by the specified amount */ private RGB lighten(RGB color, float amount) { float[] hsb = color.getHSB(); float b = hsb[2] + hsb[2] * amount; if (b < 0) b=0; if (b > 1) b=1; return new RGB(hsb[0], hsb[1], b); } /** * Make sure we remove our listeners... */ private DisposeListener disposeListener = new DisposeListener() { public void widgetDisposed(DisposeEvent e) { removeTraverseListener(traverseListener); removeFocusListener(focusListener); removePaintListener(paintListener); removeMouseListener(mouseListener); removeKeyListener(keyListener); removeDisposeListener(disposeListener); // Dispose colors here CELL_BACKGROUND_LIGHT.dispose(); CELL_BORDER_LIGHT.dispose(); TIME_BAR_COLOR.dispose(); FOCUS_RUBBERBAND.dispose(); } }; private KeyListener keyListener = new KeyAdapter() { public void keyPressed(KeyEvent e) { switch (e.keyCode) { case SWT.ARROW_LEFT: traverse(SWT.TRAVERSE_TAB_PREVIOUS); return; case SWT.ARROW_RIGHT: traverse(SWT.TRAVERSE_TAB_NEXT); return; } } }; private Point preferredSize = new Point(-1, -1); public Point computeSize(int wHint, int hHint, boolean changed) { if (preferredSize.x == -1 || changed) { preferredSize.x = getSize().x; Display display = Display.getCurrent(); GC gc = new GC(display); try { Font font = display.getSystemFont(); gc.setFont(font); FontMetrics fm = gc.getFontMetrics(); preferredSize.y = fm.getHeight(); } finally { gc.dispose(); } } return preferredSize; } /** * Paint the control. */ private PaintListener paintListener = new PaintListener() { public void paintControl(PaintEvent e) { GC gc = e.gc; Color oldForeground = gc.getForeground(); Color oldBackground = gc.getBackground(); Point controlSize = getSize(); // Draw basic background here try { // Draw "time bar" on left side gc.setBackground(WHITE); gc.setForeground(WHITE); gc.fillRectangle(0, 0, TIME_BAR_WIDTH, controlSize.y); gc.setForeground(CELL_BORDER_LIGHT); int lineStyle = gc.getLineStyle(); gc.setLineStyle(SWT.LINE_DOT); gc.drawLine(TIME_BAR_WIDTH + 1, 0, TIME_BAR_WIDTH + 1, controlSize.y); gc.setLineStyle(lineStyle); gc.setForeground(TIME_BAR_COLOR); gc.drawLine(controlSize.x - 1, 0, controlSize.x - 1, controlSize.y); if (isMinutesAfterHour(0)) { gc.setForeground(CELL_BORDER_EMPHASIZED); } else { gc.setForeground(CELL_BORDER_LIGHT); } // gc.drawLine(TIME_BAR_WIDTH + 2, 0, controlSize.x - 2, 0); if (isMinutesAfterHour(0) || isMinutesAfterHour(30) && !isAllDay()) { gc.drawLine(0, 0, controlSize.x, 0); } } finally { gc.setBackground(oldBackground); gc.setForeground(oldForeground); } // Draw focus rubberband if we're focused int oldLineStyle = gc.getLineStyle(); int oldLineWidth = gc.getLineWidth(); try { if (focusControl) { gc.setLineStyle(SWT.LINE_DASH); gc.setLineWidth(FOCUS_LINE_WIDTH); gc.setForeground(FOCUS_RUBBERBAND); Point parentSize = getSize(); gc.drawRectangle(FOCUS_LINE_WIDTH, FOCUS_LINE_WIDTH, parentSize.x - 4, parentSize.y - 3); } gc.setForeground(CELL_BACKGROUND_LIGHT); } finally { gc.setForeground(oldForeground); gc.setLineStyle(oldLineStyle); gc.setLineWidth(oldLineWidth); } } }; /** * When we gain/lose focus, redraw ourselves appropriately */ private FocusListener focusListener = new FocusListener() { public void focusGained(FocusEvent e) { focusControl = true; redraw(); } public void focusLost(FocusEvent e) { focusControl = false; redraw(); } }; /** * Permit focus events via keyboard. */ private TraverseListener traverseListener = new TraverseListener() { public void keyTraversed(TraverseEvent e) { // NOOP: this just lets us receive focus from SWT } }; private MouseListener mouseListener = new MouseAdapter() { public void mouseDown(MouseEvent e) { setFocus(); } }; /** * @param minute The minute to check * * @return true if the time falls on the specified minute of the hour. * false otherwise. */ public boolean isMinutesAfterHour(int minute) { Calendar calendar = new GregorianCalendar(); calendar.setTime(time); return calendar.get(Calendar.MINUTE) == minute; } private boolean allDay = false; /** * @param isAllDayEvent */ public void setAllDay(boolean isAllDayEvent) { this.allDay = isAllDayEvent; if (isAllDayEvent) { setBackground(CELL_BACKGROUND_WHITE); } else { setBackground(CELL_BACKGROUND_LIGHT); } } /** * @return Returns the allDay. */ public boolean isAllDay() { return allDay; } private Date time = new Date(); /** * @param currentTime */ public void setTime(Date currentTime) { this.time = currentTime; redraw(); } }