Initial revision
[wmaker-crm.git] / WINGs / wscrollview.c
blobcbbcb4c8b8a558f05825ec3080a631b9450d15b1
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_ViewProcedureTable _ScrollViewViewProcedures = {
42 NULL,
43 resizeScrollView,
44 NULL
49 WMScrollView*
50 WMCreateScrollView(WMWidget *parent)
52 ScrollView *sPtr;
54 sPtr = wmalloc(sizeof(ScrollView));
55 memset(sPtr, 0, sizeof(ScrollView));
57 sPtr->widgetClass = WC_ScrollView;
59 sPtr->view = W_CreateView(W_VIEW(parent));
60 if (!sPtr->view) {
61 free(sPtr);
62 return NULL;
64 sPtr->viewport = W_CreateView(sPtr->view);
65 if (!sPtr->view) {
66 W_DestroyView(sPtr->view);
67 free(sPtr);
68 return NULL;
71 sPtr->viewport->flags.mapWhenRealized = 1;
73 WMCreateEventHandler(sPtr->view, StructureNotifyMask|ExposureMask,
74 handleEvents, sPtr);
75 WMCreateEventHandler(sPtr->viewport, SubstructureNotifyMask,
76 handleViewportEvents, sPtr);
78 sPtr->lineScroll = 4;
80 sPtr->pageScroll = 0;
82 return sPtr;
87 static void
88 reorganizeInterior(WMScrollView *sPtr)
90 int hx, hy, hw;
91 int vx, vy, vh;
92 int cx, cy, cw, ch;
95 cw = hw = sPtr->view->size.width;
96 vh = ch = sPtr->view->size.height;
98 if (sPtr->flags.relief == WRSimple) {
99 cw -= 2;
100 ch -= 2;
101 cx = 1;
102 cy = 1;
103 } else if (sPtr->flags.relief != WRFlat) {
104 cw -= 3;
105 ch -= 3;
106 cx = 2;
107 cy = 2;
108 } else {
109 cx = 0;
110 cy = 0;
113 if (sPtr->flags.hasHScroller) {
114 int h = W_VIEW(sPtr->hScroller)->size.height;
116 ch -= h;
118 if (sPtr->flags.relief == WRSimple) {
119 hx = 0;
120 hy = sPtr->view->size.height - h;
121 } else if (sPtr->flags.relief != WRFlat) {
122 hx = 1;
123 hy = sPtr->view->size.height - h - 1;
124 hw -= 2;
125 } else {
126 hx = 0;
127 hy = sPtr->view->size.height - h;
129 } else {
130 /* make compiler shutup */
131 hx = 0;
132 hy = 0;
135 if (sPtr->flags.hasVScroller) {
136 int w = W_VIEW(sPtr->vScroller)->size.width;
137 cw -= w;
138 cx += w;
139 hx += w - 1;
140 hw -= w - 1;
142 if (sPtr->flags.relief == WRSimple) {
143 vx = 0;
144 vy = 0;
145 } else if (sPtr->flags.relief != WRFlat) {
146 vx = 1;
147 vy = 1;
148 vh -= 2;
149 } else {
150 vx = 0;
151 vy = 0;
153 } else {
154 /* make compiler shutup */
155 vx = 0;
156 vy = 0;
159 W_ResizeView(sPtr->viewport, cw, ch);
160 W_MoveView(sPtr->viewport, cx, cy);
162 if (sPtr->flags.hasHScroller) {
163 WMResizeWidget(sPtr->hScroller, hw, 20);
164 WMMoveWidget(sPtr->hScroller, hx, hy);
166 if (sPtr->flags.hasVScroller) {
167 WMResizeWidget(sPtr->vScroller, 20, vh);
168 WMMoveWidget(sPtr->vScroller, vx, vy);
173 static void
174 resizeScrollView(WMScrollView *sPtr, unsigned int width, unsigned int height)
176 W_ResizeView(sPtr->view, width, height);
178 reorganizeInterior(sPtr);
183 void
184 WMResizeScrollViewContent(WMScrollView *sPtr, unsigned int width,
185 unsigned int height)
187 int w, h, x;
189 w = width;
190 h = height;
192 x = 0;
193 if (sPtr->flags.relief == WRSimple) {
194 w += 2;
195 h += 2;
196 } else if (sPtr->flags.relief != WRFlat) {
197 w += 4;
198 h += 4;
199 x = 1;
202 if (sPtr->flags.hasVScroller) {
203 w -= W_VIEW(sPtr->hScroller)->size.width;
204 WMResizeWidget(sPtr->vScroller, 20, h);
206 if (sPtr->flags.hasHScroller) {
207 h -= W_VIEW(sPtr->hScroller)->size.height;
208 WMResizeWidget(sPtr->hScroller, w, 20);
209 WMMoveWidget(sPtr->hScroller, x, h);
212 W_ResizeView(sPtr->view, w, h);
214 W_ResizeView(sPtr->viewport, width, height);
218 void
219 WMSetScrollViewLineScroll(WMScrollView *sPtr, int amount)
221 assert(amount > 0);
223 sPtr->lineScroll = amount;
227 void
228 WMSetScrollViewPageScroll(WMScrollView *sPtr, int amount)
230 assert(amount >= 0);
232 sPtr->pageScroll = amount;
236 static void
237 doScrolling(WMWidget *self, void *data)
239 ScrollView *sPtr = (ScrollView*)data;
240 float value;
241 int pos;
242 int vpsize;
243 float size;
245 if (sPtr->hScroller == self) {
246 pos = -sPtr->contentView->pos.x;
247 size = sPtr->contentView->size.width-sPtr->viewport->size.width;
248 vpsize = sPtr->viewport->size.width - sPtr->pageScroll;
249 } else {
250 pos = -sPtr->contentView->pos.y;
251 size = sPtr->contentView->size.height-sPtr->viewport->size.height;
252 vpsize = sPtr->viewport->size.height - sPtr->pageScroll;
254 if (vpsize <= 0)
255 vpsize = 1;
257 switch (WMGetScrollerHitPart(self)) {
258 case WSDecrementLine:
259 if (pos > 0) {
260 pos-=sPtr->lineScroll;
261 if (pos < 0)
262 pos = 0;
263 value = (float)pos / size;
264 WMSetScrollerParameters(self, value,
265 WMGetScrollerKnobProportion(self));
267 break;
268 case WSIncrementLine:
269 if (pos < size) {
270 pos+=sPtr->lineScroll;
271 if (pos > size)
272 pos = size;
273 value = (float)pos / size;
274 WMSetScrollerParameters(self, value,
275 WMGetScrollerKnobProportion(self));
277 break;
278 case WSKnob:
279 value = WMGetScrollerValue(self);
280 pos = value*size;
281 break;
283 case WSDecrementPage:
284 if (pos > 0) {
285 pos -= vpsize;
286 if (pos < 0)
287 pos = 0;
288 value = (float)pos / size;
289 WMSetScrollerParameters(self, value,
290 WMGetScrollerKnobProportion(self));
292 break;
294 case WSIncrementPage:
295 if (pos < size) {
296 pos += vpsize;
297 if (pos > size)
298 pos = size;
299 value = (float)pos / size;
300 WMSetScrollerParameters(self, value,
301 WMGetScrollerKnobProportion(self));
303 break;
305 case WSNoPart:
306 case WSKnobSlot:
307 break;
310 if (sPtr->hScroller == self) {
311 W_MoveView(sPtr->contentView, -pos, sPtr->contentView->pos.y);
312 } else {
313 W_MoveView(sPtr->contentView, sPtr->contentView->pos.x, -pos);
318 WMScroller*
319 WMGetScrollViewHorizontalScroller(WMScrollView *sPtr)
321 return sPtr->hScroller;
326 WMScroller*
327 WMGetScrollViewVerticalScroller(WMScrollView *sPtr)
329 return sPtr->vScroller;
333 void
334 WMSetScrollViewHasHorizontalScroller(WMScrollView *sPtr, Bool flag)
336 if (flag) {
337 if (sPtr->flags.hasHScroller)
338 return;
339 sPtr->flags.hasHScroller = 1;
341 sPtr->hScroller = WMCreateScroller(sPtr);
342 WMSetScrollerAction(sPtr->hScroller, doScrolling, sPtr);
343 /* make it a horiz. scroller */
344 WMResizeWidget(sPtr->hScroller, 2, 1);
346 reorganizeInterior(sPtr);
348 WMMapWidget(sPtr->hScroller);
349 } else {
350 if (!sPtr->flags.hasHScroller)
351 return;
353 WMUnmapWidget(sPtr->hScroller);
354 WMDestroyWidget(sPtr->hScroller);
355 sPtr->hScroller = NULL;
356 sPtr->flags.hasHScroller = 0;
358 reorganizeInterior(sPtr);
363 void
364 WMSetScrollViewHasVerticalScroller(WMScrollView *sPtr, Bool flag)
366 if (flag) {
367 if (sPtr->flags.hasVScroller)
368 return;
369 sPtr->flags.hasVScroller = 1;
371 sPtr->vScroller = WMCreateScroller(sPtr);
372 WMSetScrollerAction(sPtr->vScroller, doScrolling, sPtr);
373 WMSetScrollerArrowsPosition(sPtr->vScroller, WSAMaxEnd);
374 /* make it a vert. scroller */
375 WMResizeWidget(sPtr->vScroller, 1, 2);
377 reorganizeInterior(sPtr);
379 WMMapWidget(sPtr->vScroller);
380 } else {
381 if (!sPtr->flags.hasVScroller)
382 return;
383 sPtr->flags.hasVScroller = 0;
385 WMUnmapWidget(sPtr->vScroller);
386 WMDestroyWidget(sPtr->vScroller);
387 sPtr->vScroller = NULL;
389 reorganizeInterior(sPtr);
394 void
395 WMSetScrollViewContentView(WMScrollView *sPtr, WMView *view)
397 assert(sPtr->contentView == NULL);
399 sPtr->contentView = view;
401 W_ReparentView(sPtr->contentView, sPtr->viewport);
403 if (sPtr->flags.hasHScroller) {
404 float prop;
406 prop = (float)sPtr->viewport->size.width/sPtr->contentView->size.width;
407 WMSetScrollerParameters(sPtr->hScroller, 0, prop);
409 if (sPtr->flags.hasVScroller) {
410 float prop;
412 prop = (float)sPtr->viewport->size.height/sPtr->contentView->size.height;
414 WMSetScrollerParameters(sPtr->vScroller, 0, prop);
419 void
420 WMSetScrollViewRelief(WMScrollView *sPtr, WMReliefType type)
422 sPtr->flags.relief = type;
424 if (sPtr->view->flags.mapped)
425 paintScrollView(sPtr);
431 static void
432 paintScrollView(ScrollView *sPtr)
434 W_DrawRelief(sPtr->view->screen, sPtr->view->window, 0, 0,
435 sPtr->view->size.width, sPtr->view->size.height,
436 sPtr->flags.relief);
440 static void
441 updateScrollerProportion(ScrollView *sPtr)
443 float prop, value;
445 if (sPtr->flags.hasHScroller) {
446 prop = (float)sPtr->viewport->size.width/sPtr->contentView->size.width;
447 value = WMGetScrollerValue(sPtr->hScroller);
449 WMSetScrollerParameters(sPtr->hScroller, value, prop);
451 if (sPtr->flags.hasVScroller) {
452 prop = (float)sPtr->viewport->size.height/sPtr->contentView->size.height;
454 value = WMGetScrollerValue(sPtr->vScroller);
456 WMSetScrollerParameters(sPtr->vScroller, value, prop);
461 static void
462 handleViewportEvents(XEvent *event, void *data)
464 ScrollView *sPtr = (ScrollView*)data;
466 if (sPtr->contentView
467 && event->xconfigure.window == sPtr->contentView->window)
468 updateScrollerProportion(sPtr);
472 static void
473 handleEvents(XEvent *event, void *data)
475 ScrollView *sPtr = (ScrollView*)data;
477 CHECK_CLASS(data, WC_ScrollView);
479 switch (event->type) {
480 case Expose:
481 if (event->xexpose.count!=0)
482 break;
483 paintScrollView(sPtr);
484 break;
486 case DestroyNotify:
487 destroyScrollView(sPtr);
488 break;
494 static void
495 destroyScrollView(ScrollView *sPtr)
499 free(sPtr);