microsoft / PowerToys

Windows system utilities to maximize productivity
MIT License
111.31k stars 6.55k forks source link

[FancyZones] Redesign the logic/UI to activate a zone over another #1167

Closed enricogior closed 3 years ago

enricogior commented 4 years ago

Making this the main issue for this problem and closing:

A change to the current logic should not cause a feature regression. There are several ways to decide which zone should be activated when multiple zones are overlapping. We may consider adding a settings to let the users choose their preferred logic. We may also consider changing the UI and provide a completely different way to activate a zone.

h3lo commented 4 years ago

+1 for settings to let users choose preferred logic.

Also, I suggest making that logic tune-able so it is more versatile. An example of where this is useful is having a large zone overlapping two smaller ones -- some way to set custom hit boxes for each zone would be a great solution for maximum customization.

crutkas commented 4 years ago

My worry about different types of logic is testing the permutations for bugs. I think a logic mode could be fine but would be a v2 item.

crutkas commented 4 years ago

what is the current math for detecting this. smallest area?

enricogior commented 4 years ago

Yes, currently the smallest zone wins.

h3lo commented 4 years ago

Even a simple toggle to reverse that would solve my issue... (Largest zone wins, as an option) I generally have a large zone for snapping video windows to, and two smaller zones that completely cover the larger zone, but have some space at the top so I can select them.

That said, a completely custom hit box per zone would be the best solution imo since it would allow complete customization, as well as open the door to some really complicated layouts.

This is the layout I'm using. It worked perfectly on v0.11.0. The larger zone took precedence and I would drag near the top to get the two overlapping smaller zones. image

In an idea world, I would like to overlap a zone on the right side that fills the vertical space, and choose whether I want to snap to the top half, lower half, or whole zone based on where I drag to. This has never been possible though and isn't easily implemented like my suggestion for inverting the largest/smallest zone wins situation for the overlapping zone on the left.

enricogior commented 4 years ago

@h3lo for single monitor users, the toggle can be a solution, but for multi monitor users the toggle would work better if it's per-zoneset and not global. Another feature we should implement is to allow to snap to two adjacent zones when hovering over the common edge.

crutkas commented 4 years ago

Think I figured a possible solution. I am building out a quick tester app to iterate possible layouts to see if it will work

Thought is closest to edge, in time, bigger area wins.

crutkas commented 4 years ago

https://github.com/microsoft/PowerToys/tree/master/tools/FancyZone_HitTest has my tester app.

Tested a few different ways of doing this. I don't think it is perfect BUT it solves overlapping. I feel like it does need some 'snap' / 'gravity' to it.

Algorithm:

What i do think we need to do is get more data on what are real world zone layouts when people have overlapping zones. I cannot stress enough "real world", not "i want to break FancyZones".

h3lo commented 4 years ago

I posted a picture previously of my real world use case... but to be honest, if the overlapping capabilities allowed it, I would overlap some more options. Not because I want to break FancyZones, but because different workloads call for different layouts.

If someone who has a good understanding of the code were willing to explain how some of it works, I would love to learn. Admittedly, I am not well versed enough to get started myself, but if anyone considers it worth their time...

crutkas commented 4 years ago

@h3lo just post what you want. 100% think we should support different layouts for different workloads and would love to see what you want.

What we want is to understand what people use so we can focus on making stuff awesome versus solving hypothetical problems. :)

Huseriato commented 4 years ago

It's also a big deal for me. I'm trying to migrate from GridMove. In GridMove you can define hitzones and window sizes. So it's up to the configuration, where a zone hits or not. May be the hit zone can be sub zone of the configurated window zone (selectable and resizeable in the zone configurator).

eremem commented 4 years ago

In GridMove you can define hitzones and window sizes. So it's up to the configuration, where a zone hits or not.

Same here. Since GridMove doesn't work with my middle mouse button (thank you Logitech:/), I'm looking for a decent and open source alternative. The concept of hitzones allows for choosing from multiple layouts w/o the need of actually having any of them active. I found it extremly easy to use and productive.

ivan100sic commented 4 years ago

