Change to the linux kernel coding style
[wmaker-crm.git] / WINGs / wscrollview.c
blob7733e27ce75cf4eefbb22337ecef2eb97fd440fe
2 #include "WINGsP.h"
4 typedef struct W_ScrollView {
5 W_Class widgetClass;
6 WMView *view;
8 WMView *contentView;
9 WMView *viewport;
11 WMScroller *vScroller;
12 WMScroller *hScroller;
14 short lineScroll;
15 short pageScroll;
17 struct {
18 WMReliefType relief:3;
19 unsigned int hasVScroller:1;
20 unsigned int hasHScroller:1;
22 } flags;
24 } ScrollView;
26 static void destroyScrollView(ScrollView * sPtr);
28 static void paintScrollView(ScrollView * sPtr);
29 static void handleEvents(XEvent * event, void *data);
30 static void handleViewportEvents(XEvent * event, void *data);
31 static void resizeScrollView();
32 static void updateScrollerProportion();
34 W_ViewDelegate _ScrollViewViewDelegate = {
35 NULL,
36 NULL,
37 resizeScrollView,
38 NULL,
39 NULL
42 WMScrollView *WMCreateScrollView(WMWidget * parent)
44 ScrollView *sPtr;
46 sPtr = wmalloc(sizeof(ScrollView));
47 memset(sPtr, 0, sizeof(ScrollView));
49 sPtr->widgetClass = WC_ScrollView;
51 sPtr->view = W_CreateView(W_VIEW(parent));
52 if (!sPtr->view) {
53 wfree(sPtr);
54 return NULL;
56 sPtr->viewport = W_CreateView(sPtr->view);
57 if (!sPtr->viewport) {
58 W_DestroyView(sPtr->view);
59 wfree(sPtr);
60 return NULL;
62 sPtr->view->self = sPtr;
63 sPtr->viewport->self = sPtr;
65 sPtr->view->delegate = &_ScrollViewViewDelegate;
67 sPtr->viewport->flags.mapWhenRealized = 1;
69 WMCreateEventHandler(sPtr->view, StructureNotifyMask | ExposureMask, handleEvents, sPtr);
70 WMCreateEventHandler(sPtr->viewport, SubstructureNotifyMask, handleViewportEvents, sPtr);
72 sPtr->lineScroll = 4;
74 sPtr->pageScroll = 0;
76 return sPtr;
79 static void applyScrollerValues(WMScrollView * sPtr)
81 int x, y;
83 if (sPtr->contentView == NULL)
84 return;
86 if (sPtr->flags.hasHScroller) {
87 float v = WMGetScrollerValue(sPtr->hScroller);
88 int size;
90 size = sPtr->contentView->size.width - sPtr->viewport->size.width;
92 x = v * size;
93 } else {
94 x = 0;
97 if (sPtr->flags.hasVScroller) {
98 float v = WMGetScrollerValue(sPtr->vScroller);
100 int size;
102 size = sPtr->contentView->size.height - sPtr->viewport->size.height;
104 y = v * size;
105 } else {
106 y = 0;
109 x = WMAX(0, x);
110 y = WMAX(0, y);
112 W_MoveView(sPtr->contentView, -x, -y);
114 W_RaiseView(sPtr->viewport);
117 static void reorganizeInterior(WMScrollView * sPtr)
119 int hx, hy, hw;
120 int vx, vy, vh;
121 int cx, cy, cw, ch;
123 cw = hw = sPtr->view->size.width;
124 vh = ch = sPtr->view->size.height;
126 if (sPtr->flags.relief == WRSimple) {
127 cw -= 2;
128 ch -= 2;
129 cx = 1;
130 cy = 1;
131 } else if (sPtr->flags.relief != WRFlat) {
132 cw -= 3;
133 ch -= 3;
134 cx = 2;
135 cy = 2;
136 } else {
137 cx = 0;
138 cy = 0;
141 if (sPtr->flags.hasHScroller) {
142 int h = 20;
144 ch -= h;
146 if (sPtr->flags.relief == WRSimple) {
147 hx = 0;
148 hy = sPtr->view->size.height - h;
149 } else if (sPtr->flags.relief != WRFlat) {
150 hx = 1;
151 hy = sPtr->view->size.height - h - 1;
152 hw -= 2;
153 } else {
154 hx = 0;
155 hy = sPtr->view->size.height - h;
157 } else {
158 /* make compiler shutup */
159 hx = 0;
160 hy = 0;
163 if (sPtr->flags.hasVScroller) {
164 int w = 20;
165 cw -= w;
166 cx += w;
167 hx += w - 1;
168 hw -= w - 1;
170 if (sPtr->flags.relief == WRSimple) {
171 vx = 0;
172 vy = 0;
173 } else if (sPtr->flags.relief != WRFlat) {
174 vx = 1;
175 vy = 1;
176 vh -= 2;
177 } else {
178 vx = 0;
179 vy = 0;
181 } else {
182 /* make compiler shutup */
183 vx = 0;
184 vy = 0;
187 W_ResizeView(sPtr->viewport, cw, ch);
188 W_MoveView(sPtr->viewport, cx, cy);
190 if (sPtr->flags.hasHScroller) {
191 WMResizeWidget(sPtr->hScroller, hw, 20);
192 WMMoveWidget(sPtr->hScroller, hx, hy);
194 if (sPtr->flags.hasVScroller) {
195 WMResizeWidget(sPtr->vScroller, 20, vh);
196 WMMoveWidget(sPtr->vScroller, vx, vy);
199 applyScrollerValues(sPtr);
202 static void resizeScrollView(W_ViewDelegate * self, WMView * view)
204 reorganizeInterior(view->self);
205 updateScrollerProportion(view->self);
208 void WMResizeScrollViewContent(WMScrollView * sPtr, unsigned int width, unsigned int height)
210 int w, h, x;
212 w = width;
213 h = height;
215 x = 0;
216 if (sPtr->flags.relief == WRSimple) {
217 w += 2;
218 h += 2;
219 } else if (sPtr->flags.relief != WRFlat) {
220 w += 4;
221 h += 4;
222 x = 1;
225 if (sPtr->flags.hasVScroller) {
226 WMResizeWidget(sPtr->vScroller, 20, h);
227 width -= W_VIEW(sPtr->vScroller)->size.width;
230 if (sPtr->flags.hasHScroller) {
231 WMResizeWidget(sPtr->hScroller, w, 20);
232 WMMoveWidget(sPtr->hScroller, x, h);
233 height -= W_VIEW(sPtr->hScroller)->size.height;
236 W_ResizeView(sPtr->view, w, h);
238 W_ResizeView(sPtr->viewport, width, height);
241 void WMSetScrollViewLineScroll(WMScrollView * sPtr, int amount)
243 assert(amount > 0);
245 sPtr->lineScroll = amount;
248 void WMSetScrollViewPageScroll(WMScrollView * sPtr, int amount)
250 assert(amount >= 0);
252 sPtr->pageScroll = amount;
255 WMRect WMGetScrollViewVisibleRect(WMScrollView * sPtr)
257 WMRect rect;
259 rect.pos.x = -sPtr->contentView->pos.x;
260 rect.pos.y = -sPtr->contentView->pos.y;
261 rect.size = sPtr->viewport->size;
263 return rect;
266 void WMScrollViewScrollPoint(WMScrollView * sPtr, WMPoint point)
268 float xsize, ysize;
269 float xpos, ypos;
271 xsize = sPtr->contentView->size.width - sPtr->viewport->size.width;
272 ysize = sPtr->contentView->size.height - sPtr->viewport->size.height;
274 xpos = point.x / xsize;
275 ypos = point.y / ysize;
277 if (sPtr->hScroller)
278 WMSetScrollerParameters(sPtr->hScroller, xpos, WMGetScrollerKnobProportion(sPtr->hScroller));
279 if (sPtr->vScroller)
280 WMSetScrollerParameters(sPtr->vScroller, ypos, WMGetScrollerKnobProportion(sPtr->vScroller));
282 W_MoveView(sPtr->contentView, -point.x, -point.y);
285 static void doScrolling(WMWidget * self, void *data)
287 ScrollView *sPtr = (ScrollView *) data;
288 float value;
289 int pos;
290 int vpsize;
291 float size;
293 if (sPtr->hScroller == (WMScroller *) self) {
294 pos = -sPtr->contentView->pos.x;
295 size = sPtr->contentView->size.width - sPtr->viewport->size.width;
296 vpsize = sPtr->viewport->size.width - sPtr->pageScroll;
297 } else {
298 pos = -sPtr->contentView->pos.y;
299 size = sPtr->contentView->size.height - sPtr->viewport->size.height;
300 vpsize = sPtr->viewport->size.height - sPtr->pageScroll;
302 if (vpsize <= 0)
303 vpsize = 1;
305 switch (WMGetScrollerHitPart(self)) {
306 case WSDecrementLine:
307 if (pos > 0) {
308 pos -= sPtr->lineScroll;
309 if (pos < 0)
310 pos = 0;
311 value = (float)pos / size;
312 WMSetScrollerParameters(self, value, WMGetScrollerKnobProportion(self));
314 break;
315 case WSIncrementLine:
316 if (pos < size) {
317 pos += sPtr->lineScroll;
318 if (pos > size)
319 pos = size;
320 value = (float)pos / size;
321 WMSetScrollerParameters(self, value, WMGetScrollerKnobProportion(self));
323 break;
325 case WSKnob:
326 value = WMGetScrollerValue(self);
327 pos = value * size;
328 break;
330 case WSDecrementPage:
331 if (pos > 0) {
332 pos -= vpsize;
333 if (pos < 0)
334 pos = 0;
335 value = (float)pos / size;
336 WMSetScrollerParameters(self, value, WMGetScrollerKnobProportion(self));
338 break;
340 case WSDecrementWheel:
341 if (pos > 0) {
342 pos -= vpsize / 3;
343 if (pos < 0)
344 pos = 0;
345 value = (float)pos / size;
346 WMSetScrollerParameters(self, value, WMGetScrollerKnobProportion(self));
348 break;
350 case WSIncrementPage:
351 if (pos < size) {
352 pos += vpsize;
353 if (pos > size)
354 pos = size;
355 value = (float)pos / size;
356 WMSetScrollerParameters(self, value, WMGetScrollerKnobProportion(self));
358 break;
360 case WSIncrementWheel:
361 if (pos < size) {
362 pos += vpsize / 3;
363 if (pos > size)
364 pos = size;
365 value = (float)pos / size;
366 WMSetScrollerParameters(self, value, WMGetScrollerKnobProportion(self));
368 break;
370 case WSNoPart:
371 case WSKnobSlot:
372 break;
375 if (sPtr->hScroller == (WMScroller *) self) {
376 W_MoveView(sPtr->contentView, -pos, sPtr->contentView->pos.y);
377 } else {
378 W_MoveView(sPtr->contentView, sPtr->contentView->pos.x, -pos);
382 WMScroller *WMGetScrollViewHorizontalScroller(WMScrollView * sPtr)
384 return sPtr->hScroller;
387 WMScroller *WMGetScrollViewVerticalScroller(WMScrollView * sPtr)
389 return sPtr->vScroller;
392 void WMSetScrollViewHasHorizontalScroller(WMScrollView * sPtr, Bool flag)
394 if (flag) {
395 if (sPtr->flags.hasHScroller)
396 return;
397 sPtr->flags.hasHScroller = 1;
399 sPtr->hScroller = WMCreateScroller(sPtr);
400 WMSetScrollerAction(sPtr->hScroller, doScrolling, sPtr);
401 /* make it a horiz. scroller */
402 WMResizeWidget(sPtr->hScroller, 2, 1);
404 if (W_VIEW_REALIZED(sPtr->view)) {
405 WMRealizeWidget(sPtr->hScroller);
408 reorganizeInterior(sPtr);
410 WMMapWidget(sPtr->hScroller);
411 } else {
412 if (!sPtr->flags.hasHScroller)
413 return;
415 WMUnmapWidget(sPtr->hScroller);
416 WMDestroyWidget(sPtr->hScroller);
417 sPtr->hScroller = NULL;
418 sPtr->flags.hasHScroller = 0;
420 reorganizeInterior(sPtr);
424 void WMSetScrollViewHasVerticalScroller(WMScrollView * sPtr, Bool flag)
426 if (flag) {
427 if (sPtr->flags.hasVScroller)
428 return;
429 sPtr->flags.hasVScroller = 1;
431 sPtr->vScroller = WMCreateScroller(sPtr);
432 WMSetScrollerAction(sPtr->vScroller, doScrolling, sPtr);
433 WMSetScrollerArrowsPosition(sPtr->vScroller, WSAMaxEnd);
434 /* make it a vert. scroller */
435 WMResizeWidget(sPtr->vScroller, 1, 2);
437 if (W_VIEW_REALIZED(sPtr->view)) {
438 WMRealizeWidget(sPtr->vScroller);
441 reorganizeInterior(sPtr);
443 WMMapWidget(sPtr->vScroller);
444 } else {
445 if (!sPtr->flags.hasVScroller)
446 return;
447 sPtr->flags.hasVScroller = 0;
449 WMUnmapWidget(sPtr->vScroller);
450 WMDestroyWidget(sPtr->vScroller);
451 sPtr->vScroller = NULL;
453 reorganizeInterior(sPtr);
457 void WMSetScrollViewContentView(WMScrollView * sPtr, WMView * view)
459 assert(sPtr->contentView == NULL);
461 sPtr->contentView = view;
463 W_ReparentView(sPtr->contentView, sPtr->viewport, 0, 0);
465 if (sPtr->flags.hasHScroller) {
466 float prop;
468 prop = (float)sPtr->viewport->size.width / sPtr->contentView->size.width;
469 WMSetScrollerParameters(sPtr->hScroller, 0, prop);
471 if (sPtr->flags.hasVScroller) {
472 float prop;
474 prop = (float)sPtr->viewport->size.height / sPtr->contentView->size.height;
476 WMSetScrollerParameters(sPtr->vScroller, 0, prop);
480 void WMSetScrollViewRelief(WMScrollView * sPtr, WMReliefType type)
482 sPtr->flags.relief = type;
484 reorganizeInterior(sPtr);
486 if (sPtr->view->flags.mapped)
487 paintScrollView(sPtr);
491 static void paintScrollView(ScrollView * sPtr)
493 W_DrawRelief(sPtr->view->screen, sPtr->view->window, 0, 0,
494 sPtr->view->size.width, sPtr->view->size.height, sPtr->flags.relief);
497 static void updateScrollerProportion(ScrollView * sPtr)
499 float prop, value;
500 float oldV, oldP;
502 if (sPtr->flags.hasHScroller) {
503 oldV = WMGetScrollerValue(sPtr->hScroller);
504 oldP = WMGetScrollerKnobProportion(sPtr->hScroller);
506 prop = (float)sPtr->viewport->size.width / (float)sPtr->contentView->size.width;
508 if (oldP == 1.0)
509 value = 0;
510 else
511 value = (prop * oldV) / oldP;
512 WMSetScrollerParameters(sPtr->hScroller, value, prop);
514 if (sPtr->flags.hasVScroller) {
515 oldV = WMGetScrollerValue(sPtr->vScroller);
516 oldP = WMGetScrollerKnobProportion(sPtr->vScroller);
518 prop = (float)sPtr->viewport->size.height / (float)sPtr->contentView->size.height;
520 if (oldP == 1.0)
521 value = 0;
522 else
523 value = (prop * oldV) / oldP;
524 WMSetScrollerParameters(sPtr->vScroller, value, prop);
526 applyScrollerValues(sPtr);
529 static void handleViewportEvents(XEvent * event, void *data)
531 ScrollView *sPtr = (ScrollView *) data;
533 if (sPtr->contentView && event->xconfigure.window == sPtr->contentView->window)
534 updateScrollerProportion(sPtr);
537 static void handleEvents(XEvent * event, void *data)
539 ScrollView *sPtr = (ScrollView *) data;
541 CHECK_CLASS(data, WC_ScrollView);
543 switch (event->type) {
544 case Expose:
545 if (event->xexpose.count != 0)
546 break;
547 if (event->xexpose.serial == 0) /* means it's artificial */
548 W_RedisplayView(sPtr->contentView);
549 else
550 paintScrollView(sPtr);
551 break;
553 case DestroyNotify:
554 destroyScrollView(sPtr);
555 break;
560 static void destroyScrollView(ScrollView * sPtr)
562 wfree(sPtr);