Search in sources :

Example 6 with Pair

use of mpicbg.trakem2.util.Downsampler.Pair in project TrakEM2 by trakem2.

the class Display method getPopupMenu.

/**
 * Return a context-sensitive popup menu.
 */
protected JPopupMenu getPopupMenu() {
    // get the job canceling dialog
    if (!canvas.isInputEnabled()) {
        return project.getLoader().getJobsPopup(this);
    }
    // create new
    this.popup = new JPopupMenu();
    JMenuItem item = null;
    JMenu menu = null;
    if (mode instanceof InspectPatchTrianglesMode) {
        item = new JMenuItem("Exit inspection");
        item.addActionListener(this);
        popup.add(item);
        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, true));
        return popup;
    } else if (canvas.isTransforming()) {
        item = new JMenuItem("Apply transform");
        item.addActionListener(this);
        popup.add(item);
        // dummy, for I don't add a MenuKeyListener, but "works" through the normal key listener. It's here to provide a visual cue
        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, true));
        item = new JMenuItem("Apply transform propagating to last layer");
        item.addActionListener(this);
        popup.add(item);
        if (layer.getParent().indexOf(layer) == layer.getParent().size() - 1)
            item.setEnabled(false);
        if (!(getMode().getClass() == AffineTransformMode.class || getMode().getClass() == NonLinearTransformMode.class))
            item.setEnabled(false);
        item = new JMenuItem("Apply transform propagating to first layer");
        item.addActionListener(this);
        popup.add(item);
        if (0 == layer.getParent().indexOf(layer))
            item.setEnabled(false);
        if (!(getMode().getClass() == AffineTransformMode.class || getMode().getClass() == NonLinearTransformMode.class))
            item.setEnabled(false);
        item = new JMenuItem("Cancel transform");
        item.addActionListener(this);
        popup.add(item);
        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, true));
        item = new JMenuItem("Specify transform...");
        item.addActionListener(this);
        popup.add(item);
        if (getMode().getClass() != AffineTransformMode.class)
            item.setEnabled(false);
        if (getMode().getClass() == ManualAlignMode.class) {
            final JMenuItem lexport = new JMenuItem("Export landmarks");
            popup.add(lexport);
            final JMenuItem limport = new JMenuItem("Import landmarks");
            popup.add(limport);
            final ActionListener a = new ActionListener() {

                @Override
                public void actionPerformed(final ActionEvent ae) {
                    final ManualAlignMode mam = (ManualAlignMode) getMode();
                    final Object source = ae.getSource();
                    if (lexport == source) {
                        mam.exportLandmarks();
                    } else if (limport == source) {
                        mam.importLandmarks();
                    }
                }
            };
            lexport.addActionListener(a);
            limport.addActionListener(a);
        }
        return popup;
    }
    final Class<?> aclass = null == active ? null : active.getClass();
    if (null != active) {
        if (Profile.class == aclass) {
            item = new JMenuItem("Duplicate, link and send to next layer");
            item.addActionListener(this);
            popup.add(item);
            Layer nl = layer.getParent().next(layer);
            if (nl == layer)
                item.setEnabled(false);
            item = new JMenuItem("Duplicate, link and send to previous layer");
            item.addActionListener(this);
            popup.add(item);
            nl = layer.getParent().previous(layer);
            if (nl == layer)
                item.setEnabled(false);
            menu = new JMenu("Duplicate, link and send to");
            int i = 1;
            for (final Layer la : layer.getParent().getLayers()) {
                // TODO should label which layers contain Profile instances linked to the one being duplicated
                item = new JMenuItem(i + ": z = " + la.getZ());
                // TODO should label which layers contain Profile instances linked to the one being duplicated
                item.addActionListener(this);
                // TODO should label which layers contain Profile instances linked to the one being duplicated
                menu.add(item);
                if (la == this.layer)
                    item.setEnabled(false);
                i++;
            }
            popup.add(menu);
            item = new JMenuItem("Duplicate, link and send to...");
            item.addActionListener(this);
            popup.add(item);
            popup.addSeparator();
            item = new JMenuItem("Unlink from images");
            item.addActionListener(this);
            popup.add(item);
            // isLinked() checks if it's linked to a Patch in its own layer
            if (!active.isLinked())
                item.setEnabled(false);
            item = new JMenuItem("Show in 3D");
            item.addActionListener(this);
            popup.add(item);
            popup.addSeparator();
        } else if (Patch.class == aclass) {
            final JMenu m = new JMenu("Patch");
            item = new JMenuItem("Fill ROI in alpha mask");
            item.addActionListener(this);
            m.add(item);
            item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F, 0));
            item.setEnabled(null != getRoi());
            item = new JMenuItem("Fill inverse ROI in alpha mask");
            item.addActionListener(this);
            m.add(item);
            item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F, Event.SHIFT_MASK));
            item.setEnabled(null != getRoi());
            item = new JMenuItem("Remove alpha mask");
            item.addActionListener(this);
            m.add(item);
            if (!((Patch) active).hasAlphaMask())
                item.setEnabled(false);
            item = new JMenuItem("Unlink from images");
            item.addActionListener(this);
            m.add(item);
            if (!active.isLinked(Patch.class))
                item.setEnabled(false);
            if (((Patch) active).isStack()) {
                item = new JMenuItem("Unlink slices");
                item.addActionListener(this);
                m.add(item);
            }
            final int n_sel_patches = selection.getSelected(Patch.class).size();
            item = new JMenuItem("Snap");
            item.addActionListener(this);
            m.add(item);
            item.setEnabled(1 == n_sel_patches);
            item = new JMenuItem("Montage");
            item.addActionListener(this);
            m.add(item);
            item.setEnabled(n_sel_patches > 1);
            item = new JMenuItem("Lens correction");
            item.addActionListener(this);
            m.add(item);
            item.setEnabled(n_sel_patches > 1);
            item = new JMenuItem("Blend");
            item.addActionListener(this);
            m.add(item);
            item.setEnabled(n_sel_patches > 1);
            item = new JMenuItem("Open image");
            item.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(final ActionEvent e) {
                    for (final Patch p : selection.get(Patch.class)) {
                        p.getImagePlus().show();
                    }
                }
            });
            m.add(item);
            item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_D, KeyEvent.SHIFT_MASK, true));
            item = new JMenuItem("Open original image");
            item.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(final ActionEvent e) {
                    for (final Patch p : selection.get(Patch.class)) {
                        p.getProject().getLoader().releaseToFit(p.getOWidth(), p.getOHeight(), p.getType(), 5);
                        p.getProject().getLoader().openImagePlus(p.getImageFilePath()).show();
                    }
                }
            });
            item = new JMenuItem("View volume");
            item.addActionListener(this);
            m.add(item);
            final HashSet<Displayable> hs = active.getLinked(Patch.class);
            if (null == hs || 0 == hs.size())
                item.setEnabled(false);
            item = new JMenuItem("View orthoslices");
            item.addActionListener(this);
            m.add(item);
            // if no Patch instances among the directly linked, then it's not a stack
            if (null == hs || 0 == hs.size())
                item.setEnabled(false);
            popup.add(m);
            popup.addSeparator();
        } else {
            item = new JMenuItem("Unlink");
            item.addActionListener(this);
            popup.add(item);
            item = new JMenuItem("Show in 3D");
            item.addActionListener(this);
            popup.add(item);
            popup.addSeparator();
        }
        if (AreaList.class == aclass) {
            final ArrayList<?> al = selection.getSelected();
            int n = 0;
            for (final Iterator<?> it = al.iterator(); it.hasNext(); ) {
                if (it.next().getClass() == AreaList.class)
                    n++;
            }
            item = new JMenuItem("Merge");
            item.addActionListener(this);
            popup.add(item);
            if (n < 2)
                item.setEnabled(false);
            item = new JMenuItem("Split");
            item.addActionListener(this);
            popup.add(item);
            if (n < 1)
                item.setEnabled(false);
            addAreaListAreasMenu(popup, active);
            popup.addSeparator();
        } else if (Pipe.class == aclass) {
            item = new JMenuItem("Reverse point order");
            item.addActionListener(this);
            popup.add(item);
            popup.addSeparator();
        } else if (Treeline.class == aclass || AreaTree.class == aclass) {
            if (AreaTree.class == aclass)
                addAreaTreeAreasMenu(popup, (AreaTree) active);
            item = new JMenuItem("Reroot");
            item.addActionListener(this);
            popup.add(item);
            item = new JMenuItem("Part subtree");
            item.addActionListener(this);
            popup.add(item);
            item = new JMenuItem("Join");
            item.addActionListener(this);
            popup.add(item);
            item = new JMenuItem("Show tabular view");
            item.addActionListener(this);
            popup.add(item);
            final Collection<Tree> trees = selection.get(Tree.class);
            // 
            final JMenu nodeMenu = new JMenu("Nodes");
            item = new JMenuItem("Mark");
            item.addActionListener(this);
            nodeMenu.add(item);
            item = new JMenuItem("Clear marks (selected Trees)");
            item.addActionListener(this);
            nodeMenu.add(item);
            final JMenuItem nodeColor = new JMenuItem("Color...");
            nodeMenu.add(nodeColor);
            nodeColor.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.SHIFT_MASK, true));
            final JMenuItem nodePairColor = new JMenuItem("Color path between two nodes tagged as...");
            nodeMenu.add(nodePairColor);
            final JMenuItem nodeRadius = active instanceof Treeline ? new JMenuItem("Radius...") : null;
            if (null != nodeRadius) {
                nodeMenu.add(nodeRadius);
                nodeRadius.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, 0, true));
            }
            final JMenuItem removeAllTags = new JMenuItem("Drop all tags (selected trees)");
            nodeMenu.add(removeAllTags);
            final JMenuItem removeTag = new JMenuItem("Drop all occurrences of tag...");
            nodeMenu.add(removeTag);
            final JMenuItem colorizeByNodeCentrality = new JMenuItem("Colorize by node betweenness centrality");
            nodeMenu.add(colorizeByNodeCentrality);
            final JMenuItem colorizeByBranchCentrality = new JMenuItem("Colorize by branch betweenness centrality");
            nodeMenu.add(colorizeByBranchCentrality);
            popup.add(nodeMenu);
            final ActionListener ln = new ActionListener() {

                @Override
                public void actionPerformed(final ActionEvent ae) {
                    if (null == active) {
                        Utils.showMessage("No tree selected!");
                        return;
                    }
                    if (!(active instanceof Tree)) {
                        Utils.showMessage("The selected object is not a Tree!");
                        return;
                    }
                    final Tree tree = (Tree) active;
                    final Object src = ae.getSource();
                    // 
                    if (src == nodeColor) {
                        final Node nd = tree.getLastVisited();
                        if (null == nd) {
                            Utils.showMessage("Select a node first by clicking on it\nor moving the mouse over it and pushing 'g'.");
                            return;
                        }
                        // sets an undo step
                        tree.adjustNodeColors(nd);
                    } else if (src == nodePairColor) {
                        final TreeMap<String, Tag> sm = getTags(tree);
                        if (null == sm)
                            return;
                        if (1 == sm.size()) {
                            Utils.showMessage("Need at least two different tags in the tree!");
                            return;
                        }
                        final Color color = tree.getColor();
                        final GenericDialog gd = new GenericDialog("Node colors");
                        gd.addSlider("Red: ", 0, 255, color.getRed());
                        gd.addSlider("Green: ", 0, 255, color.getGreen());
                        gd.addSlider("Blue: ", 0, 255, color.getBlue());
                        final String[] stags = asStrings(sm);
                        sm.keySet().toArray(stags);
                        gd.addChoice("Upstream tag:", stags, stags[0]);
                        gd.addChoice("Downstream tag:", stags, stags[1]);
                        gd.showDialog();
                        if (gd.wasCanceled())
                            return;
                        final Color newColor = new Color((int) gd.getNextNumber(), (int) gd.getNextNumber(), (int) gd.getNextNumber());
                        final Tag upstreamTag = sm.get(gd.getNextChoice());
                        final Tag downstreamTag = sm.get(gd.getNextChoice());
                        final List<Tree<?>.NodePath> pairs = tree.findTaggedPairs(upstreamTag, downstreamTag);
                        if (null == pairs || pairs.isEmpty()) {
                            Utils.showMessage("No pairs found for '" + upstreamTag + "' and '" + downstreamTag + "'");
                            return;
                        }
                        getLayerSet().addDataEditStep(tree);
                        for (final Tree<?>.NodePath pair : pairs) {
                            for (final Node<?> nd : pair.path) {
                                nd.setColor(newColor);
                            }
                        }
                        getLayerSet().addDataEditStep(tree);
                        Display.repaint();
                    } else if (src == nodeRadius) {
                        if (!(tree instanceof Treeline))
                            return;
                        final Node nd = tree.getLastVisited();
                        if (null == nd) {
                            Utils.showMessage("Select a node first by clicking on it\nor moving the mouse over it and pushing 'g'.");
                            return;
                        }
                        // sets an undo step
                        ((Treeline) tree).askAdjustRadius(nd);
                    } else if (src == removeAllTags) {
                        if (!Utils.check("Really remove all tags from all selected trees?"))
                            return;
                        final List<Tree> sel = selection.get(Tree.class);
                        getLayerSet().addDataEditStep(new HashSet<Displayable>(sel));
                        try {
                            for (final Tree t : sel) {
                                t.dropAllTags();
                            }
                            // current state
                            getLayerSet().addDataEditStep(new HashSet<Displayable>(sel));
                        } catch (final Exception e) {
                            getLayerSet().undoOneStep();
                            IJError.print(e);
                        }
                        Display.repaint();
                    } else if (src == removeTag) {
                        final TreeMap<String, Tag> tags = getTags(tree);
                        final String[] ts = asStrings(tags);
                        final GenericDialog gd = new GenericDialog("Remove tags");
                        gd.addChoice("Tag:", ts, ts[0]);
                        final String[] c = new String[] { "Active tree", "All selected trees and connectors", "All trees and connectors" };
                        gd.addChoice("From: ", c, c[0]);
                        gd.showDialog();
                        if (gd.wasCanceled())
                            return;
                        final HashSet<Displayable> ds = new HashSet<Displayable>();
                        final Tag tag = tags.get(gd.getNextChoice());
                        switch(gd.getNextChoiceIndex()) {
                            case 0:
                                ds.add(tree);
                                break;
                            case 1:
                                ds.addAll(selection.get(Tree.class));
                            case 2:
                                ds.addAll(getLayerSet().getZDisplayables(Tree.class, true));
                        }
                        getLayerSet().addDataEditStep(ds);
                        try {
                            for (final Displayable d : ds) {
                                final Tree t = (Tree) d;
                                t.removeTag(tag);
                            }
                            getLayerSet().addDataEditStep(ds);
                        } catch (final Exception e) {
                            getLayerSet().undoOneStep();
                            IJError.print(e);
                        }
                        Display.repaint();
                    } else if (src == colorizeByNodeCentrality) {
                        final List<Tree> ts = selection.get(Tree.class);
                        final HashSet<Tree> ds = new HashSet<Tree>(ts);
                        getLayerSet().addDataEditStep(ds);
                        try {
                            for (final Tree t : ts) {
                                t.colorizeByNodeBetweennessCentrality();
                            }
                            getLayerSet().addDataEditStep(ds);
                            Display.repaint();
                        } catch (final Exception e) {
                            getLayerSet().undoOneStep();
                            IJError.print(e);
                        }
                    } else if (src == colorizeByBranchCentrality) {
                        final List<Tree> ts = selection.get(Tree.class);
                        final HashSet<Tree> ds = new HashSet<Tree>(ts);
                        getLayerSet().addDataEditStep(ds);
                        try {
                            for (final Tree t : ts) {
                                t.colorizeByBranchBetweennessCentrality(2);
                            }
                            getLayerSet().addDataEditStep(ds);
                            Display.repaint();
                        } catch (final Exception e) {
                            getLayerSet().undoOneStep();
                            IJError.print(e);
                        }
                    }
                }
            };
            for (final JMenuItem a : new JMenuItem[] { nodeColor, nodePairColor, nodeRadius, removeAllTags, removeTag, colorizeByNodeCentrality, colorizeByBranchCentrality }) {
                if (null == a)
                    continue;
                a.addActionListener(ln);
            }
            // 
            final JMenu review = new JMenu("Review");
            final JMenuItem tgenerate = new JMenuItem("Generate review stacks (selected Trees)");
            review.add(tgenerate);
            tgenerate.setEnabled(trees.size() > 0);
            final JMenuItem tslab = new JMenuItem("Generate review stack for current slab");
            review.add(tslab);
            final JMenuItem tsubtree = new JMenuItem("Generate review stacks for subtree");
            review.add(tsubtree);
            final JMenuItem tremove = new JMenuItem("Remove reviews (selected Trees)");
            review.add(tremove);
            tremove.setEnabled(trees.size() > 0);
            final JMenuItem tconnectors = new JMenuItem("View table of outgoing/incoming connectors");
            review.add(tconnectors);
            final ActionListener l = new ActionListener() {

                @Override
                public void actionPerformed(final ActionEvent ae) {
                    if (!Utils.check("Really " + ae.getActionCommand())) {
                        return;
                    }
                    dispatcher.exec(new Runnable() {

                        @Override
                        public void run() {
                            int count = 0;
                            for (final Tree<?> t : trees) {
                                Utils.log("Processing " + (++count) + "/" + trees.size());
                                Bureaucrat bu = null;
                                if (ae.getSource() == tgenerate)
                                    bu = t.generateAllReviewStacks();
                                else if (ae.getSource() == tremove)
                                    bu = t.removeReviews();
                                else if (ae.getSource() == tslab) {
                                    final Point po = canvas.consumeLastPopupPoint();
                                    Utils.log2(po, layer, 1.0);
                                    bu = t.generateReviewStackForSlab(po.x, po.y, Display.this.layer, 1.0);
                                } else if (ae.getSource() == tsubtree) {
                                    final Point po = canvas.consumeLastPopupPoint();
                                    bu = t.generateSubtreeReviewStacks(po.x, po.y, Display.this.layer, 1.0);
                                }
                                if (null != bu)
                                    try {
                                        bu.getWorker().join();
                                    } catch (final InterruptedException ie) {
                                        return;
                                    }
                            }
                        }
                    });
                }
            };
            for (final JMenuItem c : new JMenuItem[] { tgenerate, tslab, tsubtree, tremove }) c.addActionListener(l);
            tconnectors.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(final ActionEvent ae) {
                    for (final Tree<?> t : trees) TreeConnectorsView.create(t);
                }
            });
            popup.add(review);
            final JMenu go = new JMenu("Go");
            item = new JMenuItem("Previous branch node or start");
            item.addActionListener(this);
            go.add(item);
            item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_B, 0, true));
            item = new JMenuItem("Next branch node or end");
            item.addActionListener(this);
            go.add(item);
            item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, 0, true));
            item = new JMenuItem("Root");
            item.addActionListener(this);
            go.add(item);
            item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, 0, true));
            go.addSeparator();
            item = new JMenuItem("Last added node");
            item.addActionListener(this);
            go.add(item);
            item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L, 0, true));
            item = new JMenuItem("Last edited node");
            item.addActionListener(this);
            go.add(item);
            item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_E, 0, true));
            popup.add(go);
            final JMenu tmeasure = new JMenu("Measure");
            final JMenuItem dist_to_root = new JMenuItem("Distance from this node to root");
            tmeasure.add(dist_to_root);
            final JMenuItem dist_to_tag = new JMenuItem("Distance from this node to all nodes tagged as...");
            tmeasure.add(dist_to_tag);
            final JMenuItem dist_to_mark = new JMenuItem("Distance from this node to the marked node");
            tmeasure.add(dist_to_mark);
            final JMenuItem dist_pairs = new JMenuItem("Shortest distances between all pairs of nodes tagged as...");
            tmeasure.add(dist_pairs);
            final ActionListener tma = getTreePathMeasureListener((Tree<?>) active);
            for (final JMenuItem mi : new JMenuItem[] { dist_to_root, dist_to_tag, dist_to_mark, dist_pairs }) {
                mi.addActionListener(tma);
            }
            popup.add(tmeasure);
            final String[] name = new String[] { AreaTree.class.getSimpleName(), Treeline.class.getSimpleName() };
            if (Treeline.class == aclass) {
                final String a = name[0];
                name[0] = name[1];
                name[1] = a;
            }
            item = new JMenuItem("Duplicate " + name[0] + " as " + name[1]);
            item.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(final ActionEvent e) {
                    Bureaucrat.createAndStart(new Worker.Task("Converting") {

                        @Override
                        public void exec() {
                            try {
                                getLayerSet().addChangeTreesStep();
                                final Map<Tree<?>, Tree<?>> m = Tree.duplicateAs(selection.getSelected(), (Class<Tree<?>>) (Treeline.class == aclass ? AreaTree.class : Treeline.class));
                                if (m.isEmpty()) {
                                    getLayerSet().removeLastUndoStep();
                                } else {
                                    getLayerSet().addChangeTreesStep();
                                }
                            } catch (final Exception e) {
                                IJError.print(e);
                            }
                        }
                    }, getProject());
                }
            });
            popup.add(item);
            popup.addSeparator();
        } else if (Connector.class == aclass) {
            item = new JMenuItem("Merge");
            item.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(final ActionEvent ae) {
                    if (null == getActive() || getActive().getClass() != Connector.class) {
                        Utils.log("Active object must be a Connector!");
                        return;
                    }
                    final List<Connector> col = selection.get(Connector.class);
                    if (col.size() < 2) {
                        Utils.log("Select more than one Connector!");
                        return;
                    }
                    if (col.get(0) != getActive()) {
                        if (col.remove(getActive())) {
                            col.add(0, (Connector) getActive());
                        } else {
                            Utils.log("ERROR: cannot find active object in selection list!");
                            return;
                        }
                    }
                    Bureaucrat.createAndStart(new Worker.Task("Merging connectors") {

                        @Override
                        public void exec() {
                            getLayerSet().addChangeTreesStep();
                            Connector base = null;
                            try {
                                base = Connector.merge(col);
                            } catch (final Exception e) {
                                IJError.print(e);
                            }
                            if (null == base) {
                                Utils.log("ERROR: could not merge connectors!");
                                getLayerSet().undoOneStep();
                            } else {
                                getLayerSet().addChangeTreesStep();
                            }
                            Display.repaint();
                        }
                    }, getProject());
                }
            });
            popup.add(item);
            item.setEnabled(selection.getSelected(Connector.class).size() > 1);
            popup.addSeparator();
        }
        item = new JMenuItem("Duplicate");
        item.addActionListener(this);
        popup.add(item);
        item = new JMenuItem("Color...");
        item.addActionListener(this);
        popup.add(item);
        if (active instanceof LayerSet)
            item.setEnabled(false);
        if (active.isLocked()) {
            item = new JMenuItem("Unlock");
            item.addActionListener(this);
            popup.add(item);
        } else {
            item = new JMenuItem("Lock");
            item.addActionListener(this);
            popup.add(item);
        }
        menu = new JMenu("Move");
        popup.addSeparator();
        final LayerSet ls = layer.getParent();
        item = new JMenuItem("Move to top");
        item.addActionListener(this);
        menu.add(item);
        // this is just to draw the key name by the menu; it does not incur on any event being generated (that I know if), and certainly not any event being listened to by TrakEM2.
        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0, true));
        if (ls.isTop(active))
            item.setEnabled(false);
        item = new JMenuItem("Move up");
        item.addActionListener(this);
        menu.add(item);
        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0, true));
        if (ls.isTop(active))
            item.setEnabled(false);
        item = new JMenuItem("Move down");
        item.addActionListener(this);
        menu.add(item);
        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0, true));
        if (ls.isBottom(active))
            item.setEnabled(false);
        item = new JMenuItem("Move to bottom");
        item.addActionListener(this);
        menu.add(item);
        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_END, 0, true));
        if (ls.isBottom(active))
            item.setEnabled(false);
        popup.add(menu);
        popup.addSeparator();
        item = new JMenuItem("Delete...");
        item.addActionListener(this);
        popup.add(item);
        try {
            if (Patch.class == aclass) {
                if (!active.isOnlyLinkedTo(Patch.class)) {
                    item.setEnabled(false);
                }
            }
        } catch (final Exception e) {
            IJError.print(e);
            item.setEnabled(false);
        }
        if (Patch.class == aclass) {
            item = new JMenuItem("Revert");
            item.addActionListener(this);
            popup.add(item);
            if (null == ((Patch) active).getOriginalPath())
                item.setEnabled(false);
            popup.addSeparator();
        }
        item = new JMenuItem("Properties...");
        item.addActionListener(this);
        popup.add(item);
        item = new JMenuItem("Show centered");
        item.addActionListener(this);
        popup.add(item);
        popup.addSeparator();
        if (!(active instanceof ZDisplayable)) {
            final int i_layer = layer.getParent().indexOf(layer);
            final int n_layers = layer.getParent().size();
            item = new JMenuItem("Send to previous layer");
            item.addActionListener(this);
            popup.add(item);
            if (1 == n_layers || 0 == i_layer || active.isLinked())
                item.setEnabled(false);
            else // check if the active is a profile and contains a link to another profile in the layer it is going to be sent to, or it is linked
            if (active instanceof Profile && !active.canSendTo(layer.getParent().previous(layer)))
                item.setEnabled(false);
            item = new JMenuItem("Send to next layer");
            item.addActionListener(this);
            popup.add(item);
            if (1 == n_layers || n_layers - 1 == i_layer || active.isLinked())
                item.setEnabled(false);
            else if (active instanceof Profile && !active.canSendTo(layer.getParent().next(layer)))
                item.setEnabled(false);
            menu = new JMenu("Send linked group to...");
            if (active.hasLinkedGroupWithinLayer(this.layer)) {
                int i = 1;
                for (final Layer la : ls.getLayers()) {
                    String layer_title = i + ": " + la.getTitle();
                    if (-1 == layer_title.indexOf(' '))
                        layer_title += " ";
                    item = new JMenuItem(layer_title);
                    item.addActionListener(this);
                    menu.add(item);
                    if (la == this.layer)
                        item.setEnabled(false);
                    i++;
                }
                popup.add(menu);
            } else {
                menu.setEnabled(false);
            // Utils.log("Active's linked group not within layer.");
            }
            popup.add(menu);
            popup.addSeparator();
        }
    }
    item = new JMenuItem("Undo");
    item.addActionListener(this);
    popup.add(item);
    if (!layer.getParent().canUndo() || canvas.isTransforming())
        item.setEnabled(false);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, Utils.getControlModifier(), true));
    item = new JMenuItem("Redo");
    item.addActionListener(this);
    popup.add(item);
    if (!layer.getParent().canRedo() || canvas.isTransforming())
        item.setEnabled(false);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, Event.SHIFT_MASK | Utils.getControlModifier(), true));
    popup.addSeparator();
    try {
        menu = new JMenu("Hide/Unhide");
        item = new JMenuItem("Hide deselected");
        item.addActionListener(this);
        menu.add(item);
        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_H, Event.SHIFT_MASK, true));
        boolean none = 0 == selection.getNSelected();
        if (none)
            item.setEnabled(false);
        item = new JMenuItem("Hide deselected except images");
        item.addActionListener(this);
        menu.add(item);
        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_H, Event.SHIFT_MASK | Event.ALT_MASK, true));
        if (none)
            item.setEnabled(false);
        item = new JMenuItem("Hide selected");
        item.addActionListener(this);
        menu.add(item);
        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_H, 0, true));
        if (none)
            item.setEnabled(false);
        none = !layer.getParent().containsDisplayable(DLabel.class);
        item = new JMenuItem("Hide all labels");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        item = new JMenuItem("Unhide all labels");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        none = !layer.getParent().contains(AreaList.class);
        item = new JMenuItem("Hide all arealists");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        item = new JMenuItem("Unhide all arealists");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        none = !layer.contains(Profile.class);
        item = new JMenuItem("Hide all profiles");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        item = new JMenuItem("Unhide all profiles");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        none = !layer.getParent().contains(Pipe.class);
        item = new JMenuItem("Hide all pipes");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        item = new JMenuItem("Unhide all pipes");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        none = !layer.getParent().contains(Polyline.class);
        item = new JMenuItem("Hide all polylines");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        item = new JMenuItem("Unhide all polylines");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        none = !layer.getParent().contains(Treeline.class);
        item = new JMenuItem("Hide all treelines");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        item = new JMenuItem("Unhide all treelines");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        none = !layer.getParent().contains(AreaTree.class);
        item = new JMenuItem("Hide all areatrees");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        item = new JMenuItem("Unhide all areatrees");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        none = !layer.getParent().contains(Ball.class);
        item = new JMenuItem("Hide all balls");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        item = new JMenuItem("Unhide all balls");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        none = !layer.getParent().contains(Connector.class);
        item = new JMenuItem("Hide all connectors");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        item = new JMenuItem("Unhide all connectors");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        none = !layer.getParent().containsDisplayable(Patch.class);
        item = new JMenuItem("Hide all images");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        item = new JMenuItem("Unhide all images");
        item.addActionListener(this);
        menu.add(item);
        if (none)
            item.setEnabled(false);
        item = new JMenuItem("Hide all but images");
        item.addActionListener(this);
        menu.add(item);
        item = new JMenuItem("Unhide all");
        item.addActionListener(this);
        menu.add(item);
        item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_H, Event.ALT_MASK, true));
        popup.add(menu);
    } catch (final Exception e) {
        IJError.print(e);
    }
    // plugins, if any
    Utils.addPlugIns(popup, "Display", project, new Callable<Displayable>() {

        @Override
        public Displayable call() {
            return Display.this.getActive();
        }
    });
    final JMenu align_menu = new JMenu("Align");
    item = new JMenuItem("Align stack slices");
    item.addActionListener(this);
    align_menu.add(item);
    if (selection.isEmpty() || !(getActive().getClass() == Patch.class && ((Patch) getActive()).isStack()))
        item.setEnabled(false);
    item = new JMenuItem("Align layers");
    item.addActionListener(this);
    align_menu.add(item);
    if (1 == layer.getParent().size())
        item.setEnabled(false);
    item = new JMenuItem("Align layers manually with landmarks");
    item.addActionListener(this);
    align_menu.add(item);
    if (1 == layer.getParent().size())
        item.setEnabled(false);
    item = new JMenuItem("Align multi-layer mosaic");
    item.addActionListener(this);
    align_menu.add(item);
    if (1 == layer.getParent().size())
        item.setEnabled(false);
    item = new JMenuItem("Montage all images in this layer");
    item.addActionListener(this);
    align_menu.add(item);
    if (layer.getDisplayables(Patch.class).size() < 2)
        item.setEnabled(false);
    item = new JMenuItem("Montage selected images");
    item.addActionListener(this);
    align_menu.add(item);
    if (selection.getSelected(Patch.class).size() < 2)
        item.setEnabled(false);
    item = new JMenuItem("Montage multiple layers");
    item.addActionListener(this);
    align_menu.add(item);
    popup.add(align_menu);
    final JMenuItem st = new JMenu("Transform");
    final StartTransformMenuListener tml = new StartTransformMenuListener();
    item = new JMenuItem("Transform (affine)");
    item.addActionListener(tml);
    st.add(item);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_T, 0, true));
    if (null == active)
        item.setEnabled(false);
    item = new JMenuItem("Transform (non-linear)");
    item.addActionListener(tml);
    st.add(item);
    if (null == active)
        item.setEnabled(false);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_T, Event.SHIFT_MASK, true));
    item = new JMenuItem("Cancel transform");
    st.add(item);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, true));
    // just added as a self-documenting cue; no listener
    item.setEnabled(false);
    item = new JMenuItem("Remove rotation, scaling and shear (selected images)");
    item.addActionListener(tml);
    st.add(item);
    if (null == active)
        item.setEnabled(false);
    item = new JMenuItem("Remove rotation, scaling and shear layer-wise");
    item.addActionListener(tml);
    st.add(item);
    item = new JMenuItem("Remove coordinate transforms (selected images)");
    item.addActionListener(tml);
    st.add(item);
    if (null == active)
        item.setEnabled(false);
    item = new JMenuItem("Remove coordinate transforms layer-wise");
    item.addActionListener(tml);
    st.add(item);
    item = new JMenuItem("Adjust mesh resolution (selected images)");
    item.addActionListener(tml);
    st.add(item);
    if (null == active)
        item.setEnabled(false);
    item = new JMenuItem("Adjust mesh resolution layer-wise");
    item.addActionListener(tml);
    st.add(item);
    item = new JMenuItem("Set coordinate transform of selected image to other selected images");
    item.addActionListener(tml);
    st.add(item);
    if (null == active)
        item.setEnabled(false);
    item = new JMenuItem("Set coordinate transform of selected image layer-wise");
    item.addActionListener(tml);
    st.add(item);
    if (null == active)
        item.setEnabled(false);
    item = new JMenuItem("Set affine transform of selected image to other selected images");
    item.addActionListener(tml);
    st.add(item);
    if (null == active)
        item.setEnabled(false);
    item = new JMenuItem("Set affine transform of selected image layer-wise");
    item.addActionListener(tml);
    st.add(item);
    if (null == active)
        item.setEnabled(false);
    popup.add(st);
    final JMenu link_menu = new JMenu("Link");
    item = new JMenuItem("Link images...");
    item.addActionListener(this);
    link_menu.add(item);
    item = new JMenuItem("Unlink all selected images");
    item.addActionListener(this);
    link_menu.add(item);
    item.setEnabled(selection.getSelected(Patch.class).size() > 0);
    item = new JMenuItem("Unlink all");
    item.addActionListener(this);
    link_menu.add(item);
    popup.add(link_menu);
    final JMenu adjust_menu = new JMenu("Adjust images");
    item = new JMenuItem("Enhance contrast layer-wise...");
    item.addActionListener(this);
    adjust_menu.add(item);
    item = new JMenuItem("Enhance contrast (selected images)...");
    item.addActionListener(this);
    adjust_menu.add(item);
    if (selection.isEmpty())
        item.setEnabled(false);
    item = new JMenuItem("Adjust image filters (selected images)");
    item.addActionListener(this);
    adjust_menu.add(item);
    if (selection.isEmpty())
        item.setEnabled(false);
    item = new JMenuItem("Set Min and Max layer-wise...");
    item.addActionListener(this);
    adjust_menu.add(item);
    item = new JMenuItem("Set Min and Max (selected images)...");
    item.addActionListener(this);
    adjust_menu.add(item);
    if (selection.isEmpty())
        item.setEnabled(false);
    item = new JMenuItem("Adjust min and max (selected images)...");
    item.addActionListener(this);
    adjust_menu.add(item);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_J, 0));
    if (selection.isEmpty())
        item.setEnabled(false);
    item = new JMenuItem("Mask image borders (layer-wise)...");
    item.addActionListener(this);
    adjust_menu.add(item);
    item = new JMenuItem("Mask image borders (selected images)...");
    item.addActionListener(this);
    adjust_menu.add(item);
    if (selection.isEmpty())
        item.setEnabled(false);
    item = new JMenuItem("Remove alpha masks (layer-wise)...");
    item.addActionListener(this);
    adjust_menu.add(item);
    item = new JMenuItem("Remove alpha masks (selected images)...");
    item.addActionListener(this);
    adjust_menu.add(item);
    if (selection.isEmpty())
        item.setEnabled(false);
    item = new JMenuItem("Split images under polyline ROI");
    item.addActionListener(this);
    adjust_menu.add(item);
    final Roi roi = canvas.getFakeImagePlus().getRoi();
    if (null == roi || !(roi.getType() == Roi.POLYLINE || roi.getType() == Roi.FREELINE))
        item.setEnabled(false);
    item = new JMenuItem("Blend (layer-wise)...");
    item.addActionListener(this);
    adjust_menu.add(item);
    item = new JMenuItem("Blend (selected images)...");
    item.addActionListener(this);
    adjust_menu.add(item);
    if (selection.isEmpty())
        item.setEnabled(false);
    item = new JMenuItem("Match intensities (layer-wise)...");
    item.addActionListener(this);
    adjust_menu.add(item);
    item = new JMenuItem("Remove intensity maps (layer-wise)...");
    item.addActionListener(this);
    adjust_menu.add(item);
    popup.add(adjust_menu);
    final JMenu script = new JMenu("Script");
    final MenuScriptListener msl = new MenuScriptListener();
    item = new JMenuItem("Set preprocessor script layer-wise...");
    item.addActionListener(msl);
    script.add(item);
    item = new JMenuItem("Set preprocessor script (selected images)...");
    item.addActionListener(msl);
    script.add(item);
    if (selection.isEmpty())
        item.setEnabled(false);
    item = new JMenuItem("Remove preprocessor script layer-wise...");
    item.addActionListener(msl);
    script.add(item);
    item = new JMenuItem("Remove preprocessor script (selected images)...");
    item.addActionListener(msl);
    script.add(item);
    if (selection.isEmpty())
        item.setEnabled(false);
    popup.add(script);
    menu = new JMenu("Import");
    item = new JMenuItem("Import image");
    item.addActionListener(this);
    menu.add(item);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_I, Event.ALT_MASK & Event.SHIFT_MASK, true));
    item = new JMenuItem("Import stack...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Import stack with landmarks...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Import grid...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Import sequence as grid...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Import from text file...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Import labels as arealists...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Tags ...");
    item.addActionListener(this);
    menu.add(item);
    popup.add(menu);
    menu = new JMenu("Export");
    final boolean has_arealists = layer.getParent().contains(AreaList.class);
    item = new JMenuItem("Make flat image...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Arealists as labels (tif)");
    item.addActionListener(this);
    menu.add(item);
    item.setEnabled(has_arealists);
    item = new JMenuItem("Arealists as labels (amira)");
    item.addActionListener(this);
    menu.add(item);
    item.setEnabled(has_arealists);
    item = new JMenuItem("Image stack under selected Arealist");
    item.addActionListener(this);
    menu.add(item);
    item.setEnabled(null != active && AreaList.class == active.getClass());
    item = new JMenuItem("Fly through selected Treeline/AreaTree");
    item.addActionListener(this);
    menu.add(item);
    item.setEnabled(null != active && Tree.class.isInstance(active));
    item = new JMenuItem("Tags...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Connectivity graph...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("NeuroML...");
    item.addActionListener(this);
    menu.add(item);
    popup.add(menu);
    menu = new JMenu("Display");
    item = new JMenuItem("Resize canvas/LayerSet...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Autoresize canvas/LayerSet");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Resize canvas/LayerSet to ROI");
    item.addActionListener(this);
    menu.add(item);
    item.setEnabled(null != canvas.getFakeImagePlus().getRoi());
    item = new JMenuItem("Properties ...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Calibration...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Grid overlay...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Adjust snapping parameters...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Adjust fast-marching parameters...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Adjust arealist paint parameters...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Show current 2D position in 3D");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Show layers as orthoslices in 3D");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Inspect image mesh triangles");
    item.addActionListener(this);
    menu.add(item);
    popup.add(menu);
    menu = new JMenu("Project");
    this.project.getLoader().setupMenuItems(menu, this.getProject());
    item = new JMenuItem("Project properties...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Create subproject");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Create sibling project with retiled layers");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Release memory...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Flush image cache");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Regenerate all mipmaps");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Regenerate mipmaps (selected images)");
    item.addActionListener(this);
    menu.add(item);
    menu.addSeparator();
    item = new JMenuItem("Measurement options...");
    item.addActionListener(this);
    menu.add(item);
    popup.add(menu);
    menu = new JMenu("Selection");
    item = new JMenuItem("Select all");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Select all visible");
    item.addActionListener(this);
    menu.add(item);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, Utils.getControlModifier(), true));
    if (0 == layer.getDisplayableList().size() && 0 == layer.getParent().getDisplayableList().size())
        item.setEnabled(false);
    item = new JMenuItem("Select all that match...");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Select none");
    item.addActionListener(this);
    menu.add(item);
    if (0 == selection.getNSelected())
        item.setEnabled(false);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, true));
    final JMenu bytype = new JMenu("Select all by type");
    item = new JMenuItem("AreaList");
    item.addActionListener(bytypelistener);
    bytype.add(item);
    item = new JMenuItem("AreaTree");
    item.addActionListener(bytypelistener);
    bytype.add(item);
    item = new JMenuItem("Ball");
    item.addActionListener(bytypelistener);
    bytype.add(item);
    item = new JMenuItem("Connector");
    item.addActionListener(bytypelistener);
    bytype.add(item);
    item = new JMenuItem("Dissector");
    item.addActionListener(bytypelistener);
    bytype.add(item);
    item = new JMenuItem("Image");
    item.addActionListener(bytypelistener);
    bytype.add(item);
    item = new JMenuItem("Pipe");
    item.addActionListener(bytypelistener);
    bytype.add(item);
    item = new JMenuItem("Polyline");
    item.addActionListener(bytypelistener);
    bytype.add(item);
    item = new JMenuItem("Profile");
    item.addActionListener(bytypelistener);
    bytype.add(item);
    item = new JMenuItem("Text");
    item.addActionListener(bytypelistener);
    bytype.add(item);
    item = new JMenuItem("Treeline");
    item.addActionListener(bytypelistener);
    bytype.add(item);
    menu.add(bytype);
    item = new JMenuItem("Restore selection");
    item.addActionListener(this);
    menu.add(item);
    item = new JMenuItem("Select under ROI");
    item.addActionListener(this);
    menu.add(item);
    if (canvas.getFakeImagePlus().getRoi() == null)
        item.setEnabled(false);
    final JMenu graph = new JMenu("Graph");
    final GraphMenuListener gl = new GraphMenuListener();
    item = new JMenuItem("Select outgoing Connectors");
    item.addActionListener(gl);
    graph.add(item);
    item = new JMenuItem("Select incoming Connectors");
    item.addActionListener(gl);
    graph.add(item);
    item = new JMenuItem("Select downstream targets");
    item.addActionListener(gl);
    graph.add(item);
    item = new JMenuItem("Select upstream targets");
    item.addActionListener(gl);
    graph.add(item);
    graph.setEnabled(!selection.isEmpty());
    menu.add(graph);
    item = new JMenuItem("Measure");
    item.addActionListener(this);
    menu.add(item);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_M, 0, true));
    item.setEnabled(!selection.isEmpty());
    popup.add(menu);
    menu = new JMenu("Tool");
    item = new JMenuItem("Rectangular ROI");
    item.addActionListener(new SetToolListener(Toolbar.RECTANGLE));
    menu.add(item);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0, true));
    item = new JMenuItem("Polygon ROI");
    item.addActionListener(new SetToolListener(Toolbar.POLYGON));
    menu.add(item);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0, true));
    item = new JMenuItem("Freehand ROI");
    item.addActionListener(new SetToolListener(Toolbar.FREEROI));
    menu.add(item);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F3, 0, true));
    item = new JMenuItem("Text");
    item.addActionListener(new SetToolListener(Toolbar.TEXT));
    menu.add(item);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F4, 0, true));
    item = new JMenuItem("Magnifier glass");
    item.addActionListener(new SetToolListener(Toolbar.MAGNIFIER));
    menu.add(item);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F5, 0, true));
    item = new JMenuItem("Hand");
    item.addActionListener(new SetToolListener(Toolbar.HAND));
    menu.add(item);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F6, 0, true));
    item = new JMenuItem("Select");
    item.addActionListener(new SetToolListener(ProjectToolbar.SELECT));
    menu.add(item);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F9, 0, true));
    item = new JMenuItem("Pencil");
    item.addActionListener(new SetToolListener(ProjectToolbar.PENCIL));
    menu.add(item);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F10, 0, true));
    item = new JMenuItem("Pen");
    item.addActionListener(new SetToolListener(ProjectToolbar.PEN));
    menu.add(item);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F11, 0, true));
    popup.add(menu);
    item = new JMenuItem("Search...");
    item.addActionListener(this);
    popup.add(item);
    item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F, Utils.getControlModifier(), true));
    // canvas.add(popup);
    return popup;
}
Also used : AlignTask(mpicbg.trakem2.align.AlignTask) AlignLayersTask(mpicbg.trakem2.align.AlignLayersTask) DistortionCorrectionTask(lenscorrection.DistortionCorrectionTask) ActionEvent(java.awt.event.ActionEvent) Bureaucrat(ini.trakem2.utils.Bureaucrat) ArrayList(java.util.ArrayList) List(java.util.List) CoordinateTransformList(mpicbg.trakem2.transform.CoordinateTransformList) HashSet(java.util.HashSet) Color(java.awt.Color) PolygonRoi(ij.gui.PolygonRoi) ShapeRoi(ij.gui.ShapeRoi) Roi(ij.gui.Roi) ActionListener(java.awt.event.ActionListener) DBObject(ini.trakem2.persistence.DBObject) InspectPatchTrianglesMode(ini.trakem2.display.inspect.InspectPatchTrianglesMode) GenericDialog(ij.gui.GenericDialog) Worker(ini.trakem2.utils.Worker) JMenuItem(javax.swing.JMenuItem) Point(java.awt.Point) TreeMap(java.util.TreeMap) JPopupMenu(javax.swing.JPopupMenu) Point(java.awt.Point) NoninvertibleTransformException(java.awt.geom.NoninvertibleTransformException) JMenu(javax.swing.JMenu)

