4 typedef struct W_ScrollView
{
11 WMScroller
*vScroller
;
12 WMScroller
*hScroller
;
18 WMReliefType relief
:3;
19 unsigned int hasVScroller
:1;
20 unsigned int hasHScroller
:1;
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
= {
42 WMScrollView
*WMCreateScrollView(WMWidget
* parent
)
46 sPtr
= wmalloc(sizeof(ScrollView
));
47 sPtr
->widgetClass
= WC_ScrollView
;
49 sPtr
->view
= W_CreateView(W_VIEW(parent
));
54 sPtr
->viewport
= W_CreateView(sPtr
->view
);
55 if (!sPtr
->viewport
) {
56 W_DestroyView(sPtr
->view
);
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
);
77 static void applyScrollerValues(WMScrollView
* sPtr
)
81 if (sPtr
->contentView
== NULL
)
84 if (sPtr
->flags
.hasHScroller
) {
85 float v
= WMGetScrollerValue(sPtr
->hScroller
);
88 size
= sPtr
->contentView
->size
.width
- sPtr
->viewport
->size
.width
;
95 if (sPtr
->flags
.hasVScroller
) {
96 float v
= WMGetScrollerValue(sPtr
->vScroller
);
100 size
= sPtr
->contentView
->size
.height
- sPtr
->viewport
->size
.height
;
110 W_MoveView(sPtr
->contentView
, -x
, -y
);
112 W_RaiseView(sPtr
->viewport
);
115 static void reorganizeInterior(WMScrollView
* sPtr
)
121 cw
= hw
= sPtr
->view
->size
.width
;
122 vh
= ch
= sPtr
->view
->size
.height
;
124 if (sPtr
->flags
.relief
== WRSimple
) {
129 } else if (sPtr
->flags
.relief
!= WRFlat
) {
139 if (sPtr
->flags
.hasHScroller
) {
144 if (sPtr
->flags
.relief
== WRSimple
) {
146 hy
= sPtr
->view
->size
.height
- h
;
147 } else if (sPtr
->flags
.relief
!= WRFlat
) {
149 hy
= sPtr
->view
->size
.height
- h
- 1;
153 hy
= sPtr
->view
->size
.height
- h
;
156 /* make compiler shutup */
161 if (sPtr
->flags
.hasVScroller
) {
168 if (sPtr
->flags
.relief
== WRSimple
) {
171 } else if (sPtr
->flags
.relief
!= WRFlat
) {
180 /* make compiler shutup */
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
)
214 if (sPtr
->flags
.relief
== WRSimple
) {
217 } else if (sPtr
->flags
.relief
!= WRFlat
) {
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
)
243 sPtr
->lineScroll
= amount
;
246 void WMSetScrollViewPageScroll(WMScrollView
* sPtr
, int amount
)
250 sPtr
->pageScroll
= amount
;
253 WMRect
WMGetScrollViewVisibleRect(WMScrollView
* sPtr
)
257 rect
.pos
.x
= -sPtr
->contentView
->pos
.x
;
258 rect
.pos
.y
= -sPtr
->contentView
->pos
.y
;
259 rect
.size
= sPtr
->viewport
->size
;
264 void WMScrollViewScrollPoint(WMScrollView
* sPtr
, WMPoint point
)
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
;
276 WMSetScrollerParameters(sPtr
->hScroller
, xpos
, WMGetScrollerKnobProportion(sPtr
->hScroller
));
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
;
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
;
296 pos
= -sPtr
->contentView
->pos
.y
;
297 size
= sPtr
->contentView
->size
.height
- sPtr
->viewport
->size
.height
;
298 vpsize
= sPtr
->viewport
->size
.height
- sPtr
->pageScroll
;
303 switch (WMGetScrollerHitPart(self
)) {
304 case WSDecrementLine
:
306 pos
-= sPtr
->lineScroll
;
309 value
= (float)pos
/ size
;
310 WMSetScrollerParameters(self
, value
, WMGetScrollerKnobProportion(self
));
313 case WSIncrementLine
:
315 pos
+= sPtr
->lineScroll
;
318 value
= (float)pos
/ size
;
319 WMSetScrollerParameters(self
, value
, WMGetScrollerKnobProportion(self
));
324 value
= WMGetScrollerValue(self
);
328 case WSDecrementPage
:
333 value
= (float)pos
/ size
;
334 WMSetScrollerParameters(self
, value
, WMGetScrollerKnobProportion(self
));
338 case WSDecrementWheel
:
343 value
= (float)pos
/ size
;
344 WMSetScrollerParameters(self
, value
, WMGetScrollerKnobProportion(self
));
348 case WSIncrementPage
:
353 value
= (float)pos
/ size
;
354 WMSetScrollerParameters(self
, value
, WMGetScrollerKnobProportion(self
));
358 case WSIncrementWheel
:
363 value
= (float)pos
/ size
;
364 WMSetScrollerParameters(self
, value
, WMGetScrollerKnobProportion(self
));
373 if (sPtr
->hScroller
== (WMScroller
*) self
) {
374 W_MoveView(sPtr
->contentView
, -pos
, sPtr
->contentView
->pos
.y
);
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
)
393 if (sPtr
->flags
.hasHScroller
)
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
);
410 if (!sPtr
->flags
.hasHScroller
)
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
)
425 if (sPtr
->flags
.hasVScroller
)
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
);
443 if (!sPtr
->flags
.hasVScroller
)
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
) {
466 prop
= (float)sPtr
->viewport
->size
.width
/ sPtr
->contentView
->size
.width
;
467 WMSetScrollerParameters(sPtr
->hScroller
, 0, prop
);
469 if (sPtr
->flags
.hasVScroller
) {
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
)
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
;
507 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
;
519 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
) {
543 if (event
->xexpose
.count
!= 0)
545 if (event
->xexpose
.serial
== 0) /* means it's artificial */
546 W_RedisplayView(sPtr
->contentView
);
548 paintScrollView(sPtr
);
552 destroyScrollView(sPtr
);
558 static void destroyScrollView(ScrollView
* sPtr
)