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 support for transparent HTML overlays #1425

Closed
Merudo opened this issue Mar 28, 2020 · 42 comments
Closed

Add support for transparent HTML overlays #1425

Merudo opened this issue Mar 28, 2020 · 42 comments
Assignees
Labels
feature Adding functionality that adds value macro changes This issue adds or changes macro functions. Extra work is required (testing, wiki, code editor) tested This issue has been QA tested by someone other than the developer.

Comments

@Merudo
Copy link
Member

Merudo commented Mar 28, 2020

Is your feature request related to a problem? Please describe.

Transparent HTML overlays would be a great way to display UI elements, such as a health meter, clickable icons that can launch macros, and a picture of the selected character.

A good example is provided here by @melek : https://forums.rptools.net/viewtopic.php?f=26&p=275748

Describe the solution you'd like

One option would be to extend the dialog() function to allow for invisible dialogs, which could then function as overlays

Another would be to make a whole new function for overlays.

Additional context

The implementation of overlays poses two difficulties:

  1. the user should be able to specify where they want the overlay to appear on the map (center, corner, side, etc), and the overlay should stay on the same relative spot after resizing the map or docking new frame
  2. the user should presumably have some way to close the overlay manually. Maybe some sort of close button could appear on overlay after a mouse over?
@Merudo
Copy link
Member Author

Merudo commented Mar 28, 2020

For #1 I'm thinking we could add parameters to dialog.

Parameter overlay. By default 0, setting it to 1 would make the dialog invisible.

Parameter relativePosition. This parameter could work for both overlay and non-overlay dialogs. The nine allowed options would be center, top, bottom, left, right, top-left, top-right, bottom-left, and bottom-right. For overlays this would be where they are displayed relative to the map, and for non-overlays it would be relative to the MapTool overall frame.

Parameters x and y. These parameters can give an additional offset over the relativePosition parameter. So y = 100 and relativePosition=bottom would make the dialog show up 100 pixel above the bottom.

@JamzTheMan
Copy link
Member

