1
0
mirror of https://github.com/gryf/wmaker.git synced 2025-12-18 20:10:29 +01:00
Files
wmaker/WINGs/wscrollview.c
Christophe CURIS 79a95d7173 Fixed floating point constants defined as double but expected as float
To preserve the accuracy of the operation, the C standard request that the
mathematical operation is performed using double precision, but in many
case this is not necessary so this patch fixes a few constants to avoid
that conversion.

Signed-off-by: Christophe CURIS <christophe.curis@free.fr>
2015-05-24 23:25:57 +01:00

565 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)
{
/* Parameter not used, but tell the compiler that it is ok */
(void) self;
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.0F)
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.0F)
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);
}