changed indentation to use spaces only
[wmaker-crm.git] / WINGs / wscrollview.c
blob0285a2379498f0e58934f0fc5609e3bb1cc21324
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 WMResizeWidget(sPtr->vScroller, 20, h);
252 width -= W_VIEW(sPtr->vScroller)->size.width;
255 if (sPtr->flags.hasHScroller) {
256 WMResizeWidget(sPtr->hScroller, w, 20);
257 WMMoveWidget(sPtr->hScroller, x, h);
258 height -= W_VIEW(sPtr->hScroller)->size.height;
261 W_ResizeView(sPtr->view, w, h);
263 W_ResizeView(sPtr->viewport, width, height);
267 void
268 WMSetScrollViewLineScroll(WMScrollView *sPtr, int amount)
270 assert(amount > 0);
272 sPtr->lineScroll = amount;
276 void
277 WMSetScrollViewPageScroll(WMScrollView *sPtr, int amount)
279 assert(amount >= 0);
281 sPtr->pageScroll = amount;
285 WMRect
286 WMGetScrollViewVisibleRect(WMScrollView *sPtr)
288 WMRect rect;
290 rect.pos.x = -sPtr->contentView->pos.x;
291 rect.pos.y = -sPtr->contentView->pos.y;
292 rect.size = sPtr->viewport->size;
294 return rect;
298 void
299 WMScrollViewScrollPoint(WMScrollView *sPtr, WMPoint point)
301 float xsize, ysize;
302 float xpos, ypos;
304 xsize = sPtr->contentView->size.width-sPtr->viewport->size.width;
305 ysize = sPtr->contentView->size.height-sPtr->viewport->size.height;
307 xpos = point.x / xsize;
308 ypos = point.y / ysize;
310 if (sPtr->hScroller)
311 WMSetScrollerParameters(sPtr->hScroller, xpos,
312 WMGetScrollerKnobProportion(sPtr->hScroller));
313 if (sPtr->vScroller)
314 WMSetScrollerParameters(sPtr->vScroller, ypos,
315 WMGetScrollerKnobProportion(sPtr->vScroller));
317 W_MoveView(sPtr->contentView, -point.x, -point.y);
321 static void
322 doScrolling(WMWidget *self, void *data)
324 ScrollView *sPtr = (ScrollView*)data;
325 float value;
326 int pos;
327 int vpsize;
328 float size;
330 if (sPtr->hScroller == (WMScroller *)self) {
331 pos = -sPtr->contentView->pos.x;
332 size = sPtr->contentView->size.width-sPtr->viewport->size.width;
333 vpsize = sPtr->viewport->size.width - sPtr->pageScroll;
334 } else {
335 pos = -sPtr->contentView->pos.y;
336 size = sPtr->contentView->size.height-sPtr->viewport->size.height;
337 vpsize = sPtr->viewport->size.height - sPtr->pageScroll;
339 if (vpsize <= 0)
340 vpsize = 1;
342 switch (WMGetScrollerHitPart(self)) {
343 case WSDecrementLine:
344 if (pos > 0) {
345 pos-=sPtr->lineScroll;
346 if (pos < 0)
347 pos = 0;
348 value = (float)pos / size;
349 WMSetScrollerParameters(self, value,
350 WMGetScrollerKnobProportion(self));
352 break;
353 case WSIncrementLine:
354 if (pos < size) {
355 pos+=sPtr->lineScroll;
356 if (pos > size)
357 pos = size;
358 value = (float)pos / size;
359 WMSetScrollerParameters(self, value,
360 WMGetScrollerKnobProportion(self));
362 break;
364 case WSKnob:
365 value = WMGetScrollerValue(self);
366 pos = value*size;
367 break;
369 case WSDecrementPage:
370 if (pos > 0) {
371 pos -= vpsize;
372 if (pos < 0)
373 pos = 0;
374 value = (float)pos / size;
375 WMSetScrollerParameters(self, value,
376 WMGetScrollerKnobProportion(self));
378 break;
380 case WSDecrementWheel:
381 if (pos > 0) {
382 pos -= vpsize/3;
383 if (pos < 0)
384 pos = 0;
385 value = (float)pos / size;
386 WMSetScrollerParameters(self, value,
387 WMGetScrollerKnobProportion(self));
389 break;
391 case WSIncrementPage:
392 if (pos < size) {
393 pos += vpsize;
394 if (pos > size)
395 pos = size;
396 value = (float)pos / size;
397 WMSetScrollerParameters(self, value,
398 WMGetScrollerKnobProportion(self));
400 break;
402 case WSIncrementWheel:
403 if (pos < size) {
404 pos += vpsize/3;
405 if (pos > size)
406 pos = size;
407 value = (float)pos / size;
408 WMSetScrollerParameters(self, value,
409 WMGetScrollerKnobProportion(self));
411 break;
413 case WSNoPart:
414 case WSKnobSlot:
415 break;
418 if (sPtr->hScroller == (WMScroller *)self) {
419 W_MoveView(sPtr->contentView, -pos, sPtr->contentView->pos.y);
420 } else {
421 W_MoveView(sPtr->contentView, sPtr->contentView->pos.x, -pos);
426 WMScroller*
427 WMGetScrollViewHorizontalScroller(WMScrollView *sPtr)
429 return sPtr->hScroller;
434 WMScroller*
435 WMGetScrollViewVerticalScroller(WMScrollView *sPtr)
437 return sPtr->vScroller;
441 void
442 WMSetScrollViewHasHorizontalScroller(WMScrollView *sPtr, Bool flag)
444 if (flag) {
445 if (sPtr->flags.hasHScroller)
446 return;
447 sPtr->flags.hasHScroller = 1;
449 sPtr->hScroller = WMCreateScroller(sPtr);
450 WMSetScrollerAction(sPtr->hScroller, doScrolling, sPtr);
451 /* make it a horiz. scroller */
452 WMResizeWidget(sPtr->hScroller, 2, 1);
454 if (W_VIEW_REALIZED(sPtr->view)) {
455 WMRealizeWidget(sPtr->hScroller);
458 reorganizeInterior(sPtr);
460 WMMapWidget(sPtr->hScroller);
461 } else {
462 if (!sPtr->flags.hasHScroller)
463 return;
465 WMUnmapWidget(sPtr->hScroller);
466 WMDestroyWidget(sPtr->hScroller);
467 sPtr->hScroller = NULL;
468 sPtr->flags.hasHScroller = 0;
470 reorganizeInterior(sPtr);
475 void
476 WMSetScrollViewHasVerticalScroller(WMScrollView *sPtr, Bool flag)
478 if (flag) {
479 if (sPtr->flags.hasVScroller)
480 return;
481 sPtr->flags.hasVScroller = 1;
483 sPtr->vScroller = WMCreateScroller(sPtr);
484 WMSetScrollerAction(sPtr->vScroller, doScrolling, sPtr);
485 WMSetScrollerArrowsPosition(sPtr->vScroller, WSAMaxEnd);
486 /* make it a vert. scroller */
487 WMResizeWidget(sPtr->vScroller, 1, 2);
489 if (W_VIEW_REALIZED(sPtr->view)) {
490 WMRealizeWidget(sPtr->vScroller);
493 reorganizeInterior(sPtr);
495 WMMapWidget(sPtr->vScroller);
496 } else {
497 if (!sPtr->flags.hasVScroller)
498 return;
499 sPtr->flags.hasVScroller = 0;
501 WMUnmapWidget(sPtr->vScroller);
502 WMDestroyWidget(sPtr->vScroller);
503 sPtr->vScroller = NULL;
505 reorganizeInterior(sPtr);
510 void
511 WMSetScrollViewContentView(WMScrollView *sPtr, WMView *view)
513 assert(sPtr->contentView == NULL);
515 sPtr->contentView = view;
517 W_ReparentView(sPtr->contentView, sPtr->viewport, 0, 0);
519 if (sPtr->flags.hasHScroller) {
520 float prop;
522 prop = (float)sPtr->viewport->size.width/sPtr->contentView->size.width;
523 WMSetScrollerParameters(sPtr->hScroller, 0, prop);
525 if (sPtr->flags.hasVScroller) {
526 float prop;
528 prop = (float)sPtr->viewport->size.height/sPtr->contentView->size.height;
530 WMSetScrollerParameters(sPtr->vScroller, 0, prop);
535 void
536 WMSetScrollViewRelief(WMScrollView *sPtr, WMReliefType type)
538 sPtr->flags.relief = type;
540 reorganizeInterior(sPtr);
542 if (sPtr->view->flags.mapped)
543 paintScrollView(sPtr);
550 static void
551 paintScrollView(ScrollView *sPtr)
553 W_DrawRelief(sPtr->view->screen, sPtr->view->window, 0, 0,
554 sPtr->view->size.width, sPtr->view->size.height,
555 sPtr->flags.relief);
559 static void
560 updateScrollerProportion(ScrollView *sPtr)
562 float prop, value;
563 float oldV, oldP;
565 if (sPtr->flags.hasHScroller) {
566 oldV = WMGetScrollerValue(sPtr->hScroller);
567 oldP = WMGetScrollerKnobProportion(sPtr->hScroller);
569 prop = (float)sPtr->viewport->size.width/(float)sPtr->contentView->size.width;
571 if (oldP == 1.0)
572 value = 0;
573 else
574 value = (prop * oldV) / oldP;
575 WMSetScrollerParameters(sPtr->hScroller, value, prop);
577 if (sPtr->flags.hasVScroller) {
578 oldV = WMGetScrollerValue(sPtr->vScroller);
579 oldP = WMGetScrollerKnobProportion(sPtr->vScroller);
581 prop = (float)sPtr->viewport->size.height/(float)sPtr->contentView->size.height;
583 if (oldP == 1.0)
584 value = 0;
585 else
586 value = (prop * oldV) / oldP;
587 WMSetScrollerParameters(sPtr->vScroller, value, prop);
589 applyScrollerValues(sPtr);
593 static void
594 handleViewportEvents(XEvent *event, void *data)
596 ScrollView *sPtr = (ScrollView*)data;
598 if (sPtr->contentView
599 && event->xconfigure.window == sPtr->contentView->window)
600 updateScrollerProportion(sPtr);
604 static void
605 handleEvents(XEvent *event, void *data)
607 ScrollView *sPtr = (ScrollView*)data;
609 CHECK_CLASS(data, WC_ScrollView);
611 switch (event->type) {
612 case Expose:
613 if (event->xexpose.count!=0)
614 break;
615 if (event->xexpose.serial == 0) /* means it's artificial */
616 W_RedisplayView(sPtr->contentView);
617 else
618 paintScrollView(sPtr);
619 break;
621 case DestroyNotify:
622 destroyScrollView(sPtr);
623 break;
629 static void
630 destroyScrollView(ScrollView *sPtr)
632 wfree(sPtr);