Text Selection 99% complete, replaceSelection added
[wmaker-crm.git] / WINGs / wruler.c
blob23e76a382feaadd203c89d0fd7e1f86069771c74
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 WMScreen *screen = rPtr->view->screen;
228 if (!rPtr->drawBuffer || !rPtr->view->flags.realized)
229 return;
231 if (rPtr->flags.redraw)
232 drawRulerOnPixmap(rPtr);
233 XCopyArea(rPtr->view->screen->display, rPtr->drawBuffer,
234 rPtr->view->window, rPtr->bg, 0, 0, rPtr->view->size.width, 40,
235 0, 0);
239 static Bool
240 verifyMarkerMove(Ruler * rPtr, int x)
242 if (rPtr->flags.whichMarker < 1 || rPtr->flags.whichMarker > 6)
243 return False;
245 switch (rPtr->flags.whichMarker) {
246 case 1:
247 if (x > rPtr->margins.right - 10 || x < rPtr->offset ||
248 rPtr->margins.body + x > rPtr->margins.right - MIN_DOC_WIDTH ||
249 rPtr->margins.first + x > rPtr->margins.right - MIN_DOC_WIDTH)
250 return False;
251 break;
253 case 2:
254 if (x < rPtr->margins.first + MIN_DOC_WIDTH ||
255 x < rPtr->margins.body + MIN_DOC_WIDTH ||
256 x < rPtr->margins.left + MIN_DOC_WIDTH ||
257 x > rPtr->end) /*rPtr->view->size.width) */
258 return False;
259 break;
261 case 3:
262 if (x >= rPtr->margins.right - MIN_DOC_WIDTH || x < rPtr->margins.left)
263 return False;
264 break;
266 case 4:
267 if (x >= rPtr->margins.right - MIN_DOC_WIDTH || x < rPtr->margins.left)
268 return False;
269 break;
271 case 6:
272 if (x >= rPtr->margins.right - MIN_DOC_WIDTH || x < rPtr->margins.left)
273 return False;
274 break;
276 default:
277 return False;
280 rPtr->motion = x;
281 return True;
285 static int whichMarker(Ruler * rPtr, int x, int y)
287 if (x < rPtr->offset || y > 22)
288 return 0;
290 if (rPtr->margins.left - x >= -6 && y <= 9
291 && (rPtr->margins.left - x <= 0) && y >= 4) {
292 rPtr->motion = rPtr->margins.left;
293 return 1;
295 if (rPtr->margins.right - x >= -1 && y <= 11
296 && rPtr->margins.right - x <= 5 && y >= 4) {
297 rPtr->motion = rPtr->margins.right;
298 return 2;
300 #if 0
301 /* both first and body? */
302 if (rPtr->margins.first - x <= 4 && rPtr->margins.first - x >= -5
303 && rPtr->margins.body - x <= 4 && rPtr->margins.body - x >= -5
304 && y >= 15 && y <= 17) {
305 rPtr->motion = rPtr->margins.first;
306 return 6;
308 #endif
310 if (rPtr->margins.first - x <= 4 && y <= 15
311 && rPtr->margins.first - x >= -5 && y >= 10) {
312 rPtr->motion = rPtr->margins.first;
313 return 3;
315 if (rPtr->margins.body - x <= 4 && y <= 21 &&
316 rPtr->margins.body - x >= -5 && y >= 17) {
317 rPtr->motion = rPtr->margins.body;
318 return 4;
320 /* do tabs (5) */
323 return 0;
326 static void rulerDidResize(W_ViewDelegate * self, WMView * view)
328 Ruler *rPtr = (Ruler *) view->self;
330 createDrawBuffer(rPtr);
331 rPtr->flags.redraw = True;
332 paintRuler(rPtr);
337 static void handleEvents(XEvent * event, void *data)
339 Ruler *rPtr = (Ruler *) data;
340 Display *dpy = event->xany.display;
342 switch (event->type) {
343 case Expose:
344 rulerDidResize(rPtr->view->delegate, rPtr->view);
345 break;
347 case MotionNotify:
348 if (rPtr->flags.buttonPressed
349 && (event->xmotion.state & Button1Mask)) {
350 if (verifyMarkerMove(rPtr, event->xmotion.x)) {
351 GC gc = WMColorGC(WMDarkGrayColor(rPtr->view->screen));
353 if (rPtr->moveAction)
354 (rPtr->moveAction) (rPtr, rPtr->clientData);
355 rPtr->flags.redraw = True;
356 paintRuler(rPtr);
357 XSetLineAttributes(rPtr->view->screen->display, gc, 1,
358 LineSolid, CapNotLast, JoinMiter);
359 XDrawLine(rPtr->pview->screen->display,
360 rPtr->pview->window,
361 gc, rPtr->motion + 1, 40,
362 rPtr->motion + 1, rPtr->pview->size.height - 5);
365 break;
367 case ButtonPress:
368 if (event->xbutton.button != Button1)
369 return;
370 rPtr->flags.buttonPressed = True;
371 rPtr->flags.whichMarker =
372 whichMarker(rPtr, event->xmotion.x,
373 event->xmotion.y);
374 break;
376 case ButtonRelease:
377 if (event->xbutton.button != Button1)
378 return;
379 rPtr->flags.buttonPressed = False;
380 switch (rPtr->flags.whichMarker) {
381 case 1:{
382 int change = rPtr->margins.left - rPtr->motion;
384 rPtr->margins.first -= change;
385 rPtr->margins.body -= change;
386 rPtr->margins.left = rPtr->motion;
387 rPtr->flags.redraw = True;
388 paintRuler(rPtr);
389 break;
391 case 2:
392 rPtr->margins.right = rPtr->motion;
393 break;
394 case 3:
395 rPtr->margins.first = rPtr->motion;
396 break;
397 case 4:
398 rPtr->margins.body = rPtr->motion;
399 break;
400 case 6:
401 rPtr->margins.first = rPtr->margins.body
402 = rPtr->motion;
403 break;
405 if (rPtr->releaseAction)
406 (rPtr->releaseAction) (rPtr, rPtr->clientData);
407 break;
412 W_ViewDelegate _RulerViewDelegate =
414 NULL,
415 NULL,
416 rulerDidResize,
417 NULL,
418 NULL
422 WMRuler *
423 WMCreateRuler(WMWidget * parent)
425 Ruler *rPtr = wmalloc(sizeof(Ruler));
426 unsigned int w = WMWidgetWidth(parent);
428 memset(rPtr, 0, sizeof(Ruler));
430 rPtr->widgetClass = WC_Ruler;
432 rPtr->view = W_CreateView(W_VIEW(parent));
434 if (!rPtr->view) {
435 free(rPtr);
436 return NULL;
439 rPtr->view->self = rPtr;
441 rPtr->drawBuffer = (Pixmap) NULL;
443 W_ResizeView(rPtr->view, w, 40);
445 WMCreateEventHandler(rPtr->view, ExposureMask | StructureNotifyMask
446 | EnterWindowMask | LeaveWindowMask | FocusChangeMask
447 | ButtonReleaseMask | ButtonPressMask | KeyReleaseMask
448 | KeyPressMask | Button1MotionMask, handleEvents, rPtr);
450 rPtr->view->delegate = &_RulerViewDelegate;
452 rPtr->bg = WMColorGC(WMGrayColor(rPtr->view->screen));
453 rPtr->fg = WMColorGC(WMBlackColor(rPtr->view->screen));
454 rPtr->font = WMSystemFontOfSize(rPtr->view->screen, 8);
456 rPtr->offset = 22;
457 rPtr->margins.left = 22;
458 rPtr->margins.body = 22;
459 rPtr->margins.first = 42;
460 rPtr->margins.right = (w < 502 ? w : 502);
461 rPtr->margins.tabs = NULL;
463 rPtr->flags.whichMarker = 0; /* none */
464 rPtr->flags.buttonPressed = False;
465 rPtr->flags.redraw = True;
467 rPtr->moveAction = NULL;
468 rPtr->releaseAction = NULL;
470 rPtr->pview = W_VIEW(parent);
472 return rPtr;
476 void WMSetRulerMargins(WMRuler * rPtr, WMRulerMargins margins)
478 if (!rPtr)
479 return;
480 rPtr->margins.left = margins.left + rPtr->offset;
481 rPtr->margins.right = margins.right + rPtr->offset;
482 rPtr->margins.first = margins.first + rPtr->offset;
483 rPtr->margins.body = margins.body + rPtr->offset;
484 rPtr->margins.tabs = margins.tabs; /*for loop */
485 rPtr->flags.redraw = True;
486 paintRuler(rPtr);
491 WMRulerMargins
492 WMGetRulerMargins(WMRuler * rPtr)
494 WMRulerMargins margins;
496 if (!rPtr) {
497 margins.first = margins.body = margins.left = 0;
498 margins.right = 100;
499 return margins;
502 margins.left = rPtr->margins.left - rPtr->offset;
503 margins.right = rPtr->margins.right - rPtr->offset;
504 margins.first = rPtr->margins.first - rPtr->offset;
505 margins.body = rPtr->margins.body - rPtr->offset;
506 /*for */
507 margins.tabs = rPtr->margins.tabs;
509 return rPtr->margins;
513 void WMSetRulerOffset(WMRuler * rPtr, int pixels)
515 if (!rPtr || pixels < 0 || pixels + MIN_DOC_WIDTH >= rPtr->view->size.width)
516 return;
517 rPtr->offset = pixels;
518 /*rulerDidResize(rPtr, rPtr->view); */
522 int WMGetRulerOffset(WMRuler * rPtr)
524 if (!rPtr)
525 return;
526 return rPtr->offset;
530 void WMSetRulerReleaseAction(WMRuler * rPtr, WMAction * action, void *clientData)
532 if (!rPtr)
533 return;
535 rPtr->releaseAction = action;
536 rPtr->clientData = clientData;
540 void WMSetRulerMoveAction(WMRuler * rPtr, WMAction * action, void *clientData)
542 if (!rPtr)
543 return;
545 rPtr->moveAction = action;
546 rPtr->clientData = clientData;
550 /* _which_ one was released */
551 int WMGetReleasedRulerMargin(WMRuler * rPtr)
553 if (!rPtr)
554 return 0;
555 return rPtr->flags.whichMarker;
559 /* _which_ one is being grabbed */
560 int WMGetGrabbedRulerMargin(WMRuler * rPtr)
562 if (!rPtr)
563 return 0;
564 return rPtr->flags.whichMarker;