Replies: 14 comments 11 replies
-
|
Beta Was this translation helpful? Give feedback.
-
I just started using Kitty this week and this is a feature I really want and am also interesting in adding. I use the I made a little PoC of this earlier via a I pushed that to my branch in case you want to see what that looks like in code: It's still full of bugs but just meant to prove that this could be possible. I think coming up with a full design for this that would be merge-able will require a bit of thought as there are a handful of cases to consider; however, i3wm has implemented this quite well so I think in many cases their design could be used. Some thoughts/challenges:
There are probably solves to those problems above but just some observations from the time I spent putting together the PoC. I'm going to keep hacking on this in my free time |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
The resize_window kitten uses remote control, the kitty @ resize_window
command, which in turn calls Boss.resize_layout_window()
|
Beta Was this translation helpful? Give feedback.
-
So I played around with this a bit more and got it into a pretty good spot: Didn't want to record/upload a several minute gif so that only shows a subset of the possible cases but I believe I'm handling all normal cases now:
There are some assumptions being made that I'm not sure are correct, such as assuming that border width/height are always the same as cell width and height. From reading some of the possible config options, I don't think that's true. There's also some room for improvement in general and handling edge cases , some of which is called out in TODOs. I think changing the cursor when hovering above borders would be a nice feature as it can be hard to tell whether or not you're clicking on a border. Also, highlighting the borders that are being adjusted when the mouse button is held. But, as a general draft I'd say I'm pretty happy with the direction so far. Code is in my Going to continue solidifying this and working towards getting it in a more mergeable state. |
Beta Was this translation helpful? Give feedback.
-
Looks good. Some minor comments from looking at the GIF only.
1) you will need to implement it for all layouts to be mergeable.
2) given that borders are so thin I am guessing (without looking at the code)
that there is some zone around the borders in which one can click to
drag. This is going to interfere with mouse selection/clicking on
hyperlink etc. It might be better to have a dedicated modifier for this.
So for example, holding shift+meta+left mouse down will start the resize. This
will need to be configurable via the existing mouse_actions framework.
I may have misunderstood the GIF and you are doing this already, if so
apologies.
|
Beta Was this translation helpful? Give feedback.
-
I appreciate the feedback! I wanted to get this working just for the splits layout initially since that's the only layout I use but now that I know I can take advantage of My most recent gif shows the ability to click and drag on window borders to resize but my original post worked more like what you are saying. It mimicked the behavior of i3wm/swaywm where the user can hold a modifier and then click and drag anywhere in a window to resize that window. Now that I've had some time to familiarize with the codebase (This is my first contribution) I think I have a better idea of how things work. I'll probably go back to that original idea because I prefer the resizing behavior in i3wm and like you said, trying to click narrow borders is a bit of a pain. That said, now that I know how, I'll implement it without adding a kitten which introduced a few complications. Will follow up once I have something that's less of a proof-of-concept and closer to being mergeable. |
Beta Was this translation helpful? Give feedback.
-
Cool, all the best. I look forward to your PR.
|
Beta Was this translation helpful? Give feedback.
-
Haven't forgotten about this but been busy with baby lately. Had some time today so I gave this another pass. Changed it back to being more like the mouse resize functionality in Theoretically I think it should work for all layouts but I could be wrong so I need to spend some time testing all of them. Also need to add a bit of polish:
Hopefully will have a PR up sometime soon but if anyone wants to help with testing or just play around with this, code is in my |
Beta Was this translation helpful? Give feedback.
-
Another approach is to have modes. So when ctrl+shift+r particular modifier is
pressed kitty goes into window resize mode and shows the keyboard
controls as it does now, but additionally in this mode dragging with the
mouse resizes.
|
Beta Was this translation helpful? Give feedback.
-
On Fri, Mar 17, 2023 at 09:30:13AM -0700, Paul Ewing wrote:
One other thought, does right click and drag do anything currently? For folks who don't want to have to hold a modifier, perhaps they could just make right click drag without a modifier do the resize.
It extends selections. https://sw.kovidgoyal.net/kitty/overview/#mouse-features
and
https://sw.kovidgoyal.net/kitty/conf/#mouse-actions
|
Beta Was this translation helpful? Give feedback.
-
I was just looking to see if this was possible, and it looks like this isn't merged yet. I realize @pcewing hasn't had much time with family and all, and I don't want to pressure them if they don't have time, but I was wondering if there were any updates on this. If you don't have time, or have abandoned the idea, I'd gladly pick it up and look into continuing your work. I think it would be very reasonable to have this enabled by default in resize mode, but I agree with @Erotemic in that half the point of resizing with mouse is to avoid using the keyboard. In my case, my One could maybe have some |
Beta Was this translation helpful? Give feedback.
-
For this to have amazing value for me, a modifier key press would not be required. Tilix as an example, but more generally speaking-- most resizeable windows are a simple select-and-drag to resize a split. Sometimes I'll slide one window lower to look at something quickly (say, the status of a build) and then flip it up, squashing it mostly out of view (except for the last line or two), or do a resize to keep a part of different terminals in view -- if only for aesthetic reasons... So to have to hunt down some memorized key-combo at the same time and use multiple hands would be a real bummer and source of frustration. All this said, the mouse resizing is essential so please do support a simple keyless select-and-drag. I can bear the massive risk of accidentally misclicking an adjascent character (not a tragedy- this can happen when resizing windows too) and just having to try again to select the border. No big deal. Thanks! |
Beta Was this translation helpful? Give feedback.
-
Hello I like this so I rebased the patch on the current version of kitty it's still working for me. mouse-drag-resize.diff--- a/kitty/boss.py
+++ b/kitty/boss.py
@@ -13,6 +13,7 @@
from contextlib import contextmanager, suppress
from functools import partial
from gettext import gettext as _
+from math import floor
from gettext import ngettext
from time import sleep
from typing import (
@@ -224,6 +225,7 @@ def as_text(**kw: bool) -> str:
class DumpCommands: # {{{
def __init__(self, args: CLIOptions):
+ self.drag_resize_active = False
self.draw_dump_buf: list[str] = []
if args.dump_bytes:
self.dump_bytes_to = open(args.dump_bytes, 'wb')
@@ -2129,6 +2131,52 @@ def switch_focus_to(self, window_id: int) -> None:
if tab:
tab.set_active_window(window_id)
+ def drag_resize_start(self, x: float, y: float, cell_width: int, cell_height: int) -> None:
+ tab = self.active_tab
+ if not tab:
+ return
+
+ (horizontal, vertical) = tab.current_layout.drag_resize_target_windows(x, y, tab.windows)
+
+ self.drag_resize_cell_width = cell_width
+ self.drag_resize_cell_height = cell_height
+ self.drag_resize_target_horizontal = horizontal
+ self.drag_resize_target_vertical = vertical
+ self.drag_resize_active = True
+ self.drag_resize_initial_x = x
+ self.drag_resize_initial_y = y
+ self.drag_resize_last_step_x = 0
+ self.drag_resize_last_step_y = 0
+
+ def drag_resize_update(self, x: float, y: float) -> None:
+ if not self.drag_resize_active:
+ return
+
+ if self.drag_resize_target_horizontal is not None:
+ step_x = floor((x - self.drag_resize_initial_x) / self.drag_resize_cell_width)
+ dx = step_x - self.drag_resize_last_step_x
+ if not dx == 0:
+ self.resize_layout_window(self.drag_resize_target_horizontal, float(dx), True, False)
+ self.drag_resize_last_step_x = step_x
+
+ if self.drag_resize_target_vertical is not None:
+ step_y = floor((y - self.drag_resize_initial_y) / self.drag_resize_cell_height)
+ dy = step_y - self.drag_resize_last_step_y
+ if not dy == 0:
+ self.resize_layout_window(self.drag_resize_target_vertical, float(dy), False, False)
+ self.drag_resize_last_step_y = step_y
+
+ def drag_resize_end(self) -> None:
+ self.drag_resize_cell_width = 0
+ self.drag_resize_cell_height = 0
+ self.drag_resize_target_horizontal = None
+ self.drag_resize_target_vertical = None
+ self.drag_resize_active = False
+ self.drag_resize_initial_x = 0.0
+ self.drag_resize_initial_y = 0.0
+ self.drag_resize_last_step_x = 0
+ self.drag_resize_last_step_y = 0
+
def open_kitty_website(self) -> None:
self.open_url(website_url())
--- a/kitty/layout/base.py
+++ b/kitty/layout/base.py
@@ -428,3 +428,36 @@ def layout_action(self, action_name: str, args: Sequence[str], all_windows: Wind
def layout_state(self) -> Dict[str, Any]:
return {}
+
+ def drag_resize_target_windows(self, x: float, y: float, all_windows: WindowList) -> Tuple[WindowType, WindowType]:
+ # Identify the window where the click occurred and which horizontal and
+ # vertical half it was in
+ click_window, left_half_clicked, top_half_clicked = (None, False, False)
+ for w in all_windows.all_windows:
+ g = w.geometry
+ if x >= g.left and x <= g.right and y >= g.top and y <= g.bottom:
+ click_window = w
+ left_half_clicked = g.left <= x and x <= g.left + (float(g.right - g.left) / 2.0)
+ top_half_clicked = g.top <= y and y <= g.top + (float(g.bottom - g.top) / 2.0)
+ break
+
+ if click_window is None:
+ raise Exception("Failed to determine click window")
+
+ neighbors = self.neighbors_for_window(click_window, all_windows)
+
+ # Infer which window should be horizontally resized based on click
+ # position and layout state
+ horizontal_target = click_window
+ if ((left_half_clicked and len(neighbors["left"]) > 0) or
+ (not left_half_clicked and len(neighbors["left"]) > 0 and len(neighbors["right"]) == 0)):
+ horizontal_target = all_windows.id_map[neighbors["left"][0]]
+
+ # Infer which window should be vertically resized based on click
+ # position and layout state
+ vertical_target = click_window
+ if ((top_half_clicked and len(neighbors["top"]) > 0) or
+ (not top_half_clicked and len(neighbors["top"]) > 0 and len(neighbors["bottom"]) == 0)):
+ vertical_target = all_windows.id_map[neighbors["top"][0]]
+
+ return (horizontal_target, vertical_target)
\ No newline at end of file
--- a/kitty/mouse.c
+++ b/kitty/mouse.c
@@ -660,6 +660,35 @@ closest_window_for_event(unsigned int *window_idx) {
return ans;
}
+static void
+drag_resize_start(double mouse_x, double mouse_y, unsigned int cell_width, unsigned int cell_height) {
+ call_boss(drag_resize_start, "ddII", mouse_x, mouse_y, cell_width, cell_height);
+}
+
+static void
+drag_resize_update(double mouse_x, double mouse_y) {
+ call_boss(drag_resize_update, "dd", mouse_x, mouse_y);
+}
+
+static void
+drag_resize_end(void) {
+ call_boss(drag_resize_end, "");
+}
+
+static bool
+is_in_window(double mouse_x, double mouse_y) {
+ Tab *active_tab = global_state.callback_os_window->tabs + global_state.callback_os_window->active_tab;
+
+ for (unsigned int i = 0; i < active_tab->num_windows; ++i) {
+ WindowGeometry *g = &active_tab->windows[i].geometry;
+ if (g->left <= mouse_x && mouse_x <= g->right && g->top <= mouse_y && mouse_y <= g->bottom) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
void
focus_in_event(void) {
// Ensure that no URL is highlighted and the mouse cursor is in default shape
@@ -770,6 +799,27 @@ mouse_event(const int button, int modifiers, int action) {
bool in_tab_bar;
unsigned int window_idx = 0;
Window *w = NULL;
+
+ OSWindow *osw = global_state.callback_os_window;
+
+ // Handle mouse drag window resizing
+ if (!global_state.active_drag_resize && button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS && modifiers & GLFW_MOD_CONTROL) {
+ if (is_in_window(osw->mouse_x, osw->mouse_y)) {
+ drag_resize_start(osw->mouse_x, osw->mouse_y, osw->fonts_data->cell_width, osw->fonts_data->cell_height);
+ global_state.active_drag_resize = true;
+ return;
+ }
+ } else if (global_state.active_drag_resize) {
+ if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_RELEASE) {
+ drag_resize_end();
+ global_state.active_drag_resize = false;
+ return;
+ } else if (button < 0) {
+ drag_resize_update(osw->mouse_x, osw->mouse_y);
+ return;
+ }
+ }
+
if (OPT(debug_keyboard)) {
if (button < 0) { debug("%s x: %.1f y: %.1f ", "\x1b[36mMove\x1b[m", global_state.callback_os_window->mouse_x, global_state.callback_os_window->mouse_y); }
else { debug("%s mouse_button: %d %s", action == GLFW_RELEASE ? "\x1b[32mRelease\x1b[m" : "\x1b[31mPress\x1b[m", button, format_mods(modifiers)); }
--- a/kitty/state.h
+++ b/kitty/state.h
@@ -315,7 +315,7 @@ typedef struct {
bool has_pending_resizes, has_pending_closes;
bool check_for_active_animated_images;
struct { double x, y; } default_dpi;
- id_type active_drag_in_window, tracked_drag_in_window;
+ id_type active_drag_in_window, tracked_drag_in_window, active_drag_resize;
int active_drag_button, tracked_drag_button;
CloseRequest quit_request;
bool redirect_mouse_handling; |
Beta Was this translation helpful? Give feedback.
-
Hi,
I'm aware that I can use ctrl+r and S or T to make the window shorter or taller for a horizontal split, but one of the things I currently value greatly in my current terminal (terminator) is the ability to drag to resize splits.
I'm wondering if:
Beta Was this translation helpful? Give feedback.
All reactions