Gaaah!
[wmaker-crm.git] / WINGs / wruler.c
blob4431c911e9c19a514dc9bc47201e996593fabd6b
1 /* WMRuler: nifty ruler widget for WINGs (OK, for WMText ;-) */
2 /* Copyleft (>) 1999, 2000 Nwanua Elumeze <nwanua@colorado.edu> */
5 #include "WINGsP.h"
7 #define MIN_DOC_WIDTH 10
9 typedef struct W_Ruler {
10 W_Class widgetClass;
11 W_View *view;
12 W_View *pview; /* the parent's view (for drawing the line) */
14 WMAction *moveAction; /* what to when while moving */
15 WMAction *releaseAction; /* what to do when released */
16 void *clientData;
18 GC fg, bg;
19 WMFont *font;
20 WMRulerMargins margins;
21 int offset;
22 int motion; /* the position of the _moving_ marker(s) */
23 int end; /* the last tick on the baseline (restrict markers to it) */
25 Pixmap drawBuffer;
27 struct {
28 unsigned int buttonPressed:1;
29 /* 0, 1, 2, 3, 4, 5, 6 */
30 unsigned int whichMarker:3; /* none, left, right, first, body, tabstop, both */
31 unsigned int RESERVED:28;
32 } flags;
33 } Ruler;
37 /* Marker for left margin
40 | \
41 |__\
46 static void
47 drawLeftMarker(Ruler *rPtr)
49 XPoint points[4];
50 int xpos = (rPtr->flags.whichMarker==1?
51 rPtr->motion:rPtr->margins.left);
53 XDrawLine(rPtr->view->screen->display, rPtr->drawBuffer,
54 rPtr->fg, xpos, 8, xpos, 22);
55 points[0].x = xpos;
56 points[0].y = 1;
57 points[1].x = points[0].x+6;
58 points[1].y = 8;
59 points[2].x = points[0].x+6;
60 points[2].y = 9;
61 points[3].x = points[0].x;
62 points[3].y = 9;
63 XFillPolygon (rPtr->view->screen->display, rPtr->drawBuffer,
64 rPtr->fg, points, 4, Convex, CoordModeOrigin);
68 /* Marker for right margin
71 / |
72 /__|
77 static void
78 drawRightMarker(Ruler *rPtr)
80 XPoint points[4];
81 int xpos = (rPtr->flags.whichMarker==2?
82 rPtr->motion:rPtr->margins.right);
84 XDrawLine(rPtr->view->screen->display, rPtr->drawBuffer,
85 rPtr->fg, xpos, 8, xpos, 22);
86 points[0].x = xpos+1;
87 points[0].y = 0;
88 points[1].x = points[0].x-6;
89 points[1].y = 7;
90 points[2].x = points[0].x-6;
91 points[2].y = 9;
92 points[3].x = points[0].x;
93 points[3].y = 9;
94 XFillPolygon (rPtr->view->screen->display, rPtr->drawBuffer,
95 rPtr->fg, points, 4, Convex, CoordModeOrigin);
99 /* Marker for first line only
100 _____
101 |___|
105 static void
106 drawFirstMarker(Ruler *rPtr)
108 int xpos = ((rPtr->flags.whichMarker==3 || rPtr->flags.whichMarker==6)?
109 rPtr->motion:rPtr->margins.first);
110 XFillRectangle(rPtr->view->screen->display, rPtr->drawBuffer,
111 rPtr->fg, xpos-5, 10, 11, 5);
112 XDrawLine(rPtr->view->screen->display, rPtr->drawBuffer,
113 rPtr->fg, xpos, 12, xpos, 22);
116 /* Marker for rest of body
117 _____
121 static void
122 drawBodyMarker(Ruler *rPtr)
124 XPoint points[4];
125 int xpos = ((rPtr->flags.whichMarker==4 || rPtr->flags.whichMarker==6)?
126 rPtr->motion:rPtr->margins.body);
127 points[0].x = xpos-5;
128 points[0].y = 16;
129 points[1].x = points[0].x+11;
130 points[1].y = 16;
131 points[2].x = points[0].x+5;
132 points[2].y = 22;
133 XFillPolygon (rPtr->view->screen->display, rPtr->drawBuffer,
134 rPtr->fg, points, 3, Convex, CoordModeOrigin);
138 static void
139 createDrawBuffer(Ruler *rPtr)
141 if(rPtr->drawBuffer)
142 XFreePixmap(rPtr->view->screen->display, rPtr->drawBuffer);
143 rPtr->drawBuffer = XCreatePixmap(rPtr->view->screen->display,
144 rPtr->view->window, rPtr->view->size.width, 40,
145 rPtr->view->screen->depth);
146 XFillRectangle(rPtr->view->screen->display, rPtr->drawBuffer,
147 rPtr->bg, 0, 0, rPtr->view->size.width, 40);
151 static void
152 drawRulerOnPixmap(Ruler *rPtr)
154 int i, j, w, m;
155 char c[3];
156 int marks[9] = {11, 3, 5, 3, 7, 3, 5, 3};
158 if(!rPtr->drawBuffer)
159 createDrawBuffer(rPtr);
161 XFillRectangle(rPtr->view->screen->display, rPtr->drawBuffer,
162 rPtr->bg, 0, 0, rPtr->view->size.width, 40);
164 WMDrawString(rPtr->view->screen, rPtr->drawBuffer, rPtr->fg,
165 rPtr->font, rPtr->margins.left+2, 26, "0 inches", 10);
167 /* marker ticks */
168 i=j=m=0;
169 w = rPtr->view->size.width - rPtr->margins.left;
170 while(m < w) {
171 XDrawLine(rPtr->view->screen->display, rPtr->drawBuffer,
172 rPtr->fg, rPtr->margins.left+m, 23,
173 rPtr->margins.left+m, marks[i%8]+23);
174 if(i!=0 && i%8==0) {
175 if(j<10)
176 snprintf(c,3,"%d",++j);
177 else
178 snprintf(c,3,"%2d",++j);
179 WMDrawString(rPtr->view->screen, rPtr->drawBuffer, rPtr->fg,
180 rPtr->font, rPtr->margins.left+2+m, 26, c, 2);
182 m = (++i)*10;
185 rPtr->end = rPtr->margins.left+m-10;
186 if(rPtr->margins.right > rPtr->end)
187 rPtr->margins.right = rPtr->end;
188 /* base line */
189 XDrawLine(rPtr->view->screen->display, rPtr->drawBuffer, rPtr->fg,
190 rPtr->margins.left, 22, rPtr->margins.left+m-10, 22);
192 drawLeftMarker(rPtr);
193 drawRightMarker(rPtr);
194 drawFirstMarker(rPtr);
195 drawBodyMarker(rPtr);
199 static void
200 paintRuler(Ruler *rPtr)
202 WMScreen *screen = rPtr->view->screen;
203 if(1||!rPtr->drawBuffer) {
204 drawRulerOnPixmap(rPtr);
207 XCopyArea(rPtr->view->screen->display, rPtr->drawBuffer,
208 rPtr->view->window, rPtr->bg, 0, 0, rPtr->view->size.width, 40,
209 0, 0);
213 static Bool
214 verifyMarkerMove(Ruler *rPtr, int x)
216 if(rPtr->flags.whichMarker<1 || rPtr->flags.whichMarker>6)
217 return False;
219 switch(rPtr->flags.whichMarker) {
220 case 1:
221 if(x > rPtr->margins.right - 10 || x < rPtr->offset ||
222 rPtr->margins.body + x > rPtr->margins.right-MIN_DOC_WIDTH ||
223 rPtr->margins.first + x > rPtr->margins.right-MIN_DOC_WIDTH)
224 return False;
225 break;
227 case 2:
228 if(x < rPtr->margins.first+MIN_DOC_WIDTH ||
229 x < rPtr->margins.body+MIN_DOC_WIDTH ||
230 x < rPtr->margins.left+MIN_DOC_WIDTH ||
231 x > rPtr->end) /*rPtr->view->size.width)*/
232 return False;
233 break;
235 case 3:
236 if(x >= rPtr->margins.right-MIN_DOC_WIDTH || x < rPtr->margins.left)
237 return False;
238 break;
240 case 4:
241 if(x >= rPtr->margins.right-MIN_DOC_WIDTH || x < rPtr->margins.left)
242 return False;
243 break;
245 case 6:
246 if(x >= rPtr->margins.right-MIN_DOC_WIDTH || x < rPtr->margins.left)
247 return False;
248 break;
250 default:
251 return False;
254 rPtr->motion = x;
255 return True;
259 static int
260 whichMarker(Ruler *rPtr, int x, int y)
262 if(x<rPtr->offset || y>22)
263 return 0;
265 if( rPtr->margins.left-x >= -6 && y <= 9
266 && (rPtr->margins.left-x <=0) && y>=4) {
267 rPtr->motion = rPtr->margins.left;
268 return 1;
271 if(rPtr->margins.right-x >= -1 && y <= 11
272 && rPtr->margins.right-x <=5 && y>=4) {
273 rPtr->motion = rPtr->margins.right;
274 return 2;
277 #if 0
278 /* both first and body? */
279 if( rPtr->margins.first-x <= 4 && rPtr->margins.first-x >= -5
280 && rPtr->margins.body-x <= 4 && rPtr->margins.body-x >= -5
281 && y>=15 && y<=17) {
282 rPtr->motion = rPtr->margins.first;
283 return 6;
285 #endif
287 if(rPtr->margins.first-x <= 4 && y<=15
288 && rPtr->margins.first-x >= -5 && y>=10) {
289 rPtr->motion = rPtr->margins.first;
290 return 3;
293 if( rPtr->margins.body-x <= 4 && y<=21 &&
294 rPtr->margins.body-x >= -5 && y>=17) {
295 rPtr->motion = rPtr->margins.body;
296 return 4;
300 /* do tabs (5)*/
303 return 0;
307 static void
308 handleEvents(XEvent *event, void *data)
310 Ruler *rPtr = (Ruler*)data;
311 Display *dpy = event->xany.display;
313 switch (event->type) {
314 case Expose:
315 paintRuler(rPtr);
316 break;
318 case MotionNotify:
319 if(rPtr->flags.buttonPressed
320 && (event->xmotion.state & Button1Mask)) {
321 if(verifyMarkerMove(rPtr, event->xmotion.x)){
322 GC gc = WMColorGC(WMDarkGrayColor(rPtr->view->screen));
323 paintRuler(rPtr);
324 if(rPtr->moveAction)
325 (rPtr->moveAction)(rPtr, rPtr->clientData);
326 XSetLineAttributes(rPtr->view->screen->display, gc, 1,
327 LineSolid, CapNotLast, JoinMiter);
328 XDrawLine(rPtr->pview->screen->display,
329 rPtr->pview->window,
330 gc, rPtr->motion+1, 40,
331 rPtr->motion+1, rPtr->pview->size.height-5);
334 break;
336 case ButtonPress:
337 if(event->xbutton.button != Button1)
338 return;
339 rPtr->flags.buttonPressed = True;
340 rPtr->flags.whichMarker =
341 whichMarker(rPtr, event->xmotion.x,
342 event->xmotion.y);
343 break;
345 case ButtonRelease:
346 if(event->xbutton.button != Button1)
347 return;
348 rPtr->flags.buttonPressed = False;
349 switch(rPtr->flags.whichMarker) {
350 case 1: {
351 int change = rPtr->margins.left-rPtr->motion;
352 rPtr->margins.first -=change;
353 rPtr->margins.body -= change;
354 rPtr->margins.left = rPtr->motion;
355 paintRuler(rPtr); break;
357 case 2: rPtr->margins.right = rPtr->motion; break;
358 case 3: rPtr->margins.first = rPtr->motion; break;
359 case 4: rPtr->margins.body = rPtr->motion; break;
360 case 6: rPtr->margins.first = rPtr->margins.body
361 = rPtr->motion; break;
363 if(rPtr->releaseAction)
364 (rPtr->releaseAction)(rPtr, rPtr->clientData);
365 break;
369 static void
370 rulerDidResize(W_ViewDelegate *self, WMView *view)
372 Ruler *rPtr = (Ruler *)view->self;
374 createDrawBuffer(rPtr);
375 paintRuler(rPtr);
380 W_ViewDelegate _RulerViewDelegate =
382 NULL,
383 NULL,
384 rulerDidResize,
385 NULL,
386 NULL
390 WMRuler *
391 WMCreateRuler(WMWidget *parent)
393 Ruler *rPtr = wmalloc(sizeof(Ruler));
394 unsigned int w = WMWidgetWidth(parent);
396 memset(rPtr, 0, sizeof(Ruler));
398 rPtr->widgetClass = WC_Ruler;
400 rPtr->view = W_CreateView(W_VIEW(parent));
401 if (!rPtr->view) {
402 free(rPtr);
403 return NULL;
405 rPtr->view->self = rPtr;
407 rPtr->drawBuffer = (Pixmap) NULL;
409 W_ResizeView(rPtr->view, w, 40);
411 WMCreateEventHandler(rPtr->view, ExposureMask|StructureNotifyMask
412 |EnterWindowMask|LeaveWindowMask|FocusChangeMask
413 |ButtonReleaseMask|ButtonPressMask|KeyReleaseMask
414 |KeyPressMask|Button1MotionMask, handleEvents, rPtr);
416 rPtr->view->delegate = &_RulerViewDelegate;
418 rPtr->bg = WMColorGC(WMGrayColor(rPtr->view->screen));
419 rPtr->fg = WMColorGC(WMBlackColor(rPtr->view->screen));
420 rPtr->font = WMSystemFontOfSize(rPtr->view->screen, 8);
422 rPtr->offset = 22;
423 rPtr->margins.left = 22;
424 rPtr->margins.body = 22;
425 rPtr->margins.first = 42;
426 rPtr->margins.right = (w<502?w:502);
428 rPtr->flags.whichMarker = 0; /* none */
429 rPtr->flags.buttonPressed = False;
431 rPtr->moveAction = NULL;
432 rPtr->releaseAction = NULL;
434 rPtr->pview = W_VIEW(parent);
436 return rPtr;
440 void
441 WMSetRulerMargins(WMRuler *rPtr, WMRulerMargins margins)
443 if(!rPtr)
444 return;
445 rPtr->margins.left = margins.left + rPtr->offset;
446 rPtr->margins.right = margins.right + rPtr->offset;
447 rPtr->margins.first = margins.first + rPtr->offset;
448 rPtr->margins.body = margins.body + rPtr->offset;
449 rPtr->margins.tabs = margins.tabs; /*for loop*/
450 paintRuler(rPtr);
455 WMRulerMargins
456 WMGetRulerMargins(WMRuler *rPtr)
458 WMRulerMargins margins;
460 if(!rPtr)
461 return margins;
463 margins.left = rPtr->margins.left - rPtr->offset;
464 margins.right = rPtr->margins.right - rPtr->offset;
465 margins.first = rPtr->margins.first - rPtr->offset;
466 margins.body = rPtr->margins.body - rPtr->offset;
467 /*for*/
468 margins.tabs = rPtr->margins.tabs;
470 return rPtr->margins;
474 void
475 WMSetRulerOffset(WMRuler *rPtr, int pixels)
477 if(!rPtr || pixels<0 || pixels+MIN_DOC_WIDTH>=rPtr->view->size.width)
478 return;
479 rPtr->offset = pixels;
480 /*rulerDidResize(rPtr, rPtr->view);*/
485 WMGetRulerOffset(WMRuler *rPtr)
487 if(!rPtr)
488 return;
489 return rPtr->offset;
493 void
494 WMSetRulerReleaseAction(WMRuler *rPtr, WMAction *action, void *clientData)
496 if(!rPtr)
497 return;
499 rPtr->releaseAction = action;
500 rPtr->clientData = clientData;
504 void
505 WMSetRulerMoveAction(WMRuler *rPtr, WMAction *action, void *clientData)
507 if(!rPtr)
508 return;
510 rPtr->moveAction = action;
511 rPtr->clientData = clientData;
515 /* _which_ one was released */
517 WMGetReleasedRulerMargin(WMRuler *rPtr)
519 if(!rPtr)
520 return 0;
521 return rPtr->flags.whichMarker;
525 /* _which_ one is being grabbed */
527 WMGetGrabbedRulerMargin(WMRuler *rPtr)
529 if(!rPtr)
530 return 0;
531 return rPtr->flags.whichMarker;