#include "WINGsP.h" typedef struct W_ScrollView { W_Class widgetClass; WMView *view; WMView *contentView; WMView *viewport; WMScroller *vScroller; WMScroller *hScroller; short lineScroll; short pageScroll; struct { WMReliefType relief:3; unsigned int hasVScroller:1; unsigned int hasHScroller:1; } flags; } ScrollView; static void destroyScrollView(ScrollView *sPtr); static void paintScrollView(ScrollView *sPtr); static void handleEvents(XEvent *event, void *data); static void handleViewportEvents(XEvent *event, void *data); static void resizeScrollView(); W_ViewDelegate _ScrollViewViewDelegate = { NULL, NULL, resizeScrollView, NULL, NULL }; WMScrollView* WMCreateScrollView(WMWidget *parent) { ScrollView *sPtr; sPtr = wmalloc(sizeof(ScrollView)); memset(sPtr, 0, sizeof(ScrollView)); sPtr->widgetClass = WC_ScrollView; sPtr->view = W_CreateView(W_VIEW(parent)); if (!sPtr->view) { wfree(sPtr); return NULL; } sPtr->viewport = W_CreateView(sPtr->view); if (!sPtr->view) { W_DestroyView(sPtr->view); wfree(sPtr); return NULL; } sPtr->view->self = sPtr; sPtr->view->delegate = &_ScrollViewViewDelegate; sPtr->viewport->flags.mapWhenRealized = 1; WMCreateEventHandler(sPtr->view, StructureNotifyMask|ExposureMask, handleEvents, sPtr); WMCreateEventHandler(sPtr->viewport, SubstructureNotifyMask, handleViewportEvents, sPtr); sPtr->lineScroll = 4; sPtr->pageScroll = 0; return sPtr; } static void reorganizeInterior(WMScrollView *sPtr) { int hx, hy, hw; int vx, vy, vh; int cx, cy, cw, ch; cw = hw = sPtr->view->size.width; vh = ch = sPtr->view->size.height; if (sPtr->flags.relief == WRSimple) { cw -= 2; ch -= 2; cx = 1; cy = 1; } else if (sPtr->flags.relief != WRFlat) { cw -= 3; ch -= 3; cx = 2; cy = 2; } else { cx = 0; cy = 0; } if (sPtr->flags.hasHScroller) { int h = W_VIEW(sPtr->hScroller)->size.height; ch -= h; if (sPtr->flags.relief == WRSimple) { hx = 0; hy = sPtr->view->size.height - h; } else if (sPtr->flags.relief != WRFlat) { hx = 1; hy = sPtr->view->size.height - h - 1; hw -= 2; } else { hx = 0; hy = sPtr->view->size.height - h; } } else { /* make compiler shutup */ hx = 0; hy = 0; } if (sPtr->flags.hasVScroller) { int w = W_VIEW(sPtr->vScroller)->size.width; cw -= w; cx += w; hx += w - 1; hw -= w - 1; if (sPtr->flags.relief == WRSimple) { vx = 0; vy = 0; } else if (sPtr->flags.relief != WRFlat) { vx = 1; vy = 1; vh -= 2; } else { vx = 0; vy = 0; } } else { /* make compiler shutup */ vx = 0; vy = 0; } W_ResizeView(sPtr->viewport, cw, ch); W_MoveView(sPtr->viewport, cx, cy); if (sPtr->flags.hasHScroller) { WMResizeWidget(sPtr->hScroller, hw, 20); WMMoveWidget(sPtr->hScroller, hx, hy); } if (sPtr->flags.hasVScroller) { WMResizeWidget(sPtr->vScroller, 20, vh); WMMoveWidget(sPtr->vScroller, vx, vy); } } static void resizeScrollView(W_ViewDelegate *self, WMView *view) { reorganizeInterior(view->self); } void WMResizeScrollViewContent(WMScrollView *sPtr, unsigned int width, unsigned int height) { int w, h, x; w = width; h = height; x = 0; if (sPtr->flags.relief == WRSimple) { w += 2; h += 2; } else if (sPtr->flags.relief != WRFlat) { w += 4; h += 4; x = 1; } if (sPtr->flags.hasVScroller) { w -= W_VIEW(sPtr->hScroller)->size.width; WMResizeWidget(sPtr->vScroller, 20, h); } if (sPtr->flags.hasHScroller) { h -= W_VIEW(sPtr->hScroller)->size.height; WMResizeWidget(sPtr->hScroller, w, 20); WMMoveWidget(sPtr->hScroller, x, h); } W_ResizeView(sPtr->view, w, h); W_ResizeView(sPtr->viewport, width, height); } void WMSetScrollViewLineScroll(WMScrollView *sPtr, int amount) { assert(amount > 0); sPtr->lineScroll = amount; } void WMSetScrollViewPageScroll(WMScrollView *sPtr, int amount) { assert(amount >= 0); sPtr->pageScroll = amount; } static void doScrolling(WMWidget *self, void *data) { ScrollView *sPtr = (ScrollView*)data; float value; int pos; int vpsize; float size; if (sPtr->hScroller == (WMScroller *)self) { pos = -sPtr->contentView->pos.x; size = sPtr->contentView->size.width-sPtr->viewport->size.width; vpsize = sPtr->viewport->size.width - sPtr->pageScroll; } else { pos = -sPtr->contentView->pos.y; size = sPtr->contentView->size.height-sPtr->viewport->size.height; vpsize = sPtr->viewport->size.height - sPtr->pageScroll; } if (vpsize <= 0) vpsize = 1; switch (WMGetScrollerHitPart(self)) { case WSDecrementLine: if (pos > 0) { pos-=sPtr->lineScroll; if (pos < 0) pos = 0; value = (float)pos / size; WMSetScrollerParameters(self, value, WMGetScrollerKnobProportion(self)); } break; case WSIncrementLine: if (pos < size) { pos+=sPtr->lineScroll; if (pos > size) pos = size; value = (float)pos / size; WMSetScrollerParameters(self, value, WMGetScrollerKnobProportion(self)); } break; case WSKnob: value = WMGetScrollerValue(self); pos = value*size; break; case WSDecrementPage: if (pos > 0) { pos -= vpsize; if (pos < 0) pos = 0; value = (float)pos / size; WMSetScrollerParameters(self, value, WMGetScrollerKnobProportion(self)); } break; case WSIncrementPage: if (pos < size) { pos += vpsize; if (pos > size) pos = size; value = (float)pos / size; WMSetScrollerParameters(self, value, WMGetScrollerKnobProportion(self)); } break; case WSNoPart: case WSKnobSlot: break; } if (sPtr->hScroller == (WMScroller *)self) { W_MoveView(sPtr->contentView, -pos, sPtr->contentView->pos.y); } else { W_MoveView(sPtr->contentView, sPtr->contentView->pos.x, -pos); } } WMScroller* WMGetScrollViewHorizontalScroller(WMScrollView *sPtr) { return sPtr->hScroller; } WMScroller* WMGetScrollViewVerticalScroller(WMScrollView *sPtr) { return sPtr->vScroller; } void WMSetScrollViewHasHorizontalScroller(WMScrollView *sPtr, Bool flag) { if (flag) { if (sPtr->flags.hasHScroller) return; sPtr->flags.hasHScroller = 1; sPtr->hScroller = WMCreateScroller(sPtr); WMSetScrollerAction(sPtr->hScroller, doScrolling, sPtr); /* make it a horiz. scroller */ WMResizeWidget(sPtr->hScroller, 2, 1); reorganizeInterior(sPtr); WMMapWidget(sPtr->hScroller); } else { if (!sPtr->flags.hasHScroller) return; WMUnmapWidget(sPtr->hScroller); WMDestroyWidget(sPtr->hScroller); sPtr->hScroller = NULL; sPtr->flags.hasHScroller = 0; reorganizeInterior(sPtr); } } void WMSetScrollViewHasVerticalScroller(WMScrollView *sPtr, Bool flag) { if (flag) { if (sPtr->flags.hasVScroller) return; sPtr->flags.hasVScroller = 1; sPtr->vScroller = WMCreateScroller(sPtr); WMSetScrollerAction(sPtr->vScroller, doScrolling, sPtr); WMSetScrollerArrowsPosition(sPtr->vScroller, WSAMaxEnd); /* make it a vert. scroller */ WMResizeWidget(sPtr->vScroller, 1, 2); reorganizeInterior(sPtr); WMMapWidget(sPtr->vScroller); } else { if (!sPtr->flags.hasVScroller) return; sPtr->flags.hasVScroller = 0; WMUnmapWidget(sPtr->vScroller); WMDestroyWidget(sPtr->vScroller); sPtr->vScroller = NULL; reorganizeInterior(sPtr); } } void WMSetScrollViewContentView(WMScrollView *sPtr, WMView *view) { assert(sPtr->contentView == NULL); sPtr->contentView = view; W_ReparentView(sPtr->contentView, sPtr->viewport, 0, 0); if (sPtr->flags.hasHScroller) { float prop; prop = (float)sPtr->viewport->size.width/sPtr->contentView->size.width; WMSetScrollerParameters(sPtr->hScroller, 0, prop); } if (sPtr->flags.hasVScroller) { float prop; prop = (float)sPtr->viewport->size.height/sPtr->contentView->size.height; WMSetScrollerParameters(sPtr->vScroller, 0, prop); } } void WMSetScrollViewRelief(WMScrollView *sPtr, WMReliefType type) { sPtr->flags.relief = type; if (sPtr->view->flags.mapped) paintScrollView(sPtr); } static void paintScrollView(ScrollView *sPtr) { W_DrawRelief(sPtr->view->screen, sPtr->view->window, 0, 0, sPtr->view->size.width, sPtr->view->size.height, sPtr->flags.relief); } static void updateScrollerProportion(ScrollView *sPtr) { float prop, value; if (sPtr->flags.hasHScroller) { prop = (float)sPtr->viewport->size.width/sPtr->contentView->size.width; value = WMGetScrollerValue(sPtr->hScroller); WMSetScrollerParameters(sPtr->hScroller, value, prop); } if (sPtr->flags.hasVScroller) { prop = (float)sPtr->viewport->size.height/sPtr->contentView->size.height; value = WMGetScrollerValue(sPtr->vScroller); WMSetScrollerParameters(sPtr->vScroller, value, prop); } } static void handleViewportEvents(XEvent *event, void *data) { ScrollView *sPtr = (ScrollView*)data; if (sPtr->contentView && event->xconfigure.window == sPtr->contentView->window) updateScrollerProportion(sPtr); } static void handleEvents(XEvent *event, void *data) { ScrollView *sPtr = (ScrollView*)data; CHECK_CLASS(data, WC_ScrollView); switch (event->type) { case Expose: if (event->xexpose.count!=0) break; paintScrollView(sPtr); break; case DestroyNotify: destroyScrollView(sPtr); break; } } static void destroyScrollView(ScrollView *sPtr) { wfree(sPtr); }