Imported MultiLineLabel, Swing Component.
Added static general information labels to the overview tab.
This commit is contained in:
@ -265,6 +265,7 @@ public class Main {
|
||||
}*/
|
||||
|
||||
/*
|
||||
// Test shutdown - worked at one point :) Possibly now as well.
|
||||
System.out.println("\nSetRouterRunner: Shutdown ");
|
||||
try {
|
||||
SetRouterRunner.execute(ROUTER_RUNNER.SHUTDOWN);
|
||||
|
@ -1,23 +1,39 @@
|
||||
package net.i2p.itoopie.gui;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.EventQueue;
|
||||
|
||||
import info.monitorenter.gui.chart.Chart2D;
|
||||
import info.monitorenter.gui.chart.views.ChartPanel;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.event.ChangeEvent;
|
||||
|
||||
import net.i2p.itoopie.gui.component.BandwidthChart;
|
||||
import net.i2p.itoopie.gui.component.MultiLineLabel;
|
||||
import net.i2p.itoopie.gui.component.ParticipatingTunnelsChart;
|
||||
import net.i2p.itoopie.gui.component.TabLogoPanel;
|
||||
import net.i2p.itoopie.gui.component.multilinelabel.MultiLineLabelUI;
|
||||
import net.i2p.itoopie.i18n.Transl;
|
||||
|
||||
public class OverviewTab extends TabLogoPanel {
|
||||
JLabel lblI2P;
|
||||
JLabel lblVersion;
|
||||
JLabel lblVersionSpecified;
|
||||
JLabel lblStatus;
|
||||
JLabel lblStatusSpecified;
|
||||
JLabel lblUptime;
|
||||
JLabel lblUptimeSpecified;
|
||||
JLabel lblNetworkStatus;
|
||||
MultiLineLabel lblNetworkStatusSpecified;
|
||||
|
||||
public OverviewTab(String imageName) {
|
||||
super(imageName);
|
||||
super.setLayout(null);
|
||||
|
||||
|
||||
Chart2D bwChart = BandwidthChart.getChart();
|
||||
Chart2D partTunnelChart = ParticipatingTunnelsChart.getChart();
|
||||
ChartPanel pt = new ChartPanel(partTunnelChart);
|
||||
@ -25,20 +41,94 @@ public class OverviewTab extends TabLogoPanel {
|
||||
pt.setLocation(15, 10);
|
||||
pt.setBorder(BorderFactory.createLineBorder(Color.GRAY));
|
||||
ChartPanel cp = new ChartPanel(bwChart);
|
||||
cp.setSize(300,135);
|
||||
cp.setSize(300, 135);
|
||||
cp.setLocation(15, 155);
|
||||
cp.setBorder(BorderFactory.createLineBorder(Color.GRAY));
|
||||
|
||||
|
||||
add(pt);
|
||||
add(cp);
|
||||
|
||||
lblI2P = new JLabel();
|
||||
add(lblI2P);
|
||||
lblI2P.setBounds(285, 30, 100, 15);
|
||||
lblI2P.setText("I2P");
|
||||
lblI2P.setHorizontalAlignment(SwingConstants.RIGHT);
|
||||
|
||||
lblVersion = new JLabel();
|
||||
add(lblVersion);
|
||||
lblVersion.setBounds(285, 50, 100, 15);
|
||||
lblVersion.setText(Transl._("Version:"));
|
||||
lblVersion.setHorizontalAlignment(SwingConstants.RIGHT);
|
||||
|
||||
lblVersionSpecified = new JLabel();
|
||||
add(lblVersionSpecified);
|
||||
lblVersionSpecified.setBounds(395, 50, 140, 15);
|
||||
lblVersionSpecified.setHorizontalAlignment(SwingConstants.LEFT);
|
||||
lblVersionSpecified.setText("0.8.7-48rc"); // Delete Me
|
||||
|
||||
|
||||
lblUptime = new JLabel();
|
||||
add(lblUptime);
|
||||
lblUptime.setBounds(285, 70, 100, 15);
|
||||
lblUptime.setHorizontalAlignment(SwingConstants.RIGHT);
|
||||
lblUptime.setText(Transl._("Uptime:"));
|
||||
|
||||
lblUptimeSpecified = new JLabel();
|
||||
add(lblUptimeSpecified);
|
||||
lblUptimeSpecified.setBounds(395, 70, 140, 15);
|
||||
lblUptimeSpecified.setHorizontalAlignment(SwingConstants.LEFT);
|
||||
lblUptimeSpecified.setText("93 min"); // Delete Me
|
||||
|
||||
|
||||
lblStatus = new JLabel();
|
||||
add(lblStatus);
|
||||
lblStatus.setBounds(285, 90, 100, 15);
|
||||
lblStatus.setHorizontalAlignment(SwingConstants.RIGHT);
|
||||
lblStatus.setText(Transl._("Status:"));
|
||||
|
||||
lblStatusSpecified = new JLabel();
|
||||
add(lblStatusSpecified);
|
||||
lblStatusSpecified.setBounds(395, 90, 140, 15);
|
||||
lblStatusSpecified.setHorizontalAlignment(SwingConstants.LEFT);
|
||||
lblStatusSpecified.setText("Rejecting Tunnels"); // Delete Me
|
||||
|
||||
lblNetworkStatus = new JLabel();
|
||||
add(lblNetworkStatus);
|
||||
lblNetworkStatus.setBounds(285, 110, 100, 15);
|
||||
lblNetworkStatus.setHorizontalAlignment(SwingConstants.RIGHT);
|
||||
lblNetworkStatus.setText(Transl._("Netstatus:"));
|
||||
|
||||
lblNetworkStatusSpecified = new MultiLineLabel();
|
||||
add(lblNetworkStatusSpecified);
|
||||
lblNetworkStatusSpecified.setBounds(395, 110, 130, 60);
|
||||
lblNetworkStatusSpecified.setHorizontalAlignment(SwingConstants.LEFT);
|
||||
lblNetworkStatusSpecified.setVerticalTextAlignment(JLabel.TOP);
|
||||
lblNetworkStatusSpecified.setText("WARN-Firewalled with Inbound TCP Enabled".replace('-', ' ')); // Delete Me
|
||||
|
||||
validate();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void onTabFocus(ChangeEvent e) {
|
||||
System.out.println("OverviewTab onTabFocus()");
|
||||
|
||||
// Do thigns when shown?
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch the application.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
EventQueue.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
JFrame frame = new JFrame();
|
||||
frame.setBounds(0, 0, Main.FRAME_WIDTH, Main.FRAME_HEIGHT);
|
||||
OverviewTab window = new OverviewTab("itoopie-opaque12");
|
||||
frame.add(window);
|
||||
frame.setVisible(true);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
124
src/net/i2p/itoopie/gui/component/MultiLineLabel.java
Normal file
124
src/net/i2p/itoopie/gui/component/MultiLineLabel.java
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2009 Samuel Sjoberg
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
package net.i2p.itoopie.gui.component;
|
||||
|
||||
import java.awt.Rectangle;
|
||||
|
||||
import javax.swing.JLabel;
|
||||
|
||||
import net.i2p.itoopie.gui.component.multilinelabel.MultiLineLabelUI;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A {@link JLabel} with support for multi-line text that wraps when the line
|
||||
* doesn't fit in the available width. Multi-line text support is handled by the
|
||||
* {@link MultiLineLabelUI}, the default UI delegate of this component. The text
|
||||
* in the label can be horizontally and vertically aligned, relative to the
|
||||
* bounds of the component.
|
||||
*
|
||||
* @author Samuel Sjoberg, http://samuelsjoberg.com
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public class MultiLineLabel extends JLabel {
|
||||
|
||||
/** Default serial version UID. */
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** Horizontal text alignment. */
|
||||
private int halign = LEFT;
|
||||
|
||||
/** Vertical text alignment. */
|
||||
private int valign = CENTER;
|
||||
|
||||
/** Cache to save heap allocations. */
|
||||
private Rectangle bounds;
|
||||
|
||||
/**
|
||||
* Creates a new empty label.
|
||||
*/
|
||||
public MultiLineLabel() {
|
||||
super();
|
||||
setUI(MultiLineLabelUI.labelUI);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new label with <code>text</code> value.
|
||||
*
|
||||
* @param text
|
||||
* the value of the label
|
||||
*/
|
||||
public MultiLineLabel(String text) {
|
||||
this();
|
||||
setText(text);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public Rectangle getBounds() {
|
||||
if (bounds == null) {
|
||||
bounds = new Rectangle();
|
||||
}
|
||||
return super.getBounds(bounds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the vertical text alignment.
|
||||
*
|
||||
* @param alignment
|
||||
* vertical alignment
|
||||
*/
|
||||
public void setVerticalTextAlignment(int alignment) {
|
||||
firePropertyChange("verticalTextAlignment", valign, alignment);
|
||||
valign = alignment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the horizontal text alignment.
|
||||
*
|
||||
* @param alignment
|
||||
* horizontal alignment
|
||||
*/
|
||||
public void setHorizontalTextAlignment(int alignment) {
|
||||
firePropertyChange("horizontalTextAlignment", halign, alignment);
|
||||
halign = alignment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the vertical text alignment.
|
||||
*
|
||||
* @return vertical text alignment
|
||||
*/
|
||||
public int getVerticalTextAlignment() {
|
||||
return valign;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the horizontal text alignment.
|
||||
*
|
||||
* @return horizontal text alignment
|
||||
*/
|
||||
public int getHorizontalTextAlignment() {
|
||||
return halign;
|
||||
}
|
||||
}
|
345
src/net/i2p/itoopie/gui/component/multilinelabel/Effects.java
Normal file
345
src/net/i2p/itoopie/gui/component/multilinelabel/Effects.java
Normal file
@ -0,0 +1,345 @@
|
||||
package net.i2p.itoopie.gui.component.multilinelabel;
|
||||
|
||||
/*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2009 Samuel Sjoberg
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Color;
|
||||
import java.awt.Composite;
|
||||
import java.awt.GradientPaint;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.event.ComponentAdapter;
|
||||
import java.awt.event.ComponentEvent;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
|
||||
/**
|
||||
* Static graphics and look and feel effects.
|
||||
*
|
||||
* @author Samuel Sjoberg, http://samuelsjoberg.com
|
||||
* @version 1.3.0
|
||||
*/
|
||||
public final class Effects {
|
||||
|
||||
/** Prevent initialization. */
|
||||
private Effects() {
|
||||
}
|
||||
|
||||
/** Text drop shadow size. */
|
||||
public static final int TEXT_SHADOW_SIZE = 2;
|
||||
|
||||
/**
|
||||
* Set the color to black with given alpha value.
|
||||
*
|
||||
* @param g
|
||||
* the graphics to paint on
|
||||
* @param alpha
|
||||
* the alpha value between 0-1.
|
||||
*/
|
||||
public static void setAlpha(Graphics g, float alpha) {
|
||||
g.setColor(new Color(0, 0, 0, Math.round(255 * alpha)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the alpha channel from the passed color.
|
||||
*
|
||||
* @param c
|
||||
* a color
|
||||
* @return the same color, but without an alpha channel
|
||||
*/
|
||||
public static Color removeAlpha(Color c) {
|
||||
if (c.getAlpha() != 100) {
|
||||
c = new Color(c.getRGB());
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a string with a blur or shadow effect. The light angle is assumed to
|
||||
* be 0 degrees, (i.e., window is illuminated from top). The effect is
|
||||
* intended to be subtle to be usable in as many text components as
|
||||
* possible. The effect is generated with multiple calls to draw string.
|
||||
* This method paints the text on coordinates <code>tx</code>,
|
||||
* <code>ty</code>. If text should be painted elsewhere, a transform should
|
||||
* be applied to the graphics before passing it.
|
||||
* <p>
|
||||
* All modifications to the graphics object is restored by this method
|
||||
* before returning.
|
||||
* <p>
|
||||
* Based on code by Romain Guy, {@linkplain http://filthyrichclients.org/},
|
||||
* see examples from chapter 16.
|
||||
*
|
||||
* @param g
|
||||
* graphics component to paint on
|
||||
* @param s
|
||||
* the string to paint
|
||||
* @param c
|
||||
* effect color
|
||||
* @param size
|
||||
* effect size
|
||||
* @param tx
|
||||
* x-coordinate translation (i.e, pixels to move the center of
|
||||
* the x-axis)
|
||||
* @param ty
|
||||
* y-coordinate translation (i.e, pixels to move the center of
|
||||
* the y-axis)
|
||||
* @param isShadow
|
||||
* <code>true</code> if this is a shadow being painted that
|
||||
* should be slightly offset to look more like a shadow being
|
||||
* casted, otherwise <code>false</code>.
|
||||
*/
|
||||
private static void paintTextEffect(Graphics2D g, String s, Color c,
|
||||
int size, double tx, double ty, boolean isShadow) {
|
||||
|
||||
prepareGraphics(g);
|
||||
|
||||
final float opacity = 0.8f; // Effect "darkness".
|
||||
final Composite oldComposite = g.getComposite();
|
||||
final Color oldColor = g.getColor();
|
||||
|
||||
// Use a alpha blend smaller than 1 to prevent the effect from becoming
|
||||
// too dark when multiple paints occur on top of each other.
|
||||
float preAlpha = 0.4f;
|
||||
if (oldComposite instanceof AlphaComposite
|
||||
&& ((AlphaComposite) oldComposite).getRule() == AlphaComposite.SRC_OVER) {
|
||||
preAlpha = Math.min(((AlphaComposite) oldComposite).getAlpha(),
|
||||
preAlpha);
|
||||
}
|
||||
g.setColor(c);
|
||||
|
||||
g.translate(tx, ty);
|
||||
|
||||
// If the effect is a shadow it looks better to stop painting a bit to
|
||||
// early... (shadow will look softer).
|
||||
int maxSize = isShadow ? size - 1 : size;
|
||||
|
||||
for (int i = -size; i <= maxSize; i++) {
|
||||
for (int j = -size; j <= maxSize; j++) {
|
||||
double distance = i * i + j * j;
|
||||
float alpha = opacity;
|
||||
if (distance > 0.0d) {
|
||||
alpha = (float) (1.0f / ((distance * size) * opacity));
|
||||
}
|
||||
alpha *= preAlpha;
|
||||
if (alpha > 1.0f) {
|
||||
alpha = 1.0f;
|
||||
}
|
||||
g.setComposite(AlphaComposite.getInstance(
|
||||
AlphaComposite.SRC_OVER, alpha));
|
||||
g.drawString(s, i + size, j + size);
|
||||
}
|
||||
}
|
||||
|
||||
// Restore graphics
|
||||
g.translate(-tx, -ty);
|
||||
g.setComposite(oldComposite);
|
||||
g.setColor(oldColor);
|
||||
|
||||
g.drawString(s, 0, 0);
|
||||
}
|
||||
|
||||
private static void prepareGraphics(Graphics2D g) {
|
||||
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
|
||||
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a string with a drop shadow. The light angle is assumed to be 0
|
||||
* degrees, (i.e., window is illuminated from top) and the shadow size is 2,
|
||||
* with a 1 pixel vertical displacement. The shadow is intended to be subtle
|
||||
* to be usable in as many text components as possible. The shadow is
|
||||
* generated with multiple calls to draw string. This method paints the text
|
||||
* on coordinates 0, 1. If text should be painted elsewhere, a transform
|
||||
* should be applied to the graphics before passing it.
|
||||
* <p>
|
||||
* All modifications to the graphics object is restored by this method
|
||||
* before returning.
|
||||
*
|
||||
* @see #paintTextEffect(Graphics2D, String, Color, int, boolean)
|
||||
*
|
||||
* @param g
|
||||
* graphics component to paint on
|
||||
* @param s
|
||||
* the string to paint
|
||||
* @param c
|
||||
* the color of the shadow. Any alpha channel will be discarded
|
||||
*/
|
||||
public static void paintTextShadow(Graphics2D g, String s, Color c) {
|
||||
paintTextEffect(g, s, removeAlpha(c), TEXT_SHADOW_SIZE,
|
||||
-TEXT_SHADOW_SIZE, 1 - TEXT_SHADOW_SIZE, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a string with a drop shadow. The light angle is assumed to be 0
|
||||
* degrees, (i.e., window is illuminated from top) and the shadow size is 2,
|
||||
* with a 1 pixel vertical displacement. The shadow is intended to be subtle
|
||||
* to be usable in as many text components as possible. The shadow is
|
||||
* generated with multiple calls to draw string. This method paints the text
|
||||
* on coordinates 0, 1. If text should be painted elsewhere, a transform
|
||||
* should be applied to the graphics before passing it.
|
||||
* <p>
|
||||
* All modifications to the graphics object is restored by this method
|
||||
* before returning.
|
||||
*
|
||||
* @see #paintTextEffect(Graphics2D, String, Color, int, boolean)
|
||||
*
|
||||
* @param g
|
||||
* graphics component to paint on
|
||||
* @param s
|
||||
* the string to paint
|
||||
*/
|
||||
public static void paintTextShadow(Graphics2D g, String s) {
|
||||
paintTextShadow(g, s, Color.BLACK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a string with a glow effect. Glow differs from a drop shadow in that
|
||||
* it isn't offset in any direction (i.e., not affected by
|
||||
* "lighting conditions").
|
||||
* <p>
|
||||
* All modifications to the graphics object is restored by this method
|
||||
* before returning.
|
||||
*
|
||||
* @param g
|
||||
* graphics component to paint on
|
||||
* @param s
|
||||
* the string to draw
|
||||
* @param glow
|
||||
* the solid glow color. Do not use the alpha channel as this
|
||||
* will be discarded
|
||||
*/
|
||||
public static void paintTextGlow(Graphics2D g, String s, Color glow) {
|
||||
paintTextEffect(g, s, removeAlpha(glow), TEXT_SHADOW_SIZE,
|
||||
-TEXT_SHADOW_SIZE, -TEXT_SHADOW_SIZE, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility to assist with painting of a vertical gradient. The opaque
|
||||
* property of the component being painted is not honored. If
|
||||
* {@link #paint(Graphics, JComponent)} is invoked a gradient background is
|
||||
* always painted.
|
||||
* <p>
|
||||
* <strong>A note on cyclic gradients:</strong><br>
|
||||
* Cyclic gradients yields better performance, however they cannot be safely
|
||||
* used to paint backgrounds on components that perform partial repaints
|
||||
* (e.g., <code>JList</code>). Cyclic gradients can be turned on using
|
||||
* {@link #setCyclic(boolean)} but are not used by default in this painter.
|
||||
*
|
||||
* @author Samuel Sjoberg, Extenda AB
|
||||
*/
|
||||
public static class GradientPainter {
|
||||
|
||||
/** Start color. */
|
||||
private Color c1;
|
||||
|
||||
/** End color. */
|
||||
private Color c2;
|
||||
|
||||
/** Cached gradient paint. */
|
||||
private GradientPaint paint;
|
||||
|
||||
/** Cyclic gradient. */
|
||||
private boolean cyclic = false;
|
||||
|
||||
/**
|
||||
* Create a new <code>GradientPainter</code> using the background color
|
||||
* of the passed component. The gradient will fade from the background
|
||||
* color in to a darker shade of the same color.
|
||||
*
|
||||
* @param c
|
||||
* the component owning the painter
|
||||
*/
|
||||
public GradientPainter(JComponent c) {
|
||||
this(c, c.getBackground(), c.getBackground().darker().darker());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new <code>GradientPainter</code> using the passed colors.
|
||||
* The gradient will fade from <code>c1</code> to <code>c2</code>.
|
||||
*
|
||||
* @param c
|
||||
* the component owning the painter
|
||||
* @param c1
|
||||
* the start color
|
||||
* @param c2
|
||||
* the end color
|
||||
*/
|
||||
public GradientPainter(JComponent c, Color c1, Color c2) {
|
||||
this.c1 = c1;
|
||||
this.c2 = c2;
|
||||
c.addComponentListener(new ComponentAdapter() {
|
||||
public void componentResized(ComponentEvent e) {
|
||||
paint = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the gradient colors. For changes to take effect, the component
|
||||
* must be repainted by invoking e.g. {@link JComponent#repaint()}.
|
||||
*
|
||||
* @param c1
|
||||
* the start color
|
||||
* @param c2
|
||||
* the end color
|
||||
*/
|
||||
public void setColors(Color c1, Color c2) {
|
||||
this.c1 = c1;
|
||||
this.c2 = c2;
|
||||
paint = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use cyclic gradients. Default behavior is non-cyclic gradients.
|
||||
*
|
||||
* @param cyclic
|
||||
* If <code>true</code>, cyclic gradients a used, otherwise
|
||||
* non-cyclic gradients are used.
|
||||
*/
|
||||
public void setCyclic(boolean cyclic) {
|
||||
this.cyclic = cyclic;
|
||||
paint = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill the component with a gradient background. This method does not
|
||||
* honor the opaque property.
|
||||
*
|
||||
* @param g
|
||||
* graphics to paint upon
|
||||
* @param c
|
||||
* the component being painted
|
||||
*/
|
||||
public void paint(Graphics g, JComponent c) {
|
||||
if (paint == null) {
|
||||
paint = new GradientPaint(0, 0, c1, 0, c.getHeight(), c2,
|
||||
cyclic);
|
||||
}
|
||||
((Graphics2D) g).setPaint(paint);
|
||||
g.fillRect(0, 0, c.getWidth(), c.getHeight());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,608 @@
|
||||
package net.i2p.itoopie.gui.component.multilinelabel;
|
||||
|
||||
/*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2009 Samuel Sjoberg
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.event.ComponentListener;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.LabelUI;
|
||||
import javax.swing.plaf.basic.BasicLabelUI;
|
||||
import javax.swing.text.BadLocationException;
|
||||
import javax.swing.text.Document;
|
||||
import javax.swing.text.Element;
|
||||
import javax.swing.text.PlainDocument;
|
||||
import javax.swing.text.Segment;
|
||||
import javax.swing.text.Utilities;
|
||||
import javax.swing.text.View;
|
||||
|
||||
import net.i2p.itoopie.gui.component.MultiLineLabel;
|
||||
|
||||
|
||||
/**
|
||||
* Label UI delegate that supports multiple lines and line wrapping. Hard line
|
||||
* breaks (<code>\n</code>) are preserved. If the dimensions of the label is too
|
||||
* small to fit all content, the string will be clipped and "..." appended to
|
||||
* the end of the visible text (similar to the default behavior of
|
||||
* <code>JLabel</code>). If used in conjunction with a {@link MultiLineLabel},
|
||||
* text alignment (horizontal and vertical) is supported. The UI delegate can be
|
||||
* used on a regular <code>JLabel</code> if text alignment isn't required. The
|
||||
* default alignment, left and vertically centered, will then be used.
|
||||
* <p>
|
||||
* Example of usage:
|
||||
*
|
||||
* <pre>
|
||||
* JLabel myLabel = new JLabel();
|
||||
* myLabel.setUI(MultiLineLabelUI.labelUI);
|
||||
* myLabel.setText("A long label that will wrap automatically.");
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* The line and wrapping support is implemented without using a
|
||||
* <code>View</code> to make it easy for subclasses to add custom text effects
|
||||
* by overriding {@link #paintEnabledText(JLabel, Graphics, String, int, int)}
|
||||
* and {@link #paintDisabledText(JLabel, Graphics, String, int, int)}. This
|
||||
* class is designed to be easily extended by subclasses.
|
||||
*
|
||||
* @author Samuel Sjoberg, http://samuelsjoberg.com
|
||||
* @version 1.3.0
|
||||
*/
|
||||
public class MultiLineLabelUI extends BasicLabelUI implements ComponentListener {
|
||||
|
||||
/** Shared instance of the UI delegate. */
|
||||
public static LabelUI labelUI = new MultiLineLabelUI();
|
||||
|
||||
/**
|
||||
* Client property key used to store the calculated wrapped lines on the
|
||||
* JLabel.
|
||||
*/
|
||||
public static final String PROPERTY_KEY = "WrappedText";
|
||||
|
||||
// Static references to avoid heap allocations.
|
||||
protected static Rectangle paintIconR = new Rectangle();
|
||||
protected static Rectangle paintTextR = new Rectangle();
|
||||
protected static Rectangle paintViewR = new Rectangle();
|
||||
protected static Insets paintViewInsets = new Insets(0, 0, 0, 0);
|
||||
|
||||
/** Font metrics of the JLabel being rendered. */
|
||||
protected FontMetrics metrics;
|
||||
|
||||
/** Default size of the lines list. */
|
||||
protected static int defaultSize = 4;
|
||||
|
||||
/**
|
||||
* Get the shared UI instance.
|
||||
*
|
||||
* @param c
|
||||
* the component about to be installed
|
||||
* @return the shared UI delegate instance
|
||||
*/
|
||||
public static ComponentUI createUI(JComponent c) {
|
||||
return labelUI;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void uninstallDefaults(JLabel c) {
|
||||
super.uninstallDefaults(c);
|
||||
clearCache(c);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void installListeners(JLabel c) {
|
||||
super.installListeners(c);
|
||||
c.addComponentListener(this);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void uninstallListeners(JLabel c) {
|
||||
super.uninstallListeners(c);
|
||||
c.removeComponentListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the wrapped line cache.
|
||||
*
|
||||
* @param l
|
||||
* the label containing a cached value
|
||||
*/
|
||||
protected void clearCache(JLabel l) {
|
||||
l.putClientProperty(PROPERTY_KEY, null);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void propertyChange(PropertyChangeEvent e) {
|
||||
super.propertyChange(e);
|
||||
final String name = e.getPropertyName();
|
||||
if (name.equals("text") || "font".equals(name)) {
|
||||
clearCache((JLabel) e.getSource());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the paint rectangles for the icon and text for the passed
|
||||
* label.
|
||||
*
|
||||
* @param l
|
||||
* a label
|
||||
* @param fm
|
||||
* the font metrics to use, or <code>null</code> to get the font
|
||||
* metrics from the label
|
||||
* @param width
|
||||
* label width
|
||||
* @param height
|
||||
* label height
|
||||
*/
|
||||
protected void updateLayout(JLabel l, FontMetrics fm, int width, int height) {
|
||||
if (fm == null) {
|
||||
fm = l.getFontMetrics(l.getFont());
|
||||
}
|
||||
metrics = fm;
|
||||
|
||||
String text = l.getText();
|
||||
Icon icon = l.getIcon();
|
||||
Insets insets = l.getInsets(paintViewInsets);
|
||||
|
||||
paintViewR.x = insets.left;
|
||||
paintViewR.y = insets.top;
|
||||
paintViewR.width = width - (insets.left + insets.right);
|
||||
paintViewR.height = height - (insets.top + insets.bottom);
|
||||
|
||||
paintIconR.x = paintIconR.y = paintIconR.width = paintIconR.height = 0;
|
||||
paintTextR.x = paintTextR.y = paintTextR.width = paintTextR.height = 0;
|
||||
|
||||
layoutCL(l, fm, text, icon, paintViewR, paintIconR, paintTextR);
|
||||
}
|
||||
|
||||
protected void prepareGraphics(Graphics g) {
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void paint(Graphics g, JComponent c) {
|
||||
|
||||
// parent's update method fills the background
|
||||
prepareGraphics(g);
|
||||
|
||||
JLabel label = (JLabel) c;
|
||||
String text = label.getText();
|
||||
Icon icon = (label.isEnabled()) ? label.getIcon() : label
|
||||
.getDisabledIcon();
|
||||
|
||||
if ((icon == null) && (text == null)) {
|
||||
return;
|
||||
}
|
||||
|
||||
FontMetrics fm = g.getFontMetrics();
|
||||
|
||||
updateLayout(label, fm, c.getWidth(), c.getHeight());
|
||||
|
||||
if (icon != null) {
|
||||
icon.paintIcon(c, g, paintIconR.x, paintIconR.y);
|
||||
}
|
||||
|
||||
if (text != null) {
|
||||
View v = (View) c.getClientProperty("html");
|
||||
if (v != null) {
|
||||
// HTML view disables multi-line painting.
|
||||
v.paint(g, paintTextR);
|
||||
} else {
|
||||
// Paint the multi line text
|
||||
paintTextLines(g, label, fm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Paint the wrapped text lines.
|
||||
*
|
||||
* @param g
|
||||
* graphics component to paint on
|
||||
* @param label
|
||||
* the label being painted
|
||||
* @param fm
|
||||
* font metrics for current font
|
||||
*/
|
||||
protected void paintTextLines(Graphics g, JLabel label, FontMetrics fm) {
|
||||
List<String> lines = getTextLines(label);
|
||||
|
||||
// Available component height to paint on.
|
||||
int height = getAvailableHeight(label);
|
||||
|
||||
int textHeight = lines.size() * fm.getHeight();
|
||||
while (textHeight > height) {
|
||||
// Remove one line until no. of visible lines is found.
|
||||
textHeight -= fm.getHeight();
|
||||
}
|
||||
paintTextR.height = Math.min(textHeight, height);
|
||||
paintTextR.y = alignmentY(label, fm, paintTextR);
|
||||
|
||||
int textX = paintTextR.x;
|
||||
int textY = paintTextR.y;
|
||||
|
||||
for (Iterator<String> it = lines.iterator(); it.hasNext()
|
||||
&& paintTextR.contains(textX, textY + getAscent(fm)); textY += fm
|
||||
.getHeight()) {
|
||||
|
||||
String text = it.next().trim();
|
||||
|
||||
if (it.hasNext()
|
||||
&& !paintTextR.contains(textX, textY + fm.getHeight()
|
||||
+ getAscent(fm))) {
|
||||
// The last visible row, add a clip indication.
|
||||
text = clip(text, fm, paintTextR);
|
||||
}
|
||||
|
||||
int x = alignmentX(label, fm, text, paintTextR);
|
||||
|
||||
if (label.isEnabled()) {
|
||||
paintEnabledText(label, g, text, x, textY);
|
||||
} else {
|
||||
paintDisabledText(label, g, text, x, textY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the available height to paint text on. This is the height of the
|
||||
* passed component with insets subtracted.
|
||||
*
|
||||
* @param l
|
||||
* a component
|
||||
* @return the available height
|
||||
*/
|
||||
protected int getAvailableHeight(JLabel l) {
|
||||
l.getInsets(paintViewInsets);
|
||||
return l.getHeight() - paintViewInsets.top - paintViewInsets.bottom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a clip indication to the string. It is important that the string
|
||||
* length does not exceed the length or the original string.
|
||||
*
|
||||
* @param text
|
||||
* the to be painted
|
||||
* @param fm
|
||||
* font metrics
|
||||
* @param bounds
|
||||
* the text bounds
|
||||
* @return the clipped string
|
||||
*/
|
||||
protected String clip(String text, FontMetrics fm, Rectangle bounds) {
|
||||
// Fast and lazy way to insert a clip indication is to simply replace
|
||||
// the last characters in the string with the clip indication.
|
||||
// A better way would be to use metrics and calculate how many (if any)
|
||||
// characters that need to be replaced.
|
||||
if (text.length() < 3) {
|
||||
return "...";
|
||||
}
|
||||
return text.substring(0, text.length() - 3) + "...";
|
||||
}
|
||||
|
||||
/**
|
||||
* Establish the vertical text alignment. The default alignment is to center
|
||||
* the text in the label.
|
||||
*
|
||||
* @param label
|
||||
* the label to paint
|
||||
* @param fm
|
||||
* font metrics
|
||||
* @param bounds
|
||||
* the text bounds rectangle
|
||||
* @return the vertical text alignment, defaults to CENTER.
|
||||
*/
|
||||
protected int alignmentY(JLabel label, FontMetrics fm, Rectangle bounds) {
|
||||
final int height = getAvailableHeight(label);
|
||||
int textHeight = bounds.height;
|
||||
|
||||
if (label instanceof MultiLineLabel) {
|
||||
int align = ((MultiLineLabel) label).getVerticalTextAlignment();
|
||||
switch (align) {
|
||||
case JLabel.TOP:
|
||||
return getAscent(fm) + paintViewInsets.top;
|
||||
case JLabel.BOTTOM:
|
||||
return getAscent(fm) + height - paintViewInsets.top
|
||||
+ paintViewInsets.bottom - textHeight;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
// Center alignment
|
||||
int textY = paintViewInsets.top + (height - textHeight) / 2
|
||||
+ getAscent(fm);
|
||||
return Math.max(textY, getAscent(fm) + paintViewInsets.top);
|
||||
}
|
||||
|
||||
private static int getAscent(FontMetrics fm) {
|
||||
return fm.getAscent() + fm.getLeading();
|
||||
}
|
||||
|
||||
/**
|
||||
* Establish the horizontal text alignment. The default alignment is left
|
||||
* aligned text.
|
||||
*
|
||||
* @param label
|
||||
* the label to paint
|
||||
* @param fm
|
||||
* font metrics
|
||||
* @param s
|
||||
* the string to paint
|
||||
* @param bounds
|
||||
* the text bounds rectangle
|
||||
* @return the x-coordinate to use when painting for proper alignment
|
||||
*/
|
||||
protected int alignmentX(JLabel label, FontMetrics fm, String s,
|
||||
Rectangle bounds) {
|
||||
if (label instanceof MultiLineLabel) {
|
||||
int align = ((MultiLineLabel) label).getHorizontalTextAlignment();
|
||||
switch (align) {
|
||||
case JLabel.RIGHT:
|
||||
return bounds.x + paintViewR.width - fm.stringWidth(s);
|
||||
case JLabel.CENTER:
|
||||
return bounds.x + paintViewR.width / 2 - fm.stringWidth(s) / 2;
|
||||
default:
|
||||
return bounds.x;
|
||||
}
|
||||
}
|
||||
return bounds.x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the given string to see if it should be rendered as HTML. Code
|
||||
* based on implementation found in
|
||||
* <code>BasicHTML.isHTMLString(String)</code> in future JDKs.
|
||||
*
|
||||
* @param s
|
||||
* the string
|
||||
* @return <code>true</code> if string is HTML, otherwise <code>false</code>
|
||||
*/
|
||||
private static boolean isHTMLString(String s) {
|
||||
if (s != null) {
|
||||
if ((s.length() >= 6) && (s.charAt(0) == '<')
|
||||
&& (s.charAt(5) == '>')) {
|
||||
String tag = s.substring(1, 5);
|
||||
return tag.equalsIgnoreCase("html");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public Dimension getPreferredSize(JComponent c) {
|
||||
Dimension d = super.getPreferredSize(c);
|
||||
JLabel label = (JLabel) c;
|
||||
|
||||
if (isHTMLString(label.getText())) {
|
||||
return d; // HTML overrides everything and we don't need to process
|
||||
}
|
||||
|
||||
// Width calculated by super is OK. The preferred width is the width of
|
||||
// the unwrapped content as long as it does not exceed the width of the
|
||||
// parent container.
|
||||
|
||||
if (c.getParent() != null) {
|
||||
// Ensure that preferred width never exceeds the available width
|
||||
// (including its border insets) of the parent container.
|
||||
Insets insets = c.getParent().getInsets();
|
||||
Dimension size = c.getParent().getSize();
|
||||
if (size.width > 0) {
|
||||
// If width isn't set component shouldn't adjust.
|
||||
d.width = size.width - insets.left - insets.right;
|
||||
}
|
||||
}
|
||||
|
||||
updateLayout(label, null, d.width, d.height);
|
||||
|
||||
// The preferred height is either the preferred height of the text
|
||||
// lines, or the height of the icon.
|
||||
d.height = Math.max(d.height, getPreferredHeight(label));
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
/**
|
||||
* The preferred height of the label is the height of the lines with added
|
||||
* top and bottom insets.
|
||||
*
|
||||
* @param label
|
||||
* the label
|
||||
* @return the preferred height of the wrapped lines.
|
||||
*/
|
||||
protected int getPreferredHeight(JLabel label) {
|
||||
int numOfLines = getTextLines(label).size();
|
||||
Insets insets = label.getInsets(paintViewInsets);
|
||||
return numOfLines * metrics.getHeight() + insets.top + insets.bottom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lines of text contained in the text label. The prepared lines is
|
||||
* cached as a client property, accessible via {@link #PROPERTY_KEY}.
|
||||
*
|
||||
* @param l
|
||||
* the label
|
||||
* @return the text lines of the label.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected List<String> getTextLines(JLabel l) {
|
||||
List<String> lines = (List<String>) l.getClientProperty(PROPERTY_KEY);
|
||||
if (lines == null) {
|
||||
lines = prepareLines(l);
|
||||
l.putClientProperty(PROPERTY_KEY, lines);
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void componentHidden(ComponentEvent e) {
|
||||
// Don't care
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void componentMoved(ComponentEvent e) {
|
||||
// Don't care
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void componentResized(ComponentEvent e) {
|
||||
clearCache((JLabel) e.getSource());
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
public void componentShown(ComponentEvent e) {
|
||||
// Don't care
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the text lines for rendering. The lines are wrapped to fit in the
|
||||
* current available space for text. Explicit line breaks are preserved.
|
||||
*
|
||||
* @param l
|
||||
* the label to render
|
||||
* @return a list of text lines to render
|
||||
*/
|
||||
protected List<String> prepareLines(JLabel l) {
|
||||
List<String> lines = new ArrayList<String>(defaultSize);
|
||||
String text = l.getText();
|
||||
if (text == null) {
|
||||
return null; // Null guard
|
||||
}
|
||||
PlainDocument doc = new PlainDocument();
|
||||
try {
|
||||
doc.insertString(0, text, null);
|
||||
} catch (BadLocationException e) {
|
||||
return null;
|
||||
}
|
||||
Element root = doc.getDefaultRootElement();
|
||||
for (int i = 0, j = root.getElementCount(); i < j; i++) {
|
||||
wrap(lines, root.getElement(i));
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* If necessary, wrap the text into multiple lines.
|
||||
*
|
||||
* @param lines
|
||||
* line array in which to store the wrapped lines
|
||||
* @param elem
|
||||
* the document element containing the text content
|
||||
*/
|
||||
protected void wrap(List<String> lines, Element elem) {
|
||||
int p1 = elem.getEndOffset();
|
||||
Document doc = elem.getDocument();
|
||||
for (int p0 = elem.getStartOffset(); p0 < p1;) {
|
||||
int p = calculateBreakPosition(doc, p0, p1);
|
||||
try {
|
||||
lines.add(doc.getText(p0, p - p0));
|
||||
} catch (BadLocationException e) {
|
||||
throw new Error("Can't get line text. p0=" + p0 + " p=" + p);
|
||||
}
|
||||
p0 = (p == p0) ? p1 : p;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the position on which to break (wrap) the line.
|
||||
*
|
||||
* @param doc
|
||||
* the document
|
||||
* @param p0
|
||||
* start position
|
||||
* @param p1
|
||||
* end position
|
||||
* @return the actual end position, will be <code>p1</code> if content does
|
||||
* not need to wrap, otherwise it will be less than <code>p1</code>.
|
||||
*/
|
||||
protected int calculateBreakPosition(Document doc, int p0, int p1) {
|
||||
Segment segment = SegmentCache.getSegment();
|
||||
try {
|
||||
doc.getText(p0, p1 - p0, segment);
|
||||
} catch (BadLocationException e) {
|
||||
throw new Error("Can't get line text");
|
||||
}
|
||||
|
||||
int width = paintTextR.width;
|
||||
int p = p0
|
||||
+ Utilities.getBreakLocation(segment, metrics, 0, width, null,
|
||||
p0);
|
||||
SegmentCache.releaseSegment(segment);
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Static singleton {@link Segment} cache.
|
||||
*
|
||||
* @see javax.swing.text.SegmentCache
|
||||
*
|
||||
* @author Samuel Sjoberg
|
||||
*/
|
||||
protected static final class SegmentCache {
|
||||
|
||||
/** Reused segments. */
|
||||
private ArrayList<Segment> segments = new ArrayList<Segment>(2);
|
||||
|
||||
/** Singleton instance. */
|
||||
private static SegmentCache cache = new SegmentCache();
|
||||
|
||||
/** Private constructor. */
|
||||
private SegmentCache() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a <code>Segment</code>. When done, the <code>Segment</code>
|
||||
* should be recycled by invoking {@link #releaseSegment(Segment)}.
|
||||
*
|
||||
* @return a <code>Segment</code>.
|
||||
*/
|
||||
public static Segment getSegment() {
|
||||
int size = cache.segments.size();
|
||||
if (size > 0) {
|
||||
return cache.segments.remove(size - 1);
|
||||
}
|
||||
return new Segment();
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases a <code>Segment</code>. A segment should not be used after
|
||||
* it is released, and a segment should never be released more than
|
||||
* once.
|
||||
*/
|
||||
public static void releaseSegment(Segment segment) {
|
||||
segment.array = null;
|
||||
segment.count = 0;
|
||||
cache.segments.add(segment);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
package net.i2p.itoopie.gui.component.multilinelabel;
|
||||
|
||||
/*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2009 Samuel Sjoberg
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.LabelUI;
|
||||
|
||||
/**
|
||||
* <code>MultiLineLabelUI</code> that paints the text with a drop shadow.
|
||||
*
|
||||
* @see MultiLineLabelUI
|
||||
* @see Effects#paintTextShadow(Graphics2D, String)
|
||||
*
|
||||
* @author Samuel Sjoberg, http://samuelsjoberg.com
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public class MultiLineShadowUI extends MultiLineLabelUI {
|
||||
|
||||
/** Shared UI instance. */
|
||||
public static LabelUI labelUI = new MultiLineShadowUI();
|
||||
|
||||
/**
|
||||
* Get the shared UI instance.
|
||||
*
|
||||
* @param c
|
||||
* the component requesting a UI delegate
|
||||
* @return the shared UI instance.
|
||||
*/
|
||||
public static ComponentUI createUI(JComponent c) {
|
||||
return labelUI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Paint the text with a text effect.
|
||||
*
|
||||
* @param g
|
||||
* graphics component used to paint on
|
||||
* @param s
|
||||
* the string to paint
|
||||
* @param textX
|
||||
* the x coordinate
|
||||
* @param textY
|
||||
* the y coordinate
|
||||
*/
|
||||
private void paintText(Graphics g, String s, int textX, int textY) {
|
||||
g.translate(textX, textY);
|
||||
Effects.paintTextShadow((Graphics2D) g, s);
|
||||
g.translate(-textX, -textY);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void paintEnabledText(JLabel l, Graphics g, String s, int textX,
|
||||
int textY) {
|
||||
g.setColor(l.getForeground());
|
||||
paintText(g, s, textX, textY);
|
||||
}
|
||||
|
||||
/** {inheritDoc} */
|
||||
protected void paintDisabledText(JLabel l, Graphics g, String s, int textX,
|
||||
int textY) {
|
||||
g.setColor(l.getBackground().darker());
|
||||
paintText(g, s, textX, textY);
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
package net.i2p.itoopie.gui.component.multilinelabel;
|
||||
|
||||
/*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2009 Samuel Sjoberg
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.plaf.LabelUI;
|
||||
import javax.swing.plaf.basic.BasicLabelUI;
|
||||
|
||||
/**
|
||||
* Label UI delegate painting the text with a subtle drop shadow.
|
||||
*
|
||||
* @author Samuel Sjoberg, http://samuelsjoberg.com
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public class ShadowLabelUI extends BasicLabelUI {
|
||||
|
||||
/** Static reference to the UI. */
|
||||
public static LabelUI labelUI = new ShadowLabelUI();
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void installDefaults(JLabel c) {
|
||||
super.installDefaults(c);
|
||||
if (c.getBorder() == null) {
|
||||
c.setBorder(new EmptyBorder(2, 2, 2, 2));
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void paintDisabledText(JLabel l, Graphics g, String s, int textX,
|
||||
int textY) {
|
||||
g.setColor(l.getBackground().darker());
|
||||
g.translate(textX, textY);
|
||||
Effects.paintTextShadow((Graphics2D) g, s);
|
||||
g.translate(-textX, -textY);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void paintEnabledText(JLabel l, Graphics g, String s, int textX,
|
||||
int textY) {
|
||||
g.setColor(l.getForeground());
|
||||
g.translate(textX, textY);
|
||||
Effects.paintTextShadow((Graphics2D) g, s);
|
||||
g.translate(-textX, -textY);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user