source: trunk/src/org/expeditee/gui/Popup.java@ 1102

Last change on this file since 1102 was 1102, checked in by davidb, 6 years ago

Reworking of the code-base to separate logic from graphics. This version of Expeditee now supports a JFX graphics as an alternative to SWING

File size: 7.2 KB
Line 
1/**
2 * Popup.java
3 * Copyright (C) 2010 New Zealand Digital Library, http://expeditee.org
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19package org.expeditee.gui;
20
21import org.expeditee.core.Clip;
22import org.expeditee.core.Colour;
23import org.expeditee.core.EnforcedClipStack.EnforcedClipKey;
24import org.expeditee.core.Fill;
25import org.expeditee.core.Lifetime;
26import org.expeditee.core.Stroke;
27import org.expeditee.core.bounds.AxisAlignedBoxBounds;
28import org.expeditee.gio.EcosystemManager;
29import org.expeditee.gio.GraphicsManager;
30import org.expeditee.gui.PopupManager.PopupAnimator;
31import org.expeditee.items.ItemUtils;
32
33/**
34 * A Custom swing pop-up in Expeditee.
35 *
36 * Expeditee pop-ups can be re-used. Pop-ups are always heavyweight (i.e. uses invalidation).
37 *
38 * @see {@link PopupManager}
39 *
40 * @author Brook Novak
41 */
42public abstract class Popup
43{
44 //Mike says: Can we get the border for the IW to which this popup corresponds?
45 // Brook says: Would be nice - but popups are actually independent from widgets
46 // =>Now: It is up to the user of the popup to set the border thickness
47 private static final Stroke DEFAULT_STROKE = new Stroke(2.0f);
48
49 private Stroke _borderStroke = DEFAULT_STROKE;
50 private Colour _borderColour = Colour.BLACK;
51 private Fill _backgroundFill = new Fill(Colour.WHITE);
52
53 private PopupAnimator _animator = null;
54
55 private Lifetime _autoHideTime = new Lifetime(Lifetime.INFINITE_LIFETIME);
56 private Runnable _autoHideRoutine = new Runnable()
57 {
58 @Override
59 public void run()
60 {
61 hide();
62 DisplayController.invalidateArea(getBounds());
63 DisplayController.requestRefresh(true);
64 }
65 };
66
67 private boolean _hidden = true;
68
69 private boolean _consumeBackClick = false;
70
71 /**
72 * Creates a new pop-up.
73 * Auto-hide is set to true.
74 */
75 public Popup(PopupAnimator animator)
76 {
77 setAnimator(animator);
78 }
79
80 public Popup(PopupAnimator animator, long lifetime)
81 {
82 this(animator);
83 _autoHideTime.setLifetime(lifetime);
84 }
85
86 public Lifetime getAutoHideTime()
87 {
88 return _autoHideTime;
89 }
90
91 public void setAnimator(PopupAnimator animator)
92 {
93 _animator = animator;
94 }
95
96 public PopupAnimator getAnimator()
97 {
98 return _animator;
99 }
100
101 public boolean isShowing()
102 {
103 return !_hidden;
104 }
105
106 public void show()
107 {
108 if (_hidden) onShow();
109
110 if (_animator != null) {
111 _animator.show();
112 if (!_animator.isFinished()) {
113 _autoHideTime.cancelExpiry();
114 } else {
115 _autoHideTime.refresh();
116 _autoHideTime.onExpiry(_autoHideRoutine);
117 }
118 } else {
119 _autoHideTime.refresh();
120 _autoHideTime.onExpiry(_autoHideRoutine);
121 }
122
123 _hidden = false;
124 }
125
126 public void hide()
127 {
128 if (!_hidden) onHide();
129
130 if (_animator != null) _animator.hide();
131 _autoHideTime.cancelExpiry();
132 _hidden = true;
133 }
134
135 public boolean update()
136 {
137 if (_animator != null) {
138 if (!_hidden && !_animator.isFinished()) {
139 if (!_animator.update()) {
140 _autoHideTime.refresh();
141 _autoHideTime.onExpiry(_autoHideRoutine);
142 }
143 }
144
145 if (_hidden && !_animator.isFinished()) {
146 return _animator.update();
147 }
148 } else {
149 if (_autoHideTime.hasExpired()) hide();
150 }
151
152 return false;
153
154 }
155
156 public final void paint()
157 {
158 GraphicsManager g = EcosystemManager.getGraphicsManager();
159
160 // Make sure the popup isn't hidden
161 AxisAlignedBoxBounds currentBounds = getBounds();
162 if (currentBounds == null) return;
163
164 // Draw border and background
165 g.drawRectangle(currentBounds, 0.0, _backgroundFill, _borderColour, _borderStroke, null);
166
167 EnforcedClipKey key = g.pushClip(new Clip(currentBounds));
168
169 paintInternal();
170
171 g.popClip(key);
172 }
173
174 /** Draws the interior paint area of the popup. */
175 protected abstract void paintInternal();
176
177 /** Gets the bounds of this popup when it's fully shown. */
178 public abstract AxisAlignedBoxBounds getFullBounds();
179
180 /** Gets the bounds of this popup in its current animated state. */
181 public AxisAlignedBoxBounds getBounds()
182 {
183 if (_animator == null) {
184 if (_autoHideTime.hasExpired()) {
185 return null;
186 } else {
187 return getFullBounds();
188 }
189 }
190
191 return _animator.getAnimatedBounds(getFullBounds());
192 }
193
194 /** Invoked when the popup becomes hidden, or when the popup is animating to show but cancelled. */
195 public abstract void onHide();
196
197 /** Invoked when the popup shows. Note this might not eventuate for animated popups. */
198 public abstract void onShow();
199
200 public boolean shouldConsumeBackClick()
201 {
202 return _consumeBackClick;
203 }
204
205 /**
206 * @param consumeBackClick
207 * Set to True for whenever the user clicks empty space
208 * to go back a frame that if this popup is visible should
209 * consume the back-click event.
210 */
211 protected void setConsumeBackClick(boolean consumeBackClick)
212 {
213 _consumeBackClick = consumeBackClick;
214 }
215
216 /**
217 * @return
218 * True if this popup auto hides.
219 */
220 public boolean doesAutoHide()
221 {
222 return _autoHideTime.remainingLifetime() != Lifetime.INFINITE_LIFETIME;
223 }
224
225 /**
226 * Invalidates self.
227 *
228 * @param thickness
229 * The new thickness to set. Null for no border.
230 */
231 public void setBorderThickness(float thickness)
232 {
233 assert(thickness >= 0);
234
235 if (_borderStroke != null && _borderStroke.thickness == thickness) return;
236
237 boolean posInvalidate = true;
238
239 if (thickness < _borderStroke.thickness) {
240 invalidateAppearance();
241 posInvalidate = false;
242 }
243
244 if (thickness == 0) {
245 _borderStroke = null;
246 } else {
247 _borderStroke = new Stroke(thickness);
248 }
249
250 if (posInvalidate) invalidateAppearance();
251
252 }
253
254 /**
255 * @return
256 * The border thickness of this popup. Zero or more.
257 */
258 public float getBorderThickness()
259 {
260 if (_borderStroke == null) return 0.0f;
261
262 return _borderStroke.thickness;
263 }
264
265 /**
266 * Sets the border color around the popup.
267 * Invalidates self.
268 *
269 * @param c
270 * The new color. Null for transparent.
271 */
272 public void setBorderColor(Colour c)
273 {
274 if (c == null && _borderColour != null) invalidateAppearance();
275
276 if (c != _borderColour) {
277 _borderColour = c;
278 invalidateAppearance();
279 }
280 }
281
282 /**
283 * @return
284 * The border color for the popup. NUll if transparent
285 */
286 public Colour getBorderColor()
287 {
288 return _borderColour;
289 }
290
291 /**
292 * Invalidates the whole pop-up so that it must be fully repainted.
293 */
294 public void invalidateAppearance()
295 {
296 AxisAlignedBoxBounds bounds = getBounds();
297
298 if (bounds == null) return;
299
300 if (_borderColour != null && _borderStroke != null && _borderStroke.thickness > 0) { // border
301 DisplayController.invalidateArea(ItemUtils.expandRectangle(bounds, (int)Math.ceil(getBorderThickness()) + 1));
302 } else { // no border
303 DisplayController.invalidateArea(bounds);
304 }
305
306 }
307}
Note: See TracBrowser for help on using the repository browser.