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