Let Z = (Z1, Z2, ..., Zn) be a zone set, where each Zi is a rectangle, possibly with overlapping or even equal (?) rectangles. What if we find a set Q = (Q1, Q2, ..., Qn) of rectangles, such that: (1) Qi is a subrectangle of Zi
(2) Qi, Qj don't overlap for all i < j. (3) The total "distance" between Z and Q should somehow be minimized. Then make Qi the "activation area" for zone Zi. Then we could make this more user-friendly by drawing these activation areas inside zones so that users can see where to place their cursor to activate the desired zone.

enricogior commented 4 years ago

@ivan100sic sounds very interesting, since the calculation has to be done only once, when the zoneset is saved, it shouldn't have any significant impact and actually it would make more lightweight the activation check at run-time. I would definitely like to see in practice how it works for some the various layouts.

Huseriato commented 4 years ago

@ivan100sic Thank's that is exacly what I meant. The user can simply draw the activation area inside every zone window. So overlapping of desired zones is no problem anymore.

enricogior commented 4 years ago

@Huseriato it's better if it's done automatically, instead of requiring the users to do it manually, to do you agree?

h3lo commented 4 years ago

No, custom activation zones would be the ultimate feature here. I would create many more zones with custom activations areas in them.

Huseriato commented 4 years ago

@Huseriato it's better if it's done automatically, instead of requiring the users to do it manually, to you agree?

No, I do not agree. The better way is to let the user customize the hit zones. An automatic logic may work if those hit zones overlap. Per default a hit zone should be as big as the zone itself. With this behaviour you'll have full customization for advanced users and the automatic for all other users.

enricogior commented 4 years ago

@Huseriato

An automatic logic may work if those hit zones overlap

That is the point of this issue, to simply the way overlapping zones are activated. I understand some users may prefer to manually edit each zone's activation area, that is a nice feature to have in general, not only for overlapping zones. But for overlapping zone, if we have a well done automatic activation area, I think a lot of user will be happy to not have to manually set it for each zone.

Having both is the ideal solution. For 0.16 we can provide the automatic solution. The manual editing for the activation area will require more work.

h3lo commented 4 years ago

@enricogior

Having both is the ideal solution. For 0.16 we can provide the automatic solution. The manual editing for the activation area will require more work.

I get that it's a lot of work, but I'm glad you see the value for a possible future iteration. In the meantime, lets talk about the automatic solution. Which of the above suggestions do you think is best for automatic? Also, while building the automatic solution, let's be careful to do so with it in mind that custom manual zones is a feature we want in the future. I could see some implementations of automatic logic making the custom manual hit boxes harder to implement, so it's good to know it's on the roadmap early.

Better overlapping zones will be a game changer for me. To be honest, FancyZones is the thing that made me start liking Windows 10.

aribilow commented 4 years ago

Stitching in suggestions I made in #4157, which was deemed redundant with this issue...

Provide means for user to change the order in which zones capture hit-tests by moving the desired zone "forward" or "backward". arrange

This will provide the user with the means to create overlapping zones that predictably capture a moved window.

overlap

The problem is there is no obvious way for the user to determine which zone will capture a window. Certain configurations create conditions where smaller zones don't hit-test since they are overlapped by a larger zone.

An MVP implementation would simply be a "forward" and "backward" buttons. Pressing forward would move a selected zone forward one layer, and backward would move it back on layer. Zone selection would need to persist on click, with a clear highlight state, so that the desired zone could moved easily add_buttons A more robust implementation could include numeric input for scaling and positioning zones, alignment tools to place a series of zones along an edge, and spacing distribution similar to Adobe Illustrator to evenly space zones apart from one another. distribute and align

enricogior commented 4 years ago

An alternative idea: make only the top part of the zones active https://github.com/microsoft/PowerToys/issues/1005

vitjok commented 4 years ago

@Huseriato

An automatic logic may work if those hit zones overlap

That is the point of this issue, to simply the way overlapping zones are activated. I understand some users may prefer to manually edit each zone's activation area, that is a nice feature to have in general, not only for overlapping zones. But for overlapping zone, if we have a well done automatic activation area, I think a lot of user will be happy to not have to manually set it for each zone.

Having both is the ideal solution. For 0.16 we can provide the automatic solution. The manual editing for the activation area will require more work.

@enricogior

