changed indentation to use spaces only
[wmaker-crm.git] / WINGs / wruler.c
blobe98caac500a96ed7f506c8aa82d08bf5389e0c56
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
99 drawRightMarker(Ruler * rPtr)
101 XPoint points[4];
102 int xpos = (rPtr->flags.whichMarker==2 ? rPtr->motion : rPtr->margins.right);
104 XDrawLine(rPtr->view->screen->display, rPtr->drawBuffer, rPtr->fgGC,
105 xpos, 8, xpos, 22);
106 points[0].x = xpos + 1;
107 points[0].y = 0;
108 points[1].x = points[0].x - 6;
109 points[1].y = 7;
110 points[2].x = points[0].x - 6;
111 points[2].y = 9;
112 points[3].x = points[0].x;
113 points[3].y = 9;
114 XFillPolygon(rPtr->view->screen->display, rPtr->drawBuffer, rPtr->fgGC,
115 points, 4, Convex, CoordModeOrigin);
119 /* Marker for first line only
120 _____
121 |___|
125 static void
126 drawFirstMarker(Ruler * rPtr)
128 int xpos = ((rPtr->flags.whichMarker == 3 || rPtr->flags.whichMarker == 6) ?
129 rPtr->motion : rPtr->margins.first);
131 XFillRectangle(rPtr->view->screen->display, rPtr->drawBuffer, rPtr->fgGC,
132 xpos - 5, 10, 11, 5);
133 XDrawLine(rPtr->view->screen->display, rPtr->drawBuffer, rPtr->fgGC,
134 xpos, 12, xpos, 22);
137 /* Marker for rest of body
138 _____
142 static void
143 drawBodyMarker(Ruler * rPtr)
145 XPoint points[4];
146 int xpos = ((rPtr->flags.whichMarker == 4 || rPtr->flags.whichMarker == 6) ?
147 rPtr->motion : rPtr->margins.body);
149 points[0].x = xpos - 5;
150 points[0].y = 16;
151 points[1].x = points[0].x + 11;
152 points[1].y = 16;
153 points[2].x = points[0].x + 5;
154 points[2].y = 22;
155 XFillPolygon(rPtr->view->screen->display, rPtr->drawBuffer, rPtr->fgGC,
156 points, 3, Convex, CoordModeOrigin);
160 static void
161 createDrawBuffer(Ruler * rPtr)
163 if(!rPtr->view->flags.realized)
164 return;
166 if (rPtr->drawBuffer)
167 XFreePixmap(rPtr->view->screen->display, rPtr->drawBuffer);
169 rPtr->drawBuffer = XCreatePixmap(rPtr->view->screen->display,
170 rPtr->view->window, rPtr->view->size.width, 40,
171 rPtr->view->screen->depth);
172 XFillRectangle(rPtr->view->screen->display, rPtr->drawBuffer,
173 rPtr->bgGC, 0, 0, rPtr->view->size.width, 40);
177 static void
178 drawRulerOnPixmap(Ruler * rPtr)
180 int i, j, w, m;
181 char c[3];
182 int marks[9] = {11, 3, 5, 3, 7, 3, 5, 3};
184 if (!rPtr->drawBuffer || !rPtr->view->flags.realized)
185 return;
188 XFillRectangle(rPtr->view->screen->display, rPtr->drawBuffer,
189 rPtr->bgGC, 0, 0, rPtr->view->size.width, 40);
191 WMDrawString(rPtr->view->screen, rPtr->drawBuffer, rPtr->fg,
192 rPtr->font, rPtr->margins.left + 2, 26, _("0 inches"), 10);
194 /* marker ticks */
195 i = j = m = 0;
196 w = rPtr->view->size.width - rPtr->margins.left;
197 while (m < w) {
198 XDrawLine(rPtr->view->screen->display, rPtr->drawBuffer,
199 rPtr->fgGC, rPtr->margins.left + m, 23,
200 rPtr->margins.left + m, marks[i % 8] + 23);
201 if (i != 0 && i % 8 == 0) {
202 if (j < 10)
203 snprintf(c, 3, "%d", ++j);
204 else
205 snprintf(c, 3, "%2d", ++j);
206 WMDrawString(rPtr->view->screen, rPtr->drawBuffer, rPtr->fg,
207 rPtr->font, rPtr->margins.left + 2 + m, 26, c, 2);
209 m = (++i) * 10;
212 rPtr->end = rPtr->margins.left + m - 10;
213 if (rPtr->margins.right > rPtr->end)
214 rPtr->margins.right = rPtr->end;
215 /* base line */
216 XDrawLine(rPtr->view->screen->display, rPtr->drawBuffer, rPtr->fgGC,
217 rPtr->margins.left, 22, rPtr->margins.left + m - 10, 22);
219 drawLeftMarker(rPtr);
220 drawRightMarker(rPtr);
221 drawFirstMarker(rPtr);
222 drawBodyMarker(rPtr);
224 rPtr->flags.redraw = False;
228 static void
229 paintRuler(Ruler * rPtr)
231 if (!rPtr->drawBuffer || !rPtr->view->flags.realized)
232 return;
234 if (rPtr->flags.redraw)
235 drawRulerOnPixmap(rPtr);
236 XCopyArea(rPtr->view->screen->display, rPtr->drawBuffer,
237 rPtr->view->window, rPtr->bgGC, 0, 0,
238 rPtr->view->size.width, 40, 0, 0);
242 static Bool
243 verifyMarkerMove(Ruler * rPtr, int x)
245 if (rPtr->flags.whichMarker < 1 || rPtr->flags.whichMarker > 6)
246 return False;
248 switch (rPtr->flags.whichMarker) {
249 case 1:
250 if (x > rPtr->margins.right - 10 || x < rPtr->offset ||
251 rPtr->margins.body + x > rPtr->margins.right - MIN_DOC_WIDTH ||
252 rPtr->margins.first + x > rPtr->margins.right - MIN_DOC_WIDTH)
253 return False;
254 break;
256 case 2:
257 if (x < rPtr->margins.first + MIN_DOC_WIDTH ||
258 x < rPtr->margins.body + MIN_DOC_WIDTH ||
259 x < rPtr->margins.left + MIN_DOC_WIDTH ||
260 x > rPtr->end) /*rPtr->view->size.width) */
261 return False;
262 break;
264 case 3:
265 if (x >= rPtr->margins.right - MIN_DOC_WIDTH || x < rPtr->margins.left)
266 return False;
267 break;
269 case 4:
270 if (x >= rPtr->margins.right - MIN_DOC_WIDTH || x < rPtr->margins.left)
271 return False;
272 break;
274 case 6:
275 if (x >= rPtr->margins.right - MIN_DOC_WIDTH || x < rPtr->margins.left)
276 return False;
277 break;
279 default:
280 return False;
283 rPtr->motion = x;
284 return True;
288 static int
289 whichMarker(Ruler * rPtr, int x, int y)
291 if (x < rPtr->offset || y > 22)
292 return 0;
294 if (rPtr->margins.left - x >= -6 && y <= 9
295 && (rPtr->margins.left - x <= 0) && y >= 4) {
296 rPtr->motion = rPtr->margins.left;
297 return 1;
299 if (rPtr->margins.right - x >= -1 && y <= 11
300 && rPtr->margins.right - x <= 5 && y >= 4) {
301 rPtr->motion = rPtr->margins.right;
302 return 2;
304 #if 0
305 /* both first and body? */
306 if (rPtr->margins.first - x <= 4 && rPtr->margins.first - x >= -5
307 && rPtr->margins.body - x <= 4 && rPtr->margins.body - x >= -5
308 && y >= 15 && y <= 17) {
309 rPtr->motion = rPtr->margins.first;
310 return 6;
312 #endif
314 if (rPtr->margins.first - x <= 4 && y <= 15
315 && rPtr->margins.first - x >= -5 && y >= 10) {
316 rPtr->motion = rPtr->margins.first;
317 return 3;
319 if (rPtr->margins.body - x <= 4 && y <= 21 &&
320 rPtr->margins.body - x >= -5 && y >= 17) {
321 rPtr->motion = rPtr->margins.body;
322 return 4;
324 /* do tabs (5) */
327 return 0;
330 static void
331 rulerDidResize(W_ViewDelegate * self, WMView * view)
333 Ruler *rPtr = (Ruler *) view->self;
335 createDrawBuffer(rPtr);
336 rPtr->flags.redraw = True;
337 paintRuler(rPtr);
342 static void
343 handleEvents(XEvent * event, void *data)
345 Ruler *rPtr = (Ruler *) data;
347 switch (event->type) {
348 case Expose:
349 rulerDidResize(rPtr->view->delegate, rPtr->view);
350 break;
352 case MotionNotify:
353 if (rPtr->flags.buttonPressed
354 && (event->xmotion.state & Button1Mask)) {
355 if (verifyMarkerMove(rPtr, event->xmotion.x)) {
356 GC gc = WMColorGC(WMDarkGrayColor(rPtr->view->screen));
358 if (rPtr->moveAction)
359 (rPtr->moveAction) (rPtr, rPtr->clientData);
360 rPtr->flags.redraw = True;
361 paintRuler(rPtr);
362 XSetLineAttributes(rPtr->view->screen->display, gc, 1,
363 LineSolid, CapNotLast, JoinMiter);
364 XDrawLine(rPtr->pview->screen->display,
365 rPtr->pview->window,
366 gc, rPtr->motion + 1, 40,
367 rPtr->motion + 1, rPtr->pview->size.height - 5);
370 break;
372 case ButtonPress:
373 if (event->xbutton.button != Button1)
374 return;
375 rPtr->flags.buttonPressed = True;
376 rPtr->flags.whichMarker =
377 whichMarker(rPtr, event->xmotion.x,
378 event->xmotion.y);
379 break;
381 case ButtonRelease:
382 if (event->xbutton.button != Button1)
383 return;
384 rPtr->flags.buttonPressed = False;
385 switch (rPtr->flags.whichMarker) {
386 case 1:{
387 int change = rPtr->margins.left - rPtr->motion;
389 rPtr->margins.first -= change;
390 rPtr->margins.body -= change;
391 rPtr->margins.left = rPtr->motion;
392 rPtr->flags.redraw = True;
393 paintRuler(rPtr);
394 break;
396 case 2:
397 rPtr->margins.right = rPtr->motion;
398 break;
399 case 3:
400 rPtr->margins.first = rPtr->motion;
401 break;
402 case 4:
403 rPtr->margins.body = rPtr->motion;
404 break;
405 case 6:
406 rPtr->margins.first = rPtr->margins.body
407 = rPtr->motion;
408 break;
410 if (rPtr->releaseAction)
411 (rPtr->releaseAction) (rPtr, rPtr->clientData);
412 break;
417 W_ViewDelegate _RulerViewDelegate =
419 NULL,
420 NULL,
421 rulerDidResize,
422 NULL,
423 NULL
427 WMRuler *
428 WMCreateRuler(WMWidget * parent)
430 Ruler *rPtr = wmalloc(sizeof(Ruler));
431 unsigned int w = WMWidgetWidth(parent);
433 memset(rPtr, 0, sizeof(Ruler));
435 rPtr->widgetClass = WC_Ruler;
437 rPtr->view = W_CreateView(W_VIEW(parent));
439 if (!rPtr->view) {
440 wfree(rPtr);
441 return NULL;
444 rPtr->view->self = rPtr;
446 rPtr->drawBuffer = (Pixmap) NULL;
448 W_ResizeView(rPtr->view, w, 40);
450 WMCreateEventHandler(rPtr->view, ExposureMask | StructureNotifyMask
451 | EnterWindowMask | LeaveWindowMask | FocusChangeMask
452 | ButtonReleaseMask | ButtonPressMask | KeyReleaseMask
453 | KeyPressMask | Button1MotionMask, handleEvents, rPtr);
455 rPtr->view->delegate = &_RulerViewDelegate;
457 rPtr->fg = WMBlackColor(rPtr->view->screen);
458 rPtr->fgGC = WMColorGC(rPtr->fg);
459 rPtr->bgGC = WMColorGC(WMGrayColor(rPtr->view->screen));
460 rPtr->font = WMSystemFontOfSize(rPtr->view->screen, 8);
462 rPtr->offset = 22;
463 rPtr->margins.left = 22;
464 rPtr->margins.body = 22;
465 rPtr->margins.first = 42;
466 rPtr->margins.right = (w < 502 ? w : 502);
467 rPtr->margins.tabs = NULL;
469 rPtr->flags.whichMarker = 0; /* none */
470 rPtr->flags.buttonPressed = False;
471 rPtr->flags.redraw = True;
473 rPtr->moveAction = NULL;
474 rPtr->releaseAction = NULL;
476 rPtr->pview = W_VIEW(parent);
478 return rPtr;
482 void
483 WMSetRulerMargins(WMRuler * rPtr, WMRulerMargins margins)
485 if (!rPtr)
486 return;
487 rPtr->margins.left = margins.left + rPtr->offset;
488 rPtr->margins.right = margins.right + rPtr->offset;
489 rPtr->margins.first = margins.first + rPtr->offset;
490 rPtr->margins.body = margins.body + rPtr->offset;
491 rPtr->margins.tabs = margins.tabs; /*for loop */
492 rPtr->flags.redraw = True;
493 paintRuler(rPtr);
498 WMRulerMargins *
499 WMGetRulerMargins(WMRuler * rPtr)
501 WMRulerMargins *margins = wmalloc(sizeof(WMRulerMargins));
503 if (!rPtr) {
504 margins->first = margins->body = margins->left = 0;
505 margins->right = 100;
506 return margins;
509 margins->left = rPtr->margins.left - rPtr->offset;
510 margins->right = rPtr->margins.right - rPtr->offset;
511 margins->first = rPtr->margins.first - rPtr->offset;
512 margins->body = rPtr->margins.body - rPtr->offset;
513 /*for */
514 margins->tabs = rPtr->margins.tabs;
516 return margins;
520 Bool
521 WMIsMarginEqualToMargin(WMRulerMargins *aMargin, WMRulerMargins *anotherMargin)
523 if(aMargin == anotherMargin)
524 return True;
525 else if(!aMargin || !anotherMargin)
526 return False;
527 if(aMargin->left != anotherMargin->left)
528 return False;
529 if(aMargin->first != anotherMargin->first)
530 return False;
531 if(aMargin->body != anotherMargin->body)
532 return False;
533 if(aMargin->right != anotherMargin->right)
534 return False;
536 return True;
542 void
543 WMSetRulerOffset(WMRuler * rPtr, int pixels)
545 if (!rPtr || pixels < 0 || pixels + MIN_DOC_WIDTH >= rPtr->view->size.width)
546 return;
547 rPtr->offset = pixels;
548 /*rulerDidResize(rPtr, rPtr->view); */
553 WMGetRulerOffset(WMRuler * rPtr)
555 if (!rPtr)
556 return 0; /* what value should return if no ruler? -1 or 0? */
557 return rPtr->offset;
561 void
562 WMSetRulerReleaseAction(WMRuler * rPtr, WMAction * action, void *clientData)
564 if (!rPtr)
565 return;
567 rPtr->releaseAction = action;
568 rPtr->clientData = clientData;
572 void
573 WMSetRulerMoveAction(WMRuler * rPtr, WMAction * action, void *clientData)
575 if (!rPtr)
576 return;
578 rPtr->moveAction = action;
579 rPtr->clientData = clientData;
583 /* _which_ one was released */
585 WMGetReleasedRulerMargin(WMRuler * rPtr)
587 if (!rPtr)
588 return 0;
589 return rPtr->flags.whichMarker;
593 /* _which_ one is being grabbed */
595 WMGetGrabbedRulerMargin(WMRuler * rPtr)
597 if (!rPtr)
598 return 0;
599 return rPtr->flags.whichMarker;