├── src └── org │ └── kwt │ ├── package.html │ ├── ui │ ├── package.html │ ├── KWTCheckboxGroup.java │ ├── KWTScrollPanel.java │ ├── KWTCheckbox.java │ ├── KWTProgressBar.java │ └── KWTSelectableLabel.java │ └── InvalidStyleException.java ├── .gitignore ├── samples ├── KWTCheckbox │ ├── kindlet.properties │ ├── src │ │ └── org │ │ │ └── kwt │ │ │ └── samples │ │ │ └── kwtcheckbox │ │ │ └── Main.java │ └── build.xml ├── KWTProgressBar │ ├── kindlet.properties │ ├── src │ │ └── org │ │ │ └── kwt │ │ │ └── samples │ │ │ └── kwtprogressbar │ │ │ └── Main.java │ └── build.xml ├── KWTScrollPanel │ ├── kindlet.properties │ ├── src │ │ └── org │ │ │ └── kwt │ │ │ └── samples │ │ │ └── kwtscrollpanel │ │ │ └── Main.java │ └── build.xml └── KWTSelectableLabel │ ├── kindlet.properties │ ├── src │ └── org │ │ └── kwt │ │ └── samples │ │ └── kwtselectablelabel │ │ └── Main.java │ └── build.xml ├── README.md └── LICENSE /src/org/kwt/package.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | General utility classes for KWT. 4 | 5 | -------------------------------------------------------------------------------- /src/org/kwt/ui/package.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | A collection of general user interface elements for KWT. 4 | 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build directory ignore 2 | build/ 3 | 4 | # Eclipse-specific ignores 5 | bin/ 6 | .settings/ 7 | .classpath 8 | .project 9 | 10 | -------------------------------------------------------------------------------- /samples/KWTCheckbox/kindlet.properties: -------------------------------------------------------------------------------- 1 | kindlet.title=KWTCheckboxSample 2 | kindlet.url=http\://github.com/AdrianP/Kindle-Widget-Toolkit 3 | kindlet.image= 4 | kindlet.keystore=developer-signing.keystore 5 | kindlet.version=1 6 | kindlet.mainClass=org.kwt.samples.kwtcheckbox.Main 7 | kindlet.networkSupport=false 8 | kindlet.vendor=KWT 9 | kindlet.id= 10 | -------------------------------------------------------------------------------- /samples/KWTProgressBar/kindlet.properties: -------------------------------------------------------------------------------- 1 | kindlet.title=KWTProgressBarSample 2 | kindlet.url=http\://github.com/AdrianP/Kindle-Widget-Toolkit 3 | kindlet.image= 4 | kindlet.keystore=developer-signing.keystore 5 | kindlet.version=1 6 | kindlet.mainClass=org.kwt.samples.kwtprogressbar.Main 7 | kindlet.networkSupport=false 8 | kindlet.vendor=KWT 9 | kindlet.id= 10 | -------------------------------------------------------------------------------- /samples/KWTScrollPanel/kindlet.properties: -------------------------------------------------------------------------------- 1 | kindlet.title=KWTScrollPanelSample 2 | kindlet.url=http\://github.com/AdrianP/Kindle-Widget-Toolkit 3 | kindlet.image= 4 | kindlet.keystore=developer-signing.keystore 5 | kindlet.version=1 6 | kindlet.mainClass=org.kwt.samples.kwtscrollpanel.Main 7 | kindlet.networkSupport=false 8 | kindlet.vendor=KWT 9 | kindlet.id= 10 | -------------------------------------------------------------------------------- /samples/KWTSelectableLabel/kindlet.properties: -------------------------------------------------------------------------------- 1 | kindlet.title=KWTSelectableLabelSample 2 | kindlet.url=http\://github.com/AdrianP/Kindle-Widget-Toolkit 3 | kindlet.image= 4 | kindlet.keystore=developer-signing.keystore 5 | kindlet.version=1 6 | kindlet.mainClass=org.kwt.samples.kwtselectablelabel.Main 7 | kindlet.networkSupport=false 8 | kindlet.vendor=KWT 9 | kindlet.id= 10 | -------------------------------------------------------------------------------- /samples/KWTScrollPanel/src/org/kwt/samples/kwtscrollpanel/Main.java: -------------------------------------------------------------------------------- 1 | package org.kwt.samples.kwtscrollpanel; 2 | 3 | import java.awt.Container; 4 | 5 | import org.kwt.ui.KWTScrollPanel; 6 | import org.kwt.ui.KWTSelectableLabel; 7 | 8 | import com.amazon.kindle.kindlet.AbstractKindlet; 9 | import com.amazon.kindle.kindlet.KindletContext; 10 | import com.amazon.kindle.kindlet.ui.KBoxLayout; 11 | import com.amazon.kindle.kindlet.ui.KLabel; 12 | import com.amazon.kindle.kindlet.ui.KPanel; 13 | 14 | /** 15 | * This sample Kindlet demonstrates the use of the KWTScrollPanel 16 | * 17 | * @author Adrian Petrescu 18 | * 19 | */ 20 | public class Main extends AbstractKindlet { 21 | 22 | public void create(final KindletContext context) { 23 | final Container rootContainer = context.getRootContainer(); 24 | Container testContainer = new KWTScrollPanel(80); 25 | testContainer.setLayout(new KBoxLayout(testContainer, KBoxLayout.Y_AXIS)); 26 | rootContainer.add(testContainer); 27 | 28 | KLabel[] labels = new KLabel[25]; 29 | for (int i = 0; i < labels.length; i++) { 30 | labels[i] = new KLabel("This is Label #" + i); 31 | testContainer.add(labels[i]); 32 | } 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/org/kwt/InvalidStyleException.java: -------------------------------------------------------------------------------- 1 | package org.kwt; 2 | 3 | /** 4 | * An exception thrown by styleable KWT components which indicates that they do not support 5 | * the provided style. This may occur either because an incorrect style from another class was 6 | * provided, or because that particular style applies to some other part of the component. 7 | * 8 | */ 9 | public class InvalidStyleException extends RuntimeException { 10 | private static final long serialVersionUID = -8543895842607438654L; 11 | 12 | private int invalidStyle; 13 | 14 | /** 15 | * Constructs a new exception with the specified detail message and style. 16 | * @param message the detail message 17 | * @param invalidStyle the style which could not be applied 18 | */ 19 | public InvalidStyleException(String message, int invalidStyle) { 20 | super(message); 21 | this.invalidStyle = invalidStyle; 22 | } 23 | 24 | /** 25 | * Returns the style which could not be applied. 26 | * @return the invalid style 27 | */ 28 | public int getInvalidStyle() { 29 | return invalidStyle; 30 | } 31 | 32 | /** 33 | * Returns a detail message specifying why the style could not be applied. 34 | * @return the detail message 35 | */ 36 | public String getMessage() { 37 | return super.getMessage() + " [Invalid Style: " + invalidStyle + "]"; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /samples/KWTCheckbox/src/org/kwt/samples/kwtcheckbox/Main.java: -------------------------------------------------------------------------------- 1 | package org.kwt.samples.kwtcheckbox; 2 | 3 | import java.awt.Container; 4 | import java.awt.FlowLayout; 5 | 6 | import org.kwt.ui.KWTCheckbox; 7 | import org.kwt.ui.KWTCheckboxGroup; 8 | 9 | import com.amazon.kindle.kindlet.AbstractKindlet; 10 | import com.amazon.kindle.kindlet.KindletContext; 11 | import com.amazon.kindle.kindlet.ui.KLabel; 12 | 13 | /** 14 | * This sample Kindlet demonstrates the use of the KWTCheckbox. 15 | * 16 | * @author Adrian Petrescu 17 | * 18 | */ 19 | public class Main extends AbstractKindlet { 20 | 21 | public void create(final KindletContext context) { 22 | Container rootContainer = context.getRootContainer(); 23 | rootContainer.setLayout(new FlowLayout()); 24 | 25 | KWTCheckboxGroup group = new KWTCheckboxGroup(); 26 | 27 | rootContainer.add(new KWTCheckbox(group)); 28 | rootContainer.add(new KWTCheckbox(group)); 29 | rootContainer.add(new KWTCheckbox(group)); 30 | rootContainer.add(new KWTCheckbox(group)); 31 | rootContainer.add(new KWTCheckbox(group)); 32 | 33 | group = null; 34 | 35 | rootContainer.add(new KWTCheckbox(group)); 36 | rootContainer.add(new KWTCheckbox(group)); 37 | rootContainer.add(new KWTCheckbox(group)); 38 | rootContainer.add(new KWTCheckbox(group)); 39 | rootContainer.add(new KWTCheckbox(group)); 40 | 41 | KWTCheckbox button = new KWTCheckbox(group); 42 | rootContainer.add(button); 43 | 44 | button.requestFocus(); 45 | rootContainer.add(new KLabel("Click this option!")); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/org/kwt/ui/KWTCheckboxGroup.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010 Dan Fabulich. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located in the LICENSE file included with this 7 | * distribution. 8 | * 9 | * This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 10 | * CONDITIONS OF ANY KIND, either express or implied. See the License 11 | * for the specific language governing permissions and limitations under the 12 | * License. 13 | */ 14 | 15 | package org.kwt.ui; 16 | 17 | /** 18 | * This group binds together multiple radio buttons, ensuring that only one 19 | * radio button is selected at a time. 20 | * 21 | * @author Dan Fabulich 22 | * 23 | */ 24 | public class KWTCheckboxGroup { 25 | private KWTCheckbox selected = null; 26 | 27 | /** 28 | * Returns the currently selected radio button. 29 | * 30 | * @return the currently selected radio button 31 | */ 32 | public KWTCheckbox getSelected() { 33 | return selected; 34 | } 35 | 36 | /** 37 | * Selects a radio button, deselecting the previously selected button. 38 | * 39 | * @param box a radio button belonging to this group, ornull to deselect
40 | * everything.
41 | */
42 | public void setSelected(KWTCheckbox box) {
43 | if (box != null && box.group != this) {
44 | return;
45 | }
46 | KWTCheckbox oldChoice = this.selected;
47 | this.selected = box;
48 | if (oldChoice != null && oldChoice != box && oldChoice.group == this) {
49 | oldChoice.setSelected(false);
50 | }
51 | if (box != null && oldChoice != box && !box.isSelected()) {
52 | box.setSelected(true);
53 | }
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/samples/KWTSelectableLabel/src/org/kwt/samples/kwtselectablelabel/Main.java:
--------------------------------------------------------------------------------
1 | package org.kwt.samples.kwtselectablelabel;
2 |
3 | import java.awt.Container;
4 | import java.awt.event.ActionEvent;
5 | import java.awt.event.ActionListener;
6 |
7 | import org.kwt.ui.KWTSelectableLabel;
8 |
9 | import com.amazon.kindle.kindlet.AbstractKindlet;
10 | import com.amazon.kindle.kindlet.KindletContext;
11 | import com.amazon.kindle.kindlet.ui.KBoxLayout;
12 | import com.amazon.kindle.kindlet.ui.KLabel;
13 |
14 | /**
15 | * This sample Kindlet demonstrates the use of the KWTSelectableLabel.
16 | *
17 | * @author Adrian Petrescu
18 | *
19 | */
20 | public class Main extends AbstractKindlet {
21 |
22 | public void create(final KindletContext context) {
23 | final Container rootContainer = context.getRootContainer();
24 | rootContainer.setLayout(new KBoxLayout(rootContainer, KBoxLayout.Y_AXIS));
25 |
26 | final KLabel description = new KLabel("No label has been selected yet.");
27 |
28 | KWTSelectableLabel[] labels = new KWTSelectableLabel[5];
29 | for (int i = 0; i < labels.length; i++) {
30 | final int selectedLabel = i;
31 | labels[i] = new KWTSelectableLabel("This is Label #" + i);
32 | labels[i].setUnderlineWidth((i+1) * 2);
33 | labels[i].setUnderlineGap(i * 2);
34 | labels[i].setUnderlineStyle((i % 2 == 0) ?
35 | KWTSelectableLabel.STYLE_SOLID
36 | : KWTSelectableLabel.STYLE_DASHED);
37 | labels[i].addActionListener(new ActionListener() {
38 | public void actionPerformed(ActionEvent arg0) {
39 | description.setText("Label #" + selectedLabel + " was selected.");
40 | rootContainer.repaint();
41 | }
42 | });
43 | rootContainer.add(labels[i]);
44 | }
45 | labels[0].requestFocus();
46 | rootContainer.add(description);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/samples/KWTProgressBar/src/org/kwt/samples/kwtprogressbar/Main.java:
--------------------------------------------------------------------------------
1 | package org.kwt.samples.kwtprogressbar;
2 |
3 | import java.awt.Container;
4 | import java.awt.event.ActionEvent;
5 | import java.awt.event.ActionListener;
6 |
7 | import org.kwt.ui.KWTProgressBar;
8 |
9 | import com.amazon.kindle.kindlet.AbstractKindlet;
10 | import com.amazon.kindle.kindlet.KindletContext;
11 | import com.amazon.kindle.kindlet.ui.KButton;
12 | import com.amazon.kindle.kindlet.ui.KPanel;
13 |
14 | public class Main extends AbstractKindlet {
15 |
16 | public void create(final KindletContext context) {
17 | final Container rootContainer = context.getRootContainer();
18 | final KPanel panel = new KPanel();
19 | rootContainer.add(panel);
20 |
21 | final KWTProgressBar progressBar1 = new KWTProgressBar();
22 | progressBar1.setWidth(800);
23 | progressBar1.setLabelStyle(KWTProgressBar.STYLE_NONE);
24 |
25 | final KWTProgressBar progressBar2 = new KWTProgressBar();
26 | progressBar2.setWidth(800);
27 | progressBar2.setLabelStyle(KWTProgressBar.STYLE_PERCENTAGE);
28 |
29 | final KWTProgressBar progressBar3 = new KWTProgressBar();
30 | progressBar3.setWidth(800);
31 | progressBar3.setLabelStyle(KWTProgressBar.STYLE_TOTAL);
32 |
33 | KButton increaseTicks = new KButton("Increase ticks");
34 | KButton decreaseTicks = new KButton("Decrease ticks");
35 | increaseTicks.addActionListener(new ActionListener() {
36 | public void actionPerformed(ActionEvent e) {
37 | progressBar1.setCurrentTick(progressBar1.getCurrentTick() + 1);
38 | progressBar2.setCurrentTick(progressBar2.getCurrentTick() + 1);
39 | progressBar3.setCurrentTick(progressBar3.getCurrentTick() + 1);
40 | panel.repaint();
41 | }
42 | });
43 | decreaseTicks.addActionListener(new ActionListener() {
44 | public void actionPerformed(ActionEvent e) {
45 | progressBar1.setCurrentTick(progressBar1.getCurrentTick() - 1);
46 | progressBar2.setCurrentTick(progressBar2.getCurrentTick() - 1);
47 | progressBar3.setCurrentTick(progressBar3.getCurrentTick() - 1);
48 | panel.repaint();
49 | }
50 | });
51 | increaseTicks.requestFocus();
52 |
53 | panel.add(progressBar1);
54 | panel.add(progressBar2);
55 | panel.add(progressBar3);
56 | panel.add(increaseTicks);
57 | panel.add(decreaseTicks);
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Kindle Widget Toolkit
2 | =====================
3 |
4 | The KWT (**Kindle Widget Toolkit**) is a set of KComponents to be used with the Kindle Development Kit to create compelling user interfaces for Active Content.
5 |
6 | The components in KWT attempt to match the style of the KDK APIs and the underlying Java AWT, and should in most cases be a drop-in replacement for the default components in the KDK.
7 |
8 | Features
9 | --------
10 |
11 | At the moment, KWT supports the following components.
12 |
13 | **KWTCheckbox** - A simple toggle-able checkbox, or a selectable radio button, depending on whether it belongs to a **KWTCheckboxGroup**.
14 |
15 | **KWTDiagram/KWTMutableDiagram** - A diagram, in both mutable and non-mutable versions, which can be added to a container and have text flow around it.
16 |
17 | **KWTProgressBar** - A graphical representation of the progress towards completion of a particular task.
18 |
19 | **KWTScrollPanel** - A KPanel that supports vertical scrolling, instead of the Kindle's usual Paged metaphor.
20 |
21 | **KWTSelectableLabel** - A KLabel that can receive ActionEvents as if it were a KButton.
22 |
23 | Further components are in active development.
24 |
25 | Using KWT
26 | ---------
27 |
28 | Unfortunately, the KDK does not enable app bundles to contain third-party JARs, so using KWT is not as simple as adding it to the classpath. There are two main approaches you can use.
29 |
30 | ### Copying the source
31 |
32 | You can simply copy the widgets you want to use into your own package and compile it together with your application. This is the easiest way to get everything working, but you will have to manually apply updates as KWT adds features and improvements. Alternatively, you can include the KWT package as a git submodule in your repository.
33 |
34 | ### Use the JAR
35 | Although the KDK does not enable its app bundles to contain third-party JARs, you can add a target to your **build.xml** that copies the required Class files into your own JAR. Updating KWT then becomes simply a matter of dropping in the latest release. You can see an example of such a target in the sample project distributed together with KWT.
36 |
37 | Documentation
38 | -------------
39 |
40 | You can view a full JavaDoc API Reference for KWT [here](http://s3.amazonaws.com/kwt-dev/javadoc/index.html), or you can generate one yourself using the **generate-public-javadoc** build target.
41 |
42 | License
43 | -------
44 |
45 | KWT is distributed under a permissive Apache 2.0 License (see our LICENSE file). As such, it can safely be used in both proprietary and free Kindle applications.
46 |
47 | Contributing
48 | ------------
49 |
50 | KWT is still in the early stages of development, and there are many great components still to be added. If you have some bug fixes or new components you would like included in KWT, please feel free to send a pull request. If you have bug reports, ideas for new features, or general feedback, please use GitHub's Issue tracker to let us know.
51 |
--------------------------------------------------------------------------------
/src/org/kwt/ui/KWTScrollPanel.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2010 Adrian Petrescu.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License").
5 | * You may not use this file except in compliance with the License.
6 | * A copy of the License is located in the LICENSE file included with this
7 | * distribution.
8 | *
9 | * This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
10 | * CONDITIONS OF ANY KIND, either express or implied. See the License
11 | * for the specific language governing permissions and limitations under the
12 | * License.
13 | */
14 |
15 | package org.kwt.ui;
16 |
17 | import java.awt.Dimension;
18 | import java.awt.Graphics;
19 | import java.awt.Rectangle;
20 | import java.awt.Shape;
21 |
22 | import com.amazon.kindle.kindlet.ui.KPanel;
23 |
24 | public class KWTScrollPanel extends KPanel {
25 | private static final long serialVersionUID = 323032064088045342L;
26 |
27 | private static final int LEFT_GAP = 10;
28 | private static final int SCROLLBAR_WIDTH = 20;
29 | private static final int SCROLLBAR_LEFT_GAP = 10;
30 | private static final int SCROLLBAR_RIGHT_GAP = 10;
31 | private static final int RIGHT_GAP = SCROLLBAR_LEFT_GAP + SCROLLBAR_WIDTH + SCROLLBAR_RIGHT_GAP;
32 | private static final int TOP_GAP = 10;
33 | private static final int BOTTOM_GAP = 10;
34 |
35 | /**
36 | * The height of the viewport displaying the underlying KPanel. Since KWTScrollPanels only
37 | * support vertical scrolling, only a viewportHeight is needed, and not a viewportWidth.
38 | */
39 | private int viewportHeight;
40 |
41 | /**
42 | * How far down the component the scroll bar is. 0 represents the very top,
43 | * 1 represents the very bottom.
44 | */
45 | private double scrollLevel;
46 |
47 | public KWTScrollPanel(int height) {
48 | scrollLevel = 0.0;
49 | viewportHeight = height;
50 | }
51 |
52 | public void setSize(Dimension d) {
53 | setSize(d.width, d.height);
54 | }
55 |
56 | public void setSize(int width, int height) {
57 | viewportHeight = height;
58 |
59 | super.setSize(width - (LEFT_GAP + RIGHT_GAP), super.getSize().height);
60 | }
61 |
62 | public Dimension getSize() {
63 | Dimension d = super.getSize();
64 | d.width += (LEFT_GAP + RIGHT_GAP);
65 | d.height = viewportHeight + (TOP_GAP + BOTTOM_GAP);
66 | return d;
67 | }
68 |
69 | public Dimension getSize(Dimension rv) {
70 | super.getSize(rv);
71 | rv.width += (LEFT_GAP + RIGHT_GAP);
72 | rv.height = viewportHeight + (TOP_GAP + BOTTOM_GAP);
73 | return rv;
74 | }
75 |
76 | public void paint(Graphics g) {
77 | Shape clip = g.getClip();
78 |
79 | // Draw the outer border
80 | g.drawRect(0, 0, super.getMinimumSize().width + (LEFT_GAP + RIGHT_GAP), viewportHeight + (TOP_GAP + BOTTOM_GAP));
81 |
82 | // Clip g to viewport
83 | g.clipRect(LEFT_GAP, TOP_GAP, super.getMinimumSize().width, viewportHeight);
84 | // Translate g to the current vertical scroll level
85 | g.translate(LEFT_GAP, -180);
86 | // Paint the underlying KPanel onto the viewport
87 | super.paint(g);
88 |
89 | // Restore the original clip
90 | Rectangle r = g.getClipBounds();
91 | g.setClip(clip);
92 |
93 | // Draw the viewport border.
94 | g.drawRect(r.x, r.y, r.width, r.height);
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/src/org/kwt/ui/KWTCheckbox.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2010 Dan Fabulich.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License").
5 | * You may not use this file except in compliance with the License.
6 | * A copy of the License is located in the LICENSE file included with this
7 | * distribution.
8 | *
9 | * This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
10 | * CONDITIONS OF ANY KIND, either express or implied. See the License
11 | * for the specific language governing permissions and limitations under the
12 | * License.
13 | */
14 |
15 | package org.kwt.ui;
16 |
17 | import java.awt.Color;
18 | import java.awt.Dimension;
19 | import java.awt.Graphics;
20 | import java.awt.event.ActionEvent;
21 | import java.awt.event.ActionListener;
22 |
23 | import com.amazon.kindle.kindlet.ui.KButton;
24 |
25 | /**
26 | * A custom checkbox. If the KWTCheckbox belongs to an instance of a KWTCheckboxGroup, it will behave
27 | * and look like a radio button; otherwise, it will be a simple toggleable checkbox.
28 | *
29 | *
31 | *
32 | * @author Dan Fabulich
33 | *
34 | */
35 | public class KWTCheckbox extends KButton implements ActionListener {
36 | private static final long serialVersionUID = 8105922331821759692L;
37 |
38 | private boolean selected = false;
39 | final KWTCheckboxGroup group;
40 |
41 | // TODO: Make these values styleable.
42 | private static final int padding = 1, border = 2;
43 |
44 | private boolean isRadioButton() {
45 | return group != null;
46 | }
47 |
48 | /**
49 | * Returns whether the box is checked.
50 | *
51 | * @return whether the box is checked
52 | */
53 | public boolean isSelected() {
54 | return selected;
55 | }
56 |
57 | /** Toggle the state of this box. If it belongs to a KWTCheckboxGroup, it will deselect the currently
58 | * selected box in that group.
59 | *
60 | * @param selected whether to select or deselect this box.
61 | */
62 | public void setSelected(boolean selected) {
63 | if (this.selected == selected) return;
64 | if (selected && group != null) group.setSelected(this);
65 | this.selected = selected;
66 | repaint();
67 | }
68 |
69 | /**
70 | * Constructs a new checkbox. It will be a toggleable checkbox not belonging to a group.
71 | */
72 | public KWTCheckbox() {
73 | this(null);
74 | }
75 |
76 | /** Constructs a radio button belonging to a group.
77 | *
78 | * @param group the group this radio button will belong to
79 | */
80 | public KWTCheckbox(KWTCheckboxGroup group) {
81 | this.group = group;
82 | addActionListener(this);
83 | }
84 |
85 | /**
86 | * {@inheritDoc }
87 | */
88 | public Dimension getPreferredSize() {
89 | return getMinimumSize();
90 | }
91 |
92 | /**
93 | * {@inheritDoc }
94 | */
95 | public Dimension getMinimumSize() {
96 | int d = getFontMetrics(getFont()).getMaxAscent();
97 | d += (padding + border) * 2;
98 | return new Dimension(d, d);
99 | }
100 |
101 | /**
102 | * {@inheritDoc }
103 | */
104 | public void paint(Graphics g) {
105 | // Max Ascent ~ maximum height of a letter from the baseline
106 | // We'll use maxAscent to size our checkbox
107 | int maxAscent = g.getFontMetrics().getMaxAscent();
108 | int diameter = maxAscent - border;
109 |
110 | int x = padding + border;
111 | int y = padding + border;
112 |
113 | g.setColor(Color.black);
114 | if (isRadioButton()) {
115 | if (selected) g.fillOval(x, y, diameter, diameter);
116 | g.drawOval(x, y, diameter, diameter);
117 | } else {
118 | // checkbox
119 | if (selected) {
120 | // draw X
121 | g.drawLine(x, y, x+diameter, y+diameter);
122 | g.drawLine(x, y+diameter, x+diameter, y);
123 | }
124 | g.drawRect(x, y, diameter, diameter);
125 | }
126 |
127 | if (!isFocusOwner()) {
128 | g.setColor(Color.white);
129 | }
130 | for (int i = 0; i < border; i++) {
131 | // Draw the border as a sequence of self-contained rectangles
132 | // The first border is the full size, the next border is 1px smaller, and so on
133 | int rectWidth = diameter + 2 * (padding + border - i);
134 | g.drawRect(i, i, rectWidth, rectWidth);
135 | }
136 | }
137 |
138 | /**
139 | * Called when the checkbox is toggled by the user. This method should never be called by
140 | * client code.
141 | *
142 | * @param event the event that toggled this action
143 | */
144 | public void actionPerformed(ActionEvent event) {
145 | if (isRadioButton() && selected) return; // can't deselect last radio button
146 | setSelected(!selected);
147 | }
148 |
149 |
150 | }
151 |
--------------------------------------------------------------------------------
/src/org/kwt/ui/KWTProgressBar.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2010 Adrian Petrescu.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License").
5 | * You may not use this file except in compliance with the License.
6 | * A copy of the License is located in the LICENSE file included with this
7 | * distribution.
8 | *
9 | * This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
10 | * CONDITIONS OF ANY KIND, either express or implied. See the License
11 | * for the specific language governing permissions and limitations under the
12 | * License.
13 | */
14 |
15 | package org.kwt.ui;
16 |
17 | import java.awt.Color;
18 | import java.awt.Dimension;
19 | import java.awt.Graphics;
20 |
21 | import org.kwt.InvalidStyleException;
22 |
23 | import com.amazon.kindle.kindlet.ui.KComponent;
24 |
25 | /**
26 | * A progress bar. Represents the proportion of progress towards completing a particular task. Meant
27 | * to emulate the book progress bar at the bottom of the regular Kindle reader application.
28 | *
29 | *
31 | *
32 | * @author Adrian Petrescu
33 | *
34 | */
35 | public class KWTProgressBar extends KComponent {
36 | private static final long serialVersionUID = 5781953629278873008L;
37 |
38 | private static final int VERTICAL_PADDING = 3;
39 | private static final int HORIZONTAL_PADDING = 10;
40 | private static final int CORNER_ROUNDING = 10;
41 |
42 | /** An empty style. */
43 | public static final int STYLE_NONE = 0;
44 | /** A percentage description of progress */
45 | public static final int STYLE_PERCENTAGE = 1;
46 | /** A fractional description of progress */
47 | public static final int STYLE_TOTAL = 2;
48 |
49 | private int width;
50 | private int labelStyle = STYLE_PERCENTAGE;
51 | private int totalTicks;
52 | private int currentTick;
53 |
54 | /**
55 | * Constructs a new progress bar, with 100 total ticks. The current tick begins at 0.
56 | */
57 | public KWTProgressBar() {
58 | this(100);
59 | }
60 |
61 | /**
62 | * Constructs a new progress bar. The current tick begins at 0.
63 | *
64 | * @param totalTicks The total number of ticks representing completion of the task.
65 | */
66 | public KWTProgressBar(int totalTicks) {
67 | this.totalTicks = totalTicks;
68 | this.currentTick = 0;
69 |
70 | this.setFocusable(false);
71 | }
72 |
73 | /**
74 | * Returns the total number of ticks.
75 | *
76 | * @return the total number of ticks.
77 | */
78 | public int getTotalTicks() {
79 | return totalTicks;
80 | }
81 |
82 | /**
83 | * Sets the total number of ticks. If the current tick is larger than totalTicks,
84 | * then it is set to totalTicks.
85 | *
86 | * @param totalTicks the total number of ticks representing completion of the task.
87 | */
88 | public void setTotalTicks(int totalTicks) {
89 | this.totalTicks = totalTicks;
90 |
91 | // Make sure current tick is not beyond the maximum value.
92 | setCurrentTick(currentTick);
93 | }
94 |
95 | /**
96 | * Returns the current tick.
97 | *
98 | * @return the current tick.
99 | */
100 | public int getCurrentTick() {
101 | return currentTick;
102 | }
103 |
104 | /**
105 | * Sets the current tick. If currentTick < 0 or
106 | * currentTick > totalTicks, then currentTick
107 | * will be set to 0 or totalTicks respectively.
108 | *
109 | * @param currentTick the current tick.
110 | */
111 | public void setCurrentTick(int currentTick) {
112 | this.currentTick = Math.min(totalTicks, Math.max(0, currentTick));
113 | }
114 |
115 | /**
116 | * Increments the current tick by 1. If the current tick is already at
117 | * the maximum value, this does nothing.
118 | */
119 | public void incrementTick() {
120 | if (currentTick < totalTicks) currentTick += 1;
121 | }
122 |
123 | /**
124 | * Decrements the current tick by 1. If the current tick is already at
125 | * 0, this does nothing.
126 | */
127 | public void decrementTick() {
128 | if (currentTick > 0) currentTick -= 1;
129 | }
130 |
131 | /**
132 | * Returns the style of label to be used. Valid options are:
133 | * STYLE_NONE - no label will be shown.
135 | * STYLE_PERCENTAGE - the label will display a percentage of completion.
136 | * STYLE_TOTAL - the label will display a fraction of totalTicks
137 | * STYLE_NONE - no label will be shown.
149 | * STYLE_PERCENTAGE - the label will display a percentage of completion.
150 | * STYLE_TOTAL - the label will display a fraction of totalTicks
151 | * style is not one of the allowed values.
155 | */
156 | public void setLabelStyle(int style) throws InvalidStyleException {
157 | if (style < STYLE_NONE || style > STYLE_TOTAL)
158 | throw new InvalidStyleException(this.getClass().getName() +
159 | " does not support the given style for highlighting.", style);
160 | labelStyle = style;
161 | }
162 |
163 | /**
164 | * {@inheritDoc }
165 | */
166 | public Dimension getPreferredSize() {
167 | Dimension d = getMinimumSize();
168 | d.width = Math.max(width, d.width);
169 | return d;
170 | }
171 |
172 | /**
173 | * {@inheritDoc }
174 | */
175 | public Dimension getMinimumSize() {
176 | return new Dimension(getMinimumWidth() + 2 * HORIZONTAL_PADDING,
177 | getMinimumHeight() + 2 * VERTICAL_PADDING);
178 | }
179 |
180 | /**
181 | * Sets the width (in pixels) of this component.
182 | * @param width the width (in pixels) of this component.
183 | */
184 | public void setWidth(int width) {
185 | this.width = width;
186 | }
187 |
188 | /**
189 | * {@inheritDoc }
190 | */
191 | public void paint(Graphics g) {
192 | double progress = (double) currentTick / totalTicks;
193 | g.drawRoundRect(0, 0, getWidth() - 1, getHeight() - 1, CORNER_ROUNDING, CORNER_ROUNDING);
194 | g.setColor(Color.BLACK);
195 | g.fillRoundRect(0, 0, (int) (progress * getWidth()) - 1, getHeight() - 1, CORNER_ROUNDING, CORNER_ROUNDING);
196 |
197 | if (labelStyle == STYLE_PERCENTAGE || labelStyle == STYLE_TOTAL) {
198 | String progressString = "";
199 | switch (labelStyle) {
200 | case STYLE_PERCENTAGE:
201 | progressString = ((int) (progress * 100)) + "%";
202 | break;
203 | case STYLE_TOTAL:
204 | progressString = currentTick + "/" + totalTicks;
205 | }
206 | g.setXORMode(Color.WHITE);
207 | g.drawString(progressString,
208 | ((getWidth() - 1) / 2) - (getFontMetrics(getFont()).stringWidth(progressString) / 2),
209 | getFontMetrics(getFont()).getHeight());
210 | }
211 | }
212 |
213 | private int getMinimumHeight() {
214 | switch (labelStyle) {
215 | case STYLE_NONE: return 0;
216 | case STYLE_PERCENTAGE:
217 | case STYLE_TOTAL:
218 | default:
219 | return getFontMetrics(getFont()).getHeight();
220 | }
221 | }
222 |
223 | private int getMinimumWidth() {
224 | switch (labelStyle) {
225 | case STYLE_NONE: return 0;
226 | case STYLE_PERCENTAGE:
227 | return getFontMetrics(getFont()).stringWidth("100%");
228 | case STYLE_TOTAL:
229 | String longest = String.valueOf(totalTicks);
230 | longest = longest + "/" + longest;
231 | return getFontMetrics(getFont()).stringWidth(longest);
232 | }
233 |
234 | return 0;
235 | }
236 | }
237 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 |
4 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
5 |
6 | 1. Definitions.
7 |
8 | "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
9 |
10 | "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
11 |
12 | "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
13 |
14 | "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
15 |
16 | "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
17 |
18 | "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
19 |
20 | "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
21 |
22 | "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
23 |
24 | "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
25 |
26 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
27 |
28 | 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
29 |
30 | 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
31 |
32 | 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
33 |
34 | 1. You must give any other recipients of the Work or Derivative Works a copy of this License; and
35 | 2. You must cause any modified files to carry prominent notices stating that You changed the files; and
36 | 3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
37 | 4. If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
38 |
39 | You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
40 |
41 | 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
42 |
43 | 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
44 |
45 | 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
46 |
47 | 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
48 |
49 | 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
50 |
51 | END OF TERMS AND CONDITIONS
52 |
53 | Note: Other license terms may apply to certain, identified software files contained within or distributed with the accompanying software if such terms are included in the directory containing the accompanying software. Such other license terms will then apply in lieu of the terms of the software license above.
--------------------------------------------------------------------------------
/src/org/kwt/ui/KWTSelectableLabel.java:
--------------------------------------------------------------------------------
1 | package org.kwt.ui;
2 |
3 | import java.awt.AWTEvent;
4 | import java.awt.Color;
5 | import java.awt.Dimension;
6 | import java.awt.Graphics;
7 | import java.awt.event.ActionEvent;
8 | import java.awt.event.ActionListener;
9 | import java.awt.event.KeyEvent;
10 |
11 | import java.util.Iterator;
12 | import java.util.LinkedList;
13 | import java.util.List;
14 |
15 | import org.kwt.InvalidStyleException;
16 |
17 | import com.amazon.kindle.kindlet.ui.KLabel;
18 |
19 | /**
20 | * A selectable KLabel that can be focusable and receive ActionEvents. Intended to be sometimes
21 | * used in lieu of a KButton.
22 | *
23 | *
25 | *
26 | * @author Adrian Petrescu
27 | *
28 | */
29 | public class KWTSelectableLabel extends KLabel {
30 | private static final long serialVersionUID = 8118660222383683366L;
31 |
32 | private static final int BUTTON_DOWN_EVENT = 401;
33 | private static final int SELECT_BUTTON_KEY = 61451;
34 | private static final int DEFAULT_UNDERLINE_WIDTH = 5;
35 | private static final int DEFAULT_UNDERLINE_GAP = 2;
36 |
37 | /** An empty style */
38 | public static final int STYLE_NONE = 0;
39 | /** A solid style in the foreground color */
40 | public static final int STYLE_SOLID = 1;
41 | /** A dashed line in the foreground color */
42 | public static final int STYLE_DASHED = 2;
43 |
44 | private List actionListeners;
45 | private int highlightStyle = STYLE_NONE;
46 | private int underlineStyle = STYLE_SOLID;
47 | private int underlineWidth = DEFAULT_UNDERLINE_WIDTH;
48 | private int underlineGap = DEFAULT_UNDERLINE_GAP;
49 |
50 | /* This is a dirty hack to get around the fact that KLabels do not respond to setPosition().
51 | * Instead, when painting the superclass, we have to trick it into thinking its size is smaller
52 | * than it actually is. However, we don't want this faulty size to be read at any other time.
53 | * Hence this flag for when to spoof the size.
54 | */
55 | private boolean spoofSize = false;
56 |
57 | /**
58 | * Constructs a new selectable label with no text.
59 | */
60 | public KWTSelectableLabel() {
61 | this(null);
62 | }
63 |
64 | /**
65 | * Constructs a new selectable label with the given text. The text will be clipped if it extends
66 | * past the label's maximum size.
67 | *
68 | * @param text the label's text
69 | */
70 | public KWTSelectableLabel(String text) {
71 | super(text);
72 | enableEvents(AWTEvent.KEY_EVENT_MASK);
73 | setFocusable(true);
74 | actionListeners = new LinkedList();
75 | }
76 |
77 | /**
78 | * Returns the style of highlighting to be used when the label has the focus. Valid results are:
79 | * STYLE_NONE - the label will not be highlighted at all
81 | * STYLE_SOLID - the label will have an inverted foreground and background color.
82 | * STYLE_NONE - the label will not be highlighted at all
94 | * STYLE_SOLID - the label will have an inverted foreground and background color.
95 | * style is not one of the allowed values.
99 | */
100 | public void setHighlightStyle(int style) throws InvalidStyleException {
101 | if (style < STYLE_NONE || style > STYLE_SOLID)
102 | throw new InvalidStyleException(this.getClass().getName() +
103 | " does not support the given style for highlighting.", style);
104 | highlightStyle = style;
105 | }
106 |
107 | /**
108 | * Returns the style of underlining to be used when the label has the focus. Valid results are:
109 | * STYLE_NONE - the label will not be underlined at all
111 | * STYLE_SOLID - the label will be underlined by a solid line
112 | * STYLE_DASHED - the label will be underlined by a dashed line
113 | * STYLE_NONE - the label will not be underlined at all
125 | * STYLE_SOLID - the label will be underlined by a solid line
126 | * STYLE_DASHED - the label will be underlined by a dashed line
127 | * STYLE_NONE
141 | *
142 | * @return the width of the underline
143 | */
144 | public int getUnderlineWidth() {
145 | return underlineWidth;
146 | }
147 |
148 | /**
149 | * Sets the width of the underline, assuming the style provides one.
150 | *
151 | * @param width the width of the underline
152 | */
153 | public void setUnderlineWidth(int width) {
154 | underlineWidth = width;
155 | }
156 |
157 | /**
158 | * Sets the gap between the bottom of the label's text and the top of the underline, assuming the style
159 | * provides one. Note that the gap takes into account the maximum descent of the text's font.
160 | *
161 | * @param gap the gap between the label and the underline
162 | */
163 | public void setUnderlineGap(int gap) {
164 | underlineGap = gap;
165 | }
166 |
167 | /**
168 | * Returns the gap between the bottom of the label's text and the top of the underline, assuming the style
169 | * provides one. Note that the gap takes into account hte maximum descent of the text's font.
170 | *
171 | * @return the gap between the label and the underline
172 | */
173 | public int getUnderlineGap() {
174 | return underlineGap;
175 | }
176 |
177 | /**
178 | * {@inheritDoc }
179 | */
180 | public Dimension getPreferredSize() {
181 | return getMinimumSize();
182 | }
183 |
184 | /**
185 | * {@inheritDoc }
186 | */
187 | public Dimension getMinimumSize() {
188 | // Use KLabel's preferred size for its minimum size, to work around a known bug in the KDK.
189 | Dimension d = super.getPreferredSize();
190 | if (spoofSize) return new Dimension(d.width, d.height - underlineGap - underlineWidth);
191 | return new Dimension(d.width, d.height + underlineGap + underlineWidth + 1);
192 | }
193 |
194 | /**
195 | * {@inheritDoc }
196 | */
197 | public Dimension getSize() {
198 | Dimension d = super.getSize();
199 | if (spoofSize) return new Dimension(d.width, d.height - underlineGap - underlineWidth);
200 | return new Dimension(d.width, d.height + underlineGap + underlineWidth + 1);
201 | }
202 |
203 | /**
204 | * {@inheritDoc }
205 | */
206 | public void paint(Graphics g) {
207 | spoofSize = true;
208 | super.paint(g);
209 | spoofSize = false;
210 | if (this.isFocusOwner()) {
211 | int y = super.getSize().height - (underlineGap + underlineWidth);
212 | g.setColor(Color.BLACK);
213 | switch (underlineStyle) {
214 | case STYLE_SOLID:
215 | g.fillRect(0, y + underlineGap, this.getWidth() - 1, underlineWidth - 1);
216 | break;
217 | case STYLE_DASHED:
218 | for (int i = 0; i <= (this.getWidth() - 1) / (underlineWidth - 1); i += 2) {
219 | g.fillRect(i * (underlineWidth - 1), y + underlineGap, underlineWidth - 1, underlineWidth - 1);
220 | }
221 | }
222 | }
223 | }
224 |
225 | /**
226 | * Registers a listener who wishes to be notified whenever this label is clicked by the user.
227 | *
228 | * @param listener a listener who wishes to be notified
229 | */
230 | public void addActionListener(ActionListener listener) {
231 | this.actionListeners.add(listener);
232 | }
233 |
234 | /**
235 | * {@inheritDoc }
236 | */
237 | protected void processEvent(AWTEvent e) {
238 | switch(e.getID()) {
239 | case BUTTON_DOWN_EVENT:
240 | if (((KeyEvent) e).getKeyCode() != SELECT_BUTTON_KEY) break;
241 | Iterator it = actionListeners.iterator();
242 | while (it.hasNext()) {
243 | ActionListener listener = (ActionListener) it.next();
244 | listener.actionPerformed(new ActionEvent(this, BUTTON_DOWN_EVENT, null));
245 | }
246 | break;
247 | default:
248 | break;
249 | }
250 | }
251 | }
252 |
--------------------------------------------------------------------------------
/samples/KWTCheckbox/build.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |