Files
@ 443938b472d4
Branch filter:
Location: workgroups2/workgroups-morph.el
443938b472d4
5.3 KiB
text/x-elisp
initial commit
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | ;;; morph
;;
;; TODO: Add upward and left morphing. And once it's been added, add selection
;; of a random morph direction.
;;
(defun wg-morph-p ()
"Return t when it's ok to morph, nil otherwise."
(and after-init-time wg-morph-on))
(defun wg-morph-step-edges (w1 w2)
"Step W1's edges toward W2's by `wg-morph-hsteps' and `wg-morph-vsteps'."
(wg-step-edges (wg-w-edges w1) (wg-w-edges w2)
wg-morph-hsteps wg-morph-vsteps))
(defun wg-morph-determine-steps (gui-steps &optional term-steps)
(max 1 (if (and (not window-system) term-steps) term-steps gui-steps)))
(defun wg-morph-match-wlist (wt1 wt2)
"Return a wlist by matching WT1's wlist to WT2's.
When wlist1's and wlist2's lengths are equal, return wlist1.
When wlist1 is shorter than wlist2, add a window at the front of wlist1.
When wlist1 is longer than wlist2, package up wlist1's excess windows
into a wtree, so it's the same length as wlist2."
(let* ((wl1 (wg-wtree-wlist wt1))
(l1 (length wl1))
(d1 (wg-wtree-dir wt1))
(wl2 (wg-wtree-wlist wt2))
(l2 (length wl2)))
(cond ((= l1 l2) wl1)
((< l1 l2)
(cons (wg-minified-copy-of-last-win (wg-rnth (1+ l1) wl2))
(if (< (wg-w-size (car wl1) d1)
(* 2 (wg-actual-min-size d1)))
wl1
(cons (wg-w-edge-operation (car wl1) wg-min-edges #'-)
(cdr wl1)))))
((> l1 l2)
(append (wg-take wl1 (1- l2))
(list (wg-make-wtree
:dir d1
:edges wg-null-edges
:wlist (nthcdr (1- l2) wl1))))))))
(defun wg-morph-win-to-win (w1 w2 &optional swap)
"Return a copy of W1 with its edges stepped once toward W2.
When SWAP is non-nil, return a copy of W2 instead."
(wg-set-edges (wg-copy-win (if swap w2 w1)) (wg-morph-step-edges w1 w2)))
(defun wg-morph-win-to-wtree (win wtree)
"Return a new wtree with WIN's edges and WTREE's last two windows."
(wg-make-wtree
:dir (wg-wtree-dir wtree)
:edges (wg-morph-step-edges win wtree)
:wlist (let ((wg-morph-hsteps 2) (wg-morph-vsteps 2))
(wg-docar (w (wg-leave (wg-wtree-wlist wtree) 2))
(wg-morph-win-to-win (wg-minified-copy-of-last-win w) w)))))
(defun wg-morph-wtree-to-win (wtree win &optional noswap)
"Grow the first window of WTREE and its subtrees one step toward WIN.
This eventually wipes WTREE's components, leaving only a window.
Swap WTREE's first actual window for WIN, unless NOSWAP is non-nil."
(if (wg-win-p wtree) (wg-morph-win-to-win wtree win (not noswap))
(wg-make-wtree
:dir (wg-wtree-dir wtree)
:edges (wg-morph-step-edges wtree win)
:wlist (wg-dbind (fwin . wins) (wg-wtree-wlist wtree)
(cons (wg-morph-wtree-to-win fwin win noswap)
(wg-docar (sw wins)
(if (wg-win-p sw) sw
(wg-morph-wtree-to-win sw win t))))))))
(defun wg-morph-wtree-to-wtree (wt1 wt2)
"Return a new wtree morphed one step toward WT2 from WT1.
Mutually recursive with `wg-morph-dispatch' to traverse the
structures of WT1 and WT2 looking for discrepancies."
(let ((d1 (wg-wtree-dir wt1)) (d2 (wg-wtree-dir wt2)))
(wg-make-wtree
:dir d2
:edges (wg-morph-step-edges wt1 wt2)
:wlist (if (not (eq (wg-wtree-dir wt1) (wg-wtree-dir wt2)))
(list (wg-minified-copy-of-last-win wt2) wt1)
(mapcar* #'wg-morph-dispatch
(wg-morph-match-wlist wt1 wt2)
(wg-wtree-wlist wt2))))))
(defun wg-morph-dispatch (w1 w2)
"Return a wtree morphed one step toward W2 from W1.
Dispatches on each possible combination of types."
(cond ((and (wg-win-p w1) (wg-win-p w2))
(wg-morph-win-to-win w1 w2 t))
((and (wg-wtree-p w1) (wg-wtree-p w2))
(wg-morph-wtree-to-wtree w1 w2))
((and (wg-win-p w1) (wg-wtree-p w2))
(wg-morph-win-to-wtree w1 w2))
((and (wg-wtree-p w1) (wg-win-p w2))
(wg-morph-wtree-to-win w1 w2))))
(defun wg-morph (to &optional from)
"Morph from wtree FROM to wtree TO.
Assumes both FROM and TO fit in `selected-frame'."
(let ((from (or from (wg-window-tree-to-wtree (window-tree))))
(wg-morph-hsteps
(wg-morph-determine-steps wg-morph-hsteps wg-morph-terminal-hsteps))
(wg-morph-vsteps
(wg-morph-determine-steps wg-morph-vsteps wg-morph-terminal-vsteps))
(truncate-partial-width-windows wg-morph-truncate-partial-width-windows)
(wg-record-incorrectly-restored-bufs nil)
(wg-restore-scroll-bars nil)
(wg-restore-fringes nil)
(wg-restore-margins nil)
(wg-restore-point nil)
(wg-restore-mark nil)
(watchdog 0))
(wg-until (wg-equal-wtrees from to)
(condition-case err
(if (> (incf watchdog) wg-morph-max-steps)
(error "`wg-morph-max-steps' exceeded")
(setq from (wg-normalize-wtree (wg-morph-dispatch from to)))
(wg-restore-window-tree from)
(redisplay))
(error (wg-dbind (sym data) err
(unless (and (stringp data)
(string-match "too small" data))
(signal sym data))))))
to))
(provide 'workgroups-morph)
|