1 /*
2 Copyright (C) 2000-2001 Ulric Eriksson <ulric@siag.nu>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the Licence, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston,
17 MA 02111-1307, USA.
18 */
19
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <sys/stat.h>
24
25 #include <X11/IntrinsicP.h>
26 #include <X11/StringDefs.h>
27
28 #include "MwUtils.h"
29 #include "MwXutils.h"
30 #include <X11/xpm.h>
31
32 #include "MwTabstopP.h"
33
34 static float floatOne = 1.0;
35
36 #define offset(field) XtOffsetOf(MwTabstopRec, mwTabstop.field)
37 static XtResource resources[] = {
38 {
39 XtNleftMargin,
40 XtCLeftMargin,
41 XtRInt,
42 sizeof(int),
43 offset(left_margin),
44 XtRImmediate,
45 (XtPointer)72
46 }, {
47 XtNrightMargin,
48 XtCRightMargin,
49 XtRInt,
50 sizeof(int),
51 offset(right_margin),
52 XtRImmediate,
53 (XtPointer)72
54 }, {
55 XtNpaperWidth,
56 XtCPaperWidth,
57 XtRInt,
58 sizeof(int),
59 offset(paper_width),
60 XtRImmediate,
61 (XtPointer)595
62 }, {
63 XtNtabstopTopCol,
64 XtCTabstopTopCol,
65 XtRInt,
66 sizeof(int),
67 offset(top_col),
68 XtRImmediate,
69 (XtPointer)0
70 }, {
71 XtNzoom,
72 XtCZoom,
73 XtRFloat,
74 sizeof(float),
75 offset(zoom),
76 XtRFloat,
77 (XtPointer)&floatOne
78 }, {
79 XtNfont,
80 XtCFont,
81 XtRFontStruct,
82 sizeof(XFontStruct *),
83 offset(font),
84 XtRString,
85 XtDefaultFont
86 }, {
87 XtNtabs,
88 XtCTabs,
89 XtRString,
90 sizeof(String),
91 offset(tabs),
92 XtRImmediate,
93 (XtPointer)0
94 }, {
95 XtNcallback,
96 XtCCallback,
97 XtRCallback,
98 sizeof(XtPointer),
99 offset(callbacks),
100 XtRCallback,
101 (XtPointer)NULL
102 }
103 };
104 #undef offset
105
106 /* methods */
107 static void Realize(Widget w, XtValueMask *, XSetWindowAttributes *);
108 static void Redisplay(Widget, XEvent *, Region);
109 static Boolean SetValues(Widget, Widget, Widget, ArgList, Cardinal *);
110
111 /* actions */
112 static void Notify(Widget, XEvent *, String *, Cardinal *);
113 static void DeleteTab(Widget, XEvent *, String *, Cardinal *);
114 static void AddTab(Widget, XEvent *, String *, Cardinal *);
115
116 static XtActionsRec actions[] =
117 {
118 {"notify", Notify},
119 {"add_tab", AddTab},
120 {"delete_tab", DeleteTab},
121 };
122
123 /* translations */
124 static char translations[] =
125 "Shift<Btn1Down>: delete_tab() notify()\n"
126 ":<Btn1Down>: add_tab(l) notify()\n"
127 ":<Btn2Down>: add_tab(c) notify()\n"
128 ":<Btn3Down>: add_tab(r) notify()\n"
129 ;
130
131 MwTabstopClassRec mwTabstopClassRec = {
132 { /* core fields */
133 /* superclass */ (WidgetClass) &widgetClassRec,
134 /* class_name */ "MwTabstop",
135 /* widget_size */ sizeof(MwTabstopRec),
136 /* class_initialize */ NULL,
137 /* class_part_initialize */ NULL,
138 /* class_inited */ FALSE,
139 /* initialize */ NULL,
140 /* initialize_hook */ NULL,
141 /* realize */ Realize,
142 /* actions */ actions,
143 /* num_actions */ XtNumber(actions),
144 /* resources */ resources,
145 /* num_resources */ XtNumber(resources),
146 /* xrm_class */ NULLQUARK,
147 /* compress_motion */ TRUE,
148 /* compress_exposure */ TRUE,
149 /* compress_enterleave */ TRUE,
150 /* visible_interest */ FALSE,
151 /* destroy */ NULL,
152 /* resize */ NULL,
153 /* expose */ Redisplay,
154 /* set_values */ SetValues,
155 /* set_values_hook */ NULL,
156 /* set_values_almost */ XtInheritSetValuesAlmost,
157 /* get_values_hook */ NULL,
158 /* accept_focus */ NULL,
159 /* version */ XtVersion,
160 /* callback_private */ NULL,
161 /* tm_table */ translations,
162 /* query_geometry */ XtInheritQueryGeometry,
163 /* display_accelerator */ XtInheritDisplayAccelerator,
164 /* extension */ NULL
165 },
166 { /* mwTabstop fields */
167 /* empty */ 0
168 }
169 };
170
171 WidgetClass mwTabstopWidgetClass = (WidgetClass)&mwTabstopClassRec;
172
173
MwTabstopNextStop(Widget w,int t)174 MwTabstop MwTabstopNextStop(Widget w, int t)
175 {
176 MwTabstopWidget rw = (MwTabstopWidget)w;
177 if (w == None) return MwNextTab(NULL, t+1);
178 return MwNextTab(rw->mwTabstop.tt, t);
179 }
180
Notify(Widget w,XEvent * event,String * params,Cardinal * n)181 static void Notify(Widget w, XEvent *event, String *params, Cardinal *n)
182 {
183 MwTabstopWidget rw = (MwTabstopWidget)w;
184 XtCallCallbackList(w, rw->mwTabstop.callbacks, (XtPointer)rw->mwTabstop.tabs);
185 }
186
DeleteTab(Widget w,XEvent * event,String * params,Cardinal * n)187 static void DeleteTab(Widget w, XEvent *event, String *params, Cardinal *n)
188 {
189 MwTabstopWidget rw = (MwTabstopWidget)w;
190 float zoom = rw->mwTabstop.zoom;
191 int lm = rw->mwTabstop.left_margin, tc = rw->mwTabstop.top_col, ps = lm-tc+1;
192 int x = (event->xbutton.x)/zoom-ps;
193 int i;
194 char *p = rw->mwTabstop.tabs;
195 MwTabstop *tt = rw->mwTabstop.tt;
196 /* no need to reallocate the tab string */
197 for (i = 0; tt[i].j && tt[i].x < x; i++) {
198 sprintf(p, "%c%d ", tt[i].j, tt[i].x);
199 p += strlen(p);
200 }
201 if (tt[i].j) i++;
202 while (tt[i].j) {
203 sprintf(p, "%c%d ", tt[i].j, tt[i].x);
204 p += strlen(p);
205 i++;
206 }
207 MwFree(rw->mwTabstop.tt);
208 rw->mwTabstop.tt = MwGetTabs(rw->mwTabstop.tabs);
209 XClearWindow(XtDisplay(w), XtWindow(w));
210 Redisplay(w, NULL, None);
211 }
212
AddTab(Widget w,XEvent * event,String * params,Cardinal * n)213 static void AddTab(Widget w, XEvent *event, String *params, Cardinal *n)
214 {
215 MwTabstopWidget rw = (MwTabstopWidget)w;
216 float zoom = rw->mwTabstop.zoom;
217 int lm = rw->mwTabstop.left_margin, tc = rw->mwTabstop.top_col, ps = lm-tc+1;
218 int x = (event->xbutton.x)/zoom-ps;
219 int i;
220 char *p;
221 MwTabstop *tt = rw->mwTabstop.tt;
222
223 p = MwMalloc(strlen(rw->mwTabstop.tabs)+10);
224 MwFree(rw->mwTabstop.tabs);
225 rw->mwTabstop.tabs = p;
226 for (i = 0; tt[i].j && tt[i].x < x; i++) {
227 sprintf(p, "%c%d ", tt[i].j, tt[i].x);
228 p += strlen(p);
229 }
230 sprintf(p, "%c%d ", params[0][0], x);
231 p += strlen(p);
232 while (tt[i].j) {
233 sprintf(p, "%c%d ", tt[i].j, tt[i].x);
234 p += strlen(p);
235 i++;
236 }
237 MwFree(rw->mwTabstop.tt);
238 rw->mwTabstop.tt = MwGetTabs(rw->mwTabstop.tabs);
239 XClearWindow(XtDisplay(w), XtWindow(w));
240 Redisplay(w, NULL, None);
241 }
242
243 #define superclass (&coreClassRec)
244
Realize(Widget w,XtValueMask * v,XSetWindowAttributes * a)245 static void Realize(Widget w, XtValueMask *v, XSetWindowAttributes *a)
246 {
247 MwTabstopWidget rw = (MwTabstopWidget)w;
248 unsigned long mask = 0;
249 XGCValues values;
250 Display *dpy = XtDisplay(w);
251 unsigned long grey;
252 (*superclass->core_class.realize)(w, v, a);
253 values.font = rw->mwTabstop.font->fid;
254 mask = GCFont;
255 rw->mwTabstop.gc = XCreateGC(dpy, XtWindow(w), mask, &values);
256 if (rw->mwTabstop.tabs == NULL) {
257 rw->mwTabstop.tabs = MwStrdup("l36 l72 l108 l144 l180 l216 "
258 "l252 l288 l324 l360 l396 l432");
259 rw->mwTabstop.tt = MwGetTabs(rw->mwTabstop.tabs);
260 }
261 XtVaGetValues(w, XtNbackground, &grey, (char *)0);
262 rw->mwTabstop.ctab = MwLoadPixmap(dpy, grey, "ctab.xpm");
263 rw->mwTabstop.ltab = MwLoadPixmap(dpy, grey, "ltab.xpm");
264 rw->mwTabstop.rtab = MwLoadPixmap(dpy, grey, "rtab.xpm");
265 }
266
Redisplay(Widget w,XEvent * event,Region r)267 static void Redisplay(Widget w, XEvent *event, Region r)
268 {
269 MwTabstopWidget aw = (MwTabstopWidget)w;
270 int h = aw->core.height;
271 int w1 = aw->core.width;
272 Display *dpy = XtDisplay(w);
273 Screen *s = XtScreen(w);
274 Window wi = XtWindow(w);
275 int i, o, x;
276 GC gc = aw->mwTabstop.gc;
277 unsigned long black = BlackPixelOfScreen(s);
278 unsigned long white = WhitePixelOfScreen(s);
279 float zoom = aw->mwTabstop.zoom;
280 int pw = aw->mwTabstop.paper_width,
281 lm = aw->mwTabstop.left_margin, rm = aw->mwTabstop.right_margin,
282 tc = aw->mwTabstop.top_col, ps = lm-tc+1, pe = pw-rm-tc, in;
283 Pixmap pm;
284 Pixmap scribble;
285
286 scribble = XCreatePixmap(dpy, wi, w1, h, aw->core.depth);
287 if (scribble == None) return;
288
289 XSetForeground(dpy, gc, aw->core.background_pixel);
290 XFillRectangle(dpy, scribble, gc, 0, 0, w1, h);
291
292 XSetForeground(dpy, gc, white);
293
294 XFillRectangle(dpy, scribble, gc, zoom*ps, 5, zoom*(pw-lm-rm), h-10);
295 o = -1;
296
297 XSetForeground(dpy, gc, black);
298
299 /* draw tab stops */
300 if (aw->mwTabstop.tt == NULL) aw->mwTabstop.tt = MwGetTabs(aw->mwTabstop.tabs);
301 for (i = 0; aw->mwTabstop.tt[i].j; i++) {
302 switch (aw->mwTabstop.tt[i].j) {
303 case 'c': pm = aw->mwTabstop.ctab; break;
304 case 'r': pm = aw->mwTabstop.rtab; break;
305 default: pm = aw->mwTabstop.ltab; break;
306 }
307
308 x = aw->mwTabstop.tt[i].x;
309 XCopyArea(dpy, pm, scribble, gc, 0, 0, 9, 5,
310 zoom*(ps+x)-4+o, h-5);
311 }
312
313 /* draw half inch markers */
314 for (i = ps+36; i < pe; i += 72) {
315 XDrawLine(dpy, scribble, gc, zoom*i+o, 9, zoom*i+o, h-10);
316 }
317
318 /* draw inch numbers */
319 for (i = ps+72, in = 1; i < pe; i += 72, in++) {
320 char num[10];
321 int nw;
322 sprintf(num, "%d", in);
323 nw = XTextWidth(aw->mwTabstop.font, num, strlen(num));
324 XDrawString(dpy, scribble, gc, zoom*i-nw/2, h-9, num, strlen(num));
325 }
326 XDrawLine(dpy, scribble, gc, zoom*-tc, 0, zoom*-tc, h-1);
327 XDrawLine(dpy, scribble, gc, zoom*(pw-tc-1), 0, zoom*(pw-tc-1), h-1);
328 XDrawLine(dpy, scribble, gc, 0, 0, 0, h-1);
329 XDrawLine(dpy, scribble, gc, 0, 0, w1-1, 0);
330 XDrawLine(dpy, scribble, gc, 0, h-1, w1-1, h-1);
331 XDrawLine(dpy, scribble, gc, w1-1, 0, w1-1, h-1);
332
333 XCopyArea(dpy, scribble, wi, gc, 0, 0, w1, h, 0, 0);
334 XFreePixmap(dpy, scribble);
335 }
336
SetValues(Widget current,Widget request,Widget new,ArgList args,Cardinal * nargs)337 static Boolean SetValues(Widget current, Widget request, Widget new,
338 ArgList args, Cardinal *nargs)
339 {
340 MwTabstopWidget rw1 = (MwTabstopWidget)current;
341 MwTabstopWidget rw2 = (MwTabstopWidget)new;
342 Boolean do_redisplay =
343 (rw1->mwTabstop.tabs != rw2->mwTabstop.tabs)
344 || strcmp(rw1->mwTabstop.tabs, rw2->mwTabstop.tabs)
345 || (rw1->mwTabstop.zoom != rw2->mwTabstop.zoom)
346 || (rw1->mwTabstop.top_col != rw2->mwTabstop.top_col)
347 || (rw1->mwTabstop.left_margin != rw2->mwTabstop.left_margin)
348 || (rw1->mwTabstop.right_margin != rw2->mwTabstop.right_margin)
349 || (rw1->mwTabstop.paper_width != rw2->mwTabstop.paper_width);
350 if (rw1->mwTabstop.tabs != rw2->mwTabstop.tabs) {
351 MwFree(rw1->mwTabstop.tabs);
352 rw2->mwTabstop.tabs = MwStrdup(rw2->mwTabstop.tabs);
353 MwFree(rw1->mwTabstop.tt);
354 rw2->mwTabstop.tt = MwGetTabs(rw2->mwTabstop.tabs);
355 }
356
357 return do_redisplay;
358 }
359
MwTabstopSetZoom(Widget w,float zoom)360 void MwTabstopSetZoom(Widget w, float zoom)
361 {
362 MwTabstopWidget rw = (MwTabstopWidget)w;
363
364 if (zoom < .1) zoom = .1;
365 if (zoom > 10) zoom = 10;
366 if (zoom != rw->mwTabstop.zoom) {
367 rw->mwTabstop.zoom = zoom;
368 XClearWindow(XtDisplay(w), XtWindow(w));
369 Redisplay(w, NULL, None);
370 }
371 }
372
MwGetTabs(char * p)373 MwTabstop *MwGetTabs(char *p)
374 {
375 char *q;
376 MwTabstop *tt;
377 int i = 0;
378
379 p = MwStrdup(p);
380 tt = MwMalloc((strlen(p)/3+1)*sizeof *tt);
381 for (q = strtok(p, " "); q; q = strtok(NULL, " ")) {
382 tt[i].j = q[0];
383 tt[i].x = atoi(q+1);
384 i++;
385 }
386 tt[i].j = 0;
387 MwFree(p);
388 return tt;
389 }
390
MwNextTab(MwTabstop * tt,int t)391 MwTabstop MwNextTab(MwTabstop *tt, int t)
392 {
393 int i;
394 MwTabstop def = {'l', 0};
395
396 for (i = 0; tt && tt[i].j; i++)
397 if (tt[i].x > t) return tt[i];
398 def.x = t;
399 return def;
400 }
401
402