Example 7 with Pair

use of mpicbg.trakem2.util.Downsampler.Pair in project TrakEM2 by trakem2.

the class DownsamplerTest method main.

/**
 * @param args
 */
public static void main(final String[] args) {
    new ImageJ();
    final Timer timer = new Timer();
    final ImagePlus imp = new ImagePlus("/home/saalfeld/tmp/fetter-example.tif");
    // final ImagePlus imp = new ImagePlus( "/home/albert/Desktop/t2/fetter-example.tif" );
    // final ImagePlus imp = new ImagePlus( "/home/saalfeld/Desktop/norway.jpg" );
    imp.show();
    final ImageProcessor ip = imp.getProcessor().duplicate();
    System.out.println("short");
    final ShortProcessor ipShort = (ShortProcessor) ip.convertToShort(false);
    for (int i = 0; i < n; ++i) {
        timer.start();
        testShort(ipShort);
        final long t = timer.stop();
        System.out.println(i + ": " + t + "ms");
    }
    System.out.println("downsampleShort() + downsampleByteProcessor() (independent short with byte mapping + alpha)");
    for (int i = 0; i < n; ++i) {
        final Pair<ShortProcessor, byte[]> ba = new Pair<ShortProcessor, byte[]>(ipShort, (byte[]) ipShort.convertToByte(true).getPixels());
        final ByteProcessor alpha = new ByteProcessor(ipShort.getWidth(), ipShort.getHeight(), (byte[]) ipShort.convertToByte(true).getPixels(), null);
        timer.start();
        testShortAlphaIndependently(ba, alpha);
        final long t = timer.stop();
        System.out.println(i + ": " + t + "ms");
    }
    System.out.println("downsampleShortProcessor() + convertToByte() + downsampleByteProcessor() (independent short + byte mapping + alpha)");
    for (int i = 0; i < n; ++i) {
        final ByteProcessor alpha = new ByteProcessor(ipShort.getWidth(), ipShort.getHeight(), (byte[]) ipShort.convertToByte(true).getPixels(), null);
        timer.start();
        testShortAlphaByteMappingIndependently(ipShort, alpha);
        final long t = timer.stop();
        System.out.println(i + ": " + t + "ms");
    }
    System.out.println("float");
    final FloatProcessor ipFloat = (FloatProcessor) ip.convertToFloat();
    for (int i = 0; i < n; ++i) {
        timer.start();
        testFloat(ipFloat);
        final long t = timer.stop();
        System.out.println(i + ": " + t + "ms");
    }
    System.out.println("independent float with byte mapping + alpha");
    for (int i = 0; i < n; ++i) {
        final Pair<FloatProcessor, byte[]> ba = new Pair<FloatProcessor, byte[]>(ipFloat, (byte[]) ipShort.convertToByte(true).getPixels());
        final ByteProcessor alpha = new ByteProcessor(ipShort.getWidth(), ipShort.getHeight(), (byte[]) ipShort.convertToByte(true).getPixels(), null);
        timer.start();
        testFloatAlphaIndependently(ba, alpha);
        final long t = timer.stop();
        System.out.println(i + ": " + t + "ms");
    }
    System.out.println("byte");
    final ByteProcessor ipByte = (ByteProcessor) ip.convertToByte(true);
    for (int i = 0; i < n; ++i) {
        timer.start();
        testByte(ipByte);
        final long t = timer.stop();
        System.out.println(i + ": " + t + "ms");
    }
    System.out.println("2 x byte");
    final ByteProcessor ipByte2 = (ByteProcessor) ipByte.duplicate();
    for (int i = 0; i < n; ++i) {
        timer.start();
        testByte(ipByte);
        testByte(ipByte2);
        final long t = timer.stop();
        System.out.println(i + ": " + t + "ms");
    }
    System.out.println("color");
    final ColorProcessor ipColor = (ColorProcessor) ip.convertToRGB();
    for (int i = 0; i < n; ++i) {
        timer.start();
        testColor(ipColor);
        final long t = timer.stop();
        System.out.println(i + ": " + t + "ms");
    }
    System.out.println("independent color with byte mapping + alpha");
    for (int i = 0; i < n; ++i) {
        final byte[][] rgb = new byte[4][ipColor.getWidth() * ipColor.getHeight()];
        ipColor.getRGB(rgb[0], rgb[1], rgb[2]);
        final Pair<ColorProcessor, byte[][]> ba = new Pair<ColorProcessor, byte[][]>(ipColor, rgb);
        final ByteProcessor alpha = new ByteProcessor(ipShort.getWidth(), ipShort.getHeight(), (byte[]) ipShort.convertToByte(true).getPixels(), null);
        timer.start();
        testColorAlphaIndependently(ba, alpha);
        final long t = timer.stop();
        System.out.println(i + ": " + t + "ms");
    }
    System.out.println("alpha + outside");
    for (int i = 0; i < n; ++i) {
        ByteProcessor outside = new ByteProcessor(ipByte.getWidth(), ipByte.getHeight());
        outside.setRoi(new OvalRoi(100, 100, ipByte.getWidth() - 200, ipByte.getHeight() - 200));
        outside.setValue(255);
        outside.fill(outside.getMask());
        final Pair<ByteProcessor, ByteProcessor> ba = new Pair<ByteProcessor, ByteProcessor>(ipByte, outside);
        timer.start();
        testAlphaOutside(ba);
        final long t = timer.stop();
        System.out.println(i + ": " + t + "ms");
    }
    System.out.println("outside");
    for (int i = 0; i < n; ++i) {
        ByteProcessor outside = new ByteProcessor(ipByte.getWidth(), ipByte.getHeight());
        outside.setRoi(new OvalRoi(100, 100, ipByte.getWidth() - 200, ipByte.getHeight() - 200));
        outside.setValue(255);
        outside.fill(outside.getMask());
        timer.start();
        testOutside(outside);
        final long t = timer.stop();
        System.out.println(i + ": " + t + "ms");
    }
// System.out.println( "byte integral" );
// final ByteProcessor ipByteI = ( ByteProcessor )ipShort.convertToByte( true );
// 
// for ( int i = 0; i < 10; ++i )
// {
// timer.start();
// testByteIntegral( ipByteI );
// final long t = timer.stop();
// System.out.println( i + ": " + t  + "ms" );
// }
}
Also used : ByteProcessor(ij.process.ByteProcessor) FloatProcessor(ij.process.FloatProcessor) OvalRoi(ij.gui.OvalRoi) ImagePlus(ij.ImagePlus) ShortProcessor(ij.process.ShortProcessor) ImageJ(ij.ImageJ) ImageProcessor(ij.process.ImageProcessor) ColorProcessor(ij.process.ColorProcessor) Timer(mpicbg.util.Timer) Pair(mpicbg.trakem2.util.Downsampler.Pair)