Having manually editable activation areas would be nice and I understand it requires more work.

How about improve the automatic algorithm to activate on "mouse-over-area-number"? In most cases when even the areas are overlapping, the numbers of the areas are not:

image

image

image

So I think the automatic algorithm could be to check first

The numbers would be kind of activation areas without any UI work :)

And if anybody don't like the activation by mouse-over-number, it could be only one checkbox to disable it.

teecrow commented 4 years ago

Any updates on this? On a portrait monitor with three zones, I can only drag windows to the two zones which constitute the full top and bottom halves of the screen area. The third zone, larger than the other two, is the same width as the other two (i.e., the full width of the screen). The top edge of the third zone starts about 20% down from the top of the monitor, and the bottom edge lies about 70% down from the top. Zone 3 is visible "behind" the other two, but it seems there is no way to actually drop a window into that zone. I'm using PowerToys v0.20.1. Thanks to all you devs for the great work!

tfki commented 4 years ago

what about just using the scroll wheel to chose between all the zones the mouse is currently held over?

Huseriato commented 4 years ago

I don't understand, why not just implement seperate trigger and target zones. A trigger zone can be a zone that's smaller than the target zone. In the configuration this can be a panel inside the pseudo target zone window that's resizeable, too. All implemented intelligence to find the correct window can be applied to the trigger zones. By default a trigger zone is as big as the target zone. I'm currently not using FancyZones any more because of this issue (I made me a fork of GridMove).

crutkas commented 4 years ago

what about just using the scroll wheel to chose between all the zones the mouse is currently held over?

Trackpad, pen, touch screen users.

zevisert commented 3 years ago

what about just using the scroll wheel to chose between all the zones the mouse is currently held over?

Came here looking to propose this too.

Trackpad, pen, touch screen users.

Good point. What about using something like a dwell timer to trigger a selection menu? If you can't use the mouse wheel, then I think the next most usable thing would be to show a radial menu or alike that shows all of the zones that hit-test successfully wherever the dwell occurred. Obviously it doesn't have to be radial, even something like a mini alt-tab list would work. Then the whole selection can happen with something like a pen, but still allows a mouse to scroll the radial menu when it's up.

image

--

Though @vitjok's suggestion of hit testing over the zone numbers with priority could work well too. I like that as well

Huseriato commented 3 years ago

That seems to be a lot of waiting. As a ~15 year user of GridMove I can tell you, that hitzones that can differ from windowzones are really cool. Because you never have to wait. You knew where to drag a window to move it to the desired location. Currently my grid set has 16 windowszones and 16 hitzones. The windowzones are all overlapping each other.

When dragging, there is a ghost window, that shows which position and size a window will get, after mouseup.

I'm using a forked version of GridMove with some Bugfixes for Windows 10. But I'm really waiting for a FancyZones release that can deal with overlapping window zones.

vitjok commented 3 years ago

Though @vitjok's suggestion of hit testing over the zone numbers with priority could work well too. I like that as well

@zevisert To be clear: I would definitely prefer the solution with 'user defined hitzones' where the smallest hitzone wins.

The suggestion to "improve the automatic algorithm to activate on mouse-over-area-number" was just a thought for a little effort hotfix :)

zevisert commented 3 years ago

That seems to be a lot of waiting.

I put N seconds in that figure intentionally, figuring that people could use 0 seconds as N. Then instantly, any time there's multiple hits the radial would be shown

mshancock commented 3 years ago

I wanted to add an idea/recommendation to the set. This is actually related to the idea by @vitjok, but instead of using the actual number, use the centre point of the rectangles. I would also not default back to what the algorithm is now, because there are unreachable zones in the current algorithm (which I see as the biggest problem) and it would probably be confusing to switch.

My suggestion has two variations.

Variation 1 (probably easier to understand):

Variation 2 (possibly faster in terms of target acquisition):

The second option is a bit like Bubble Cursor, which is why I recommend it. However, there may be some use case where people prefer to have "empty" zones and not have anything selected.

enricogior commented 3 years ago

@mshancock since no one has come up with a solution that covers all the cases, I lean towards a different approach. Use the current logic of giving priority to small zones when the zones first activate, and then switch to give priority to larger zones after releasing and pressing again the shift key. And/or offer the option to choose between a list of different logic.