Could we utilize the current "docking" and add a button that removes the window decorations (and allow for transparent backgrounds?

And maybe under Window menu -> Custom (or better name?) we show all the current window dialog frames and allow for the window decorations to toggle and or close the window?

@Merudo
Copy link
Member Author

Merudo commented Mar 28, 2020

@JamzTheMan I assume the reason for using docking frames is to let the user move their UI overlay elements as they wish using the mouse?

@JamzTheMan
Copy link
Member

Yes, that and it would always center, snap and fill automatically (and reload on campaign load), Although not sure about "click through" to the map will be a problem or not? You get some built in stuff, although, admittedly it couples the functionality to the existing docking framework which we would eventually get rid of.

I'm ok with your suggestion as well, just tossing out ideas and seeing what sticks.

@Phergus Phergus added the feature Adding functionality that adds value label Mar 29, 2020
@Phergus Phergus added this to Needs triage in Backlog via automation Mar 29, 2020
@Merudo
Copy link
Member Author

Merudo commented Mar 29, 2020

Yes, that and it would always center, snap and fill automatically (and reload on campaign load),

Seems to me it would be helpful to implement the relativePosition , x and y parameters I mentioned. That way the overlays would appear at the correct spot, instead of all bunched up in the center.

Although not sure about "click through" to the map will be a problem or not? You get some built in stuff, although, admittedly it couples the functionality to the existing docking framework which we would eventually get rid of.

I'm ok with your suggestion as well, just tossing out ideas and seeing what sticks.

I think I've figured how to pass mouse events to the zoneRenderer so that it becomes possible to "click through" to the map underneath. Hopefully there won't be any issues.

I like the idea of the user reorganizing their UI as they wish by moving the overlays around.

If the overlay is movable, how should the overlay behave if the map is resized, for example if a frame / window gets docked or undocked? If a frame is docked and the overlay doesn't move, the overlay may become inaccessible. So presumably, we would want to "anchor" the overlay to the closest corner / side once placed by the user, so that it remains proportionally at the same spot after a resize.

@JamzTheMan
Copy link
Member

Ya, I would think having a "corner" overlay to be very useful.

I assume all coordinate/offset x,y, etc would be relative to the "map" frame and NOT the whole UI? Then you shouldn't have to worry about all the other windows.

Should this be it's own "function" instead of extending the dialog5? (I like the name overlay). I can't think of a usecase were I would need a transparent overlay (vs a normal frame/dialog) that wasn't over the map?

Also, what do we do with Layers dialog for the GM? Is it always over the overlay? (drawing panel as well although that makes sense to pop it over overlays when needed)

@melek
Copy link
Collaborator

melek commented Mar 30, 2020

Exciting stuff.

I agree that in macro script this could be a separate overlay() function as Jamz is suggesting, that makes sense to me! Edit: Agreed, these would be relative to the mapview frame and could not appear outside of it.

The Layers/Drawing/Adjust Map modals should simply render directly over any Custom UI overlays as if they are a part of the map. Any currently open modal should have a corresponding class applied to overlays for CSS to respond to - I feel like the current UI should be generally 'first class' and user-defined overlays should be given information to work around it if they choose.

Eventually (once html5 is applied to them, probably), I think overlays should be responsive based on the width and height of the Mapview with CSS media queries and other classes assigned to the overlay body.

I am still interested in having UI defined in the campaign properties and have the initial layout at least be strictly defined for a campaign; each overlay needs HTML and CSS and possibly Javascript and images, so it makes sense to make each overlay a tidy package in Campaign properties. A compact edit UI like https://jsfiddle.net/ would make a lot of sense, though that seems a bit ambitious - maybe down the road? :)

Anyway, 'Custom UI' tab in Campaign Properties that lets you create a list of named overlays would be a little more approachable for GMs and elevate the feature a bit as a way for GMs to make their frameworks distinctive. I worry if not, they will only be used by a minority of more advanced users. (This might dovetail into #1422 and the overlays might be a folder in a campaign notebook I'm not sure).

In my dream world where players can connect on their android and iOS devices, mature frameworks can have a custom UI defined that makes playing on a tablet a breeze.

@melek
Copy link
Collaborator

melek commented Mar 30, 2020

I just had a thought; if click-through does end up working while still allowing button presses, would custom overlays being combined into a single HTML 5 overlay that is the entire width/height of the map view which combines all overlays as absolutely positioned DIVs be more performant ?

I just had a thought of framework creators adding small, individual overlays for lots of pieces of overlapping UI creating a performance issue (like chrome with lots and lots of tabs), and smushing all defined overlays into a single HTML document might be a lot faster.

edit: brain switched half a sentence around..

@JamzTheMan
Copy link
Member

JamzTheMan commented Mar 30, 2020

Ok, just had another shower thought....

@Merudo How about adding a visible attribute as well with default true but also allow on-hover, on-select (and false?)

This may run into/over/compliment/replace #1424 as you could now create "stat sheets" of any sort where ever you wanted.

Another useful "coordinate" would be an offset based on a token for on-hover and on-select. Envision a round token getting a nice radial "HUD" if you will around/over a selected token! How cool would that look? It would/could replace/enhance health bars & states by letting us take them off the token and using them in an overlay over and around the tokens.

@melek
Copy link
Collaborator

melek commented Mar 30, 2020

Created a brief fiddle demonstrating a sample single HTML document overlay system with 9 potential overlay base positions:

https://jsfiddle.net/digiacom/dvu1h4bo/

@JamzTheMan
Copy link
Member

Can we position said overlay relative to another overlay? Lets say I had 1-4 overlays I wanted to display in the upper right, each with 0-n padding between them. And lets say I may want to display 1, 2, & 4 for player 1 vs 1, 3, & 4 for GM, I wouldn't want that gap in there. Yes, this could be 1 overlay but lets entertain I need 4?

Or better yet, lets say I had 0-n overlays (maybe each is a "state") and as such I want them to start in upper left but "wrap" down into a second row?

Should we instead treat the map "frame" as one large "window" that we can pass CSS to and organize the overlays that way? Does each "overlay" need to be it's own "dialog/frame"?

Also are these elements in the overlay intractable/clickable (I assume so and the click-thru is only for transparent parts of the overlay?)

@melek
Copy link
Collaborator

melek commented Mar 30, 2020

@JamzTheMan At least in my approach we could structure an overlay to be another overlay's parent, then style that overlay to wrap a flexbox container around the contents if that is happening. By styling the parent div's options we could change the flex properties, but columns would be a good default.

Updated the fiddle with an example, try clicking or manually adding and removing copies of #OVERLAY-004 & 005:
https://jsfiddle.net/digiacom/dvu1h4bo/

@JamzTheMan
Copy link
Member

Yea, I'm just wondering if it would be best to have a single overlay acting like a "glass" layer the framework launching several overlay windows each running it's own webengine. A single instance of a webengine to render a whole page of elements may be more performant.

Although I think we are saying the same thing really. Develop all of your "overlays" in a single html/css "dialog" and forget about having to launch multiple "overlay" dialogs each with there own relativePosition.

@Azhrei
Copy link
Member

Azhrei commented Mar 30, 2020

(This has been exciting stuff to watch develop. :))

My only concern with using CSS is how touchy CSS can be about layout issues. Is there an option to create some kind of LayoutManager and use that? I could see a LayoutManager that gives each child a priority and a position, then lays them out in priority order. The position might be "+5+0" to mean 5 units to the right and 0 units up from the previous component, and "-10+10" would mean 10 units left and 10 units up, always relative to the corner specified by the offset. So numbers that are +,+ would be from the lower left corner and numbers that are -,+ would be from the bottom right corner. This is the style used by the X Window system to place child windows...

Whatever comes out of this, I'm looking forward to it. ;)

@JamzTheMan
Copy link
Member

(This has been exciting stuff to watch develop. :))

