Various bug fixes.
[wmaker-crm.git] / WINGs / wscrollview.c
bloba28033b694aefbfe39ffeac783042e8271479e78
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 free(sPtr);
64 return NULL;
66 sPtr->viewport = W_CreateView(sPtr->view);
67 if (!sPtr->view) {
68 W_DestroyView(sPtr->view);
69 free(sPtr);
70 return NULL;
72 sPtr->view->self = sPtr;
74 sPtr->view->delegate = &_ScrollViewViewDelegate;
76 sPtr->viewport->flags.mapWhenRealized = 1;
78 WMCreateEventHandler(sPtr->view, StructureNotifyMask|ExposureMask,
79 handleEvents, sPtr);
80 WMCreateEventHandler(sPtr->viewport, SubstructureNotifyMask,
81 handleViewportEvents, sPtr);
83 sPtr->lineScroll = 4;
85 sPtr->pageScroll = 0;
87 return sPtr;
92 static void
93 reorganizeInterior(WMScrollView *sPtr)
95 int hx, hy, hw;
96 int vx, vy, vh;
97 int cx, cy, cw, ch;
100 cw = hw = sPtr->view->size.width;
101 vh = ch = sPtr->view->size.height;
103 if (sPtr->flags.relief == WRSimple) {
104 cw -= 2;
105 ch -= 2;
106 cx = 1;
107 cy = 1;
108 } else if (sPtr->flags.relief != WRFlat) {
109 cw -= 3;
110 ch -= 3;
111 cx = 2;
112 cy = 2;
113 } else {
114 cx = 0;
115 cy = 0;
118 if (sPtr->flags.hasHScroller) {
119 int h = W_VIEW(sPtr->hScroller)->size.height;
121 ch -= h;
123 if (sPtr->flags.relief == WRSimple) {
124 hx = 0;
125 hy = sPtr->view->size.height - h;
126 } else if (sPtr->flags.relief != WRFlat) {
127 hx = 1;
128 hy = sPtr->view->size.height - h - 1;
129 hw -= 2;
130 } else {
131 hx = 0;
132 hy = sPtr->view->size.height - h;
134 } else {
135 /* make compiler shutup */
136 hx = 0;
137 hy = 0;
140 if (sPtr->flags.hasVScroller) {
141 int w = W_VIEW(sPtr->vScroller)->size.width;
142 cw -= w;
143 cx += w;
144 hx += w - 1;
145 hw -= w - 1;
147 if (sPtr->flags.relief == WRSimple) {
148 vx = 0;
149 vy = 0;
150 } else if (sPtr->flags.relief != WRFlat) {
151 vx = 1;
152 vy = 1;
153 vh -= 2;
154 } else {
155 vx = 0;
156 vy = 0;
158 } else {
159 /* make compiler shutup */
160 vx = 0;
161 vy = 0;
164 W_ResizeView(sPtr->viewport, cw, ch);
165 W_MoveView(sPtr->viewport, cx, cy);
167 if (sPtr->flags.hasHScroller) {
168 WMResizeWidget(sPtr->hScroller, hw, 20);
169 WMMoveWidget(sPtr->hScroller, hx, hy);
171 if (sPtr->flags.hasVScroller) {
172 WMResizeWidget(sPtr->vScroller, 20, vh);
173 WMMoveWidget(sPtr->vScroller, vx, vy);
178 static void
179 resizeScrollView(W_ViewDelegate *self, WMView *view)
181 reorganizeInterior(view->self);
186 void
187 WMResizeScrollViewContent(WMScrollView *sPtr, unsigned int width,
188 unsigned int height)
190 int w, h, x;
192 w = width;
193 h = height;
195 x = 0;
196 if (sPtr->flags.relief == WRSimple) {
197 w += 2;
198 h += 2;
199 } else if (sPtr->flags.relief != WRFlat) {
200 w += 4;
201 h += 4;
202 x = 1;
205 if (sPtr->flags.hasVScroller) {
206 w -= W_VIEW(sPtr->hScroller)->size.width;
207 WMResizeWidget(sPtr->vScroller, 20, h);
209 if (sPtr->flags.hasHScroller) {
210 h -= W_VIEW(sPtr->hScroller)->size.height;
211 WMResizeWidget(sPtr->hScroller, w, 20);
212 WMMoveWidget(sPtr->hScroller, x, h);
215 W_ResizeView(sPtr->view, w, h);
217 W_ResizeView(sPtr->viewport, width, height);
221 void
222 WMSetScrollViewLineScroll(WMScrollView *sPtr, int amount)
224 assert(amount > 0);
226 sPtr->lineScroll = amount;
230 void
231 WMSetScrollViewPageScroll(WMScrollView *sPtr, int amount)
233 assert(amount >= 0);
235 sPtr->pageScroll = amount;
239 static void
240 doScrolling(WMWidget *self, void *data)
242 ScrollView *sPtr = (ScrollView*)data;
243 float value;
244 int pos;
245 int vpsize;
246 float size;
248 if (sPtr->hScroller == (WMScroller *)self) {
249 pos = -sPtr->contentView->pos.x;
250 size = sPtr->contentView->size.width-sPtr->viewport->size.width;
251 vpsize = sPtr->viewport->size.width - sPtr->pageScroll;
252 } else {
253 pos = -sPtr->contentView->pos.y;
254 size = sPtr->contentView->size.height-sPtr->viewport->size.height;
255 vpsize = sPtr->viewport->size.height - sPtr->pageScroll;
257 if (vpsize <= 0)
258 vpsize = 1;
260 switch (WMGetScrollerHitPart(self)) {
261 case WSDecrementLine:
262 if (pos > 0) {
263 pos-=sPtr->lineScroll;
264 if (pos < 0)
265 pos = 0;
266 value = (float)pos / size;
267 WMSetScrollerParameters(self, value,
268 WMGetScrollerKnobProportion(self));
270 break;
271 case WSIncrementLine:
272 if (pos < size) {
273 pos+=sPtr->lineScroll;
274 if (pos > size)
275 pos = size;
276 value = (float)pos / size;
277 WMSetScrollerParameters(self, value,
278 WMGetScrollerKnobProportion(self));
280 break;
281 case WSKnob:
282 value = WMGetScrollerValue(self);
283 pos = value*size;
284 break;
286 case WSDecrementPage:
287 if (pos > 0) {
288 pos -= vpsize;
289 if (pos < 0)
290 pos = 0;
291 value = (float)pos / size;
292 WMSetScrollerParameters(self, value,
293 WMGetScrollerKnobProportion(self));
295 break;
297 case WSIncrementPage:
298 if (pos < size) {
299 pos += vpsize;
300 if (pos > size)
301 pos = size;
302 value = (float)pos / size;
303 WMSetScrollerParameters(self, value,
304 WMGetScrollerKnobProportion(self));
306 break;
308 case WSNoPart:
309 case WSKnobSlot:
310 break;
313 if (sPtr->hScroller == (WMScroller *)self) {
314 W_MoveView(sPtr->contentView, -pos, sPtr->contentView->pos.y);
315 } else {
316 W_MoveView(sPtr->contentView, sPtr->contentView->pos.x, -pos);
321 WMScroller*
322 WMGetScrollViewHorizontalScroller(WMScrollView *sPtr)
324 return sPtr->hScroller;
329 WMScroller*
330 WMGetScrollViewVerticalScroller(WMScrollView *sPtr)
332 return sPtr->vScroller;
336 void
337 WMSetScrollViewHasHorizontalScroller(WMScrollView *sPtr, Bool flag)
339 if (flag) {
340 if (sPtr->flags.hasHScroller)
341 return;
342 sPtr->flags.hasHScroller = 1;
344 sPtr->hScroller = WMCreateScroller(sPtr);
345 WMSetScrollerAction(sPtr->hScroller, doScrolling, sPtr);
346 /* make it a horiz. scroller */
347 WMResizeWidget(sPtr->hScroller, 2, 1);
349 reorganizeInterior(sPtr);
351 WMMapWidget(sPtr->hScroller);
352 } else {
353 if (!sPtr->flags.hasHScroller)
354 return;
356 WMUnmapWidget(sPtr->hScroller);
357 WMDestroyWidget(sPtr->hScroller);
358 sPtr->hScroller = NULL;
359 sPtr->flags.hasHScroller = 0;
361 reorganizeInterior(sPtr);
366 void
367 WMSetScrollViewHasVerticalScroller(WMScrollView *sPtr, Bool flag)
369 if (flag) {
370 if (sPtr->flags.hasVScroller)
371 return;
372 sPtr->flags.hasVScroller = 1;
374 sPtr->vScroller = WMCreateScroller(sPtr);
375 WMSetScrollerAction(sPtr->vScroller, doScrolling, sPtr);
376 WMSetScrollerArrowsPosition(sPtr->vScroller, WSAMaxEnd);
377 /* make it a vert. scroller */
378 WMResizeWidget(sPtr->vScroller, 1, 2);
380 reorganizeInterior(sPtr);
382 WMMapWidget(sPtr->vScroller);
383 } else {
384 if (!sPtr->flags.hasVScroller)
385 return;
386 sPtr->flags.hasVScroller = 0;
388 WMUnmapWidget(sPtr->vScroller);
389 WMDestroyWidget(sPtr->vScroller);
390 sPtr->vScroller = NULL;
392 reorganizeInterior(sPtr);
397 void
398 WMSetScrollViewContentView(WMScrollView *sPtr, WMView *view)
400 assert(sPtr->contentView == NULL);
402 sPtr->contentView = view;
404 W_ReparentView(sPtr->contentView, sPtr->viewport, 0, 0);
406 if (sPtr->flags.hasHScroller) {
407 float prop;
409 prop = (float)sPtr->viewport->size.width/sPtr->contentView->size.width;
410 WMSetScrollerParameters(sPtr->hScroller, 0, prop);
412 if (sPtr->flags.hasVScroller) {
413 float prop;
415 prop = (float)sPtr->viewport->size.height/sPtr->contentView->size.height;
417 WMSetScrollerParameters(sPtr->vScroller, 0, prop);
422 void
423 WMSetScrollViewRelief(WMScrollView *sPtr, WMReliefType type)
425 sPtr->flags.relief = type;
427 if (sPtr->view->flags.mapped)
428 paintScrollView(sPtr);
434 static void
435 paintScrollView(ScrollView *sPtr)
437 W_DrawRelief(sPtr->view->screen, sPtr->view->window, 0, 0,
438 sPtr->view->size.width, sPtr->view->size.height,
439 sPtr->flags.relief);
443 static void
444 updateScrollerProportion(ScrollView *sPtr)
446 float prop, value;
448 if (sPtr->flags.hasHScroller) {
449 prop = (float)sPtr->viewport->size.width/sPtr->contentView->size.width;
450 value = WMGetScrollerValue(sPtr->hScroller);
452 WMSetScrollerParameters(sPtr->hScroller, value, prop);
454 if (sPtr->flags.hasVScroller) {
455 prop = (float)sPtr->viewport->size.height/sPtr->contentView->size.height;
457 value = WMGetScrollerValue(sPtr->vScroller);
459 WMSetScrollerParameters(sPtr->vScroller, value, prop);
464 static void
465 handleViewportEvents(XEvent *event, void *data)
467 ScrollView *sPtr = (ScrollView*)data;
469 if (sPtr->contentView
470 && event->xconfigure.window == sPtr->contentView->window)
471 updateScrollerProportion(sPtr);
475 static void
476 handleEvents(XEvent *event, void *data)
478 ScrollView *sPtr = (ScrollView*)data;
480 CHECK_CLASS(data, WC_ScrollView);
482 switch (event->type) {
483 case Expose:
484 if (event->xexpose.count!=0)
485 break;
486 paintScrollView(sPtr);
487 break;
489 case DestroyNotify:
490 destroyScrollView(sPtr);
491 break;
497 static void
498 destroyScrollView(ScrollView *sPtr)
502 free(sPtr);