various fixes, scrollview scrollers, text painting
[wmaker-crm.git] / WINGs / wscrollview.c
blob460620b554be9e5e29fc055dd4f80213831948ab
5 #include "WINGsP.h"
8 typedef struct W_ScrollView {
9 W_Class widgetClass;
10 WMView *view;
12 WMView *contentView;
13 WMView *viewport;
15 WMScroller *vScroller;
16 WMScroller *hScroller;
18 short lineScroll;
19 short pageScroll;
21 struct {
22 WMReliefType relief:3;
23 unsigned int hasVScroller:1;
24 unsigned int hasHScroller:1;
26 } flags;
28 } ScrollView;
33 static void destroyScrollView(ScrollView *sPtr);
35 static void paintScrollView(ScrollView *sPtr);
36 static void handleEvents(XEvent *event, void *data);
37 static void handleViewportEvents(XEvent *event, void *data);
38 static void resizeScrollView();
39 static void updateScrollerProportion();
41 W_ViewDelegate _ScrollViewViewDelegate = {
42 NULL,
43 NULL,
44 resizeScrollView,
45 NULL,
46 NULL
51 WMScrollView*
52 WMCreateScrollView(WMWidget *parent)
54 ScrollView *sPtr;
56 sPtr = wmalloc(sizeof(ScrollView));
57 memset(sPtr, 0, sizeof(ScrollView));
59 sPtr->widgetClass = WC_ScrollView;
61 sPtr->view = W_CreateView(W_VIEW(parent));
62 if (!sPtr->view) {
63 wfree(sPtr);
64 return NULL;
66 sPtr->viewport = W_CreateView(sPtr->view);
67 if (!sPtr->viewport) {
68 W_DestroyView(sPtr->view);
69 wfree(sPtr);
70 return NULL;
72 sPtr->view->self = sPtr;
73 sPtr->viewport->self = sPtr;
75 sPtr->view->delegate = &_ScrollViewViewDelegate;
77 sPtr->viewport->flags.mapWhenRealized = 1;
79 WMCreateEventHandler(sPtr->view, StructureNotifyMask|ExposureMask,
80 handleEvents, sPtr);
81 WMCreateEventHandler(sPtr->viewport, SubstructureNotifyMask,
82 handleViewportEvents, sPtr);
84 sPtr->lineScroll = 4;
86 sPtr->pageScroll = 0;
88 return sPtr;
92 static void
93 applyScrollerValues(WMScrollView *sPtr)
95 int x, y;
97 if (sPtr->contentView == NULL)
98 return;
100 if (sPtr->flags.hasHScroller) {
101 float v = WMGetScrollerValue(sPtr->hScroller);
102 int size;
104 size = sPtr->contentView->size.width-sPtr->viewport->size.width;
106 x = v * size;
107 } else {
108 x = 0;
111 if (sPtr->flags.hasVScroller) {
112 float v = WMGetScrollerValue(sPtr->vScroller);
114 int size;
116 size = sPtr->contentView->size.height-sPtr->viewport->size.height;
118 y = v * size;
119 } else {
120 y = 0;
125 x = WMAX(0, x);
126 y = WMAX(0, y);
128 W_MoveView(sPtr->contentView, -x, -y);
130 W_RaiseView(sPtr->viewport);
134 static void
135 reorganizeInterior(WMScrollView *sPtr)
137 int hx, hy, hw;
138 int vx, vy, vh;
139 int cx, cy, cw, ch;
142 cw = hw = sPtr->view->size.width;
143 vh = ch = sPtr->view->size.height;
145 if (sPtr->flags.relief == WRSimple) {
146 cw -= 2;
147 ch -= 2;
148 cx = 1;
149 cy = 1;
150 } else if (sPtr->flags.relief != WRFlat) {
151 cw -= 3;
152 ch -= 3;
153 cx = 2;
154 cy = 2;
155 } else {
156 cx = 0;
157 cy = 0;
160 if (sPtr->flags.hasHScroller) {
161 int h = 20;
163 ch -= h;
165 if (sPtr->flags.relief == WRSimple) {
166 hx = 0;
167 hy = sPtr->view->size.height - h;
168 } else if (sPtr->flags.relief != WRFlat) {
169 hx = 1;
170 hy = sPtr->view->size.height - h - 1;
171 hw -= 2;
172 } else {
173 hx = 0;
174 hy = sPtr->view->size.height - h;
176 } else {
177 /* make compiler shutup */
178 hx = 0;
179 hy = 0;
182 if (sPtr->flags.hasVScroller) {
183 int w = 20;
184 cw -= w;
185 cx += w;
186 hx += w - 1;
187 hw -= w - 1;
189 if (sPtr->flags.relief == WRSimple) {
190 vx = 0;
191 vy = 0;
192 } else if (sPtr->flags.relief != WRFlat) {
193 vx = 1;
194 vy = 1;
195 vh -= 2;
196 } else {
197 vx = 0;
198 vy = 0;
200 } else {
201 /* make compiler shutup */
202 vx = 0;
203 vy = 0;
206 W_ResizeView(sPtr->viewport, cw, ch);
207 W_MoveView(sPtr->viewport, cx, cy);
209 if (sPtr->flags.hasHScroller) {
210 WMResizeWidget(sPtr->hScroller, hw, 20);
211 WMMoveWidget(sPtr->hScroller, hx, hy);
213 if (sPtr->flags.hasVScroller) {
214 WMResizeWidget(sPtr->vScroller, 20, vh);
215 WMMoveWidget(sPtr->vScroller, vx, vy);
218 applyScrollerValues(sPtr);
222 static void
223 resizeScrollView(W_ViewDelegate *self, WMView *view)
225 reorganizeInterior(view->self);
226 updateScrollerProportion(view->self);
231 void
232 WMResizeScrollViewContent(WMScrollView *sPtr, unsigned int width,
233 unsigned int height)
235 int w, h, x;
237 w = width;
238 h = height;
240 x = 0;
241 if (sPtr->flags.relief == WRSimple) {
242 w += 2;
243 h += 2;
244 } else if (sPtr->flags.relief != WRFlat) {
245 w += 4;
246 h += 4;
247 x = 1;
250 if (sPtr->flags.hasVScroller) {
251 width -= W_VIEW(sPtr->hScroller)->size.width;
252 WMResizeWidget(sPtr->vScroller, 20, h);
254 if (sPtr->flags.hasHScroller) {
255 height -= W_VIEW(sPtr->hScroller)->size.height;
256 WMResizeWidget(sPtr->hScroller, w, 20);
257 WMMoveWidget(sPtr->hScroller, x, h);
260 W_ResizeView(sPtr->view, w, h);
262 W_ResizeView(sPtr->viewport, width, height);
266 void
267 WMSetScrollViewLineScroll(WMScrollView *sPtr, int amount)
269 assert(amount > 0);
271 sPtr->lineScroll = amount;
275 void
276 WMSetScrollViewPageScroll(WMScrollView *sPtr, int amount)
278 assert(amount >= 0);
280 sPtr->pageScroll = amount;
284 WMRect
285 WMGetScrollViewVisibleRect(WMScrollView *sPtr)
287 WMRect rect;
289 rect.pos.x = -sPtr->contentView->pos.x;
290 rect.pos.y = -sPtr->contentView->pos.y;
291 rect.size = sPtr->viewport->size;
293 return rect;
297 void
298 WMScrollViewScrollPoint(WMScrollView *sPtr, WMPoint point)
300 float xsize, ysize;
301 float xpos, ypos;
303 xsize = sPtr->contentView->size.width-sPtr->viewport->size.width;
304 ysize = sPtr->contentView->size.height-sPtr->viewport->size.height;
306 xpos = point.x / xsize;
307 ypos = point.y / ysize;
309 if (sPtr->hScroller)
310 WMSetScrollerParameters(sPtr->hScroller, xpos,
311 WMGetScrollerKnobProportion(sPtr->hScroller));
312 if (sPtr->vScroller)
313 WMSetScrollerParameters(sPtr->vScroller, ypos,
314 WMGetScrollerKnobProportion(sPtr->vScroller));
316 W_MoveView(sPtr->contentView, -point.x, -point.y);
320 static void
321 doScrolling(WMWidget *self, void *data)
323 ScrollView *sPtr = (ScrollView*)data;
324 float value;
325 int pos;
326 int vpsize;
327 float size;
329 if (sPtr->hScroller == (WMScroller *)self) {
330 pos = -sPtr->contentView->pos.x;
331 size = sPtr->contentView->size.width-sPtr->viewport->size.width;
332 vpsize = sPtr->viewport->size.width - sPtr->pageScroll;
333 } else {
334 pos = -sPtr->contentView->pos.y;
335 size = sPtr->contentView->size.height-sPtr->viewport->size.height;
336 vpsize = sPtr->viewport->size.height - sPtr->pageScroll;
338 if (vpsize <= 0)
339 vpsize = 1;
341 switch (WMGetScrollerHitPart(self)) {
342 case WSDecrementLine:
343 if (pos > 0) {
344 pos-=sPtr->lineScroll;
345 if (pos < 0)
346 pos = 0;
347 value = (float)pos / size;
348 WMSetScrollerParameters(self, value,
349 WMGetScrollerKnobProportion(self));
351 break;
352 case WSIncrementLine:
353 if (pos < size) {
354 pos+=sPtr->lineScroll;
355 if (pos > size)
356 pos = size;
357 value = (float)pos / size;
358 WMSetScrollerParameters(self, value,
359 WMGetScrollerKnobProportion(self));
361 break;
363 case WSKnob:
364 value = WMGetScrollerValue(self);
365 pos = value*size;
366 break;
368 case WSDecrementPage:
369 if (pos > 0) {
370 pos -= vpsize;
371 if (pos < 0)
372 pos = 0;
373 value = (float)pos / size;
374 WMSetScrollerParameters(self, value,
375 WMGetScrollerKnobProportion(self));
377 break;
379 case WSDecrementWheel:
380 if (pos > 0) {
381 pos -= vpsize/3;
382 if (pos < 0)
383 pos = 0;
384 value = (float)pos / size;
385 WMSetScrollerParameters(self, value,
386 WMGetScrollerKnobProportion(self));
388 break;
390 case WSIncrementPage:
391 if (pos < size) {
392 pos += vpsize;
393 if (pos > size)
394 pos = size;
395 value = (float)pos / size;
396 WMSetScrollerParameters(self, value,
397 WMGetScrollerKnobProportion(self));
399 break;
401 case WSIncrementWheel:
402 if (pos < size) {
403 pos += vpsize/3;
404 if (pos > size)
405 pos = size;
406 value = (float)pos / size;
407 WMSetScrollerParameters(self, value,
408 WMGetScrollerKnobProportion(self));
410 break;
412 case WSNoPart:
413 case WSKnobSlot:
414 break;
417 if (sPtr->hScroller == (WMScroller *)self) {
418 W_MoveView(sPtr->contentView, -pos, sPtr->contentView->pos.y);
419 } else {
420 W_MoveView(sPtr->contentView, sPtr->contentView->pos.x, -pos);
425 WMScroller*
426 WMGetScrollViewHorizontalScroller(WMScrollView *sPtr)
428 return sPtr->hScroller;
433 WMScroller*
434 WMGetScrollViewVerticalScroller(WMScrollView *sPtr)
436 return sPtr->vScroller;
440 void
441 WMSetScrollViewHasHorizontalScroller(WMScrollView *sPtr, Bool flag)
443 if (flag) {
444 if (sPtr->flags.hasHScroller)
445 return;
446 sPtr->flags.hasHScroller = 1;
448 sPtr->hScroller = WMCreateScroller(sPtr);
449 WMSetScrollerAction(sPtr->hScroller, doScrolling, sPtr);
450 /* make it a horiz. scroller */
451 WMResizeWidget(sPtr->hScroller, 2, 1);
453 if (W_VIEW_REALIZED(sPtr->view)) {
454 WMRealizeWidget(sPtr->hScroller);
457 reorganizeInterior(sPtr);
459 WMMapWidget(sPtr->hScroller);
460 } else {
461 if (!sPtr->flags.hasHScroller)
462 return;
464 WMUnmapWidget(sPtr->hScroller);
465 WMDestroyWidget(sPtr->hScroller);
466 sPtr->hScroller = NULL;
467 sPtr->flags.hasHScroller = 0;
469 reorganizeInterior(sPtr);
474 void
475 WMSetScrollViewHasVerticalScroller(WMScrollView *sPtr, Bool flag)
477 if (flag) {
478 if (sPtr->flags.hasVScroller)
479 return;
480 sPtr->flags.hasVScroller = 1;
482 sPtr->vScroller = WMCreateScroller(sPtr);
483 WMSetScrollerAction(sPtr->vScroller, doScrolling, sPtr);
484 WMSetScrollerArrowsPosition(sPtr->vScroller, WSAMaxEnd);
485 /* make it a vert. scroller */
486 WMResizeWidget(sPtr->vScroller, 1, 2);
488 if (W_VIEW_REALIZED(sPtr->view)) {
489 WMRealizeWidget(sPtr->vScroller);
492 reorganizeInterior(sPtr);
494 WMMapWidget(sPtr->vScroller);
495 } else {
496 if (!sPtr->flags.hasVScroller)
497 return;
498 sPtr->flags.hasVScroller = 0;
500 WMUnmapWidget(sPtr->vScroller);
501 WMDestroyWidget(sPtr->vScroller);
502 sPtr->vScroller = NULL;
504 reorganizeInterior(sPtr);
509 void
510 WMSetScrollViewContentView(WMScrollView *sPtr, WMView *view)
512 assert(sPtr->contentView == NULL);
514 sPtr->contentView = view;
516 W_ReparentView(sPtr->contentView, sPtr->viewport, 0, 0);
518 if (sPtr->flags.hasHScroller) {
519 float prop;
521 prop = (float)sPtr->viewport->size.width/sPtr->contentView->size.width;
522 WMSetScrollerParameters(sPtr->hScroller, 0, prop);
524 if (sPtr->flags.hasVScroller) {
525 float prop;
527 prop = (float)sPtr->viewport->size.height/sPtr->contentView->size.height;
529 WMSetScrollerParameters(sPtr->vScroller, 0, prop);
534 void
535 WMSetScrollViewRelief(WMScrollView *sPtr, WMReliefType type)
537 sPtr->flags.relief = type;
539 reorganizeInterior(sPtr);
541 if (sPtr->view->flags.mapped)
542 paintScrollView(sPtr);
549 static void
550 paintScrollView(ScrollView *sPtr)
552 W_DrawRelief(sPtr->view->screen, sPtr->view->window, 0, 0,
553 sPtr->view->size.width, sPtr->view->size.height,
554 sPtr->flags.relief);
558 static void
559 updateScrollerProportion(ScrollView *sPtr)
561 float prop, value;
562 float oldV, oldP;
564 if (sPtr->flags.hasHScroller) {
565 oldV = WMGetScrollerValue(sPtr->hScroller);
566 oldP = WMGetScrollerKnobProportion(sPtr->hScroller);
568 prop = (float)sPtr->viewport->size.width/(float)sPtr->contentView->size.width;
570 if (oldP == 1.0)
571 value = 0;
572 else
573 value = (prop * oldV) / oldP;
574 WMSetScrollerParameters(sPtr->hScroller, value, prop);
576 if (sPtr->flags.hasVScroller) {
577 oldV = WMGetScrollerValue(sPtr->vScroller);
578 oldP = WMGetScrollerKnobProportion(sPtr->vScroller);
580 prop = (float)sPtr->viewport->size.height/(float)sPtr->contentView->size.height;
582 if (oldP == 1.0)
583 value = 0;
584 else
585 value = (prop * oldV) / oldP;
586 WMSetScrollerParameters(sPtr->vScroller, value, prop);
588 applyScrollerValues(sPtr);
592 static void
593 handleViewportEvents(XEvent *event, void *data)
595 ScrollView *sPtr = (ScrollView*)data;
597 if (sPtr->contentView
598 && event->xconfigure.window == sPtr->contentView->window)
599 updateScrollerProportion(sPtr);
603 static void
604 handleEvents(XEvent *event, void *data)
606 ScrollView *sPtr = (ScrollView*)data;
608 CHECK_CLASS(data, WC_ScrollView);
610 switch (event->type) {
611 case Expose:
612 if (event->xexpose.count!=0)
613 break;
614 if (event->xexpose.serial == 0) /* means it's artificial */
615 W_RedisplayView(sPtr->contentView);
616 else
617 paintScrollView(sPtr);
618 break;
620 case DestroyNotify:
621 destroyScrollView(sPtr);
622 break;
628 static void
629 destroyScrollView(ScrollView *sPtr)
631 wfree(sPtr);