package com.opendoorlogistics.studio.controls; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.util.Timer; import java.util.TimerTask; import javax.swing.BorderFactory; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JToolBar; import javax.swing.event.AncestorEvent; import javax.swing.event.AncestorListener; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.MouseInputAdapter; import javax.swing.event.MouseInputListener; import com.opendoorlogistics.utils.ui.Icons; public class ODLScrollableToolbar extends JPanel { /** * This timer is static and shared between all instances of this class, as the internal thread * only gets disposed on garbage collection otherwise. */ private static final Timer MOVEMENT_TIMER = new Timer(); private final JToolBar toolBar; private final JScrollPane scrollPane; private boolean isNeedsScroll = false; private final JButton leftButton; private final JButton rightButton; public ODLScrollableToolbar(){ this(JToolBar.HORIZONTAL); } public ODLScrollableToolbar(int toolbarOrientation) { this(Icons.loadFromStandardPath("window-toolbar-left.png"), Icons.loadFromStandardPath("window-toolbar-right.png"),toolbarOrientation); } public ODLScrollableToolbar(Icon leftIcon, Icon rightIcon, int toolbarOrientation) { toolBar = new JToolBar(toolbarOrientation); toolBar.setFloatable(false); setLayout(new BorderLayout()); scrollPane = new JScrollPane(toolBar); scrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); scrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); scrollPane.getViewport().addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { updateScrollState(); } }); add(scrollPane, BorderLayout.CENTER); leftButton =leftIcon!=null? new JButton(leftIcon): new JButton("<"); leftButton.setVisible(false); leftButton.addMouseListener(createMouseListener(true)); add(leftButton, BorderLayout.WEST); rightButton = rightIcon!=null ? new JButton(rightIcon) : new JButton(">"); rightButton.setVisible(false); rightButton.addMouseListener(createMouseListener(false)); add(rightButton, BorderLayout.EAST); addComponentListener(new ComponentListener() { @Override public void componentShown(ComponentEvent e) { updateScrollState(); } @Override public void componentResized(ComponentEvent e) { updateScrollState(); } @Override public void componentMoved(ComponentEvent e) { updateScrollState(); } @Override public void componentHidden(ComponentEvent e) { updateScrollState(); } }); // addAncestorListener(new AncestorListener() { // // @Override // public void ancestorRemoved(AncestorEvent event) { // // TODO Auto-generated method stub // // } // // @Override // public void ancestorMoved(AncestorEvent event) { // updateScrollState(); // } // // @Override // public void ancestorAdded(AncestorEvent event) { // // TODO Auto-generated method stub // // } // }); } private MouseListener createMouseListener(final boolean isLeft) { return new MouseListener() { TimerTask task; @Override public void mouseReleased(MouseEvent e) { if (task != null) { task.cancel(); task = null; } } @Override public void mousePressed(MouseEvent e) { final long startTime = System.currentTimeMillis(); task = new TimerTask() { @Override public void run() { long duration = System.currentTimeMillis() - startTime; long increment = 1 + duration / 150; increment = Math.min(increment, 6); scroll((int) (isLeft ? -increment : +increment)); } }; MOVEMENT_TIMER.scheduleAtFixedRate(task, 0, 10); } @Override public void mouseExited(MouseEvent e) { // task.cancel(); } @Override public void mouseEntered(MouseEvent e) { } @Override public void mouseClicked(MouseEvent e) { } }; } public JToolBar getToolBar() { return toolBar; } private void scroll(int value) { Point pos = scrollPane.getViewport().getViewPosition(); pos = new Point(pos.x + value, pos.y); if (pos.x < 0) { pos.x = 0; } int max = toolBar.getWidth() - scrollPane.getWidth(); max = Math.max(0, max); if (pos.x > max) { pos.x = max; } setViewportPosition(pos); } private void setViewportPosition(Point pos) { scrollPane.getViewport().setViewPosition(pos); scrollPane.repaint(); } public void setScrollViewToInitialPosition(){ Point pos = scrollPane.getViewport().getViewPosition(); setViewportPosition(new Point(0, pos.y)); } private boolean isHorizontal(){ return toolBar.getOrientation() == JToolBar.HORIZONTAL; } private void updateScrollState() { boolean newNeedsScroll = isHorizontal()? scrollPane.getWidth() < toolBar.getWidth() : scrollPane.getHeight() < toolBar.getHeight(); if (isNeedsScroll != newNeedsScroll) { leftButton.setVisible(newNeedsScroll); rightButton.setVisible(newNeedsScroll); isNeedsScroll = newNeedsScroll; } } public static void main(String[] args) { JPanel mainPanel = new JPanel(); mainPanel.setLayout(new BorderLayout()); JFrame frame = new JFrame(); frame.setContentPane(mainPanel); ODLScrollableToolbar sPanel = new ODLScrollableToolbar(); for (int i = 1; i < 100; i++) { sPanel.getToolBar().add(new JButton("hello" + i)); } frame.add(sPanel, BorderLayout.SOUTH); frame.pack(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } }