Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add overlay() function to display a html overlay #1438

Merged
merged 1 commit into from
Mar 31, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/main/java/net/rptools/maptool/client/MapToolLineParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ private enum CodeType { // Mutually exclusive code-execution options
private enum OutputLoc { // Mutually exclusive output location
CHAT,
DIALOG,
OVERLAY,
DIALOG5,
FRAME,
FRAME5
Expand Down Expand Up @@ -357,6 +358,8 @@ private enum OptionType {
DIALOG5("dialog5", 1, 2, "\"\""),
// HTML webView
FRAME5("frame5", 1, 2, "\"\""),
// HTML overlay
OVERLAY("overlay", 0, 1, "\"\""),
// Run for another token
TOKEN("token", 1, 1);

Expand Down Expand Up @@ -517,6 +520,10 @@ private void parseOptionString(String optionString, int start) throws RollOption
matcher.region(start, endOfString);
List<String> paramList = new ArrayList<String>();
boolean lastItem = false; // true if last match ended in ")"
if (")".equals(optionString.substring(start))) {
lastItem = true;
start += 1;
}

while (!lastItem) {
if (matcher.find()) {
Expand Down Expand Up @@ -1028,6 +1035,11 @@ public String parseLine(
frameOpts = option.getParsedParam(1, resolver, tokenInContext).toString();
outputTo = OutputLoc.FRAME5;
break;
case OVERLAY:
codeType = CodeType.CODEBLOCK;
outputTo = OutputLoc.OVERLAY;
frameOpts = option.getParsedParam(0, resolver, tokenInContext).toString();
break;
///////////////////////////////////////////////////
// CODE OPTIONS
///////////////////////////////////////////////////
Expand Down Expand Up @@ -1424,6 +1436,9 @@ public String parseLine(
HTMLFrameFactory.show(
frameName, false, false, frameOpts, expressionBuilder.toString());
break;
case OVERLAY:
MapTool.getFrame().getHtmlOverlay().updateContents(expressionBuilder.toString());
break;
case CHAT:
builder.append(expressionBuilder);
break;
Expand Down
58 changes: 45 additions & 13 deletions src/main/java/net/rptools/maptool/client/ui/MapToolFrame.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,7 @@

import com.jidesoft.docking.DefaultDockableHolder;
import com.jidesoft.docking.DockableFrame;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Desktop;
import java.awt.EventQueue;
import java.awt.GraphicsConfiguration;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.IllegalComponentStateException;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.*;
import java.awt.desktop.AboutEvent;
import java.awt.desktop.AboutHandler;
import java.awt.desktop.PreferencesEvent;
Expand Down Expand Up @@ -123,6 +112,7 @@
import net.rptools.maptool.client.ui.drawpanel.DrawPanelTreeCellRenderer;
import net.rptools.maptool.client.ui.drawpanel.DrawPanelTreeModel;
import net.rptools.maptool.client.ui.drawpanel.DrawablesPanel;
import net.rptools.maptool.client.ui.htmlframe.HTMLOverlay;
import net.rptools.maptool.client.ui.lookuptable.LookupTablePanel;
import net.rptools.maptool.client.ui.macrobuttons.buttons.MacroButton;
import net.rptools.maptool.client.ui.macrobuttons.panels.*;
Expand Down Expand Up @@ -181,6 +171,8 @@ public class MapToolFrame extends DefaultDockableHolder
private final ClientConnectionPanel connectionPanel;
/** The panel showing the initiative order. */
private final InitiativePanel initiativePanel;
/** The HTML pane showing the map overlay. */
private final HTMLOverlay htmlOverlay;

private final PointerOverlay pointerOverlay;
private final CommandPanel commandPanel;
Expand Down Expand Up @@ -462,6 +454,7 @@ public MapToolFrame(JMenuBar menuBar) {
connectionPanel = createConnectionPanel();
toolbox = new Toolbox();
initiativePanel = createInitiativePanel();
htmlOverlay = new HTMLOverlay();

zoneRendererList = new CopyOnWriteArrayList<ZoneRenderer>();
pointerOverlay = new PointerOverlay();
Expand Down Expand Up @@ -512,9 +505,15 @@ public MapToolFrame(JMenuBar menuBar) {
commandPanel = new CommandPanel();
MapTool.getMessageList().addObserver(commandPanel);

// Setup a JLayeredPane to display the HTML overlay over the map.
JLayeredPane zoneRenderLayered = new JLayeredPane();
zoneRenderLayered.setLayout(new LayeredPaneLayout());
zoneRenderLayered.add(zoneRendererPanel, JLayeredPane.DEFAULT_LAYER);
zoneRenderLayered.add(htmlOverlay, JLayeredPane.POPUP_LAYER);

rendererBorderPanel = new JPanel(new GridLayout());
rendererBorderPanel.setBorder(BorderFactory.createLineBorder(Color.darkGray));
rendererBorderPanel.add(zoneRendererPanel);
rendererBorderPanel.add(zoneRenderLayered);
toolbarPanel = new ToolbarPanel(toolbox);

// Put it all together
Expand Down Expand Up @@ -1509,6 +1508,11 @@ public ZoneRenderer getCurrentZoneRenderer() {
return currentRenderer;
}

/** @return the HTMLOverlay */
public HTMLOverlay getHtmlOverlay() {
return htmlOverlay;
}

public void addZoneRenderer(ZoneRenderer renderer) {
zoneRendererList.add(renderer);
}
Expand Down Expand Up @@ -2101,4 +2105,32 @@ public void actionPerformed(ActionEvent e) {
}
}
}

/**
* Layout for LayeredPanel where the bounds of every component is set to the size of the parent.
*/
private static class LayeredPaneLayout implements LayoutManager {
@Override
public void addLayoutComponent(String name, Component comp) {}

@Override
public void removeLayoutComponent(Component comp) {}

@Override
public Dimension preferredLayoutSize(Container parent) {
return parent.getSize();
}

@Override
public Dimension minimumLayoutSize(Container parent) {
return preferredLayoutSize(parent);
}

@Override
public void layoutContainer(Container parent) {
for (Component comp : parent.getComponents()) {
comp.setBounds(0, 0, parent.getWidth(), parent.getHeight());
}
}
}
}
181 changes: 181 additions & 0 deletions src/main/java/net/rptools/maptool/client/ui/htmlframe/HTMLOverlay.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/*
* This software Copyright by the RPTools.net development team, and
* licensed under the Affero GPL Version 3 or, at your option, any later
* version.
*
* MapTool Source Code is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public
* License * along with this source Code. If not, please visit
* <http://www.gnu.org/licenses/> and specifically the Affero license
* text at <http://www.gnu.org/licenses/agpl.html>.
*/
package net.rptools.maptool.client.ui.htmlframe;

import java.awt.*;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.util.List;
import java.util.TooManyListenersException;
import javax.swing.*;
import javax.swing.text.*;
import net.rptools.maptool.client.AppPreferences;
import net.rptools.maptool.client.MapTool;
import net.rptools.maptool.client.ScreenPoint;
import net.rptools.maptool.client.TransferableHelper;
import net.rptools.maptool.client.ui.zone.ZoneRenderer;
import net.rptools.maptool.model.Token;
import net.rptools.maptool.model.ZonePoint;

/** Represents the transparent HTML overlay over the map. */
public class HTMLOverlay extends HTMLPane implements DropTargetListener {
/** The default rule for an invisible body tag. */
private static final String CSS_RULE_BODY =
"body { font-family: sans-serif; font-size: %dpt; background: none}";

public HTMLOverlay() {
super();
setFocusable(false);
setHighlighter(null);
setOpaque(false);
addMouseListeners();
setCaretColor(new Color(0, 0, 0, 0)); // invisible, needed or it shows in DnD operations

setTransferHandler(new TransferableHelper()); // set the Drag & Drop handler
try {
getDropTarget().addDropTargetListener(this);
} catch (TooManyListenersException e1) {
// Should never happen because the transfer handler fixes this problem.
}
}

/**
* Return the rule for an invisible body.
*
* @return the rule
*/
@Override
public String getRuleBody() {
return String.format(CSS_RULE_BODY, AppPreferences.getFontSize());
}

@Override
public void dragEnter(DropTargetDragEvent dtde) {}

@Override
public void dragOver(DropTargetDragEvent dtde) {}

@Override
public void dropActionChanged(DropTargetDragEvent dtde) {}

@Override
public void dragExit(DropTargetEvent dte) {}

/**
* Add the tokens to the current zone renderer if a token is dropped on the overlay.
*
* @param dtde the event of the drop
*/
@Override
public void drop(DropTargetDropEvent dtde) {
ZoneRenderer zr = MapTool.getFrame().getCurrentZoneRenderer();
Point point = SwingUtilities.convertPoint(this, dtde.getLocation(), zr);

ZonePoint zp = new ScreenPoint((int) point.getX(), (int) point.getY()).convertToZone(zr);
TransferableHelper th = (TransferableHelper) getTransferHandler();
List<Token> tokens = th.getTokens();
if (tokens != null && !tokens.isEmpty()) {
zr.addTokens(tokens, zp, th.getConfigureTokens(), false);
}
}

/** Add the mouse listeners to forward the mouse events to the current ZoneRenderer. */
private void addMouseListeners() {
addMouseWheelListener(this::passMouseEvent);
addMouseMotionListener(
new MouseMotionAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
passMouseEvent(e);
}

@Override
public void mouseDragged(MouseEvent e) {
passMouseEvent(e);
}
});
addMouseListener(
new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
passMouseEvent(e, true);
}

@Override
public void mouseClicked(MouseEvent e) {
passMouseEvent(e, true);
}

@Override
public void mouseEntered(MouseEvent e) {
passMouseEvent(e);
}

@Override
public void mouseReleased(MouseEvent e) {
passMouseEvent(e);
}

@Override
public void mouseExited(MouseEvent e) {
passMouseEvent(e);
}
});
}

/**
* Passes a mouse event to the ZoneRenderer. If checking for transparency, only forwards the event
* if it happened over a transparent pixel.
*
* @param e the mouse event to forward
* @param checkForTransparency whether to check for transparency
*/
private void passMouseEvent(MouseEvent e, boolean checkForTransparency) {
SwingUtilities.invokeLater(
() -> {
if (checkForTransparency && isOpaque(e.getPoint())) {
return; // don't forward
}
Component c = MapTool.getFrame().getCurrentZoneRenderer();
c.dispatchEvent(SwingUtilities.convertMouseEvent(e.getComponent(), e, c));
});
}

/**
* Passes a mouse event to the ZoneRenderer.
*
* @param e the mouse event to forward
*/
private void passMouseEvent(MouseEvent e) {
passMouseEvent(e, false);
}

/**
* Returns true if the pixel of the component at the point is opaque.
*
* @param p the point
* @return true if the pixel is opaque
*/
public boolean isOpaque(Point p) {
Rectangle rect = getBounds();
BufferedImage img = new BufferedImage(rect.width, rect.height, BufferedImage.TYPE_INT_ARGB);
paintAll(img.createGraphics());
return new Color(img.getRGB(p.x, p.y), true).getAlpha() != 0;
}
}
Loading