com.alee.laf.list.WebListUI Maven / Gradle / Ivy
/*
* This file is part of WebLookAndFeel library.
*
* WebLookAndFeel library 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.
*
* WebLookAndFeel library 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 WebLookAndFeel library. If not, see .
*/
package com.alee.laf.list;
import com.alee.global.StyleConstants;
import com.alee.laf.WebLookAndFeel;
import com.alee.utils.GeometryUtils;
import com.alee.utils.GraphicsUtils;
import com.alee.utils.LafUtils;
import com.alee.utils.SwingUtils;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.plaf.ColorUIResource;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicListUI;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.RoundRectangle2D;
/**
* Custom UI for JList component.
*
* @author Mikle Garin
*/
public class WebListUI extends BasicListUI
{
/**
* Style settings.
*/
private boolean decorateSelection = WebListStyle.decorateSelection;
private boolean highlightRolloverCell = WebListStyle.highlightRolloverCell;
private int selectionRound = WebListStyle.selectionRound;
private int selectionShadeWidth = WebListStyle.selectionShadeWidth;
private boolean autoScrollToSelection = WebListStyle.autoScrollToSelection;
/**
* List listeners.
*/
private MouseAdapter mouseoverAdapter;
private ListSelectionListener selectionListener;
/**
* Runtime variables.
*/
private int rolloverIndex = -1;
/**
* Returns an instance of the WebListUI for the specified component.
* This tricky method is used by UIManager to create component UIs when needed.
*
* @param c component that will use UI instance
* @return instance of the WebListUI
*/
@SuppressWarnings ("UnusedParameters")
public static ComponentUI createUI ( final JComponent c )
{
return new WebListUI ();
}
/**
* Installs UI in the specified component.
*
* @param c component for this UI
*/
@Override
public void installUI ( final JComponent c )
{
super.installUI ( c );
// Default settings
SwingUtils.setOrientation ( list );
LookAndFeel.installProperty ( list, WebLookAndFeel.OPAQUE_PROPERTY, Boolean.TRUE );
list.setBackground ( new ColorUIResource ( WebListStyle.background ) );
list.setForeground ( new ColorUIResource ( WebListStyle.foreground ) );
// Rollover listener
mouseoverAdapter = new MouseAdapter ()
{
@Override
public void mouseMoved ( final MouseEvent e )
{
updateMouseover ( e );
}
@Override
public void mouseDragged ( final MouseEvent e )
{
updateMouseover ( e );
}
private void updateMouseover ( final MouseEvent e )
{
// Ignore events if rollover highlight is disabled
if ( !decorateSelection || !highlightRolloverCell )
{
return;
}
// Determining highlighted cell index
int index = list.locationToIndex ( e.getPoint () );
final Rectangle bounds = list.getCellBounds ( index, index );
if ( bounds == null || !bounds.contains ( e.getPoint () ) || !list.isEnabled () )
{
index = -1;
}
// Updating rollover cell
if ( rolloverIndex != index )
{
final int oldIndex = rolloverIndex;
rolloverIndex = index;
repaintChange ( oldIndex, rolloverIndex );
}
}
@Override
public void mouseExited ( final MouseEvent e )
{
// Cleaning up rollover index
if ( rolloverIndex != -1 )
{
final int oldIndex = rolloverIndex;
rolloverIndex = -1;
repaintChange ( oldIndex, rolloverIndex );
}
}
private void repaintChange ( final int oldIndex, final int newIndex )
{
final Rectangle oldBounds = list.getCellBounds ( oldIndex, oldIndex );
final Rectangle newBounds = list.getCellBounds ( newIndex, newIndex );
final Rectangle rect = GeometryUtils.getContainingRect ( oldBounds, newBounds );
if ( rect != null )
{
list.repaint ( rect );
}
}
};
list.addMouseListener ( mouseoverAdapter );
list.addMouseMotionListener ( mouseoverAdapter );
// Selection listener
selectionListener = new ListSelectionListener ()
{
@Override
public void valueChanged ( final ListSelectionEvent e )
{
if ( autoScrollToSelection )
{
if ( list.getSelectedIndex () != -1 )
{
final int index = list.getLeadSelectionIndex ();
final Rectangle selection = getCellBounds ( list, index, index );
if ( selection != null && !selection.intersects ( list.getVisibleRect () ) )
{
list.scrollRectToVisible ( selection );
}
}
}
}
};
list.addListSelectionListener ( selectionListener );
}
/**
* Uninstalls UI from the specified component.
*
* @param c component with this UI
*/
@Override
public void uninstallUI ( final JComponent c )
{
list.removeMouseListener ( mouseoverAdapter );
list.removeMouseMotionListener ( mouseoverAdapter );
list.removeListSelectionListener ( selectionListener );
super.uninstallUI ( c );
}
/**
* Returns whether should decorate selected and rollover cells or not.
*
* @return true if should decorate selected and rollover cells, false otherwise
*/
public boolean isDecorateSelection ()
{
return decorateSelection;
}
/**
* Sets whether should decorate selected and rollover cells or not.
*
* @param decorateSelection whether should decorate selected and rollover cells or not
*/
public void setDecorateSelection ( final boolean decorateSelection )
{
this.decorateSelection = decorateSelection;
}
/**
* Returns whether should highlight rollover cell or not.
*
* @return true if rollover cell is being highlighted, false otherwise
*/
public boolean isHighlightRolloverCell ()
{
return highlightRolloverCell;
}
/**
* Sets whether should highlight rollover cell or not.
*
* @param highlightRolloverCell whether should highlight rollover cell or not
*/
public void setHighlightRolloverCell ( final boolean highlightRolloverCell )
{
this.highlightRolloverCell = highlightRolloverCell;
}
/**
* Returns cells selection rounding.
*
* @return cells selection rounding
*/
public int getSelectionRound ()
{
return selectionRound;
}
/**
* Sets cells selection rounding.
*
* @param selectionRound new cells selection rounding
*/
public void setSelectionRound ( final int selectionRound )
{
this.selectionRound = selectionRound;
}
/**
* Returns cells selection shade width.
*
* @return cells selection shade width
*/
public int getSelectionShadeWidth ()
{
return selectionShadeWidth;
}
/**
* Sets cells selection shade width.
*
* @param selectionShadeWidth new cells selection shade width
*/
public void setSelectionShadeWidth ( final int selectionShadeWidth )
{
this.selectionShadeWidth = selectionShadeWidth;
}
/**
* Returns whether to scroll list down to selection automatically or not.
*
* @return true if list is being automatically scrolled to selection, false otherwise
*/
public boolean isAutoScrollToSelection ()
{
return autoScrollToSelection;
}
/**
* Sets whether to scroll list down to selection automatically or not.
*
* @param autoScrollToSelection whether to scroll list down to selection automatically or not
*/
public void setAutoScrollToSelection ( final boolean autoScrollToSelection )
{
this.autoScrollToSelection = autoScrollToSelection;
}
/**
* Paints list content.
*
* @param g graphics context
* @param c painted component
*/
@Override
public void paint ( final Graphics g, final JComponent c )
{
super.paint ( g, c );
// todo Visual shade effect
// Rectangle vr = c.getVisibleRect ();
// if ( vr.y > 0 )
// {
// final int shadeWidth = 10;
// float opacity = shadeWidth > vr.y ? 1f - ( float ) ( shadeWidth - vr.y ) / shadeWidth : 1f;
// NinePatchIcon npi = NinePatchUtils.getShadeIcon ( shadeWidth, 0, opacity );
// Dimension ps = npi.getPreferredSize ();
// npi.paintIcon ( ( Graphics2D ) g, vr.x - shadeWidth, vr.y + shadeWidth - ps.height, vr.width + shadeWidth * 2, ps.height );
// }
}
/**
* Paint one List cell: compute the relevant state, get the "rubber stamp" cell renderer component, and then use the CellRendererPane
* to paint it. Subclasses may want to override this method rather than paint().
*
* @param g graphics context
* @param index cell index
* @param rowBounds cell bounds
* @param cellRenderer cell renderer
* @param dataModel list model
* @param selModel list selection model
* @param leadIndex lead cell index
* @see #paint
*/
@Override
protected void paintCell ( final Graphics g, final int index, final Rectangle rowBounds, final ListCellRenderer cellRenderer,
final ListModel dataModel, final ListSelectionModel selModel, final int leadIndex )
{
// todo Even-odd cells highlight
// if ( list.getLayoutOrientation () == WebList.VERTICAL && ( evenLineColor != null || oddLineColor != null ) )
// {
// boolean even = index % 2 == 0;
// if ( even && evenLineColor != null )
// {
// g.setColor ( evenLineColor );
// g.fillRect ( rowBounds.x, rowBounds.y, rowBounds.width, rowBounds.height );
// }
// if ( !even && oddLineColor != null )
// {
// g.setColor ( oddLineColor );
// g.fillRect ( rowBounds.x, rowBounds.y, rowBounds.width, rowBounds.height );
// }
// }
final Object value = dataModel.getElementAt ( index );
final boolean isSelected = selModel.isSelectedIndex ( index );
if ( decorateSelection && ( isSelected || index == rolloverIndex ) )
{
final Graphics2D g2d = ( Graphics2D ) g;
final Composite oc = GraphicsUtils.setupAlphaComposite ( g2d, 0.35f, !isSelected );
LafUtils.drawCustomWebBorder ( g2d, list,
new RoundRectangle2D.Double ( rowBounds.x + selectionShadeWidth, rowBounds.y + selectionShadeWidth,
rowBounds.width - selectionShadeWidth * 2 - 1, rowBounds.height - selectionShadeWidth * 2 - 1,
selectionRound * 2, selectionRound * 2 ), StyleConstants.shadeColor, selectionShadeWidth, true, true
);
GraphicsUtils.restoreComposite ( g2d, oc, !isSelected );
}
final boolean cellHasFocus = list.hasFocus () && ( index == leadIndex );
final Component rendererComponent = cellRenderer.getListCellRendererComponent ( list, value, index, isSelected, cellHasFocus );
rendererPane.paintComponent ( g, rendererComponent, list, rowBounds.x, rowBounds.y, rowBounds.width, rowBounds.height, true );
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy