/*******************************************************************************
* Copyright (c) 2014 Mentor Graphics and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Mentor Graphics - initial API and implementation
*******************************************************************************/
package com.codesourcery.installer.ui;
import java.util.ArrayList;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import com.codesourcery.installer.ui.InfoButton.ElementColor;
/**
* Displays a scrollable list of
* {@link com.codesourcery.installer.ui.InfoButton}.
*/
public class InfoList extends ScrolledComposite {
/** List items */
private ArrayList<InfoButton> items = new ArrayList<InfoButton>();
/** Label font */
private Font labelFont;
/** Hover color */
private Color hoverColor;
/** Items area */
private Composite itemsArea;
/** Selection listeners */
private ListenerList selectionListeners;
/** Mouse listeners */
private ListenerList mouseListeners;
/** <code>true</code> if text should be shortened */
private boolean shortenText = false;
/**
* Constructor
*
* @param parent Parent
* @param style Styles
*/
public InfoList(Composite parent, int style) {
super(parent, style);
// Create hover color
hoverColor = new Color(getShell().getDisplay(),
blendRGB(
getShell().getDisplay().getSystemColor(SWT.COLOR_LIST_SELECTION).getRGB(),
getShell().getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND).getRGB(),
40));
// Create options area
itemsArea = new Composite(this, SWT.NONE);
GridLayout itemsLayout = new GridLayout(1, true);
itemsLayout.verticalSpacing = 0;
itemsArea.setLayout(itemsLayout);
setExpandHorizontal(true);
setExpandVertical(true);
// Handle items resize
itemsArea.addControlListener(new ControlAdapter() {
int width = -1;
@Override
public void controlResized(ControlEvent e) {
getShell().getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
int newWidth = itemsArea.getSize().x;
if (newWidth != width) {
width = newWidth;
int minHeight = itemsArea.computeSize(newWidth, SWT.DEFAULT).y;
setMinHeight(minHeight);
}
}
});
}
});
setContent(itemsArea);
setShowFocusedControl(true);
}
@Override
public void dispose() {
if (hoverColor != null) {
hoverColor.dispose();
hoverColor = null;
}
super.dispose();
}
/**
* Returns the area for items.
*
* @return Items area
*/
protected Composite getItemsArea() {
return itemsArea;
}
/**
* Blends two RGB values using the provided ratio.
*
* @param c1 First RGB value
* @param c2 Second RGB value
* @param ratio Percentage of the first RGB to blend with
* second RGB (0-100)
*
* @return The RGB value of the blended color
*/
public static RGB blendRGB(RGB c1, RGB c2, int ratio) {
ratio = Math.max(0, Math.min(255, ratio));
int r = Math.max(0, Math.min(255, (ratio * c1.red + (100 - ratio) * c2.red) / 100));
int g = Math.max(0, Math.min(255, (ratio * c1.green + (100 - ratio) * c2.green) / 100));
int b = Math.max(0, Math.min(255, (ratio * c1.blue + (100 - ratio) * c2.blue) / 100));
return new RGB(r, g, b);
}
/**
* Sets if the label text should be shortened if it will not fit in the
* button width. The middle of the text will be replaced with "..." to
* fit the width.
*
* @param shortenText <code>true</code> to shorten text
*/
public void setShortenText(boolean shortenText) {
this.shortenText = shortenText;
}
/**
* Returns if the label text should be shortened.
*
* @return <code>true</code> if text will be shortened
*/
public boolean getShortenText() {
return shortenText;
}
/**
* Sets the label font.
*
* @param labelFont Label font
*/
public void setLabelFont(Font labelFont) {
this.labelFont = labelFont;
for (InfoButton item : items) {
item.setLabelFont(labelFont);
}
}
/**
* Returns the label font.
*
* @return Label font
*/
public Font getLabelFont() {
return labelFont;
}
/**
* Adds a new item.
*
* @param image Item image or <code>null</code>
* @param text Item text
* @param description Item description or <code>null</code>
* @return New item
*/
public InfoButton addItem(Image image, String text, String description) {
InfoButton button = new InfoButton(getItemsArea(), SWT.RADIO);
button.setShortenText(getShortenText());
button.setImage(image);
button.setText(text);
button.setDescription(description);
button.setRounded(true);
button.setColor(ElementColor.description, getShell().getDisplay().getSystemColor(SWT.COLOR_WIDGET_DARK_SHADOW));
GridData gridData = new GridData(SWT.FILL, SWT.CENTER, true, false);
button.setLayoutData(gridData);
button.setColor(ElementColor.hoverBackground, hoverColor);
button.setLabelFont(getLabelFont());
// Selection listener
button.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
notifySelectionListeners(e);
}
});
// Mouse listener
button.addMouseListener(new MouseListener() {
@Override
public void mouseDoubleClick(MouseEvent e) {
notifyMouseListeners(3, e);
}
@Override
public void mouseDown(MouseEvent e) {
notifyMouseListeners(1, e);
}
@Override
public void mouseUp(MouseEvent e) {
notifyMouseListeners(2, e);
}
});
return button;
}
/**
* Adds a new item.
*
* @param text Item text
* @return New item
*/
public InfoButton addItem(String text) {
InfoButton item = addItem(null, text, null);
items.add(item);
return item;
}
/**
* Removes an item.
*
* @param item Item to remove
*/
public void removeItem(InfoButton item) {
items.remove(item);
item.dispose();
getItemsArea().layout(true);
}
/**
* Removes all items.
*/
public void removeAllItems() {
for (InfoButton item : items) {
item.dispose();
}
getItemsArea().layout(true);
}
/**
* Returns the items.
*
* @return Items
*/
public InfoButton[] getItems() {
return items.toArray(new InfoButton[items.size()]);
}
/**
* Notifies selection listeners.
*
* @param event Selection event
*/
protected void notifySelectionListeners(SelectionEvent event) {
Object[] listeners = selectionListeners.getListeners();
for (Object listener : listeners) {
((SelectionListener)listener).widgetSelected(event);
}
}
/**
* Notifies mouse listeners.
*
* @param type Event type
* @param event Mouse event
*/
protected void notifyMouseListeners(int type, MouseEvent event) {
Object[] listeners = mouseListeners.getListeners();
for (Object listener : listeners) {
if (type == 1) {
((MouseListener)listener).mouseDown(event);
}
else if (type == 2) {
((MouseListener)listener).mouseUp(event);
}
else if (type == 3) {
((MouseListener)listener).mouseDoubleClick(event);
}
}
}
/**
* Adds a listener to selection events. If the listener has already been
* added, this method does nothing.
*
* @param listener Listener to add
*/
public void addSelectionListener(SelectionListener listener) {
if (selectionListeners == null) {
selectionListeners = new ListenerList();
}
selectionListeners.add(listener);
}
/**
* Removes a listener from selection events.
*
* @param listener Listener to remove
*/
public void removeSelectionListener(SelectionListener listener) {
if (selectionListeners != null) {
selectionListeners.remove(listener);
}
}
/**
* Adds a listener to mouse events. If the listener has already been
* added, this method does nothing.
*
* @Param listener Listener to add
*/
public void addMouseListener(MouseListener listener) {
if (mouseListeners == null) {
mouseListeners = new ListenerList();
}
mouseListeners.add(listener);
}
/**
* Removes a listener from mouse events.
*
* @Param listener Listener to remove
*/
public void removeMouseListener(MouseListener listener) {
if (mouseListeners != null) {
mouseListeners.remove(listener);
}
}
}