Example 8 with Pair

use of mpicbg.trakem2.util.Downsampler.Pair in project TrakEM2 by trakem2.

the class BlockMatchPairCallable method makeFlatImage.

/**
 * Use different methods depending on the dimensions of the target image and the availability of mipmaps.
 * The goal is to obtain the best possible image.
 *
 * The alpha channel is returned with values between [0..1]
 *
 * @param layer
 * @param patches
 * @param box
 * @param scale
 * @return
 */
private Pair<FloatProcessor, FloatProcessor> makeFlatImage(final Layer layer, final List<Patch> patches, final Rectangle box, final double scale) {
    final Pair<FloatProcessor, FloatProcessor> pair = new ExportBestFlatImage(patches, box, 0, scale).makeFlatFloatGrayImageAndAlpha();
    // Map alpha from 8-bit to the range [0..1]
    final float[] alpha = (float[]) pair.b.getPixels();
    for (int i = 0; i < alpha.length; ++i) {
        alpha[i] = alpha[i] / 255f;
    }
    return pair;
}
Also used : FloatProcessor(ij.process.FloatProcessor) ExportBestFlatImage(mpicbg.trakem2.transform.ExportBestFlatImage) Point(mpicbg.models.Point)

Example 9 with Pair

use of mpicbg.trakem2.util.Downsampler.Pair in project TrakEM2 by trakem2.

