- Fixed a flickering problem with the scrollview.
[wmaker-crm.git] / WINGs / wscrollview.c
blobd392eca53ce825fb8b4747568b6ba469b42a60d9
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();
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->view) {
68 W_DestroyView(sPtr->view);
69 wfree(sPtr);
70 return NULL;
72 sPtr->view->self = sPtr;
74 sPtr->view->delegate = &_ScrollViewViewDelegate;
76 /* This has a very bad effect when the scrollview is mapped, making it
77 * flicker with each item added to it. It also seems to draw slower.
78 * Why should it be black anyway? -Dan
80 /*W_SetViewBackgroundColor(sPtr->viewport,
81 WMBlackColor(WMWidgetScreen(parent)));*/
82 sPtr->viewport->flags.mapWhenRealized = 1;
84 WMCreateEventHandler(sPtr->view, StructureNotifyMask|ExposureMask,
85 handleEvents, sPtr);
86 WMCreateEventHandler(sPtr->viewport, SubstructureNotifyMask,
87 handleViewportEvents, sPtr);
89 sPtr->lineScroll = 4;
91 sPtr->pageScroll = 0;
93 return sPtr;
98 static void
99 reorganizeInterior(WMScrollView *sPtr)
101 int hx, hy, hw;
102 int vx, vy, vh;
103 int cx, cy, cw, ch;
106 cw = hw = sPtr->view->size.width;
107 vh = ch = sPtr->view->size.height;
109 if (sPtr->flags.relief == WRSimple) {
110 cw -= 2;
111 ch -= 2;
112 cx = 1;
113 cy = 1;
114 } else if (sPtr->flags.relief != WRFlat) {
115 cw -= 3;
116 ch -= 3;
117 cx = 2;
118 cy = 2;
119 } else {
120 cx = 0;
121 cy = 0;
124 if (sPtr->flags.hasHScroller) {
125 int h = W_VIEW(sPtr->hScroller)->size.height;
127 ch -= h;
129 if (sPtr->flags.relief == WRSimple) {
130 hx = 0;
131 hy = sPtr->view->size.height - h;
132 } else if (sPtr->flags.relief != WRFlat) {
133 hx = 1;
134 hy = sPtr->view->size.height - h - 1;
135 hw -= 2;
136 } else {
137 hx = 0;
138 hy = sPtr->view->size.height - h;
140 } else {
141 /* make compiler shutup */
142 hx = 0;
143 hy = 0;
146 if (sPtr->flags.hasVScroller) {
147 int w = W_VIEW(sPtr->vScroller)->size.width;
148 cw -= w;
149 cx += w;
150 hx += w - 1;
151 hw -= w - 1;
153 if (sPtr->flags.relief == WRSimple) {
154 vx = 0;
155 vy = 0;
156 } else if (sPtr->flags.relief != WRFlat) {
157 vx = 1;
158 vy = 1;
159 vh -= 2;
160 } else {
161 vx = 0;
162 vy = 0;
164 } else {
165 /* make compiler shutup */
166 vx = 0;
167 vy = 0;
170 W_ResizeView(sPtr->viewport, cw, ch);
171 W_MoveView(sPtr->viewport, cx, cy);
173 if (sPtr->flags.hasHScroller) {
174 WMResizeWidget(sPtr->hScroller, hw, 20);
175 WMMoveWidget(sPtr->hScroller, hx, hy);
177 if (sPtr->flags.hasVScroller) {
178 WMResizeWidget(sPtr->vScroller, 20, vh);
179 WMMoveWidget(sPtr->vScroller, vx, vy);
184 static void
185 resizeScrollView(W_ViewDelegate *self, WMView *view)
187 reorganizeInterior(view->self);
192 void
193 WMResizeScrollViewContent(WMScrollView *sPtr, unsigned int width,
194 unsigned int height)
196 int w, h, x;
198 w = width;
199 h = height;
201 x = 0;
202 if (sPtr->flags.relief == WRSimple) {
203 w += 2;
204 h += 2;
205 } else if (sPtr->flags.relief != WRFlat) {
206 w += 4;
207 h += 4;
208 x = 1;
211 if (sPtr->flags.hasVScroller) {
212 w -= W_VIEW(sPtr->hScroller)->size.width;
213 WMResizeWidget(sPtr->vScroller, 20, h);
215 if (sPtr->flags.hasHScroller) {
216 h -= W_VIEW(sPtr->hScroller)->size.height;
217 WMResizeWidget(sPtr->hScroller, w, 20);
218 WMMoveWidget(sPtr->hScroller, x, h);
221 W_ResizeView(sPtr->view, w, h);
223 W_ResizeView(sPtr->viewport, width, height);
227 void
228 WMSetScrollViewLineScroll(WMScrollView *sPtr, int amount)
230 assert(amount > 0);
232 sPtr->lineScroll = amount;
236 void
237 WMSetScrollViewPageScroll(WMScrollView *sPtr, int amount)
239 assert(amount >= 0);
241 sPtr->pageScroll = amount;
245 WMRect
246 WMGetScrollViewVisibleRect(WMScrollView *sPtr)
248 WMRect rect;
250 rect.pos = sPtr->contentView->pos;
251 rect.size = sPtr->viewport->size;
253 return rect;
256 static void
257 doScrolling(WMWidget *self, void *data)
259 ScrollView *sPtr = (ScrollView*)data;
260 float value;
261 int pos;
262 int vpsize;
263 float size;
265 if (sPtr->hScroller == (WMScroller *)self) {
266 pos = -sPtr->contentView->pos.x;
267 size = sPtr->contentView->size.width-sPtr->viewport->size.width;
268 vpsize = sPtr->viewport->size.width - sPtr->pageScroll;
269 } else {
270 pos = -sPtr->contentView->pos.y;
271 size = sPtr->contentView->size.height-sPtr->viewport->size.height;
272 vpsize = sPtr->viewport->size.height - sPtr->pageScroll;
274 if (vpsize <= 0)
275 vpsize = 1;
277 switch (WMGetScrollerHitPart(self)) {
278 case WSDecrementLine:
279 if (pos > 0) {
280 pos-=sPtr->lineScroll;
281 if (pos < 0)
282 pos = 0;
283 value = (float)pos / size;
284 WMSetScrollerParameters(self, value,
285 WMGetScrollerKnobProportion(self));
287 break;
288 case WSIncrementLine:
289 if (pos < size) {
290 pos+=sPtr->lineScroll;
291 if (pos > size)
292 pos = size;
293 value = (float)pos / size;
294 WMSetScrollerParameters(self, value,
295 WMGetScrollerKnobProportion(self));
297 break;
299 case WSKnob:
300 value = WMGetScrollerValue(self);
301 pos = value*size;
302 break;
304 case WSDecrementPage:
305 if (pos > 0) {
306 pos -= vpsize;
307 if (pos < 0)
308 pos = 0;
309 value = (float)pos / size;
310 WMSetScrollerParameters(self, value,
311 WMGetScrollerKnobProportion(self));
313 break;
315 case WSDecrementWheel:
316 if (pos > 0) {
317 pos -= vpsize/3;
318 if (pos < 0)
319 pos = 0;
320 value = (float)pos / size;
321 WMSetScrollerParameters(self, value,
322 WMGetScrollerKnobProportion(self));
324 break;
326 case WSIncrementPage:
327 if (pos < size) {
328 pos += vpsize;
329 if (pos > size)
330 pos = size;
331 value = (float)pos / size;
332 WMSetScrollerParameters(self, value,
333 WMGetScrollerKnobProportion(self));
335 break;
337 case WSIncrementWheel:
338 if (pos < size) {
339 pos += vpsize/3;
340 if (pos > size)
341 pos = size;
342 value = (float)pos / size;
343 WMSetScrollerParameters(self, value,
344 WMGetScrollerKnobProportion(self));
346 break;
348 case WSNoPart:
349 case WSKnobSlot:
350 break;
353 if (sPtr->hScroller == (WMScroller *)self) {
354 W_MoveView(sPtr->contentView, -pos, sPtr->contentView->pos.y);
355 } else {
356 W_MoveView(sPtr->contentView, sPtr->contentView->pos.x, -pos);
361 WMScroller*
362 WMGetScrollViewHorizontalScroller(WMScrollView *sPtr)
364 return sPtr->hScroller;
369 WMScroller*
370 WMGetScrollViewVerticalScroller(WMScrollView *sPtr)
372 return sPtr->vScroller;
376 void
377 WMSetScrollViewHasHorizontalScroller(WMScrollView *sPtr, Bool flag)
379 if (flag) {
380 if (sPtr->flags.hasHScroller)
381 return;
382 sPtr->flags.hasHScroller = 1;
384 sPtr->hScroller = WMCreateScroller(sPtr);
385 WMSetScrollerAction(sPtr->hScroller, doScrolling, sPtr);
386 /* make it a horiz. scroller */
387 WMResizeWidget(sPtr->hScroller, 2, 1);
389 reorganizeInterior(sPtr);
391 WMMapWidget(sPtr->hScroller);
392 } else {
393 if (!sPtr->flags.hasHScroller)
394 return;
396 WMUnmapWidget(sPtr->hScroller);
397 WMDestroyWidget(sPtr->hScroller);
398 sPtr->hScroller = NULL;
399 sPtr->flags.hasHScroller = 0;
401 reorganizeInterior(sPtr);
406 void
407 WMSetScrollViewHasVerticalScroller(WMScrollView *sPtr, Bool flag)
409 if (flag) {
410 if (sPtr->flags.hasVScroller)
411 return;
412 sPtr->flags.hasVScroller = 1;
414 sPtr->vScroller = WMCreateScroller(sPtr);
415 WMSetScrollerAction(sPtr->vScroller, doScrolling, sPtr);
416 WMSetScrollerArrowsPosition(sPtr->vScroller, WSAMaxEnd);
417 /* make it a vert. scroller */
418 WMResizeWidget(sPtr->vScroller, 1, 2);
420 reorganizeInterior(sPtr);
422 WMMapWidget(sPtr->vScroller);
423 } else {
424 if (!sPtr->flags.hasVScroller)
425 return;
426 sPtr->flags.hasVScroller = 0;
428 WMUnmapWidget(sPtr->vScroller);
429 WMDestroyWidget(sPtr->vScroller);
430 sPtr->vScroller = NULL;
432 reorganizeInterior(sPtr);
437 void
438 WMSetScrollViewContentView(WMScrollView *sPtr, WMView *view)
440 assert(sPtr->contentView == NULL);
442 sPtr->contentView = view;
444 W_ReparentView(sPtr->contentView, sPtr->viewport, 0, 0);
446 if (sPtr->flags.hasHScroller) {
447 float prop;
449 prop = (float)sPtr->viewport->size.width/sPtr->contentView->size.width;
450 WMSetScrollerParameters(sPtr->hScroller, 0, prop);
452 if (sPtr->flags.hasVScroller) {
453 float prop;
455 prop = (float)sPtr->viewport->size.height/sPtr->contentView->size.height;
457 WMSetScrollerParameters(sPtr->vScroller, 0, prop);
462 void
463 WMSetScrollViewRelief(WMScrollView *sPtr, WMReliefType type)
465 sPtr->flags.relief = type;
467 reorganizeInterior(sPtr);
469 if (sPtr->view->flags.mapped)
470 paintScrollView(sPtr);
476 static void
477 paintScrollView(ScrollView *sPtr)
479 W_DrawRelief(sPtr->view->screen, sPtr->view->window, 0, 0,
480 sPtr->view->size.width, sPtr->view->size.height,
481 sPtr->flags.relief);
485 static void
486 updateScrollerProportion(ScrollView *sPtr)
488 float prop, value;
490 if (sPtr->flags.hasHScroller) {
491 prop = (float)sPtr->viewport->size.width/sPtr->contentView->size.width;
492 value = WMGetScrollerValue(sPtr->hScroller);
494 WMSetScrollerParameters(sPtr->hScroller, value, prop);
496 if (sPtr->flags.hasVScroller) {
497 prop = (float)sPtr->viewport->size.height/sPtr->contentView->size.height;
499 value = WMGetScrollerValue(sPtr->vScroller);
501 WMSetScrollerParameters(sPtr->vScroller, value, prop);
506 static void
507 handleViewportEvents(XEvent *event, void *data)
509 ScrollView *sPtr = (ScrollView*)data;
511 if (sPtr->contentView
512 && event->xconfigure.window == sPtr->contentView->window)
513 updateScrollerProportion(sPtr);
517 static void
518 handleEvents(XEvent *event, void *data)
520 ScrollView *sPtr = (ScrollView*)data;
522 CHECK_CLASS(data, WC_ScrollView);
524 switch (event->type) {
525 case Expose:
526 if (event->xexpose.count!=0)
527 break;
528 paintScrollView(sPtr);
529 break;
531 case DestroyNotify:
532 destroyScrollView(sPtr);
533 break;
539 static void
540 destroyScrollView(ScrollView *sPtr)
542 puts("destroyScrollView not implemented");
544 wfree(sPtr);