fixed lots of compile bugs in wtext.c and made a few api changes to it
[wmaker-crm.git] / WINGs / wruler.c
blob9f13efe668e637f5f6b52c08e2b35bfe2901cd4c
1 /* WMRuler: nifty ruler widget for WINGs (OK, for WMText ;-) */
2 /* Copyleft (>) 1999, 2000 Nwanua Elumeze <nwanua@colorado.edu> */
5 #include "WINGsP.h"
7 #define MIN_DOC_WIDTH 10
9 typedef struct W_Ruler {
10 W_Class widgetClass;
11 W_View *view;
12 W_View *pview; /* the parent's view (for drawing the line) */
14 WMAction *moveAction; /* what to when while moving */
15 WMAction *releaseAction; /* what to do when released */
16 void *clientData;
18 GC fg, bg;
19 WMFont *font;
20 WMRulerMargins margins;
21 int offset;
22 int motion; /* the position of the _moving_ marker(s) */
23 int end; /* the last tick on the baseline (restrict markers to it) */
25 Pixmap drawBuffer;
27 struct {
28 unsigned int buttonPressed:1;
29 /* 0, 1, 2, 3, 4, 5, 6 */
30 unsigned int whichMarker:3; /* none, left, right, first, body, tabstop, both */
31 unsigned int RESERVED:28;
32 } flags;
33 } Ruler;
37 /* Marker for left margin
40 | \
41 |__\
43 | */
44 static void
45 drawLeftMarker(Ruler *rPtr)
47 XPoint points[4];
48 int xpos = (rPtr->flags.whichMarker==1?
49 rPtr->motion:rPtr->margins.left);
51 XDrawLine(rPtr->view->screen->display, rPtr->drawBuffer,
52 rPtr->fg, xpos, 8, xpos, 22);
53 points[0].x = xpos;
54 points[0].y = 1;
55 points[1].x = points[0].x+6;
56 points[1].y = 8;
57 points[2].x = points[0].x+6;
58 points[2].y = 9;
59 points[3].x = points[0].x;
60 points[3].y = 9;
61 XFillPolygon (rPtr->view->screen->display, rPtr->drawBuffer,
62 rPtr->fg, points, 4, Convex, CoordModeOrigin);
65 /* Marker for right margin
68 / |
69 /__|
71 | */
73 static void
74 drawRightMarker(Ruler *rPtr)
76 XPoint points[4];
77 int xpos = (rPtr->flags.whichMarker==2?
78 rPtr->motion:rPtr->margins.right);
80 XDrawLine(rPtr->view->screen->display, rPtr->drawBuffer,
81 rPtr->fg, xpos, 8, xpos, 22);
82 points[0].x = xpos+1;
83 points[0].y = 0;
84 points[1].x = points[0].x-6;
85 points[1].y = 7;
86 points[2].x = points[0].x-6;
87 points[2].y = 9;
88 points[3].x = points[0].x;
89 points[3].y = 9;
90 XFillPolygon (rPtr->view->screen->display, rPtr->drawBuffer,
91 rPtr->fg, points, 4, Convex, CoordModeOrigin);
95 /* Marker for first line only
96 _____
97 |___|
98 | */
99 static void
100 drawFirstMarker(Ruler *rPtr)
102 int xpos = ((rPtr->flags.whichMarker==3 || rPtr->flags.whichMarker==6)?
103 rPtr->motion:rPtr->margins.first);
104 XFillRectangle(rPtr->view->screen->display, rPtr->drawBuffer,
105 rPtr->fg, xpos-5, 10, 11, 5);
106 XDrawLine(rPtr->view->screen->display, rPtr->drawBuffer,
107 rPtr->fg, xpos, 12, xpos, 22);
110 /* Marker for rest of body
111 _____
113 \./ */
114 static void
115 drawBodyMarker(Ruler *rPtr)
117 XPoint points[4];
118 int xpos = ((rPtr->flags.whichMarker==4 || rPtr->flags.whichMarker==6)?
119 rPtr->motion:rPtr->margins.body);
120 points[0].x = xpos-5;
121 points[0].y = 16;
122 points[1].x = points[0].x+11;
123 points[1].y = 16;
124 points[2].x = points[0].x+5;
125 points[2].y = 22;
126 XFillPolygon (rPtr->view->screen->display, rPtr->drawBuffer,
127 rPtr->fg, points, 3, Convex, CoordModeOrigin);
130 static void
131 createDrawBuffer(Ruler *rPtr)
133 if(rPtr->drawBuffer)
134 XFreePixmap(rPtr->view->screen->display, rPtr->drawBuffer);
135 rPtr->drawBuffer = XCreatePixmap(rPtr->view->screen->display,
136 rPtr->view->window, rPtr->view->size.width, 40,
137 rPtr->view->screen->depth);
138 XFillRectangle(rPtr->view->screen->display, rPtr->drawBuffer,
139 rPtr->bg, 0, 0, rPtr->view->size.width, 40);
142 static void
143 drawRulerOnPixmap(Ruler *rPtr)
145 int i, j, w, m;
146 char c[3];
147 int marks[9] = {11, 3, 5, 3, 7, 3, 5, 3};
149 if(!rPtr->drawBuffer)
150 createDrawBuffer(rPtr);
152 XFillRectangle(rPtr->view->screen->display, rPtr->drawBuffer,
153 rPtr->bg, 0, 0, rPtr->view->size.width, 40);
156 WMDrawString(rPtr->view->screen, rPtr->drawBuffer,
157 rPtr->fg, rPtr->font, rPtr->margins.left+2, 26, "0 inches", 10);
159 /* marker ticks */
160 i=j=m=0;
161 w = rPtr->view->size.width - rPtr->margins.left;
162 while(m < w) {
163 XDrawLine(rPtr->view->screen->display, rPtr->drawBuffer,
164 rPtr->fg, rPtr->margins.left+m, 23,
165 rPtr->margins.left+m, marks[i%8]+23);
166 if(i!=0 && i%8==0) {
167 if(j<10)
168 snprintf(c,3,"%d",++j);
169 else
170 snprintf(c,3,"%2d",++j);
171 WMDrawString(rPtr->view->screen, rPtr->drawBuffer,
172 rPtr->fg, rPtr->font, rPtr->margins.left+2+m, 26, c, 2);
174 m = (++i)*10;
177 rPtr->end = rPtr->margins.left+m-10;
178 if(rPtr->margins.right > rPtr->end)
179 rPtr->margins.right = rPtr->end;
180 /* base line */
181 XDrawLine(rPtr->view->screen->display, rPtr->drawBuffer,
182 rPtr->fg, rPtr->margins.left, 22, rPtr->margins.left+m-10, 22);
184 drawLeftMarker(rPtr);
185 drawRightMarker(rPtr);
186 drawFirstMarker(rPtr);
187 drawBodyMarker(rPtr);
190 static void
191 paintRuler(Ruler *rPtr)
193 WMScreen *screen = rPtr->view->screen;
194 if(1||!rPtr->drawBuffer) { //first exposure
195 drawRulerOnPixmap(rPtr);
198 XCopyArea(rPtr->view->screen->display, rPtr->drawBuffer,
199 rPtr->view->window, rPtr->bg, 0, 0, rPtr->view->size.width, 40,
200 0, 0);
203 static Bool
204 verifyMarkerMove(Ruler *rPtr, int x)
206 if(rPtr->flags.whichMarker<1 || rPtr->flags.whichMarker>6)
207 return False;
209 switch(rPtr->flags.whichMarker) {
210 case 1:
211 if( x > rPtr->margins.right - 10
212 || rPtr->margins.body + x > rPtr->margins.right-MIN_DOC_WIDTH
213 || rPtr->margins.first + x > rPtr->margins.right-MIN_DOC_WIDTH
214 || x < rPtr->offset)
215 return False;
216 break;
218 case 2:
219 if( x < rPtr->margins.first+MIN_DOC_WIDTH
220 || x < rPtr->margins.body+MIN_DOC_WIDTH
221 || x < rPtr->margins.left+MIN_DOC_WIDTH
222 || x > rPtr->end) //rPtr->view->size.width)
223 return False;
224 break;
226 case 3:
227 if( x >= rPtr->margins.right-MIN_DOC_WIDTH
228 || x < rPtr->margins.left)
229 return False;
230 break;
232 case 4:
233 if( x >= rPtr->margins.right-MIN_DOC_WIDTH
234 || x < rPtr->margins.left)
235 return False;
236 break;
238 case 6:
239 if( x >= rPtr->margins.right-MIN_DOC_WIDTH
240 || x < rPtr->margins.left)
241 return False;
242 break;
244 default: return False;
247 rPtr->motion = x;
248 return True;
252 static int
253 whichMarker(Ruler *rPtr, int x, int y)
255 if(x<rPtr->offset || y>22)
256 return 0;
258 if( rPtr->margins.left-x >= -6 && y <= 9
259 && (rPtr->margins.left-x <=0) && y>=4) {
260 rPtr->motion = rPtr->margins.left;
261 return 1;
264 if(rPtr->margins.right-x >= -1 && y <= 11
265 && rPtr->margins.right-x <=5 && y>=4) {
266 rPtr->motion = rPtr->margins.right;
267 return 2;
270 #if 0
271 /* both first and body? */
272 if( rPtr->margins.first-x <= 4 && rPtr->margins.first-x >= -5
273 && rPtr->margins.body-x <= 4 && rPtr->margins.body-x >= -5
274 && y>=15 && y<=17) {
275 rPtr->motion = rPtr->margins.first;
276 return 6;
278 #endif
280 if(rPtr->margins.first-x <= 4 && y<=15
281 && rPtr->margins.first-x >= -5 && y>=10) {
282 rPtr->motion = rPtr->margins.first;
283 return 3;
286 if( rPtr->margins.body-x <= 4 && y<=21 &&
287 rPtr->margins.body-x >= -5 && y>=17) {
288 rPtr->motion = rPtr->margins.body;
289 return 4;
293 /* do tabs (5)*/
296 return 0;
300 static void
301 handleEvents(XEvent *event, void *data)
303 Ruler *rPtr = (Ruler*)data;
304 Display *dpy = event->xany.display;
306 switch (event->type) {
307 case Expose:
308 paintRuler(rPtr);
309 break;
311 case MotionNotify:
312 if(rPtr->flags.buttonPressed
313 && (event->xmotion.state & Button1Mask)) {
314 if(verifyMarkerMove(rPtr, event->xmotion.x)){
315 GC gc = WMColorGC(WMDarkGrayColor(rPtr->view->screen));
316 paintRuler(rPtr);
317 if(rPtr->moveAction)
318 (rPtr->moveAction)(rPtr, rPtr->clientData);
319 XSetLineAttributes(rPtr->view->screen->display, gc, 1,
320 LineSolid, CapNotLast, JoinMiter);
321 XDrawLine(rPtr->pview->screen->display,
322 rPtr->pview->window,
323 gc, rPtr->motion+1, 40,
324 rPtr->motion+1, rPtr->pview->size.height-5);
327 break;
329 case ButtonPress:
330 if(event->xbutton.button != Button1)
331 return;
332 rPtr->flags.buttonPressed = True;
333 rPtr->flags.whichMarker =
334 whichMarker(rPtr, event->xmotion.x,
335 event->xmotion.y);
336 break;
338 case ButtonRelease:
339 if(event->xbutton.button != Button1)
340 return;
341 rPtr->flags.buttonPressed = False;
342 switch(rPtr->flags.whichMarker) {
343 case 1: {
344 int change = rPtr->margins.left-rPtr->motion;
345 rPtr->margins.first -=change;
346 rPtr->margins.body -= change;
347 rPtr->margins.left = rPtr->motion;
348 paintRuler(rPtr); break;
350 case 2: rPtr->margins.right = rPtr->motion; break;
351 case 3: rPtr->margins.first = rPtr->motion; break;
352 case 4: rPtr->margins.body = rPtr->motion; break;
353 case 6: rPtr->margins.first = rPtr->margins.body
354 = rPtr->motion; break;
356 if(rPtr->releaseAction)
357 (rPtr->releaseAction)(rPtr, rPtr->clientData);
358 break;
362 static void
363 rulerDidResize(W_ViewDelegate *self, WMView *view)
365 Ruler *rPtr = (Ruler *)view->self;
367 createDrawBuffer(rPtr);
368 paintRuler(rPtr);
373 W_ViewDelegate _RulerViewDelegate =
375 NULL,
376 NULL,
377 rulerDidResize,
378 NULL,
379 NULL
383 WMRuler *
384 WMCreateRuler(WMWidget *parent)
386 Ruler *rPtr = wmalloc(sizeof(Ruler));
387 unsigned int w = WMWidgetWidth(parent);
389 memset(rPtr, 0, sizeof(Ruler));
391 rPtr->widgetClass = WC_Ruler;
393 rPtr->view = W_CreateView(W_VIEW(parent));
394 if (!rPtr->view) {
395 free(rPtr);
396 return NULL;
398 rPtr->view->self = rPtr;
400 rPtr->drawBuffer = (Pixmap) NULL;
402 W_ResizeView(rPtr->view, w, 40);
404 WMCreateEventHandler(rPtr->view, ExposureMask|StructureNotifyMask
405 |EnterWindowMask|LeaveWindowMask|FocusChangeMask
406 |ButtonReleaseMask|ButtonPressMask|KeyReleaseMask
407 |KeyPressMask|Button1MotionMask, handleEvents, rPtr);
409 rPtr->view->delegate = &_RulerViewDelegate;
411 rPtr->bg = WMColorGC(WMGrayColor(rPtr->view->screen));
412 rPtr->fg = WMColorGC(WMBlackColor(rPtr->view->screen));
413 rPtr->font = WMSystemFontOfSize(rPtr->view->screen, 8);
415 rPtr->offset = 22;
416 rPtr->margins.left = 22;
417 rPtr->margins.body = 22;
418 rPtr->margins.first = 42;
419 rPtr->margins.right = (w<502?w:502);
421 rPtr->flags.whichMarker = 0; /* none */
422 rPtr->flags.buttonPressed = False;
424 rPtr->moveAction = NULL;
425 rPtr->releaseAction = NULL;
427 rPtr->pview = W_VIEW(parent);
429 return rPtr;
433 void
434 WMSetRulerMargins(WMRuler *rPtr, WMRulerMargins margins)
436 if(!rPtr)
437 return;
438 rPtr->margins.left = margins.left + rPtr->offset;
439 rPtr->margins.right = margins.right + rPtr->offset;
440 rPtr->margins.first = margins.first + rPtr->offset;
441 rPtr->margins.body = margins.body + rPtr->offset;
442 rPtr->margins.tabs = margins.tabs; //for loop
443 paintRuler(rPtr);
447 WMRulerMargins
448 WMGetRulerMargins(WMRuler *rPtr)
450 WMRulerMargins margins;
451 if(!rPtr)
452 return margins;
454 margins.left = rPtr->margins.left - rPtr->offset;
455 margins.right = rPtr->margins.right - rPtr->offset;
456 margins.first = rPtr->margins.first - rPtr->offset;
457 margins.body = rPtr->margins.body - rPtr->offset;
458 //for
459 margins.tabs = rPtr->margins.tabs;
461 return rPtr->margins;
464 void
465 WMSetRulerOffset(WMRuler *rPtr, int pixels)
467 if(!rPtr || pixels<0 || pixels+MIN_DOC_WIDTH>=rPtr->view->size.width)
468 return;
469 rPtr->offset = pixels;
470 //rulerDidResize(rPtr, rPtr->view);
474 WMGetRulerOffset(WMRuler *rPtr)
476 if(!rPtr)
477 return;
478 return rPtr->offset;
481 void
482 WMSetRulerReleaseAction(WMRuler *rPtr, WMAction *action, void *clientData)
484 if(!rPtr)
485 return;
487 rPtr->releaseAction = action;
488 rPtr->clientData = clientData;
491 void
492 WMSetRulerMoveAction(WMRuler *rPtr, WMAction *action, void *clientData)
494 if(!rPtr)
495 return;
497 rPtr->moveAction = action;
498 rPtr->clientData = clientData;
501 /* _which_ one was released */
503 WMGetReleasedRulerMargin(WMRuler *rPtr)
505 if(!rPtr)
506 return 0;
507 return rPtr->flags.whichMarker;
510 /* _which_ one is being grabbed */
512 WMGetGrabbedRulerMargin(WMRuler *rPtr)
514 if(!rPtr)
515 return 0;
516 return rPtr->flags.whichMarker;