My only concern with using CSS is how touchy CSS can be about layout issues. Is there an option to create some kind of LayoutManager and use that? I could see a LayoutManager that gives each child a priority and a position, then lays them out in priority order. The position might be "+5+0" to mean 5 units to the right and 0 units up from the previous component, and "-10+10" would mean 10 units left and 10 units up, always relative to the corner specified by the offset. So numbers that are +,+ would be from the lower left corner and numbers that are -,+ would be from the bottom right corner. This is the style used by the X Window system to place child windows...

Whatever comes out of this, I'm looking forward to it. ;)

FWIW I'm not suggesting to use CSS to layout swing dialog aka "windows" but rather there is a full width/height invisible pane that is always on and overlaying the map and the user can via macro add content to it. If they wanted a "status panel" in the upper right corner, you would use standard HTML/CSS to place it there.

I would think you would be able to layout some simple elements in the corners/sides this way but ya sure, YMMV, i mean, it IS webkit after all so /shrug

@Azhrei
Copy link
Member

Azhrei commented Mar 30, 2020

Should we instead treat the map "frame" as one large "window" that we can pass CSS to and organize the overlays that way? Does each "overlay" need to be it's own "dialog/frame"?

That's the question. If there is a single overlayPane (that sits between the contentPane and glassPane?) and it's a single WebView component, the CSS is being used to position the individual overlays within the WebView and thus, within the overlayPane.

But if that overlayPane holds multiple WebView components, then it needs some kind of layout manager to position them (something like SpringLayoutManager). I was suggesting that if this were the solution chosen, the X Window system's "geometry" syntax might be useful in coding the layout manager.

It's kind of a toss-up. Using a single WebView means CSS has to be used and CSS is finicky, particularly when it comes to rule specificity. But LayoutManagers are not exactly dream components either and they can be hard to get right. And the CSS rules are already written...

@melek
Copy link
Collaborator

melek commented Mar 31, 2020

I like the idea of a single HTML overlay since it gives a very high ceiling of possibility immediately. This is assuming the click-through method Merudo is working on works as expected and can 'catch' clicks/hover events that the overlay wants to react to (anchors, buttons, inputs; elements with onclick handlers and hover effects).