Adrelix commented 3 years ago

Why not just give each zone a customable priority value that the user gets to set while editing zones? Gives great flexability for different cases. A seperated hitbox/zone box would be very usefull aswell but can quickly become very complex for new users to learn.

Alternative: Prioritise by number. Much easier implementation but can lead to painfull editing sessions when you need a high priority number and thereby have to get one of the early numbers back.

enricogior commented 3 years ago

@Adrelix we prefer to find a solution that doesn't require manual editing, otherwise the user experience of creating new layouts will become tedious, especially on multi-monitor and/or high resolution monitor where the user might have tens of zones.

Adrelix commented 3 years ago

Hmm i understand that. I'm new to the community so I haven't grasped what's considered preferable or not yet. Would it then maybe be possible to have a "closest center" priority, where the zone with the closest center gets prioritized? This would be a pretty clean way to sort out the zones without user-entered priority.

I myself use a 5120x1440 monitor and imo there is a huge need to have overlapping zones that you can control priority of.

sliepie commented 3 years ago

Why not implement an alt+tab like feature? This way a user could cycle through the zones. UI for this could be a scaled down version of the monitor with all the zones visible, and the active/selected one visible. For mouse users we could use an exploded view, with zones still overlapping for a bit.

The downside of this approach is that it's keyboard/mouse focused.

mshancock commented 3 years ago

