removed compile warnings in wmtext :-)
[wmaker-crm.git] / WINGs / wruler.c
blob3f468f28bccb0fea84b09624a87080fce6f273ff
1 /*
2 * WINGs WMRuler nifty ruler widget for WINGs (OK, for WMText ;-)
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 buttonPressed:1;
46 unsigned int whichMarker:3;
47 /* 0, 1, 2, 3, 4, 5, 6 */
48 /* none, left, right, first, body, tabstop, first & body */
49 unsigned int RESERVED:28;
50 } flags;
51 } Ruler;
55 /* Marker for left margin
58 | \
59 |__\
64 static void
65 drawLeftMarker(Ruler * rPtr)
67 XPoint points[4];
68 int xpos = (rPtr->flags.whichMarker == 1 ?
69 rPtr->motion : rPtr->margins.left);
71 XDrawLine(rPtr->view->screen->display, rPtr->drawBuffer,
72 rPtr->fg, xpos, 8, xpos, 22);
73 points[0].x = xpos;
74 points[0].y = 1;
75 points[1].x = points[0].x + 6;
76 points[1].y = 8;
77 points[2].x = points[0].x + 6;
78 points[2].y = 9;
79 points[3].x = points[0].x;
80 points[3].y = 9;
81 XFillPolygon(rPtr->view->screen->display, rPtr->drawBuffer,
82 rPtr->fg, points, 4, Convex, CoordModeOrigin);
86 /* Marker for right margin
89 / |
90 /__|
95 static void drawRightMarker(Ruler * rPtr)
97 XPoint points[4];
98 int xpos = (rPtr->flags.whichMarker == 2 ?
99 rPtr->motion : rPtr->margins.right);
101 XDrawLine(rPtr->view->screen->display, rPtr->drawBuffer,
102 rPtr->fg, xpos, 8, xpos, 22);
103 points[0].x = xpos + 1;
104 points[0].y = 0;
105 points[1].x = points[0].x - 6;
106 points[1].y = 7;
107 points[2].x = points[0].x - 6;
108 points[2].y = 9;
109 points[3].x = points[0].x;
110 points[3].y = 9;
111 XFillPolygon(rPtr->view->screen->display, rPtr->drawBuffer,
112 rPtr->fg, points, 4, Convex, CoordModeOrigin);
116 /* Marker for first line only
117 _____
118 |___|
122 static void drawFirstMarker(Ruler * rPtr)
124 int xpos = ((rPtr->flags.whichMarker == 3 || rPtr->flags.whichMarker == 6) ?
125 rPtr->motion : rPtr->margins.first);
127 XFillRectangle(rPtr->view->screen->display, rPtr->drawBuffer,
128 rPtr->fg, xpos - 5, 10, 11, 5);
129 XDrawLine(rPtr->view->screen->display, rPtr->drawBuffer,
130 rPtr->fg, xpos, 12, xpos, 22);
133 /* Marker for rest of body
134 _____
138 static void drawBodyMarker(Ruler * rPtr)
140 XPoint points[4];
141 int xpos = ((rPtr->flags.whichMarker == 4 || rPtr->flags.whichMarker == 6) ?
142 rPtr->motion : rPtr->margins.body);
144 points[0].x = xpos - 5;
145 points[0].y = 16;
146 points[1].x = points[0].x + 11;
147 points[1].y = 16;
148 points[2].x = points[0].x + 5;
149 points[2].y = 22;
150 XFillPolygon(rPtr->view->screen->display, rPtr->drawBuffer,
151 rPtr->fg, points, 3, Convex, CoordModeOrigin);
155 static void createDrawBuffer(Ruler * rPtr)
157 if (rPtr->drawBuffer)
158 XFreePixmap(rPtr->view->screen->display, rPtr->drawBuffer);
159 rPtr->drawBuffer = XCreatePixmap(rPtr->view->screen->display,
160 rPtr->view->window, rPtr->view->size.width, 40,
161 rPtr->view->screen->depth);
162 XFillRectangle(rPtr->view->screen->display, rPtr->drawBuffer,
163 rPtr->bg, 0, 0, rPtr->view->size.width, 40);
167 static void drawRulerOnPixmap(Ruler * rPtr)
169 int i, j, w, m;
170 char c[3];
171 int marks[9] =
172 {11, 3, 5, 3, 7, 3, 5, 3};
174 if (!rPtr->drawBuffer)
175 createDrawBuffer(rPtr);
177 XFillRectangle(rPtr->view->screen->display, rPtr->drawBuffer,
178 rPtr->bg, 0, 0, rPtr->view->size.width, 40);
180 WMDrawString(rPtr->view->screen, rPtr->drawBuffer, rPtr->fg,
181 rPtr->font, rPtr->margins.left + 2, 26, "0 inches", 10);
183 /* marker ticks */
184 i = j = m = 0;
185 w = rPtr->view->size.width - rPtr->margins.left;
186 while (m < w) {
187 XDrawLine(rPtr->view->screen->display, rPtr->drawBuffer,
188 rPtr->fg, rPtr->margins.left + m, 23,
189 rPtr->margins.left + m, marks[i % 8] + 23);
190 if (i != 0 && i % 8 == 0) {
191 if (j < 10)
192 snprintf(c, 3, "%d", ++j);
193 else
194 snprintf(c, 3, "%2d", ++j);
195 WMDrawString(rPtr->view->screen, rPtr->drawBuffer, rPtr->fg,
196 rPtr->font, rPtr->margins.left + 2 + m, 26, c, 2);
198 m = (++i) * 10;
201 rPtr->end = rPtr->margins.left + m - 10;
202 if (rPtr->margins.right > rPtr->end)
203 rPtr->margins.right = rPtr->end;
204 /* base line */
205 XDrawLine(rPtr->view->screen->display, rPtr->drawBuffer, rPtr->fg,
206 rPtr->margins.left, 22, rPtr->margins.left + m - 10, 22);
208 drawLeftMarker(rPtr);
209 drawRightMarker(rPtr);
210 drawFirstMarker(rPtr);
211 drawBodyMarker(rPtr);
215 static void paintRuler(Ruler * rPtr)
217 WMScreen *screen = rPtr->view->screen;
219 if (1 || !rPtr->drawBuffer) {
220 drawRulerOnPixmap(rPtr);
222 XCopyArea(rPtr->view->screen->display, rPtr->drawBuffer,
223 rPtr->view->window, rPtr->bg, 0, 0, rPtr->view->size.width, 40,
224 0, 0);
228 static Bool
229 verifyMarkerMove(Ruler * rPtr, int x)
231 if (rPtr->flags.whichMarker < 1 || rPtr->flags.whichMarker > 6)
232 return False;
234 switch (rPtr->flags.whichMarker) {
235 case 1:
236 if (x > rPtr->margins.right - 10 || x < rPtr->offset ||
237 rPtr->margins.body + x > rPtr->margins.right - MIN_DOC_WIDTH ||
238 rPtr->margins.first + x > rPtr->margins.right - MIN_DOC_WIDTH)
239 return False;
240 break;
242 case 2:
243 if (x < rPtr->margins.first + MIN_DOC_WIDTH ||
244 x < rPtr->margins.body + MIN_DOC_WIDTH ||
245 x < rPtr->margins.left + MIN_DOC_WIDTH ||
246 x > rPtr->end) /*rPtr->view->size.width) */
247 return False;
248 break;
250 case 3:
251 if (x >= rPtr->margins.right - MIN_DOC_WIDTH || x < rPtr->margins.left)
252 return False;
253 break;
255 case 4:
256 if (x >= rPtr->margins.right - MIN_DOC_WIDTH || x < rPtr->margins.left)
257 return False;
258 break;
260 case 6:
261 if (x >= rPtr->margins.right - MIN_DOC_WIDTH || x < rPtr->margins.left)
262 return False;
263 break;
265 default:
266 return False;
269 rPtr->motion = x;
270 return True;
274 static int whichMarker(Ruler * rPtr, int x, int y)
276 if (x < rPtr->offset || y > 22)
277 return 0;
279 if (rPtr->margins.left - x >= -6 && y <= 9
280 && (rPtr->margins.left - x <= 0) && y >= 4) {
281 rPtr->motion = rPtr->margins.left;
282 return 1;
284 if (rPtr->margins.right - x >= -1 && y <= 11
285 && rPtr->margins.right - x <= 5 && y >= 4) {
286 rPtr->motion = rPtr->margins.right;
287 return 2;
289 #if 0
290 /* both first and body? */
291 if (rPtr->margins.first - x <= 4 && rPtr->margins.first - x >= -5
292 && rPtr->margins.body - x <= 4 && rPtr->margins.body - x >= -5
293 && y >= 15 && y <= 17) {
294 rPtr->motion = rPtr->margins.first;
295 return 6;
297 #endif
299 if (rPtr->margins.first - x <= 4 && y <= 15
300 && rPtr->margins.first - x >= -5 && y >= 10) {
301 rPtr->motion = rPtr->margins.first;
302 return 3;
304 if (rPtr->margins.body - x <= 4 && y <= 21 &&
305 rPtr->margins.body - x >= -5 && y >= 17) {
306 rPtr->motion = rPtr->margins.body;
307 return 4;
309 /* do tabs (5) */
312 return 0;
316 static void handleEvents(XEvent * event, void *data)
318 Ruler *rPtr = (Ruler *) data;
319 Display *dpy = event->xany.display;
321 switch (event->type) {
322 case Expose:
323 paintRuler(rPtr);
324 break;
326 case MotionNotify:
327 if (rPtr->flags.buttonPressed
328 && (event->xmotion.state & Button1Mask)) {
329 if (verifyMarkerMove(rPtr, event->xmotion.x)) {
330 GC gc = WMColorGC(WMDarkGrayColor(rPtr->view->screen));
332 if (rPtr->moveAction)
333 (rPtr->moveAction) (rPtr, rPtr->clientData);
334 paintRuler(rPtr);
335 XSetLineAttributes(rPtr->view->screen->display, gc, 1,
336 LineSolid, CapNotLast, JoinMiter);
337 XDrawLine(rPtr->pview->screen->display,
338 rPtr->pview->window,
339 gc, rPtr->motion + 1, 40,
340 rPtr->motion + 1, rPtr->pview->size.height - 5);
343 break;
345 case ButtonPress:
346 if (event->xbutton.button != Button1)
347 return;
348 rPtr->flags.buttonPressed = True;
349 rPtr->flags.whichMarker =
350 whichMarker(rPtr, event->xmotion.x,
351 event->xmotion.y);
352 break;
354 case ButtonRelease:
355 if (event->xbutton.button != Button1)
356 return;
357 rPtr->flags.buttonPressed = False;
358 switch (rPtr->flags.whichMarker) {
359 case 1:{
360 int change = rPtr->margins.left - rPtr->motion;
362 rPtr->margins.first -= change;
363 rPtr->margins.body -= change;
364 rPtr->margins.left = rPtr->motion;
365 paintRuler(rPtr);
366 break;
368 case 2:
369 rPtr->margins.right = rPtr->motion;
370 break;
371 case 3:
372 rPtr->margins.first = rPtr->motion;
373 break;
374 case 4:
375 rPtr->margins.body = rPtr->motion;
376 break;
377 case 6:
378 rPtr->margins.first = rPtr->margins.body
379 = rPtr->motion;
380 break;
382 if (rPtr->releaseAction)
383 (rPtr->releaseAction) (rPtr, rPtr->clientData);
384 break;
388 static void rulerDidResize(W_ViewDelegate * self, WMView * view)
390 Ruler *rPtr = (Ruler *) view->self;
392 createDrawBuffer(rPtr);
393 paintRuler(rPtr);
398 W_ViewDelegate _RulerViewDelegate =
400 NULL,
401 NULL,
402 rulerDidResize,
403 NULL,
404 NULL
408 WMRuler *
409 WMCreateRuler(WMWidget * parent)
411 Ruler *rPtr = wmalloc(sizeof(Ruler));
412 unsigned int w = WMWidgetWidth(parent);
414 memset(rPtr, 0, sizeof(Ruler));
416 rPtr->widgetClass = WC_Ruler;
418 rPtr->view = W_CreateView(W_VIEW(parent));
419 if (!rPtr->view) {
420 free(rPtr);
421 return NULL;
423 rPtr->view->self = rPtr;
425 rPtr->drawBuffer = (Pixmap) NULL;
427 W_ResizeView(rPtr->view, w, 40);
429 WMCreateEventHandler(rPtr->view, ExposureMask | StructureNotifyMask
430 | EnterWindowMask | LeaveWindowMask | FocusChangeMask
431 | ButtonReleaseMask | ButtonPressMask | KeyReleaseMask
432 | KeyPressMask | Button1MotionMask, handleEvents, rPtr);
434 rPtr->view->delegate = &_RulerViewDelegate;
436 rPtr->bg = WMColorGC(WMGrayColor(rPtr->view->screen));
437 rPtr->fg = WMColorGC(WMBlackColor(rPtr->view->screen));
438 rPtr->font = WMSystemFontOfSize(rPtr->view->screen, 8);
440 rPtr->offset = 22;
441 rPtr->margins.left = 22;
442 rPtr->margins.body = 22;
443 rPtr->margins.first = 42;
444 rPtr->margins.right = (w < 502 ? w : 502);
446 rPtr->flags.whichMarker = 0; /* none */
447 rPtr->flags.buttonPressed = False;
449 rPtr->moveAction = NULL;
450 rPtr->releaseAction = NULL;
452 rPtr->pview = W_VIEW(parent);
454 return rPtr;
458 void WMSetRulerMargins(WMRuler * rPtr, WMRulerMargins margins)
460 if (!rPtr)
461 return;
462 rPtr->margins.left = margins.left + rPtr->offset;
463 rPtr->margins.right = margins.right + rPtr->offset;
464 rPtr->margins.first = margins.first + rPtr->offset;
465 rPtr->margins.body = margins.body + rPtr->offset;
466 rPtr->margins.tabs = margins.tabs; /*for loop */
467 paintRuler(rPtr);
472 WMRulerMargins
473 WMGetRulerMargins(WMRuler * rPtr)
475 WMRulerMargins margins;
477 if (!rPtr)
478 return margins;
480 margins.left = rPtr->margins.left - rPtr->offset;
481 margins.right = rPtr->margins.right - rPtr->offset;
482 margins.first = rPtr->margins.first - rPtr->offset;
483 margins.body = rPtr->margins.body - rPtr->offset;
484 /*for */
485 margins.tabs = rPtr->margins.tabs;
487 return rPtr->margins;
491 void WMSetRulerOffset(WMRuler * rPtr, int pixels)
493 if (!rPtr || pixels < 0 || pixels + MIN_DOC_WIDTH >= rPtr->view->size.width)
494 return;
495 rPtr->offset = pixels;
496 /*rulerDidResize(rPtr, rPtr->view); */
500 int WMGetRulerOffset(WMRuler * rPtr)
502 if (!rPtr)
503 return;
504 return rPtr->offset;
508 void WMSetRulerReleaseAction(WMRuler * rPtr, WMAction * action, void *clientData)
510 if (!rPtr)
511 return;
513 rPtr->releaseAction = action;
514 rPtr->clientData = clientData;
518 void WMSetRulerMoveAction(WMRuler * rPtr, WMAction * action, void *clientData)
520 if (!rPtr)
521 return;
523 rPtr->moveAction = action;
524 rPtr->clientData = clientData;
528 /* _which_ one was released */
529 int WMGetReleasedRulerMargin(WMRuler * rPtr)
531 if (!rPtr)
532 return 0;
533 return rPtr->flags.whichMarker;
537 /* _which_ one is being grabbed */
538 int WMGetGrabbedRulerMargin(WMRuler * rPtr)
540 if (!rPtr)
541 return 0;
542 return rPtr->flags.whichMarker;