/* This file is part of leafdigital leafChat. leafChat is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. leafChat is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with leafChat. If not, see <http://www.gnu.org/licenses/>. Copyright 2011 Samuel Marshall. */ package com.leafdigital.ui; import java.awt.*; import java.awt.image.BufferedImage; import java.util.*; import javax.swing.*; import com.leafdigital.ui.api.*; /** Toolbar at top of window */ public class ToolBar extends JPanel implements ThemeListener { /** Space between buttons */ private final static int BUTTONSPACING=4; /** Map of Tool -> ToolInfo */ private Map<Tool, ToolInfo> m = new HashMap<Tool, ToolInfo>(); /** UI singleton */ private UISingleton ui; private BufferedImage tileOriginal, tileStretched; private int tileHeight=-1; private int usedWidth = 0; ToolBar(UISingleton ui) { this.ui = ui; setLayout(null); setOpaque(false); setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2)); ui.informThemeListener(this); } @Override public void updateTheme(Theme t) { repaint(); } @Override protected void paintComponent(Graphics g) { BufferedImage tile = ui.getTheme().getImageProperty( "toolbar", "tilePic", false, null, null); if(tile==null) { // Fill background with default colour g.setColor(getBackground()); g.fillRect(0, 0, getWidth(), getHeight()); } else { if(tile!=tileOriginal || getHeight()!=tileHeight) { // Stretch image if needed tileOriginal = tile; if(tileOriginal.getHeight() == getHeight()) { tileStretched=tileOriginal; } else { tileStretched = new BufferedImage( tileOriginal.getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB); Graphics2D g2 = tileStretched.createGraphics(); g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); g2.drawImage(tileOriginal, 0, 0, tileStretched.getWidth(), tileStretched.getHeight(), 0, 0, tileOriginal.getWidth(), tileOriginal.getHeight(), null); } tileHeight=tileStretched.getHeight(); } // Draw background using tile for(int x=0; x<getWidth(); x+=tileStretched.getWidth()) { g.drawImage(tileStretched, x, 0, null); } } } @Override public Dimension getPreferredSize() { Insets i = getInsets(); ToolButton button = new ToolButton(ui); return new Dimension( usedWidth, button.getPreferredSize().height + i.top + i.bottom); } @Override public void setBounds(int x, int y, int width, int height) { super.setBounds(x, y, width, height); rearrangeTools(); } @Override public void validate() { super.validate(); rearrangeTools(); } void rearrangeTools() { UISingleton.runInSwing(new Runnable() { @Override public void run() { // Get list of tools and sort it by current position (note: we don't use // a sorted set because I'm not sure whether that handles position changing // after creation) ToolInfo[] tools = m.values().toArray(new ToolInfo[0]); Arrays.sort(tools); // Work out default/initial positions Insets i = getInsets(); int x=i.left, y=i.top, height=getHeight()-i.top-i.bottom; // For each tool, add it if necessary and update position for(int tool=0; tool<tools.length; tool++) { Component c = tools[tool].c; Dimension toolSize = c.getPreferredSize(); int width = toolSize.width; if(!tools[tool].added) { add(c); tools[tool].added = true; } c.setBounds(x, y, width, height); x += width + BUTTONSPACING; } usedWidth = x; repaint(); } }); } /** * Registers a tool (adds it to the toolbar). * @param t Tool to add */ public void register(final Tool t) { UISingleton.runInSwing(new Runnable() { @Override public void run() { // Create info about tool ToolInfo ti=new ToolInfo(); ti.position=t.getDefaultPosition(); // Set up tool's actual component if(t instanceof SimpleTool) { SimpleTool st=(SimpleTool)t; ti.c=new ToolButton(ui, st.getLabel(), st.getThemeType(), st); } else if(t instanceof PageTool) { PageTool pt=(PageTool)t; ti.c=new ToolPage(pt); } else throw new IllegalArgumentException("Unexpected tool type"); m.put(t, ti); rearrangeTools(); } }); } /** * Informs the toolbar that it's closed */ void informClosed() { for(ToolInfo ti :m.values()) { if(ti.c instanceof ToolPage) { ((ToolPage)ti.c).getPage().informClosed(); } } } /** * Unregisters a tool (removes it from the toolbar). * @param t Tool to remove */ public void unregister(Tool t) { ToolInfo info = m.get(t); if(info.added) { remove(info.c); info.added = false; } m.remove(t); rearrangeTools(); } private static class ToolInfo implements Comparable<ToolInfo> { int position; Component c; boolean added=false; @Override public int compareTo(ToolInfo other) { return position - other.position; } } }