1 package be
.nikiroo
.utils
.ui
;
3 import java
.awt
.event
.ActionEvent
;
4 import java
.awt
.event
.ActionListener
;
6 import javax
.swing
.BoxLayout
;
7 import javax
.swing
.DefaultComboBoxModel
;
8 import javax
.swing
.Icon
;
9 import javax
.swing
.JButton
;
10 import javax
.swing
.JComboBox
;
13 * A small panel that let you choose a zoom level or an actual zoom value (when
14 * there is enough space to allow that).
18 public class ZoomBox
extends ListenerPanel
{
19 private static final long serialVersionUID
= 1L;
21 /** The event that is fired on zoom change. */
22 public static final String ZOOM_CHANGED
= "zoom_changed";
24 private enum ZoomLevel
{
25 FIT_TO_WIDTH(0, true), //
26 FIT_TO_HEIGHT(0, false), //
27 ACTUAL_SIZE(1, null), //
28 HALF_SIZE(0.5, null), //
29 DOUBLE_SIZE(2, null),//
32 private final double zoom
;
33 private final Boolean snapMode
;
35 private ZoomLevel(double zoom
, Boolean snapMode
) {
37 this.snapMode
= snapMode
;
40 public double getZoom() {
44 public Boolean
getSnapToWidth() {
49 * Use default values that can be understood by a human.
52 public String
toString() {
55 return "Fit to width";
57 return "Fit to height";
65 return super.toString();
68 static ZoomLevel
[] values(boolean orderedSelection
) {
69 if (orderedSelection
) {
70 return new ZoomLevel
[] { //
83 private boolean vertical
;
84 private boolean small
;
86 private JButton zoomIn
;
87 private JButton zoomOut
;
88 private JButton snapWidth
;
89 private JButton snapHeight
;
91 @SuppressWarnings("rawtypes") // JComboBox<?> is not java 1.6 compatible
92 private JComboBox zoombox
;
94 private double zoom
= 1;
95 private Boolean snapMode
= true;
97 @SuppressWarnings("rawtypes") // JComboBox<?> not compatible java 1.6
98 private DefaultComboBoxModel zoomBoxModel
;
101 * Create a new {@link ZoomBox}.
103 @SuppressWarnings({ "unchecked", "rawtypes" }) // JComboBox<?> not
104 // compatible java 1.6
106 zoomIn
= new JButton();
107 zoomIn
.addActionListener(new ActionListener() {
109 public void actionPerformed(ActionEvent e
) {
114 zoomBoxModel
= new DefaultComboBoxModel(ZoomLevel
.values(true));
115 zoombox
= new JComboBox(zoomBoxModel
);
116 zoombox
.setEditable(true);
117 zoombox
.addActionListener(new ActionListener() {
119 public void actionPerformed(ActionEvent e
) {
120 Object selected
= zoomBoxModel
.getSelectedItem();
122 if (selected
== null) {
126 if (selected
instanceof ZoomLevel
) {
127 ZoomLevel selectedZoomLevel
= (ZoomLevel
) selected
;
128 setZoomSnapMode(selectedZoomLevel
.getZoom(),
129 selectedZoomLevel
.getSnapToWidth());
131 String selectedString
= selected
.toString();
132 selectedString
= selectedString
.trim();
133 if (selectedString
.endsWith("%")) {
134 selectedString
= selectedString
135 .substring(0, selectedString
.length() - 1)
140 int pc
= Integer
.parseInt(selectedString
);
142 throw new NumberFormatException("invalid");
145 setZoomSnapMode(pc
/ 100.0, null);
146 } catch (NumberFormatException nfe
) {
150 fireActionPerformed(ZOOM_CHANGED
);
154 zoomOut
= new JButton();
155 zoomOut
.addActionListener(new ActionListener() {
157 public void actionPerformed(ActionEvent e
) {
162 snapWidth
= new JButton();
163 snapWidth
.addActionListener(new ActionListener() {
165 public void actionPerformed(ActionEvent e
) {
170 snapHeight
= new JButton();
171 snapHeight
.addActionListener(new ActionListener() {
173 public void actionPerformed(ActionEvent e
) {
178 setIcons(null, null, null, null);
179 setOrientation(vertical
);
185 * It usually returns 1 (default value), the value you passed yourself or 0
186 * (a snap to width or snap to height was asked by the user).
188 * Will cause a fire event if needed.
193 public void setZoom(double zoom
) {
194 if (this.zoom
!= zoom
) {
196 fireActionPerformed(ZOOM_CHANGED
);
201 * The snap mode (NULL means no snap mode, TRUE for snap to width, FALSE for
204 * Will cause a fire event if needed.
209 public void setSnapMode(Boolean snapToWidth
) {
210 if (this.snapMode
!= snapToWidth
) {
211 doSetSnapMode(snapToWidth
);
212 fireActionPerformed(ZOOM_CHANGED
);
217 * Set both {@link ZoomBox#setZoom(double)} and
218 * {@link ZoomBox#setSnapMode(Boolean)} but fire only one change event.
220 * Will cause a fire event if needed.
227 public void setZoomSnapMode(double zoom
, Boolean snapMode
) {
228 if (this.zoom
!= zoom
|| this.snapMode
!= snapMode
) {
230 doSetSnapMode(snapMode
);
231 fireActionPerformed(ZOOM_CHANGED
);
238 * It usually returns 1 (default value), the value you passed yourself or 0
239 * (a snap to width or snap to height was asked by the user).
241 * @return the zoom level
243 public double getZoom() {
248 * The snap mode (NULL means no snap mode, TRUE for snap to width, FALSE for
251 * @return the snap mode
253 public Boolean
getSnapMode() {
258 * Zoom in, by a certain amount in "steps".
260 * Note that zoomIn(-1) is the same as zoomOut(1).
263 * the number of zoom steps to make, can be negative
265 public void zoomIn(int steps
) {
266 // TODO: redo zoomIn/zoomOut correctly
272 double newZoom
= zoom
;
273 for (int i
= 0; i
< steps
; i
++) {
274 newZoom
= newZoom
+ (newZoom
< 0.1 ?
0.01 : 0.1);
276 newZoom
= Math
.round(newZoom
* 10.0) / 10.0; // snap to 10%
278 newZoom
= Math
.round(newZoom
* 100.0) / 100.0; // snap to 1%
282 setZoomSnapMode(newZoom
, null);
283 fireActionPerformed(ZOOM_CHANGED
);
287 * Zoom out, by a certain amount in "steps".
289 * Note that zoomOut(-1) is the same as zoomIn(1).
292 * the number of zoom steps to make, can be negative
294 public void zoomOut(int steps
) {
300 double newZoom
= zoom
;
301 for (int i
= 0; i
< steps
; i
++) {
302 newZoom
= newZoom
- (newZoom
> 0.19 ?
0.1 : 0.01);
303 if (newZoom
< 0.01) {
309 newZoom
= Math
.round(newZoom
* 10.0) / 10.0; // snap to 10%
311 newZoom
= Math
.round(newZoom
* 100.0) / 100.0; // snap to 1%
315 setZoomSnapMode(newZoom
, null);
316 fireActionPerformed(ZOOM_CHANGED
);
320 * Set icons for the buttons instead of square brackets.
322 * Any NULL value will make the button use square brackets again.
325 * the icon of the button "go to first page"
327 * the icon of the button "go to previous page"
329 * the icon of the button "go to next page"
331 * the icon of the button "go to last page"
333 public void setIcons(Icon zoomIn
, Icon zoomOut
, Icon snapWidth
,
335 this.zoomIn
.setIcon(zoomIn
);
336 this.zoomIn
.setText(zoomIn
== null ?
"+" : "");
337 this.zoomOut
.setIcon(zoomOut
);
338 this.zoomOut
.setText(zoomOut
== null ?
"-" : "");
339 this.snapWidth
.setIcon(snapWidth
);
340 this.snapWidth
.setText(snapWidth
== null ?
"W" : "");
341 this.snapHeight
.setIcon(snapHeight
);
342 this.snapHeight
.setText(snapHeight
== null ?
"H" : "");
346 * A smaller {@link ZoomBox} that uses buttons instead of a big combo box
347 * for the zoom modes.
349 * Always small in vertical orientation.
351 * @return TRUE if it is small
353 public boolean getSmall() {
358 * A smaller {@link ZoomBox} that uses buttons instead of a big combo box
359 * for the zoom modes.
361 * Always small in vertical orientation.
364 * TRUE to set it small
366 * @return TRUE if it changed something
368 public boolean setSmall(boolean small
) {
369 return setUi(small
, vertical
);
373 * The general orientation of the component.
375 * @return TRUE for vertical orientation, FALSE for horisontal orientation
377 public boolean getOrientation() {
382 * The general orientation of the component.
385 * TRUE for vertical orientation, FALSE for horisontal
388 * @return TRUE if it changed something
390 public boolean setOrientation(boolean vertical
) {
391 return setUi(small
, vertical
);
395 * Set the zoom level, no fire event.
397 * It usually returns 1 (default value), the value you passed yourself or 0
398 * (a snap to width or snap to height was asked by the user).
403 private void doSetZoom(double zoom
) {
404 if (snapMode
== null) {
405 zoomBoxModel
.setSelectedItem(
406 Integer
.toString((int) Math
.round(zoom
* 100)) + " %");
413 * Set the snap mode, no fire event.
418 private void doSetSnapMode(Boolean snapToWidth
) {
419 if (snapToWidth
== null) {
420 zoomBoxModel
.setSelectedItem(
421 Integer
.toString((int) Math
.round(zoom
* 100)) + " %");
423 for (ZoomLevel level
: ZoomLevel
.values()) {
424 if (level
.getSnapToWidth() == snapToWidth
) {
425 zoomBoxModel
.setSelectedItem(level
);
430 this.snapMode
= snapToWidth
;
433 private boolean setUi(boolean small
, boolean vertical
) {
434 if (getWidth() == 0 || this.small
!= small
435 || this.vertical
!= vertical
) {
437 this.vertical
= vertical
;
439 BoxLayout layout
= new BoxLayout(this,
440 vertical ? BoxLayout
.Y_AXIS
: BoxLayout
.X_AXIS
);
445 if (vertical
|| small
) {
447 this.add(snapHeight
);