Added new wruler.{c,h} files from nwanua
[wmaker-crm.git] / WINGs / wruler.c
blob3d2c7e6c65259a695ec45f7967028353910fed6f
1 #include "wruler.h"
3 #define MIN_DOC_WIDTH 10
5 typedef struct W_Ruler {
6 W_Class widgetClass;
7 W_View *view;
8 W_View *pview; /* the parent's view (for drawing the line) */
10 WMAction *moveAction; /* what to when while moving */
11 WMAction *releaseAction; /* what to do when released */
12 void *clientData;
14 GC fg, bg;
15 WMFont *font;
16 WMRulerMargins margins;
17 int offset;
18 int motion; /* the position of the _moving_ marker(s) */
19 int end; /* the last tick on the baseline (restrict markers to it) */
21 Pixmap drawBuffer;
23 struct {
24 unsigned int buttonPressed:1;
25 /* 0, 1, 2, 3, 4, 5, 6 */
26 unsigned int whichMarker:3; /* none, left, right, first, body, tabstop, both */
27 unsigned int RESERVED:28;
28 } flags;
29 } Ruler;
33 /* Marker for left margin
36 | \
37 |__\
39 | */
40 static void
41 drawLeftMarker(Ruler *rPtr)
43 XPoint points[4];
44 int xpos = (rPtr->flags.whichMarker==1?
45 rPtr->motion:rPtr->margins.left);
47 XDrawLine(rPtr->view->screen->display, rPtr->drawBuffer,
48 rPtr->fg, xpos, 8, xpos, 22);
49 points[0].x = xpos;
50 points[0].y = 1;
51 points[1].x = points[0].x+6;
52 points[1].y = 8;
53 points[2].x = points[0].x+6;
54 points[2].y = 9;
55 points[3].x = points[0].x;
56 points[3].y = 9;
57 XFillPolygon (rPtr->view->screen->display, rPtr->drawBuffer,
58 rPtr->fg, points, 4, Convex, CoordModeOrigin);
61 /* Marker for right margin
64 / |
65 /__|
67 | */
69 static void
70 drawRightMarker(Ruler *rPtr)
72 XPoint points[4];
73 int xpos = (rPtr->flags.whichMarker==2?
74 rPtr->motion:rPtr->margins.right);
76 XDrawLine(rPtr->view->screen->display, rPtr->drawBuffer,
77 rPtr->fg, xpos, 8, xpos, 22);
78 points[0].x = xpos+1;
79 points[0].y = 0;
80 points[1].x = points[0].x-6;
81 points[1].y = 7;
82 points[2].x = points[0].x-6;
83 points[2].y = 9;
84 points[3].x = points[0].x;
85 points[3].y = 9;
86 XFillPolygon (rPtr->view->screen->display, rPtr->drawBuffer,
87 rPtr->fg, points, 4, Convex, CoordModeOrigin);
91 /* Marker for first line only
92 _____
93 |___|
94 | */
95 static void
96 drawFirstMarker(Ruler *rPtr)
98 int xpos = ((rPtr->flags.whichMarker==3 || rPtr->flags.whichMarker==6)?
99 rPtr->motion:rPtr->margins.first);
100 XFillRectangle(rPtr->view->screen->display, rPtr->drawBuffer,
101 rPtr->fg, xpos-5, 10, 11, 5);
102 XDrawLine(rPtr->view->screen->display, rPtr->drawBuffer,
103 rPtr->fg, xpos, 12, xpos, 22);
106 /* Marker for rest of body
107 _____
109 \./ */
110 static void
111 drawBodyMarker(Ruler *rPtr)
113 XPoint points[4];
114 int xpos = ((rPtr->flags.whichMarker==4 || rPtr->flags.whichMarker==6)?
115 rPtr->motion:rPtr->margins.body);
116 points[0].x = xpos-5;
117 points[0].y = 16;
118 points[1].x = points[0].x+11;
119 points[1].y = 16;
120 points[2].x = points[0].x+5;
121 points[2].y = 22;
122 XFillPolygon (rPtr->view->screen->display, rPtr->drawBuffer,
123 rPtr->fg, points, 3, Convex, CoordModeOrigin);
126 static void
127 createDrawBuffer(Ruler *rPtr)
129 if(rPtr->drawBuffer)
130 XFreePixmap(rPtr->view->screen->display, rPtr->drawBuffer);
131 rPtr->drawBuffer = XCreatePixmap(rPtr->view->screen->display,
132 rPtr->view->window, rPtr->view->size.width, 40,
133 rPtr->view->screen->depth);
134 XFillRectangle(rPtr->view->screen->display, rPtr->drawBuffer,
135 rPtr->bg, 0, 0, rPtr->view->size.width, 40);
138 static void
139 drawRulerOnPixmap(Ruler *rPtr)
141 int i, j, w, m;
142 char c[3];
143 int marks[9] = {11, 3, 5, 3, 7, 3, 5, 3};
145 if(!rPtr->drawBuffer)
146 createDrawBuffer(rPtr);
148 XFillRectangle(rPtr->view->screen->display, rPtr->drawBuffer,
149 rPtr->bg, 0, 0, rPtr->view->size.width, 40);
152 WMDrawString(rPtr->view->screen, rPtr->drawBuffer,
153 rPtr->fg, rPtr->font, rPtr->margins.left+2, 26, "0 inches", 10);
155 /* marker ticks */
156 i=j=m=0;
157 w = rPtr->view->size.width - rPtr->margins.left;
158 while(m < w) {
159 XDrawLine(rPtr->view->screen->display, rPtr->drawBuffer,
160 rPtr->fg, rPtr->margins.left+m, 23,
161 rPtr->margins.left+m, marks[i%8]+23);
162 if(i!=0 && i%8==0) {
163 if(j<10)
164 snprintf(c,3,"%d",++j);
165 else
166 snprintf(c,3,"%2d",++j);
167 WMDrawString(rPtr->view->screen, rPtr->drawBuffer,
168 rPtr->fg, rPtr->font, rPtr->margins.left+2+m, 26, c, 2);
170 m = (++i)*10;
173 rPtr->end = rPtr->margins.left+m-10;
174 if(rPtr->margins.right > rPtr->end)
175 rPtr->margins.right = rPtr->end;
176 /* base line */
177 XDrawLine(rPtr->view->screen->display, rPtr->drawBuffer,
178 rPtr->fg, rPtr->margins.left, 22, rPtr->margins.left+m-10, 22);
180 drawLeftMarker(rPtr);
181 drawRightMarker(rPtr);
182 drawFirstMarker(rPtr);
183 drawBodyMarker(rPtr);
186 static void
187 paintRuler(Ruler *rPtr)
189 WMScreen *screen = rPtr->view->screen;
190 if(1||!rPtr->drawBuffer) { //first exposure
191 drawRulerOnPixmap(rPtr);
194 XCopyArea(rPtr->view->screen->display, rPtr->drawBuffer,
195 rPtr->view->window, rPtr->bg, 0, 0, rPtr->view->size.width, 40,
196 0, 0);
199 static Bool
200 verifyMarkerMove(Ruler *rPtr, int x)
202 if(rPtr->flags.whichMarker<1 || rPtr->flags.whichMarker>6)
203 return False;
205 switch(rPtr->flags.whichMarker) {
206 case 1:
207 if( x > rPtr->margins.right - 10
208 || rPtr->margins.body + x > rPtr->margins.right-MIN_DOC_WIDTH
209 || rPtr->margins.first + x > rPtr->margins.right-MIN_DOC_WIDTH
210 || x < rPtr->offset)
211 return False;
212 break;
214 case 2:
215 if( x < rPtr->margins.first+MIN_DOC_WIDTH
216 || x < rPtr->margins.body+MIN_DOC_WIDTH
217 || x < rPtr->margins.left+MIN_DOC_WIDTH
218 || x > rPtr->end) //rPtr->view->size.width)
219 return False;
220 break;
222 case 3:
223 if( x >= rPtr->margins.right-MIN_DOC_WIDTH
224 || x < rPtr->margins.left)
225 return False;
226 break;
228 case 4:
229 if( x >= rPtr->margins.right-MIN_DOC_WIDTH
230 || x < rPtr->margins.left)
231 return False;
232 break;
234 case 6:
235 if( x >= rPtr->margins.right-MIN_DOC_WIDTH
236 || x < rPtr->margins.left)
237 return False;
238 break;
240 default: return False;
243 rPtr->motion = x;
244 return True;
248 static int
249 whichMarker(Ruler *rPtr, int x, int y)
251 if(x<rPtr->offset || y>22)
252 return 0;
254 if( rPtr->margins.left-x >= -6 && y <= 9
255 && (rPtr->margins.left-x <=0) && y>=4) {
256 rPtr->motion = rPtr->margins.left;
257 return 1;
260 if(rPtr->margins.right-x >= -1 && y <= 11
261 && rPtr->margins.right-x <=5 && y>=4) {
262 rPtr->motion = rPtr->margins.right;
263 return 2;
266 #if 0
267 /* both first and body? */
268 if( rPtr->margins.first-x <= 4 && rPtr->margins.first-x >= -5
269 && rPtr->margins.body-x <= 4 && rPtr->margins.body-x >= -5
270 && y>=15 && y<=17) {
271 rPtr->motion = rPtr->margins.first;
272 return 6;
274 #endif
276 if(rPtr->margins.first-x <= 4 && y<=15
277 && rPtr->margins.first-x >= -5 && y>=10) {
278 rPtr->motion = rPtr->margins.first;
279 return 3;
282 if( rPtr->margins.body-x <= 4 && y<=21 &&
283 rPtr->margins.body-x >= -5 && y>=17) {
284 rPtr->motion = rPtr->margins.body;
285 return 4;
289 /* do tabs (5)*/
292 return 0;
296 static void
297 handleEvents(XEvent *event, void *data)
299 Ruler *rPtr = (Ruler*)data;
300 Display *dpy = event->xany.display;
302 switch (event->type) {
303 case Expose:
304 paintRuler(rPtr);
305 break;
307 case MotionNotify:
308 if(rPtr->flags.buttonPressed
309 && (event->xmotion.state & Button1Mask)) {
310 if(verifyMarkerMove(rPtr, event->xmotion.x)){
311 GC gc = WMColorGC(WMDarkGrayColor(rPtr->view->screen));
312 paintRuler(rPtr);
313 if(rPtr->moveAction)
314 (rPtr->moveAction)(rPtr, rPtr->clientData);
315 XSetLineAttributes(rPtr->view->screen->display, gc, 1,
316 LineSolid, CapNotLast, JoinMiter);
317 XDrawLine(rPtr->pview->screen->display,
318 rPtr->pview->window,
319 gc, rPtr->motion+1, 40,
320 rPtr->motion+1, rPtr->pview->size.height-5);
323 break;
325 case ButtonPress:
326 if(event->xbutton.button != Button1)
327 return;
328 rPtr->flags.buttonPressed = True;
329 rPtr->flags.whichMarker =
330 whichMarker(rPtr, event->xmotion.x,
331 event->xmotion.y);
332 break;
334 case ButtonRelease:
335 if(event->xbutton.button != Button1)
336 return;
337 rPtr->flags.buttonPressed = False;
338 switch(rPtr->flags.whichMarker) {
339 case 1: {
340 int change = rPtr->margins.left-rPtr->motion;
341 rPtr->margins.first -=change;
342 rPtr->margins.body -= change;
343 rPtr->margins.left = rPtr->motion;
344 paintRuler(rPtr); break;
346 case 2: rPtr->margins.right = rPtr->motion; break;
347 case 3: rPtr->margins.first = rPtr->motion; break;
348 case 4: rPtr->margins.body = rPtr->motion; break;
349 case 6: rPtr->margins.first = rPtr->margins.body
350 = rPtr->motion; break;
352 if(rPtr->releaseAction)
353 (rPtr->releaseAction)(rPtr, rPtr->clientData);
354 break;
358 static void
359 rulerDidResize(W_ViewDelegate *self, WMView *view)
361 Ruler *rPtr = (Ruler *)view->self;
363 createDrawBuffer(rPtr);
364 paintRuler(rPtr);
369 W_ViewDelegate _RulerViewDelegate =
371 NULL,
372 NULL,
373 rulerDidResize,
374 NULL,
375 NULL
379 WMRuler *
380 WMCreateRuler(WMWidget *parent)
382 Ruler *rPtr = wmalloc(sizeof(Ruler));
383 unsigned int w = WMWidgetWidth(parent);
385 memset(rPtr, 0, sizeof(Ruler));
387 rPtr->widgetClass = WC_Ruler;
389 rPtr->view = W_CreateView(W_VIEW(parent));
390 if (!rPtr->view) {
391 free(rPtr);
392 return NULL;
394 rPtr->view->self = rPtr;
396 rPtr->drawBuffer = (Pixmap) NULL;
398 W_ResizeView(rPtr->view, w, 40);
400 WMCreateEventHandler(rPtr->view, ExposureMask|StructureNotifyMask
401 |EnterWindowMask|LeaveWindowMask|FocusChangeMask
402 |ButtonReleaseMask|ButtonPressMask|KeyReleaseMask
403 |KeyPressMask|Button1MotionMask, handleEvents, rPtr);
405 rPtr->view->delegate = &_RulerViewDelegate;
407 rPtr->bg = WMColorGC(WMGrayColor(rPtr->view->screen));
408 rPtr->fg = WMColorGC(WMBlackColor(rPtr->view->screen));
409 rPtr->font = WMSystemFontOfSize(rPtr->view->screen, 8);
411 rPtr->offset = 22;
412 rPtr->margins.left = 22;
413 rPtr->margins.body = 22;
414 rPtr->margins.first = 42;
415 rPtr->margins.right = (w<502?w:502);
417 rPtr->flags.whichMarker = 0; /* none */
418 rPtr->flags.buttonPressed = False;
420 rPtr->moveAction = NULL;
421 rPtr->releaseAction = NULL;
423 rPtr->pview = W_VIEW(parent);
425 return rPtr;
429 void
430 WMSetRulerMargins(WMRuler *rPtr, WMRulerMargins margins)
432 if(!rPtr)
433 return;
434 rPtr->margins.left = margins.left + rPtr->offset;
435 rPtr->margins.right = margins.right + rPtr->offset;
436 rPtr->margins.first = margins.first + rPtr->offset;
437 rPtr->margins.body = margins.body + rPtr->offset;
438 rPtr->margins.tabs = margins.tabs; //for loop
439 paintRuler(rPtr);
443 WMRulerMargins
444 WMGetRulerMargins(WMRuler *rPtr)
446 WMRulerMargins margins;
447 if(!rPtr)
448 return margins;
450 margins.left = rPtr->margins.left - rPtr->offset;
451 margins.right = rPtr->margins.right - rPtr->offset;
452 margins.first = rPtr->margins.first - rPtr->offset;
453 margins.body = rPtr->margins.body - rPtr->offset;
454 //for
455 margins.tabs = rPtr->margins.tabs;
457 return rPtr->margins;
460 void
461 WMSetRulerOffset(WMRuler *rPtr, int pixels)
463 if(!rPtr || pixels<0 || pixels+MIN_DOC_WIDTH>=rPtr->view->size.width)
464 return;
465 rPtr->offset = pixels;
466 //rulerDidResize(rPtr, rPtr->view);
469 int
470 WMGetRulerOffset(WMRuler *rPtr)
472 if(!rPtr)
473 return;
474 return rPtr->offset;
477 void
478 WMSetRulerReleaseAction(WMRuler *rPtr, WMAction *action, void *clientData)
480 if(!rPtr)
481 return;
483 rPtr->releaseAction = action;
484 rPtr->clientData = clientData;
487 void
488 WMSetRulerMoveAction(WMRuler *rPtr, WMAction *action, void *clientData)
490 if(!rPtr)
491 return;
493 rPtr->moveAction = action;
494 rPtr->clientData = clientData;
497 /* _which_ one was released */
498 int
499 WMGetReleasedRulerMargin(WMRuler *rPtr)
501 if(!rPtr)
502 return 0;
503 return rPtr->flags.whichMarker;
506 /* _which_ one is being grabbed */
507 int
508 WMGetGrabbedRulerMargin(WMRuler *rPtr)
510 if(!rPtr)
511 return 0;
512 return rPtr->flags.whichMarker;