As for CSS being finicky, since we can rely on exactly the HTML rendering shipping with MapTool, I feel like CSS will be very reliable and will render the same across all clients. We can scope CSS for a given overlay to that overlay's ID, like I do in my fiddle example.

I like the Window X geometry you propose; I think that we can use that system also in CSS using the top, left, bottom, and right attributes - so for an overlay we could store the offset in a Window-X friendly way and it would work fine. At very worst, the overlay could be stored with offsets that need to have some work done to them before they're used in CSS.

To get WAY ahead of myself, this is an ambitious mockup of the kind of UI I'm imagining in Campaign Properties. This is extra ambitious because it implies that MapTool would additionally ship and work with Vuejs, though I don't really expect that.. ;)
CustomUI-Props

The overlay class would be rendered in the order of the overlays in the list; all the HTML, CSS and Javascript would be compiled and cacheable. I only used a Vue pattern because I just am not sure how to 'watch' a variable in Javascript with MapTool to update an HTML frame, but I hope the ideas get across.

@cwisniew
Copy link
Member

I like the idea of a single HTML overlay since it gives a very high ceiling of possibility immediately. This is assuming the click-through method Merudo is working on works as expected and can 'catch' clicks/hover events that the overlay wants to react to (anchors, buttons, inputs; elements with onclick handlers and hover effects).

I second this, its both easier to implement and more flexible.

As for CSS being finicky, since we can rely on exactly the HTML rendering shipping with MapTool, I feel like CSS will be very reliable and will render the same across all clients. We can scope CSS for a given overlay to that overlay's ID, like I do in my fiddle example.

I like the Window X geometry you propose; I think that we can use that system also in CSS using the top, left, bottom, and right attributes - so for an overlay we could store the offset in a Window-X friendly way and it would work fine. At very worst, the overlay could be stored with offsets that need to have some work done to them before they're used in CSS.

This above. Plus we open the pool to potential contributors for UIs so much.

@Merudo
Copy link
Member Author

Merudo commented Mar 31, 2020

That's the question. If there is a single overlayPane (that sits between the contentPane and glassPane?)

Right now I'm using a LayeredPane, but adding stuff to the glassPane is another option.

Should we instead treat the map "frame" as one large "window" that we can pass CSS to and organize the overlays that way? Does each "overlay" need to be it's own "dialog/frame"?

That's the question. If there is a single overlayPane (that sits between the contentPane and glassPane?) and it's a single WebView component, the CSS is being used to position the individual overlays within the WebView and thus, within the overlayPane.

...

It's kind of a toss-up. Using a single WebView means CSS has to be used and CSS is finicky, particularly when it comes to rule specificity. But LayoutManagers are not exactly dream components either and they can be hard to get right. And the CSS rules are already written...

One advantage of multiple overlay components may be faster updates ; if a single overlay needs updating, it will in general be faster to update that single component instead of processing the html for the entire overlay screen.

However, I do agree that having one single overlay html component taking the entire screen is probably more effective. For one, it then becomes possible to arrange the layout entirely with CSS & javascript, which is preferable to us reinventing an API. I'm especially excited about the draggable option in HTML 5 - it could allow the player to easily rearrange the placement of overlays to their liking, for example.

But if that overlayPane holds multiple WebView components, then it needs some kind of layout manager to position them (something like SpringLayoutManager). I was suggesting that if this were the solution chosen, the X Window system's "geometry" syntax might be useful in coding the layout manager.

I made a basic LayoutManager for JLayeredPane to support multiple component. Each component is given a halign (left/center/right), a valign (top/center/bottom), and a xOffset and yOffset. So for example specifying right + top with a xOffset=-40 offset will draw the component 40 pixels away from component at the top right of the panel, with 40 pixels between the left side of the component and the right edge of the screen. It works good enough, but having it done by CSS / JS would be more flexible.

@melek
Copy link
Collaborator

melek commented Mar 31, 2020

Are Ajax techniques possible in Java web components so we can dynamically update the dom without forcing a total refresh? Finding a way to provide updates without a total reload of the html would be great for snappy performance - but I just don't know if something like Vue/react can work in this context...

