AmendHub

Download

jcs

/

subtext

/

tetab.c

 

(View History)

jcs   tetab: Remove, no longer needed Latest amendment: 567 on 2023-11-28

1 /*
2 * Copyright (c) 2021 joshua stein <jcs@jcs.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 /*
18 * Implements tab spacing in TextEdit controls with a fixed-width font.
19 * Only works on styled TextEdit controls (created with TEStylNew) and
20 * assumes that functions get called with a text buffer that starts at the
21 * beginning of the line.
22 *
23 * Usage is per-TextEdit control, so these hooks need to be established
24 * on all controls where tabs should be expanded:
25 *
26 * TEHandle te;
27 * ProcPtr teproc;
28 *
29 * [..]
30 * te = TEStylNew(&bounds, &bounds);
31 * TEAutoView(true, te);
32 * TETabEnable(te);
33 *
34 * The tab width is set to 4 by default in the TETabWidth global.
35 *
36 * Thanks to Ari Halberstadt for their 1989 Usenet post on
37 * comp.sys.mac.programmer with HitTestHook assembly.
38 */
39
40 #include <Script.h>
41 #include <SetUpA4.h>
42
43 #include "tetab.h"
44
45 pascal void TETabDrawHook(void);
46 pascal void TETabWidthHook(void);
47 pascal void TETabHitTestHook(void);
48
49 short TETabWidth = 4;
50
51 void
52 TETabEnable(TEHandle te)
53 {
54 ProcPtr teproc;
55
56 TEAutoView(true, te);
57 teproc = StripAddress(TETabWidthHook);
58 TECustomHook(intWidthHook, &teproc, te);
59 teproc = StripAddress(TETabDrawHook);
60 TECustomHook(intDrawHook, &teproc, te);
61 teproc = StripAddress(TETabHitTestHook);
62 TECustomHook(intHitTestHook, &teproc, te);
63 }
64
65 pascal void
66 TETabDrawHook(void)
67 {
68 /* entry registers, in order */
69 short offset;
70 short length;
71 Ptr text;
72
73 /* locals */
74 short i, cwidth, cpos, space, startdraw;
75 char c;
76
77 asm {
78 movem.l d3-d7/a0-a3, -(a7)
79 move.w d0, offset
80 move.w d1, length
81 move.l a0, text
82 }
83 SetUpA4();
84
85 cwidth = CharWidth(' ');
86
87 /*
88 * This startdraw stuff is to try to draw long blocks of non-tab text
89 * with one call to DrawText() instead of DrawChar()ing every character
90 * one at a time, for speed.
91 */
92 for (i = 0, cpos = 0, startdraw = 0; i < length; i++) {
93 c = text[offset + i];
94
95 if (c == '\t') {
96 if (i - startdraw)
97 DrawText(text, startdraw, i - startdraw);
98
99 space = (TETabWidth - (cpos % TETabWidth));
100 if (!space)
101 space = TETabWidth;
102 cpos += space;
103 Move(cwidth * space, 0);
104 startdraw = i + 1;
105 } else {
106 cpos++;
107 }
108 }
109
110 if (startdraw != i)
111 DrawText(text, startdraw, i - startdraw);
112
113 /* return nothing */
114
115 /* restore registers */
116 RestoreA4();
117 asm {
118 movem.l (a7)+, d3-d7/a0-a3
119 }
120 }
121
122 pascal void
123 TETabWidthHook(void)
124 {
125 /* entry registers, in order */
126 short length;
127 short offset;
128 Ptr text;
129
130 /* exit */
131 short width;
132
133 short i, cwidth, cpos, space;
134 char c;
135
136 asm {
137 movem.l d3-d7/a0-a3, -(a7)
138 move.w d0, length
139 move.w d1, offset
140 move.l a0, text
141 }
142 SetUpA4();
143
144 cwidth = CharWidth(' ');
145
146 for (i = 0, cpos = 0; i < length; i++) {
147 c = text[offset + i];
148
149 if (c == '\t') {
150 space = (TETabWidth - (cpos % TETabWidth));
151 if (!space)
152 space = TETabWidth;
153 cpos += space;
154 } else {
155 cpos++;
156 }
157 }
158
159 width = cwidth * cpos;
160
161 /* return length */
162 asm {
163 move.w width, d1
164 }
165
166 /* restore registers */
167 RestoreA4();
168 asm {
169 movem.l (a7)+, d3-d7/a0-a3
170 }
171 }
172
173 pascal void
174 TETabHitTestHook(void)
175 {
176 /* entry registers, in order */
177 short length;
178 short poffset;
179 Ptr text;
180
181 /* exit */
182 short width;
183 short offset = 0;
184 short leftside = 0;
185
186 /* locals */
187 short i, cwidth, cpos, wpos, space, found;
188 char c;
189
190 asm {
191 movem.l d3-d7/a0-a3, -(a7)
192 move.w d0, length
193 move.w d1, poffset
194 move.l a0, text
195 }
196 SetUpA4();
197
198 cwidth = CharWidth(' ');
199
200 for (i = 0, wpos = 0, cpos = 0, found = 0; i < length; i++) {
201 c = text[i];
202
203 if (c == '\t') {
204 space = (TETabWidth - (wpos % TETabWidth));
205 if (!space)
206 space = TETabWidth;
207 wpos += space;
208 } else if (c == '\r')
209 break;
210 else
211 wpos++;
212
213 cpos++;
214
215 if (poffset <= (wpos * cwidth)) {
216 found = 1;
217 cpos++;
218 break;
219 }
220 }
221
222 /* put found in hi word */
223 width = (wpos * cwidth) | (found << 8);
224 offset = cpos;
225 leftside = (poffset < (width - (cwidth / 2)));
226
227 asm {
228 move.w width, d0
229 move.w offset, d1
230 move.w leftside, d2
231 }
232
233 /* restore registers */
234 RestoreA4();
235 asm {
236 movem.l (a7)+, d3-d7/a0-a3
237 }
238 }