the class ExportARGB method makeFlatImageARGBFromMipMaps.

/**
 * Returns nonsense or throws an Exception if mipmaps are not available.
 * Limited to 2GB arrays for the final image.
 *
 * @param patches
 * @param roi
 * @param backgroundValue
 * @param scale
 * @return
 */
public static final Pair<ColorProcessor, ByteProcessor> makeFlatImageARGBFromMipMaps(final List<Patch> patches, final Rectangle roi, final double backgroundValue, final double scale) {
    final int width = (int) (roi.width * scale);
    final int height = (int) (roi.height * scale);
    // Process the three channels separately in order to use proper alpha composition
    final ColorProcessor target = new ColorProcessor(width, height);
    target.setInterpolationMethod(ImageProcessor.BILINEAR);
    final ByteProcessor targetMask = new ByteProcessor(width, height);
    targetMask.setInterpolationMethod(ImageProcessor.BILINEAR);
    final Loader loader = patches.get(0).getProject().getLoader();
    for (final Patch patch : patches) {
        // MipMap image, already including any coordinate transforms and the alpha mask (if any), by definition.
        final MipMapImage mipMap = loader.fetchImage(patch, scale);
        // / DEBUG: is there an alpha channel at all?
        // new ij.ImagePlus("alpha of " + patch.getTitle(), new ByteProcessor( mipMap.image.getWidth(null), mipMap.image.getHeight(null), new ColorProcessor( mipMap.image ).getChannel( 4 ))).show();
        // Yes, there is, even though the mipmap images have the alpha pre-multiplied
        // Work-around strange bug that makes mipmap-loaded images paint with 7-bit depth instead of 8-bit depth
        final BufferedImage bi = new BufferedImage(mipMap.image.getWidth(null), mipMap.image.getHeight(null), BufferedImage.TYPE_INT_ARGB);
        final Graphics2D g2d = bi.createGraphics();
        g2d.drawImage(mipMap.image, 0, 0, null);
        g2d.dispose();
        final int[] pix = extractARGBIntArray(bi);
        bi.flush();
        // DEBUG: does the BufferedImage have the alpha channel?
        // {
        // final byte[] aa = new byte[pix.length];
        // for (int i=0; i<aa.length; ++i) aa[i] = (byte)((pix[i] & 0xff000000) >> 24);
        // new ij.ImagePlus("alpha of BI of " + patch.getTitle(), new ByteProcessor(bi.getWidth(), bi.getHeight(), aa)).show();
        // }
        // YES: the alpha, containing the outside too. All fine.
        final ByteProcessor alpha;
        final ColorProcessor rgb = new ColorProcessor(bi.getWidth(), bi.getHeight(), pix);
        if (patch.hasAlphaChannel()) {
            // The mipMap has the alpha channel in it, even if the alpha is pre-multiplied as well onto the images.
            final byte[] a = new byte[pix.length];
            for (int i = 0; i < a.length; ++i) {
                a[i] = (byte) ((pix[i] & 0xff000000) >> 24);
            }
            alpha = new ByteProcessor(bi.getWidth(), bi.getHeight(), a);
        } else {
            alpha = new ByteProcessor(bi.getWidth(), bi.getHeight());
            Arrays.fill((byte[]) alpha.getPixels(), (byte) 255);
        }
        // The affine to apply to the MipMap.image
        final AffineTransform atc = new AffineTransform();
        atc.scale(scale, scale);
        atc.translate(-roi.x, -roi.y);
        final AffineTransform at = new AffineTransform();
        at.preConcatenate(atc);
        at.concatenate(patch.getAffineTransform());
        at.scale(mipMap.scaleX, mipMap.scaleY);
        final AffineModel2D aff = new AffineModel2D();
        aff.set(at);
        final CoordinateTransformMesh mesh = new CoordinateTransformMesh(aff, patch.getMeshResolution(), bi.getWidth(), bi.getHeight());
        final TransformMeshMappingWithMasks<CoordinateTransformMesh> mapping = new TransformMeshMappingWithMasks<CoordinateTransformMesh>(mesh);
        // no interpolation
        alpha.setInterpolationMethod(ImageProcessor.NEAREST_NEIGHBOR);
        rgb.setInterpolationMethod(ImageProcessor.BILINEAR);
        mapping.map(rgb, alpha, target, targetMask);
    }
    return new Pair<ColorProcessor, ByteProcessor>(target, targetMask);
}
Also used : ByteProcessor(ij.process.ByteProcessor) Loader(ini.trakem2.persistence.Loader) BufferedImage(java.awt.image.BufferedImage) Graphics2D(java.awt.Graphics2D) ColorProcessor(ij.process.ColorProcessor) MipMapImage(ini.trakem2.display.MipMapImage) CoordinateTransformMesh(mpicbg.models.CoordinateTransformMesh) AffineTransform(java.awt.geom.AffineTransform) Patch(ini.trakem2.display.Patch) Pair(mpicbg.trakem2.util.Pair)

