-
Notifications
You must be signed in to change notification settings - Fork 780
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
Adds some snap helpers to split windows to the left in various ways #1465
base: main
Are you sure you want to change the base?
Changes from 11 commits
c2d28a3
7ff5564
e9c7119
2fd3a03
a0ba238
b0cd5a1
3e1e786
d16a023
99595a1
bf4c21a
26e6557
fb34ba6
d50497b
64ca1b0
66f99bf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -17,6 +17,10 @@ | |||||||||||||||||||||||||||||||
"window_snap_positions", | ||||||||||||||||||||||||||||||||
"Predefined window positions for the current window. See `RelativeScreenPos`.", | ||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||
mod.list( | ||||||||||||||||||||||||||||||||
"window_split_positions", | ||||||||||||||||||||||||||||||||
"Predefined window positions when splitting the screen between three applications.", | ||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||
mod.setting( | ||||||||||||||||||||||||||||||||
"window_snap_screen", | ||||||||||||||||||||||||||||||||
type=str, | ||||||||||||||||||||||||||||||||
|
@@ -272,14 +276,38 @@ def __init__(self, left, top, right, bottom): | |||||||||||||||||||||||||||||||
"fullscreen": RelativeScreenPos(0, 0, 1, 1), | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
_split_positions = { | ||||||||||||||||||||||||||||||||
"split": [ | ||||||||||||||||||||||||||||||||
_snap_positions["left third"], | ||||||||||||||||||||||||||||||||
_snap_positions["center third"], | ||||||||||||||||||||||||||||||||
_snap_positions["right third"], | ||||||||||||||||||||||||||||||||
], | ||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Let's make the values a list of lists, with different numbers of inputs. That way the data structure can support snapping layouts with 2/3/4/etc windows ergonomically. The action can then look at the number of windows that were passed, and find the layout that matches that length. As an added bonus, if there isn't one, it can show a useful error explaining this ("layout 'clock' requires 3, 4, or 5 windows, but 2 were given") The top level will still be string keys for simplicity (the spoken form) so we don't have to duplicate the list for each n-combination. For the value, instead of a list of lists, we could use a dictionary with numeric keys (indicating the number of applications supported). But that's redundant given that the length of the value itself already has that information; it's less work for the user to just use list of lists. Make the code do the hard work of figuring out which one matches. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had a thought that I've talked myself out of: we could simplify this a bit further. Instead of needing to index into The only downside from my perspective is that in your current version you can use an anonymous You could do something where the values could be either string keys (in which case they are assumed to be So the current way is fine, just posting this comment in case the line of thought is interesting. |
||||||||||||||||||||||||||||||||
"clock": [ | ||||||||||||||||||||||||||||||||
_snap_positions["left"], | ||||||||||||||||||||||||||||||||
_snap_positions["top right"], | ||||||||||||||||||||||||||||||||
_snap_positions["bottom right"], | ||||||||||||||||||||||||||||||||
], | ||||||||||||||||||||||||||||||||
"counterclock": [ | ||||||||||||||||||||||||||||||||
_snap_positions["right"], | ||||||||||||||||||||||||||||||||
_snap_positions["top left"], | ||||||||||||||||||||||||||||||||
_snap_positions["bottom left"], | ||||||||||||||||||||||||||||||||
], | ||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
@mod.capture(rule="{user.window_snap_positions}") | ||||||||||||||||||||||||||||||||
def window_snap_position(m) -> RelativeScreenPos: | ||||||||||||||||||||||||||||||||
return _snap_positions[m.window_snap_positions] | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
@mod.capture(rule="{user.window_split_positions}") | ||||||||||||||||||||||||||||||||
def window_split_position(m) -> list[RelativeScreenPos]: | ||||||||||||||||||||||||||||||||
return _split_positions[m.window_split_positions] | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't actually think you need a capture here, the "I want a dictionary so the spoken form is a certain string but the action gets the object that corresponds to that string" mapping can be done with a simple list. (There are lots of places in community that seem to define unnecessary captures that just wrap a list, for reasons I'm not sure about.) But I'll follow up to make sure. Feel free to hold off until I've checked 😅 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. lists are a string->string mapping, they can't map to objects There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. derp, right. |
||||||||||||||||||||||||||||||||
ctx = Context() | ||||||||||||||||||||||||||||||||
ctx.lists["user.window_snap_positions"] = _snap_positions.keys() | ||||||||||||||||||||||||||||||||
ctx.lists["user.window_split_positions"] = _split_positions.keys() | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
@mod.action_class | ||||||||||||||||||||||||||||||||
|
@@ -310,6 +338,30 @@ def snap_app(app_name: str, position: RelativeScreenPos): | |||||||||||||||||||||||||||||||
_bring_forward(window) | ||||||||||||||||||||||||||||||||
_snap_window_helper(window, position) | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
def snap_split_two(app_one: str, app_two: str): | ||||||||||||||||||||||||||||||||
"""Split the screen between two applications.""" | ||||||||||||||||||||||||||||||||
window = _get_app_window(app_one) | ||||||||||||||||||||||||||||||||
window_two = _get_app_window(app_two) | ||||||||||||||||||||||||||||||||
_snap_window_helper(window_two, _snap_positions["right"]) | ||||||||||||||||||||||||||||||||
_snap_window_helper(window, _snap_positions["left"]) | ||||||||||||||||||||||||||||||||
window_two.focus() | ||||||||||||||||||||||||||||||||
window.focus() | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
def snap_split_three( | ||||||||||||||||||||||||||||||||
positions: list[RelativeScreenPos], app_one: str, app_two: str, app_three: str | ||||||||||||||||||||||||||||||||
): | ||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can just make this one single action with lots of application parameters, and just make the ones greater than 2 optional:
Suggested change
Might as well support up to 5 in case people want to make more interesting layouts. I don't think there's an explicit
That way you don't have to duplicate the action for each number of applications. Also I think it'd be helpful to give this functionality a useful name, to distinguish it from the existing single-window snapping functionality. Since "split" is itself a layout I think it should probably have a broader name like "layout" or "arrangement" (not strongly opinionated on the name itself, just that it has one). Do any of those sound good to you, or perhaps do you have a better one? 😁 |
||||||||||||||||||||||||||||||||
"""Split the screen between three applications.""" | ||||||||||||||||||||||||||||||||
window = _get_app_window(app_one) | ||||||||||||||||||||||||||||||||
window_two = _get_app_window(app_two) | ||||||||||||||||||||||||||||||||
window_three = _get_app_window(app_three) | ||||||||||||||||||||||||||||||||
_snap_window_helper(window, positions[0]) | ||||||||||||||||||||||||||||||||
_snap_window_helper(window_two, positions[1]) | ||||||||||||||||||||||||||||||||
_snap_window_helper(window_three, positions[2]) | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
window_three.focus() | ||||||||||||||||||||||||||||||||
window_two.focus() | ||||||||||||||||||||||||||||||||
window.focus() | ||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||
def move_app_to_screen(app_name: str, screen_number: int): | ||||||||||||||||||||||||||||||||
"""Move a specific application to another screen.""" | ||||||||||||||||||||||||||||||||
window = _get_app_window(app_name) | ||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Per discussion, if the version with two windows only really supports splitting side by side, the grammar should look like this. Otherwise you're suggesting you could use any of the other layouts with two windows, and it would still silently give you the 2v2 split. (It shouldn't be possible to say that or it should be an error.)
But I think we had a much better idea detailed below, to make the grammar arbitrarily support layouts with different numbers of windows.