comparison lisp/modes/strokes.el @ 185:3d6bfa290dbd r20-3b19

Import from CVS: tag r20-3b19
author cvs
date Mon, 13 Aug 2007 09:55:28 +0200
parents 6075d714658b
children b405438285a2
comparison
equal deleted inserted replaced
184:bcd2674570bf 185:3d6bfa290dbd
1 ;;; strokes.el -- Control XEmacs through mouse strokes -- 1 ;;; strokes.el -- Control XEmacs through mouse strokes --
2 ;; Mon Jun 2 12:40:41 EDT 1997 2 ;; Mon Jul 25 12:40:41 EDT 1997
3 3
4 ;; Copyright (C) 1997 Free Software Foundation, Inc. 4 ;; Copyright (C) 1997 Free Software Foundation, Inc.
5 5
6 ;; Author: David Bakhash <cadet@mit.edu> 6 ;; Author: David Bakhash <cadet@mit.edu>
7 ;; Maintainer: David Bakhash <cadet@mit.edu> 7 ;; Maintainer: David Bakhash <cadet@mit.edu>
8 ;; Version: 2.3 8 ;; Version: 2.4-beta
9 ;; Created: 12 April 1997 9 ;; Created: 12 April 1997
10 ;; Keywords: lisp, mouse, extensions 10 ;; Keywords: lisp, mouse, extensions
11 11
12 ;; This file is part of XEmacs. 12 ;; This file is part of XEmacs.
13 13
28 28
29 ;;; Synched up with: Not in FSF. 29 ;;; Synched up with: Not in FSF.
30 30
31 ;;; Commentary: 31 ;;; Commentary:
32 32
33 ;; This package is written for for XEmacs v19.14 and up. 33 ;; This package is written for for XEmacs v19.15 and up. This is the
34 ;; This is the strokes package. It is intended to allow the user to 34 ;; strokes package. It is intended to allow the user to control
35 ;; control XEmacs by means of mouse strokes. Once strokes is loaded, you 35 ;; XEmacs by means of mouse strokes. Once strokes is loaded, you can
36 ;; can always get help be invoking `strokes-help': 36 ;; always get help be invoking `strokes-help':
37 37
38 ;; > M-x strokes-help 38 ;; > M-x strokes-help
39 39
40 ;; and you can learn how to use the package. A mouse stroke, for now, 40 ;; and you can learn how to use the package. A mouse stroke, for now,
41 ;; can be defined as holding the middle button, for instance, and then 41 ;; can be defined as holding the middle button, for instance, and then
42 ;; moving the mouse in whatever pattern you wish, which you have set 42 ;; moving the mouse in whatever pattern you wish, which you have set
43 ;; XEmacs to understand as mapping to a given command. For example, you 43 ;; XEmacs to understand as mapping to a given command. For example,
44 ;; may wish the have a mouse stroke that looks like a capital `C' which 44 ;; you may wish the have a mouse stroke that looks like a capital `C'
45 ;; means `copy-region-as-kill'. Treat strokes just like you do key 45 ;; which means `copy-region-as-kill'. Treat strokes just like you do
46 ;; bindings. For example, XEmacs sets key bindings globally with the 46 ;; key bindings. For example, XEmacs sets key bindings globally with
47 ;; `global-set-key' command. Likewise, you can do 47 ;; the `global-set-key' command. Likewise, you can do
48 48
49 ;; > M-x global-set-stroke 49 ;; > M-x global-set-stroke
50 50
51 ;; to interactively program in a stroke. It would be wise to set the 51 ;; to interactively program in a stroke. It would be wise to set the
52 ;; first one to this very command, so that from then on, you invoke 52 ;; first one to this very command, so that from then on, you invoke
64 64
65 ;; 1) To describe a stroke binding, you can type 65 ;; 1) To describe a stroke binding, you can type
66 66
67 ;; > M-x describe-stroke 67 ;; > M-x describe-stroke
68 68
69 ;; analogous to `describe-key'. It's also wise to have a stroke, 69 ;; analogous to `describe-key'. It's also wise to have a
70 ;; like an `h', for help, or a `?', mapped to `describe-stroke'. 70 ;; stroke, like an `h', for help, or a `?', mapped to
71 71 ;; `describe-stroke'.
72 ;; 2) stroke bindings are set internally through the lisp function 72
73 ;; 2) stroke bindings are set internally through the Lisp function
73 ;; `define-stroke', similar to the `define-key' function. some 74 ;; `define-stroke', similar to the `define-key' function. some
74 ;; examples for a 3x3 stroke grid would be 75 ;; examples for a 3x3 stroke grid would be
75 76
76 ;; (define-stroke c-mode-stroke-map 77 ;; (define-stroke c-mode-stroke-map
77 ;; '((0 . 0) (1 . 1) (2 . 2)) 78 ;; '((0 . 0) (1 . 1) (2 . 2))
78 ;; 'kill-region) 79 ;; 'kill-region)
79 ;; (define-stroke strokes-global-map 80 ;; (define-stroke strokes-global-map
80 ;; '((0 . 0) (0 . 1) (0 . 2) (1 . 2) (2 . 2)) 81 ;; '((0 . 0) (0 . 1) (0 . 2) (1 . 2) (2 . 2))
81 ;; 'list-buffers) 82 ;; 'list-buffers)
82 83
83 ;; however, if you would probably just have the user enter in the 84 ;; however, if you would probably just have the user enter in
84 ;; stroke interactively and then set the stroke to whatever he/she 85 ;; the stroke interactively and then set the stroke to whatever
85 ;; entered. The lisp function to interactively read a stroke is 86 ;; he/she entered. The Lisp function to interactively read a
86 ;; `strokes-read-stroke'. This is especially helpful when you're 87 ;; stroke is `strokes-read-stroke'. This is especially helpful
87 ;; on a fast computer that can handle a 9x9 stroke grid. 88 ;; when you're on a fast computer that can handle a 9x9 stroke
89 ;; grid.
88 90
89 ;; NOTE: only global stroke bindings are currently implemented, 91 ;; NOTE: only global stroke bindings are currently implemented,
90 ;; however mode- and buffer-local stroke bindings may eventually 92 ;; however mode- and buffer-local stroke bindings may eventually
91 ;; be implemented in a future version. 93 ;; be implemented in a future version.
92 94
96 ;; > M-x customize 98 ;; > M-x customize
97 99
98 ;; and customizing the group named `strokes'. You can also read 100 ;; and customizing the group named `strokes'. You can also read
99 ;; documentation on the variables there. 101 ;; documentation on the variables there.
100 102
101 ;; `strokes-minimum-match-score' (determines the threshold of error that 103 ;; `strokes-minimum-match-score' (determines the threshold of error
102 ;; makes a stroke acceptable or unacceptable. If your strokes arn't 104 ;; that makes a stroke acceptable or unacceptable. If your strokes
103 ;; matching, then you should raise this variable. 105 ;; aren't matching, then you should raise this variable.
104 106
105 ;; `strokes-grid-resolution' (determines the grid dimensions that you use 107 ;; `strokes-grid-resolution' (determines the grid dimensions that you
106 ;; when defining/reading strokes. The finer the grid your computer can 108 ;; use when defining/reading strokes. The finer the grid your
107 ;; handle, the more you can do, but even a 3x3 grid is pretty cool.) 109 ;; computer can handle, the more you can do, but even a 3x3 grid is
108 ;; The default value (7) should be fine for most decent computers. 110 ;; pretty cool.) The default value (7) should be fine for most decent
109 ;; NOTE: This variable should not be set to a number less than 3. 111 ;; computers. NOTE: This variable should not be set to a number less
112 ;; than 3.
110 113
111 ;; `strokes-display-strokes-buffer' will allow you to hide the strokes 114 ;; `strokes-display-strokes-buffer' will allow you to hide the strokes
112 ;; buffer when doing simple strokes. This is a speedup for slow 115 ;; buffer when doing simple strokes. This is a speedup for slow
113 ;; computers as well as people who don't want to see their strokes. 116 ;; computers as well as people who don't want to see their strokes.
114 117
122 ;; Whenever you load in the strokes package, you will be able to save 125 ;; Whenever you load in the strokes package, you will be able to save
123 ;; what you've done upon exiting XEmacs. You can also do 126 ;; what you've done upon exiting XEmacs. You can also do
124 127
125 ;; > M-x save-strokes 128 ;; > M-x save-strokes
126 129
127 ;; and it will save your strokes in ~/.strokes, or you may wish to change 130 ;; and it will save your strokes in ~/.strokes, or you may wish to
128 ;; this by setting the variable `strokes-file'. 131 ;; change this by setting the variable `strokes-file'.
129 132
130 ;; Note that internally, all of the routines that are part of this 133 ;; Note that internally, all of the routines that are part of this
131 ;; package are able to deal with complex strokes, as they are a superset 134 ;; package are able to deal with complex strokes, as they are a
132 ;; of simple strokes. However, the default of this package will map 135 ;; superset of simple strokes. However, the default of this package
133 ;; mouse button2 to the command `strokes-do-stroke', and NOT 136 ;; will map mouse button2 to the command `strokes-do-stroke', and NOT
134 ;; `strokes-do-complex-stroke'. If you wish to use complex strokes, you 137 ;; `strokes-do-complex-stroke'. If you wish to use complex strokes,
135 ;; will have to override this key mapping. Complex strokes are terminated 138 ;; you will have to override this key mapping. Complex strokes are
136 ;; with mouse button3. The strokes package will not interfere with 139 ;; terminated with mouse button3. The strokes package will not
137 ;; `mouse-yank', but you may want to examine how this is done (see the 140 ;; interfere with `mouse-yank', but you may want to examine how this
138 ;; variable `strokes-click-command') 141 ;; is done (see the variable `strokes-click-command')
139 142
140 ;; To get strokes to work as part of your your setup, then you'll have 143 ;; To get strokes to work as part of your your setup, then you'll have
141 ;; put the strokes package in your load-path (preferably byte-compiled) 144 ;; put the strokes package in your load-path (preferably
142 ;; and then add the following to your .xemacs-options file (or wherever 145 ;; byte-compiled) and then add the following to your .emacs file (or
143 ;; you put XEmacs-specific startup preferences): 146 ;; wherever you put XEmacs-specific startup preferences):
144 147
145 ;;(and (fboundp 'device-on-window-system-p) 148 ;; (if window-system (require 'strokes))
146 ;; (device-on-window-system-p)
147 ;; (require 'strokes))
148 149
149 ;; Once loaded, you can start stroking. You can also toggle between 150 ;; Once loaded, you can start stroking. You can also toggle between
150 ;; strokes mode by simple typing 151 ;; strokes mode by simple typing
151 152
152 ;; > M-x strokes-mode 153 ;; > M-x strokes-mode
153 154
154 ;; I am now in the process of porting this package to emacs. I also hope 155 ;; I am now in the process of porting this package to Emacs. I also
155 ;; that, with the help of others, this package will be useful in entering 156 ;; hope that, with the help of others, this package will be useful in
156 ;; in pictographic-like language text using the mouse (i.e. Korean). 157 ;; entering in pictographic-like language text using the mouse
157 ;; Japanese and Chinese are a bit trickier, but I'm sure that with help 158 ;; (i.e. Korean). Japanese and Chinese are a bit trickier, but I'm
158 ;; it can be done. The next version will allow the user to enter strokes 159 ;; sure that with help it can be done. The next version will allow
159 ;; which "remove the pencil from the paper" so to speak, so one character 160 ;; the user to enter strokes which "remove the pencil from the paper"
160 ;; can have multiple strokes. 161 ;; so to speak, so one character can have multiple strokes.
161 162
162 ;; You can read more about strokes at: 163 ;; You can read more about strokes at:
163 164
164 ;; http://www.mit.edu/people/cadet/strokes-help.html 165 ;; http://www.mit.edu/people/cadet/strokes-help.html
165 166
166 ;; If you're interested in using strokes for writing English into XEmacs 167 ;; If you're interested in using strokes for writing English into
167 ;; using strokes, then you'll want to read about it on the web page above 168 ;; XEmacs using strokes, then you'll want to read about it on the web
168 ;; or just download from http://www.mit.edu/people/cadet/strokes-abc.el, 169 ;; page above or just download from
169 ;; which is nothing but a file with some helper commands for inserting 170 ;; http://www.mit.edu/people/cadet/strokes-abc.el, which is nothing
170 ;; alphanumerics and punctuation. 171 ;; but a file with some helper commands for inserting alphanumerics
171 172 ;; and punctuation.
172 ;; Great thanks to Rob Ristroph for his generosity in letting me use his 173
173 ;; PC to develop this, Jason Johnson for his help in algorithms, Euna 174 ;; Great thanks to Rob Ristroph for his generosity in letting me use
174 ;; Kim for her help in Korean, and massive thanks to the helpful guys 175 ;; his PC to develop this, Jason Johnson for his help in algorithms,
175 ;; on the help instance on athena (zeno, jered, amu, gsstark, ghudson, etc) 176 ;; Euna Kim for her help in Korean, and massive thanks to the helpful
176 ;; Special thanks to Steve Baur and Hrvoje Niksic for all their help. 177 ;; guys on the help instance on athena (zeno, jered, amu, gsstark,
177 ;; And even more thanks to Dave Gillespie for all the elisp help--he 178 ;; ghudson, etc) Special thanks to Steve Baur, Kyle Jones, and Hrvoje
178 ;; is responsible for helping me use the cl macros at (near) max speed. 179 ;; Niksic for all their help. And special thanks to Dave Gillespie
180 ;; for all the elisp help--he is responsible for helping me use the cl
181 ;; macros at (near) max speed.
179 182
180 ;; Tasks: (what I'm getting ready for future version)... 183 ;; Tasks: (what I'm getting ready for future version)...
181 ;; 2) use 'strokes-read-complex-stroke for korean, etc. 184 ;; 2) use 'strokes-read-complex-stroke for korean, etc.
182 ;; 4) buffer-local 'strokes-local-map, and mode-stroke-maps would be nice 185 ;; 4) buffer-local 'strokes-local-map, and mode-stroke-maps would be nice
183 ;; 5) 'list-strokes (kinda important). What do people want?
184 ;; How about an optional docstring for each stroke so that a person
185 ;; can examine the strokes-file and actually make sense of it?
186 ;; (e.g. "This stroke is a pentagram")
187 ;; 6) add some hooks, like `strokes-read-stroke-hook' 186 ;; 6) add some hooks, like `strokes-read-stroke-hook'
188 ;; 7) See what people think of the factory settings. Should I change 187 ;; 7) See what people think of the factory settings. Should I change
189 ;; them? They're all pretty arbitrary in a way. I guess they 188 ;; them? They're all pretty arbitrary in a way. I guess they
190 ;; should be minimal, but computers are getting lots faster, and 189 ;; should be minimal, but computers are getting lots faster, and
191 ;; if I choose the defaults too conservatively, then strokes will 190 ;; if I choose the defaults too conservatively, then strokes will
192 ;; surely dissapoint some people on decent machines (until they 191 ;; surely disappoint some people on decent machines (until they
193 ;; figure out M-x customize). I need feedback. 192 ;; figure out M-x customize). I need feedback.
194 ;; Other: I always have the most beta version of strokes, so if you 193 ;; Other: I always have the most beta version of strokes, so if you
195 ;; want it just let me know. 194 ;; want it just let me know.
196 195
197 ;;; Change Log: 196 ;;; Change Log:
198 197
199 ;; 1.3: provided user variable `strokes-use-strokes-buffer' to let users 198 ;; 1.3: provided user variable `strokes-use-strokes-buffer' to let
200 ;; hide the strokes and strokes buffer when entering simple strokes. 199 ;; users hide the strokes and strokes buffer when entering simple
200 ;; strokes.
201 ;; 1.3: cleaned up most leaks. 201 ;; 1.3: cleaned up most leaks.
202 ;; 1.3: with Jari Aalto's help, cleaned up overall program. 202 ;; 1.3: with Jari Aalto's help, cleaned up overall program.
203 ;; 1.3: added `strokes-help' for help on strokes 203 ;; 1.3: added `strokes-help' for help on strokes
204 ;; 1.3: fixed 'strokes-load-hook bug 204 ;; 1.3: fixed 'strokes-load-hook bug
205 ;; 1.3: email address change: now <cadet@mit.edu> 205 ;; 1.3: email address change: now <cadet@mit.edu>
206 ;; 1.3: added `strokes-report-bug' based on efs/dired's `dired-report-bug' 206 ;; 1.3: added `strokes-report-bug' based on efs/dired's
207 ;; `dired-report-bug'
207 ;; 1.3: added more dialog-box queries for mouse-event stuff. 208 ;; 1.3: added more dialog-box queries for mouse-event stuff.
208 ;; 1.4: allowed strokes to invoke kbd macros as well (thanks gsstark!) 209 ;; 1.4: allowed strokes to invoke kbd macros as well (thanks gsstark!)
209 ;; 2.0: fixed up ordering of certain functions. 210 ;; 2.0: fixed up ordering of certain functions.
210 ;; 2.0: fixed bug applying to strokes in dedicated and minibuffer windows. 211 ;; 2.0: fixed bug applying to strokes in dedicated and minibuffer
212 ;; windows.
211 ;; 2.0: punted the C-h way of invoking strokes help routines. 213 ;; 2.0: punted the C-h way of invoking strokes help routines.
212 ;; 2.0: fixed `strokes-define-stroke' so it would error check against 214 ;; 2.0: fixed `strokes-define-stroke' so it would error check against
213 ;; defining strokes that were too short (really clicks) 215 ;; defining strokes that were too short (really clicks) 2.0:
214 ;; 2.0: added `strokes-toggle-strokes-buffer' interactive function 216 ;; added `strokes-toggle-strokes-buffer' interactive function
215 ;; 2.0: added `customize' support, thanks to patch from Hrvoje (thanks) 217 ;; 2.0: added `customize' support, thanks to patch from Hrvoje
216 ;; 2.1: strokes no longer forces `mouse-yank-at-point' to t on mouse-yank 218 ;; (thanks)
217 ;; (i.e. `mouse-yank-at-point' is up to you again) 219 ;; 2.1: strokes no longer forces `mouse-yank-at-point' to t on
220 ;; mouse-yank (i.e. `mouse-yank-at-point' is up to you again)
218 ;; 2.1: toggling strokes-mode off and then back on no longer deletes 221 ;; 2.1: toggling strokes-mode off and then back on no longer deletes
219 ;; the strokes that you programmed in but didn't save before 222 ;; the strokes that you programmed in but didn't save before
220 ;; toggling off strokes-mode. 223 ;; toggling off strokes-mode.
221 ;; 2.1: advised may functions for modes like VM and w3 so that they too 224 ;; 2.1: advised may functions for modes like VM and w3 so that they
222 ;; can use strokes, while still mantaining old button2 functionality. 225 ;; too can use strokes, while still maintaining old button2
223 ;; 2.1: with steve's help, got the autoload for `strokes-mode' and 226 ;; functionality.
227 ;; 2.1: with Steve's help, got the autoload for `strokes-mode' and
224 ;; fixed up the package so loading it does not enable strokes 228 ;; fixed up the package so loading it does not enable strokes
225 ;; until user calls `strokes-mode'. 229 ;; until user calls `strokes-mode'.
226 ;; 2.2: made sure that abbrev-mode was off in the ` *strokes*' buffer 230 ;; 2.2: made sure that abbrev-mode was off in the ` *strokes*' buffer
227 ;; 2.2: added more dired advice for mouse permissions commands 231 ;; 2.2: added more dired advice for mouse permissions commands
228 ;; 2.2: added some checks to see if saving strokes is really necessary so 232 ;; 2.2: added some checks to see if saving strokes is really necessary
229 ;; the user doesn't get promped aimlessly. 233 ;; so the user doesn't get prompted aimlessly.
230 ;; 2.2: change the `strokes-lift' symbol to a keyword of value `:strokes-lift' 234 ;; 2.2: change the `strokes-lift' symbol to a keyword of value
231 ;; for legibility. IF YOUR OLD STROKES DON'T WORK, THIS IS PROBABLY WHY. 235 ;; `:strokes-lift' for legibility. IF YOUR OLD STROKES DON'T
232 ;; 2.2: I might have to change this back to `'strokes-lift' because the keyword 236 ;; WORK, THIS IS PROBABLY WHY.
233 ;; fails in emacs, though I don't know why. 237 ;; 2.2: I might have to change this back to `'strokes-lift' because
238 ;; the keyword fails in emacs, though I don't know why.
234 ;; 2.2: `strokes-describe-stroke' is nicer during recursive edits 239 ;; 2.2: `strokes-describe-stroke' is nicer during recursive edits
235 ;; 2.2: provided `strokes-fill-stroke' to fill in empty spaces of strokes 240 ;; 2.2: provided `strokes-fill-stroke' to fill in empty spaces of strokes
236 ;; as an important step towards platform (speed) independence. 241 ;; as an important step towards platform (speed) independence.
237 ;; Because of this, I moved the global setting of `strokes-last-stroke' 242 ;; Because of this, I moved the global setting of
238 ;; from `strokes-eliminate-consecutive-redundancies' to 243 ;; `strokes-last-stroke' from
239 ;; `strokes-fill-stroke' since the latter comes later in processing 244 ;; `strokes-eliminate-consecutive-redundancies' to
240 ;; a user stroke. 245 ;; `strokes-fill-stroke' since the latter comes later in
246 ;; processing a user stroke.
241 ;; 2.2: Finally changed the defaults, so now `strokes-grid-resolution' is 9 247 ;; 2.2: Finally changed the defaults, so now `strokes-grid-resolution' is 9
242 ;; and `strokes-minimum-match-score' is 1000 by default. This will surely 248 ;; and `strokes-minimum-match-score' is 1000 by default. This
243 ;; mess some people up, but if so, just set it back w/ M-x customize. 249 ;; will surely mess some people up, but if so, just set it back
244 ;; 2.2: Fixed up the mechanism for updating the `strokes-window-configuration'. 250 ;; w/ M-x customize.
245 ;; Now it only uses one function (`strokes-update-window-configuration') 251 ;; 2.2: Fixed up the mechanism for updating the
246 ;; which does it all, and much more efficiently (thanks RMS!). 252 ;; `strokes-window-configuration'. Now it only uses one function
247 ;; 2.2 Fixed up the appearance of the *strokes* buffer so that there are no 253 ;; (`strokes-update-window-configuration') which does it all, and
248 ;; ugly line truncations, and I got rid of the bug which would draw the stroke 254 ;; much more efficiently (thanks RMS!).
249 ;; on the wrong line. I still wish that `event-closest-point' was smarter. 255 ;; 2.2 Fixed up the appearance of the *strokes* buffer so that there
250 ;; In fact, `event-closest-point' does *not* do what its name suggests. 256 ;; are no ugly line truncations, and I got rid of the bug which
251 ;; 2.3 Added more to `strokes-update-window-configuration' so it goes to hell less often 257 ;; would draw the stroke on the wrong line. I still wish that
252 ;; 2.3 `strokes-mode' no longer will undefine keys unless it's sure that the user had 258 ;; `event-closest-point' was smarter. In fact,
253 ;; had them mapped to a strokes command. 259 ;; `event-closest-point' does *not* do what its name suggests.
254 ;; 2.3 added more magic autoload statements so strokes work more smoothly. 260 ;; 2.3 Added more to `strokes-update-window-configuration' so it goes
255 ;; similarly, I made strokes-mode turn itself on when the user defines a stroke 261 ;; to hell less often
256 ;; (thanks Hrvoje). 262 ;; 2.3 `strokes-mode' no longer will undefined keys unless it's sure
257 ;; 2.3 Added "Strokes" to the modeline when strokes is on, and allow toggling strokes 263 ;; that the user had had them mapped to a strokes command.
258 ;; with mouse button2. 264 ;; 2.3 Added more magic autoload statements so strokes work more
259 ;; 2.3 Added `list-strokes', which is a really nice function which graphically lists 265 ;; smoothly. similarly, I made strokes-mode turn itself on when
260 ;; all the strokes that the user has defined and their corresponding commands. 266 ;; the user defines a stroke (thanks Hrvoje).
261 ;; `list-strokes' will appropriately colorize the pixmaps to display some time info. 267 ;; 2.3 Added "Strokes" to the modeline when strokes is on, and allow
268 ;; toggling strokes with mouse button2.
269 ;; 2.3 Added `list-strokes', which is a really nice function which
270 ;; graphically lists all the strokes that the user has defined
271 ;; and their corresponding commands. `list-strokes' will
272 ;; appropriately colorize the pixmaps to display some time info.
273 ;; 2.4 Added all new functionality to strokes by allowing the user to
274 ;; enter strokes in graphically into XEmacs, allowing true graphic
275 ;; editing, Chinese/Japanese, etc. User simply uses C-button2 to
276 ;; draw strokes (function: `strokes-compose-complex-stroke'). Then
277 ;; after the glyph gets inserted into the current buffer at (point),
278 ;; the use can treat that glyph as any other character, and
279 ;; copy/paste/delete/undo, etc. Also, when the user would like to
280 ;; save/send the glyphs (to other XEmacs users, of course), he/she
281 ;; can use the helper functions:
282 ;;
283 ;; i. M-x strokes-encode-buffer -- Ascii-encodes and compresses
284 ;; strokes to base-64.
285 ;; ii. M-x strokes-decode-buffer -- Decodes ascii-encoded strokes
286 ;; back into glyphs.
287 ;; 2.4 With help from Kyle fixed the itimer (timeout event) bug, where I
288 ;; forgot to check for timeouts.
289 ;; 2.4 Around this time, made a successful port of strokes.el for emacs.
290 ;; 2.4 Made added `strokes-xpm-header' as a variable.
291 ;; 2.4 Changed the default value of `strokes-character' from `o' to
292 ;; `@' since it looks nicer when drawn.
293 ;; 2.4 Changed `strokes-click-p' so that it considers only a stroke
294 ;; of length <= 1 a click, as opposed to a length 2 being a
295 ;; click.
296 ;; 2.4 Totally made the the function `strokes-read-stroke' (and a bit
297 ;; on `strokes-read-complex-stroke') more efficient and robust,
298 ;; making the former use the optional event passed to it, and
299 ;; thus not losing the first mouse event position when reading a
300 ;; stroke on the fly.
301 ;; 2.4 Finally fixed the mouse-yank / mouse-yank-at-point bug (after
302 ;; months of struggling with it). I simply inserted a (sit-for 0)
303 ;; before the (command-execute strokes-click-command) and that
304 ;; patched it up. I'd thought that it was a kludge, but I later
305 ;; found out that it wasn't, as redisplay has several states, and
306 ;; command-execute often must decide which of two states must be
307 ;; considered when executing a command. The (sit-for 0) merely
308 ;; allowed redisplay to be sure to wait for the ` *strokes*'
309 ;; buffer to vanish before executing the command (thanks for the
310 ;; explanation of why my frobbing worked Kyle). Fixing this bug
311 ;; also (magically) fixed the bug which prevented strokes from
312 ;; executing a stroke in a mode which had it's own binding for
313 ;; button-2, such as w3 when the variable
314 ;; `strokes-use-strokes-buffer' is non-nil. It used to be that
315 ;; if you chose to view your strokes, then you couldn't use
316 ;; strokes properly in modes like VM or w3. Now you can!
317 ;; 2.4 Replaced `kill-emacs-hook' with `kill-emacs-query-functions'
318 ;; for prompting the user to save his/her strokes, since
319 ;; `kill-emacs-hook' was not the right hook to use.
320 ;; 2.4 Having `strokes-update-window-configuration' bound to
321 ;; `select-frame-hook' was a heavy function for such a commonly
322 ;; run hook -- especially since event-Xt.c (?) will add the
323 ;; eval-event to the event queue. So the effect was that if XEmacs
324 ;; was doing an interpreter-intensive task while the user (re)selected
325 ;; the frame n times, then the intensive window config updating
326 ;; took place n times. So to deal, I put in some extra checks to
327 ;; see if the frame parameters really changed, making an update
328 ;; worthwhile. See `strokes-update-window-configuration-plist'.
262 329
263 ;;; Code: 330 ;;; Code:
264 331
265 ;;; Requirements and provisions... 332 ;;; Requirements and provisions...
266 333
267 (autoload 'reporter-submit-bug-report "reporter") 334 (autoload 'reporter-submit-bug-report "reporter")
268 (autoload 'mail-position-on-field "sendmail") 335 (autoload 'mail-position-on-field "sendmail")
269 (eval-when-compile 336 (eval-when-compile
270 (mapc 'require '(xpm-mode pp annotations reporter advice))) 337 (mapc 'require '(xpm-mode pp annotations reporter advice view-less)))
271 338
272 ;;; Constants... 339 ;;; Constants...
273 340
274 (defconst strokes-version "2.3") 341 (defconst strokes-version "2.4-beta")
275 342
276 (defconst strokes-bug-address "cadet@mit.edu") 343 (defconst strokes-bug-address "cadet@mit.edu")
277 344
278 (defconst strokes-lift :strokes-lift 345 (defconst strokes-lift :strokes-lift
279 "Symbol representing a stroke lift event for complex strokes. 346 "Symbol representing a stroke lift event for complex strokes.
283 (defconst strokes-xpm-header "/* XPM */ 350 (defconst strokes-xpm-header "/* XPM */
284 static char * stroke_xpm[] = { 351 static char * stroke_xpm[] = {
285 /* width height ncolors cpp [x_hot y_hot] */ 352 /* width height ncolors cpp [x_hot y_hot] */
286 \"33 33 9 1 26 23\", 353 \"33 33 9 1 26 23\",
287 /* colors */ 354 /* colors */
288 \" c #D9D9D9D9D9D9\", 355 \" c none s none\",
289 \"* s iconColor1 m black c black\", 356 \"* c #000000 s foreground\",
290 \"R c #FFFF00000000\", 357 \"R c #FFFF00000000\",
291 \"O c #FFFF80000000\", 358 \"O c #FFFF80000000\",
292 \"Y c #FFFFFFFF0000\", 359 \"Y c #FFFFFFFF0000\",
293 \"G c #0000FFFF0000\", 360 \"G c #0000FFFF0000\",
294 \"B c #00000000FFFF\", 361 \"B c #00000000FFFF\",
298 "The header to all xpm buffers created by strokes") 365 "The header to all xpm buffers created by strokes")
299 366
300 ;;; user variables... 367 ;;; user variables...
301 368
302 (defgroup strokes nil 369 (defgroup strokes nil
303 "Control Emacs through mouse strokes" 370 "Control Emacs through mouse strokes."
304 :group 'mouse) 371 :group 'mouse)
305 372
306 (defcustom strokes-modeline-string " Strokes" 373 (defcustom strokes-modeline-string " Strokes"
307 "*Modeline identification when strokes are on \(default is \" Strokes\"\)." 374 "*Modeline identification when strokes are on \(default is \" Strokes\"\)."
308 :type 'string 375 :type 'string
309 :group 'strokes) 376 :group 'strokes)
310 377
311 (defcustom strokes-character ?o 378 (defcustom strokes-character ?@
312 "*Character used when drawing strokes in the strokes buffer. 379 "*Character used when drawing strokes in the strokes buffer.
313 \(The default is lower-case `o', which works okay\)." 380 \(The default is lower-case `@', which works okay\)."
314 :type 'character 381 :type 'character
315 :group 'strokes) 382 :group 'strokes)
316 383
317 (defcustom strokes-minimum-match-score 1000 384 (defcustom strokes-minimum-match-score 1000
318 "*Minimum score for a stroke to be considered a possible match. 385 "*Minimum score for a stroke to be considered a possible match.
336 The grid is a square grid, where STROKES-GRID-RESOLUTION defaults to 403 The grid is a square grid, where STROKES-GRID-RESOLUTION defaults to
337 `9', making a 9x9 grid whose coordinates go from (0 . 0) on the top 404 `9', making a 9x9 grid whose coordinates go from (0 . 0) on the top
338 left to ((STROKES-GRID-RESOLUTION - 1) . (STROKES-GRID-RESOLUTION - 1)) 405 left to ((STROKES-GRID-RESOLUTION - 1) . (STROKES-GRID-RESOLUTION - 1))
339 on the bottom right. The greater the resolution, the more intricate 406 on the bottom right. The greater the resolution, the more intricate
340 your strokes can be. 407 your strokes can be.
341 NOTE: This variable should be odd and MUST NOT be less than 3. 408 NOTE: This variable should be odd and MUST NOT be less than 3 and need
409 not be greater than 33, which is the resolution of the pixmaps.
342 WARNING: Changing the value of this variable will gravely affect the 410 WARNING: Changing the value of this variable will gravely affect the
343 strokes you have already programmed in. You should try to 411 strokes you have already programmed in. You should try to
344 figure out what it should be based on your needs and on how 412 figure out what it should be based on your needs and on how
345 quick the particular platform(s) you're operating on, and 413 quick the particular platform(s) you're operating on, and
346 only then start programming in your custom strokes." 414 only then start programming in your custom strokes."
379 447
380 (defvar strokes-window-configuration nil 448 (defvar strokes-window-configuration nil
381 "The special window configuration used when entering strokes. 449 "The special window configuration used when entering strokes.
382 This is set properly in the function `strokes-update-window-configuration'.") 450 This is set properly in the function `strokes-update-window-configuration'.")
383 451
452 (defvar strokes-window-configuration-plist
453 (list 'frame nil 'frame-height nil 'frame-width nil)
454 "Plist describing the state of the current strokes-window-configuration.
455 The plist consists of the following keys:
456
457 'frame Frame to draw strokes in.
458 'frame-height Height of the frame.
459 'frame-width Width of the frame.")
460
384 (defvar strokes-last-stroke nil 461 (defvar strokes-last-stroke nil
385 "Last stroke entered by the user. 462 "Last stroke entered by the user.
386 Its value gets set every time the function 463 Its value gets set every time the function
387 `strokes-fill-stroke' gets called, 464 `strokes-fill-stroke' gets called,
388 since that is the best time to set the variable") 465 since that is the best time to set the variable")
395 corresponding interactive function") 472 corresponding interactive function")
396 473
397 (defvar strokes-load-hook nil 474 (defvar strokes-load-hook nil
398 "Function or functions to be called when `strokes' is loaded.") 475 "Function or functions to be called when `strokes' is loaded.")
399 476
400 (defvar edit-strokes-menu 477 ;;; ### NOT IMPLEMENTED YET ###
401 '("Edit-Strokes" 478 ;;(defvar edit-strokes-menu
402 ["Add stroke..." strokes-global-set-stroke t] 479 ;; '("Edit-Strokes"
403 ["Delete stroke..." strokes-edit-delete-stroke t] 480 ;; ["Add stroke..." strokes-global-set-stroke t]
404 ["Change stroke" strokes-smaller t] 481 ;; ["Delete stroke..." strokes-edit-delete-stroke t]
405 ["Change definition" strokes-larger t] 482 ;; ["Change stroke" strokes-smaller t]
406 ["[Re]List Strokes chronologically" strokes-list-strokes t] 483 ;; ["Change definition" strokes-larger t]
407 ["[Re]List Strokes alphabetically" strokes-list-strokes t] 484 ;; ["[Re]List Strokes chronologically" strokes-list-strokes t]
408 ["Quit" strokes-edit-quit t] 485 ;; ["[Re]List Strokes alphabetically" strokes-list-strokes t]
409 )) 486 ;; ["Quit" strokes-edit-quit t]
487 ;; ))
410 488
411 ;;; Macros... 489 ;;; Macros...
490
491 (defmacro strokes-while-inhibiting-garbage-collector (&rest forms)
492 "Execute FORMS without interference from the garbage collector."
493 `(let ((gc-cons-threshold 134217727))
494 ,@forms))
412 495
413 (defsubst strokes-click-p (stroke) 496 (defsubst strokes-click-p (stroke)
414 "Non-nil if STROKE is really click." 497 "Non-nil if STROKE is really click."
415 (< (length stroke) 3)) 498 (< (length stroke) 2))
416 499
417 ;;; old, but worked pretty good (just in case)... 500 ;;; old, but worked pretty good (just in case)...
418 ;;(defmacro strokes-define-stroke (stroke-map stroke def) 501 ;;(defmacro strokes-define-stroke (stroke-map stroke def)
419 ;; "Add STROKE to STROKE-MAP alist with given command DEF" 502 ;; "Add STROKE to STROKE-MAP alist with given command DEF"
420 ;; (list 'if (list '< (list 'length stroke) 3) 503 ;; (list 'if (list '< (list 'length stroke) 3)
422 ;; "That's a click, not a stroke. See `strokes-click-command'") 505 ;; "That's a click, not a stroke. See `strokes-click-command'")
423 ;; (list 'setq stroke-map (list 'cons (list 'cons stroke def) 506 ;; (list 'setq stroke-map (list 'cons (list 'cons stroke def)
424 ;; (list 'remassoc stroke stroke-map))))) 507 ;; (list 'remassoc stroke stroke-map)))))
425 508
426 (defmacro strokes-define-stroke (stroke-map stroke def) 509 (defmacro strokes-define-stroke (stroke-map stroke def)
427 "Add STROKE to STROKE-MAP alist with given command DEF" 510 "Add STROKE to STROKE-MAP alist with given command DEF."
428 `(if (strokes-click-p ,stroke) 511 `(if (strokes-click-p ,stroke)
429 (error "That's a click, not a stroke; see `strokes-click-command'") 512 (error "That's a click, not a stroke; see `strokes-click-command'")
430 (setq ,stroke-map (cons (cons ,stroke ,def) 513 (setq ,stroke-map (cons (cons ,stroke ,def)
431 (remassoc ,stroke ,stroke-map))))) 514 (remassoc ,stroke ,stroke-map)))))
432 515
436 "Returns the square of the number X" 519 "Returns the square of the number X"
437 (* x x)) 520 (* x x))
438 521
439 (defsubst strokes-distance-squared (p1 p2) 522 (defsubst strokes-distance-squared (p1 p2)
440 "Gets the distance (squared) between to points P1 and P2. 523 "Gets the distance (squared) between to points P1 and P2.
441 Each point is a cons cells (X . Y)" 524 P1 and P2 are cons cells in the form (X . Y)."
442 (let ((x1 (car p1)) 525 (let ((x1 (car p1))
443 (y1 (cdr p1)) 526 (y1 (cdr p1))
444 (x2 (car p2)) 527 (x2 (car p2))
445 (y2 (cdr p2))) 528 (y2 (cdr p2)))
446 (+ (strokes-square (- x2 x1)) 529 (+ (strokes-square (- x2 x1))
447 (strokes-square (- y2 y1))))) 530 (strokes-square (- y2 y1)))))
448 531
449 ;;; Advice for various functions... 532 ;;; Advice for various functions...
450 533
451 ;; I'd originally wanted to write a macro that would just take in the 534 ;; I'd originally wanted to write a macro that would just take in the
452 ;; generic functions which use mouse button2 in various modes. Most of 535 ;; generic functions which use mouse button2 in various modes. Most
453 ;; them are identical in form: they take an event as the single argument 536 ;; of them are identical in form: they take an event as the single
454 ;; and then do their thing. I tried writing a macro that looked 537 ;; argument and then do their thing. I tried writing a macro that
455 ;; something like this, but failed. Advice just ain't that easy. The 538 ;; looked something like this, but failed. Advice just ain't that
456 ;; one that bugged me the most was `Manual-follow-xref', because that had 539 ;; easy. The one that bugged me the most was `Manual-follow-xref',
457 ;; &rest arguments, and I didn't know how to work around it in defadvice. 540 ;; because that had &rest arguments, and I didn't know how to work
458 ;; However, I was able to fix up most of the important modes (i.e. the 541 ;; around it in defadvice. However, I was able to fix up most of the
459 ;; ones I use all the time). One `bug' in the program that I just can't 542 ;; important modes (i.e. the ones I use all the time). One `bug' in
460 ;; seem to figure out is why I can only advise other button2 functions 543 ;; the program that I just can't seem to figure out is why I can only
461 ;; successfully when the variable `strokes-use-strokes-buffer' is nil. I 544 ;; advise other button2 functions successfully when the variable
462 ;; did all the save-excursion/save-window-excursion stuff SPECIFICALLY so 545 ;; `strokes-use-strokes-buffer' is nil. I did all the
463 ;; that using the strokes buffer or not would absolutely not affect any 546 ;; save-excursion/save-window-excursion stuff SPECIFICALLY so that
464 ;; other part of the program. If someone can figure out how to make the 547 ;; using the strokes buffer or not would absolutely not affect any
465 ;; following advices work w/ regardless of that variable 548 ;; other part of the program. If someone can figure out how to make
466 ;; `strokes-use-strokes-buffer', then that would be a great victory. If 549 ;; the following advices work w/ regardless of that variable
467 ;; someone out there would be kind enough to make the commented code 550 ;; `strokes-use-strokes-buffer', then that would be a great victory.
468 ;; below work, I'd be grateful. By the way, I put the `protect' keywords 551 ;; If someone out there would be kind enough to make the commented
469 ;; there to insure that if a stroke went bad, then 552 ;; code below work, I'd be grateful. By the way, I put the `protect'
470 ;; `strokes-click-command' would be set back. If this isn't necessary, 553 ;; keywords there to insure that if a stroke went bad, then
471 ;; then feel free to let me know. 554 ;; `strokes-click-command' would be set back. If this isn't
555 ;; necessary, then feel free to let me know.
472 556
473 ;; For what follows, I really wanted something that would work like this: 557 ;; For what follows, I really wanted something that would work like this:
474 558
475 ;;(strokes-fix-button2 'vm-mouse-button-2) 559 ;;(strokes-fix-button2 'vm-mouse-button-2)
476 560
491 (strokes-fix-button2-command 'vm-mouse-button-2)" 575 (strokes-fix-button2-command 'vm-mouse-button-2)"
492 (let ((command (eval command))) 576 (let ((command (eval command)))
493 `(progn 577 `(progn
494 (defadvice ,command (around strokes-fix-button2 compile preactivate) 578 (defadvice ,command (around strokes-fix-button2 compile preactivate)
495 ,(format "Fix %s to work with strokes." command) 579 ,(format "Fix %s to work with strokes." command)
496 (if strokes-use-strokes-buffer 580 (let ((strokes-click-command
497 ;; then strokes is no good and we'll have to use the original
498 ad-do-it
499 ;; otherwise, we can make strokes work too...
500 (let ((strokes-click-command
501 ',(intern (format "ad-Orig-%s" command)))) 581 ',(intern (format "ad-Orig-%s" command))))
502 (strokes-do-stroke (ad-get-arg 0)))))))) 582 (strokes-do-stroke (ad-get-arg 0)))))))
503 583
504 (strokes-fix-button2-command 'vm-mouse-button-2) 584 (strokes-fix-button2-command 'vm-mouse-button-2)
505 (strokes-fix-button2-command 'rmail-summary-mouse-goto-msg) 585 (strokes-fix-button2-command 'rmail-summary-mouse-goto-msg)
506 (strokes-fix-button2-command 'Buffer-menu-mouse-select) 586 (strokes-fix-button2-command 'Buffer-menu-mouse-select)
507 (strokes-fix-button2-command 'w3-widget-button-click) 587 (strokes-fix-button2-command 'w3-widget-button-click)
544 ;; (strokes-do-stroke (ad-get-arg 0))))) 624 ;; (strokes-do-stroke (ad-get-arg 0)))))
545 625
546 ;;; Functions... 626 ;;; Functions...
547 627
548 (defun strokes-lift-p (object) 628 (defun strokes-lift-p (object)
549 "Return non-nil if object is a stroke-lift" 629 "Return non-nil if object is a stroke-lift."
550 (eq object strokes-lift)) 630 (eq object strokes-lift))
551 631
552 (defun strokes-unset-last-stroke () 632 (defun strokes-unset-last-stroke ()
553 "Undo the last stroke definition." 633 "Undo the last stroke definition."
554 (interactive) 634 (interactive)
571 (interactive 651 (interactive
572 (list 652 (list
573 (and (or strokes-mode (strokes-mode t)) 653 (and (or strokes-mode (strokes-mode t))
574 (strokes-read-complex-stroke 654 (strokes-read-complex-stroke
575 "Define a new stroke. Draw with button1 (or 2). End with button3...")) 655 "Define a new stroke. Draw with button1 (or 2). End with button3..."))
576 (read-command "command to map stroke to: "))) 656 (read-command-or-command-sexp "command to map stroke to: ")))
577 (strokes-define-stroke strokes-global-map stroke command)) 657 (strokes-define-stroke strokes-global-map stroke command))
578 658
579 ;;;###autoload 659 ;;;###autoload
580 (defalias 'global-set-stroke 'strokes-global-set-stroke) 660 (defalias 'global-set-stroke 'strokes-global-set-stroke)
581 661
588 ;; (strokes-read-stroke "Enter the stroke you want to delete..."))) 668 ;; (strokes-read-stroke "Enter the stroke you want to delete...")))
589 ;; (strokes-define-stroke 'strokes-global-map stroke command)) 669 ;; (strokes-define-stroke 'strokes-global-map stroke command))
590 670
591 (defun strokes-get-grid-position (stroke-extent position &optional grid-resolution) 671 (defun strokes-get-grid-position (stroke-extent position &optional grid-resolution)
592 "Map POSITION to a new grid position based on its STROKE-EXTENT and GRID-RESOLUTION. 672 "Map POSITION to a new grid position based on its STROKE-EXTENT and GRID-RESOLUTION.
593 STROKE-EXTENT as a list \(\(xmin . ymin\) \(xmax . ymax\)\). 673 STROKE-EXTENT as a list \(\(XMIN . YMIN\) \(XMAX . YMAX\)\).
594 If POSITION is a `strokes-lift', then it is itself returned. 674 If POSITION is a `strokes-lift', then it is itself returned.
595 Optional GRID-RESOLUTION may be used in place of STROKES-GRID-RESOLUTION. 675 Optional GRID-RESOLUTION may be used in place of STROKES-GRID-RESOLUTION.
596 The grid is a square whose dimesion is [0,GRID-RESOLUTION)." 676 The grid is a square whose dimesion is [0,GRID-RESOLUTION)."
597 (cond ((consp position) ; actual pixel location 677 (cond ((consp position) ; actual pixel location
598 (let ((grid-resolution (or grid-resolution strokes-grid-resolution)) 678 (let ((grid-resolution (or grid-resolution strokes-grid-resolution))
611 (/ (float (- y ymin)) 691 (/ (float (- y ymin))
612 (- ymax ymin))))))) 692 (- ymax ymin)))))))
613 ((strokes-lift-p position) ; stroke lift 693 ((strokes-lift-p position) ; stroke lift
614 strokes-lift))) 694 strokes-lift)))
615 695
616 ;;(defun strokes-get-grid-position (stroke-extent pix-pos)
617 ;; "Return the stroke-grid position for PIX-POS given the total STROKE-EXTENT.
618 ;;STROKE-EXTENT as a list \(\(xmin . ymin\) \(xmax . ymax\)\) and a particular
619 ;;pixel position or `strokes-lift', find the corresponding grid position
620 ;;\(based on `strokes-grid-resolution'\) for the PIX-POS."
621 ;; (cond ((consp pix-pos) ; actual pixel location
622 ;; (let ((x (car pix-pos))
623 ;; (y (cdr pix-pos))
624 ;; (xmin (caar stroke-extent))
625 ;; (ymin (cdar stroke-extent))
626 ;; ;; the `1+' is there to insure that the
627 ;; ;; formula evaluates correctly at the boundaries
628 ;; (xmax (1+ (caadr stroke-extent)))
629 ;; (ymax (1+ (cdadr stroke-extent))))
630 ;; (cons (floor (* strokes-grid-resolution
631 ;; (/ (float (- x xmin))
632 ;; (- xmax xmin))))
633 ;; (floor (* strokes-grid-resolution
634 ;; (/ (float (- y ymin))
635 ;; (- ymax ymin)))))))
636 ;; ((strokes-lift-p pix-pos) ; stroke lift
637 ;; strokes-lift)))
638
639 (defun strokes-get-stroke-extent (pixel-positions) 696 (defun strokes-get-stroke-extent (pixel-positions)
640 "From a list of absolute PIXEL-POSITIONS, returns absolute spatial extent. 697 "From a list of absolute PIXEL-POSITIONS, returns absolute spatial extent.
641 The return value is a list ((xmin . ymin) (xmax . ymax))." 698 The return value is a list ((XMIN . YMIN) (XMAX . YMAX))."
642 (if pixel-positions 699 (if pixel-positions
643 (let ((xmin (caar pixel-positions)) 700 (let ((xmin (caar pixel-positions))
644 (xmax (caar pixel-positions)) 701 (xmax (caar pixel-positions))
645 (ymin (cdar pixel-positions)) 702 (ymin (cdar pixel-positions))
646 (ymax (cdar pixel-positions)) 703 (ymax (cdar pixel-positions))
711 (let ((stroke-extent (strokes-get-stroke-extent positions))) 768 (let ((stroke-extent (strokes-get-stroke-extent positions)))
712 (mapcar (function 769 (mapcar (function
713 (lambda (pos) 770 (lambda (pos)
714 (strokes-get-grid-position stroke-extent pos grid-resolution))) 771 (strokes-get-grid-position stroke-extent pos grid-resolution)))
715 positions))) 772 positions)))
716
717 ;;(defun strokes-normalize-pixels-to-grid (pixel-positions)
718 ;; "Map PIXEL-POSITIONS to the stroke grid.
719 ;;PIXEL-POSITIONS is a list of pixel-positions and stroke-lifts. The
720 ;;normalized stroke grid is defined by the variable STROKES-GRID-RESOLUTION"
721 ;; (let ((stroke-extent (strokes-get-stroke-extent pixel-positions)))
722 ;; (mapcar (function
723 ;; (lambda (pix-pos)
724 ;; (strokes-get-grid-position stroke-extent pix-pos)))
725 ;; pixel-positions)))
726 773
727 (defun strokes-fill-stroke (unfilled-stroke &optional force) 774 (defun strokes-fill-stroke (unfilled-stroke &optional force)
728 "Fill in missing grid locations in the list of UNFILLED-STROKE. 775 "Fill in missing grid locations in the list of UNFILLED-STROKE.
729 If FORCE is non-nil, then fill the stroke even if it's `stroke-click'. 776 If FORCE is non-nil, then fill the stroke even if it's `stroke-click'.
730 NOTE: This is where the global variable `strokes-last-stroke' is set." 777 NOTE: This is where the global variable `strokes-last-stroke' is set."
873 "Read a simple stroke (interactively) and return the stroke. 920 "Read a simple stroke (interactively) and return the stroke.
874 Optional PROMPT in minibuffer displays before and during stroke reading. 921 Optional PROMPT in minibuffer displays before and during stroke reading.
875 This function will display the stroke interactively as it is being 922 This function will display the stroke interactively as it is being
876 entered in the strokes buffer if the variable 923 entered in the strokes buffer if the variable
877 `strokes-use-strokes-buffer' is non-nil. 924 `strokes-use-strokes-buffer' is non-nil.
878 Optional EVENT is currently not used, but hopefully will be soon." 925 Optional EVENT is acceptable as the starting event of the stroke"
879 (save-excursion 926 (save-excursion
880 (let ((pix-locs nil) 927 (let ((pix-locs nil)
881 (grid-locs nil) 928 (grid-locs nil)
882 (event (or event (make-event)))) 929 (safe-to-draw-p nil))
883 (if strokes-use-strokes-buffer 930 (strokes-while-inhibiting-garbage-collector
884 ;; switch to the strokes buffer and 931 (if strokes-use-strokes-buffer
885 ;; display the stroke as it's being read 932 ;; switch to the strokes buffer and
886 (save-window-excursion 933 ;; display the stroke as it's being read
887 (set-window-configuration strokes-window-configuration) 934 (save-window-excursion
888 (if prompt 935 (set-window-configuration strokes-window-configuration)
889 (progn 936 (when prompt
890 (setq event (next-event event prompt)) 937 (setq event (next-command-event event prompt))
891 (while (not (button-press-event-p event)) 938 (or (button-press-event-p event)
892 (dispatch-event event) 939 (error "You must draw with the mouse")))
893 (setq event (next-event event))))) 940 (or event (setq event (next-event nil prompt)
894 (unwind-protect 941 safe-to-draw-p t))
895 (progn 942 (unwind-protect
896 (setq event (next-event event)) 943 (progn
897 (while (not (button-release-event-p event)) 944 (while (not (button-release-event-p event))
898 (if (mouse-event-p event) 945 (if (mouse-event-p event)
899 (let ((point (event-closest-point event))) 946 (let ((point (event-closest-point event)))
900 (when point 947 (if (and point safe-to-draw-p)
901 (goto-char point) 948 ;; we can draw that point
902 (subst-char-in-region point (1+ point) ?\ strokes-character)) 949 (progn
903 (push (cons (event-x-pixel event) 950 (goto-char point)
904 (event-y-pixel event)) 951 (subst-char-in-region point (1+ point) ?\ strokes-character))
905 pix-locs))) 952 ;; otherwise, we can start drawing the next time...
906 (setq event (next-event event)))) 953 (setq safe-to-draw-p t))
907 ;; protected 954 (push (cons (event-x-pixel event)
908 ;; clean up strokes buffer and then bury it. 955 (event-y-pixel event))
909 (when (equal (buffer-name) strokes-buffer-name) 956 pix-locs))
910 (subst-char-in-region (point-min) (point-max) strokes-character ?\ ) 957 ;; otherwise, if it's not a mouse-event...
911 (goto-char (point-min)) 958 (dispatch-event event))
912 (bury-buffer)))) 959 (setq event (next-event event))))
913 ;; Otherwise, don't use strokes buffer and read stroke silently 960 ;; protected
914 (if prompt 961 ;; clean up strokes buffer and then bury it.
915 (progn 962 (when (equal (buffer-name) strokes-buffer-name)
916 (setq event (next-event event prompt)) 963 (subst-char-in-region (point-min) (point-max) strokes-character ?\ )
917 (while (not (button-press-event-p event)) 964 (goto-char (point-min))
918 (dispatch-event event) 965 (bury-buffer))))
919 (setq event (next-event event))))) 966 ;; Otherwise, don't use strokes buffer and read stroke silently
920 (setq event (next-event)) 967 (when prompt
921 (while (not (button-release-event-p event)) 968 (setq event (next-command-event event prompt))
922 (if (mouse-event-p event) 969 (or (button-press-event-p event)
923 (push (cons (event-x-pixel event) 970 (error "You must draw with the mouse")))
924 (event-y-pixel event)) 971 (or event (setq event (next-event nil prompt)))
925 pix-locs)) 972 (while (not (button-release-event-p event))
926 (setq event (next-event event)))) 973 (if (mouse-event-p event)
974 (push (cons (event-x-pixel event)
975 (event-y-pixel event))
976 pix-locs)
977 (dispatch-event event))
978 (setq event (next-event event)))))
927 (setq grid-locs (strokes-renormalize-to-grid (nreverse pix-locs))) 979 (setq grid-locs (strokes-renormalize-to-grid (nreverse pix-locs)))
928 (strokes-fill-stroke (strokes-eliminate-consecutive-redundancies grid-locs))))) 980 (strokes-fill-stroke (strokes-eliminate-consecutive-redundancies grid-locs)))))
929 981
930 ;;;###autoload 982 ;;; This version of `strokes-read-stroke' is not broken, but pathetic.
983 ;;(defun strokes-read-stroke (&optional prompt event)
984 ;; "Read a simple stroke (interactively) and return the stroke.
985 ;;Optional PROMPT in minibuffer displays before and during stroke reading.
986 ;;This function will display the stroke interactively as it is being
987 ;;entered in the strokes buffer if the variable
988 ;;`strokes-use-strokes-buffer' is non-nil.
989 ;;Optional EVENT is currently not used, but hopefully will be soon."
990 ;; (save-excursion
991 ;; (strokes-while-inhibiting-garbage-collector
992 ;; (let ((pix-locs nil)
993 ;; (grid-locs nil)
994 ;; (event (or event (make-event))))
995 ;; (if strokes-use-strokes-buffer
996 ;; ;; switch to the strokes buffer and
997 ;; ;; display the stroke as it's being read
998 ;; (save-window-excursion
999 ;; (set-window-configuration strokes-window-configuration)
1000 ;; (if prompt
1001 ;; (progn
1002 ;; (setq event (next-event event prompt))
1003 ;; (while (not (button-press-event-p event))
1004 ;; (dispatch-event event)
1005 ;; (setq event (next-event event)))))
1006 ;; (unwind-protect
1007 ;; (progn
1008 ;; (setq event (next-event event))
1009 ;; (while (not (button-release-event-p event))
1010 ;; (if (mouse-event-p event)
1011 ;; (let ((point (event-closest-point event)))
1012 ;; (when point
1013 ;; (goto-char point)
1014 ;; (subst-char-in-region point (1+ point) ?\ strokes-character))
1015 ;; (push (cons (event-x-pixel event)
1016 ;; (event-y-pixel event))
1017 ;; pix-locs)))
1018 ;; (setq event (next-event event))))
1019 ;; ;; protected
1020 ;; ;; clean up strokes buffer and then bury it.
1021 ;; (when (equal (buffer-name) strokes-buffer-name)
1022 ;; (subst-char-in-region (point-min) (point-max) strokes-character ?\ )
1023 ;; (goto-char (point-min))
1024 ;; (bury-buffer))))
1025 ;; ;; Otherwise, don't use strokes buffer and read stroke silently
1026 ;; (if prompt
1027 ;; (progn
1028 ;; (setq event (next-event event prompt))
1029 ;; (while (not (button-press-event-p event))
1030 ;; (dispatch-event event)
1031 ;; (setq event (next-event event)))))
1032 ;; (setq event (next-event))
1033 ;; (while (not (button-release-event-p event))
1034 ;; (if (mouse-event-p event)
1035 ;; (push (cons (event-x-pixel event)
1036 ;; (event-y-pixel event))
1037 ;; pix-locs))
1038 ;; (setq event (next-event event))))
1039 ;; (setq grid-locs (strokes-renormalize-to-grid (nreverse pix-locs)))
1040 ;; (strokes-fill-stroke (strokes-eliminate-consecutive-redundancies grid-locs))))))
1041
931 (defun strokes-read-complex-stroke (&optional prompt event) 1042 (defun strokes-read-complex-stroke (&optional prompt event)
932 "Read a complex stroke (interactively) and return the stroke. 1043 "Read a complex stroke (interactively) and return the stroke.
933 Optional PROMPT in minibuffer displays before and during stroke reading. 1044 Optional PROMPT in minibuffer displays before and during stroke reading.
934 Note that a complex stroke allows the user to pen-up and pen-down. This 1045 Note that a complex stroke allows the user to pen-up and pen-down. This
935 is implemented by allowing the user to paint with button1 or button2 and 1046 is implemented by allowing the user to paint with button1 or button2 and
936 then complete the stroke with button3. 1047 then complete the stroke with button3.
937 Optional EVENT is currently not used, but hopefully will be soon." 1048 Optional EVENT is acceptable as the starting event of the stroke"
938 (save-excursion 1049 (save-excursion
939 (save-window-excursion 1050 (save-window-excursion
940 (set-window-configuration strokes-window-configuration) 1051 (strokes-while-inhibiting-garbage-collector
941 (let ((pix-locs nil) 1052 (set-window-configuration strokes-window-configuration)
942 (grid-locs nil) 1053 (let ((pix-locs nil)
943 (event (or event (next-event nil prompt)))) 1054 (grid-locs nil)
944 (if prompt 1055 (safe-to-draw-p nil))
945 (while (not (button-press-event-p event)) 1056 (when prompt
946 (dispatch-event event) 1057 (setq event (next-command-event event prompt))
947 (setq event (next-event event)))) 1058 (or (button-press-event-p event)
948 (unwind-protect 1059 (error "You must draw with the mouse")))
949 (progn 1060 (or event (setq event (next-event nil prompt)
950 (setq event (next-event event prompt)) 1061 safe-to-draw-p t))
951 (while (not (and (button-press-event-p event) 1062 (unwind-protect
952 (eq (event-button event) 3))) 1063 (progn
953 (while (not (button-release-event-p event)) 1064 (while (not (and (button-press-event-p event)
954 (if (mouse-event-p event) 1065 (eq (event-button event) 3)))
955 (let ((point (event-closest-point event))) 1066 (while (not (button-release-event-p event))
956 (when point 1067 (if (mouse-event-p event)
957 (goto-char point) 1068 (let ((point (event-closest-point event)))
958 (subst-char-in-region point (1+ point) ?\ strokes-character)) 1069 (if (and point safe-to-draw-p)
959 (push (cons (event-x-pixel event) 1070 ;; we can draw that point
960 (event-y-pixel event)) 1071 (progn
961 pix-locs))) 1072 (goto-char point)
962 (setq event (next-event event prompt))) 1073 (subst-char-in-region point (1+ point) ?\ strokes-character))
963 (push strokes-lift pix-locs) 1074 ;; otherwise, we can start drawing the next time...
964 (while (not (button-press-event-p event)) 1075 (setq safe-to-draw-p t))
965 (dispatch-event event) 1076 (push (cons (event-x-pixel event)
966 (setq event (next-event event prompt)))) 1077 (event-y-pixel event))
967 (setq pix-locs (nreverse (cdr pix-locs)) 1078 pix-locs))
968 grid-locs (strokes-renormalize-to-grid pix-locs)) 1079 (dispatch-event event))
969 (strokes-fill-stroke 1080 (setq event (next-event event prompt)))
970 (strokes-eliminate-consecutive-redundancies grid-locs))) 1081 (push strokes-lift pix-locs)
971 ;; protected 1082 (while (not (button-press-event-p event))
972 (when (equal (buffer-name) strokes-buffer-name) 1083 (dispatch-event event)
973 (subst-char-in-region (point-min) (point-max) strokes-character ?\ ) 1084 (setq event (next-event event prompt))))
974 (goto-char (point-min)) 1085 (setq pix-locs (nreverse (cdr pix-locs)))
975 (bury-buffer))))))) 1086 ;; minor bug fix here for when user enters ` *strokes*'
1087 ;; buffer with a click instead of a drag...
1088 (when (strokes-lift-p (car pix-locs))
1089 (setq pix-locs (cdr pix-locs)))
1090 (setq grid-locs (strokes-renormalize-to-grid pix-locs))
1091 (strokes-fill-stroke
1092 (strokes-eliminate-consecutive-redundancies grid-locs)))
1093 ;; protected
1094 (when (equal (buffer-name) strokes-buffer-name)
1095 (subst-char-in-region (point-min) (point-max) strokes-character ?\ )
1096 (goto-char (point-min))
1097 (bury-buffer))))))))
976 1098
977 (defun strokes-execute-stroke (stroke) 1099 (defun strokes-execute-stroke (stroke)
978 "Given STROKE, execute the command which corresponds to it. 1100 "Given STROKE, execute the command which corresponds to it.
979 The command will be executed provided one exists for that stroke, 1101 The command will be executed provided one exists for that stroke,
980 based on the variable `strokes-minimum-match-score'. 1102 based on the variable `strokes-minimum-match-score'.
981 If no stroke matches, nothing is done and return value is nil." 1103 If no stroke matches, nothing is done and return value is nil."
982 (let* ((match (strokes-match-stroke stroke strokes-global-map)) 1104 (let* ((match (strokes-match-stroke stroke strokes-global-map))
983 (command (car match)) 1105 (command (car match))
984 (score (cdr match))) 1106 (score (cdr match)))
985 (cond ((strokes-click-p stroke) 1107 (cond ((strokes-click-p stroke)
986 ;; This is the case of a `click' type event 1108 ;; This is the case of a `click' type event.
1109 ;; The `sit-for' is a minor frob that has to do with timing
1110 ;; problems. Without the `sit-for', mouse-yank will not
1111 ;; yank at the proper location if the user opted for
1112 ;; mouse-yank-at-point to be nil (i.e. mouse-yank takes
1113 ;; place at pointer position). The sit-for tells redisplay
1114 ;; to be sure to wait for the `*strokes*' buffer to vanish
1115 ;; from consideration when deciding on a point to be used
1116 ;; for mouse-yank.
1117 (sit-for 0)
987 (command-execute strokes-click-command)) 1118 (command-execute strokes-click-command))
988 ((and match (<= score strokes-minimum-match-score)) 1119 ((and match (<= score strokes-minimum-match-score))
989 (message "%s" command) 1120 (message "%s" command)
990 (command-execute command)) 1121 (command-execute command))
991 ((null strokes-global-map) 1122 ((null strokes-global-map)
1000 "No stroke matches; see variable `strokes-minimum-match-score'") 1131 "No stroke matches; see variable `strokes-minimum-match-score'")
1001 nil)))) 1132 nil))))
1002 1133
1003 ;;;###autoload 1134 ;;;###autoload
1004 (defun strokes-do-stroke (event) 1135 (defun strokes-do-stroke (event)
1005 "Read a simple stroke from the user and then exectute its comand. 1136 "Read a simple stroke from the user and then exectute its command.
1006 This must be bound to a mouse event." 1137 This must be bound to a mouse event."
1007 (interactive "e") 1138 (interactive "e")
1008 (or strokes-mode (strokes-mode t)) 1139 (or strokes-mode (strokes-mode t))
1009 (strokes-execute-stroke (strokes-read-stroke nil event))) 1140 (strokes-execute-stroke (strokes-read-stroke nil event)))
1010 1141
1048 (lambda () 1179 (lambda ()
1049 (save-excursion 1180 (save-excursion
1050 (let ((helpdoc 1181 (let ((helpdoc
1051 "This is help for the strokes package. 1182 "This is help for the strokes package.
1052 1183
1053 If you find something wrong with it, or feel that it can be improved 1184 If you find something wrong with strokes, or feel that it can be
1054 in some way, then please feel free to email me: 1185 improved in some way, then please feel free to email me:
1055 1186
1056 David Bakhash <cadet@mit.edu> 1187 David Bakhash <cadet@mit.edu>
1057 1188
1058 or just do 1189 or just do
1059 1190
1060 M-x strokes-report-bug 1191 M-x strokes-report-bug
1061 1192
1062 ------------------------------------------------------------ 1193 ------------------------------------------------------------
1194
1195 ** Strokes...
1063 1196
1064 The strokes package allows you to define strokes (that you make with 1197 The strokes package allows you to define strokes (that you make with
1065 the mouse or other pointer device) that XEmacs can interpret as 1198 the mouse or other pointer device) that XEmacs can interpret as
1066 corresponding to commands, and then executes the commands. It does 1199 corresponding to commands, and then executes the commands. It does
1067 character recognition, so you don't have to worry about getting it 1200 character recognition, so you don't have to worry about getting it
1068 right every time. 1201 right every time.
1069 1202
1203 Strokes also allows you to compose documents graphically. You can
1204 fully edit documents in Chinese, Japanese, etc. based on XEmacs
1205 strokes. Once you've done so, you can ascii compress-and-encode them
1206 and then safely save them for later use, send letters to friends
1207 (using XEmacs, of course). Strokes will later decode these documents,
1208 extracting the strokes for editing use once again, so the editing
1209 cycle can continue.
1210
1070 Strokes are easy to program and fun to use. To start strokes going, 1211 Strokes are easy to program and fun to use. To start strokes going,
1071 you'll want to put the following line in your .emacs file: 1212 you'll want to put the following line in your .emacs file:
1072 1213
1073 (and (fboundp 'device-on-window-system-p) 1214 (if window-system
1074 (device-on-window-system-p) 1215 (require 'strokes))
1075 (require 'strokes))
1076 1216
1077 This will load strokes when and only when you start XEmacs on a window 1217 This will load strokes when and only when you start XEmacs on a window
1078 system (i.e. that has a pointer (mouse) device, etc.). 1218 system (i.e. that has a pointer (mouse) device, etc.).
1079 1219
1080 To toggle strokes-mode, you just do 1220 To toggle strokes-mode, you just do
1081 1221
1082 > M-x strokes-mode 1222 > M-x strokes-mode
1223
1224 ** Strokes for controlling the behavior of XEmacs...
1083 1225
1084 When you're ready to start defining strokes, just use the command 1226 When you're ready to start defining strokes, just use the command
1085 1227
1086 > M-x global-set-stroke 1228 > M-x global-set-stroke
1087 1229
1146 Your strokes get loaded automatically when you enable `strokes-mode'. 1288 Your strokes get loaded automatically when you enable `strokes-mode'.
1147 You can also load in your user-defined strokes with 1289 You can also load in your user-defined strokes with
1148 1290
1149 > M-x load-user-strokes 1291 > M-x load-user-strokes
1150 1292
1151 A few more important things: 1293 ** Strokes for pictographic editing...
1152 1294
1153 o The command `strokes-do-stroke' is also invoked with C-button2, so that you 1295 If you'd like to create graphical files with strokes, you'll have to
1154 can still enter a stroke in modes which use button2 for other things, 1296 be running XEmacs on a window system, with XPM support. You use the
1155 such as cross-referencing. 1297 binding C-button2 to start drawing your strokes. These are just
1156 1298 complex strokes, and thus you continue drawing with buttons 1 or 2 and
1157 o Complex strokes (i.e. `strokes-do-complex-stroke'), by default, use 1299 end with button-3. Then the stroke glyph gets inserted into the
1158 Sh-button2. 1300 buffer. You treat it like any other character, which you can copy,
1301 paste, delete, move, etc. The command which is bound to C-button2 is
1302 called `strokes-compose-complex-stroke'. When all is done, you may
1303 want to send the file, or save it. This is done with
1304
1305 > M-x strokes-encode-buffer
1306
1307 Likewise, to decode the strokes from a strokes-encoded buffer you do
1308
1309 > M-x strokes-decode-buffer
1310
1311 ** A few more important things...
1312
1313 o The command `strokes-do-complex-stroke' is invoked with M-button2, so that you
1314 can execute complex strokes (i.e. with more than one lift) if preferred.
1159 1315
1160 o Strokes are a bit computer-dependent in that they depend somewhat on 1316 o Strokes are a bit computer-dependent in that they depend somewhat on
1161 the speed of the computer you're working on. This means that you 1317 the speed of the computer you're working on. This means that you
1162 may have to tweak some variables. You can read about them in the 1318 may have to tweak some variables. You can read about them in the
1163 commentary of `strokes.el'. Better to just use apropos and read their 1319 commentary of `strokes.el'. Better to just use apropos and read their
1165 variable which many people wanted to see was 1321 variable which many people wanted to see was
1166 `strokes-use-strokes-buffer' which allows the user to use strokes 1322 `strokes-use-strokes-buffer' which allows the user to use strokes
1167 silently--without displaying the strokes. All variables can be set 1323 silently--without displaying the strokes. All variables can be set
1168 by customizing the group named `strokes' via the customization package: 1324 by customizing the group named `strokes' via the customization package:
1169 1325
1170 > M-x customize 1326 > M-x customize"))
1171
1172 o A problem with strokes happens when you resize windows. If you
1173 enlarge your XEmacs window a lot and realize that your strokes
1174 buffer is not big enough, you may need to fix it with
1175
1176 > M-x strokes-update-window-configuration."))
1177 (princ helpdoc standard-output))))))) 1327 (princ helpdoc standard-output)))))))
1178 1328
1179 (defun strokes-report-bug () 1329 (defun strokes-report-bug ()
1180 "Submit a bug report for strokes." 1330 "Submit a bug report for strokes."
1181 (interactive) 1331 (interactive)
1206 (goto-char (match-end 0)) 1356 (goto-char (match-end 0))
1207 (delete-char -1) 1357 (delete-char -1)
1208 (insert " " strokes-version " bug:"))))))))) 1358 (insert " " strokes-version " bug:")))))))))
1209 1359
1210 (defsubst strokes-fill-current-buffer-with-whitespace () 1360 (defsubst strokes-fill-current-buffer-with-whitespace ()
1211 "Erase the contents of the current buffer and fill it with whitespace" 1361 "Erase the contents of the current buffer and fill it with whitespace."
1212 (erase-buffer) 1362 (erase-buffer)
1213 (loop repeat (frame-height) do 1363 (loop repeat (frame-height) do
1214 (insert-char ?\ (1- (frame-width))) 1364 (insert-char ?\ (1- (frame-width)))
1215 (newline)) 1365 (newline))
1216 (goto-char (point-min))) 1366 (goto-char (point-min)))
1217 1367
1368 (defun strokes-window-configuration-changed-p ()
1369 "Non-nil if the `strokes-window-configuration' frame properties changed.
1370 This is based on the last time the `strokes-window-configuration was updated."
1371 (not (and (eq (selected-frame)
1372 (plist-get strokes-window-configuration-plist
1373 'frame))
1374 (eq (frame-height)
1375 (plist-get strokes-window-configuration-plist
1376 'frame-height))
1377 (eq (frame-width)
1378 (plist-get strokes-window-configuration-plist
1379 'frame-width)))))
1380
1381 (defun strokes-update-window-configuration-plist ()
1382 "Update the `strokes-window-configuration-plist' based on the current state."
1383 (plist-put strokes-window-configuration-plist
1384 'frame
1385 (selected-frame))
1386 (plist-put strokes-window-configuration-plist
1387 'frame-height
1388 (frame-height))
1389 (plist-put strokes-window-configuration-plist
1390 'frame-width
1391 (frame-width)))
1392
1218 (defun strokes-update-window-configuration () 1393 (defun strokes-update-window-configuration ()
1219 "Insure that `strokes-window-configuration' is up-to-date." 1394 "Update the `strokes-window-configuration'."
1220 (interactive) 1395 (interactive)
1221 (let ((current-window (selected-window))) 1396 (let ((current-window (selected-window)))
1222 (cond ((or (window-minibuffer-p current-window) 1397 (cond ((or (window-minibuffer-p current-window)
1223 (window-dedicated-p current-window)) 1398 (window-dedicated-p current-window))
1224 ;; don't try to update strokes window configuration 1399 ;; don't try to update strokes window configuration
1240 (abbrev-mode 0) 1415 (abbrev-mode 0)
1241 (buffer-disable-undo (current-buffer)) 1416 (buffer-disable-undo (current-buffer))
1242 (setq truncate-lines nil) 1417 (setq truncate-lines nil)
1243 (strokes-fill-current-buffer-with-whitespace) 1418 (strokes-fill-current-buffer-with-whitespace)
1244 (setq strokes-window-configuration (current-window-configuration)) 1419 (setq strokes-window-configuration (current-window-configuration))
1420 (strokes-update-window-configuration-plist)
1245 (bury-buffer)))) 1421 (bury-buffer))))
1246 (t ; `strokes buffer' still exists... 1422 ((strokes-window-configuration-changed-p) ; simple update
1247 ;; update the strokes-window-configuration for this specific frame... 1423 ;; update the strokes-window-configuration for this
1424 ;; specific frame...
1248 (save-excursion 1425 (save-excursion
1249 (save-window-excursion 1426 (save-window-excursion
1250 (set-window-buffer current-window strokes-buffer-name) 1427 (set-window-buffer current-window strokes-buffer-name)
1251 (delete-other-windows) 1428 (delete-other-windows)
1252 (strokes-fill-current-buffer-with-whitespace) 1429 (strokes-fill-current-buffer-with-whitespace)
1253 (setq strokes-window-configuration (current-window-configuration)) 1430 (setq strokes-window-configuration (current-window-configuration))
1431 (strokes-update-window-configuration-plist)
1254 (bury-buffer))))))) 1432 (bury-buffer)))))))
1255 1433
1256 ;;;###autoload 1434 ;;;###autoload
1257 (defun strokes-load-user-strokes () 1435 (defun strokes-load-user-strokes ()
1258 "Load user-defined strokes from file named by `strokes-file'." 1436 "Load user-defined strokes from file named by `strokes-file'."
1378 (pop-to-buffer "*strokes-xpm*") 1556 (pop-to-buffer "*strokes-xpm*")
1379 ;; (xpm-mode 1) 1557 ;; (xpm-mode 1)
1380 (xpm-show-image) 1558 (xpm-show-image)
1381 (goto-char (point-min)))))) 1559 (goto-char (point-min))))))
1382 1560
1383 ;;; Strokes Edit stuff... 1561 ;;; Strokes Edit stuff... ### NOT IMLEMENTED YET ###
1384 1562
1385 (defun strokes-edit-quit () 1563 ;;(defun strokes-edit-quit ()
1386 (interactive) 1564 ;; (interactive)
1387 (or (one-window-p t 0) 1565 ;; (or (one-window-p t 0)
1388 (delete-window)) 1566 ;; (delete-window))
1389 (kill-buffer "*Strokes List*")) 1567 ;; (kill-buffer "*Strokes List*"))
1390 1568
1391 (define-derived-mode edit-strokes-mode list-mode 1569 ;;(define-derived-mode edit-strokes-mode list-mode
1392 "Edit-Strokes" 1570 ;; "Edit-Strokes"
1393 "Major mode for `edit-strokes' and `list-strokes' buffers. 1571 ;; "Major mode for `edit-strokes' and `list-strokes' buffers.
1394 1572
1395 Editing commands: 1573 ;;Editing commands:
1396 1574
1397 \\{edit-strokes-mode-map}" 1575 ;;\\{edit-strokes-mode-map}"
1398 (setq truncate-lines nil 1576 ;; (setq truncate-lines nil
1399 auto-show-mode nil ; don't want problems here either 1577 ;; auto-show-mode nil ; don't want problems here either
1400 mode-popup-menu edit-strokes-menu) ; what about extent-specific stuff? 1578 ;; mode-popup-menu edit-strokes-menu) ; what about extent-specific stuff?
1401 (and (featurep 'menubar) 1579 ;; (and (featurep 'menubar)
1402 current-menubar 1580 ;; current-menubar
1403 (set (make-local-variable 'current-menubar) 1581 ;; (set (make-local-variable 'current-menubar)
1404 (copy-sequence current-menubar)) 1582 ;; (copy-sequence current-menubar))
1405 (add-submenu nil edit-strokes-menu))) 1583 ;; (add-submenu nil edit-strokes-menu)))
1406 1584
1407 (let ((map edit-strokes-mode-map)) 1585 ;;(let ((map edit-strokes-mode-map))
1408 (define-key map "<" 'beginning-of-buffer) 1586 ;; (define-key map "<" 'beginning-of-buffer)
1409 (define-key map ">" 'end-of-buffer) 1587 ;; (define-key map ">" 'end-of-buffer)
1410 ;; (define-key map "c" 'strokes-copy-other-face) 1588 ;; ;; (define-key map "c" 'strokes-copy-other-face)
1411 ;; (define-key map "C" 'strokes-copy-this-face) 1589 ;; ;; (define-key map "C" 'strokes-copy-this-face)
1412 ;; (define-key map "s" 'strokes-smaller) 1590 ;; ;; (define-key map "s" 'strokes-smaller)
1413 ;; (define-key map "l" 'strokes-larger) 1591 ;; ;; (define-key map "l" 'strokes-larger)
1414 ;; (define-key map "b" 'strokes-bold) 1592 ;; ;; (define-key map "b" 'strokes-bold)
1415 ;; (define-key map "i" 'strokes-italic) 1593 ;; ;; (define-key map "i" 'strokes-italic)
1416 (define-key map "e" 'strokes-list-edit) 1594 ;; (define-key map "e" 'strokes-list-edit)
1417 ;; (define-key map "f" 'strokes-font) 1595 ;; ;; (define-key map "f" 'strokes-font)
1418 ;; (define-key map "u" 'strokes-underline) 1596 ;; ;; (define-key map "u" 'strokes-underline)
1419 ;; (define-key map "t" 'strokes-truefont) 1597 ;; ;; (define-key map "t" 'strokes-truefont)
1420 ;; (define-key map "F" 'strokes-foreground) 1598 ;; ;; (define-key map "F" 'strokes-foreground)
1421 ;; (define-key map "B" 'strokes-background) 1599 ;; ;; (define-key map "B" 'strokes-background)
1422 ;; (define-key map "D" 'strokes-doc-string) 1600 ;; ;; (define-key map "D" 'strokes-doc-string)
1423 (define-key map "a" 'strokes-global-set-stroke) 1601 ;; (define-key map "a" 'strokes-global-set-stroke)
1424 (define-key map "d" 'strokes-list-delete-stroke) 1602 ;; (define-key map "d" 'strokes-list-delete-stroke)
1425 ;; (define-key map "n" 'strokes-list-next) 1603 ;; ;; (define-key map "n" 'strokes-list-next)
1426 ;; (define-key map "p" 'strokes-list-prev) 1604 ;; ;; (define-key map "p" 'strokes-list-prev)
1427 ;; (define-key map " " 'strokes-list-next) 1605 ;; ;; (define-key map " " 'strokes-list-next)
1428 ;; (define-key map "\C-?" 'strokes-list-prev) 1606 ;; ;; (define-key map "\C-?" 'strokes-list-prev)
1429 (define-key map "g" 'strokes-list-strokes) ; refresh display 1607 ;; (define-key map "g" 'strokes-list-strokes) ; refresh display
1430 (define-key map "q" 'strokes-edit-quit) 1608 ;; (define-key map "q" 'strokes-edit-quit)
1431 (define-key map [(control c) (control c)] 'bury-buffer)) 1609 ;; (define-key map [(control c) (control c)] 'bury-buffer))
1432 1610
1433 ;;;###autoload 1611 ;;;;;###autoload
1434 (defun strokes-edit-strokes (&optional chronological strokes-map) 1612 ;;(defun strokes-edit-strokes (&optional chronological strokes-map)
1435 ;; ### DEAL WITH THE 2nd ARGUMENT ISSUE! ### 1613 ;; ;; ### DEAL WITH THE 2nd ARGUMENT ISSUE! ###
1436 "Edit strokes in a pop-up buffer containing strokes and their definitions. 1614 ;; "Edit strokes in a pop-up buffer containing strokes and their definitions.
1437 If STROKES-MAP is not given, `strokes-global-map' will be used instead. 1615 ;;If STROKES-MAP is not given, `strokes-global-map' will be used instead.
1438 1616
1439 Editing commands: 1617 ;;Editing commands:
1440 1618
1441 \\{edit-faces-mode-map}" 1619 ;;\\{edit-faces-mode-map}"
1442 (interactive "P") 1620 ;; (interactive "P")
1443 (pop-to-buffer (get-buffer-create "*Strokes List*")) 1621 ;; (pop-to-buffer (get-buffer-create "*Strokes List*"))
1444 (reset-buffer (current-buffer)) ; handy function from minibuf.el 1622 ;; (reset-buffer (current-buffer)) ; handy function from minibuf.el
1445 (setq strokes-map (or strokes-map 1623 ;; (setq strokes-map (or strokes-map
1446 strokes-global-map 1624 ;; strokes-global-map
1447 (progn 1625 ;; (progn
1448 (strokes-load-user-strokes) 1626 ;; (strokes-load-user-strokes)
1449 strokes-global-map))) 1627 ;; strokes-global-map)))
1450 (or chronological 1628 ;; (or chronological
1451 (setq strokes-map (sort (copy-sequence strokes-map) 1629 ;; (setq strokes-map (sort (copy-sequence strokes-map)
1452 'strokes-alphabetic-lessp))) 1630 ;; 'strokes-alphabetic-lessp)))
1453 ;; (push-window-configuration) 1631 ;; ;; (push-window-configuration)
1454 (insert 1632 ;; (insert
1455 "Command Stroke\n" 1633 ;; "Command Stroke\n"
1456 "------- ------") 1634 ;; "------- ------")
1457 (loop for def in strokes-map 1635 ;; (loop for def in strokes-map
1458 for i from 0 to (1- (length strokes-map)) do 1636 ;; for i from 0 to (1- (length strokes-map)) do
1459 (let ((stroke (car def)) 1637 ;; (let ((stroke (car def))
1460 (command-name (symbol-name (cdr def)))) 1638 ;; (command-name (symbol-name (cdr def))))
1461 (strokes-xpm-for-stroke stroke " *strokes-xpm*") 1639 ;; (strokes-xpm-for-stroke stroke " *strokes-xpm*")
1462 (newline 2) 1640 ;; (newline 2)
1463 (insert-char ?\ 45) 1641 ;; (insert-char ?\ 45)
1464 (beginning-of-line) 1642 ;; (beginning-of-line)
1465 (insert command-name) 1643 ;; (insert command-name)
1466 (beginning-of-line) 1644 ;; (beginning-of-line)
1467 (forward-char 45) 1645 ;; (forward-char 45)
1468 (set (intern (format "strokes-list-annotation-%d" i)) 1646 ;; (set (intern (format "strokes-list-annotation-%d" i))
1469 (make-annotation (make-glyph 1647 ;; (make-annotation (make-glyph
1470 (list 1648 ;; (list
1471 (vector 'xpm 1649 ;; (vector 'xpm
1472 :data (buffer-substring 1650 ;; :data (buffer-substring
1473 (point-min " *strokes-xpm*") 1651 ;; (point-min " *strokes-xpm*")
1474 (point-max " *strokes-xpm*") 1652 ;; (point-max " *strokes-xpm*")
1475 " *strokes-xpm*")) 1653 ;; " *strokes-xpm*"))
1476 [string :data "[Stroke]"])) 1654 ;; [string :data "[Stroke]"]))
1477 (point) 'text)) 1655 ;; (point) 'text))
1478 (set-annotation-data (symbol-value (intern (format "strokes-list-annotation-%d" i))) 1656 ;; (set-annotation-data (symbol-value (intern (format "strokes-list-annotation-%d" i)))
1479 def)) 1657 ;; def))
1480 finally do (kill-region (1+ (point)) (point-max))) 1658 ;; finally do (kill-region (1+ (point)) (point-max)))
1481 (edit-strokes-mode) 1659 ;; (edit-strokes-mode)
1482 (goto-char (point-min))) 1660 ;; (goto-char (point-min)))
1483 1661
1484 ;;;###autoload 1662 ;;;;;###autoload
1485 (defalias 'edit-strokes 'strokes-edit-strokes) 1663 ;;(defalias 'edit-strokes 'strokes-edit-strokes)
1486 1664
1487 ;;;###autoload 1665 ;;;###autoload
1488 (defun strokes-list-strokes (&optional chronological strokes-map) 1666 (defun strokes-list-strokes (&optional chronological strokes-map)
1489 "Pop up a buffer containing an alphabetical listing of strokes in STROKES-MAP. 1667 "Pop up a buffer containing an alphabetical listing of strokes in STROKES-MAP.
1490 With CHRONOLOGICAL prefix arg \(\\[universal-argument]\) list strokes 1668 With CHRONOLOGICAL prefix arg \(\\[universal-argument]\) list strokes
1510 (loop for def in strokes-map do 1688 (loop for def in strokes-map do
1511 (let ((stroke (car def)) 1689 (let ((stroke (car def))
1512 (command-name (symbol-name (cdr def)))) 1690 (command-name (symbol-name (cdr def))))
1513 (strokes-xpm-for-stroke stroke " *strokes-xpm*") 1691 (strokes-xpm-for-stroke stroke " *strokes-xpm*")
1514 (newline 2) 1692 (newline 2)
1515 (insert-char ?\ 45) 1693 (insert-char ?\ 45)
1516 (beginning-of-line) 1694 (beginning-of-line)
1517 (insert command-name) 1695 (insert command-name)
1518 (beginning-of-line) 1696 (beginning-of-line)
1519 (forward-char 45) 1697 (forward-char 45)
1520 (make-annotation (make-glyph 1698 (make-annotation (make-glyph
1552 Note that `strokes-mode' is a global mode. Think of it as a minor 1730 Note that `strokes-mode' is a global mode. Think of it as a minor
1553 mode in all buffers when activated. 1731 mode in all buffers when activated.
1554 By default, strokes are invoked with mouse button-2. You can define 1732 By default, strokes are invoked with mouse button-2. You can define
1555 new strokes with 1733 new strokes with
1556 1734
1557 > M-x global-set-stroke" 1735 > M-x global-set-stroke
1736
1737 To use strokes for pictographic editing, such as Chinese/Japanese, use
1738 Sh-button-2, which draws strokes and inserts them. Encode/decode your
1739 strokes with
1740
1741 > M-x strokes-encode-buffer
1742 > M-x strokes-decode-buffer"
1558 (interactive "P") 1743 (interactive "P")
1559 (let ((on-p (if arg 1744 (let ((on-p (if arg
1560 (> (prefix-numeric-value arg) 0) 1745 (> (prefix-numeric-value arg) 0)
1561 (not strokes-mode)))) 1746 (not strokes-mode))))
1562 (cond ((not (device-on-window-system-p)) 1747 (cond ((not (device-on-window-system-p))
1563 (error "Can't use strokes without windows")) 1748 (error "Can't use strokes without windows"))
1564 (on-p ; turn on strokes 1749 (on-p ; turn on strokes
1565 (and (file-exists-p strokes-file) 1750 (and (file-exists-p strokes-file)
1566 (null strokes-global-map) 1751 (null strokes-global-map)
1567 (strokes-load-user-strokes)) 1752 (strokes-load-user-strokes))
1568 (add-hook 'kill-emacs-hook 1753 (add-hook 'kill-emacs-query-functions
1569 'strokes-prompt-user-save-strokes) 1754 'strokes-prompt-user-save-strokes)
1570 (add-hook 'select-frame-hook 1755 (add-hook 'select-frame-hook
1571 'strokes-update-window-configuration) 1756 'strokes-update-window-configuration)
1572 (strokes-update-window-configuration) 1757 (strokes-update-window-configuration)
1573 (define-key global-map [(button2)] 'strokes-do-stroke) 1758 (define-key global-map [(button2)] 'strokes-do-stroke)
1574 (define-key global-map [(control button2)] 'strokes-do-stroke) 1759 (define-key global-map [(meta button2)] 'strokes-do-complex-stroke)
1575 (define-key global-map [(shift button2)] 1760 ;; (define-key global-map [(control button2)] 'strokes-do-complex-stroke)
1576 'strokes-do-complex-stroke) 1761 (define-key global-map [(control button2)]
1762 'strokes-compose-complex-stroke)
1577 (ad-activate-regexp "^strokes-") ; advise button2 commands 1763 (ad-activate-regexp "^strokes-") ; advise button2 commands
1578 (setq strokes-mode t)) 1764 (setq strokes-mode t))
1579 (t ; turn off strokes 1765 (t ; turn off strokes
1580 (if (get-buffer strokes-buffer-name) 1766 (if (get-buffer strokes-buffer-name)
1581 (kill-buffer (get-buffer strokes-buffer-name))) 1767 (kill-buffer (get-buffer strokes-buffer-name)))
1582 (remove-hook 'select-frame-hook 1768 (remove-hook 'select-frame-hook
1583 'strokes-update-window-configuration) 1769 'strokes-update-window-configuration)
1584 (if (string-match "^strokes-" (symbol-name (key-binding [(button2)]))) 1770 (if (string-match "^strokes-" (symbol-name (key-binding [(button2)])))
1585 (define-key global-map [(button2)] strokes-click-command)) 1771 (define-key global-map [(button2)] strokes-click-command))
1772 (if (string-match "^strokes-" (symbol-name (key-binding [(meta button2)])))
1773 (global-unset-key [(meta button2)]))
1586 (if (string-match "^strokes-" (symbol-name (key-binding [(control button2)]))) 1774 (if (string-match "^strokes-" (symbol-name (key-binding [(control button2)])))
1587 (global-unset-key [(control button2)])) 1775 (global-unset-key [(control button2)]))
1588 (if (string-match "^strokes-" (symbol-name (key-binding [(shift button2)]))) 1776 ;; (if (string-match "^strokes-" (symbol-name (key-binding [(shift button2)])))
1589 (global-unset-key [(shift button2)])) 1777 ;; (global-unset-key [(shift button2)]))
1590 (ad-deactivate-regexp "^strokes-") ; unadvise strokes-button2 commands 1778 (ad-deactivate-regexp "^strokes-") ; unadvise strokes-button2 commands
1591 (setq strokes-mode nil)))) 1779 (setq strokes-mode nil))))
1592 (redraw-modeline)) 1780 (redraw-modeline))
1593 1781
1594 (add-minor-mode 'strokes-mode strokes-modeline-string nil nil 'strokes-mode) 1782 (add-minor-mode 'strokes-mode strokes-modeline-string nil nil 'strokes-mode)
1595 1783
1596 (unless (find-face 'strokes-char-face) 1784 ;;;; strokes-xpm stuff (later may be separate)...
1597 (copy-face 'default 'strokes-char-face) 1785
1598 (set-face-background 'strokes-char-face "lightgray")) 1786 ;; This is the stuff that will eventuall be used for composing letters in
1787 ;; any language, compression, decompression, graphics, editing, etc.
1788
1789 (require 'atomic-extents) ; might as well say
1790 ; (require 'not-so-atomic-extents)
1791 ; but what can you do?
1792
1793 ;;(unless (find-face 'strokes-char-face)
1794 (copy-face 'default 'strokes-char-face)
1795 (set-face-background 'strokes-char-face "lightgray") ; I should really
1796 ; make this a
1797 ; user-option,
1798 ; but I'm too
1799 ; lazy right now.
1800 ; In a few days.
1599 1801
1600 (defconst strokes-char-value-hashtable (make-hashtable 62) ; 1802 (defconst strokes-char-value-hashtable (make-hashtable 62) ;
1601 ; (make-char-table 1803 ; (make-char-table
1602 ; 'syntax) 1804 ; 'syntax)
1603 ; in 20.* 1805 ; in 20.*
1604 ;; ### This will become a char-table for XEmacs-20 !!! ### 1806 ;; ### This will/should become a char-table for XEmacs-20 !!! ###
1605 "The table which stores values for the character keys.") 1807 "The table which stores values for the character keys.")
1606 (puthash ?0 0 strokes-char-value-hashtable) ; (put-char-table ?0 0 1808 (puthash ?0 0 strokes-char-value-hashtable) ; (put-char-table ?0 0
1607 ; strokes-value-chartable) 1809 ; strokes-value-chartable)
1608 ; in 20.* 1810 ; in 20.*
1609 (puthash ?1 1 strokes-char-value-hashtable) 1811 (puthash ?1 1 strokes-char-value-hashtable)
1794 ;; "0" 1996 ;; "0"
1795 (strokes-xpm-encode-length-as-string 0)) 1997 (strokes-xpm-encode-length-as-string 0))
1796 (strokes-xpm-encode-length-as-string count))) 1998 (strokes-xpm-encode-length-as-string count)))
1797 "/")))) 1999 "/"))))
1798 2000
1799 (defun strokes-strokify-buffer (&optional buffer) 2001 ;;;###autoload
2002 (defun strokes-decode-buffer (&optional buffer force)
1800 "Decode stroke strings in BUFFER and display their corresponding glyphs. 2003 "Decode stroke strings in BUFFER and display their corresponding glyphs.
1801 BUFFER defaults to the current buffer." 2004 Optional BUFFER defaults to the current buffer.
2005 Optional FORCE non-nil will ignore the buffer's read-only status."
1802 (interactive) 2006 (interactive)
1803 ;; (interactive "*bStrokify buffer: ") 2007 ;; (interactive "*bStrokify buffer: ")
1804 (save-excursion 2008 (save-excursion
1805 (set-buffer (or buffer (setq buffer (current-buffer)))) 2009 (set-buffer (setq buffer (get-buffer (or buffer (current-buffer)))))
1806 (if (interactive-p) 2010 (when (or (not buffer-read-only)
1807 (message "Strokifying %s..." buffer)) 2011 force
1808 (goto-char (point-min)) 2012 inhibit-read-only
1809 (let (ext string) 2013 (y-or-n-p-maybe-dialog-box
1810 ;; The comment below is what i'd have to do if I wanted to deal with 2014 (format "Buffer %s is read-only. Strokify anyway? " buffer)))
1811 ;; random newlines in the midst of the compressed strings. 2015 (let ((inhibit-read-only t))
1812 ;; If I do this, I'll also have to change `strokes-xpm-to-compress-string' 2016 (message "Strokifying %s..." buffer)
1813 ;; to deal with the newline, and possibly other whitespace stuff. YUCK! 2017 (goto-char (point-min))
1814 ;; (while (re-search-forward "\\+/\\(\\w\\| 2018 (let (ext string)
1815 ;;\\)+/" nil t nil (get-buffer buffer)) 2019 ;; The comment below is what i'd have to do if I wanted to
1816 (while (re-search-forward "\\+/\\w+/" nil t nil (get-buffer buffer)) 2020 ;; deal with random newlines in the midst of the compressed
1817 (setq string (buffer-substring (+ 2 (match-beginning 0)) 2021 ;; strings. If I do this, I'll also have to change
1818 (1- (match-end 0)))) 2022 ;; `strokes-xpm-to-compress-string' to deal with the newline,
1819 (strokes-xpm-for-compressed-string string " *strokes-xpm*") 2023 ;; and possibly other whitespace stuff. YUCK!
1820 (replace-match " ") 2024 ;; (while (re-search-forward "\\+/\\(\\w\\|\\)+/" nil t nil (get-buffer buffer))
1821 (setq ext (make-extent (1- (point)) (point))) 2025 (while (re-search-forward "\\+/\\w+/" nil t nil buffer)
1822 (set-extent-property ext 'type 'stroke-glyph) 2026 (setq string (buffer-substring (+ 2 (match-beginning 0))
1823 (set-extent-property ext 'start-open t) 2027 (1- (match-end 0))))
1824 (set-extent-property ext 'end-open t) 2028 (strokes-xpm-for-compressed-string string " *strokes-xpm*")
1825 (set-extent-property ext 'detachable t) 2029 (replace-match " ")
1826 (set-extent-property ext 'duplicable t) 2030 (setq ext (make-extent (1- (point)) (point)))
1827 (set-extent-property ext 'data string) 2031 (set-extent-property ext 'type 'stroke-glyph)
1828 (set-extent-face ext 'strokes-char-face) 2032 (set-extent-property ext 'start-open t)
1829 (set-extent-end-glyph ext (make-glyph 2033 (set-extent-property ext 'end-open t)
1830 (list 2034 (set-extent-property ext 'detachable t)
1831 (vector 'xpm 2035 (set-extent-property ext 'duplicable t)
1832 :data (buffer-substring 2036 (set-extent-property ext 'data string)
1833 (point-min " *strokes-xpm*") 2037 (set-extent-face ext 'default)
1834 (point-max " *strokes-xpm*") 2038 (set-extent-end-glyph ext (make-glyph
1835 " *strokes-xpm*")) 2039 (list
1836 [string :data "[Stroke]"]))))) 2040 (vector 'xpm
1837 (if (interactive-p) 2041 :data (buffer-substring
1838 (message "Strokifying %s...done" buffer)))) 2042 (point-min " *strokes-xpm*")
1839 2043 (point-max " *strokes-xpm*")
1840 (defun strokes-unstrokify-buffer (&optional buffer) 2044 " *strokes-xpm*"))
2045 [string :data "[Stroke]"])))))
2046 (message "Strokifying %s...done" buffer)))))
2047
2048 (defun strokes-encode-buffer (&optional buffer force)
1841 "Convert the glyphs in BUFFER to thier base-64 ASCII representations. 2049 "Convert the glyphs in BUFFER to thier base-64 ASCII representations.
1842 BUFFER defaults to the current buffer" 2050 Optional BUFFER defaults to the current buffer.
2051 Optional FORCE non-nil will ignore the buffer's read-only status."
1843 ;; ### NOTE !!! ### (for me) 2052 ;; ### NOTE !!! ### (for me)
1844 ;; For later on, you can/should make the inserted strings atomic 2053 ;; For later on, you can/should make the inserted strings atomic
1845 ;; extents, so that the users have a clue that they shouldn't be 2054 ;; extents, so that the users have a clue that they shouldn't be
1846 ;; editing inside them. Plus, if you make them extents, you can 2055 ;; editing inside them. Plus, if you make them extents, you can
1847 ;; very easily just hide the glyphs, so if you unstrokify, and the 2056 ;; very easily just hide the glyphs, so if you unstrokify, and the
1851 ;; buffer is killed? 2060 ;; buffer is killed?
1852 ;; (interactive "*bUnstrokify buffer: ") 2061 ;; (interactive "*bUnstrokify buffer: ")
1853 (interactive) 2062 (interactive)
1854 (save-excursion 2063 (save-excursion
1855 (set-buffer (setq buffer (or buffer (current-buffer)))) 2064 (set-buffer (setq buffer (or buffer (current-buffer))))
1856 ;; (map-extents 2065 (when (or (not buffer-read-only)
1857 ;; (lambda (ext buf) 2066 force
1858 ;; (when (eq (extent-property ext 'type) 'stroke-glyph) 2067 inhibit-read-only
1859 ;; (goto-char (extent-start-position ext)) 2068 (y-or-n-p-maybe-dialog-box
1860 ;; (delete-char 1) ; ### What the hell do I do here? ### 2069 (format "Buffer %s is read-only. Encode anyway? " buffer)))
1861 ;; (insert "+/" (extent-property ext 'data) "/") 2070 (message "Encoding strokes in %s..." buffer)
1862 ;; (delete-extent ext)))))) 2071 ;; (map-extents
1863 (let (start) 2072 ;; (lambda (ext buf)
1864 (map-extents 2073 ;; (when (eq (extent-property ext 'type) 'stroke-glyph)
1865 (lambda (ext buf) 2074 ;; (goto-char (extent-start-position ext))
1866 (when (eq (extent-property ext 'type) 'stroke-glyph) 2075 ;; (delete-char 1) ; ### What the hell do I do here? ###
1867 (setq start (goto-char (extent-start-position ext))) 2076 ;; (insert "+/" (extent-property ext 'data) "/")
1868 ;; (insert "+/" (extent-property ext 'data) "/") 2077 ;; (delete-extent ext))))))
1869 (insert-string "+/") 2078 (let ((inhibit-read-only t)
1870 (insert-string (extent-property ext 'data)) 2079 (start nil))
1871 (insert-string "/") 2080 (loop repeat 2 do ; ### KLUDGE!!! This it pure crap! ###
1872 (delete-char 1) 2081 (map-extents
1873 (set-extent-endpoints ext start (point)) 2082 (lambda (ext buf)
1874 (set-extent-property ext 'type 'stroke-string) 2083 (when (eq (extent-property ext 'type) 'stroke-glyph)
1875 (set-extent-property ext 'atomic t) 2084 (setq start (goto-char (extent-start-position ext)))
1876 ;; (set-extent-property ext 'read-only t) 2085 ;; (insert "+/" (extent-property ext 'data) "/")
1877 (set-extent-face ext 'strokes-char-face) 2086 (insert-string "+/")
1878 (set-extent-property ext 'stroke-glyph (extent-end-glyph ext)) 2087 (insert-string (extent-property ext 'data))
1879 (set-extent-end-glyph ext nil))))))) 2088 (insert-string "/")
2089 (delete-char 1)
2090 (set-extent-endpoints ext start (point))
2091 (set-extent-property ext 'type 'stroke-string)
2092 (set-extent-property ext 'atomic t)
2093 ;; (set-extent-property ext 'read-only t)
2094 (set-extent-face ext 'strokes-char-face)
2095 (set-extent-property ext 'stroke-glyph (extent-end-glyph ext))
2096 (set-extent-end-glyph ext nil))))))
2097 (message "Encoding strokes in %s...done" buffer))))
1880 2098
1881 (defun strokes-xpm-for-compressed-string (compressed-string &optional bufname) 2099 (defun strokes-xpm-for-compressed-string (compressed-string &optional bufname)
1882 "Convert the stroke represented by COMPRESSED-STRING into an xpm. 2100 "Convert the stroke represented by COMPRESSED-STRING into an xpm.
1883 Store xpm in buffer BUFNAME if supplied \(default is `*strokes-xpm*'\)" 2101 Store xpm in buffer BUFNAME if supplied \(default is `*strokes-xpm*'\)"
1884 (save-excursion 2102 (save-excursion
1901 (forward-char 33) 2119 (forward-char 33)
1902 (insert "\",\n")) 2120 (insert "\",\n"))
1903 (goto-char (point-min)) 2121 (goto-char (point-min))
1904 (insert strokes-xpm-header)))) 2122 (insert strokes-xpm-header))))
1905 2123
2124 ;;;###autoload
1906 (defun strokes-compose-complex-stroke () 2125 (defun strokes-compose-complex-stroke ()
2126 ;; ### NOTE !!! ###
2127 ;; Even though we have lexical scoping, it's somewhat ugly how I
2128 ;; pass around variables in the global name space. I can/should
2129 ;; change this.
2130 "Read a complex stroke and insert its glyph into the current buffer."
1907 (interactive "*") 2131 (interactive "*")
1908 (let ((strokes-grid-resolution 33)) 2132 (let ((strokes-grid-resolution 33))
1909 (strokes-read-complex-stroke) 2133 (strokes-read-complex-stroke)
1910 (strokes-xpm-for-stroke nil nil t) 2134 (strokes-xpm-for-stroke nil " *strokes-xpm*" t)
1911 (insert (strokes-xpm-to-compressed-string)) 2135 (insert (strokes-xpm-to-compressed-string " *strokes-xpm*"))
1912 (strokes-strokify-buffer))) 2136 (strokes-decode-buffer)))
1913 2137
1914 (provide 'strokes) 2138 (provide 'strokes)
1915 (run-hooks 'strokes-load-hook) 2139 (run-hooks 'strokes-load-hook)
1916 2140
1917 ;;; strokes.el ends here 2141 ;;; strokes.el ends here