diff options
9 files changed, 381 insertions, 63 deletions
diff --git a/ardor3d-examples/src/main/java/com/ardor3d/example/ui/InteractUIExample.java b/ardor3d-examples/src/main/java/com/ardor3d/example/ui/InteractUIExample.java index 45a3478..2e1e44e 100644 --- a/ardor3d-examples/src/main/java/com/ardor3d/example/ui/InteractUIExample.java +++ b/ardor3d-examples/src/main/java/com/ardor3d/example/ui/InteractUIExample.java @@ -421,8 +421,10 @@ public class InteractUIExample extends ExampleBase { tempVec.set(Camera.getCurrentCamera().getScreenCoordinates(spat.getWorldTransform().applyForward(tempVec))); tempVec.setZ(0); menu.showAt((int) tempVec.getX(), (int) tempVec.getY()); - _mouseManager.setPosition((int) tempVec.getX(), (int) tempVec.getY() + 1); _mouseManager.setPosition((int) tempVec.getX(), (int) tempVec.getY()); + if (menu.getCenterItem() != null) { + menu.getCenterItem().mouseEntered((int) tempVec.getX(), (int) tempVec.getY(), null); + } } protected void hideMenu() { diff --git a/ardor3d-examples/src/main/java/com/ardor3d/example/ui/PopOverUIExample.java b/ardor3d-examples/src/main/java/com/ardor3d/example/ui/PopOverUIExample.java new file mode 100644 index 0000000..2f1c69e --- /dev/null +++ b/ardor3d-examples/src/main/java/com/ardor3d/example/ui/PopOverUIExample.java @@ -0,0 +1,289 @@ +/** + * Copyright (c) 2008-2017 Ardor Labs, Inc. + * + * This file is part of Ardor3D. + * + * Ardor3D is free software: you can redistribute it and/or modify it + * under the terms of its license which may be found in the accompanying + * LICENSE file or at <http://www.ardor3d.com/LICENSE>. + */ + +package com.ardor3d.example.ui; + +import com.ardor3d.bounding.BoundingBox; +import com.ardor3d.example.ExampleBase; +import com.ardor3d.example.Purpose; +import com.ardor3d.extension.ui.UIButton; +import com.ardor3d.extension.ui.UIComponent; +import com.ardor3d.extension.ui.UIHud; +import com.ardor3d.extension.ui.UIMenuItem; +import com.ardor3d.extension.ui.UIPieMenu; +import com.ardor3d.extension.ui.UIPieMenuItem; +import com.ardor3d.extension.ui.UIPopupMenu; +import com.ardor3d.extension.ui.event.ActionEvent; +import com.ardor3d.extension.ui.event.ActionListener; +import com.ardor3d.extension.ui.util.Insets; +import com.ardor3d.image.Texture; +import com.ardor3d.math.ColorRGBA; +import com.ardor3d.math.MathUtils; +import com.ardor3d.math.Matrix3; +import com.ardor3d.math.Vector3; +import com.ardor3d.math.type.ReadOnlyVector3; +import com.ardor3d.renderer.Camera; +import com.ardor3d.renderer.Renderer; +import com.ardor3d.renderer.state.MaterialState; +import com.ardor3d.renderer.state.MaterialState.ColorMaterial; +import com.ardor3d.renderer.state.RenderState.StateType; +import com.ardor3d.renderer.state.TextureState; +import com.ardor3d.scenegraph.controller.SpatialController; +import com.ardor3d.scenegraph.shape.Box; +import com.ardor3d.util.ReadOnlyTimer; +import com.ardor3d.util.TextureManager; + +/** + * Illustrates the use of Popup and Pie menus. + */ +@Purpose(htmlDescriptionKey = "com.ardor3d.example.ui.PopOverUIExample", // +thumbnailPath = "com/ardor3d/example/media/thumbnails/ui_PopOverUIExample.jpg", // +maxHeapMemory = 64) +public class PopOverUIExample extends ExampleBase implements ActionListener { + private static final String[] COLORS = new String[] { "Red", "White", "Blue", "Black" }; + private static final String[] SPINS = new String[] { "None", "Around X", "Around Y", "Around Z" }; + private static final String[] TEXS = new String[] { "None", "Logo", "Ball", "Clock" }; + + UIHud hud; + private Box box; + + public static void main(final String[] args) { + start(PopOverUIExample.class); + } + + @Override + protected void initExample() { + _canvas.setTitle("PopOver UI Example"); + + UIComponent.setUseTransparency(true); + + // Add a spinning 3D box to show behind UI. + box = new Box("Box", new Vector3(0, 0, 0), 5, 5, 5); + box.setModelBound(new BoundingBox()); + box.setTranslation(new Vector3(0, 0, -15)); + _root.attachChild(box); + + final MaterialState ms = new MaterialState(); + ms.setColorMaterial(ColorMaterial.Diffuse); + box.setRenderState(ms); + + setTexture("Logo"); + setSpin("Around Y"); + + hud = new UIHud(); + hud.setupInput(_canvas, _physicalLayer, _logicalLayer); + hud.setMouseManager(_mouseManager); + final Camera cam = _canvas.getCanvasRenderer().getCamera(); + + final UIButton dropButton = new UIButton("Drop Menu"); + dropButton.setPadding(new Insets(6, 15, 6, 15)); + dropButton.setHudXY(cam.getWidth() / 10 - dropButton.getLocalComponentWidth() / 2, + cam.getHeight() - dropButton.getLocalComponentHeight() - 5); + dropButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(final ActionEvent event) { + showPopupMenu(dropButton.getHudX(), dropButton.getHudY()); + } + }); + hud.add(dropButton); + + final UIButton pieButton = new UIButton("Pie Menu"); + pieButton.setPadding(new Insets(6, 15, 6, 15)); + pieButton.setHudXY(9 * cam.getWidth() / 10 - pieButton.getLocalComponentWidth() / 2, cam.getHeight() + - pieButton.getLocalComponentHeight() - 5); + pieButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(final ActionEvent event) { + showPieMenu(cam.getWidth() / 2, cam.getHeight() / 2); + } + }); + hud.add(pieButton); + } + + @Override + public void actionPerformed(final ActionEvent event) { + final UIButton src = (UIButton) event.getSource(); + final String command = src.getActionCommand(); + switch (command) { + case "Color": + setColor(src.getText()); + return; + case "Spin": + setSpin(src.getText()); + return; + case "Texture": + setTexture(src.getText()); + return; + } + } + + protected void showPopupMenu(final int hudX, final int hudY) { + final UIPopupMenu menu = new UIPopupMenu(); + final int minWidth = 120; + + final UIPopupMenu colorMenu = new UIPopupMenu(); + colorMenu.setMinimumContentSize(minWidth, 5); + menu.addItem(new UIMenuItem("Set Color...", null, colorMenu)); + AddMenuItems(colorMenu, "Color", false, COLORS); + + final UIPopupMenu spinMenu = new UIPopupMenu(); + spinMenu.setMinimumContentSize(minWidth, 5); + menu.addItem(new UIMenuItem("Set Spin...", null, spinMenu)); + AddMenuItems(spinMenu, "Spin", false, SPINS); + + final UIPopupMenu texMenu = new UIPopupMenu(); + texMenu.setMinimumContentSize(minWidth, 5); + menu.addItem(new UIMenuItem("Set Texture...", null, texMenu)); + AddMenuItems(texMenu, "Texture", false, TEXS); + + menu.updateMinimumSizeFromContents(); + menu.layout(); + + hud.closePopupMenus(); + + hud.showSubPopupMenu(menu); + menu.showAt(hudX, hudY); + } + + protected void showPieMenu(final int hudX, final int hudY) { + final UIPieMenu menu = new UIPieMenu(hud, 70, 200); + + final UIPieMenu colorMenu = new UIPieMenu(hud); + menu.addItem(new UIPieMenuItem("Set Color...", null, colorMenu, 100)); + AddMenuItems(colorMenu, "Color", true, COLORS); + + final UIPieMenu spinMenu = new UIPieMenu(hud); + menu.addItem(new UIPieMenuItem("Set Spin...", null, spinMenu, 100)); + AddMenuItems(spinMenu, "Spin", true, SPINS); + + final UIPieMenu texMenu = new UIPieMenu(hud); + menu.addItem(new UIPieMenuItem("Set Texture...", null, texMenu, 100)); + AddMenuItems(texMenu, "Texture", true, TEXS); + + menu.setCenterItem(new UIPieMenuItem("Cancel", null, true, null)); + + menu.updateMinimumSizeFromContents(); + menu.layout(); + + hud.closePopupMenus(); + + hud.showSubPopupMenu(menu); + menu.showAt(hudX, hudY); + _mouseManager.setPosition(hudX, hudY); + if (menu.getCenterItem() != null) { + menu.getCenterItem().mouseEntered(hudX, hudY, null); + } + + } + + private void AddMenuItems(final UIPopupMenu parent, final String actionCommand, final boolean pie, + final String[] colors) { + for (final String color : colors) { + final UIMenuItem item = pie ? new UIPieMenuItem(color, null, true, this) : new UIMenuItem(color, null, + true, this); + item.setActionCommand(actionCommand); + parent.addItem(item); + } + } + + private void setColor(final String text) { + switch (text) { + case "Red": + box.setDefaultColor(ColorRGBA.RED); + break; + case "Blue": + box.setDefaultColor(ColorRGBA.BLUE); + break; + case "Black": + box.setDefaultColor(ColorRGBA.BLACK); + break; + default: + case "White": + box.setDefaultColor(ColorRGBA.WHITE); + break; + } + } + + private void setSpin(final String text) { + box.clearControllers(); + final ReadOnlyVector3 axis; + switch (text) { + case "None": + return; + case "Around X": + axis = Vector3.UNIT_X; + break; + case "Around Y": + axis = Vector3.UNIT_Y; + break; + default: + case "Around Z": + axis = Vector3.UNIT_Z; + break; + } + box.addController(new SpatialController<Box>() { + private final Matrix3 rotate = new Matrix3(); + private double angle = 0; + + public void update(final double time, final Box caller) { + angle += time * 50; + angle %= 360; + rotate.fromAngleNormalAxis(angle * MathUtils.DEG_TO_RAD, axis); + caller.setRotation(rotate); + } + }); + } + + private void setTexture(final String text) { + // Add a texture to the box. + final TextureState ts = new TextureState(); + + String imageFile; + switch (text) { + case "None": + box.clearRenderState(StateType.Texture); + box.updateWorldRenderStates(true); + return; + case "Ball": + imageFile = "images/ball.png"; + break; + case "Clock": + imageFile = "images/clock.png"; + break; + case "Logo": + default: + imageFile = "images/ardor3d_white_256.jpg"; + break; + } + + final Texture tex = TextureManager.load(imageFile, Texture.MinificationFilter.Trilinear, true); + ts.setTexture(tex); + box.setRenderState(ts); + box.updateWorldRenderStates(true); + } + + @Override + protected void updateLogicalLayer(final ReadOnlyTimer timer) { + hud.getLogicalLayer().checkTriggers(timer.getTimePerFrame()); + } + + @Override + protected void renderExample(final Renderer renderer) { + super.renderExample(renderer); + renderer.renderBuckets(); + renderer.draw(hud); + } + + @Override + protected void updateExample(final ReadOnlyTimer timer) { + hud.updateGeometricState(timer.getTimePerFrame()); + } + +} diff --git a/ardor3d-examples/src/main/resources/com/ardor3d/example/i18n/example_descriptions.properties b/ardor3d-examples/src/main/resources/com/ardor3d/example/i18n/example_descriptions.properties index fad9b46..5ba0fbf 100644 --- a/ardor3d-examples/src/main/resources/com/ardor3d/example/i18n/example_descriptions.properties +++ b/ardor3d-examples/src/main/resources/com/ardor3d/example/i18n/example_descriptions.properties @@ -85,5 +85,6 @@ com.ardor3d.example.terrain.ShapesPlusProceduralTerrainExample=Example showing t com.ardor3d.example.terrain.TerrainWaterExample=Example showing how to combine the terrain and water systems. Requires GLSL support. com.ardor3d.example.terrain.ZupTerrainExample=Example showing the Geometry Clipmap Terrain system with 'MegaTextures' using Z-Up. This is done by flipping the terrain system from y-up to z-up and inverting interactions with it back to the y-up terrain coordinate space. Requires GLSL support. com.ardor3d.example.ui.BMTextExample=Illustrates how to modify text properties (e.g. font, color, alignment) and display on a canvas. +com.ardor3d.example.ui.PopOverUIExample=Illustrates the use of Popup and Pie menus. com.ardor3d.example.ui.RotatingUIExample=Illustrates how to display and move GUI primitatives (e.g. RadioButton, Lable, TabbedPane) on a canvas. com.ardor3d.example.ui.SimpleUIExample=Illustrates how to display GUI primitatives (e.g. RadioButton, Lable, TabbedPane) on a canvas. diff --git a/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/UIComboBox.java b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/UIComboBox.java index df93d7f..88561c2 100644 --- a/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/UIComboBox.java +++ b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/UIComboBox.java @@ -3,7 +3,7 @@ * * This file is part of Ardor3D. * - * Ardor3D is free software: you can redistribute it and/or modify it + * Ardor3D is free software: you can redistribute it and/or modify it * under the terms of its license which may be found in the accompanying * LICENSE file or at <http://www.ardor3d.com/LICENSE>. */ @@ -121,7 +121,6 @@ public class UIComboBox extends UIPanel { } _valuesMenu.updateMinimumSizeFromContents(); - _valuesMenu.pack(); if (_valuesMenu.getLocalComponentWidth() < UIComboBox.this.getLocalComponentWidth()) { _valuesMenu.setLocalComponentWidth(UIComboBox.this.getLocalComponentWidth()); } diff --git a/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/UIMenuItem.java b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/UIMenuItem.java index 9ae3e61..b34ccb4 100644 --- a/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/UIMenuItem.java +++ b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/UIMenuItem.java @@ -46,4 +46,28 @@ public class UIMenuItem extends UIButton { }); } } + + public UIMenuItem(final String text, final SubTex icon, final UIPopupMenu subMenu) { + this(text, icon, false, null); + addActionListener(new ActionListener() { + public void actionPerformed(final ActionEvent event) { + showSubMenu(subMenu); + } + }); + } + + protected void showSubMenu(final UIPopupMenu subMenu) { + final UIHud hud = getHud(); + if (hud == null) { + return; + } + + hud.closePopupMenusAfter(getParent()); + subMenu.updateMinimumSizeFromContents(); + subMenu.layout(); + + hud.showSubPopupMenu(subMenu); + subMenu.showAt(getHudX() + getLocalComponentWidth() - 5, getHudY() + getLocalComponentHeight()); + } + } diff --git a/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/UIPieMenu.java b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/UIPieMenu.java index 4590bf8..f1f57a6 100644 --- a/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/UIPieMenu.java +++ b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/UIPieMenu.java @@ -16,13 +16,12 @@ import com.ardor3d.math.MathUtils; import com.ardor3d.math.Rectangle2; import com.ardor3d.math.Vector3; import com.ardor3d.scenegraph.Spatial; -import com.ardor3d.scenegraph.visitor.Visitor; import com.google.common.collect.Lists; /** * A special frame meant to display menu items. */ -public class UIPieMenu extends UIContainer implements IPopOver { +public class UIPieMenu extends UIPopupMenu implements IPopOver { public static final int DEFAULT_INNER_RADIUS = 50; @@ -102,14 +101,16 @@ public class UIPieMenu extends UIContainer implements IPopOver { return _sliceRadians; } - public void addItem(final UIPieMenuItem item) { + @Override + public void addItem(final UIMenuItem item) { _menuDirty = true; - add(item); + super.addItem(item); } - public void removeItem(final UIPieMenuItem item) { + @Override + public void removeItem(final UIMenuItem item) { _menuDirty = true; - remove(item); + super.removeItem(item); } public UIPieMenuItem getCenterItem() { @@ -131,6 +132,7 @@ public class UIPieMenu extends UIContainer implements IPopOver { setCenterItem(null); } + @Override public void clearItems() { _menuDirty = true; removeAllComponents(); @@ -236,34 +238,6 @@ public class UIPieMenu extends UIContainer implements IPopOver { setMinimumContentSize(_outerRadius * 2, _outerRadius * 2); } - @Override - public void close() { - final UIHud hud = getHud(); - if (hud == null) { - throw new IllegalStateException("UIPieMenu is not attached to a hud."); - } - - // Close any open tooltip - hud.getTooltip().setVisible(false); - - // clear any resources for standin - clearStandin(); - - // clean up any state - acceptVisitor(new Visitor() { - @Override - public void visit(final Spatial spatial) { - if (spatial instanceof StateBasedUIComponent) { - final StateBasedUIComponent comp = (StateBasedUIComponent) spatial; - comp.switchState(comp.getDefaultState()); - } - } - }, true); - - hud.remove(this); - _parent = null; - } - public int getSliceIndex(final UIPieMenuItem item) { final List<Spatial> content = getChildren(); if (content == null) { diff --git a/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/UIPopupMenu.java b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/UIPopupMenu.java index 2050865..0dbce6a 100644 --- a/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/UIPopupMenu.java +++ b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/UIPopupMenu.java @@ -9,19 +9,18 @@ package com.ardor3d.extension.ui; -import java.util.EnumSet; - import com.ardor3d.extension.ui.layout.RowLayout; -import com.ardor3d.extension.ui.util.Insets; +import com.ardor3d.scenegraph.Spatial; +import com.ardor3d.scenegraph.visitor.Visitor; /** * A special frame meant to display menu items. */ -public class UIPopupMenu extends UIFrame implements IPopOver { +public class UIPopupMenu extends UIContainer implements IPopOver { public UIPopupMenu() { - super(null, EnumSet.noneOf(UIFrame.FrameButtons.class)); - getContentPanel().setLayout(new RowLayout(false)); + super(); + setLayout(new RowLayout(false)); applySkin(); } @@ -33,16 +32,9 @@ public class UIPopupMenu extends UIFrame implements IPopOver { final int displayW = getHud().getWidth(); final int displayH = getHud().getHeight(); - if (x + width > displayW) { - setHudX(displayW - width); - } else { - final Insets border = getBorder() != null ? getBorder() : Insets.EMPTY; - setHudX(x - border.getLeft()); - } - y = y - height; - if (y < 0) { - y = 0; - } + setHudX(x + width > displayW ? displayW - width : x); + + y = Math.max(0, y - height); if (y + height > displayH) { y = displayH - height; } @@ -57,14 +49,42 @@ public class UIPopupMenu extends UIFrame implements IPopOver { } public void addItem(final UIMenuItem item) { - getContentPanel().add(item); + add(item); } public void removeItem(final UIMenuItem item) { - getContentPanel().remove(item); + remove(item); } public void clearItems() { - getContentPanel().removeAllComponents(); + removeAllComponents(); + } + + @Override + public void close() { + final UIHud hud = getHud(); + if (hud == null) { + throw new IllegalStateException("UIPopupMenu is not attached to a hud."); + } + + // Close any open tooltip + hud.getTooltip().setVisible(false); + + // clear any resources for standin + clearStandin(); + + // clean up any state + acceptVisitor(new Visitor() { + @Override + public void visit(final Spatial spatial) { + if (spatial instanceof StateBasedUIComponent) { + final StateBasedUIComponent comp = (StateBasedUIComponent) spatial; + comp.switchState(comp.getDefaultState()); + } + } + }, true); + + hud.remove(this); + _parent = null; } } diff --git a/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/skin/Skin.java b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/skin/Skin.java index 69203d6..6d024cf 100644 --- a/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/skin/Skin.java +++ b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/skin/Skin.java @@ -65,7 +65,7 @@ public abstract class Skin { applyToTextArea((UITextArea) component); } - // 4. PANEL TYPES + // 4. PANEL / CONTAINER TYPES else if (component instanceof UIProgressBar) { applyToProgressBar((UIProgressBar) component); } else if (component instanceof UIComboBox) { @@ -74,6 +74,8 @@ public abstract class Skin { applyToScrollBar((UIScrollBar) component); } else if (component instanceof UIPieMenu) { applyToPieMenu((UIPieMenu) component); + } else if (component instanceof UIPopupMenu) { + applyToPopupMenu((UIPopupMenu) component); } else if (component instanceof UIPanel) { applyToPanel((UIPanel) component); } @@ -81,8 +83,6 @@ public abstract class Skin { // 5. FRAME TYPES else if (component instanceof UITooltip) { applyToTooltip((UITooltip) component); - } else if (component instanceof UIPopupMenu) { - applyToPopupMenu((UIPopupMenu) component); } else if (component instanceof UIFrame) { applyToFrame((UIFrame) component); } diff --git a/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/skin/generic/GenericSkin.java b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/skin/generic/GenericSkin.java index a81c633..1c49dcf 100644 --- a/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/skin/generic/GenericSkin.java +++ b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/skin/generic/GenericSkin.java @@ -317,7 +317,7 @@ public class GenericSkin extends Skin { closeButton.updateMinimumSizeFromContents(); closeButton.compact(); closeButton - .setMaximumContentSize(closeButton.getContentWidth(), closeButton.getContentHeight()); + .setMaximumContentSize(closeButton.getContentWidth(), closeButton.getContentHeight()); } } @@ -618,9 +618,18 @@ public class GenericSkin extends Skin { @Override protected void applyToPopupMenu(final UIPopupMenu component) { - component.getTitleBar().removeFromParent(); - component.getStatusBar().removeFromParent(); - applyToFrame(component); + component.setOpacity(1.0f); + + component.setMargin(new Insets(0, 0, 0, 0)); + component.setPadding(new Insets(0, 0, 0, 0)); + + final SubTex borderTex = new SubTex(_sharedTex, 4, 17, 32, 36, 0, 6, 7, 6); + final UIBorder border = new ImageBorder(borderTex); + component.setBorder(border); + final ColorRGBA top = new ColorRGBA(210 / 255f, 210 / 255f, 210 / 255f, 1); + final ColorRGBA bottom = new ColorRGBA(244 / 255f, 244 / 255f, 244 / 255f, 1); + final GradientBackdrop grad = new GradientBackdrop(top, top, bottom, bottom); + component.setBackdrop(grad); } @Override |