Merudo added a commit to Merudo/maptool that referenced this issue Mar 31, 2020
- Add function overlay() to display a transparent html 3.2 overlay over the map
- Function is used similarly to frame() and dialog(), with [overlay():{ myhtml }] used to display "myhtml"
- Discussed in RPTools#1425
@Merudo
Copy link
Member Author

Merudo commented Mar 31, 2020

PR #1438 implements the feature for html 3.2. Will post an example soon.

@Merudo
Copy link
Member Author

Merudo commented Mar 31, 2020

Are Ajax techniques possible in Java web components so we can dynamically update the dom without forcing a total refresh? Finding a way to provide updates without a refresh would be neat

It's possible with HTML 5 in WebView, see #1362. Unfortunately WebView is JavaFX, and to my knowledge it is not possible to have satisfactory transparency when using JavaFX components in Swing. So this approach won't work for overlays until we switch to JavaFX.

Merudo added a commit to Merudo/maptool that referenced this issue Mar 31, 2020
- Add function overlay() to display a transparent html 3.2 overlay over the map
- Function is used similarly to frame() and dialog(), with [overlay():{ myhtml }] used to display "myhtml"
- Discussed in RPTools#1425
@Merudo
Copy link
Member Author

Merudo commented Mar 31, 2020

Another downside of a single HTML overlay: in HTML 3.2, it is not possible to vertically align an element to the bottom of the page. Having an overlay element snap to the bottom border or the vertical center is therefore not possible.

One option is to have three HTML overlays: one aligned to the top, one aligned to the bottom, and one aligned to the center.

Merudo added a commit to Merudo/maptool that referenced this issue Mar 31, 2020
- Add function overlay() to display a transparent html 3.2 overlay over the map
- Function is used similarly to frame() and dialog(), with [overlay():{ myhtml }] used to display "myhtml"
- Discussed in RPTools#1425
@Phergus Phergus added documentation needed Missing, out-of-date or bad documentation macro changes This issue adds or changes macro functions. Extra work is required (testing, wiki, code editor) labels Apr 11, 2020
@Phergus Phergus moved this from To do to In progress in MapTool 1.7.0 Apr 11, 2020
Merudo added a commit to Merudo/maptool that referenced this issue Apr 12, 2020
- Move HTMLJFXPanel WebView code to HTMLWebViewManager
- Separate HTMLOverlay into HTMLOverlayManager and HTMLWebViewManager
- Feature discussed in RPTools#1425
Merudo added a commit to Merudo/maptool that referenced this issue Apr 12, 2020
- Move HTMLJFXPanel WebView code to HTMLWebViewManager
- Separate HTMLOverlay into HTMLOverlayManager and HTMLOverlayPanel
- Feature discussed in RPTools#1425
@Phergus Phergus moved this from In progress to Review in progress in MapTool 1.7.0 Apr 13, 2020
Merudo added a commit to Merudo/maptool that referenced this issue Apr 13, 2020
- Change so overlays must be given a name, as for frames or dialogs
- Add parameter "zorder" to overlay(). The overlays will be drawn according to the zOrder (high zOrder overlays are drawn over low zOrder overlays)
- Discussed in RPTools#1425
Merudo added a commit to Merudo/maptool that referenced this issue Apr 14, 2020
- Change so overlays must be given a name, as for frames or dialogs
- Add parameter "zorder" to overlay(). The overlays will be drawn according to the zOrder (high zOrder overlays are drawn over low zOrder overlays)
- Move HTMLJFXPanel WebView code to HTMLWebViewManager
- Separate HTMLOverlay into HTMLOverlayManager and HTMLOverlayPanel
- Feature discussed in RPTools#1425
@Merudo
Copy link
Member Author

Merudo commented Apr 14, 2020

PR #1534 implements multiple overlays. I still haven't added the overlay menu in the UI but otherwise it is shaping up to look pretty good.

