emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: New keybinding suggestion: C-x _ for `shrink-window'


From: Lennart Borgman (gmail)
Subject: Re: New keybinding suggestion: C-x _ for `shrink-window'
Date: Sat, 03 Nov 2007 17:43:24 +0100
User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.6) Gecko/20070728 Thunderbird/2.0.0.6 Mnenhy/0.7.5.666

Bastien wrote:
2. Lennart jumped in and pointed to bw-interactive.el, which does a good job at resizing windows border-wise.

I took the idea of using windmove to bw-interactive.el.

In addition to that I removed the minor mode and instead used overriding-terminal-local-map directly (I was on my way to do that earlier, but I forgot it).

I also changed the feedback to the user slightly.


*** Some old and new comments on the "whys" of bw-interactive.el:

- Using a keymap directly gives the user more freedom to choose the bindings.

- Getting resizing and balancing together in one key binding seems good.

- Choosing border before resizing is essential. I guess most users will find this familiar.

- The visual feedback is now in two forms: mode-line color (a bit better than before), mouse pointer movement. In addition to that I would like mouse pointer shape changes, but that seems like a bigger job to me. Or am I wrong?

- Exiting is flexible, similar to that in isearch.
;;; bw-interactive.el --- Functions for interactive resize of windows
;;
;; Description:
;; Author: Lennart Borgman <lennart dot borgman dot 073 at student at lu at se>
;; Maintainer:
;; Created: Wed Dec 07 15:35:09 2005
;; Version: 0.91
;; Last-Updated: Sat Nov 03 17:32:16 2007 (3600 +0100)
;; Keywords:
;; Compatibility:
;;
;; Features that might be required by this library:
;;
;;   None
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;; Commentary:
;;
;; This file contains functions for interactive resizing of Emacs
;; windows. To use it put it in your `load-path' and add the following
;; to your .emacs:
;;
;;     (require 'bw-interactive)
;;     (global-set-key [(control x) ?+] 'bw-enter-resizing)
;;
;; Typing "C-x +" will now enter a temporary mode for resizing windows.
;; For more information see `bw-enter-resizing'.
;;
;; These functions were the second part of my proposal for a new
;; `balance-windows' function for Emacs. These second part were not
;; accepted into Emacs 22, but you can use this module instead to get
;; the functionality. It requires Emacs 22 from 2006 or later.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;; Change log:
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.
;;
;; This program 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.  See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program; see the file COPYING.  If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; TODO: Change mouse pointer shape during resizing.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;;; Code:


(defun bw-balance-windows ()
  "Call `balance-windows' and exit window resizing."
  (interactive)
  (balance-windows)
  (bw-exit-resize-state nil))

(defun bw-balance-siblings ()
  "Make current window siblings the same height or width."
  (interactive)
  (balance-windows (selected-window))
  (bw-exit-resize-state nil))

(defun bw-shrink-window ()
  "Shrink the window to be as small as possible to display its contents."
  (interactive)
  (fit-window-to-buffer nil (window-height))
  (bw-exit-resize-state nil))

(defun bw-exit-resize-other ()
  "Exit window resizing."
  (interactive)
  (bw-exit-resize-state t))

