File: BottomBar.java

package info (click to toggle)
mac-widgets 0.10.0%2Bsvn416-dfsg1-2
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 1,968 kB
  • ctags: 2,003
  • sloc: java: 9,909; makefile: 13; sh: 12
file content (270 lines) | stat: -rw-r--r-- 10,825 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
package com.explodingpixels.macwidgets;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Window;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;

import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JSplitPane;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;

import com.explodingpixels.border.FocusStateMatteBorder;
import com.explodingpixels.painter.FocusStatePainter;
import com.explodingpixels.painter.GradientPainter;
import com.explodingpixels.painter.MacWidgetsPainter;
import com.explodingpixels.util.PlatformUtils;
import com.explodingpixels.widgets.WindowDragger;
import com.explodingpixels.widgets.WindowUtils;


/**
 * A Mac style Bottom Bar. For a full descrption of what a Bottom Bar is, see the
 * <a href="http://developer.apple.com/documentation/UserExperience/Conceptual/AppleHIGuidelines/XHIGWindows/chapter_18_section_4.html#//apple_ref/doc/uid/20000961-SW6">Bottom Bars</a>
 * section of Apple's Human Interface Guidelines. Here's an example of what this method cretes:
 * <br>
 * <img src="../../../../graphics/BottomBar.png">
 * <br>
 * Here's a simple example that creates a Bottom Bar:
 * <pre>
 * BottomBar bottomBar = BottomBar(BottomBarSize.LARGE);
 * bottomBar.addComponentToCenter(MacWidgetFactory.createEmphasizedLabel("My Label"));
 * </pre>
 */
public class BottomBar {

	protected final TriAreaComponent fBottomBar = new TriAreaComponent(5);

	protected JSplitPane fSplitPane;

	protected final SplitterHandleMouseMovementHandler fMouseListener =
            new SplitterHandleMouseMovementHandler();

	protected static final Color ACTIVE_TOP_COLOR = new Color(0xcccccc);
	protected static final Color ACTIVE_BOTTOM_COLOR = new Color(0xa7a7a7);
	protected static final Color INACTIVE_TOP_COLOR = new Color(0xe9e9e9);
	protected static final Color INACTIVE_BOTTOM_COLOR = new Color(0xd8d8d8);
	protected static final Color BORDER_HIGHLIGHT_COLOR = new Color(255, 255, 255, 100);

	protected static final Color LEOPARD_ACTIVE_TOP_COLOR = new Color(0xbbbbbb);
	protected static final Color LEOPARD_ACTIVE_BOTTOM_COLOR = new Color(0x969696);
	protected static final Color LEOPARD_INACTIVE_TOP_COLOR = new Color(0xe3e3e3);
	protected static final Color LEOPARD_INACTIVE_BOTTOM_COLOR = new Color(0xcfcfcf);
	protected static final Color LEOPARD_BORDER_HIGHLIGHT_COLOR = new Color(255, 255, 255, 110);

	/**
	 * Creates a {@code BottomBar} of the given size.
	 *
	 * @param size the height of the {@code BottomBar}.
	 */
	public BottomBar(BottomBarSize size) {

		createAndInstallBackgroundPainter();
		createAndInstallBorder();

		fBottomBar.forceOuterAreasToHaveTheSameWidth();

		// TODO use the actual border insets instead of the hard-coded value 2.
		// calculate the height of the bottom bar. this includes adding two pixels to incorporate
		// the height of the line border.
		int height = size.getHeight() + 2;
		fBottomBar.getComponent().setPreferredSize(new Dimension(-1, height));

		// install a listener that will repaint this component when the parent window's focus state
		// changes.
		WindowUtils.installJComponentRepainterOnWindowFocusChanged(fBottomBar.getComponent());
	}

	/**
	 * Adds the given component to the left side of this {@code BottomBar}.
	 *
	 * @param toolToAdd the tool to add to this {@code BottomBar}.
	 */
	public void addComponentToLeft(JComponent toolToAdd) {
		fBottomBar.addComponentToLeft(toolToAdd);
	}