Example 10 with Pair

use of mpicbg.trakem2.util.Downsampler.Pair in project TrakEM2 by trakem2.

the class ExportBestFlatImage method makeFlatGrayImageAndAlpha.

/**
 * @return Return null when dimensions make the array larger than 2GB.
 */
public Pair<ByteProcessor, ByteProcessor> makeFlatGrayImageAndAlpha() {
    printInfo();
    if (canUseAWTImage()) {
        // In color to preserve the alpha channel present in mipmaps
        final Image img = createAWTImage(ImagePlus.COLOR_RGB);
        final int width = img.getWidth(null);
        final int height = img.getHeight(null);
        final int[] pixels = new int[width * height];
        PixelGrabber pg = new PixelGrabber(img, 0, 0, width, height, pixels, 0, width);
        try {
            pg.grabPixels();
        } catch (InterruptedException e) {
        }
        ;
        final byte[] grey = new byte[pixels.length];
        final byte[] alpha = new byte[pixels.length];
        for (int i = 0; i < pixels.length; ++i) {
            final int p = pixels[i];
            alpha[i] = (byte) ((p & 0xff000000) >> 24);
            grey[i] = (byte) ((((p & 0x00ff0000) >> 16) + ((p & 0x0000ff00) >> 8) + (p & 0x000000ff)) / 3f);
        }
        return new Pair<ByteProcessor, ByteProcessor>(new ByteProcessor(width, height, grey, null), new ByteProcessor(width, height, alpha, null));
    }
    if (!isSmallerThan2GB()) {
        Utils.log("Cannot create an image larger than 2 GB.");
        return null;
    }
    if (loader.isMipMapsRegenerationEnabled()) {
        // Use mipmaps directly: they are already Gaussian-downsampled
        return ExportUnsignedByte.makeFlatImageFromMipMaps(patches, finalBox, 0, scale);
    }
    // Else: no mipmaps
    return ExportUnsignedByte.makeFlatImageFromOriginals(patches, finalBox, 0, scale);
}
Also used : ByteProcessor(ij.process.ByteProcessor) PixelGrabber(java.awt.image.PixelGrabber) Image(java.awt.Image) Pair(mpicbg.trakem2.util.Pair)

Aggregations

ByteProcessor (ij.process.ByteProcessor)9 Pair (mpicbg.trakem2.util.Pair)7 Patch (ini.trakem2.display.Patch)6 ArrayList (java.util.ArrayList)6 Point (mpicbg.models.Point)5 ColorProcessor (ij.process.ColorProcessor)4 FloatProcessor (ij.process.FloatProcessor)4 AffineTransform (java.awt.geom.AffineTransform)4 NotEnoughDataPointsException (mpicbg.models.NotEnoughDataPointsException)4 PointMatch (mpicbg.models.PointMatch)4 Triple (mpicbg.trakem2.util.Triple)4 Layer (ini.trakem2.display.Layer)3 AffineModel2D (mpicbg.models.AffineModel2D)3 RigidModel2D (mpicbg.models.RigidModel2D)3 SimilarityModel2D (mpicbg.models.SimilarityModel2D)3 TranslationModel2D (mpicbg.models.TranslationModel2D)3 ShortProcessor (ij.process.ShortProcessor)2 Image (java.awt.Image)2 CoordinateTransformMesh (mpicbg.models.CoordinateTransformMesh)2 Spring (mpicbg.models.Spring)2