33467aedd284de298c0aeacb48897a383687c95a
[riece] / lisp / riece-layout.el
1 ;;; riece-layout.el --- layout management
2 ;; Copyright (C) 1998-2003 Daiki Ueno
3
4 ;; Author: Daiki Ueno <ueno@unixuser.org>
5 ;;      TAKAHASHI "beatmaria" Kaoru <kaoru@kaisei.org>
6 ;; Keywords: IRC, riece
7
8 ;; This file is part of Riece.
9
10 ;; This program is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 2, or (at your option)
13 ;; any later version.
14
15 ;; This program is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 ;; GNU General Public License for more details.
19
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
22 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 ;; Boston, MA 02110-1301, USA.
24
25 ;;; Code:
26
27 (require 'riece-globals)
28 (require 'riece-misc)
29
30 (defgroup riece-layout nil
31   "Window layouts."
32   :prefix "riece-"
33   :group 'riece)
34
35 (defcustom riece-layout "default"
36   "Current layout setting."
37   :type 'string
38   :group 'riece-layout)
39
40 (defcustom riece-layout-alist
41   '(("middle-right" riece-configure-windows right middle)
42     ("middle-left" riece-configure-windows left middle)
43     ("top-right" riece-configure-windows right top)
44     ("top-left" riece-configure-windows left top)
45     ("bottom-right" riece-configure-windows right bottom)
46     ("bottom-left" riece-configure-windows left bottom)
47     ("top" riece-configure-windows-top)
48     ("spiral" riece-configure-windows-spiral)
49     ("default" . "middle-right"))
50   "An alist mapping the names to layout functions.
51 An element of this alist is either in the following forms:
52
53 \(NAME CONFIGURE-FUNCTION [PARAMETERS]\)
54 \(NAME1 . NAME2\)
55
56 In the first form, NAME is a string which specifies the layout
57 setting, and CONFIGURE-FUNCTION is a function which does window
58 splitting, etc.  PARAMETERS are collected and passed to CONFIGURE-FUNCTION.
59 In the second form, NAME1 is an alias for NAME2."
60   :type '(repeat (choice (list :tag "Layout"
61                                (string :tag "Name")
62                                (function :tag "Configure function")
63                                (repeat :tag "Parameters" :inline t symbol))
64                          (cons :tag "Alias" string string)))
65   :group 'riece-layout)
66
67 (defun riece-redraw-layout (&optional force)
68   "Reconfigure windows with the current layout.
69 If optional argument FORCE is non-nil, window reconfiguration will
70 happen unconditionally."
71   (let ((layout (cdr (assoc riece-layout riece-layout-alist))))
72     (unless layout
73       (error "No such layout!"))
74     (if (stringp layout)
75         (let ((riece-layout layout))
76           (riece-redraw-layout force))
77       (if (or force
78               (riece-reconfigure-windows-predicate))
79           (apply (car layout) (cdr layout))))))
80
81 (defun riece-set-window-points ()
82   (if (get-buffer-window riece-user-list-buffer)
83       (with-current-buffer riece-user-list-buffer
84         (unless (riece-frozen riece-user-list-buffer)
85           (set-window-start (get-buffer-window riece-user-list-buffer)
86                             (point-min)))))
87   (if (get-buffer-window riece-channel-list-buffer)
88       (with-current-buffer riece-channel-list-buffer
89         (unless (riece-frozen riece-channel-list-buffer)
90           (set-window-start (get-buffer-window riece-channel-list-buffer)
91                             (point-min)))))
92   (if (and riece-channel-buffer
93            (get-buffer-window riece-channel-buffer))
94       (with-current-buffer riece-channel-buffer
95         (if (riece-frozen riece-channel-buffer)
96             (if riece-channel-buffer-window-point
97                 (set-window-point (get-buffer-window riece-channel-buffer)
98                                   riece-channel-buffer-window-point))
99           (set-window-point (get-buffer-window riece-channel-buffer)
100                             (point-max)))))
101   (if (get-buffer-window riece-others-buffer)
102       (with-current-buffer riece-others-buffer
103         (unless (riece-frozen riece-others-buffer)
104           (set-window-point (get-buffer-window riece-others-buffer)
105                             (point-max)))))
106   (if (get-buffer-window riece-dialogue-buffer)
107       (with-current-buffer riece-dialogue-buffer
108         (unless (riece-frozen riece-dialogue-buffer)
109           (set-window-point (get-buffer-window riece-dialogue-buffer)
110                             (point-max))))))
111
112 (defun riece-reconfigure-windows-predicate ()
113   "Return t, if window reconfiguration is needed.
114 This function is used by \"default\" layout."
115   (memq (window-buffer (selected-window))
116         riece-buffer-list))
117
118 (defun riece-configure-windows (hpos vpos)
119   (let ((buffer (window-buffer))
120         (show-user-list
121          (and riece-user-list-buffer-mode
122               riece-current-channel
123               ;; User list buffer is nuisance for private conversation.
124               (riece-channel-p (riece-identity-prefix
125                                 riece-current-channel)))))
126     ;; Can't expand minibuffer to full frame.
127     (if (eq (selected-window) (minibuffer-window))
128         (other-window 1))
129     (delete-other-windows)
130     (if (and riece-current-channel
131              (or show-user-list riece-channel-list-buffer-mode))
132         (let ((rest-window (split-window (selected-window)
133                                          (if (eq hpos 'left)
134                                              (- (window-width)
135                                                 (/ (window-width) 5))
136                                            (/ (window-width) 5))
137                                          t)))
138           (when (eq hpos 'left)
139             (setq rest-window (selected-window))
140             (other-window 1))
141           (if (and show-user-list riece-channel-list-buffer-mode)
142               (progn
143                 (set-window-buffer (split-window)
144                                    riece-channel-list-buffer)
145                 (set-window-buffer (selected-window)
146                                    riece-user-list-buffer))
147             (if show-user-list
148                 (set-window-buffer (selected-window)
149                                    riece-user-list-buffer)
150               (if riece-channel-list-buffer-mode
151                   (set-window-buffer (selected-window)
152                                      riece-channel-list-buffer))))
153           (select-window rest-window)))
154     (if (and riece-current-channel
155              riece-channel-buffer-mode)
156         (progn
157           (if (eq vpos 'top)
158               (let ((rest-window (split-window nil 4)))
159                 (set-window-buffer (selected-window)
160                                    riece-command-buffer)
161                 (select-window rest-window)
162                 (if riece-others-buffer-mode
163                     (set-window-buffer (split-window rest-window)
164                                        riece-others-buffer))
165                 (set-window-buffer (selected-window)
166                                    riece-channel-buffer))
167             (if (and (eq vpos 'middle)
168                      riece-others-buffer-mode)
169                 (let ((rest-window (split-window)))
170                   (set-window-buffer (selected-window)
171                                      riece-channel-buffer)
172                   (set-window-buffer (split-window rest-window 4)
173                                      riece-others-buffer)
174                   (set-window-buffer rest-window
175                                      riece-command-buffer))
176               (let ((rest-window (split-window nil (- (window-height) 4))))
177                 (if riece-others-buffer-mode
178                     (progn
179                       (set-window-buffer (selected-window)
180                                          riece-others-buffer)
181                       (set-window-buffer (split-window)
182                                          riece-channel-buffer))
183                   (set-window-buffer (selected-window)
184                                      riece-channel-buffer))
185                 (set-window-buffer rest-window
186                                    riece-command-buffer)))))
187       (if (eq vpos 'bottom)
188           (progn
189             (set-window-buffer (selected-window)
190                                riece-command-buffer)
191             (set-window-buffer (split-window (selected-window) 4)
192                                riece-dialogue-buffer))
193         (set-window-buffer (split-window (selected-window) 4)
194                            riece-dialogue-buffer)
195         (set-window-buffer (selected-window)
196                            riece-command-buffer)))
197     (riece-set-window-points)
198     (select-window (or (get-buffer-window buffer)
199                        (get-buffer-window riece-command-buffer)))))
200
201 (defun riece-configure-windows-top (&rest plist)
202   "Candidate of `riece-configure-windows-function'.
203 PLIST accept :command-height, :user-list-width, and :channel-list-width."
204   (let ((command-height (or (plist-get plist :command-height) 4))
205         (user-list-width (or (plist-get plist :user-list-width) (+ 9 1 1)))
206         (channel-list-width (or (plist-get plist :channel-list-width) 18))
207         (buffer (window-buffer))
208         (show-user-list
209          (and riece-user-list-buffer-mode
210               riece-current-channel
211               ;; User list buffer is nuisance for private conversation.
212               (riece-channel-p (riece-identity-prefix
213                                 riece-current-channel)))))
214     ;; Can't expand minibuffer to full frame.
215     (when (eq (selected-window) (minibuffer-window))
216       (other-window 1))
217     (delete-other-windows)
218     ;; top of frame
219     (let ((rest-window (split-window (selected-window) command-height)))
220       (set-window-buffer (selected-window)
221                          riece-command-buffer)
222       (select-window rest-window))
223     ;; middle of frame (vertical-spilit when need)
224     (when (or (and riece-current-channel riece-channel-buffer-mode)
225               show-user-list)
226       (let ((rest-window
227              (split-window (selected-window)
228                            (/ (* 5 (+ (window-height) command-height)) 8))))
229         (cond
230          ;; channel-buffer + user-list
231          ((and show-user-list
232                (and riece-current-channel riece-channel-buffer-mode))
233           (let ((user-list-window (split-window (selected-window) nil t)))
234             (set-window-buffer (selected-window) riece-channel-buffer)
235             (set-window-buffer user-list-window riece-user-list-buffer)
236             (select-window user-list-window)
237             (shrink-window-horizontally (- (window-width) user-list-width))))
238          ;; only user-list
239          (show-user-list
240           (set-window-buffer (selected-window) riece-user-list-buffer))
241          ;; only channel-buffer
242          (riece-channel-buffer-mode
243           (set-window-buffer (selected-window) riece-channel-buffer)))
244         (select-window rest-window)))
245     ;; bottom of frame
246     (if (and riece-current-channel
247              riece-channel-list-buffer-mode)
248         (let ((channel-list-window (split-window (selected-window) nil t)))
249           (set-window-buffer (selected-window) riece-others-buffer)
250           (set-window-buffer channel-list-window riece-channel-list-buffer)
251           (select-window channel-list-window)
252           (shrink-window-horizontally (- (window-width) channel-list-width)))
253       (set-window-buffer (selected-window) riece-dialogue-buffer))
254     (riece-set-window-points)
255     (select-window (or (get-buffer-window buffer)
256                        (get-buffer-window riece-command-buffer)))))
257
258 ;; +---+-------------------+---+
259 ;; | c | channel           | u |
260 ;; | h |                   | s |
261 ;; | a |                   | e |
262 ;; | n |-------------------+ r |   | +---+
263 ;; | n | command           | s |   | |   |
264 ;; | e +-------------------+---+   | +-> |
265 ;; | l | others                |   +-----+
266 ;; | s |                       |
267 ;; +---+-----------------------+
268 (defun riece-configure-windows-spiral ()
269   "spiral placement of windows"
270 ;;  (interactive)
271   (let ((command-height 4)
272         (users-width    15)
273         (channels-width 30)
274         (buffer         (window-buffer)))
275     (when (eq (selected-window) (minibuffer-window)) (other-window 1))
276     (delete-other-windows)
277
278     ;; (1) create channels window
279     (let ((rest (split-window (selected-window) channels-width t)))
280       (set-window-buffer (selected-window) riece-channel-list-buffer)
281       (select-window rest))
282
283     ;; (2) create others window
284     (set-window-buffer (split-window (selected-window)
285                                      (+ (/ (window-height) 2)
286                                         command-height))
287                        riece-others-buffer)
288
289     ;; (3) create users window
290     (set-window-buffer (split-window (selected-window)
291                                      (- (window-width) users-width) t)
292                        riece-user-list-buffer)
293   
294     ;; (4) create current channel window
295     (let ((rest (split-window (selected-window)
296                               (- (window-height) command-height))))
297       (set-window-buffer rest riece-command-buffer)
298       (set-window-buffer (selected-window) riece-channel-buffer))
299
300     (riece-set-window-points)
301     (select-window (or (get-buffer-window buffer)
302                        (get-buffer-window riece-command-buffer)))))
303
304 (provide 'riece-layout)
305
306 ;;; riece-layout.el ends here