comparison lisp/modes/strokes.el @ 177:6075d714658b r20-3b15

Import from CVS: tag r20-3b15
author cvs
date Mon, 13 Aug 2007 09:51:16 +0200
parents 25f70ba0133c
children 3d6bfa290dbd
comparison
equal deleted inserted replaced
176:6866abce6aaf 177:6075d714658b
1 ;;; strokes.el Sat May 24 14:18:08 1997 1 ;;; strokes.el -- Control XEmacs through mouse strokes --
2 ;; Mon Jun 2 12:40:41 EDT 1997
2 3
3 ;; Copyright (C) 1997 Free Software Foundation, Inc. 4 ;; Copyright (C) 1997 Free Software Foundation, Inc.
4 5
5 ;; Author: David Bakhash <cadet@mit.edu> 6 ;; Author: David Bakhash <cadet@mit.edu>
6 ;; Maintainer: David Bakhash <cadet@mit.edu> 7 ;; Maintainer: David Bakhash <cadet@mit.edu>
7 ;; Version: 2.3-beta 8 ;; Version: 2.3
8 ;; Created: 12 April 1997 9 ;; Created: 12 April 1997
9 ;; Keywords: lisp, mouse, extensions 10 ;; Keywords: lisp, mouse, extensions
10 11
11 ;; This file is part of XEmacs. 12 ;; This file is part of XEmacs.
12 13
156 ;; Japanese and Chinese are a bit trickier, but I'm sure that with help 157 ;; Japanese and Chinese are a bit trickier, but I'm sure that with help
157 ;; it can be done. The next version will allow the user to enter strokes 158 ;; it can be done. The next version will allow the user to enter strokes
158 ;; which "remove the pencil from the paper" so to speak, so one character 159 ;; which "remove the pencil from the paper" so to speak, so one character
159 ;; can have multiple strokes. 160 ;; can have multiple strokes.
160 161
162 ;; You can read more about strokes at:
163
164 ;; http://www.mit.edu/people/cadet/strokes-help.html
165
166 ;; If you're interested in using strokes for writing English into XEmacs
167 ;; using strokes, then you'll want to read about it on the web page above
168 ;; or just download from http://www.mit.edu/people/cadet/strokes-abc.el,
169 ;; which is nothing but a file with some helper commands for inserting
170 ;; alphanumerics and punctuation.
171
161 ;; Great thanks to Rob Ristroph for his generosity in letting me use his 172 ;; Great thanks to Rob Ristroph for his generosity in letting me use his
162 ;; PC to develop this, Jason Johnson for his help in algorithms, Euna 173 ;; PC to develop this, Jason Johnson for his help in algorithms, Euna
163 ;; Kim for her help in Korean, and massive thanks to the helpful guys 174 ;; Kim for her help in Korean, and massive thanks to the helpful guys
164 ;; on the help instance on athena (zeno, jered, amu, gsstark, ghudson, etc) 175 ;; on the help instance on athena (zeno, jered, amu, gsstark, ghudson, etc)
165 ;; Special thanks to Steve Baur and Hrvoje Niksic for all their help. 176 ;; Special thanks to Steve Baur and Hrvoje Niksic for all their help.
177 ;; And even more thanks to Dave Gillespie for all the elisp help--he
178 ;; is responsible for helping me use the cl macros at (near) max speed.
166 179
167 ;; Tasks: (what I'm getting ready for future version)... 180 ;; Tasks: (what I'm getting ready for future version)...
168 ;; 2) use 'strokes-read-complex-stroke for korean, etc. 181 ;; 2) use 'strokes-read-complex-stroke for korean, etc.
169 ;; 4) buffer-local 'strokes-local-map, and mode-stroke-maps would be nice 182 ;; 4) buffer-local 'strokes-local-map, and mode-stroke-maps would be nice
170 ;; 5) 'list-strokes (kinda important). What do people want? 183 ;; 5) 'list-strokes (kinda important). What do people want?
251 264
252 ;;; Requirements and provisions... 265 ;;; Requirements and provisions...
253 266
254 (autoload 'reporter-submit-bug-report "reporter") 267 (autoload 'reporter-submit-bug-report "reporter")
255 (autoload 'mail-position-on-field "sendmail") 268 (autoload 'mail-position-on-field "sendmail")
269 (eval-when-compile
270 (mapc 'require '(xpm-mode pp annotations reporter advice)))
256 271
257 ;;; Constants... 272 ;;; Constants...
258 273
259 (defconst strokes-version "2.3-beta") 274 (defconst strokes-version "2.3")
260 275
261 (defconst strokes-bug-address "cadet@mit.edu") 276 (defconst strokes-bug-address "cadet@mit.edu")
262 277
263 (defconst strokes-lift :strokes-lift 278 (defconst strokes-lift :strokes-lift
264 "Symbol representing a stroke lift event for complex strokes. 279 "Symbol representing a stroke lift event for complex strokes.
265 Complex strokes are those which contain two or more simple strokes. 280 Complex strokes are those which contain two or more simple strokes.
266 This will be useful for when XEmacs understands Chinese.") 281 This will be useful for when XEmacs understands Chinese.")
282
283 (defconst strokes-xpm-header "/* XPM */
284 static char * stroke_xpm[] = {
285 /* width height ncolors cpp [x_hot y_hot] */
286 \"33 33 9 1 26 23\",
287 /* colors */
288 \" c #D9D9D9D9D9D9\",
289 \"* s iconColor1 m black c black\",
290 \"R c #FFFF00000000\",
291 \"O c #FFFF80000000\",
292 \"Y c #FFFFFFFF0000\",
293 \"G c #0000FFFF0000\",
294 \"B c #00000000FFFF\",
295 \"P c #FFFF0000FFFF\",
296 \". c #45458B8B0000\",
297 /* pixels */\n"
298 "The header to all xpm buffers created by strokes")
267 299
268 ;;; user variables... 300 ;;; user variables...
269 301
270 (defgroup strokes nil 302 (defgroup strokes nil
271 "Control Emacs through mouse strokes" 303 "Control Emacs through mouse strokes"
362 normalized stroke grid, with the top left at (0 . 0). COMMAND is the 394 normalized stroke grid, with the top left at (0 . 0). COMMAND is the
363 corresponding interactive function") 395 corresponding interactive function")
364 396
365 (defvar strokes-load-hook nil 397 (defvar strokes-load-hook nil
366 "Function or functions to be called when `strokes' is loaded.") 398 "Function or functions to be called when `strokes' is loaded.")
399
400 (defvar edit-strokes-menu
401 '("Edit-Strokes"
402 ["Add stroke..." strokes-global-set-stroke t]
403 ["Delete stroke..." strokes-edit-delete-stroke t]
404 ["Change stroke" strokes-smaller t]
405 ["Change definition" strokes-larger t]
406 ["[Re]List Strokes chronologically" strokes-list-strokes t]
407 ["[Re]List Strokes alphabetically" strokes-list-strokes t]
408 ["Quit" strokes-edit-quit t]
409 ))
367 410
368 ;;; Macros... 411 ;;; Macros...
369 412
370 (defsubst strokes-click-p (stroke) 413 (defsubst strokes-click-p (stroke)
371 "Non-nil if STROKE is really click." 414 "Non-nil if STROKE is really click."
480 (strokes-fix-button2-command 'dired-g-x-mouse-toggle) 523 (strokes-fix-button2-command 'dired-g-x-mouse-toggle)
481 (strokes-fix-button2-command 'dired-o-r-mouse-toggle) 524 (strokes-fix-button2-command 'dired-o-r-mouse-toggle)
482 (strokes-fix-button2-command 'dired-o-w-mouse-toggle) 525 (strokes-fix-button2-command 'dired-o-w-mouse-toggle)
483 (strokes-fix-button2-command 'isearch-yank-x-selection) 526 (strokes-fix-button2-command 'isearch-yank-x-selection)
484 (strokes-fix-button2-command 'occur-mode-mouse-goto) 527 (strokes-fix-button2-command 'occur-mode-mouse-goto)
528 (strokes-fix-button2-command 'cvs-mouse-find-file)
485 529
486 ;;; I can fix the customize widget button click, but then 530 ;;; I can fix the customize widget button click, but then
487 ;;; people will get confused when they try to customize 531 ;;; people will get confused when they try to customize
488 ;;; strokes with the mouse and customize tells them that 532 ;;; strokes with the mouse and customize tells them that
489 ;;; `strokes-click-command' is mapped to `ad-Orig-widget-button-click' 533 ;;; `strokes-click-command' is mapped to `ad-Orig-widget-button-click'
635 679
636 (defun strokes-eliminate-consecutive-redundancies (entries) 680 (defun strokes-eliminate-consecutive-redundancies (entries)
637 "Returns a list with no consecutive redundant entries." 681 "Returns a list with no consecutive redundant entries."
638 ;; defun a grande vitesse grace a Dave G. 682 ;; defun a grande vitesse grace a Dave G.
639 (loop for element on entries 683 (loop for element on entries
640 if (not (equal (car element) (cadr element))) 684 if (not (equal (car element) (cadr element)))
641 collect (car element))) 685 collect (car element)))
642 ;; (loop for element on entries 686 ;; (loop for element on entries
643 ;; nconc (if (not (equal (car el) (cadr el))) 687 ;; nconc (if (not (equal (car el) (cadr el)))
644 ;; (list (car el))))) 688 ;; (list (car el)))))
645 ;; yet another (orig) way of doing it... 689 ;; yet another (orig) way of doing it...
646 ;; (if entries 690 ;; (if entries
647 ;; (let* ((current (car entries)) 691 ;; (let* ((current (car entries))
648 ;; (rest (cdr entries)) 692 ;; (rest (cdr entries))
661 (defun strokes-renormalize-to-grid (positions &optional grid-resolution) 705 (defun strokes-renormalize-to-grid (positions &optional grid-resolution)
662 "Map POSITIONS to a new grid whose dimensions are based on GRID-RESOLUTION. 706 "Map POSITIONS to a new grid whose dimensions are based on GRID-RESOLUTION.
663 POSITIONS is a list of positions and stroke-lifts. 707 POSITIONS is a list of positions and stroke-lifts.
664 Optional GRID-RESOLUTION may be used in place of STROKES-GRID-RESOLUTION. 708 Optional GRID-RESOLUTION may be used in place of STROKES-GRID-RESOLUTION.
665 The grid is a square whose dimesion is [0,GRID-RESOLUTION)." 709 The grid is a square whose dimesion is [0,GRID-RESOLUTION)."
710 (or grid-resolution (setq grid-resolution strokes-grid-resolution))
666 (let ((stroke-extent (strokes-get-stroke-extent positions))) 711 (let ((stroke-extent (strokes-get-stroke-extent positions)))
667 (mapcar (function 712 (mapcar (function
668 (lambda (pos) 713 (lambda (pos)
669 (strokes-get-grid-position stroke-extent pos grid-resolution))) 714 (strokes-get-grid-position stroke-extent pos grid-resolution)))
670 positions))) 715 positions)))
853 (if (mouse-event-p event) 898 (if (mouse-event-p event)
854 (let ((point (event-closest-point event))) 899 (let ((point (event-closest-point event)))
855 (when point 900 (when point
856 (goto-char point) 901 (goto-char point)
857 (subst-char-in-region point (1+ point) ?\ strokes-character)) 902 (subst-char-in-region point (1+ point) ?\ strokes-character))
858 (setq pix-locs (cons (cons (event-x-pixel event) 903 (push (cons (event-x-pixel event)
859 (event-y-pixel event)) 904 (event-y-pixel event))
860 pix-locs)))) 905 pix-locs)))
861 (setq event (next-event event)))) 906 (setq event (next-event event))))
862 ;; protected 907 ;; protected
863 ;; clean up strokes buffer and then bury it. 908 ;; clean up strokes buffer and then bury it.
864 (subst-char-in-region (point-min) (point-max) strokes-character ?\ ) 909 (when (equal (buffer-name) strokes-buffer-name)
865 (goto-char (point-min)) 910 (subst-char-in-region (point-min) (point-max) strokes-character ?\ )
866 (bury-buffer))) 911 (goto-char (point-min))
912 (bury-buffer))))
867 ;; Otherwise, don't use strokes buffer and read stroke silently 913 ;; Otherwise, don't use strokes buffer and read stroke silently
868 (if prompt 914 (if prompt
869 (progn 915 (progn
870 (setq event (next-event event prompt)) 916 (setq event (next-event event prompt))
871 (while (not (button-press-event-p event)) 917 (while (not (button-press-event-p event))
872 (dispatch-event event) 918 (dispatch-event event)
873 (setq event (next-event event))))) 919 (setq event (next-event event)))))
874 (setq event (next-event)) 920 (setq event (next-event))
875 (while (not (button-release-event-p event)) 921 (while (not (button-release-event-p event))
876 (if (mouse-event-p event) 922 (if (mouse-event-p event)
877 (setq pix-locs (cons (cons (event-x-pixel event) 923 (push (cons (event-x-pixel event)
878 (event-y-pixel event)) 924 (event-y-pixel event))
879 pix-locs))) 925 pix-locs))
880 (setq event (next-event event)))) 926 (setq event (next-event event))))
881 (setq grid-locs (strokes-renormalize-to-grid (nreverse pix-locs))) 927 (setq grid-locs (strokes-renormalize-to-grid (nreverse pix-locs)))
882 (strokes-fill-stroke (strokes-eliminate-consecutive-redundancies grid-locs))))) 928 (strokes-fill-stroke (strokes-eliminate-consecutive-redundancies grid-locs)))))
883 929
884 ;;;###autoload 930 ;;;###autoload
899 (while (not (button-press-event-p event)) 945 (while (not (button-press-event-p event))
900 (dispatch-event event) 946 (dispatch-event event)
901 (setq event (next-event event)))) 947 (setq event (next-event event))))
902 (unwind-protect 948 (unwind-protect
903 (progn 949 (progn
950 (setq event (next-event event prompt))
904 (while (not (and (button-press-event-p event) 951 (while (not (and (button-press-event-p event)
905 (eq (event-button event) 3))) 952 (eq (event-button event) 3)))
906 (while (not (button-release-event-p event)) 953 (while (not (button-release-event-p event))
907 (if (mouse-event-p event) 954 (if (mouse-event-p event)
908 (let ((point (event-closest-point event))) 955 (let ((point (event-closest-point event)))
909 (when point 956 (when point
910 (goto-char point) 957 (goto-char point)
911 (subst-char-in-region point (1+ point) ?\ strokes-character)) 958 (subst-char-in-region point (1+ point) ?\ strokes-character))
912 (setq pix-locs (cons (cons (event-x-pixel event) 959 (push (cons (event-x-pixel event)
913 (event-y-pixel event)) 960 (event-y-pixel event))
914 pix-locs)))) 961 pix-locs)))
915 (setq event (next-event event prompt))) 962 (setq event (next-event event prompt)))
916 (setq pix-locs (cons strokes-lift pix-locs)) 963 (push strokes-lift pix-locs)
917 (while (not (button-press-event-p event)) 964 (while (not (button-press-event-p event))
918 (dispatch-event event) 965 (dispatch-event event)
919 (setq event (next-event event prompt)))) 966 (setq event (next-event event prompt))))
920 (setq pix-locs (nreverse (cdr pix-locs)) 967 (setq pix-locs (nreverse (cdr pix-locs))
921 grid-locs (strokes-renormalize-to-grid pix-locs)) 968 grid-locs (strokes-renormalize-to-grid pix-locs))
922 (strokes-fill-stroke 969 (strokes-fill-stroke
923 (strokes-eliminate-consecutive-redundancies grid-locs))) 970 (strokes-eliminate-consecutive-redundancies grid-locs)))
924 ;; protected 971 ;; protected
925 (subst-char-in-region (point-min) (point-max) strokes-character ?\ ) 972 (when (equal (buffer-name) strokes-buffer-name)
926 (goto-char (point-min)) 973 (subst-char-in-region (point-min) (point-max) strokes-character ?\ )
927 (bury-buffer)))))) 974 (goto-char (point-min))
975 (bury-buffer)))))))
928 976
929 (defun strokes-execute-stroke (stroke) 977 (defun strokes-execute-stroke (stroke)
930 "Given STROKE, execute the command which corresponds to it. 978 "Given STROKE, execute the command which corresponds to it.
931 The command will be executed provided one exists for that stroke, 979 The command will be executed provided one exists for that stroke,
932 based on the variable `strokes-minimum-match-score'. 980 based on the variable `strokes-minimum-match-score'.
1076 You can always get an idea of what your current strokes look like with 1124 You can always get an idea of what your current strokes look like with
1077 the command 1125 the command
1078 1126
1079 > M-x list-strokes 1127 > M-x list-strokes
1080 1128
1081 Your strokes will be displayed in from most recent down, and the 1129 Your strokes will be displayed in alphabetical order (based on command
1082 beginning of each simple stroke will be marked by a color dot. Since 1130 names) and the beginning of each simple stroke will be marked by a
1083 you may have several simple strokes in a complex stroke, the dot 1131 color dot. Since you may have several simple strokes in a complex
1084 colors are arranged in the rainbow color sequence, `ROYGBIV'. 1132 stroke, the dot colors are arranged in the rainbow color sequence,
1133 `ROYGBIV'. If you want a listing of your strokes from most recent
1134 down, then use a prefix argument:
1135
1136 > C-u M-x list-strokes
1085 1137
1086 Your strokes are stored as you enter them. They get saved in a file 1138 Your strokes are stored as you enter them. They get saved in a file
1087 called ~/.strokes, along with other strokes configuration variables. 1139 called ~/.strokes, along with other strokes configuration variables.
1088 You can change this location by setting the variable `strokes-file'. 1140 You can change this location by setting the variable `strokes-file'.
1089 You will be prompted to save them when you exit XEmacs, or you can save 1141 You will be prompted to save them when you exit XEmacs, or you can save
1156 (insert " " strokes-version " bug:"))))))))) 1208 (insert " " strokes-version " bug:")))))))))
1157 1209
1158 (defsubst strokes-fill-current-buffer-with-whitespace () 1210 (defsubst strokes-fill-current-buffer-with-whitespace ()
1159 "Erase the contents of the current buffer and fill it with whitespace" 1211 "Erase the contents of the current buffer and fill it with whitespace"
1160 (erase-buffer) 1212 (erase-buffer)
1161 (loop for i from 1 to (frame-height) do 1213 (loop repeat (frame-height) do
1162 (progn 1214 (insert-char ?\ (1- (frame-width)))
1163 (insert-char ?\ (1- (frame-width))) 1215 (newline))
1164 (newline)))
1165 (goto-char (point-min))) 1216 (goto-char (point-min)))
1166 1217
1167 (defun strokes-update-window-configuration () 1218 (defun strokes-update-window-configuration ()
1168 "Insure that `strokes-window-configuration' is up-to-date." 1219 "Insure that `strokes-window-configuration' is up-to-date."
1169 (interactive) 1220 (interactive)
1266 (interactive "P") 1317 (interactive "P")
1267 (setq strokes-use-strokes-buffer 1318 (setq strokes-use-strokes-buffer
1268 (if arg (> (prefix-numeric-value arg) 0) 1319 (if arg (> (prefix-numeric-value arg) 0)
1269 (not strokes-use-strokes-buffer)))) 1320 (not strokes-use-strokes-buffer))))
1270 1321
1271 (defun strokes-xpm-for-stroke (stroke &optional bufname) 1322 (defun strokes-xpm-for-stroke (&optional stroke bufname b/w-only)
1272 "Create an xpm pixmap for the given stroke in buffer `*strokes-xpm*'. 1323 "Create an xpm pixmap for the given STROKE in buffer `*strokes-xpm*'.
1324 If STROKE is not supplied, then `strokes-last-stroke' will be used.
1273 Optional BUFNAME to name something else. 1325 Optional BUFNAME to name something else.
1274 The pixmap will contain time information via rainbow dot colors 1326 The pixmap will contain time information via rainbow dot colors
1275 where each individual strokes begins." 1327 where each individual strokes begins.
1328 Optional B/W-ONLY non-nil will create a mono pixmap, not intended
1329 for trying to figure out the order of strokes, but rather for reading
1330 the stroke as a character in some language."
1331 (interactive)
1276 (save-excursion 1332 (save-excursion
1277 (let ((buf (get-buffer-create (or bufname "*strokes-xpm*"))) 1333 (let ((buf (get-buffer-create (or bufname "*strokes-xpm*")))
1278 (stroke (strokes-eliminate-consecutive-redundancies 1334 (stroke (strokes-eliminate-consecutive-redundancies
1279 (strokes-fill-stroke 1335 (strokes-fill-stroke
1280 (strokes-renormalize-to-grid stroke 31)))) 1336 (strokes-renormalize-to-grid (or stroke
1337 strokes-last-stroke)
1338 31))))
1281 (lift-flag t) 1339 (lift-flag t)
1282 (rainbow-chars (list ?R ?O ?Y ?G ?B ?P)) ; ROYGBIV w/o indigo 1340 (rainbow-chars (list ?R ?O ?Y ?G ?B ?P))) ; ROYGBIV w/o indigo
1283 (header (format "/* XPM */
1284 static char * stroke_xpm[] = {
1285 /* width height ncolors cpp [x_hot y_hot] */
1286 \"33 33 9 1 26 23\",
1287 /* colors */
1288 \" c #FFFFFFFFFFFF\",
1289 \"* s iconColor1 m black c black\",
1290 \"R c #FFFF00000000\",
1291 \"O c #FFFF80000000\",
1292 \"Y c #FFFFFFFF0000\",
1293 \"G c #0000FFFF0000\",
1294 \"B c #00000000FFFF\",
1295 \"P c #FFFF0000FFFF\",
1296 \". c #45458B8B0000\",
1297 /* pixels */")))
1298 (set-buffer buf) 1341 (set-buffer buf)
1299 (erase-buffer) 1342 (erase-buffer)
1300 (insert header) 1343 (insert strokes-xpm-header)
1301 (loop repeat 33 do 1344 (loop repeat 33 do
1302 (newline)
1303 (insert-char ?\") 1345 (insert-char ?\")
1304 (insert-char ?\ 33) 1346 (insert-char ?\ 33)
1305 (insert "\",") 1347 (insert "\",")
1306 finally (insert "}\n")) 1348 (newline)
1349 finally
1350 (forward-line -1)
1351 (end-of-line)
1352 (insert "}\n"))
1307 (loop for point in stroke 1353 (loop for point in stroke
1308 for x = (car-safe point) 1354 for x = (car-safe point)
1309 for y = (cdr-safe point) do 1355 for y = (cdr-safe point) do
1310 (cond ((consp point) 1356 (cond ((consp point)
1311 ;; draw a point, and possibly a starting-point 1357 ;; draw a point, and possibly a starting-point
1312 (if lift-flag 1358 (if (and lift-flag (not b/w-only))
1313 ;; mark starting point with the appropriate color 1359 ;; mark starting point with the appropriate color
1314 (let ((char (or (car rainbow-chars) ?\.))) 1360 (let ((char (or (car rainbow-chars) ?\.)))
1315 (loop for i from 0 to 2 do 1361 (loop for i from 0 to 2 do
1316 (loop for j from 0 to 2 do 1362 (loop for j from 0 to 2 do
1317 (goto-line (+ 16 i y)) 1363 (goto-line (+ 16 i y))
1324 (goto-line (+ 17 y)) 1370 (goto-line (+ 17 y))
1325 (forward-char (+ 2 x)) 1371 (forward-char (+ 2 x))
1326 (subst-char-in-region (point) (1+ (point)) ?\ ?\*))) 1372 (subst-char-in-region (point) (1+ (point)) ?\ ?\*)))
1327 ((strokes-lift-p point) 1373 ((strokes-lift-p point)
1328 ;; a lift--tell the loop to X out the next point... 1374 ;; a lift--tell the loop to X out the next point...
1329 (setq lift-flag t))))))) 1375 (setq lift-flag t))))
1376 (when (interactive-p)
1377 (require 'xpm-mode)
1378 (pop-to-buffer "*strokes-xpm*")
1379 ;; (xpm-mode 1)
1380 (xpm-show-image)
1381 (goto-char (point-min))))))
1382
1383 ;;; Strokes Edit stuff...
1384
1385 (defun strokes-edit-quit ()
1386 (interactive)
1387 (or (one-window-p t 0)
1388 (delete-window))
1389 (kill-buffer "*Strokes List*"))
1390
1391 (define-derived-mode edit-strokes-mode list-mode
1392 "Edit-Strokes"
1393 "Major mode for `edit-strokes' and `list-strokes' buffers.
1394
1395 Editing commands:
1396
1397 \\{edit-strokes-mode-map}"
1398 (setq truncate-lines nil
1399 auto-show-mode nil ; don't want problems here either
1400 mode-popup-menu edit-strokes-menu) ; what about extent-specific stuff?
1401 (and (featurep 'menubar)
1402 current-menubar
1403 (set (make-local-variable 'current-menubar)
1404 (copy-sequence current-menubar))
1405 (add-submenu nil edit-strokes-menu)))
1406
1407 (let ((map edit-strokes-mode-map))
1408 (define-key map "<" 'beginning-of-buffer)
1409 (define-key map ">" 'end-of-buffer)
1410 ;; (define-key map "c" 'strokes-copy-other-face)
1411 ;; (define-key map "C" 'strokes-copy-this-face)
1412 ;; (define-key map "s" 'strokes-smaller)
1413 ;; (define-key map "l" 'strokes-larger)
1414 ;; (define-key map "b" 'strokes-bold)
1415 ;; (define-key map "i" 'strokes-italic)
1416 (define-key map "e" 'strokes-list-edit)
1417 ;; (define-key map "f" 'strokes-font)
1418 ;; (define-key map "u" 'strokes-underline)
1419 ;; (define-key map "t" 'strokes-truefont)
1420 ;; (define-key map "F" 'strokes-foreground)
1421 ;; (define-key map "B" 'strokes-background)
1422 ;; (define-key map "D" 'strokes-doc-string)
1423 (define-key map "a" 'strokes-global-set-stroke)
1424 (define-key map "d" 'strokes-list-delete-stroke)
1425 ;; (define-key map "n" 'strokes-list-next)
1426 ;; (define-key map "p" 'strokes-list-prev)
1427 ;; (define-key map " " 'strokes-list-next)
1428 ;; (define-key map "\C-?" 'strokes-list-prev)
1429 (define-key map "g" 'strokes-list-strokes) ; refresh display
1430 (define-key map "q" 'strokes-edit-quit)
1431 (define-key map [(control c) (control c)] 'bury-buffer))
1330 1432
1331 ;;;###autoload 1433 ;;;###autoload
1332 (defun strokes-list-strokes (&optional stroke-map) 1434 (defun strokes-edit-strokes (&optional chronological strokes-map)
1333 "Pop up a buffer containing a listing of all strokes defined in STROKE-MAP. 1435 ;; ### DEAL WITH THE 2nd ARGUMENT ISSUE! ###
1334 If STROKE-MAP is not given, `strokes-global-map' will be used instead." 1436 "Edit strokes in a pop-up buffer containing strokes and their definitions.
1335 (interactive) 1437 If STROKES-MAP is not given, `strokes-global-map' will be used instead.
1438
1439 Editing commands:
1440
1441 \\{edit-faces-mode-map}"
1442 (interactive "P")
1443 (pop-to-buffer (get-buffer-create "*Strokes List*"))
1444 (reset-buffer (current-buffer)) ; handy function from minibuf.el
1445 (setq strokes-map (or strokes-map
1446 strokes-global-map
1447 (progn
1448 (strokes-load-user-strokes)
1449 strokes-global-map)))
1450 (or chronological
1451 (setq strokes-map (sort (copy-sequence strokes-map)
1452 'strokes-alphabetic-lessp)))
1453 ;; (push-window-configuration)
1454 (insert
1455 "Command Stroke\n"
1456 "------- ------")
1457 (loop for def in strokes-map
1458 for i from 0 to (1- (length strokes-map)) do
1459 (let ((stroke (car def))
1460 (command-name (symbol-name (cdr def))))
1461 (strokes-xpm-for-stroke stroke " *strokes-xpm*")
1462 (newline 2)
1463 (insert-char ?\ 45)
1464 (beginning-of-line)
1465 (insert command-name)
1466 (beginning-of-line)
1467 (forward-char 45)
1468 (set (intern (format "strokes-list-annotation-%d" i))
1469 (make-annotation (make-glyph
1470 (list
1471 (vector 'xpm
1472 :data (buffer-substring
1473 (point-min " *strokes-xpm*")
1474 (point-max " *strokes-xpm*")
1475 " *strokes-xpm*"))
1476 [string :data "[Stroke]"]))
1477 (point) 'text))
1478 (set-annotation-data (symbol-value (intern (format "strokes-list-annotation-%d" i)))
1479 def))
1480 finally do (kill-region (1+ (point)) (point-max)))
1481 (edit-strokes-mode)
1482 (goto-char (point-min)))
1483
1484 ;;;###autoload
1485 (defalias 'edit-strokes 'strokes-edit-strokes)
1486
1487 ;;;###autoload
1488 (defun strokes-list-strokes (&optional chronological strokes-map)
1489 "Pop up a buffer containing an alphabetical listing of strokes in STROKES-MAP.
1490 With CHRONOLOGICAL prefix arg \(\\[universal-argument]\) list strokes
1491 chronologically by command name.
1492 If STROKES-MAP is not given, `strokes-global-map' will be used instead."
1493 (interactive "P")
1494 (setq strokes-map (or strokes-map
1495 strokes-global-map
1496 (progn
1497 (strokes-load-user-strokes)
1498 strokes-global-map)))
1499 (if (not chronological)
1500 ;; then alphabetize the strokes based on command names...
1501 (setq strokes-map (sort (copy-sequence strokes-map)
1502 'strokes-alphabetic-lessp)))
1336 (push-window-configuration) 1503 (push-window-configuration)
1337 (set-buffer (get-buffer-create "*Strokes List*")) 1504 (set-buffer (get-buffer-create "*Strokes List*"))
1338 (setq buffer-read-only nil) 1505 (setq buffer-read-only nil)
1339 (erase-buffer) 1506 (erase-buffer)
1340 (insert 1507 (insert
1341 "Command Stroke\n" 1508 "Command Stroke\n"
1342 "------- ------\n\n") 1509 "------- ------")
1343 (loop for def in (or stroke-map strokes-global-map) do 1510 (loop for def in strokes-map do
1344 (let ((stroke (car def)) 1511 (let ((stroke (car def))
1345 (command (cdr def))) 1512 (command-name (symbol-name (cdr def))))
1346 (strokes-xpm-for-stroke stroke " *strokes-xpm*") 1513 (strokes-xpm-for-stroke stroke " *strokes-xpm*")
1347 (insert-char ?\ 60) 1514 (newline 2)
1515 (insert-char ?\ 45)
1348 (beginning-of-line) 1516 (beginning-of-line)
1349 (insert (symbol-name command)) 1517 (insert command-name)
1350 (beginning-of-line) 1518 (beginning-of-line)
1351 (forward-char 45) 1519 (forward-char 45)
1352 (make-annotation (make-glyph 1520 (make-annotation (make-glyph
1353 (list 1521 (list
1354 (vector 'xpm 1522 (vector 'xpm
1355 :data (buffer-substring 1523 :data (buffer-substring
1356 (point-min " *strokes-xpm*") 1524 (point-min " *strokes-xpm*")
1357 (point-max " *strokes-xpm*") 1525 (point-max " *strokes-xpm*")
1358 " *strokes-xpm*")) 1526 " *strokes-xpm*"))
1359 [string :data "[Image]"])) 1527 [string :data "[Image]"]))
1360 (point) 'text) 1528 (point) 'text))
1361 (newline 2))) 1529 finally do (kill-region (1+ (point)) (point-max)))
1362 (view-buffer "*Strokes List*" t) 1530 (view-buffer "*Strokes List*" t)
1363 (goto-char (point-min)) 1531 (goto-char (point-min))
1364 ;; (define-key 1532 (define-key view-minor-mode-map [(q)] (lambda ()
1365 ;; (current-local-map (get-buffer "*Strokes List*")) 1533 (interactive)
1366 ;; [(q)] 1534 (view-quit)
1367 ;; 'pop-window-configuration)) 1535 (pop-window-configuration)
1368 ) 1536 ;; (bury-buffer "*Strokes List*")
1537 (define-key view-minor-mode-map [(q)] 'view-quit))))
1538
1539 (defun strokes-alphabetic-lessp (stroke1 stroke2)
1540 "T iff command name for STROKE1 is less than STROKE2's in lexicographic order."
1541 (let ((command-name-1 (symbol-name (cdr stroke1)))
1542 (command-name-2 (symbol-name (cdr stroke2))))
1543 (string-lessp command-name-1 command-name-2)))
1369 1544
1370 ;;;###autoload 1545 ;;;###autoload
1371 (defalias 'list-strokes 'strokes-list-strokes) 1546 (defalias 'list-strokes 'strokes-list-strokes)
1372 1547
1373 ;;;###autoload 1548 ;;;###autoload
1416 (setq strokes-mode nil)))) 1591 (setq strokes-mode nil))))
1417 (redraw-modeline)) 1592 (redraw-modeline))
1418 1593
1419 (add-minor-mode 'strokes-mode strokes-modeline-string nil nil 'strokes-mode) 1594 (add-minor-mode 'strokes-mode strokes-modeline-string nil nil 'strokes-mode)
1420 1595
1596 (unless (find-face 'strokes-char-face)
1597 (copy-face 'default 'strokes-char-face)
1598 (set-face-background 'strokes-char-face "lightgray"))
1599
1600 (defconst strokes-char-value-hashtable (make-hashtable 62) ;
1601 ; (make-char-table
1602 ; 'syntax)
1603 ; in 20.*
1604 ;; ### This will become a char-table for XEmacs-20 !!! ###
1605 "The table which stores values for the character keys.")
1606 (puthash ?0 0 strokes-char-value-hashtable) ; (put-char-table ?0 0
1607 ; strokes-value-chartable)
1608 ; in 20.*
1609 (puthash ?1 1 strokes-char-value-hashtable)
1610 (puthash ?2 2 strokes-char-value-hashtable)
1611 (puthash ?3 3 strokes-char-value-hashtable)
1612 (puthash ?4 4 strokes-char-value-hashtable)
1613 (puthash ?5 5 strokes-char-value-hashtable)
1614 (puthash ?6 6 strokes-char-value-hashtable)
1615 (puthash ?7 7 strokes-char-value-hashtable)
1616 (puthash ?8 8 strokes-char-value-hashtable)
1617 (puthash ?9 9 strokes-char-value-hashtable)
1618 (puthash ?a 10 strokes-char-value-hashtable)
1619 (puthash ?b 11 strokes-char-value-hashtable)
1620 (puthash ?c 12 strokes-char-value-hashtable)
1621 (puthash ?d 13 strokes-char-value-hashtable)
1622 (puthash ?e 14 strokes-char-value-hashtable)
1623 (puthash ?f 15 strokes-char-value-hashtable)
1624 (puthash ?g 16 strokes-char-value-hashtable)
1625 (puthash ?h 17 strokes-char-value-hashtable)
1626 (puthash ?i 18 strokes-char-value-hashtable)
1627 (puthash ?j 19 strokes-char-value-hashtable)
1628 (puthash ?k 20 strokes-char-value-hashtable)
1629 (puthash ?l 21 strokes-char-value-hashtable)
1630 (puthash ?m 22 strokes-char-value-hashtable)
1631 (puthash ?n 23 strokes-char-value-hashtable)
1632 (puthash ?o 24 strokes-char-value-hashtable)
1633 (puthash ?p 25 strokes-char-value-hashtable)
1634 (puthash ?q 26 strokes-char-value-hashtable)
1635 (puthash ?r 27 strokes-char-value-hashtable)
1636 (puthash ?s 28 strokes-char-value-hashtable)
1637 (puthash ?t 29 strokes-char-value-hashtable)
1638 (puthash ?u 30 strokes-char-value-hashtable)
1639 (puthash ?v 31 strokes-char-value-hashtable)
1640 (puthash ?w 32 strokes-char-value-hashtable)
1641 (puthash ?x 33 strokes-char-value-hashtable)
1642 (puthash ?y 34 strokes-char-value-hashtable)
1643 (puthash ?z 35 strokes-char-value-hashtable)
1644 (puthash ?A 36 strokes-char-value-hashtable)
1645 (puthash ?B 37 strokes-char-value-hashtable)
1646 (puthash ?C 38 strokes-char-value-hashtable)
1647 (puthash ?D 39 strokes-char-value-hashtable)
1648 (puthash ?E 40 strokes-char-value-hashtable)
1649 (puthash ?F 41 strokes-char-value-hashtable)
1650 (puthash ?G 42 strokes-char-value-hashtable)
1651 (puthash ?H 43 strokes-char-value-hashtable)
1652 (puthash ?I 44 strokes-char-value-hashtable)
1653 (puthash ?J 45 strokes-char-value-hashtable)
1654 (puthash ?K 46 strokes-char-value-hashtable)
1655 (puthash ?L 47 strokes-char-value-hashtable)
1656 (puthash ?M 48 strokes-char-value-hashtable)
1657 (puthash ?N 49 strokes-char-value-hashtable)
1658 (puthash ?O 50 strokes-char-value-hashtable)
1659 (puthash ?P 51 strokes-char-value-hashtable)
1660 (puthash ?Q 52 strokes-char-value-hashtable)
1661 (puthash ?R 53 strokes-char-value-hashtable)
1662 (puthash ?S 54 strokes-char-value-hashtable)
1663 (puthash ?T 55 strokes-char-value-hashtable)
1664 (puthash ?U 56 strokes-char-value-hashtable)
1665 (puthash ?V 57 strokes-char-value-hashtable)
1666 (puthash ?W 58 strokes-char-value-hashtable)
1667 (puthash ?X 59 strokes-char-value-hashtable)
1668 (puthash ?Y 60 strokes-char-value-hashtable)
1669 (puthash ?Z 61 strokes-char-value-hashtable)
1670
1671 (defconst strokes-base64-chars
1672 ;; I can easily have made this a vector of single-character strings,
1673 ;; like (vector "0" "1" "2" ...), and then the program would run
1674 ;; faster since it wouldn't then have to call `char-to-string' when it
1675 ;; did the `concat'. I left them as chars here because I want
1676 ;; *them* to change `concat' so that it accepts chars and deals with
1677 ;; them properly. i.e. the form: (concat "abc" ?T "xyz") should
1678 ;; return "abcTxyz" NOT "abc84xyz" (XEmacs 19.*) and NOT an error
1679 ;; (XEmacs 20.*).
1680 ;; (vector "0" "1" "2" "3" "4" "5" "6" "7" "8" "9"
1681 ;; "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o"
1682 ;; "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z" "A" "B" "C" "D"
1683 ;; "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S"
1684 ;; "T" "U" "V" "W" "X" "Y" "Z")
1685 (vector ?0 ?1 ?2 ?3 ?4 ?5 ?6 ?7 ?8 ?9
1686 ?a ?b ?c ?d ?e ?f ?g ?h ?i ?j ?k ?l ?m ?n ?o ?p ?q ?r ?s ?t ?u ?v ?w ?x ?y ?z
1687 ?A ?B ?C ?D ?E ?F ?G ?H ?I ?J ?K ?L ?M ?N ?O ?P ?Q ?R ?S ?T ?U ?V ?W ?X ?Y ?Z)
1688 "Character vector for fast lookup of base-64 encoding of numbers in [0,61].")
1689
1690 (defsubst strokes-xpm-char-on-p (char)
1691 ;; ### CAUTION: `char-equal' may need to change to `char=' ###
1692 "Non-nil if CHAR represents an `on' bit in the xpm."
1693 (char-equal char ?*))
1694
1695 (defsubst strokes-xpm-char-bit-p (char)
1696 "Non-nil if CHAR represents an `on' or `off' bit in the xpm."
1697 ;; ### CAUTION: `char-equal' may need to change to `char=' ###
1698 (or (char-equal char ?\ )
1699 (char-equal char ?*)))
1700
1701 ;;(defsubst strokes-xor (a b) ### Should I make this an inline function? ###
1702 ;; "T iff one and only one of A and B is non-nil; otherwise, returns nil.
1703 ;;NOTE: Don't use this as a numeric xor since it treats all non-nil
1704 ;; values as t including `0' (zero)."
1705 ;; (eq (null a) (not (null b))))
1706
1707 (defsubst strokes-xpm-encode-length-as-string (length)
1708 "Given some LENGTH in [0,62) do a fast lookup of it's encoding."
1709 (char-to-string (aref strokes-base64-chars length)))
1710
1711 (defsubst strokes-xpm-decode-char (character)
1712 "Given a CHARACTER, do a fast lookup to find its corresponding integer value."
1713 ;; ### NOTE: for XEmacs-20.* this will need to be changed to deal w/
1714 ;; char-tables !!! ###
1715 (gethash character strokes-char-value-hashtable)) ; (get-char-table
1716 ; character
1717 ; strokes-value-chartable)
1718
1719 (defun strokes-xpm-to-compressed-string (&optional xpm-buffer)
1720 "Convert the xpm in XPM-BUFFER into a compressed string representing the stroke.
1721 XPM-BUFFER is an optional argument, and defaults to `*strokes-xpm*'."
1722 (save-excursion
1723 (set-buffer (setq xpm-buffer (or xpm-buffer "*strokes-xpm*")))
1724 (goto-char (point-min))
1725 (search-forward "/* pixels */") ; skip past header junk
1726 (forward-char 2)
1727 ;; a note for below:
1728 ;; the `current-char' is the char being counted -- NOT the char at (point)
1729 ;; which happens to be called `char-at-point'
1730 (let ((compressed-string "+/") ; initialize the output
1731 (count 0) ; keep a current count of
1732 ; `current-char'
1733 (last-char-was-on-p t) ; last entered stream
1734 ; represented `on' bits
1735 (current-char-is-on-p nil) ; current stream represents `on' bits
1736 (char-at-point (char-after))) ; read the first char
1737 (while (not (char-equal char-at-point ?})) ; a `}' denotes the
1738 ; end of the pixmap
1739 (cond ((zerop count) ; must restart counting
1740 ;; check to see if the `char-at-point' is an actual pixmap bit
1741 (when (strokes-xpm-char-bit-p char-at-point)
1742 (setq count 1
1743 current-char-is-on-p (strokes-xpm-char-on-p char-at-point)))
1744 (forward-char 1))
1745 ((= count 61) ; maximum single char's
1746 ; encoding length
1747 (setq compressed-string (concat compressed-string
1748 ;; add a zero-length
1749 ;; encoding when
1750 ;; necessary
1751 (when (eq last-char-was-on-p
1752 current-char-is-on-p)
1753 ;; "0"
1754 (strokes-xpm-encode-length-as-string 0))
1755 (strokes-xpm-encode-length-as-string 61))
1756 last-char-was-on-p current-char-is-on-p
1757 count 0)) ; note that we just set
1758 ; count=0 and *don't* advance
1759 ; (point)
1760 ((strokes-xpm-char-bit-p char-at-point) ; an actual xpm bit
1761 (if (eq current-char-is-on-p
1762 (strokes-xpm-char-on-p char-at-point))
1763 ;; yet another of the same bit-type, so we continue
1764 ;; counting...
1765 (progn
1766 (incf count)
1767 (forward-char 1))
1768 ;; otherwise, it's the opposite bit-type, so we do a
1769 ;; write and then restart count ### NOTE (for myself
1770 ;; to be aware of) ### I really should advance
1771 ;; (point) in this case instead of letting another
1772 ;; iteration go through and letting the case: count=0
1773 ;; take care of this stuff for me. That's why
1774 ;; there's no (forward-char 1) below.
1775 (setq compressed-string (concat compressed-string
1776 ;; add a zero-length
1777 ;; encoding when
1778 ;; necessary
1779 (when (eq last-char-was-on-p
1780 current-char-is-on-p)
1781 ;; "0"
1782 (strokes-xpm-encode-length-as-string 0))
1783 (strokes-xpm-encode-length-as-string count))
1784 count 0
1785 last-char-was-on-p current-char-is-on-p)))
1786 (t ; ELSE it's some other useless
1787 ; char, like `"' or `,'
1788 (forward-char 1)))
1789 (setq char-at-point (char-after)))
1790 (concat compressed-string
1791 (when (> count 0)
1792 (concat (when (eq last-char-was-on-p
1793 current-char-is-on-p)
1794 ;; "0"
1795 (strokes-xpm-encode-length-as-string 0))
1796 (strokes-xpm-encode-length-as-string count)))
1797 "/"))))
1798
1799 (defun strokes-strokify-buffer (&optional buffer)
1800 "Decode stroke strings in BUFFER and display their corresponding glyphs.
1801 BUFFER defaults to the current buffer."
1802 (interactive)
1803 ;; (interactive "*bStrokify buffer: ")
1804 (save-excursion
1805 (set-buffer (or buffer (setq buffer (current-buffer))))
1806 (if (interactive-p)
1807 (message "Strokifying %s..." buffer))
1808 (goto-char (point-min))
1809 (let (ext string)
1810 ;; The comment below is what i'd have to do if I wanted to deal with
1811 ;; random newlines in the midst of the compressed strings.
1812 ;; If I do this, I'll also have to change `strokes-xpm-to-compress-string'
1813 ;; to deal with the newline, and possibly other whitespace stuff. YUCK!
1814 ;; (while (re-search-forward "\\+/\\(\\w\\|
1815 ;;\\)+/" nil t nil (get-buffer buffer))
1816 (while (re-search-forward "\\+/\\w+/" nil t nil (get-buffer buffer))
1817 (setq string (buffer-substring (+ 2 (match-beginning 0))
1818 (1- (match-end 0))))
1819 (strokes-xpm-for-compressed-string string " *strokes-xpm*")
1820 (replace-match " ")
1821 (setq ext (make-extent (1- (point)) (point)))
1822 (set-extent-property ext 'type 'stroke-glyph)
1823 (set-extent-property ext 'start-open t)
1824 (set-extent-property ext 'end-open t)
1825 (set-extent-property ext 'detachable t)
1826 (set-extent-property ext 'duplicable t)
1827 (set-extent-property ext 'data string)
1828 (set-extent-face ext 'strokes-char-face)
1829 (set-extent-end-glyph ext (make-glyph
1830 (list
1831 (vector 'xpm
1832 :data (buffer-substring
1833 (point-min " *strokes-xpm*")
1834 (point-max " *strokes-xpm*")
1835 " *strokes-xpm*"))
1836 [string :data "[Stroke]"])))))
1837 (if (interactive-p)
1838 (message "Strokifying %s...done" buffer))))
1839
1840 (defun strokes-unstrokify-buffer (&optional buffer)
1841 "Convert the glyphs in BUFFER to thier base-64 ASCII representations.
1842 BUFFER defaults to the current buffer"
1843 ;; ### NOTE !!! ### (for me)
1844 ;; 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
1846 ;; editing inside them. Plus, if you make them extents, you can
1847 ;; very easily just hide the glyphs, so if you unstrokify, and the
1848 ;; restrokify, then those that already are glyphed don't need to be
1849 ;; re-calculated, etc. It's just nicer that way. The only things
1850 ;; to worry about is cleanup (i.e. do the glyphs get gc'd when the
1851 ;; buffer is killed?
1852 ;; (interactive "*bUnstrokify buffer: ")
1853 (interactive)
1854 (save-excursion
1855 (set-buffer (setq buffer (or buffer (current-buffer))))
1856 ;; (map-extents
1857 ;; (lambda (ext buf)
1858 ;; (when (eq (extent-property ext 'type) 'stroke-glyph)
1859 ;; (goto-char (extent-start-position ext))
1860 ;; (delete-char 1) ; ### What the hell do I do here? ###
1861 ;; (insert "+/" (extent-property ext 'data) "/")
1862 ;; (delete-extent ext))))))
1863 (let (start)
1864 (map-extents
1865 (lambda (ext buf)
1866 (when (eq (extent-property ext 'type) 'stroke-glyph)
1867 (setq start (goto-char (extent-start-position ext)))
1868 ;; (insert "+/" (extent-property ext 'data) "/")
1869 (insert-string "+/")
1870 (insert-string (extent-property ext 'data))
1871 (insert-string "/")
1872 (delete-char 1)
1873 (set-extent-endpoints ext start (point))
1874 (set-extent-property ext 'type 'stroke-string)
1875 (set-extent-property ext 'atomic t)
1876 ;; (set-extent-property ext 'read-only t)
1877 (set-extent-face ext 'strokes-char-face)
1878 (set-extent-property ext 'stroke-glyph (extent-end-glyph ext))
1879 (set-extent-end-glyph ext nil)))))))
1880
1881 (defun strokes-xpm-for-compressed-string (compressed-string &optional bufname)
1882 "Convert the stroke represented by COMPRESSED-STRING into an xpm.
1883 Store xpm in buffer BUFNAME if supplied \(default is `*strokes-xpm*'\)"
1884 (save-excursion
1885 (or bufname (setq bufname "*strokes-xpm*"))
1886 (erase-buffer (set-buffer (get-buffer-create bufname)))
1887 (insert compressed-string)
1888 (goto-char (point-min))
1889 (let ((current-char-is-on-p nil))
1890 (while (not (eobp))
1891 (insert-char
1892 (if current-char-is-on-p
1893 ?*
1894 ?\ )
1895 (strokes-xpm-decode-char (char-after)))
1896 (delete-char 1)
1897 (setq current-char-is-on-p (not current-char-is-on-p)))
1898 (goto-char (point-min))
1899 (loop repeat 33 do
1900 (insert-char ?\")
1901 (forward-char 33)
1902 (insert "\",\n"))
1903 (goto-char (point-min))
1904 (insert strokes-xpm-header))))
1905
1906 (defun strokes-compose-complex-stroke ()
1907 (interactive "*")
1908 (let ((strokes-grid-resolution 33))
1909 (strokes-read-complex-stroke)
1910 (strokes-xpm-for-stroke nil nil t)
1911 (insert (strokes-xpm-to-compressed-string))
1912 (strokes-strokify-buffer)))
1913
1421 (provide 'strokes) 1914 (provide 'strokes)
1422 (run-hooks 'strokes-load-hook) 1915 (run-hooks 'strokes-load-hook)
1423 1916
1424 ;;; strokes.el ends here 1917 ;;; strokes.el ends here