- API change in WINGs for WMDraw*String().
[wmaker-crm.git] / WINGs / wruler.c
blob4b3b935e70f079d0235af0a2334475bf84e31ef7
1 /*
2 * WINGs WMRuler: nifty ruler widget for WINGs :-)
4 * Copyright (c) 1999-2000 Nwanua Elumeze
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "WINGsP.h"
23 #include "wconfig.h"
25 #define MIN_DOC_WIDTH 10
27 typedef struct W_Ruler {
28 W_Class widgetClass;
29 W_View *view;
30 W_View *pview; /* the parent's view (for drawing the line) */
32 WMAction *moveAction; /* what to when while moving */
33 WMAction *releaseAction; /* what to do when released */
34 void *clientData;
36 WMColor *fg;
37 GC fgGC, bgGC;
38 WMFont *font;
39 WMRulerMargins margins;
40 int offset;
41 int motion; /* the position of the _moving_ marker(s) */
42 int end; /* the last tick on the baseline (restrict markers to it) */
44 Pixmap drawBuffer;
46 struct {
47 unsigned int whichMarker:3;
48 /* 0, 1, 2, 3, 4, 5, 6 */
49 /* none, left, right, first, body, tabstop, first & body */
51 unsigned int buttonPressed:1;
52 unsigned int redraw:1;
53 unsigned int RESERVED:27;
54 } flags;
55 } Ruler;
59 /* Marker for left margin
62 | \
63 |__\
68 static void
69 drawLeftMarker(Ruler * rPtr)
71 XPoint points[4];
72 int xpos = (rPtr->flags.whichMarker==1 ? rPtr->motion : rPtr->margins.left);
74 XDrawLine(rPtr->view->screen->display, rPtr->drawBuffer, rPtr->fgGC,
75 xpos, 8, xpos, 22);
76 points[0].x = xpos;
77 points[0].y = 1;
78 points[1].x = points[0].x + 6;
79 points[1].y = 8;
80 points[2].x = points[0].x + 6;
81 points[2].y = 9;
82 points[3].x = points[0].x;
83 points[3].y = 9;
84 XFillPolygon(rPtr->view->screen->display, rPtr->drawBuffer, rPtr->fgGC,
85 points, 4, Convex, CoordModeOrigin);
89 /* Marker for right margin
92 / |
93 /__|
98 static void drawRightMarker(Ruler * rPtr)
100 XPoint points[4];
101 int xpos = (rPtr->flags.whichMarker==2 ? rPtr->motion : rPtr->margins.right);
103 XDrawLine(rPtr->view->screen->display, rPtr->drawBuffer, rPtr->fgGC,
104 xpos, 8, xpos, 22);
105 points[0].x = xpos + 1;
106 points[0].y = 0;
107 points[1].x = points[0].x - 6;
108 points[1].y = 7;
109 points[2].x = points[0].x - 6;
110 points[2].y = 9;
111 points[3].x = points[0].x;
112 points[3].y = 9;
113 XFillPolygon(rPtr->view->screen->display, rPtr->drawBuffer, rPtr->fgGC,
114 points, 4, Convex, CoordModeOrigin);
118 /* Marker for first line only
119 _____
120 |___|
124 static void drawFirstMarker(Ruler * rPtr)
126 int xpos = ((rPtr->flags.whichMarker == 3 || rPtr->flags.whichMarker == 6) ?
127 rPtr->motion : rPtr->margins.first);
129 XFillRectangle(rPtr->view->screen->display, rPtr->drawBuffer, rPtr->fgGC,
130 xpos - 5, 10, 11, 5);
131 XDrawLine(rPtr->view->screen->display, rPtr->drawBuffer, rPtr->fgGC,
132 xpos, 12, xpos, 22);
135 /* Marker for rest of body
136 _____
140 static void drawBodyMarker(Ruler * rPtr)
142 XPoint points[4];
143 int xpos = ((rPtr->flags.whichMarker == 4 || rPtr->flags.whichMarker == 6) ?
144 rPtr->motion : rPtr->margins.body);
146 points[0].x = xpos - 5;
147 points[0].y = 16;
148 points[1].x = points[0].x + 11;
149 points[1].y = 16;
150 points[2].x = points[0].x + 5;
151 points[2].y = 22;
152 XFillPolygon(rPtr->view->screen->display, rPtr->drawBuffer, rPtr->fgGC,
153 points, 3, Convex, CoordModeOrigin);
157 static void createDrawBuffer(Ruler * rPtr)
159 if(!rPtr->view->flags.realized)
160 return;
162 if (rPtr->drawBuffer)
163 XFreePixmap(rPtr->view->screen->display, rPtr->drawBuffer);
165 rPtr->drawBuffer = XCreatePixmap(rPtr->view->screen->display,
166 rPtr->view->window, rPtr->view->size.width, 40,
167 rPtr->view->screen->depth);
168 XFillRectangle(rPtr->view->screen->display, rPtr->drawBuffer,
169 rPtr->bgGC, 0, 0, rPtr->view->size.width, 40);
173 static void drawRulerOnPixmap(Ruler * rPtr)
175 int i, j, w, m;
176 char c[3];
177 int marks[9] = {11, 3, 5, 3, 7, 3, 5, 3};
179 if (!rPtr->drawBuffer || !rPtr->view->flags.realized)
180 return;
183 XFillRectangle(rPtr->view->screen->display, rPtr->drawBuffer,
184 rPtr->bgGC, 0, 0, rPtr->view->size.width, 40);
186 WMDrawString(rPtr->view->screen, rPtr->drawBuffer, rPtr->fg,
187 rPtr->font, rPtr->margins.left + 2, 26, _("0 inches"), 10);
189 /* marker ticks */
190 i = j = m = 0;
191 w = rPtr->view->size.width - rPtr->margins.left;
192 while (m < w) {
193 XDrawLine(rPtr->view->screen->display, rPtr->drawBuffer,
194 rPtr->fgGC, rPtr->margins.left + m, 23,
195 rPtr->margins.left + m, marks[i % 8] + 23);
196 if (i != 0 && i % 8 == 0) {
197 if (j < 10)
198 snprintf(c, 3, "%d", ++j);
199 else
200 snprintf(c, 3, "%2d", ++j);
201 WMDrawString(rPtr->view->screen, rPtr->drawBuffer, rPtr->fg,
202 rPtr->font, rPtr->margins.left + 2 + m, 26, c, 2);
204 m = (++i) * 10;
207 rPtr->end = rPtr->margins.left + m - 10;
208 if (rPtr->margins.right > rPtr->end)
209 rPtr->margins.right = rPtr->end;
210 /* base line */
211 XDrawLine(rPtr->view->screen->display, rPtr->drawBuffer, rPtr->fgGC,
212 rPtr->margins.left, 22, rPtr->margins.left + m - 10, 22);
214 drawLeftMarker(rPtr);
215 drawRightMarker(rPtr);
216 drawFirstMarker(rPtr);
217 drawBodyMarker(rPtr);
219 rPtr->flags.redraw = False;
223 static void paintRuler(Ruler * rPtr)
225 if (!rPtr->drawBuffer || !rPtr->view->flags.realized)
226 return;
228 if (rPtr->flags.redraw)
229 drawRulerOnPixmap(rPtr);
230 XCopyArea(rPtr->view->screen->display, rPtr->drawBuffer,
231 rPtr->view->window, rPtr->bgGC, 0, 0,
232 rPtr->view->size.width, 40, 0, 0);
236 static Bool
237 verifyMarkerMove(Ruler * rPtr, int x)
239 if (rPtr->flags.whichMarker < 1 || rPtr->flags.whichMarker > 6)
240 return False;
242 switch (rPtr->flags.whichMarker) {
243 case 1:
244 if (x > rPtr->margins.right - 10 || x < rPtr->offset ||
245 rPtr->margins.body + x > rPtr->margins.right - MIN_DOC_WIDTH ||
246 rPtr->margins.first + x > rPtr->margins.right - MIN_DOC_WIDTH)
247 return False;
248 break;
250 case 2:
251 if (x < rPtr->margins.first + MIN_DOC_WIDTH ||
252 x < rPtr->margins.body + MIN_DOC_WIDTH ||
253 x < rPtr->margins.left + MIN_DOC_WIDTH ||
254 x > rPtr->end) /*rPtr->view->size.width) */
255 return False;
256 break;
258 case 3:
259 if (x >= rPtr->margins.right - MIN_DOC_WIDTH || x < rPtr->margins.left)
260 return False;
261 break;
263 case 4:
264 if (x >= rPtr->margins.right - MIN_DOC_WIDTH || x < rPtr->margins.left)
265 return False;
266 break;
268 case 6:
269 if (x >= rPtr->margins.right - MIN_DOC_WIDTH || x < rPtr->margins.left)
270 return False;
271 break;
273 default:
274 return False;
277 rPtr->motion = x;
278 return True;
282 static int whichMarker(Ruler * rPtr, int x, int y)
284 if (x < rPtr->offset || y > 22)
285 return 0;
287 if (rPtr->margins.left - x >= -6 && y <= 9
288 && (rPtr->margins.left - x <= 0) && y >= 4) {
289 rPtr->motion = rPtr->margins.left;
290 return 1;
292 if (rPtr->margins.right - x >= -1 && y <= 11
293 && rPtr->margins.right - x <= 5 && y >= 4) {
294 rPtr->motion = rPtr->margins.right;
295 return 2;
297 #if 0
298 /* both first and body? */
299 if (rPtr->margins.first - x <= 4 && rPtr->margins.first - x >= -5
300 && rPtr->margins.body - x <= 4 && rPtr->margins.body - x >= -5
301 && y >= 15 && y <= 17) {
302 rPtr->motion = rPtr->margins.first;
303 return 6;
305 #endif
307 if (rPtr->margins.first - x <= 4 && y <= 15
308 && rPtr->margins.first - x >= -5 && y >= 10) {
309 rPtr->motion = rPtr->margins.first;
310 return 3;
312 if (rPtr->margins.body - x <= 4 && y <= 21 &&
313 rPtr->margins.body - x >= -5 && y >= 17) {
314 rPtr->motion = rPtr->margins.body;
315 return 4;
317 /* do tabs (5) */
320 return 0;
323 static void rulerDidResize(W_ViewDelegate * self, WMView * view)
325 Ruler *rPtr = (Ruler *) view->self;
327 createDrawBuffer(rPtr);
328 rPtr->flags.redraw = True;
329 paintRuler(rPtr);
334 static void handleEvents(XEvent * event, void *data)
336 Ruler *rPtr = (Ruler *) data;
338 switch (event->type) {
339 case Expose:
340 rulerDidResize(rPtr->view->delegate, rPtr->view);
341 break;
343 case MotionNotify:
344 if (rPtr->flags.buttonPressed
345 && (event->xmotion.state & Button1Mask)) {
346 if (verifyMarkerMove(rPtr, event->xmotion.x)) {
347 GC gc = WMColorGC(WMDarkGrayColor(rPtr->view->screen));
349 if (rPtr->moveAction)
350 (rPtr->moveAction) (rPtr, rPtr->clientData);
351 rPtr->flags.redraw = True;
352 paintRuler(rPtr);
353 XSetLineAttributes(rPtr->view->screen->display, gc, 1,
354 LineSolid, CapNotLast, JoinMiter);
355 XDrawLine(rPtr->pview->screen->display,
356 rPtr->pview->window,
357 gc, rPtr->motion + 1, 40,
358 rPtr->motion + 1, rPtr->pview->size.height - 5);
361 break;
363 case ButtonPress:
364 if (event->xbutton.button != Button1)
365 return;
366 rPtr->flags.buttonPressed = True;
367 rPtr->flags.whichMarker =
368 whichMarker(rPtr, event->xmotion.x,
369 event->xmotion.y);
370 break;
372 case ButtonRelease:
373 if (event->xbutton.button != Button1)
374 return;
375 rPtr->flags.buttonPressed = False;
376 switch (rPtr->flags.whichMarker) {
377 case 1:{
378 int change = rPtr->margins.left - rPtr->motion;
380 rPtr->margins.first -= change;
381 rPtr->margins.body -= change;
382 rPtr->margins.left = rPtr->motion;
383 rPtr->flags.redraw = True;
384 paintRuler(rPtr);
385 break;
387 case 2:
388 rPtr->margins.right = rPtr->motion;
389 break;
390 case 3:
391 rPtr->margins.first = rPtr->motion;
392 break;
393 case 4:
394 rPtr->margins.body = rPtr->motion;
395 break;
396 case 6:
397 rPtr->margins.first = rPtr->margins.body
398 = rPtr->motion;
399 break;
401 if (rPtr->releaseAction)
402 (rPtr->releaseAction) (rPtr, rPtr->clientData);
403 break;
408 W_ViewDelegate _RulerViewDelegate =
410 NULL,
411 NULL,
412 rulerDidResize,
413 NULL,
414 NULL
418 WMRuler *
419 WMCreateRuler(WMWidget * parent)
421 Ruler *rPtr = wmalloc(sizeof(Ruler));
422 unsigned int w = WMWidgetWidth(parent);
424 memset(rPtr, 0, sizeof(Ruler));
426 rPtr->widgetClass = WC_Ruler;
428 rPtr->view = W_CreateView(W_VIEW(parent));
430 if (!rPtr->view) {
431 wfree(rPtr);
432 return NULL;
435 rPtr->view->self = rPtr;
437 rPtr->drawBuffer = (Pixmap) NULL;
439 W_ResizeView(rPtr->view, w, 40);
441 WMCreateEventHandler(rPtr->view, ExposureMask | StructureNotifyMask
442 | EnterWindowMask | LeaveWindowMask | FocusChangeMask
443 | ButtonReleaseMask | ButtonPressMask | KeyReleaseMask
444 | KeyPressMask | Button1MotionMask, handleEvents, rPtr);
446 rPtr->view->delegate = &_RulerViewDelegate;
448 rPtr->fg = WMBlackColor(rPtr->view->screen);
449 rPtr->fgGC = WMColorGC(rPtr->fg);
450 rPtr->bgGC = WMColorGC(WMGrayColor(rPtr->view->screen));
451 rPtr->font = WMSystemFontOfSize(rPtr->view->screen, 8);
453 rPtr->offset = 22;
454 rPtr->margins.left = 22;
455 rPtr->margins.body = 22;
456 rPtr->margins.first = 42;
457 rPtr->margins.right = (w < 502 ? w : 502);
458 rPtr->margins.tabs = NULL;
460 rPtr->flags.whichMarker = 0; /* none */
461 rPtr->flags.buttonPressed = False;
462 rPtr->flags.redraw = True;
464 rPtr->moveAction = NULL;
465 rPtr->releaseAction = NULL;
467 rPtr->pview = W_VIEW(parent);
469 return rPtr;
473 void WMSetRulerMargins(WMRuler * rPtr, WMRulerMargins margins)
475 if (!rPtr)
476 return;
477 rPtr->margins.left = margins.left + rPtr->offset;
478 rPtr->margins.right = margins.right + rPtr->offset;
479 rPtr->margins.first = margins.first + rPtr->offset;
480 rPtr->margins.body = margins.body + rPtr->offset;
481 rPtr->margins.tabs = margins.tabs; /*for loop */
482 rPtr->flags.redraw = True;
483 paintRuler(rPtr);
488 WMRulerMargins *
489 WMGetRulerMargins(WMRuler * rPtr)
491 WMRulerMargins *margins = wmalloc(sizeof(WMRulerMargins));
493 if (!rPtr) {
494 margins->first = margins->body = margins->left = 0;
495 margins->right = 100;
496 return margins;
499 margins->left = rPtr->margins.left - rPtr->offset;
500 margins->right = rPtr->margins.right - rPtr->offset;
501 margins->first = rPtr->margins.first - rPtr->offset;
502 margins->body = rPtr->margins.body - rPtr->offset;
503 /*for */
504 margins->tabs = rPtr->margins.tabs;
506 return margins;
510 Bool
511 WMIsMarginEqualToMargin(WMRulerMargins *aMargin, WMRulerMargins *anotherMargin)
513 if(aMargin == anotherMargin)
514 return True;
515 else if(!aMargin || !anotherMargin)
516 return False;
517 if(aMargin->left != anotherMargin->left)
518 return False;
519 if(aMargin->first != anotherMargin->first)
520 return False;
521 if(aMargin->body != anotherMargin->body)
522 return False;
523 if(aMargin->right != anotherMargin->right)
524 return False;
526 return True;
532 void WMSetRulerOffset(WMRuler * rPtr, int pixels)
534 if (!rPtr || pixels < 0 || pixels + MIN_DOC_WIDTH >= rPtr->view->size.width)
535 return;
536 rPtr->offset = pixels;
537 /*rulerDidResize(rPtr, rPtr->view); */
541 int WMGetRulerOffset(WMRuler * rPtr)
543 if (!rPtr)
544 return 0; /* what value should return if no ruler? -1 or 0? */
545 return rPtr->offset;
549 void WMSetRulerReleaseAction(WMRuler * rPtr, WMAction * action, void *clientData)
551 if (!rPtr)
552 return;
554 rPtr->releaseAction = action;
555 rPtr->clientData = clientData;
559 void WMSetRulerMoveAction(WMRuler * rPtr, WMAction * action, void *clientData)
561 if (!rPtr)
562 return;
564 rPtr->moveAction = action;
565 rPtr->clientData = clientData;
569 /* _which_ one was released */
570 int WMGetReleasedRulerMargin(WMRuler * rPtr)
572 if (!rPtr)
573 return 0;
574 return rPtr->flags.whichMarker;
578 /* _which_ one is being grabbed */
579 int WMGetGrabbedRulerMargin(WMRuler * rPtr)
581 if (!rPtr)
582 return 0;
583 return rPtr->flags.whichMarker;