@enricogior (or anyone else), can you help me understand what the motivation for keeping the "smallest zone wins" algorithm is? This entire issue only matters for overlapping zones, and it seems easy to create examples where larger zones are unreachable by being overlapped by two smaller zones. It seems more unlikely that two rectangles would have the same centre, and even if they do, they are only unreachable if they are identical (and identical zones aren't really relevant).

I actually think the suggestion by @ivan100sic is the most general way of thinking of this problem (though I would relax the constraint that Qi needs to be a subrectangle of Zi):

Let Z = (Z1, Z2, ..., Zn) be a zone set, where each Zi is a rectangle, possibly with overlapping or even equal (?) rectangles. What if we find a set Q = (Q1, Q2, ..., Qn) of rectangles, such that: (1) Qi is a subrectangle of Zi (2) Qi, Qj don't overlap for all i < j. (3) The total "distance" between Z and Q should somehow be minimized. Then make Qi the "activation area" for zone Zi. Then we could make this more user-friendly by drawing these activation areas inside zones so that users can see where to place their cursor to activate the desired zone.

If we use the centres, we could use a Voronoi diagram approach to building each Qi (it's a bit different than Delaunay triangulation, because we want rectangles and probably don't care about filling up the space - although doing that would actually maximize the selectable area for every zone).

I would recommend that the logic be built to do this general thing (i.e., have a Zi for each Qi). A first pass could be this with the default that's used now (Qi = Zi - sum of all smaller zones). That would allow for most of the suggestions here to be built and also for the future possibility of custom priorities/areas. I think the question then becomes "what should the default be?" With custom, we could also have buttons for "maximize activation areas"/"prefer smaller zones"/whatever algorithm we can think of.

Btw, I agree that a good automatic algorithm is really important, so wouldn't advocate for customizability here. I'm following this issue because I was using a zone setup (that I would still prefer) that has unreachable zones (once I saw here that the "smallest wins" was the algorithm, I was able to adjust it to work, but now my zones are smaller than I want).

enricogior commented 3 years ago

@mshancock the first FZ released used the zones creation order to determine which zones had to be activated. It was disliked by many and at that time it was proposed to make the smallest zone rule, based on actual community feedback. Only later on there were requests for the largest zone to win. There are valid scenarios for both.

With the algorithm you propose, what would be the activation areas for a layout like this one:

1,2,3 are columns from top to bottom, 4 is a small area, 5 and 6 are large areas

image

Also, let's not forget we support multi-zones snapping for adjacent zones, that brings in a new level of complexity that we cannot just dismiss. So the algorithm must support it.

mshancock commented 3 years ago

Thanks for the explanation about the history of where the smallest zone wins algorithm came from (I agree it's better than creation order).

This is what a Voronoi diagram for that would look like (I generated it manually with this page, so it's not perfect): image

One option would be to just use that (I like this option, but requires the Qi to be polygons instead of rectangles). For the multi-zone snapping (which I agree is important to support), you could still use the original algorithm (i.e., the borders of the rectangles that can actually be joined still work).

If you really want to keep them as rectangles, you can just take the Voronoi diagram and grow a rectangle from the centre of each until it reaches the Voronoi border. I'm sure there are other maximization algorithms that could work, too, but this also leaves space that is "no zone", which I don't think is helpful.

crutkas commented 3 years ago

@mshankcock, what would this one look like from issue #819 image

mshancock commented 3 years ago

I think this still works: image

I can't quite tell from the image, but I think this is 6 zones:

Note that (as mentioned above), there is still a situation that doesn't work without a special condition: when two rectangles have the same centre. This could happen, for example, if the second column here was just 1 zone full height (and the one in front is very carefully placed to have the exact same centre). I think a good solution to that is to do a quick check for the same centre and just offset a little either vertically or horizontally. That would give something like this: image

crutkas commented 3 years ago

@mshancock It is 5 zones. is would be left 2 are full columns, right column is split. If the bottom image is what it would generate, that feels incorrect.

Maybe we do some type of hybrid where overlap zones are sliced up so they do get some type of weight and we can handle areas where they bleed out.

mshancock commented 3 years ago

I think for any of these options, I'd need to try it before deciding if it doesn't feel right. I think for the most part these selection areas will be invisible, so it's just when the zone activates. The advantage here is that all zones are always reachable.

I do think the splitting idea could also work. So:

That would look like this for this 5-zone example: image (purple is the centre column and the two greens are the large one in front of everything.)

Of course, you could also choose to subtract the larger one from the smaller one instead (though that means the remaining part(s) will be smaller). That would look like this: image

ivan100sic commented 3 years ago

I think I have a decent and easy to implement solution, so I'm wondering what everyone else thinks. When holding the mouse at some point, let's look at the set of all the zones that contain that point, let's name them Z1, ..., Zk. Clearly this subset of zones has a non-empty intersection, which is again a rectangle, let's call it Z. So, let's divide Z into k equal rectangles and assign the i-th part of Z to Zi. In @crutkas' example, it would look something like this:

image

vitjok commented 3 years ago

I really like the idea by @mshancock to use Voronoi diagram.

@mshancock wrote:

I think a good solution to that is to do a quick check for the same centre and just offset a little either vertically or horizontally.

May be it would be good to set the offset vertically ordered by area. So the user would have to move the mouse upwards for the bigger area and downwards for the smaller area.

It seams to work for the example I am thinking on, but I'm not sure whether it's good in common.

My example:

grafik

grafik

enricogior commented 3 years ago

@ivan100sic algorithm https://github.com/microsoft/PowerToys/issues/1167#issuecomment-772346564 works for all scenarios that I've tested. If you want to give it a try it's available here https://github.com/microsoft/PowerToys/pull/9447

There might be some optimization to make even more intuitive how the zone is selected but I believe it's a good starting point and most users will not even need further optimization. We will merge it for 0.33 and see what's the community feedback.

v-aravind commented 3 years ago

Here is how this is implemented in a DWM software called Mosaico which I currently use - this seems to me like the ideal way to do this. Looks to me like it is using some kind of centre of gravity model. also displaying the zones available as smaller representations rather than covering the whole screen seems much more elegant.

dragdrop

enricogior commented 3 years ago

Starting with 0.33, there will be a choice between multiple activation algorithms:

image

The third option allows to always have at least one activation area for each zone, so in general it fixes the overall issue, but it's logic might not be ideal for everyone. Different users might prefer different approaches to this problem. One solution that would work for all might be a unicorn.

Beside the current three algorithms (there will be a detailed explanation in the online documentation) we welcome community contributions for more. Telemetry will help us to determine which is the favorite, to set a reasonable default.

As a side note, for the third algorithm we are considering to add visual feedback to show the sub-area targets.

crutkas commented 3 years ago

Great news! This was resolved in the newly released 0.33 version of PowerToys! Head to https://aka.ms/installpowertoys to grab latest.