Merudo added a commit to Merudo/maptool that referenced this issue Apr 14, 2020
- Change so overlays must be given a name, as for frames or dialogs
- Add parameter "zorder" to overlay(). The overlays will be drawn according to the zOrder (high zOrder overlays are drawn over low zOrder overlays)
- Move HTMLJFXPanel WebView code to HTMLWebViewManager
- Separate HTMLOverlay into HTMLOverlayManager and HTMLOverlayPanel
- Feature discussed in RPTools#1425
@Phergus
Copy link
Contributor

Phergus commented Apr 14, 2020

re: HTMLFrameFactory.java

        } else if (keyLC.equals("zorder")) {
          try {
            zOrder = Integer.parseInt(value);
          } catch (NumberFormatException e) {
            // Ignoring the value; shouldn't we warn the user?
          }
        } else if (keyLC.equals("title")) {

Yeah. We'll need to report non-numeric zorder to the user and probably mention using default (or next) z-order.

Is a function to set/change zorder needed? Or just call the overlay() function again with a new zorder?

Merudo added a commit to Merudo/maptool that referenced this issue Apr 14, 2020
- Fix a graphical glitch caused by calling snapshot on a WebView.
- Feature RPTools#1425
Merudo added a commit to Merudo/maptool that referenced this issue Apr 14, 2020
- Add an overlay menu that allows each overlay to be turned on and off
- Feature discussed in RPTools#1425
@Merudo
Copy link
Member Author

Merudo commented Apr 14, 2020

PR #1543 adds an overlay menu where each overlay can be turned on or off.

overlay2

A bare-bone demo. Click on the macros of the Campaign panel to enable the three overlays:

OverlayDemo2.cmpgn.zip

@Merudo
Copy link
Member Author

Merudo commented Apr 14, 2020

re: HTMLFrameFactory.java

        } else if (keyLC.equals("zorder")) {
          try {
            zOrder = Integer.parseInt(value);
          } catch (NumberFormatException e) {
            // Ignoring the value; shouldn't we warn the user?
          }
        } else if (keyLC.equals("title")) {

Yeah. We'll need to report non-numeric zorder to the user and probably mention using default (or next) z-order.

We could use the error message macro.function.general.argumentKeyTypeI:

Argument key "zorder" to function "overlay" must be an integer.

Or, should a new error message be written?

Is a function to set/change zorder needed? Or just call the overlay() function again with a new zorder?

Currently, the overlay() function can just be called with a new zOrder.

@JamzTheMan
Copy link
Member

I like it!

@Phergus
Copy link
Contributor

Phergus commented Apr 14, 2020

We could use the error message macro.function.general.argumentKeyTypeI:

Argument key "zorder" to function "overlay" must be an integer.

That works for me.

Currently, the overlay() function can just be called with a new zOrder.

Good enough.

Merudo added a commit to Merudo/maptool that referenced this issue Apr 14, 2020
- Change so that overlay() gives the following message when provided a non-integer zOrder:

Argument key "zorder" to function "overlay" must be an integer.

- Change discussed in RPTools#1425
@Phergus
Copy link
Contributor

Phergus commented Apr 18, 2020

Feature complete?

@Merudo
Copy link
Member Author

Merudo commented Apr 19, 2020

I think so. Might be ready for an alpha / beta.

@Phergus
Copy link
Contributor

Phergus commented Apr 20, 2020

Tested with examples provided. No issues seen.

@Phergus Phergus moved this from Review in progress to Reviewer approved in MapTool 1.7.0 Apr 20, 2020
@Phergus Phergus added the tested This issue has been QA tested by someone other than the developer. label Apr 20, 2020
@Phergus Phergus closed this as completed Apr 20, 2020
MapTool 1.7.0 automation moved this from Reviewer approved to Done Apr 20, 2020
@Phergus
Copy link
Contributor

Phergus commented May 13, 2020

Page added to wiki. https://lmwcs.com/rptools/wiki/overlay_(roll_option)

@Phergus Phergus removed the documentation needed Missing, out-of-date or bad documentation label May 13, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Adding functionality that adds value macro changes This issue adds or changes macro functions. Extra work is required (testing, wiki, code editor) tested This issue has been QA tested by someone other than the developer.
Projects
No open projects
MapTool 1.7.0
  
Done
Development

No branches or pull requests

6 participants