/* * Copyright 2013 eWidgetFX. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ewidgetfx.core; import javafx.event.EventHandler; import javafx.geometry.Pos; import javafx.scene.CacheHint; import javafx.scene.Group; import javafx.scene.Node; import javafx.scene.input.MouseEvent; import javafx.scene.layout.HBox; import javafx.scene.layout.StackPane; import javafx.scene.shape.Rectangle; /** * Widget or application containers can have icons to assist in the launching of widgets. WidgetIcon objects can also * have 'badge indicators' or icon overlays for icons. * * @param <B> * @see <code>TextIconOverlay</code>. * * @author Carl Dea <carl.dea@gmail.com> * @since 1.0 */ public class WidgetIcon<B extends Node> extends HBox { Group iconSurface = new Group(); private Node appIconNode; private B badgeIndicator; public static enum BADGE_POS { NW, N, NE, E, SE, S, SW, W, CENTER, ABSOLUTE }; private BADGE_POS badgePos = BADGE_POS.NE; protected EventHandler<MouseEvent> mouseEntered = e -> ((WidgetIcon) e.getSource()).setOpacity(1); protected EventHandler<MouseEvent> mouseExit = e -> ((WidgetIcon) e.getSource()).setOpacity(.80); protected EventHandler<MouseEvent> mousePressed = e -> System.out.println(e); protected EventHandler<MouseEvent> mouseClicked = e -> System.out.println(e); private boolean layoutChildren = false; private String widgetFilename; public WidgetIcon(Node node) { super(); appIconNode = node; // TODO: build a default icon if there isn't a node init(); } public WidgetIcon(Node node, B badgeIndicator) { super(); appIconNode = node; this.badgeIndicator = badgeIndicator; // TODO: build a default icon if there isn't a node init(); } protected void init() { StackPane iconLayers = new StackPane(); iconLayers.setOpacity(.80); // This rectangle makes the icon background dimensions for StackPane width and height. Rectangle rect = new Rectangle(); // When live the rect will respond to the later value of the pref width & height rect.widthProperty().bind(prefWidthProperty()); rect.heightProperty().bind(prefHeightProperty()); // hide rect will provide an invisible sizer. rect.setVisible(false); // center both the rect (invisible sizer) and app icon. StackPane.setAlignment(rect, Pos.CENTER); iconLayers.getChildren().add(rect); StackPane.setAlignment(appIconNode, Pos.CENTER); iconLayers.getChildren().add(appIconNode); // build filters to intercept mouse events. // Scene graph Runtime RT-30659 (Not a bug..) // use the setPickOnBounds(true) setPickOnBounds(true); addEventFilter(MouseEvent.MOUSE_ENTERED, mouseEntered); addEventFilter(MouseEvent.MOUSE_EXITED, mouseExit); addEventFilter(MouseEvent.MOUSE_PRESSED, mousePressed); addEventFilter(MouseEvent.MOUSE_CLICKED, mouseClicked); iconLayers.setCacheHint(CacheHint.SPEED); appIconNode.setCacheHint(CacheHint.SPEED); iconSurface.getChildren().add(iconLayers); if (badgeIndicator != null) { hideBadgeIndicator(); iconSurface.getChildren().add(badgeIndicator); } setAlignment(Pos.CENTER); getChildren().add(iconSurface); } public Node getAppIconNode() { return appIconNode; } public void setAppIconNode(Node appIconNode) { iconSurface.getChildren().remove(this.appIconNode); this.appIconNode = appIconNode; iconSurface.getChildren().add(0, appIconNode); } public B getBadgeIndicator() { return (B) badgeIndicator; } public void setBadgePosition(BADGE_POS position) { badgePos = position; layoutChildren = false; requestLayout(); } public void refresh() { layoutChildren = false; requestLayout(); } public BADGE_POS getBadgePosition() { return badgePos; } public void setBadgeIndicator(B badgeIndicator) { if (this.badgeIndicator != null) { iconSurface.getChildren().remove(this.badgeIndicator); } this.badgeIndicator = badgeIndicator; iconSurface.getChildren().add(badgeIndicator); } public void showBadgeIndicator() { this.badgeIndicator.setVisible(true); } @Override protected void layoutChildren() { super.layoutChildren(); if (!layoutChildren) { updateBadgePosition(); } layoutChildren = true; } private void updateBadgePosition() { if (badgeIndicator == null) { return; } double w = badgeIndicator.getBoundsInLocal().getWidth(); double h = badgeIndicator.getBoundsInLocal().getHeight(); double surfaceWidth = getPrefWidth(); double surfaceHeight = getPrefHeight(); BADGE_POS badge_pos = getBadgePosition(); switch (badge_pos) { case N: badgeIndicator.setLayoutX((surfaceWidth - w) / 2); badgeIndicator.setLayoutY(0); break; case NE: badgeIndicator.setLayoutX(surfaceWidth - w); badgeIndicator.setLayoutY(0); break; case E: badgeIndicator.setLayoutX((surfaceWidth - w)); badgeIndicator.setLayoutY((surfaceHeight - h) / 2); break; case SE: badgeIndicator.setLayoutX((surfaceWidth - w)); badgeIndicator.setLayoutY((surfaceHeight - h)); break; case S: badgeIndicator.setLayoutX((surfaceWidth - w) / 2); badgeIndicator.setLayoutY((surfaceHeight - h)); break; case SW: badgeIndicator.setLayoutX(0); badgeIndicator.setLayoutY((surfaceHeight - h)); break; case W: badgeIndicator.setLayoutX(0); badgeIndicator.setLayoutY((surfaceHeight - h) / 2); break; case CENTER: badgeIndicator.setLayoutX((surfaceWidth - w) / 2); badgeIndicator.setLayoutY((surfaceHeight - h) / 2); break; case NW: badgeIndicator.setLayoutX(0); badgeIndicator.setLayoutY(0); break; case ABSOLUTE: // upper left (0,0) default: } } public void hideBadgeIndicator() { this.badgeIndicator.setVisible(false); } public void removeBadgeIndicator() { iconSurface.getChildren().remove(badgeIndicator); } public String getWidgetFilename() { return widgetFilename; } public void setWidgetFilename(String widgetFilename) { this.widgetFilename = widgetFilename; } }