wmii/liblitz/geometry.c

251 lines
5.5 KiB
C

/*
* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com>
* See LICENSE file for license details.
*/
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <cext.h>
#include "blitz.h"
BlitzAlign
blitz_align_of_rect(XRectangle *rect, int x, int y)
{
int w = x <= rect->x + rect->width / 2;
int n = y <= rect->y + rect->height / 2;
int e = x > rect->x + rect->width / 2;
int s = y > rect->y + rect->height / 2;
int nw = w && n;
int ne = e && n;
int sw = w && s;
int se = e && s;
if(nw)
return NWEST;
else if(ne)
return NEAST;
else if(se)
return SEAST;
else if(sw)
return SWEST;
return CENTER;
}
int blitz_strtoalign(BlitzAlign *result, char *val)
{
/*
* note, resize allows syntax like "east-20", this we cannot do
* include zero termination in strncmp checking!
*/
*result = CENTER;
if (!strncmp(val, "west", 4))
*result = WEST;
else if (!strncmp(val, "nwest", 5))
*result = NWEST;
else if (!strncmp(val, "north", 5))
*result = NORTH;
else if (!strncmp(val, "neast", 5))
*result = NEAST;
else if (!strncmp(val, "east", 4))
*result = EAST;
else if (!strncmp(val, "seast", 5))
*result = SEAST;
else if (!strncmp(val, "south", 5))
*result = SOUTH;
else if (!strncmp(val, "swest", 5))
*result = SWEST;
else if (!strncmp(val, "center", 6))
*result = CENTER;
else
return -1;
return 0;
}
/**
* Basic Syntax: <x> <y> <width> <height>
* Each component can be of following format:
* <...> = [+|-]0..n|<alignment>[[+|-]0..n]
*/
int blitz_strtorect(XRectangle *root, XRectangle *r, char *val)
{
const char *err;
char buf[64];
char *x, *y, *w, *h;
char *p;
int rx, ry, rw, rh, sx, sy, sw, sh;
if (!val)
return -1;
rx = r->x;
ry = r->y;
rw = r->width;
rh = r->height;
sx = sy = sw = sh = 0;
x = y = w = h = 0;
cext_strlcpy(buf, val, sizeof(buf));
x = strtok_r(buf, " ", &p);
if (x) {
y = strtok_r(0, " ", &p);
if (y) {
w = strtok_r(0, " ", &p);
if (w) {
h = strtok_r(0, "", &p);
}
}
}
if (x && (sx = (x[0] >= '0') && (x[0] <= '9')))
rx = cext_strtonum(x, 0, 65535, &err);
if (y && (sy = (y[0] >= '0') && (y[0] <= '9')))
ry = cext_strtonum(y, 0, 65535, &err);
if (w && (sw = (w[0] >= '0') && (w[0] <= '9')))
rw = cext_strtonum(w, 0, 65535, &err);
if (h && (sh = (h[0] >= '0') && (h[0] <= '9')))
rh = cext_strtonum(h, 0, 65535, &err);
if (!sx && !sw && x && w
&& x[0] != '-' && x[0] != '+' && w[0] != '-' && w[0] != '+') {
BlitzAlign ax, aw;
blitz_strtoalign(&ax, x);
blitz_strtoalign(&aw, w);
if ((ax == CENTER) && (aw == EAST)) {
rx = root->x + root->width / 2;
rw = root->width / 2;
} else {
rx = root->x;
if (aw == CENTER) {
rw = root->width / 2;
} else {
rw = root->width;
}
}
} else if (!sx && x && x[0] != '-' && x[0] != '+') {
BlitzAlign ax;
blitz_strtoalign(&ax, x);
if (ax == CENTER) {
rx = root->x + (root->width / 2) - (rw / 2);
} else if (ax == EAST) {
rx = root->x + root->width - rw;
} else {
rx = root->x;
}
} else if (!sw && w && w[0] != '-' && w[0] != '+') {
BlitzAlign aw;
blitz_strtoalign(&aw, w);
if (aw == CENTER) {
rw = (root->width / 2) - rx;
} else {
rw = root->width - rx;
}
}
if (!sy && !sh && y && h
&& y[0] != '-' && y[0] != '+' && h[0] != '-' && h[0] != '+') {
BlitzAlign ay, ah;
blitz_strtoalign(&ay, y);
blitz_strtoalign(&ah, h);
if ((ay == CENTER) && (ah == SOUTH)) {
ry = root->y + root->height / 2;
rh = root->height / 2;
} else {
ry = root->y;
if (ah == CENTER) {
rh = root->height / 2;
} else {
rh = root->height;
}
}
} else if (!sy && y && y[0] != '-' && y[0] != '+') {
BlitzAlign ay;
blitz_strtoalign(&ay, y);
if (ay == CENTER) {
ry = root->y + (root->height / 2) - (rh / 2);
} else if (ay == SOUTH) {
ry = root->y + root->height - rh;
} else {
ry = root->y;
}
} else if (!sh && h && h[0] != '-' && h[0] != '+') {
BlitzAlign ah;
blitz_strtoalign(&ah, h);
if (ah == CENTER) {
rh = (root->height / 2) - ry;
} else {
rh = root->height - ry;
}
}
/* now do final calculations */
if (x) {
p = strchr(x, '-');
if (p)
rx -= cext_strtonum(++p, 0, 65535, &err);
p = strchr(x, '+');
if (p)
rx += cext_strtonum(++p, 0, 65535, &err);
}
if (y) {
p = strchr(y, '-');
if (p)
ry -= cext_strtonum(++p, 0, 65535, &err);
p = strchr(y, '+');
if (p)
ry += cext_strtonum(++p, 0, 65535, &err);
}
if (w) {
p = strchr(w, '-');
if (p)
rw -= cext_strtonum(++p, 0, 65535, &err);
p = strchr(w, '+');
if (p)
rw += cext_strtonum(++p, 0, 65535, &err);
}
if (h) {
p = strchr(h, '-');
if (p)
rh -= cext_strtonum(++p, 0, 65535, &err);
p = strchr(h, '+');
if (p)
rh += cext_strtonum(++p, 0, 65535, &err);
}
if (rw < 1)
rw = 10;
if (rh < 1)
rh = 10;
r->x = rx;
r->y = ry;
r->width = rw;
r->height = rh;
return 0;
}
Bool blitz_ispointinrect(int x, int y, XRectangle * r)
{
return (x >= r->x) && (x <= r->x + r->width) && (y >= r->y) && (y <= r->y + r->height);
}
int blitz_distance(XRectangle * origin, XRectangle * target)
{
int ox = origin->x + origin->width / 2;
int oy = origin->y + origin->height / 2;
int tx = target->x + target->width / 2;
int ty = target->y + target->height / 2;
return (int) sqrt((double) (((ox - tx) * (ox - tx)) + ((oy - ty) * (oy - ty))));
}
void blitz_getbasegeometry(unsigned int size, unsigned int *cols, unsigned int *rows)
{
float sq, dummy;
sq = sqrt(size);
if (modff(sq, &dummy) < 0.5)
*rows = floor(sq);
else
*rows = ceil(sq);
*cols = ((*rows) * (*rows)) < (size) ? *rows + 1 : *rows;
}