/* * Licensed Materials - Property of Perforce Software, Inc. * © Copyright Perforce Software, Inc. 2014, 2021 * © Copyright IBM Corp. 2009, 2014 * © Copyright ILOG 1996, 2009 * All Rights Reserved. * * Note to U.S. Government Users Restricted Rights: * The Software and Documentation were developed at private expense and * are "Commercial Items" as that term is defined at 48 CFR 2.101, * consisting of "Commercial Computer Software" and * "Commercial Computer Software Documentation", as such terms are * used in 48 CFR 12.212 or 48 CFR 227.7202-1 through 227.7202-4, * as applicable. */ import java.awt.BorderLayout; import java.awt.Color; import java.awt.FlowLayout; import java.awt.SystemColor; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.ArrayList; import java.util.List; import java.util.Random; import javax.swing.JCheckBox; import javax.swing.JFrame; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JRootPane; import javax.swing.SwingUtilities; import ilog.views.IlvApplyObject; import ilog.views.IlvGraphic; import ilog.views.IlvHandlesSelection; import ilog.views.IlvManager; import ilog.views.IlvManagerLayer; import ilog.views.IlvManagerView; import ilog.views.IlvPoint; import ilog.views.IlvRect; import ilog.views.IlvTransformer; import ilog.views.graphic.IlvZoomableLabel; import ilog.views.interactor.IlvSelectInteractor; import ilog.views.interactor.IlvZoomViewInteractor; import ilog.views.swing.IlvJManagerViewControlBar; import ilog.views.swing.IlvJScrollManagerView; import ilog.views.swing.IlvPopupMenuContext; import ilog.views.swing.IlvPopupMenuManager; import ilog.views.swing.IlvSimplePopupMenu; /** * This is a very simple application that shows how to use * Z-ordering with or without the quadtree. */ SuppressWarnings("serial") public class ZOrderingApp extends JRootPane { IlvManager manager; IlvManagerView mgrview; { // This sample uses JViews Diagrammer features. When deploying an // application that includes this code, you need to be in possession // of a Perforce JViews Diagrammer Deployment license. // IlvProductUtil.DeploymentLicenseRequired( // IlvProductUtil.JViews_Diagrammer_Deployment); } /** * Initializes the application. */ public void init() { // create a manager manager = new IlvManager(); // create a manager view mgrview = new IlvManagerView(manager); mgrview.setSelectedWhenPopupPreferred(true); // create the scroll manager view IlvJScrollManagerView scrollManView = new IlvJScrollManagerView(mgrview); // Some settings on the manager view and on the scroll manager view mgrview.setAntialiasing(true); mgrview.setKeepingAspectRatio(true); mgrview.setBackground(Color.white); mgrview.setForeground(SystemColor.windowText); Color xc = SystemColor.windowText; xc = new Color(255 - xc.getRed(), 255 - xc.getGreen(), 255 - xc.getBlue()); mgrview.setDefaultXORColor(xc); mgrview.setDefaultGhostColor(SystemColor.windowText); mgrview.setZoomFactorRange(0.02, 10.0); // Settings parameters for selection handles IlvHandlesSelection.defaultHandleColor = Color.black; IlvHandlesSelection.defaultHandleBackgroundColor = Color.white; IlvHandlesSelection.defaultHandleShape = IlvHandlesSelection.SQUARE_SHAPE; // create the standard control bar IlvJManagerViewControlBar controlBar = new IlvJManagerViewControlBar(); controlBar.setView(mgrview); // modify the interactors such that the demo looks better ((IlvSelectInteractor) controlBar.getSelectInteractor()).setOpaqueMove(true); ((IlvZoomViewInteractor) controlBar.getZoomViewInteractor()).setPermanent(true); // set the initial interactor mgrview.setInteractor(controlBar.getSelectInteractor()); // ----------------------------------------------------------------------- // Now, fill the manager and set up the pop-up menus // register view view to the pop-up manager IlvPopupMenuManager.registerView(mgrview); // register the menus under different names IlvPopupMenuManager.registerMenu("MENU1", createMenu()); // fill the manager with graphic objects that use menu1 Random rand = new Random(0); for (int i = 0; i < 5; i++) { for (int j = 0; j < 28; j++) { // double x = rand.nextDouble() * 400; // double y = rand.nextDouble() * 400; double x = 5 + i * 100 + (j % 2) * 45; double y = 5 + j * 15; IlvZoomableLabel graphic = new IlvZoomableLabel(new IlvPoint(x, y), "Z-Order: " + i, false); graphic.setAntialiasing(true); graphic.setLeftMargin(6); graphic.setRightMargin(6); graphic.setTopMargin(4); graphic.setBottomMargin(4); graphic.setBorderOn(true); graphic.setBackgroundOn(true); int r = (int) (80 + rand.nextFloat() * (255 - 80)); int g = (int) (80 + rand.nextFloat() * (255 - 80)); int b = (int) (80 + rand.nextFloat() * (255 - 80)); r = Math.max(0, Math.min(r, 255)); g = Math.max(0, Math.min(g, 255)); b = Math.max(0, Math.min(b, 255)); graphic.setBackgroundPaint(new Color(r, g, b)); // set the pop-up menu or the graphic graphic.setPopupMenuName("MENU1"); // add the graphic to the manager manager.addObject(graphic, 0, true); } } // enable Z-Ordering final IlvManagerLayer layer = manager.getManagerLayer(0); layer.setZOrdering(true); // create a checkbox that allows to disable the Z-ordering in the layer JCheckBox useZOrder = new JCheckBox("Z-Order", true); useZOrder.setToolTipText("Enable or disable the Z-ordering"); useZOrder.addItemListener(new ItemListener() { Override public void itemStateChanged(ItemEvent e) { if (e.getStateChange() == ItemEvent.SELECTED) layer.setZOrdering(true); else if (e.getStateChange() == ItemEvent.DESELECTED) layer.setZOrdering(false); manager.reDraw(); } }); // create a checkbox that allows to disable the quadtree in the layer JCheckBox useQuadTree = new JCheckBox("Quadtree", true); useQuadTree.setToolTipText("Enable or disable the quad tree"); useQuadTree.addItemListener(new ItemListener() { Override public void itemStateChanged(ItemEvent e) { if (e.getStateChange() == ItemEvent.SELECTED) layer.setQuadtreeEnabled(true); else if (e.getStateChange() == ItemEvent.DESELECTED) layer.setQuadtreeEnabled(false); manager.reDraw(); } }); /** * To enable benchmarking * JButton bench = new JButton("Bench"); bench.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { System.out.println("Quadtree " + layer.isQuadtreeEnabled()); System.out.println("Z-Ordering " + layer.isZOrdering()); long s = System.currentTimeMillis(); for (int i = 0; i < 1000; i++) manager.getObject(new IlvPoint(i,i), mgrview); long t = System.currentTimeMillis(); System.out.println("Time for 1000 hittest: " + (t-s) + " ms"); s = System.currentTimeMillis(); IlvApplyObject f = new IlvApplyObject() { public void apply(IlvGraphic g, Object arg) {} }; for (int i = 0; i < 1000; i++) manager.mapIntersects(f, null, new IlvRect(i,i,100,100), new IlvTransformer()); t = System.currentTimeMillis(); System.out.println("Time for 1000 empty mapIntersects: " + (t-s) + " ms"); int n = layer.getCardinal(); s = System.currentTimeMillis(); for (int i = 0; i < 1000; i++) layer.setIndex(layer.getObject(n-1), i); t = System.currentTimeMillis(); System.out.println("Time for 1000 setIndex: " + (t-s) + " ms"); s = System.currentTimeMillis(); for (int i = 0; i < 1000; i++) layer.getIndex(layer.getObject(n-1)); t = System.currentTimeMillis(); System.out.println("Time for 1000 getIndex: " + (t-s) + " ms"); } }); */ // create the top panel with the toolbar and the pop-up checkbox JPanel topPanel = new JPanel(); topPanel.setLayout(new FlowLayout(FlowLayout.LEFT)); topPanel.add(controlBar); topPanel.add(useZOrder); topPanel.add(useQuadTree); // topPanel.add(bench); // put manager view, top panel and bottom panel together getContentPane().setLayout(new BorderLayout(0, 0)); getContentPane().add(scrollManView, BorderLayout.CENTER); getContentPane().add(topPanel, BorderLayout.NORTH); updateLabelTexts(); } /** * Update the text in the label to display the current Z-order. */ private void updateLabelTexts() { manager.applyToObjects(manager.getObjects(), new IlvApplyObject() { Override public void apply(IlvGraphic g, Object arg) { if (g instanceof IlvZoomableLabel) { IlvManagerLayer layer = manager.getManagerLayer(g); int zOrder = layer.getIndex(g); String s; if (zOrder < 10) s = "00" + zOrder; else if (zOrder < 100) s = "0" + zOrder; else s = "" + zOrder; ((IlvZoomableLabel) g).setLabel("Z-Order: " + s); } } }, null, true); } /** * Creates a very simple pop-up menu. * In principle, you can use any JPopupMenu at the graphic object. * However, the IlvSimplePopupMenu is very conveniant to configure, hence * we use it in this sample. */ private JPopupMenu createMenu() { // create the action listener for the pop-up menu ActionListener actionListener = new ActionListener() { Override public void actionPerformed(ActionEvent e) { // retrieve the selected menu item JMenuItem m = (JMenuItem) e.getSource(); // retrieve the graphic that has this pop-up menu IlvPopupMenuContext context = IlvPopupMenuManager.getPopupMenuContext(m); IlvGraphic graphic = context.getGraphic(); // do the action if (IlvSimplePopupMenu.getMenuItemText(m).equals("To front")) moveToFront(graphic); else if (IlvSimplePopupMenu.getMenuItemText(m).equals("Forward")) moveForward(graphic); else if (IlvSimplePopupMenu.getMenuItemText(m).equals("Backward")) moveBackward(graphic); else if (IlvSimplePopupMenu.getMenuItemText(m).equals("To back")) moveToBack(graphic); // select the object (just to have a visual feedback which object has // changed) manager.deSelectAll(true); manager.setSelected(graphic, true, true); } }; // create a simple pop-up menu IlvSimplePopupMenu menu = new IlvSimplePopupMenu("Menu1", "To front | Forward | Backward | To back", null, actionListener); return menu; } /** * Move a graphic to the top of the Z-order. */ private void moveToFront(IlvGraphic g) { IlvManager manager = (IlvManager) g.getGraphicBag(); IlvManagerLayer layer = manager.getManagerLayer(g); layer.setIndex(g, layer.getCardinal() - 1); // this also redraws updateLabelTexts(); } /** * Move a graphic to the bottom of the Z-order. */ private void moveToBack(IlvGraphic g) { IlvManager manager = (IlvManager) g.getGraphicBag(); IlvManagerLayer layer = manager.getManagerLayer(g); layer.setIndex(g, 0); // this also redraws updateLabelTexts(); } /** * Move a graphic one step forward in the Z-order * Well, not quite: if we have 1000 objects, then we would need up to * 1000 times move forward operations to move the object visible forward. * But visibly, only something happens at the Z-order of the overlapping * objects, so we shorten this by moving forward with respect to the * current overlapping. That is, we move it to the Z-order so that it * appears on top of the lowest overlapping object that is currently on top * of the input object */ private void moveForward(IlvGraphic g) { IlvManager manager = (IlvManager) g.getGraphicBag(); IlvManagerLayer layer = manager.getManagerLayer(g); IlvTransformer t = mgrview.getTransformer(); IlvRect trect = g.boundingBox(t); IlvRect rect = new IlvRect(trect); t.boundingBox(rect, true); IntersectionCollector f = new IntersectionCollector(); layer.mapIntersects(rect, trect, f, null, t); int zOrder = layer.getIndex(g); int bestZOrder; if (f.result.size() <= 1) // just move one up. Nothing overlaps, so there will not be any // immediate visual effect bestZOrder = zOrder + 1; else { // search in the result the closest object with higher Z-Order. // Move to that Z-Order, because this has an immediate visual effect. bestZOrder = layer.getCardinal(); for (int i = 0; i < f.result.size(); i++) { IlvGraphic obj = f.result.get(i); int otherZOrder = layer.getIndex(obj); if (zOrder < otherZOrder && otherZOrder < bestZOrder) bestZOrder = otherZOrder; } } layer.setIndex(g, bestZOrder); // this also redraws updateLabelTexts(); } /** * Move a graphic one step backward in the Z-order * Well, not quite: if we have 1000 objects, then we would need up to * 1000 times move backward operations to move the object visible backward. * But visibly, only something happens at the Z-order of the overlapping * objects, so we shorten this by moving backward with respect to the * current overlapping. That is, we move it to the Z-order so that it * appears below of the highest overlapping object that is currently below * of the input object */ private void moveBackward(IlvGraphic g) { IlvManager manager = (IlvManager) g.getGraphicBag(); IlvManagerLayer layer = manager.getManagerLayer(g); IlvTransformer t = mgrview.getTransformer(); IlvRect trect = g.boundingBox(t); IlvRect rect = new IlvRect(trect); t.boundingBox(rect, true); IntersectionCollector f = new IntersectionCollector(); layer.mapIntersects(rect, trect, f, null, t); int zOrder = layer.getIndex(g); int bestZOrder; if (f.result.size() <= 1) // just move one down. Nothing overlaps, so there will not be any // immediate visual effect bestZOrder = zOrder - 1; else { // search in the result the closest object with lower Z-Order. // Move to that Z-Order, because this has an immediate visual effect. bestZOrder = -1; for (int i = 0; i < f.result.size(); i++) { IlvGraphic obj = f.result.get(i); int otherZOrder = layer.getIndex(obj); if (bestZOrder < otherZOrder && otherZOrder < zOrder) bestZOrder = otherZOrder; } } layer.setIndex(g, bestZOrder); // this also redraws updateLabelTexts(); } /** * A collector apply opject. */ class IntersectionCollector implements IlvApplyObject { List<IlvGraphic> result = new ArrayList<IlvGraphic>(); Override public void apply(IlvGraphic g, Object arg) { result.add(g); } } /** * Allows you to run the demo as a standalone application. */ public static void main(String[] arg) { // Sun recommends that to put the entire GUI initialization into the // AWT thread SwingUtilities.invokeLater(new Runnable() { Override public void run() { ZOrderingApp app = new ZOrderingApp(); app.init(); JFrame frame = new JFrame("Z-Order Example"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(500, 500); frame.getContentPane().add(app); frame.setVisible(true); } }); } }