1 ;; -*- mode: Lisp; Syntax: Common-Lisp; Package: cells; -*-
4 Celtk -- Cells
, Tcl
, and Tk
6 Copyright
(C) 2006 by Kenneth Tilton
8 This library is free software
; you can redistribute it and/or
9 modify it under the terms of the Lisp Lesser GNU Public License
10 (http://opensource.franz.com
/preamble.html
), known as the LLGPL.
12 This library is distributed WITHOUT ANY WARRANTY
; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 See the Lisp Lesser GNU Public License for more details.
22 (export '(title$ active .time decoration
)))
28 full-screen-no-deco-window
32 ;;; --- decoration -------------------------------------------
34 (defmd decoration-mixin
()
35 (decoration (c-in nil
)))
37 ;;; --- toplevel ---------------------------------------------
39 (deftk toplevel
(widget decoration-mixin
)
42 -borderwidth -cursor -highlightbackground -highlightcolor
43 -highlightthickness -padx -pady -relief
44 -takefocus -background -tk-class -colormap
45 -container -height -menu -screen
50 ;; --- panedwindow -----------------------------------------
52 (deftk panedwindow
(widget decoration-mixin
)
55 -background -borderwidth -cursor -height
56 -orient -relief -width
69 (defmethod make-tk-instance ((self panedwindow
))
70 (tk-format `(:make-tk
,self
) "panedwindow ~a -orient ~(~a~)"
71 (^path
) (or (orient self
) "vertical"))
72 (tk-format `(:pack
,self
) "pack ~a -expand yes -fill both" (^path
)))
74 (defmethod parent-path ((self panedwindow
)) (^path
))
76 (defobserver .kids
((self panedwindow
))
77 (loop for k in
(^kids
)
78 do
(trc "panedwindow adds" k
(type-of k
) (md-name k
) (path k
))
79 (tk-format `(:post-make-tk
,self
) "~a add ~a" (^path
) (path k
))))
81 ; --------------------------------------------------------
83 (defmodel composite-widget
(widget)
84 ((kids-packing :initarg
:kids-packing
:accessor kids-packing
:initform nil
)))
88 (defmodel application
(family)
89 ((app-time :initform
(c-in (now))
93 (define-symbol-macro .time
(app-time *app
*))
95 (defmethod path ((self application
)) nil
)
97 (defvar *app-idle-tasks
*)
98 (defun app-idle-tasks-clear ()
99 (setf *app-idle-tasks
* nil
))
100 (defun app-idle-task-new (task-fn)
101 (push task-fn
*app-idle-tasks
*)
104 (defun app-idle-task-destroy (task-fn)
105 (setf *app-idle-tasks
*
106 (delete task-fn
*app-idle-tasks
*)))
109 (defun app-idle-task-destroy (task-cell)
110 (setf *app-idle-tasks
*
111 (if (eq task-cell
*app-idle-tasks
*)
112 (cdr *app-idle-tasks
*)
113 (mapl (lambda (tasks)
114 (when (eq task-cell
(cdr tasks
))
115 (rplacd tasks
(cdr task-cell
))))))))
118 (defun app-idle (self)
119 (loop for w in
(^kids
)
120 do
(when (not (eq :arrow
(cursor w
)))
121 (setf (cursor w
) :arrow
)))
122 (setf (^app-time
) (now))
123 (loop for task in
*app-idle-tasks
*
124 do
(funcall task self task
)))
126 (defmd window
(toplevel composite-widget decoration-mixin
)
127 (title$
(c?
(string-capitalize (class-name (class-of self
)))))
128 (dictionary (make-hash-table :test
'equalp
))
129 (tkwins (make-hash-table))
130 (xwins (make-hash-table))
131 (cursor :arrow
:cell nil
)
132 (keyboard-modifiers (c-in nil
))
133 (callbacks (make-hash-table :test
#'eq
))
134 (edit-style (c-in nil
))
135 (tk-scaling (c?
1.3 #+tki
(read-from-string (tk-eval "tk scaling"))))
138 (tkfont-info (tkfont-info-loader))
142 (focus-state (c-in nil
) :documentation
"This is about the window having the focus on the desktop, not the key focus.
143 Actually holds last event code, :focusin or :focusout")
149 (defmethod (setf cursor
) :after
(new-value (self window
))
151 (tk-format-now ". configure -cursor ~a" (string-downcase (symbol-name new-value
)))))
153 (export! .control-key-p .alt-key-p .shift-key-p focus-state ^focus-state
)
154 (define-symbol-macro .control-key-p
(find :control
(keyboard-modifiers .tkw
)))
155 (define-symbol-macro .alt-key-p
(find :alt
(keyboard-modifiers .tkw
)))
156 (define-symbol-macro .shift-key-p
(find :shift
(keyboard-modifiers .tkw
)))
158 (defmethod make-tk-instance ((self window
))
159 (setf (gethash (^path
) (dictionary .tkw
)) self
))
161 (defun screen-width ()
163 (tk-format-now "winfo screenwidth .")))
165 (defun screen-height ()
167 (tk-format-now "winfo screenheight .")))
169 (defmodel full-screen-no-deco-window
(window)
172 (defmethod initialize-instance :before
((self full-screen-no-deco-window
)
173 &key
&allow-other-keys
)
174 (tk-format '(:pre-make-tk self
)
175 "wm geometry . [winfo screenwidth .]x[winfo screenheight .]+0+0")
176 (tk-format '(:pre-make-tk self
) "update idletasks")
177 #-macosx
(tk-format '(:pre-make-tk self
) "wm attributes . -topmost yes")
178 (tk-format '(:pre-make-tk self
) "wm overrideredirect . yes")
181 (defmethod do-on-key-down :before
(self &rest args
&aux
(keysym (car args
)))
182 (trc nil
"ctk::do-on-key-down window" keysym
(keyboard-modifiers .tkw
))
183 (bwhen (mod (keysym-to-modifier keysym
))
184 (eko (nil "modifiers after adding" mod
)
185 (pushnew mod
(keyboard-modifiers .tkw
)))))
187 (defmethod do-on-key-up :before
(self &rest args
&aux
(keysym (car args
)))
188 (trc nil
"ctk::do-on-key-up before" keysym
(keyboard-modifiers .tkw
))
189 (bwhen (mod (keysym-to-modifier keysym
))
190 (eko (nil "modifiers after removing" mod
)
191 (setf (keyboard-modifiers .tkw
)
192 (delete mod
(keyboard-modifiers .tkw
))))))
194 ;;; Helper function that actually executes decoration change
195 (defun %%do-decoration
(widget decoration
)
196 (let ((path (path widget
)))
200 (tk-format '(:pre-make-tk decoration
)
201 "wm withdraw ~a" path
)
202 (tk-format '(:pre-make-tk decoration
)
203 "wm overrideredirect ~a 1" path
)
204 (tk-format '(:pre-make-tk decoration
)
205 "wm deiconify ~a" path
)
206 (tk-format '(:pre-make-tk decoration
)
207 "update idletasks" path
)
211 (tk-format '(:pre-make-tk decoration
)
212 "wm withdraw ~a" path
)
213 (tk-format '(:pre-make-tk decoration
)
214 "wm overrideredirect ~a 0" path
)
215 (tk-format '(:pre-make-tk decoration
)
216 "wm deiconify ~a" path
)
217 (tk-format '(:pre-make-tk decoration
)
218 "update idletasks" path
))))))
220 ;;; Decoration observer for all widgets that inherit from decoration-mixin
221 ;;; On Mac OS X this is a one-way operation. When created without decorations
222 ;;; then it is not possible to restore the decorations and vice versa. So on
223 ;;; OS X the window decoration will stay as you created the window with.
225 (defobserver decoration
((self decoration-mixin
)) ;; == wm overrideredirect 0|1
226 (assert (or (eq new-value nil
) ;; Does not change decoration
227 (eq new-value
:normal
) ;; "normal"
228 (eq new-value
:none
))) ;; No title bar, no nothing ...
229 (if (not (eq new-value old-value
))
230 (%%do-decoration self new-value
)))
232 (defobserver initial-focus
()
234 (tk-format '(:fini new-value
) "focus ~a" (path new-value
))))
236 (defun tkfont-info-loader ()
237 (c?
(eko (nil "tkfinfo")
238 (loop with scaling
= (^tk-scaling
)
239 for
(tkfont fname
) in
(^tkfonts-to-load
)
242 (loop for fsize in
(^tkfont-sizes-to-load
)
243 for id
= (format nil
"~(~a-~2,'0d~)" tkfont fsize
)
244 for tkf
= (tk-eval "font create ~a -family {~a} -size ~a"
246 for
(nil ascent nil descent nil linespace nil fixed
) = (tk-eval-list "font metrics ~a" tkf
)
248 (progn (trc nil
"tkfontloaded" id fname fsize tkfont tkf
)
249 (make-tkfinfo :ascent
(round (parse-integer ascent
:junk-allowed t
) scaling
)
253 :descent
(round (parse-integer descent
:junk-allowed t
) scaling
)
254 :linespace
(round (parse-integer linespace
:junk-allowed t
) scaling
)
255 :fixed
(plusp (parse-integer fixed
:junk-allowed t
))
256 :em
(round (parse-integer
257 (tk-eval "font measure ~(~a~) \"m\"" tkfont
) :junk-allowed t
)
260 (defobserver title$
((self window
))
261 (tk-format '(:configure
"title") "wm title . ~s" (or new-value
"Untitled")))
263 (defmethod path ((self window
)) ".")
264 (defmethod parent-path ((self window
)) "")
266 (defmethod iconify ((self window
))
267 (%%do-decoration self
:normal
)
268 (tk-format `(:fini
) "wm iconify ~a" (^path
)))
270 (defmethod deiconify ((self window
))
271 (%%do-decoration self
(decoration self
))
272 (tk-format `(:fini
) "wm deiconify ~a" (^path
)))