added support for Getting and Setting Selection Fonts/Colors/Underline...
[wmaker-crm.git] / WINGs / wruler.c
blob945b04c6c9662dd89a2dbdaa39f556a271b82b85
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"
24 #define MIN_DOC_WIDTH 10
26 typedef struct W_Ruler {
27 W_Class widgetClass;
28 W_View *view;
29 W_View *pview; /* the parent's view (for drawing the line) */
31 WMAction *moveAction; /* what to when while moving */
32 WMAction *releaseAction; /* what to do when released */
33 void *clientData;
35 GC fg, bg;
36 WMFont *font;
37 WMRulerMargins margins;
38 int offset;
39 int motion; /* the position of the _moving_ marker(s) */
40 int end; /* the last tick on the baseline (restrict markers to it) */
42 Pixmap drawBuffer;
44 struct {
45 unsigned int whichMarker:3;
46 /* 0, 1, 2, 3, 4, 5, 6 */
47 /* none, left, right, first, body, tabstop, first & body */
49 unsigned int buttonPressed:1;
50 unsigned int redraw:1;
51 unsigned int RESERVED:27;
52 } flags;
53 } Ruler;
57 /* Marker for left margin
60 | \
61 |__\
66 static void
67 drawLeftMarker(Ruler * rPtr)
69 XPoint points[4];
70 int xpos = (rPtr->flags.whichMarker == 1 ?
71 rPtr->motion : rPtr->margins.left);
73 XDrawLine(rPtr->view->screen->display, rPtr->drawBuffer,
74 rPtr->fg, xpos, 8, xpos, 22);
75 points[0].x = xpos;
76 points[0].y = 1;
77 points[1].x = points[0].x + 6;
78 points[1].y = 8;
79 points[2].x = points[0].x + 6;
80 points[2].y = 9;
81 points[3].x = points[0].x;
82 points[3].y = 9;
83 XFillPolygon(rPtr->view->screen->display, rPtr->drawBuffer,
84 rPtr->fg, points, 4, Convex, CoordModeOrigin);
88 /* Marker for right margin
91 / |
92 /__|
97 static void drawRightMarker(Ruler * rPtr)
99 XPoint points[4];
100 int xpos = (rPtr->flags.whichMarker == 2 ?
101 rPtr->motion : rPtr->margins.right);
103 XDrawLine(rPtr->view->screen->display, rPtr->drawBuffer,
104 rPtr->fg, 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,
114 rPtr->fg, 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,
130 rPtr->fg, xpos - 5, 10, 11, 5);
131 XDrawLine(rPtr->view->screen->display, rPtr->drawBuffer,
132 rPtr->fg, 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,
153 rPtr->fg, 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->bg, 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] =
178 {11, 3, 5, 3, 7, 3, 5, 3};
180 if (!rPtr->drawBuffer || !rPtr->view->flags.realized)
181 return;
184 XFillRectangle(rPtr->view->screen->display, rPtr->drawBuffer,
185 rPtr->bg, 0, 0, rPtr->view->size.width, 40);
187 WMDrawString(rPtr->view->screen, rPtr->drawBuffer, rPtr->fg,
188 rPtr->font, rPtr->margins.left + 2, 26, "0 inches", 10);
190 /* marker ticks */
191 i = j = m = 0;
192 w = rPtr->view->size.width - rPtr->margins.left;
193 while (m < w) {
194 XDrawLine(rPtr->view->screen->display, rPtr->drawBuffer,
195 rPtr->fg, rPtr->margins.left + m, 23,
196 rPtr->margins.left + m, marks[i % 8] + 23);
197 if (i != 0 && i % 8 == 0) {
198 if (j < 10)
199 snprintf(c, 3, "%d", ++j);
200 else
201 snprintf(c, 3, "%2d", ++j);
202 WMDrawString(rPtr->view->screen, rPtr->drawBuffer, rPtr->fg,
203 rPtr->font, rPtr->margins.left + 2 + m, 26, c, 2);
205 m = (++i) * 10;
208 rPtr->end = rPtr->margins.left + m - 10;
209 if (rPtr->margins.right > rPtr->end)
210 rPtr->margins.right = rPtr->end;
211 /* base line */
212 XDrawLine(rPtr->view->screen->display, rPtr->drawBuffer, rPtr->fg,
213 rPtr->margins.left, 22, rPtr->margins.left + m - 10, 22);
215 drawLeftMarker(rPtr);
216 drawRightMarker(rPtr);
217 drawFirstMarker(rPtr);
218 drawBodyMarker(rPtr);
220 rPtr->flags.redraw = False;
224 static void paintRuler(Ruler * rPtr)
226 if (!rPtr->drawBuffer || !rPtr->view->flags.realized)
227 return;
229 if (rPtr->flags.redraw)
230 drawRulerOnPixmap(rPtr);
231 XCopyArea(rPtr->view->screen->display, rPtr->drawBuffer,
232 rPtr->view->window, rPtr->bg, 0, 0, rPtr->view->size.width, 40,
233 0, 0);
237 static Bool
238 verifyMarkerMove(Ruler * rPtr, int x)
240 if (rPtr->flags.whichMarker < 1 || rPtr->flags.whichMarker > 6)
241 return False;
243 switch (rPtr->flags.whichMarker) {
244 case 1:
245 if (x > rPtr->margins.right - 10 || x < rPtr->offset ||
246 rPtr->margins.body + x > rPtr->margins.right - MIN_DOC_WIDTH ||
247 rPtr->margins.first + x > rPtr->margins.right - MIN_DOC_WIDTH)
248 return False;
249 break;
251 case 2:
252 if (x < rPtr->margins.first + MIN_DOC_WIDTH ||
253 x < rPtr->margins.body + MIN_DOC_WIDTH ||
254 x < rPtr->margins.left + MIN_DOC_WIDTH ||
255 x > rPtr->end) /*rPtr->view->size.width) */
256 return False;
257 break;
259 case 3:
260 if (x >= rPtr->margins.right - MIN_DOC_WIDTH || x < rPtr->margins.left)
261 return False;
262 break;
264 case 4:
265 if (x >= rPtr->margins.right - MIN_DOC_WIDTH || x < rPtr->margins.left)
266 return False;
267 break;
269 case 6:
270 if (x >= rPtr->margins.right - MIN_DOC_WIDTH || x < rPtr->margins.left)
271 return False;
272 break;
274 default:
275 return False;
278 rPtr->motion = x;
279 return True;
283 static int whichMarker(Ruler * rPtr, int x, int y)
285 if (x < rPtr->offset || y > 22)
286 return 0;
288 if (rPtr->margins.left - x >= -6 && y <= 9
289 && (rPtr->margins.left - x <= 0) && y >= 4) {
290 rPtr->motion = rPtr->margins.left;
291 return 1;
293 if (rPtr->margins.right - x >= -1 && y <= 11
294 && rPtr->margins.right - x <= 5 && y >= 4) {
295 rPtr->motion = rPtr->margins.right;
296 return 2;
298 #if 0
299 /* both first and body? */
300 if (rPtr->margins.first - x <= 4 && rPtr->margins.first - x >= -5
301 && rPtr->margins.body - x <= 4 && rPtr->margins.body - x >= -5
302 && y >= 15 && y <= 17) {
303 rPtr->motion = rPtr->margins.first;
304 return 6;
306 #endif
308 if (rPtr->margins.first - x <= 4 && y <= 15
309 && rPtr->margins.first - x >= -5 && y >= 10) {
310 rPtr->motion = rPtr->margins.first;
311 return 3;
313 if (rPtr->margins.body - x <= 4 && y <= 21 &&
314 rPtr->margins.body - x >= -5 && y >= 17) {
315 rPtr->motion = rPtr->margins.body;
316 return 4;
318 /* do tabs (5) */
321 return 0;
324 static void rulerDidResize(W_ViewDelegate * self, WMView * view)
326 Ruler *rPtr = (Ruler *) view->self;
328 createDrawBuffer(rPtr);
329 rPtr->flags.redraw = True;
330 paintRuler(rPtr);
335 static void handleEvents(XEvent * event, void *data)
337 Ruler *rPtr = (Ruler *) data;
339 switch (event->type) {
340 case Expose:
341 rulerDidResize(rPtr->view->delegate, rPtr->view);
342 break;
344 case MotionNotify:
345 if (rPtr->flags.buttonPressed
346 && (event->xmotion.state & Button1Mask)) {
347 if (verifyMarkerMove(rPtr, event->xmotion.x)) {
348 GC gc = WMColorGC(WMDarkGrayColor(rPtr->view->screen));
350 if (rPtr->moveAction)
351 (rPtr->moveAction) (rPtr, rPtr->clientData);
352 rPtr->flags.redraw = True;
353 paintRuler(rPtr);
354 XSetLineAttributes(rPtr->view->screen->display, gc, 1,
355 LineSolid, CapNotLast, JoinMiter);
356 XDrawLine(rPtr->pview->screen->display,
357 rPtr->pview->window,
358 gc, rPtr->motion + 1, 40,
359 rPtr->motion + 1, rPtr->pview->size.height - 5);
362 break;
364 case ButtonPress:
365 if (event->xbutton.button != Button1)
366 return;
367 rPtr->flags.buttonPressed = True;
368 rPtr->flags.whichMarker =
369 whichMarker(rPtr, event->xmotion.x,
370 event->xmotion.y);
371 break;
373 case ButtonRelease:
374 if (event->xbutton.button != Button1)
375 return;
376 rPtr->flags.buttonPressed = False;
377 switch (rPtr->flags.whichMarker) {
378 case 1:{
379 int change = rPtr->margins.left - rPtr->motion;
381 rPtr->margins.first -= change;
382 rPtr->margins.body -= change;
383 rPtr->margins.left = rPtr->motion;
384 rPtr->flags.redraw = True;
385 paintRuler(rPtr);
386 break;
388 case 2:
389 rPtr->margins.right = rPtr->motion;
390 break;
391 case 3:
392 rPtr->margins.first = rPtr->motion;
393 break;
394 case 4:
395 rPtr->margins.body = rPtr->motion;
396 break;
397 case 6:
398 rPtr->margins.first = rPtr->margins.body
399 = rPtr->motion;
400 break;
402 if (rPtr->releaseAction)
403 (rPtr->releaseAction) (rPtr, rPtr->clientData);
404 break;
409 W_ViewDelegate _RulerViewDelegate =
411 NULL,
412 NULL,
413 rulerDidResize,
414 NULL,
415 NULL
419 WMRuler *
420 WMCreateRuler(WMWidget * parent)
422 Ruler *rPtr = wmalloc(sizeof(Ruler));
423 unsigned int w = WMWidgetWidth(parent);
425 memset(rPtr, 0, sizeof(Ruler));
427 rPtr->widgetClass = WC_Ruler;
429 rPtr->view = W_CreateView(W_VIEW(parent));
431 if (!rPtr->view) {
432 wfree(rPtr);
433 return NULL;
436 rPtr->view->self = rPtr;
438 rPtr->drawBuffer = (Pixmap) NULL;
440 W_ResizeView(rPtr->view, w, 40);
442 WMCreateEventHandler(rPtr->view, ExposureMask | StructureNotifyMask
443 | EnterWindowMask | LeaveWindowMask | FocusChangeMask
444 | ButtonReleaseMask | ButtonPressMask | KeyReleaseMask
445 | KeyPressMask | Button1MotionMask, handleEvents, rPtr);
447 rPtr->view->delegate = &_RulerViewDelegate;
449 rPtr->bg = WMColorGC(WMGrayColor(rPtr->view->screen));
450 rPtr->fg = WMColorGC(WMBlackColor(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;