Allow WPrefs to configure the last used workspace key.
[wmaker-crm.git] / WINGs / wscrollview.c
blob8b33812e18c19c64e20b133200c0d51d3bfb0167
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 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 reorganizeInterior(view->self);
203 updateScrollerProportion(view->self);
206 void WMResizeScrollViewContent(WMScrollView * sPtr, unsigned int width, unsigned int height)
208 int w, h, x;
210 w = width;
211 h = height;
213 x = 0;
214 if (sPtr->flags.relief == WRSimple) {
215 w += 2;
216 h += 2;
217 } else if (sPtr->flags.relief != WRFlat) {
218 w += 4;
219 h += 4;
220 x = 1;
223 if (sPtr->flags.hasVScroller) {
224 WMResizeWidget(sPtr->vScroller, 20, h);
225 width -= W_VIEW(sPtr->vScroller)->size.width;
228 if (sPtr->flags.hasHScroller) {
229 WMResizeWidget(sPtr->hScroller, w, 20);
230 WMMoveWidget(sPtr->hScroller, x, h);
231 height -= W_VIEW(sPtr->hScroller)->size.height;
234 W_ResizeView(sPtr->view, w, h);
236 W_ResizeView(sPtr->viewport, width, height);
239 void WMSetScrollViewLineScroll(WMScrollView * sPtr, int amount)
241 assert(amount > 0);
243 sPtr->lineScroll = amount;
246 void WMSetScrollViewPageScroll(WMScrollView * sPtr, int amount)
248 assert(amount >= 0);
250 sPtr->pageScroll = amount;
253 WMRect WMGetScrollViewVisibleRect(WMScrollView * sPtr)
255 WMRect rect;
257 rect.pos.x = -sPtr->contentView->pos.x;
258 rect.pos.y = -sPtr->contentView->pos.y;
259 rect.size = sPtr->viewport->size;
261 return rect;
264 void WMScrollViewScrollPoint(WMScrollView * sPtr, WMPoint point)
266 float xsize, ysize;
267 float xpos, ypos;
269 xsize = sPtr->contentView->size.width - sPtr->viewport->size.width;
270 ysize = sPtr->contentView->size.height - sPtr->viewport->size.height;
272 xpos = point.x / xsize;
273 ypos = point.y / ysize;
275 if (sPtr->hScroller)
276 WMSetScrollerParameters(sPtr->hScroller, xpos, WMGetScrollerKnobProportion(sPtr->hScroller));
277 if (sPtr->vScroller)
278 WMSetScrollerParameters(sPtr->vScroller, ypos, WMGetScrollerKnobProportion(sPtr->vScroller));
280 W_MoveView(sPtr->contentView, -point.x, -point.y);
283 static void doScrolling(WMWidget * self, void *data)
285 ScrollView *sPtr = (ScrollView *) data;
286 float value;
287 int pos;
288 int vpsize;
289 float size;
291 if (sPtr->hScroller == (WMScroller *) self) {
292 pos = -sPtr->contentView->pos.x;
293 size = sPtr->contentView->size.width - sPtr->viewport->size.width;
294 vpsize = sPtr->viewport->size.width - sPtr->pageScroll;
295 } else {
296 pos = -sPtr->contentView->pos.y;
297 size = sPtr->contentView->size.height - sPtr->viewport->size.height;
298 vpsize = sPtr->viewport->size.height - sPtr->pageScroll;
300 if (vpsize <= 0)
301 vpsize = 1;
303 switch (WMGetScrollerHitPart(self)) {
304 case WSDecrementLine:
305 if (pos > 0) {
306 pos -= sPtr->lineScroll;
307 if (pos < 0)
308 pos = 0;
309 value = (float)pos / size;
310 WMSetScrollerParameters(self, value, WMGetScrollerKnobProportion(self));
312 break;
313 case WSIncrementLine:
314 if (pos < size) {
315 pos += sPtr->lineScroll;
316 if (pos > size)
317 pos = size;
318 value = (float)pos / size;
319 WMSetScrollerParameters(self, value, WMGetScrollerKnobProportion(self));
321 break;
323 case WSKnob:
324 value = WMGetScrollerValue(self);
325 pos = value * size;
326 break;
328 case WSDecrementPage:
329 if (pos > 0) {
330 pos -= vpsize;
331 if (pos < 0)
332 pos = 0;
333 value = (float)pos / size;
334 WMSetScrollerParameters(self, value, WMGetScrollerKnobProportion(self));
336 break;
338 case WSDecrementWheel:
339 if (pos > 0) {
340 pos -= vpsize / 3;
341 if (pos < 0)
342 pos = 0;
343 value = (float)pos / size;
344 WMSetScrollerParameters(self, value, WMGetScrollerKnobProportion(self));
346 break;
348 case WSIncrementPage:
349 if (pos < size) {
350 pos += vpsize;
351 if (pos > size)
352 pos = size;
353 value = (float)pos / size;
354 WMSetScrollerParameters(self, value, WMGetScrollerKnobProportion(self));
356 break;
358 case WSIncrementWheel:
359 if (pos < size) {
360 pos += vpsize / 3;
361 if (pos > size)
362 pos = size;
363 value = (float)pos / size;
364 WMSetScrollerParameters(self, value, WMGetScrollerKnobProportion(self));
366 break;
368 case WSNoPart:
369 case WSKnobSlot:
370 break;
373 if (sPtr->hScroller == (WMScroller *) self) {
374 W_MoveView(sPtr->contentView, -pos, sPtr->contentView->pos.y);
375 } else {
376 W_MoveView(sPtr->contentView, sPtr->contentView->pos.x, -pos);
380 WMScroller *WMGetScrollViewHorizontalScroller(WMScrollView * sPtr)
382 return sPtr->hScroller;
385 WMScroller *WMGetScrollViewVerticalScroller(WMScrollView * sPtr)
387 return sPtr->vScroller;
390 void WMSetScrollViewHasHorizontalScroller(WMScrollView * sPtr, Bool flag)
392 if (flag) {
393 if (sPtr->flags.hasHScroller)
394 return;
395 sPtr->flags.hasHScroller = 1;
397 sPtr->hScroller = WMCreateScroller(sPtr);
398 WMSetScrollerAction(sPtr->hScroller, doScrolling, sPtr);
399 /* make it a horiz. scroller */
400 WMResizeWidget(sPtr->hScroller, 2, 1);
402 if (W_VIEW_REALIZED(sPtr->view)) {
403 WMRealizeWidget(sPtr->hScroller);
406 reorganizeInterior(sPtr);
408 WMMapWidget(sPtr->hScroller);
409 } else {
410 if (!sPtr->flags.hasHScroller)
411 return;
413 WMUnmapWidget(sPtr->hScroller);
414 WMDestroyWidget(sPtr->hScroller);
415 sPtr->hScroller = NULL;
416 sPtr->flags.hasHScroller = 0;
418 reorganizeInterior(sPtr);
422 void WMSetScrollViewHasVerticalScroller(WMScrollView * sPtr, Bool flag)
424 if (flag) {
425 if (sPtr->flags.hasVScroller)
426 return;
427 sPtr->flags.hasVScroller = 1;
429 sPtr->vScroller = WMCreateScroller(sPtr);
430 WMSetScrollerAction(sPtr->vScroller, doScrolling, sPtr);
431 WMSetScrollerArrowsPosition(sPtr->vScroller, WSAMaxEnd);
432 /* make it a vert. scroller */
433 WMResizeWidget(sPtr->vScroller, 1, 2);
435 if (W_VIEW_REALIZED(sPtr->view)) {
436 WMRealizeWidget(sPtr->vScroller);
439 reorganizeInterior(sPtr);
441 WMMapWidget(sPtr->vScroller);
442 } else {
443 if (!sPtr->flags.hasVScroller)
444 return;
445 sPtr->flags.hasVScroller = 0;
447 WMUnmapWidget(sPtr->vScroller);
448 WMDestroyWidget(sPtr->vScroller);
449 sPtr->vScroller = NULL;
451 reorganizeInterior(sPtr);
455 void WMSetScrollViewContentView(WMScrollView * sPtr, WMView * view)
457 assert(sPtr->contentView == NULL);
459 sPtr->contentView = view;
461 W_ReparentView(sPtr->contentView, sPtr->viewport, 0, 0);
463 if (sPtr->flags.hasHScroller) {
464 float prop;
466 prop = (float)sPtr->viewport->size.width / sPtr->contentView->size.width;
467 WMSetScrollerParameters(sPtr->hScroller, 0, prop);
469 if (sPtr->flags.hasVScroller) {
470 float prop;
472 prop = (float)sPtr->viewport->size.height / sPtr->contentView->size.height;
474 WMSetScrollerParameters(sPtr->vScroller, 0, prop);
478 void WMSetScrollViewRelief(WMScrollView * sPtr, WMReliefType type)
480 sPtr->flags.relief = type;
482 reorganizeInterior(sPtr);
484 if (sPtr->view->flags.mapped)
485 paintScrollView(sPtr);
489 static void paintScrollView(ScrollView * sPtr)
491 W_DrawRelief(sPtr->view->screen, sPtr->view->window, 0, 0,
492 sPtr->view->size.width, sPtr->view->size.height, sPtr->flags.relief);
495 static void updateScrollerProportion(ScrollView * sPtr)
497 float prop, value;
498 float oldV, oldP;
500 if (sPtr->flags.hasHScroller) {
501 oldV = WMGetScrollerValue(sPtr->hScroller);
502 oldP = WMGetScrollerKnobProportion(sPtr->hScroller);
504 prop = (float)sPtr->viewport->size.width / (float)sPtr->contentView->size.width;
506 if (oldP == 1.0)
507 value = 0;
508 else
509 value = (prop * oldV) / oldP;
510 WMSetScrollerParameters(sPtr->hScroller, value, prop);
512 if (sPtr->flags.hasVScroller) {
513 oldV = WMGetScrollerValue(sPtr->vScroller);
514 oldP = WMGetScrollerKnobProportion(sPtr->vScroller);
516 prop = (float)sPtr->viewport->size.height / (float)sPtr->contentView->size.height;
518 if (oldP == 1.0)
519 value = 0;
520 else
521 value = (prop * oldV) / oldP;
522 WMSetScrollerParameters(sPtr->vScroller, value, prop);
524 applyScrollerValues(sPtr);
527 static void handleViewportEvents(XEvent * event, void *data)
529 ScrollView *sPtr = (ScrollView *) data;
531 if (sPtr->contentView && event->xconfigure.window == sPtr->contentView->window)
532 updateScrollerProportion(sPtr);
535 static void handleEvents(XEvent * event, void *data)
537 ScrollView *sPtr = (ScrollView *) data;
539 CHECK_CLASS(data, WC_ScrollView);
541 switch (event->type) {
542 case Expose:
543 if (event->xexpose.count != 0)
544 break;
545 if (event->xexpose.serial == 0) /* means it's artificial */
546 W_RedisplayView(sPtr->contentView);
547 else
548 paintScrollView(sPtr);
549 break;
551 case DestroyNotify:
552 destroyScrollView(sPtr);
553 break;
558 static void destroyScrollView(ScrollView * sPtr)
560 wfree(sPtr);