blob: 8b8fb4d6834289884dfe04c4e195aff0eef80c58 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2018 Agence spatiale canadienne / Canadian Space Agency
* 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:
* Pierre Allard,
* Regent L'Archeveque,
* Sebastien Gemme - initial API and implementation
*
* SPDX-License-Identifier: EPL-1.0
*
*******************************************************************************/
package org.eclipse.apogy.common.widgets.ui;
import java.net.URL;
import java.text.DecimalFormat;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Device;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class BatteryStatComposite extends Composite {
private static final Logger Logger = LoggerFactory.getLogger(BatteryStatComposite.class);
private static final int ALPHA_VALUE = 100; // Transparency value range: (0-255)
private static final int LINE_WIDTH = 4; // Line width
private static final int LOWER_BOUND_VALUE = 33;
private static final int UPPER_BOUND_VALUE = 66;
private static final int MIN_VALUE = 0;
private static final double MAX_VALUE = 100; // Maximum possible value for this widget
private static final float POLE_HEIGHT_FRACTION = 0.392857f; // Fraction of the pole height of the battery
private static final float BATTERY_BEFORE_POLE_FRACTION = 0.789473f; // Fraction of the full battery before getting
// the pole.
private static final String IMAGES_FOLDER = "platform:/plugin/org.eclipse.apogy.common.widgets.ui/images/"; // Images
// path
private Image background; // Background image.
private double actualValue; // This is the actual value in percent. Minimum is 0 and maximum is 100.
private Color red;
private Color green;
private Color yellow;
/**
* Constructor parameter information:
*
* @param initialValue This is the initial value of the battery. Its a percent
* and should be more of equal than 0 but less or equal than
* 100.
*/
public BatteryStatComposite(Composite parent, int style, double initialValue) {
super(parent, style | SWT.DOUBLE_BUFFERED);
setActualValue(initialValue);
// Initialize colors.
initColors();
// Initialize images.
initImages();
// Create listeners
createPaintListener();
createDisposeListener();
}
// Return actual value.
public synchronized double getActualValue() {
return this.actualValue;
}
// Set actual value.
public void setActualValue(double actualValue) {
// Validate new value.
if (actualValue < MIN_VALUE)
actualValue = MIN_VALUE;
else if (actualValue > MAX_VALUE)
actualValue = MAX_VALUE;
this.actualValue = actualValue;
redraw();
}
/**
* Initialize colors.
*/
private void initColors() {
this.green = new Color(Display.getCurrent(), 0, 255, 0);
this.yellow = new Color(Display.getCurrent(), 255, 255, 0);
this.red = new Color(Display.getCurrent(), 255, 0, 0);
}
/**
* Initialize images.
*/
private void initImages() {
try {
Device device = Display.getCurrent();
URL url = new URL(IMAGES_FOLDER + "battery.png");
this.background = new Image(device, url.openStream());
} catch (Exception e) {
Logger.error(e.getMessage(), e);
}
}
/**
* This method paint the battery.
*/
private void paintMeter(GC gc) {
if (this.background != null) // Draw background
gc.drawImage(this.background, 0, 0, this.background.getBounds().width, this.background.getBounds().height,
0, 0, getBounds().width, getBounds().height);
else // Draw a black rectangle (This code is only useful in windows builder to see
// the widget without loading images).
drawBlackRectangle(gc);
drawChargeOnBattery(gc);
drawNumberOnBattery(gc);
}
private void createPaintListener() {
addPaintListener(new PaintListener() {
@Override
public void paintControl(PaintEvent e) {
paintMeter(e.gc);
}
});
}
private void createDisposeListener() {
addDisposeListener(new DisposeListener() {
@Override
public void widgetDisposed(DisposeEvent e) {
if (BatteryStatComposite.this.background != null)
BatteryStatComposite.this.background.dispose();
BatteryStatComposite.this.green.dispose();
BatteryStatComposite.this.yellow.dispose();
BatteryStatComposite.this.red.dispose();
}
});
}
private void drawBlackRectangle(GC gc) {
Color color = new Color(getDisplay(), 0, 0, 0);
gc.setForeground(color);
gc.setLineWidth(LINE_WIDTH);
gc.drawRectangle(2, 2, getBounds().width - 4, getBounds().height - 4);
color.dispose();
}
private void drawChargeOnBattery(GC gc) {
double chargeWidth = getBounds().width - 2;
int actualCharge = (int) Math.round(chargeWidth * (this.actualValue / MAX_VALUE));
gc.setAlpha(ALPHA_VALUE);
if (this.actualValue >= UPPER_BOUND_VALUE)
gc.setBackground(this.green);
else if (this.actualValue >= LOWER_BOUND_VALUE && this.actualValue < UPPER_BOUND_VALUE)
gc.setBackground(this.yellow);
else
gc.setBackground(this.red);
if (actualCharge > Math.round((chargeWidth * BATTERY_BEFORE_POLE_FRACTION))) {
gc.fillRectangle(1, 1, (int) Math.round(chargeWidth * BATTERY_BEFORE_POLE_FRACTION),
getBounds().height - 2);
int xStartDraw = (int) Math.round(chargeWidth * BATTERY_BEFORE_POLE_FRACTION) + 1;
int yStarDraw = (int) (getBounds().height * (1f / 3f));
int chargeWidthToDraw = actualCharge - xStartDraw + 1;
int chargeHeightToDraw = Math.round((getBounds().height - 2) * POLE_HEIGHT_FRACTION);
gc.fillRectangle(xStartDraw, yStarDraw, chargeWidthToDraw, chargeHeightToDraw);
} else {
gc.fillRectangle(1, 1, actualCharge, getBounds().height - 2);
}
}
private void drawNumberOnBattery(GC gc) {
// Initialize center.
int centerXMeter = getBounds().width / 2;
int centerYMeter = getBounds().height / 2;
float XScaleFactor = 0f;
float YScaleFactor = 0f;
// Initialize scale factor.
if (this.background != null) {
XScaleFactor = (((float) getBounds().width) / ((float) this.background.getBounds().width));
YScaleFactor = (((float) getBounds().height) / ((float) this.background.getBounds().height));
}
// draw number on battery
DecimalFormat df = new DecimalFormat("0");
int size = 0;
if (XScaleFactor > YScaleFactor)
size = Math.round(5.5f * YScaleFactor);
else
size = Math.round(5.5f * XScaleFactor);
Font font = new Font(getDisplay(), "Tahoma", size, SWT.BOLD);
gc.setFont(font);
gc.setAlpha(255);
String numberPercent = df.format(this.actualValue) + "%";
int widthOfNumber = 0;
for (int i = 0; i < numberPercent.length(); i++) {
widthOfNumber += gc.getAdvanceWidth(numberPercent.charAt(i));
}
int heightOfNumber = gc.getFontMetrics().getHeight();
Color c = new Color(Display.getCurrent(), 0, 0, 0);
gc.setForeground(c);
gc.drawString(numberPercent, centerXMeter - (Math.round((widthOfNumber) / 1.5f)) + 1,
centerYMeter - (heightOfNumber / 2) + 1, true);
c.dispose();
c = new Color(Display.getCurrent(), 255, 255, 255);
gc.setForeground(c);
gc.drawString(numberPercent, centerXMeter - (Math.round((widthOfNumber) / 1.5f)),
centerYMeter - (heightOfNumber / 2), true);
c.dispose();
font.dispose();
}
}