;;; liece-window.el --- Window configuration style utility. ;; Copyright (C) 1998-2000 Daiki Ueno ;; Author: Daiki Ueno ;; Created: 1999-01-08 ;; Revised: 1999-07-05 ;; Keywords: window, window configuration ;; This file is part of Liece. ;; 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 GNU Emacs; see the file COPYING. If not, write to the ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. ;;; Commentary: ;; ;;; Code: (require 'liece-misc) (require 'liece-intl) (require 'calist) (eval-when-compile (require 'cl)) (defgroup liece-window nil "Window configuration" :tag "Window configuration" :group 'liece) (defcustom liece-window-min-width 2 "Minimal width of liece window." :type 'integer :group 'liece-window) (defcustom liece-window-min-height 2 "Minimal height of liece window." :type 'integer :group 'liece-window) (defcustom liece-window-style-directory nil "Normal position of style configuration files." :type 'directory :group 'liece-window) (defcustom liece-window-default-style "bottom" "Default style." :type 'string :group 'liece-window) (defcustom liece-window-to-buffer '((channel . liece-channel-buffer) (others . liece-others-buffer) (dialogue . liece-dialogue-buffer) (command . liece-command-buffer) (channel-list . liece-channel-list-buffer) (nick . liece-nick-buffer)) "Window abbreviation to buffer alist." :type '(repeat (cons (symbol :tag "Abbrev") (symbol :tag "Buffer"))) :group 'liece-window) (defconst liece-window-split-types '(horizontal vertical)) (defvar liece-window-style-configuration-alist nil) (defvar liece-window-current-style nil) (defvar liece-window-configuration-stack nil) (defun liece-window-field-match-method-as-default-rule (calist field-type field-value) (let* ((field (assq field-type calist)) (value (cdr field))) (cond ((null field) (cons (cons field-type field-value) calist)) ((and (symbolp field-value) (eq field-value 'any)) calist) ((and (symbolp value) (eq field-value value)) calist)))) (define-calist-field-match-method 'command-buffer-mode 'liece-window-field-match-method-as-default-rule) (define-calist-field-match-method 'channel-buffer-mode 'liece-window-field-match-method-as-default-rule) (define-calist-field-match-method 'nick-buffer-mode 'liece-window-field-match-method-as-default-rule) (define-calist-field-match-method 'channel-list-buffer-mode 'liece-window-field-match-method-as-default-rule) (defmacro liece-window-add-style (&rest calist) `(ctree-set-calist-strictly 'liece-window-style-configuration-alist ',calist)) (defmacro liece-window-define-reconfiguration-predicate (name &rest body) `(defun-maybe ,name ,@body)) (put 'liece-window-define-reconfiguration-predicate 'lisp-indent-function 'defun) (defmacro liece-window-set-default-style () "Set window configuration with fallback style." '(liece-window-add-style (command-buffer-mode . any) (channel-buffer-mode . any) (nick-buffer-mode . any) (channel-list-buffer-mode . any) (configuration (vertical 1.0 (dialogue 1.0) (command 4 point))))) (defsubst liece-window-load-style-file (style) "Load style file." (condition-case nil (progn (if (null liece-window-style-directory) (setq liece-window-style-directory (liece-locate-path "styles"))) (setq liece-window-style-configuration-alist nil) (load (expand-file-name style liece-window-style-directory)) (setq liece-window-current-style style)) (error (liece-message "Style file load failed.") (liece-window-set-default-style)))) (defmacro liece-window-percent-to-rate (percent) `(/ ,percent 100.0)) (defmacro liece-window-to-buffer-helper (window) `(cond ((symbolp ,window) (symbol-value ,window)) (t ,window))) (defmacro liece-window-safe-select-window (window) `(if ,window (select-window ,window))) ;;;###liece-autoload (defun liece-command-set-window-style (style) (interactive (let ((styles (directory-files liece-window-style-directory))) (list (liece-minibuffer-completing-read "Window style: " (list-to-alist styles) nil t nil nil liece-window-current-style)))) (liece-window-load-style-file style)) (defun liece-command-reload-window-style () (interactive) (liece-window-load-style-file (or liece-window-current-style liece-window-default-style))) (defmacro liece-window-default-reconfiguration-predicate () '(or (one-window-p t) (null (liece-get-buffer-window liece-command-buffer)) (and (not liece-channel-buffer-mode) (null (liece-get-buffer-window liece-dialogue-buffer))) (and liece-channel-buffer-mode (null (liece-get-buffer-window liece-channel-buffer)) (null (liece-get-buffer-window liece-others-buffer))) (and liece-channel-buffer-mode (if liece-nick-buffer-mode (null (liece-get-buffer-window liece-nick-buffer)) (not (null (liece-get-buffer-window liece-nick-buffer))))) (if liece-channel-list-buffer-mode (null (liece-get-buffer-window liece-channel-list-buffer)) (not (null (liece-get-buffer-window liece-channel-list-buffer)))))) ;;;###liece-autoload (defun liece-configure-windows () (let ((liece-nick-buffer-mode liece-nick-buffer-mode) (liece-channel-buffer-mode liece-channel-buffer-mode) situation calist split predicate) (if (and (get 'liece-nick-buffer-mode 'hide) liece-nick-window-auto-hide) (setq liece-nick-buffer-mode nil)) (if (not (liece-channel-last (if (eq liece-command-buffer-mode 'chat) liece-current-chat-partners liece-current-channels))) (setq liece-channel-buffer-mode nil)) (setq situation `((channel-buffer-mode . ,liece-channel-buffer-mode) (nick-buffer-mode . ,liece-nick-buffer-mode) (channel-list-buffer-mode . ,liece-channel-list-buffer-mode) (command-buffer-mode . ,liece-command-buffer-mode))) (or liece-window-current-style (liece-command-set-window-style liece-window-default-style)) (setq calist (ctree-match-calist liece-window-style-configuration-alist situation) split (cadr (assq 'configuration calist)) predicate (cdr (assq 'reconfiguration-predicate calist))) (when (and split (or (null predicate) (and predicate (liece-functionp predicate) (funcall predicate)))) (if (not (eq liece-truncate-partial-width-windows truncate-partial-width-windows)) (setq truncate-partial-width-windows liece-truncate-partial-width-windows)) (if liece-use-full-window (delete-other-windows)) (save-excursion (switch-to-buffer liece-command-buffer) ;; u-mu. (liece-window-configure-frame split))))) (defun liece-window-configure-frame (split &optional window) (or window (setq window (get-buffer-window (current-buffer)))) (liece-window-safe-select-window window) (while (and (not (assq (car split) liece-window-to-buffer)) (liece-functionp (car split))) (setq split (eval split))) (let* ((type (car split)) (subs (cddr split)) (len (if (eq type 'horizontal) (window-width) (window-height))) (total 0) (window-min-width (or liece-window-min-width window-min-width)) (window-min-height (or liece-window-min-height window-min-height)) s result new-win rest comp-subs size sub) (cond ;; Nothing to do here. ((null split)) ;; Don't switch buffers. ((null type) (and (memq 'point split) window)) ;; This is a buffer to be selected. ((not (memq type '(horizontal vertical))) (let ((buffer (cond ((stringp type) type) (t (cdr (assq type liece-window-to-buffer)))))) (unless buffer (error "Illegal buffer type: %s" type)) (switch-to-buffer (liece-window-to-buffer-helper buffer)) ;; We return the window if it has the `point' spec. (and (memq 'point split) window))) (t (when (> (length subs) 0) ;; First we have to compute the sizes of all new windows. (while subs (setq sub (append (pop subs) nil)) (while (and (not (assq (car sub) liece-window-to-buffer)) (liece-functionp (car sub))) (setq sub (eval sub))) (when sub (push sub comp-subs) (setq size (cadar comp-subs)) (cond ((equal size 1.0) (setq rest (car comp-subs)) (setq s 0)) ((floatp size) (setq s (floor (* size len)))) ((integerp size) (setq s size)) ((symbolp size) (setq s (floor (* (liece-window-percent-to-rate (symbol-value size)) len)))) (t (error "Illegal size: %s" size))) ;; Try to make sure that we are inside the safe limits. (cond ((zerop s)) ((eq type 'horizontal) (setq s (max s window-min-width))) ((eq type 'vertical) (setq s (max s window-min-height)))) (setcar (cdar comp-subs) s) (incf total s))) ;; Take care of the "1.0" spec. (if rest (setcar (cdr rest) (- len total)) (error "No 1.0 specs in %s" split)) ;; The we do the actual splitting in a nice recursive ;; fashion. (setq comp-subs (nreverse comp-subs)) (while comp-subs (if (null (cdr comp-subs)) (setq new-win window) (setq new-win (split-window window (cadar comp-subs) (eq type 'horizontal)))) (setq result (or (liece-window-configure-frame (car comp-subs) window) result)) (liece-window-safe-select-window new-win) (setq window new-win) (setq comp-subs (cdr comp-subs)))) ;; Return the proper window, if any. (liece-window-safe-select-window result))))) (defun liece-window-configuration-push () (let ((frame (selected-frame)) (config (current-window-configuration))) (push (list frame config) liece-window-configuration-stack))) (defun liece-window-configuration-pop () (let* ((frame (selected-frame)) (triple (assq frame liece-window-configuration-stack))) (when (and triple (window-configuration-p (cadr triple))) (set-window-configuration (cadr triple)) (if (setq frame (assq frame liece-window-configuration-stack)) (setq liece-window-configuration-stack (delq frame liece-window-configuration-stack)))) liece-window-configuration-stack)) (provide 'liece-window) ;;; liece-window.el ends here