	/**
	 * Adds the given component to the left side of this {@code BottomBar} followed by the
	 * given an empty space of the given pixel width.
	 *
	 * @param toolToAdd     the tool to add to this {@code BottomBar}.
	 * @param spacer_pixels the amount of space to post-pend the added component with.
	 */
	public void addComponentToLeft(JComponent toolToAdd, int spacer_pixels) {
		fBottomBar.addComponentToLeft(toolToAdd, spacer_pixels);
	}

	/**
	 * Adds the given component to the side of this {@code BottomBar}.
	 *
	 * @param toolToAdd the tool to add to this {@code BottomBar}.
	 */
	public void addComponentToCenter(JComponent toolToAdd) {
		fBottomBar.addComponentToCenter(toolToAdd);
	}

	/**
	 * Adds the given component to the center of this {@code BottomBar}. If this is not the
	 * first component to be added to the center, then the given component will be preceeded by a
	 * space of the given width.
	 *
	 * @param toolToAdd     the tool to add to this {@code BottomBar}.
	 * @param spacer_pixels the amount of space to pre-pend the added component with *if* the given
	 *                      component is *not* the first component to be added to the center.
	 */
	public void addComponentToCenter(JComponent toolToAdd, int spacer_pixels) {
		fBottomBar.addComponentToCenter(toolToAdd, spacer_pixels);
	}

	/**
	 * Adds the given component to the right side of this {@code BottomBar}.
	 *
	 * @param toolToAdd the tool to add to this {@code BottomBar}.
	 */
	public void addComponentToRight(JComponent toolToAdd) {
		fBottomBar.addComponentToRight(toolToAdd);
	}

	/**
	 * Adds the given component to the right side of this {@code BottomBar}. If this is not
	 * the first component to be added to the right, then the given component will be followed by a
	 * space of the given width.
	 *
	 * @param toolToAdd     the tool to add to this {@code BottomBar}.
	 * @param spacer_pixels the amount of space to post-pend the added component with *if* the given
	 *                      component is *not* the first component to be added to the center.
	 */
	public void addComponentToRight(JComponent toolToAdd, int spacer_pixels) {
		fBottomBar.addComponentToRight(toolToAdd, spacer_pixels);
	}

	/**
	 * Installs a drag listener on this {@code BottomBar} such that if it is dragged, it will
	 * move the given {@link java.awt.Window}.
	 *
	 * @param window the {@code Window} to move when the this {@code BottomBar} is dragged.
	 */
	public void installWindowDraggerOnWindow(Window window) {
		new WindowDragger(window, getComponent());
	}

	/**
	 * Gets the user interface component representing this {@code BottomBar}. The returned
	 * {@link JComponent} should be added to a container that will be displayed.
	 *
	 * @return the user interface component representing this {@code BottomBar}.
	 */
	public JComponent getComponent() {
		return fBottomBar.getComponent();
	}
	
    public void forceAreasToHaveTheSameWidth() {
        fBottomBar.forceAreasToHaveTheSameWidth();
    }

    public void forceOuterAreasToHaveTheSameWidth() {
        fBottomBar.forceOuterAreasToHaveTheSameWidth();
    }
    

    /**
     * Connects the draggable widget in this {@code BottomBar} to the divider of the
     * given {@link JSplitPane}. Thus when the user drags the {@code BottomBar} draggable
     * widget, the given {@code JSplitPane}s divider location will be adjusted.
     *
     * @param splitPane the {@code JSplitPane} to connect the draggable widget to.
     */
    public void installDraggableWidgetOnSplitPane(JSplitPane splitPane) {
        if (splitPane == null) {
            throw new IllegalArgumentException("JSplitPane cannot be null.");
        }

        fSplitPane = splitPane;
        this.getComponent().addMouseListener(fMouseListener);
        this.getComponent().addMouseMotionListener(fMouseListener);
        //fSplitterHandle.setCursor(Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR));
    }