(defun bw-exit-resize-state(put-back-last-event)
  (setq bw-window-resize-state nil)
  (setq overriding-terminal-local-map bw-old-overriding-terminal-local-map)
  (setq overriding-local-map-menu-flag bw-old-overriding-local-map-menu-flag)
  (setq bw-window-to-resize nil)
  (when (frame-live-p bw-frame)
    (set-face-attribute 'mode-line-inactive bw-frame :background 
bw-old-mode-line-inactive-bg)
    (set-face-attribute 'mode-line bw-frame :background bw-old-mode-line-bg))
  (message "Exited window resizing")
  (when (and put-back-last-event)
    ;; Add this to the input queue again:
    (isearch-unread last-command-event)))

(defvar bw-keymap
  (let ((map (make-sparse-keymap "Window Resizing")))
    (define-key map [menu-bar bw]
      (cons "Resize" (make-sparse-keymap "second")))
    (define-key map [menu-bar bw shrink]
      '("Shrink to Buffer" . bw-shrink-window))
    (define-key map [menu-bar bw siblings]
      '("Balance Window Siblings" . bw-balance-siblings))
    (define-key map [menu-bar bw balance]
      '("Balance Windows" . bw-balance-windows))
    (define-key map [t]  'bw-exit-resize-other)
    (define-key map [?+] 'bw-balance-windows)
    (define-key map [?.] 'bw-balance-siblings)
    (define-key map [?-] 'bw-shrink-window)
    (define-key map [(up)]    'bw-resize-up)
    (define-key map [(down)]  'bw-resize-down)
    (define-key map [(left)]  'bw-resize-left)
    (define-key map [(right)] 'bw-resize-right)
    map)
  "Keymap used during window resizing.")

(defvar bw-window-to-resize nil
  "Window selected for resizing.")
(defvar bw-frame nil "Frame for resizing.")


(defun bw-enter-resizing ()
  "Start window resizing.
During window resizing these keys are defined:
\\<bw-keymap>
\\{bw-keymap}

Arrow keys may both select border to move and resize window. See
`bw-resize-left' for an explanation of how the arrow keys
work.

All other keys exits window resizing."
  (interactive)
  (if (= 1 (length (window-list)))
      (message "There is only one window on this frame, can't resize that")
    (setq bw-window-for-side-hor nil)
    (setq bw-window-for-side-ver nil)
    (setq bw-window-to-resize (selected-window))
    (setq bw-frame (selected-frame))
    ;; Fix-me: use copy-keymap for old?
    (setq bw-old-overriding-terminal-local-map overriding-terminal-local-map)
    (setq overriding-terminal-local-map (copy-keymap bw-keymap))
    (setq bw-old-overriding-local-map-menu-flag overriding-local-map-menu-flag)
    (setq overriding-local-map-menu-flag t)
    (setq bw-old-mode-line-inactive-bg (face-attribute 'mode-line-inactive 
:background))
    (setq bw-old-mode-line-bg (face-attribute 'mode-line :background))
    (setq bw-window-resize-state t)
    (let ((left   (bw-window-beside (selected-window) 0))
          (top    (bw-window-beside (selected-window) 1))
          (right  (bw-window-beside (selected-window) 2))
          (bottom (bw-window-beside (selected-window) 3)))
      (if (< 1 (length (delq nil (list left top right bottom))))
          (progn
            (bw-move-mouse-to-middle)
            (set-face-attribute 'mode-line-inactive bw-frame :background 
"#ff0000")
            (set-face-attribute 'mode-line bw-frame :background "#ff0000")
            (message "Arrows: select border, +/./- : balance 
windows/siblings/fit, other: quit")
            )
        (when left   (bw-resize -1 t))
        (when top    (bw-resize -1 nil))
        (when right  (bw-resize 1 t))
        (when bottom (bw-resize 1 nil))
        (bw-start-resizing)))))

(defun bw-help-message ()
  (message "Arrows: resize, +/./-: balance windows/siblings/fit, other: quit"))

(defun bw-start-resizing ()
  (bw-help-message)
  (set-face-attribute 'mode-line-inactive bw-frame :background "#ffa500")
  (set-face-attribute 'mode-line bw-frame :background "#ffa500"))

(defvar bw-window-for-side-hor nil
  "Window used internally for resizing in horizontal direction.")

(defvar bw-window-for-side-ver nil
  "Window used internally for resizing in vertical direction.")

(defun bw-resize-left ()
  "Choose border to move. Or if border is choosen move that border.
When entering window resizing Emacs first need to know which
border to move. If there are several possible borders then the
first call to this function (or its siblings
`bw-resize-right', `bw-resize-top' and
`bw-resize-bottom') will choose border.

When the border is choosen this function moves that border to the left.

Note 1: This function of course only works for vertical borders.

Note 2: The behaviour is modelled after how some GUI window
managers do similar resizing."
  (interactive)(bw-resize -1 t))

(defun bw-resize-right ()
  "See `bw-resize-left'."
  (interactive)(bw-resize 1  t))

(defun bw-resize-up ()
  "See `bw-resize-left'."
  (interactive)(bw-resize -1 nil))

(defun bw-resize-down ()
  "See `bw-resize-left'."
  (interactive)(bw-resize 1  nil))

(defun bw-window-beside(window side)
  "Return a window directly beside WINDOW at side SIDE.
That means one whose edge on SIDE is touching WINDOW.  SIDE
should be a number corresponding to positions in the values
returned by 'window-edges'."
  (let* ((windmove-wrap-around nil)
         (win (windmove-find-other-window
              (cond
               ((= side 0) 'left)
               ((= side 1) 'up)
               ((= side 2) 'right)
               ((= side 3) 'down)
               ))))
    (unless (window-minibuffer-p win)
      win)))
;; (defun bw-window-beside-old(window side)
;;   (let ((start-window window)
;;         (start-left   (nth 0 (window-edges window)))
;;         (start-top    (nth 1 (window-edges window)))
;;         (start-right  (nth 2 (window-edges window)))
;;         (start-bottom (nth 3 (window-edges window)))
;;      above-window)
;;     (setq window (previous-window window 0))
;;     (while (and (not above-window) (not (eq window start-window)))
;;       (let (
;;             (left   (nth 0 (window-edges window)))
;;             (top    (nth 1 (window-edges window)))
;;             (right  (nth 2 (window-edges window)))
;;             (bottom (nth 3 (window-edges window)))
;;             )
;;         (if (or (= side 0) (= side 2))
;;             (when (and (if (= side 0) (= right start-left) (= left 
start-right))
;;                        (or (and (<= top start-top)    (<= start-bottom 
bottom))
;;                            (and (<= start-top top)    (<= top start-bottom))
;;                            (and (<= start-top bottom) (<= bottom 
start-bottom))))
;;               (setq above-window window))
;;           (when (and (if (= side 1) (= bottom start-top) (= top 
start-bottom))
;;                      (or (and (<= left start-left)  (<= start-right right))
;;                          (and (<= start-left left)  (<= left start-right))
;;                          (and (<= start-left right) (<= right start-right))))
;;             (setq above-window window))))
;;       (setq window (previous-window window)))
;;     above-window))

(defun bw-resize(arg horizontal)
  "Choose border to move. Or if border is choosen move that border.
If HORIZONTAL is non-nil use the border earlier selected for
horizontal resizing, otherwise use the one for vertical resizing.

If ARG is -1 move border to the left or up, depending on
HORIZONTAL. If ARG is 1 move border to the right or down.

Used by `bw-resize-left' etc."
  (unless (= (* arg arg) 1)
    (error "ARG must be -1 or 1"))
  (let* ((bw-side (if horizontal 'bw-window-for-side-hor 
'bw-window-for-side-ver))
         (bside (if horizontal
                    (if (< arg 0) 0 2)
                 (if (< arg 0) 1 3)))
         (window-beside (bw-window-beside (selected-window) bside)))
    (if (not (symbol-value bw-side))
        (progn
          (unless window-beside
            ;; Just take the window in the other direction then.
            (setq bside (mod (+ bside 2) 4))
            (setq window-beside (bw-window-beside (selected-window) bside))
            (setq arg (- arg)))
          (when (> arg 0) (setq window-beside (selected-window)))
          (bw-start-resizing)
          (set bw-side window-beside))
      (when bw-window-resize-state
        (condition-case err
            (adjust-window-trailing-edge (symbol-value bw-side) arg horizontal)
          (error (message "%s" (error-message-string err)))
          )))
    (when (= 1 (length (window-list))) (bw-exit-resize-state nil))
    (when (and bw-window-resize-state)
      (bw-help-message)
      (bw-move-mouse-to-resized))))

(defun bw-move-mouse-to-middle ()
  "Move mouse to the middle of the window to resize."
    (let ((bw-window-for-side-hor nil)
          (bw-window-for-side-ver nil))
      (bw-move-mouse-to-resized)))

(defun bw-move-mouse-to-resized ()
  "Move mouse to the border beeing moved in interactive resize."
  (let* ((edges (window-edges))
         (L (nth 0 edges))
         (T (nth 1 edges))
         (R (nth 2 edges))
         (B (nth 3 edges))
         (x (/ (+ L R) 2))
         (y (/ (+ T B) 2)))
    (when bw-window-for-side-hor
      (setq x (if (eq (selected-window) bw-window-for-side-hor) (- R 1) (- L 
1))))
    (when bw-window-for-side-ver
      (setq y (if (eq (selected-window) bw-window-for-side-ver) (- B 1) (- T 
1))))
    (set-mouse-position (selected-frame) x y)))


(defvar bw-old-mode-line-bg nil)
(defvar bw-old-mode-line-inactive-bg nil)
(defvar bw-old-overriding-terminal-local-map nil)
(defvar bw-old-overriding-local-map-menu-flag nil)
(defvar bw-window-resize-state t)


(provide 'bw-interactive)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; bw-interactive.el ends here

reply via email to

[Prev in Thread] Current Thread [Next in Thread]