Fixed icon loading during Attribute Inspector startup
[wmaker-crm.git] / WINGs / wscrollview.c
bloba1b030eb0a935c028e83cf24fc6c70256d846df2
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(W_ViewDelegate *self, WMView *view);
32 static void updateScrollerProportion(ScrollView *sPtr);
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 sPtr->widgetClass = WC_ScrollView;
49 sPtr->view = W_CreateView(W_VIEW(parent));
50 if (!sPtr->view) {
51 wfree(sPtr);
52 return NULL;
54 sPtr->viewport = W_CreateView(sPtr->view);
55 if (!sPtr->viewport) {
56 W_DestroyView(sPtr->view);
57 wfree(sPtr);
58 return NULL;
60 sPtr->view->self = sPtr;
61 sPtr->viewport->self = sPtr;
63 sPtr->view->delegate = &_ScrollViewViewDelegate;
65 sPtr->viewport->flags.mapWhenRealized = 1;
67 WMCreateEventHandler(sPtr->view, StructureNotifyMask | ExposureMask, handleEvents, sPtr);
68 WMCreateEventHandler(sPtr->viewport, SubstructureNotifyMask, handleViewportEvents, sPtr);
70 sPtr->lineScroll = 4;
72 sPtr->pageScroll = 0;
74 return sPtr;
77 static void applyScrollerValues(WMScrollView * sPtr)
79 int x, y;
81 if (sPtr->contentView == NULL)
82 return;
84 if (sPtr->flags.hasHScroller) {
85 float v = WMGetScrollerValue(sPtr->hScroller);
86 int size;
88 size = sPtr->contentView->size.width - sPtr->viewport->size.width;
90 x = v * size;
91 } else {
92 x = 0;
95 if (sPtr->flags.hasVScroller) {
96 float v = WMGetScrollerValue(sPtr->vScroller);
98 int size;
100 size = sPtr->contentView->size.height - sPtr->viewport->size.height;
102 y = v * size;
103 } else {
104 y = 0;
107 x = WMAX(0, x);
108 y = WMAX(0, y);
110 W_MoveView(sPtr->contentView, -x, -y);
112 W_RaiseView(sPtr->viewport);
115 static void reorganizeInterior(WMScrollView * sPtr)
117 int hx, hy, hw;
118 int vx, vy, vh;
119 int cx, cy, cw, ch;
121 cw = hw = sPtr->view->size.width;
122 vh = ch = sPtr->view->size.height;
124 if (sPtr->flags.relief == WRSimple) {
125 cw -= 2;
126 ch -= 2;
127 cx = 1;
128 cy = 1;
129 } else if (sPtr->flags.relief != WRFlat) {
130 cw -= 3;
131 ch -= 3;
132 cx = 2;
133 cy = 2;
134 } else {
135 cx = 0;
136 cy = 0;
139 if (sPtr->flags.hasHScroller) {
140 int h = 20;
142 ch -= h;
144 if (sPtr->flags.relief == WRSimple) {
145 hx = 0;
146 hy = sPtr->view->size.height - h;
147 } else if (sPtr->flags.relief != WRFlat) {
148 hx = 1;
149 hy = sPtr->view->size.height - h - 1;
150 hw -= 2;
151 } else {
152 hx = 0;
153 hy = sPtr->view->size.height - h;
155 } else {
156 /* make compiler shutup */
157 hx = 0;
158 hy = 0;
161 if (sPtr->flags.hasVScroller) {
162 int w = 20;
163 cw -= w;
164 cx += w;
165 hx += w - 1;
166 hw -= w - 1;
168 if (sPtr->flags.relief == WRSimple) {
169 vx = 0;
170 vy = 0;
171 } else if (sPtr->flags.relief != WRFlat) {
172 vx = 1;
173 vy = 1;
174 vh -= 2;
175 } else {
176 vx = 0;
177 vy = 0;
179 } else {
180 /* make compiler shutup */
181 vx = 0;
182 vy = 0;
185 W_ResizeView(sPtr->viewport, cw, ch);
186 W_MoveView(sPtr->viewport, cx, cy);
188 if (sPtr->flags.hasHScroller) {
189 WMResizeWidget(sPtr->hScroller, hw, 20);
190 WMMoveWidget(sPtr->hScroller, hx, hy);
192 if (sPtr->flags.hasVScroller) {
193 WMResizeWidget(sPtr->vScroller, 20, vh);
194 WMMoveWidget(sPtr->vScroller, vx, vy);
197 applyScrollerValues(sPtr);
200 static void resizeScrollView(W_ViewDelegate * self, WMView * view)
202 /* Parameter not used, but tell the compiler that it is ok */
203 (void) self;
205 reorganizeInterior(view->self);
206 updateScrollerProportion(view->self);
209 void WMResizeScrollViewContent(WMScrollView * sPtr, unsigned int width, unsigned int height)
211 int w, h, x;
213 w = width;
214 h = height;
216 x = 0;
217 if (sPtr->flags.relief == WRSimple) {
218 w += 2;
219 h += 2;
220 } else if (sPtr->flags.relief != WRFlat) {
221 w += 4;
222 h += 4;
223 x = 1;
226 if (sPtr->flags.hasVScroller) {
227 WMResizeWidget(sPtr->vScroller, 20, h);
228 width -= W_VIEW(sPtr->vScroller)->size.width;
231 if (sPtr->flags.hasHScroller) {
232 WMResizeWidget(sPtr->hScroller, w, 20);
233 WMMoveWidget(sPtr->hScroller, x, h);
234 height -= W_VIEW(sPtr->hScroller)->size.height;
237 W_ResizeView(sPtr->view, w, h);
239 W_ResizeView(sPtr->viewport, width, height);
242 void WMSetScrollViewLineScroll(WMScrollView * sPtr, int amount)
244 assert(amount > 0);
246 sPtr->lineScroll = amount;
249 void WMSetScrollViewPageScroll(WMScrollView * sPtr, int amount)
251 assert(amount >= 0);
253 sPtr->pageScroll = amount;
256 WMRect WMGetScrollViewVisibleRect(WMScrollView * sPtr)
258 WMRect rect;
260 rect.pos.x = -sPtr->contentView->pos.x;
261 rect.pos.y = -sPtr->contentView->pos.y;
262 rect.size = sPtr->viewport->size;
264 return rect;
267 void WMScrollViewScrollPoint(WMScrollView * sPtr, WMPoint point)
269 float xsize, ysize;
270 float xpos, ypos;
272 xsize = sPtr->contentView->size.width - sPtr->viewport->size.width;
273 ysize = sPtr->contentView->size.height - sPtr->viewport->size.height;
275 xpos = point.x / xsize;
276 ypos = point.y / ysize;
278 if (sPtr->hScroller)
279 WMSetScrollerParameters(sPtr->hScroller, xpos, WMGetScrollerKnobProportion(sPtr->hScroller));
280 if (sPtr->vScroller)
281 WMSetScrollerParameters(sPtr->vScroller, ypos, WMGetScrollerKnobProportion(sPtr->vScroller));
283 W_MoveView(sPtr->contentView, -point.x, -point.y);
286 static void doScrolling(WMWidget * self, void *data)
288 ScrollView *sPtr = (ScrollView *) data;
289 float value;
290 int pos;
291 int vpsize;
292 float size;
294 if (sPtr->hScroller == (WMScroller *) self) {
295 pos = -sPtr->contentView->pos.x;
296 size = sPtr->contentView->size.width - sPtr->viewport->size.width;
297 vpsize = sPtr->viewport->size.width - sPtr->pageScroll;
298 } else {
299 pos = -sPtr->contentView->pos.y;
300 size = sPtr->contentView->size.height - sPtr->viewport->size.height;
301 vpsize = sPtr->viewport->size.height - sPtr->pageScroll;
303 if (vpsize <= 0)
304 vpsize = 1;
306 switch (WMGetScrollerHitPart(self)) {
307 case WSDecrementLine:
308 if (pos > 0) {
309 pos -= sPtr->lineScroll;
310 if (pos < 0)
311 pos = 0;
312 value = (float)pos / size;
313 WMSetScrollerParameters(self, value, WMGetScrollerKnobProportion(self));
315 break;
316 case WSIncrementLine:
317 if (pos < size) {
318 pos += sPtr->lineScroll;
319 if (pos > size)
320 pos = size;
321 value = (float)pos / size;
322 WMSetScrollerParameters(self, value, WMGetScrollerKnobProportion(self));
324 break;
326 case WSKnob:
327 value = WMGetScrollerValue(self);
328 pos = value * size;
329 break;
331 case WSDecrementPage:
332 if (pos > 0) {
333 pos -= vpsize;
334 if (pos < 0)
335 pos = 0;
336 value = (float)pos / size;
337 WMSetScrollerParameters(self, value, WMGetScrollerKnobProportion(self));
339 break;
341 case WSDecrementWheel:
342 if (pos > 0) {
343 pos -= vpsize / 3;
344 if (pos < 0)
345 pos = 0;
346 value = (float)pos / size;
347 WMSetScrollerParameters(self, value, WMGetScrollerKnobProportion(self));
349 break;
351 case WSIncrementPage:
352 if (pos < size) {
353 pos += vpsize;
354 if (pos > size)
355 pos = size;
356 value = (float)pos / size;
357 WMSetScrollerParameters(self, value, WMGetScrollerKnobProportion(self));
359 break;
361 case WSIncrementWheel:
362 if (pos < size) {
363 pos += vpsize / 3;
364 if (pos > size)
365 pos = size;
366 value = (float)pos / size;
367 WMSetScrollerParameters(self, value, WMGetScrollerKnobProportion(self));
369 break;
371 case WSNoPart:
372 case WSKnobSlot:
373 break;
376 if (sPtr->hScroller == (WMScroller *) self) {
377 W_MoveView(sPtr->contentView, -pos, sPtr->contentView->pos.y);
378 } else {
379 W_MoveView(sPtr->contentView, sPtr->contentView->pos.x, -pos);
383 WMScroller *WMGetScrollViewHorizontalScroller(WMScrollView * sPtr)
385 return sPtr->hScroller;
388 WMScroller *WMGetScrollViewVerticalScroller(WMScrollView * sPtr)
390 return sPtr->vScroller;
393 void WMSetScrollViewHasHorizontalScroller(WMScrollView * sPtr, Bool flag)
395 if (flag) {
396 if (sPtr->flags.hasHScroller)
397 return;
398 sPtr->flags.hasHScroller = 1;
400 sPtr->hScroller = WMCreateScroller(sPtr);
401 WMSetScrollerAction(sPtr->hScroller, doScrolling, sPtr);
402 /* make it a horiz. scroller */
403 WMResizeWidget(sPtr->hScroller, 2, 1);
405 if (W_VIEW_REALIZED(sPtr->view)) {
406 WMRealizeWidget(sPtr->hScroller);
409 reorganizeInterior(sPtr);
411 WMMapWidget(sPtr->hScroller);
412 } else {
413 if (!sPtr->flags.hasHScroller)
414 return;
416 WMUnmapWidget(sPtr->hScroller);
417 WMDestroyWidget(sPtr->hScroller);
418 sPtr->hScroller = NULL;
419 sPtr->flags.hasHScroller = 0;
421 reorganizeInterior(sPtr);
425 void WMSetScrollViewHasVerticalScroller(WMScrollView * sPtr, Bool flag)
427 if (flag) {
428 if (sPtr->flags.hasVScroller)
429 return;
430 sPtr->flags.hasVScroller = 1;
432 sPtr->vScroller = WMCreateScroller(sPtr);
433 WMSetScrollerAction(sPtr->vScroller, doScrolling, sPtr);
434 WMSetScrollerArrowsPosition(sPtr->vScroller, WSAMaxEnd);
435 /* make it a vert. scroller */
436 WMResizeWidget(sPtr->vScroller, 1, 2);
438 if (W_VIEW_REALIZED(sPtr->view)) {
439 WMRealizeWidget(sPtr->vScroller);
442 reorganizeInterior(sPtr);
444 WMMapWidget(sPtr->vScroller);
445 } else {
446 if (!sPtr->flags.hasVScroller)
447 return;
448 sPtr->flags.hasVScroller = 0;
450 WMUnmapWidget(sPtr->vScroller);
451 WMDestroyWidget(sPtr->vScroller);
452 sPtr->vScroller = NULL;
454 reorganizeInterior(sPtr);
458 void WMSetScrollViewContentView(WMScrollView * sPtr, WMView * view)
460 assert(sPtr->contentView == NULL);
462 sPtr->contentView = view;
464 W_ReparentView(sPtr->contentView, sPtr->viewport, 0, 0);
466 if (sPtr->flags.hasHScroller) {
467 float prop;
469 prop = (float)sPtr->viewport->size.width / sPtr->contentView->size.width;
470 WMSetScrollerParameters(sPtr->hScroller, 0, prop);
472 if (sPtr->flags.hasVScroller) {
473 float prop;
475 prop = (float)sPtr->viewport->size.height / sPtr->contentView->size.height;
477 WMSetScrollerParameters(sPtr->vScroller, 0, prop);
481 void WMSetScrollViewRelief(WMScrollView * sPtr, WMReliefType type)
483 sPtr->flags.relief = type;
485 reorganizeInterior(sPtr);
487 if (sPtr->view->flags.mapped)
488 paintScrollView(sPtr);
492 static void paintScrollView(ScrollView * sPtr)
494 W_DrawRelief(sPtr->view->screen, sPtr->view->window, 0, 0,
495 sPtr->view->size.width, sPtr->view->size.height, sPtr->flags.relief);
498 static void updateScrollerProportion(ScrollView * sPtr)
500 float prop, value;
501 float oldV, oldP;
503 if (sPtr->flags.hasHScroller) {
504 oldV = WMGetScrollerValue(sPtr->hScroller);
505 oldP = WMGetScrollerKnobProportion(sPtr->hScroller);
507 prop = (float)sPtr->viewport->size.width / (float)sPtr->contentView->size.width;
509 if (oldP < 1.0F)
510 value = (prop * oldV) / oldP;
511 else
512 value = 0;
513 WMSetScrollerParameters(sPtr->hScroller, value, prop);
515 if (sPtr->flags.hasVScroller) {
516 oldV = WMGetScrollerValue(sPtr->vScroller);
517 oldP = WMGetScrollerKnobProportion(sPtr->vScroller);
519 prop = (float)sPtr->viewport->size.height / (float)sPtr->contentView->size.height;
521 if (oldP < 1.0F)
522 value = (prop * oldV) / oldP;
523 else
524 value = 0;
525 WMSetScrollerParameters(sPtr->vScroller, value, prop);
527 applyScrollerValues(sPtr);
530 static void handleViewportEvents(XEvent * event, void *data)
532 ScrollView *sPtr = (ScrollView *) data;
534 if (sPtr->contentView && event->xconfigure.window == sPtr->contentView->window)
535 updateScrollerProportion(sPtr);
538 static void handleEvents(XEvent * event, void *data)
540 ScrollView *sPtr = (ScrollView *) data;
542 CHECK_CLASS(data, WC_ScrollView);
544 switch (event->type) {
545 case Expose:
546 if (event->xexpose.count != 0)
547 break;
548 if (event->xexpose.serial == 0) /* means it's artificial */
549 W_RedisplayView(sPtr->contentView);
550 else
551 paintScrollView(sPtr);
552 break;
554 case DestroyNotify:
555 destroyScrollView(sPtr);
556 break;
561 static void destroyScrollView(ScrollView * sPtr)
563 wfree(sPtr);