	// Private methods. ///////////////////////////////////////////////////////////////////////////

	private void createAndInstallBackgroundPainter() {
		fBottomBar.setBackgroundPainter(PlatformUtils.isLeopard()
				? createLeopardPainter() : createDefaultPainter());
	}

	private void createAndInstallBorder() {
		FocusStateMatteBorder outterBorder = new FocusStateMatteBorder(1, 0, 0, 0,
				MacColorUtils.getTexturedWindowToolbarBorderFocusedColor(),
				MacColorUtils.getTexturedWindowToolbarBorderUnfocusedColor(),
				fBottomBar.getComponent());
		Border innerBorder = BorderFactory.createMatteBorder(1, 0, 0, 0, getBorderHighlightColor());
		Border lineBorders = BorderFactory.createCompoundBorder(outterBorder, innerBorder);

		// TODO determine if there is a good standard for this. there doesn't seem to be any
		// TODO consistent value used by Apple.
		// left and right edge padding.
		int padding = 5;
		fBottomBar.getComponent().setBorder(
				BorderFactory.createCompoundBorder(lineBorders,
						BorderFactory.createEmptyBorder(0, padding, 0, padding)));
	}

	private static MacWidgetsPainter<Component> createDefaultPainter() {
		MacWidgetsPainter<Component> focusedPainter = new GradientPainter(
				ACTIVE_TOP_COLOR, ACTIVE_BOTTOM_COLOR);
		MacWidgetsPainter<Component> unfocusedPainter = new GradientPainter(
				INACTIVE_TOP_COLOR, INACTIVE_BOTTOM_COLOR);
		return new FocusStatePainter(focusedPainter, focusedPainter, unfocusedPainter);
	}

	private static MacWidgetsPainter<Component> createLeopardPainter() {
		MacWidgetsPainter<Component> focusedPainter = new GradientPainter(
				LEOPARD_ACTIVE_TOP_COLOR, LEOPARD_ACTIVE_BOTTOM_COLOR);
		MacWidgetsPainter<Component> unfocusedPainter = new GradientPainter(
				LEOPARD_INACTIVE_TOP_COLOR, LEOPARD_INACTIVE_BOTTOM_COLOR);
		return new FocusStatePainter(focusedPainter, focusedPainter, unfocusedPainter);
	}

	private static Color getBorderHighlightColor() {
		return PlatformUtils.isLeopard() ? LEOPARD_BORDER_HIGHLIGHT_COLOR : BORDER_HIGHLIGHT_COLOR;
	}
	
	   
    // Mouse handler for splitter control widget. /////////////////////////////////////////////////

    private class SplitterHandleMouseMovementHandler extends MouseAdapter
            implements MouseMotionListener {

        private int fDelta;

        @Override
        public void mousePressed(MouseEvent e) {
            MouseEvent convertedEvent =
                    SwingUtilities.convertMouseEvent(BottomBar.this.getComponent(), e, fSplitPane);

            fDelta = fSplitPane.getDividerLocation() - convertedEvent.getPoint().y;
        }
        
        // MouseMotionListener implementation /////////////////////////////////////////////////////

        public void mouseDragged(MouseEvent e) {
            MouseEvent convertedEvent =
                    SwingUtilities.convertMouseEvent(BottomBar.this.getComponent(), e, fSplitPane);
            int newLocation = convertedEvent.getPoint().y + fDelta;
            // bound newLocation between the minimum and maximum divider locations.
            int boundedNewLocation = Math.max(fSplitPane.getMinimumDividerLocation(),
                    Math.min(newLocation, fSplitPane.getMaximumDividerLocation()));
            fSplitPane.setDividerLocation(boundedNewLocation);
        }

        public void mouseMoved(MouseEvent e) {
        }
    }    

}