mirror of
https://github.com/gryf/wmaker.git
synced 2025-12-19 04:20:27 +01:00
It is dangerous to let the compiler know about a function without letting him know the arguments because he won't be able to report invalid calls. This patch concern the cases where adding the arguments did not need other code change.
562 lines
12 KiB
C
562 lines
12 KiB
C
|
|
#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 *self, WMView *view);
|
|
static void updateScrollerProportion(ScrollView *sPtr);
|
|
|
|
W_ViewDelegate _ScrollViewViewDelegate = {
|
|
NULL,
|
|
NULL,
|
|
resizeScrollView,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
WMScrollView *WMCreateScrollView(WMWidget * parent)
|
|
{
|
|
ScrollView *sPtr;
|
|
|
|
sPtr = wmalloc(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->viewport) {
|
|
W_DestroyView(sPtr->view);
|
|
wfree(sPtr);
|
|
return NULL;
|
|
}
|
|
sPtr->view->self = sPtr;
|
|
sPtr->viewport->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 applyScrollerValues(WMScrollView * sPtr)
|
|
{
|
|
int x, y;
|
|
|
|
if (sPtr->contentView == NULL)
|
|
return;
|
|
|
|
if (sPtr->flags.hasHScroller) {
|
|
float v = WMGetScrollerValue(sPtr->hScroller);
|
|
int size;
|
|
|
|
size = sPtr->contentView->size.width - sPtr->viewport->size.width;
|
|
|
|
x = v * size;
|
|
} else {
|
|
x = 0;
|
|
}
|
|
|
|
if (sPtr->flags.hasVScroller) {
|
|
float v = WMGetScrollerValue(sPtr->vScroller);
|
|
|
|
int size;
|
|
|
|
size = sPtr->contentView->size.height - sPtr->viewport->size.height;
|
|
|
|
y = v * size;
|
|
} else {
|
|
y = 0;
|
|
}
|
|
|
|
x = WMAX(0, x);
|
|
y = WMAX(0, y);
|
|
|
|
W_MoveView(sPtr->contentView, -x, -y);
|
|
|
|
W_RaiseView(sPtr->viewport);
|
|
}
|
|
|
|
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 = 20;
|
|
|
|
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 = 20;
|
|
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);
|
|
}
|
|
|
|
applyScrollerValues(sPtr);
|
|
}
|
|
|
|
static void resizeScrollView(W_ViewDelegate * self, WMView * view)
|
|
{
|
|
reorganizeInterior(view->self);
|
|
updateScrollerProportion(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) {
|
|
WMResizeWidget(sPtr->vScroller, 20, h);
|
|
width -= W_VIEW(sPtr->vScroller)->size.width;
|
|
}
|
|
|
|
if (sPtr->flags.hasHScroller) {
|
|
WMResizeWidget(sPtr->hScroller, w, 20);
|
|
WMMoveWidget(sPtr->hScroller, x, h);
|
|
height -= W_VIEW(sPtr->hScroller)->size.height;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
WMRect WMGetScrollViewVisibleRect(WMScrollView * sPtr)
|
|
{
|
|
WMRect rect;
|
|
|
|
rect.pos.x = -sPtr->contentView->pos.x;
|
|
rect.pos.y = -sPtr->contentView->pos.y;
|
|
rect.size = sPtr->viewport->size;
|
|
|
|
return rect;
|
|
}
|
|
|
|
void WMScrollViewScrollPoint(WMScrollView * sPtr, WMPoint point)
|
|
{
|
|
float xsize, ysize;
|
|
float xpos, ypos;
|
|
|
|
xsize = sPtr->contentView->size.width - sPtr->viewport->size.width;
|
|
ysize = sPtr->contentView->size.height - sPtr->viewport->size.height;
|
|
|
|
xpos = point.x / xsize;
|
|
ypos = point.y / ysize;
|
|
|
|
if (sPtr->hScroller)
|
|
WMSetScrollerParameters(sPtr->hScroller, xpos, WMGetScrollerKnobProportion(sPtr->hScroller));
|
|
if (sPtr->vScroller)
|
|
WMSetScrollerParameters(sPtr->vScroller, ypos, WMGetScrollerKnobProportion(sPtr->vScroller));
|
|
|
|
W_MoveView(sPtr->contentView, -point.x, -point.y);
|
|
}
|
|
|
|
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 WSDecrementWheel:
|
|
if (pos > 0) {
|
|
pos -= vpsize / 3;
|
|
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 WSIncrementWheel:
|
|
if (pos < size) {
|
|
pos += vpsize / 3;
|
|
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);
|
|
|
|
if (W_VIEW_REALIZED(sPtr->view)) {
|
|
WMRealizeWidget(sPtr->hScroller);
|
|
}
|
|
|
|
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);
|
|
|
|
if (W_VIEW_REALIZED(sPtr->view)) {
|
|
WMRealizeWidget(sPtr->vScroller);
|
|
}
|
|
|
|
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;
|
|
|
|
reorganizeInterior(sPtr);
|
|
|
|
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;
|
|
float oldV, oldP;
|
|
|
|
if (sPtr->flags.hasHScroller) {
|
|
oldV = WMGetScrollerValue(sPtr->hScroller);
|
|
oldP = WMGetScrollerKnobProportion(sPtr->hScroller);
|
|
|
|
prop = (float)sPtr->viewport->size.width / (float)sPtr->contentView->size.width;
|
|
|
|
if (oldP < 1.0)
|
|
value = (prop * oldV) / oldP;
|
|
else
|
|
value = 0;
|
|
WMSetScrollerParameters(sPtr->hScroller, value, prop);
|
|
}
|
|
if (sPtr->flags.hasVScroller) {
|
|
oldV = WMGetScrollerValue(sPtr->vScroller);
|
|
oldP = WMGetScrollerKnobProportion(sPtr->vScroller);
|
|
|
|
prop = (float)sPtr->viewport->size.height / (float)sPtr->contentView->size.height;
|
|
|
|
if (oldP < 1.0)
|
|
value = (prop * oldV) / oldP;
|
|
else
|
|
value = 0;
|
|
WMSetScrollerParameters(sPtr->vScroller, value, prop);
|
|
}
|
|
applyScrollerValues(sPtr);
|
|
}
|
|
|
|
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;
|
|
if (event->xexpose.serial == 0) /* means it's artificial */
|
|
W_RedisplayView(sPtr->contentView);
|
|
else
|
|
paintScrollView(sPtr);
|
|
break;
|
|
|
|
case DestroyNotify:
|
|
destroyScrollView(sPtr);
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
static void destroyScrollView(ScrollView * sPtr)
|
|
{
|
|
wfree(sPtr);
|
|
}
|