Source List item badging

August 24, 2008

Java application with source list item badges

Item badging is a clear, concise way to add amplifying information to an icon or even simple text. In Mail for Mac OS X, for example, when the user’s inbox has 10 unread messages a small overlay with the number “10” is shown beside the “Inbox” list item. The annotation’s meaning is both discoverable and learnable, because the ancillary information lives in the same space as item being annotated.

Mac OS X has a great implementation of badges, both for items in the dock as well as items in lists. Below is my implementation of Mac badging for lists in Java. Lets start by taking an up close look at the Mac OS X badge:

Source list item with badge

One of the key elements of the badge, is that the actual badge contents are punched out, that is, the “1” in the image above is actually formed by the absence of pixels, which lets the underlying gradient show through.

To get this effect, we have to draw the badge into an image buffer first so that we can then draw the text using the AlphaComposite.DstOut AlphaComposite, which will make the pixels in the image transparent (I briefly discussed this technique here). Note that we only use this punch-out effect when the list item is selected.

Here’s the code that draws a badge with a punched out number:

public class SourceListCountBadgeRenderer {

    private CustomJLabel fLabel = new CustomJLabel();
    private boolean fSelected = false;
    private static Font BADGE_FONT = new Font("Helvetica", Font.BOLD, 11);
    private static Color BADGE_SELECTED_BACKGROUND_COLOR = Color.WHITE;
    private static Color BADGE_UNSELECTED_BACKGROUND_COLOR = new Color(0x8899bc);
    private static Color BADGE_TEXT_COLOR = BADGE_SELECTED_BACKGROUND_COLOR;

    public SourceListCountBadgeRenderer() {
        fLabel.setFont(BADGE_FONT);
        fLabel.setBorder(BorderFactory.createEmptyBorder(0,6,0,6));
    }

    public void setState(int count, boolean selected) {
        fLabel.setText(String.valueOf(count));
        fSelected = selected;
    }

    public JComponent getComponent() {
        return fLabel;
    }

    // Custom JLabel. ///////////////////////////////////////////////////////

    private class CustomJLabel extends JLabel {
        @Override
        protected void paintComponent(Graphics g) {
            // create a buffered image to draw the component into. this lets us
            // draw "out" an area, making it transparent.
            BufferedImage image = new BufferedImage(getWidth(), getHeight(),
                    BufferedImage.TYPE_INT_ARGB);

            // create the graphics and set its initial state.
            Graphics2D g2d = image.createGraphics();
            g2d.setFont(getFont());
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setColor(fSelected
                    ? BADGE_SELECTED_BACKGROUND_COLOR
                    : BADGE_UNSELECTED_BACKGROUND_COLOR);

            // draw the badge.
            g2d.fillRoundRect(0,0,getWidth(),getHeight(),getHeight(),getHeight());

            // get the bounds of the badge text in order to calculate the center.
            Rectangle2D bounds =
                    g2d.getFontMetrics().getStringBounds(getText(), g2d);
            // set the color to use for the text - note this color is always
            // the same, though it won't always show because of the composite
            // set below.
            g2d.setColor(BADGE_TEXT_COLOR);
            // if the badge is selected, punch out the text so that the
            //    underlying color shows through as the font color.
            // else use use a standard alpha composite to simply draw on top of
            //    whatever is currently there.
            g2d.setComposite(fSelected
                    ? AlphaComposite.DstOut : AlphaComposite.SrcOver);
            // calculate the bottom left point to draw the text at.
            int x = getWidth()/2 - g2d.getFontMetrics().stringWidth(getText())/2;
            int y = getHeight()/2 + g2d.getFontMetrics().getAscent()/2;
            // draw the badge text.
            g2d.drawString(getText(), x, y);

            // draw the image into this component.
            g.drawImage(image, 0, 0, null);

            // dispose of the buffered image graphics.
            g2d.dispose();
        }
    }

Stay tuned for more demos on how to create a Mac OS X Source List.

Advertisements

5 Responses to “Source List item badging”

  1. Steve McLeod Says:

    I’m looking forward to your demo on creating a Mac OS X Source List using Java. I’m currently trying to do this myself but judging by your articles and screenshots, your solution will be of high fidelity.

  2. Ken Says:

    Hi Steve,

    High fidelity is the name of the game! The screen shot above provides a glimpse at what the SourceList looks like. All in all, its pretty close to the native SourceList, but there are a few areas that are just too hard to match (like the item indentation, which are excessive above). Other than a few minor differences, a great SourceList Java implementation is on the way!

    -Ken
    P.S. Also note the I’ll be showing how to create a SourceList button bar (see the screen shot above) in future weeks. See Building a placard style PopupButton for some tips on popup button portion, as well as the icons I’ve provided here.


  3. […] lists, letting you know how many unread emails or new podcasts you have. Yet, I’ve only found one tutorial for how to create them. While it’s an excellent overview, it’s written in Java, so it […]

  4. Fernando Says:

    A realy Nice work !!

    regards.


  5. […] https://explodingpixels.wordpress.com/2008/08/24/source-list-item-badging/ Un passo avanti rispetto all'esempio precedente. In questo caso è possibile aggiungere icone alle vocie e suppora i badges. […]


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: