#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <X11/Xfuncs.h>
#include "BitmapP.h"
#include "Bitmap.h"
#include "Requests.h"
#include <stdio.h>
#include <math.h>
#ifndef abs
#define abs(x) (((x) > 0) ? (x) : -(x))
#endif
#define min(x, y) (((int)(x) < (int)(y)) ? (x) : (y))
#define max(x, y) (((int)(x) > (int)(y)) ? (x) : (y))
#ifndef rint
#define rint(x) floor(x + 0.5)
#endif
#define GetBit(image, x, y)\
((bit)((*(image->data + (x) / 8 + (y) * image->bytes_per_line) &\
(1 << ((x) % 8))) ? 1 : 0))
#if 0
bit
BWGetBit(Widget w, Position x, Position y)
{
BitmapWidget BW = (BitmapWidget) w;
if (QueryInBitmap(BW, x, y))
return GetBit(BW->bitmap.image, x, y);
else
return NotSet;
}
#endif
#define InvertBit(image, x, y)\
(*(image->data + (x) / 8 + (y) * image->bytes_per_line) ^=\
(bit) (1 << ((x) % 8)))
#define SetBit(image, x, y)\
(*(image->data + (x) / 8 + (y) * image->bytes_per_line) |=\
(bit) (1 << ((x) % 8)))
#define ClearBit(image, x, y)\
(*(image->data + (x) / 8 + (y) * image->bytes_per_line) &=\
(bit)~(1 << ((x) % 8)))
#define HighlightSquare(BW, x, y)\
XFillRectangle(XtDisplay(BW), XtWindow(BW),\
BW->bitmap.highlighting_gc,\
InWindowX(BW, x), InWindowY(BW, y),\
BW->bitmap.squareW, BW->bitmap.squareH)
#define DrawSquare(BW, x, y)\
XFillRectangle(XtDisplay(BW), XtWindow(BW),\
BW->bitmap.drawing_gc,\
InWindowX(BW, x), InWindowY(BW, y),\
BW->bitmap.squareW, BW->bitmap.squareH)
#define InvertPoint(BW, x, y)\
{InvertBit(BW->bitmap.image, x, y); DrawSquare(BW, x, y);}
#define DrawPoint(BW, x, y, value)\
if (GetBit(BW->bitmap.image, x, y) != value)\
InvertPoint(BW, x, y)
void
BWDrawPoint(Widget w, Position x, Position y, bit value)
{
BitmapWidget BW = (BitmapWidget) w;
if (QueryInBitmap(BW, x, y)) {
if (value == Highlight)
HighlightSquare(BW, x, y);
else
DrawPoint(BW, x, y, value);
}
}
static XPoint *
HotSpotShape(BitmapWidget BW, Position x, Position y)
{
static XPoint points[5];
points[0].x = InWindowX(BW, x);
points[0].y = InWindowY(BW, y + 1.0/2);
points[1].x = InWindowX(BW, x + 1.0/2);
points[1].y = InWindowY(BW, y + 1);
points[2].x = InWindowX(BW, x + 1);
points[2].y = InWindowY(BW, y + 1.0/2);
points[3].x = InWindowX(BW, x + 1.0/2);
points[3].y = InWindowY(BW, y);
points[4].x = InWindowX(BW, x);
points[4].y = InWindowY(BW, y + 1.0/2);
return points;
}
#define DrawHotSpot(BW, x, y)\
XFillPolygon(XtDisplay(BW), XtWindow(BW), BW->bitmap.drawing_gc,\
HotSpotShape(BW, x, y), 5, Convex, CoordModeOrigin)
#define HighlightHotSpot(BW, x, y)\
XFillPolygon(XtDisplay(BW), XtWindow(BW), BW->bitmap.highlighting_gc,\
HotSpotShape(BW, x, y), 5, Convex, CoordModeOrigin)
void
BWRedrawHotSpot(Widget w)
{
BitmapWidget BW = (BitmapWidget) w;
if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y))
DrawHotSpot(BW, BW->bitmap.hot.x, BW->bitmap.hot.y);
}
void
BWClearHotSpot(Widget w)
{
BitmapWidget BW = (BitmapWidget) w;
if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)) {
DrawHotSpot(BW, BW->bitmap.hot.x, BW->bitmap.hot.y);
BW->bitmap.hot.x = BW->bitmap.hot.y = NotSet;
}
}
void
BWDrawHotSpot(Widget w, Position x, Position y, int value)
{
BitmapWidget BW = (BitmapWidget) w;
if (QueryInBitmap(BW, x, y)) {
if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y) &&
((BW->bitmap.hot.x == x) && (BW->bitmap.hot.y == y))) {
if ((value == Clear) || (value == Invert)) {
BWClearHotSpot(w);
}
}
else
if ((value == Set) || (value == Invert)) {
BWClearHotSpot(w);
DrawHotSpot(BW, x, y);
BW->bitmap.hot.x = x;
BW->bitmap.hot.y = y;
}
if (value == Highlight)
HighlightHotSpot(BW, x, y);
}
}
void
BWSetHotSpot(Widget w, Position x, Position y)
{
if (QuerySet(x, y))
BWDrawHotSpot(w, x, y, Set);
else
BWClearHotSpot(w);
}
void
BWRedrawSquares(Widget w,
Position x, Position y,
Dimension width, Dimension height)
{
BitmapWidget BW = (BitmapWidget) w;
Position from_x = InBitmapX(BW, x);
Position from_y = InBitmapY(BW, y);
Position to_x = InBitmapX(BW, x + width);
Position to_y = InBitmapY(BW, y + height);
QuerySwap(from_x, to_x);
QuerySwap(from_y, to_y);
from_x = max(0, from_x);
from_y = max(0, from_y);
to_x = min(BW->bitmap.image->width - 1, to_x);
to_y = min(BW->bitmap.image->height - 1, to_y);
for (x = from_x; x <= to_x; x++)
for (y = from_y; y <= to_y; y++)
if (GetBit(BW->bitmap.image, x, y)) DrawSquare(BW, x, y);
}
void
BWDrawGrid(Widget w,
Position from_x, Position from_y,
Position to_x, Position to_y)
{
BitmapWidget BW = (BitmapWidget) w;
int i;
QuerySwap(from_x, to_x);
QuerySwap(from_y, to_y);
from_x = max(0, from_x);
from_y = max(0, from_y);
to_x = min(BW->bitmap.image->width - 1, to_x);
to_y = min(BW->bitmap.image->height - 1, to_y);
for(i = from_x + (from_x == 0); i <= to_x; i++)
XDrawLine(XtDisplay(BW), XtWindow(BW),
BW->bitmap.frame_gc,
InWindowX(BW, i), InWindowY(BW, from_y),
InWindowX(BW, i), InWindowY(BW, to_y + 1));
for(i = from_y + (from_y == 0); i <= to_y; i++)
XDrawLine(XtDisplay(BW), XtWindow(BW),
BW->bitmap.frame_gc,
InWindowX(BW, from_x), InWindowY(BW, i),
InWindowX(BW, to_x + 1), InWindowY(BW, i));
}
void
BWRedrawGrid(Widget w,
Position x, Position y,
Dimension width, Dimension height)
{
BitmapWidget BW = (BitmapWidget) w;
Position from_x = InBitmapX(BW, x);
Position from_y = InBitmapY(BW, y);
Position to_x = InBitmapX(BW, x + width);
Position to_y = InBitmapY(BW, y + height);
if (BW->bitmap.grid)
BWDrawGrid(w, from_x, from_y, to_x, to_y);
}
void
BWDrawLine(Widget w,
Position from_x, Position from_y,
Position to_x, Position to_y, int value)
{
Position i;
register double x, y;
double dx, dy, delta;
dx = to_x - from_x;
dy = to_y - from_y;
x = from_x + 0.5;
y = from_y + 0.5;
delta = max(abs(dx), abs(dy));
if (delta > 0) {
dx /= delta;
dy /= delta;
for(i = 0; i <= delta; i++) {
BWDrawPoint(w, (Position) x, (Position) y, value);
x += dx;
y += dy;
}
}
else
BWDrawPoint(w, from_x, from_y, value);
}
void
BWBlindLine(Widget w,
Position from_x, Position from_y,
Position to_x, Position to_y, int value)
{
Position i;
register double x, y;
double dx, dy, delta;
dx = to_x - from_x;
dy = to_y - from_y;
x = from_x + 0.5;
y = from_y + 0.5;
delta = max(abs(dx), abs(dy));
if (delta > 0) {
dx /= delta;
dy /= delta;
x += dx;
y += dy;
for(i = 1; i <= delta; i++) {
BWDrawPoint(w, (Position) x, (Position) y, value);
x += dx;
y += dy;
}
}
else
BWDrawPoint(w, from_x, from_y, value);
}
void
BWDrawRectangle(Widget w,
Position from_x, Position from_y,
Position to_x, Position to_y, int value)
{
register Position i;
Dimension delta, width, height;
QuerySwap(from_x, to_x);
QuerySwap(from_y, to_y);
width = to_x - from_x;
height = to_y - from_y;
delta = max(width, height);
if (!QueryZero(width, height)) {
for (i = 0; (int)i < (int)delta; i++) {
if ((int)i < (int)width) {
BWDrawPoint(w, from_x + i, from_y, value);
BWDrawPoint(w, to_x - i, to_y, value);
}
if ((int)i < (int)height) {
BWDrawPoint(w, from_x, to_y - i, value);
BWDrawPoint(w, to_x, from_y + i, value);
}
}
}
else
BWDrawLine(w,
from_x, from_y,
to_x, to_y, value);
}
void
BWDrawFilledRectangle(Widget w,
Position from_x, Position from_y,
Position to_x, Position to_y, int value)
{
register Position x, y;
QuerySwap(from_x, to_x);
QuerySwap(from_y, to_y);
for (x = from_x; x <= to_x; x++)
for (y = from_y; y <= to_y; y++)
BWDrawPoint(w, x, y, value);
}
void
BWDrawCircle(Widget w,
Position origin_x, Position origin_y,
Position point_x, Position point_y, int value)
{
register Position i, delta;
Dimension dx, dy, half;
double radius;
dx = abs(point_x - origin_x);
dy = abs(point_y - origin_y);
radius = sqrt((double) ((int)dx * (int)dx + (int)dy * (int)dy));
if (radius < 1.0) {
BWDrawPoint(w, origin_x, origin_y, value);
}
else {
BWDrawPoint(w, origin_x - (Position) floor(radius), origin_y, value);
BWDrawPoint(w, origin_x + (Position) floor(radius), origin_y, value);
BWDrawPoint(w, origin_x, origin_y - (Position) floor(radius), value);
BWDrawPoint(w, origin_x, origin_y + (Position) floor(radius), value);
}
half = radius / sqrt(2.0);
for(i = 1; (int)i <= (int)half; i++) {
delta = sqrt(radius * radius - i * i);
BWDrawPoint(w, origin_x - delta, origin_y - i, value);
BWDrawPoint(w, origin_x - delta, origin_y + i, value);
BWDrawPoint(w, origin_x + delta, origin_y - i, value);
BWDrawPoint(w, origin_x + delta, origin_y + i, value);
if (i != delta) {
BWDrawPoint(w, origin_x - i, origin_y - delta, value);
BWDrawPoint(w, origin_x - i, origin_y + delta, value);
BWDrawPoint(w, origin_x + i, origin_y - delta, value);
BWDrawPoint(w, origin_x + i, origin_y + delta, value);
}
}
}
void
BWDrawFilledCircle(Widget w,
Position origin_x, Position origin_y,
Position point_x, Position point_y, int value)
{
register Position i, j, delta;
Dimension dx, dy;
double radius;
dx = abs(point_x - origin_x);
dy = abs(point_y - origin_y);
radius = sqrt((double) ((int)dx * (int)dx + (int)dy * (int)dy));
for(j = origin_x - (Position) floor(radius);
j <= origin_x + (Position) floor(radius); j++)
BWDrawPoint(w, j, origin_y, value);
for(i = 1; i <= (Position) floor(radius); i++) {
delta = sqrt(radius * radius - i * i);
for(j = origin_x - delta; j <= origin_x + delta; j++) {
BWDrawPoint(w, j, origin_y - i, value);
BWDrawPoint(w, j, origin_y + i, value);
}
}
}
#define QueryFlood(BW, x, y, value)\
((GetBit(BW->bitmap.image, x, y) !=\
(value & 1)) && QueryInBitmap(BW, x, y))
#define Flood(BW, x, y, value)\
{if (value == Highlight) HighlightSquare(BW, x, y);\
else InvertPoint(BW, x, y);}
static void
FloodLoop(BitmapWidget BW, Position x, Position y, int value)
{
Position save_x, save_y, x_left, x_right;
if (QueryFlood(BW, x, y, value))
Flood(BW, x, y, value)
save_x = x;
save_y = y;
x++;
while (QueryFlood(BW, x, y, value)) {
Flood(BW, x, y, value);
x++;
}
x_right = --x;
x = save_x;
x--;
while (QueryFlood(BW, x, y, value)) {
Flood(BW, x, y, value);
x--;
}
x_left = ++x;
x = x_left;
y = save_y;
y++;
while (x <= x_right) {
Boolean flag = False;
Position x_enter;
while (QueryFlood(BW, x, y, value) && (x <= x_right)) {
flag = True;
x++;
}
if (flag) {
if ((x == x_right) && QueryFlood(BW, x, y, value))
FloodLoop(BW, x, y, value);
else
FloodLoop(BW, x - 1, y, value);
}
x_enter = x;
while (!QueryFlood(BW, x, y, value) && (x < x_right))
x++;
if (x == x_enter) x++;
}
x = x_left;
y = save_y;
y--;
while (x <= x_right) {
Boolean flag = False;
Position x_enter;
while (QueryFlood(BW, x, y, value) && (x <= x_right)) {
flag = True;
x++;
}
if (flag) {
if ((x == x_right) && QueryFlood(BW, x, y, value))
FloodLoop(BW, x, y, value);
else
FloodLoop(BW, x - 1, y, value);
}
x_enter = x;
while (!QueryFlood(BW, x, y, value) && (x < x_right))
x++;
if (x == x_enter) x++;
}
}
void
BWFloodFill(Widget w, Position x, Position y, int value)
{
BitmapWidget BW = (BitmapWidget) w;
int pixel;
pixel = GetBit(BW->bitmap.image, x, y);
if (value == Invert)
FloodLoop(BW, x, y, (pixel ? Clear : Set));
else if (value != pixel)
FloodLoop(BW, x, y, value);
}
#define QueryHotInMark(BW)\
((BW->bitmap.hot.x == max(BW->bitmap.mark.from_x,\
min(BW->bitmap.hot.x, BW->bitmap.mark.to_x)))\
&&\
(BW->bitmap.hot.y == max(BW->bitmap.mark.from_y,\
min(BW->bitmap.hot.y, BW->bitmap.mark.to_y))))
void
BWUp(Widget w)
{
BitmapWidget BW = (BitmapWidget) w;
register Position x, y;
bit first, up, down=0;
Position from_x, from_y, to_x, to_y;
if (BWQueryMarked(w)) {
from_x = BW->bitmap.mark.from_x;
from_y = BW->bitmap.mark.from_y;
to_x = BW->bitmap.mark.to_x;
to_y = BW->bitmap.mark.to_y;
}
else {
from_x = 0;
from_y = 0;
to_x = BW->bitmap.width - 1;
to_y = BW->bitmap.height - 1;
}
if ((to_y - from_y) == 0)
return;
for(x = from_x; x <= to_x; x++) {
first = up = GetBit(BW->bitmap.image, x, to_y);
for(y = to_y - 1; y >= from_y; y--) {
down = GetBit(BW->bitmap.image, x, y);
if (up != down)
InvertPoint(BW, x, y);
up =down;
}
if(first != down)
InvertPoint(BW, x, to_y);
}
if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
&&
!BWQueryMarked(w))
BWSetHotSpot(w,
BW->bitmap.hot.x,
(BW->bitmap.hot.y - 1 + BW->bitmap.image->height) %
BW->bitmap.image->height);
}
void
BWDown(Widget w)
{
BitmapWidget BW = (BitmapWidget) w;
register Position x, y;
bit first, down, up=0;
Position from_x, from_y, to_x, to_y;
if (BWQueryMarked(w)) {
from_x = BW->bitmap.mark.from_x;
from_y = BW->bitmap.mark.from_y;
to_x = BW->bitmap.mark.to_x;
to_y = BW->bitmap.mark.to_y;
}
else {
from_x = 0;
from_y = 0;
to_x = BW->bitmap.width - 1;
to_y = BW->bitmap.height - 1;
}
if ((to_y - from_y) == 0)
return;
for(x = from_x; x <= to_x; x++) {
first = down = GetBit(BW->bitmap.image, x, from_y);
for(y = from_y + 1; y <= to_y; y++) {
up = GetBit(BW->bitmap.image, x, y);
if (down != up)
InvertPoint(BW, x, y);
down = up;
}
if(first != up)
InvertPoint(BW, x, from_y);
}
if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
&&
!BWQueryMarked(w))
BWSetHotSpot(w,
BW->bitmap.hot.x,
(BW->bitmap.hot.y + 1) % BW->bitmap.image->height);
}
void
BWLeft(Widget w)
{
BitmapWidget BW = (BitmapWidget) w;
register Position x, y;
bit first, left, right=0;
Position from_x, from_y, to_x, to_y;
if (BWQueryMarked(w)) {
from_x = BW->bitmap.mark.from_x;
from_y = BW->bitmap.mark.from_y;
to_x = BW->bitmap.mark.to_x;
to_y = BW->bitmap.mark.to_y;
}
else {
from_x = 0;
from_y = 0;
to_x = BW->bitmap.width - 1;
to_y = BW->bitmap.height - 1;
}
if ((to_x - from_x) == 0)
return;
for(y = from_y; y <= to_y; y++) {
first = left = GetBit(BW->bitmap.image, to_x, y);
for(x = to_x - 1; x >= from_x; x--) {
right = GetBit(BW->bitmap.image, x, y);
if (left != right)
InvertPoint(BW, x, y);
left = right;
}
if(first != right)
InvertPoint(BW, to_x, y);
}
if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
&&
!BWQueryMarked(w))
BWSetHotSpot(w,
(BW->bitmap.hot.x - 1 + BW->bitmap.image->width) %
BW->bitmap.image->width,
BW->bitmap.hot.y);
}
void
BWRight(Widget w)
{
BitmapWidget BW = (BitmapWidget) w;
register Position x, y;
bit first, right, left=0;
Position from_x, from_y, to_x, to_y;
if (BWQueryMarked(w)) {
from_x = BW->bitmap.mark.from_x;
from_y = BW->bitmap.mark.from_y;
to_x = BW->bitmap.mark.to_x;
to_y = BW->bitmap.mark.to_y;
}
else {
from_x = 0;
from_y = 0;
to_x = BW->bitmap.width - 1;
to_y = BW->bitmap.height - 1;
}
if ((to_x - from_x) == 0)
return;
for(y = from_y; y <= to_y; y++) {
first = right = GetBit(BW->bitmap.image, from_x, y);
for(x = from_x + 1; x <= to_x; x++) {
left = GetBit(BW->bitmap.image, x, y);
if (right != left)
InvertPoint(BW, x, y);
right = left;
}
if(first != left)
InvertPoint(BW, from_x, y);
}
if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
&&
!BWQueryMarked(w))
BWSetHotSpot(w,
(BW->bitmap.hot.x + 1) % BW->bitmap.image->width,
BW->bitmap.hot.y);
}
void
BWFold(Widget w)
{
BitmapWidget BW = (BitmapWidget) w;
Position x, y, new_x, new_y;
Dimension horiz, vert;
char *storage_data;
XImage *storage;
storage_data = CreateCleanData(Length(BW->bitmap.image->width,
BW->bitmap.image->height));
storage = CreateBitmapImage(BW, storage_data,
(Dimension) BW->bitmap.image->width,
(Dimension) BW->bitmap.image->height);
TransferImageData(BW->bitmap.image, storage);
BW->bitmap.fold ^= True;
horiz = (BW->bitmap.image->width + BW->bitmap.fold) / 2;
vert = (BW->bitmap.image->height + BW->bitmap.fold) / 2;
for (x = 0; x < BW->bitmap.image->width; x++)
for (y = 0; y < BW->bitmap.image->height; y++) {
new_x = (int)(x + horiz) % (int)BW->bitmap.image->width;
new_y = (int)(y + vert) % (int)BW->bitmap.image->height;
if(GetBit(BW->bitmap.image, new_x, new_y) !=
GetBit(storage, x, y))
InvertPoint(BW, new_x, new_y);
}
DestroyBitmapImage(&storage);
if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y))
BWSetHotSpot(w,
(Position)
((int)(BW->bitmap.hot.x+horiz)
%(int)BW->bitmap.image->width),
(Position)
((int)(BW->bitmap.hot.y+vert)
%(int)BW->bitmap.image->height)
);
}
void
BWClear(Widget w)
{
BitmapWidget BW = (BitmapWidget) w;
register Position x, y;
int i, length;
length = Length(BW->bitmap.image->width, BW->bitmap.image->height);
for (x = 0; x < BW->bitmap.image->width; x++)
for (y = 0; y < BW->bitmap.image->height; y++)
if (GetBit(BW->bitmap.image, x, y))
DrawSquare(BW, x, y);
for (i = 0; i < length; i++)
BW->bitmap.image->data[i] = 0;
}
void
BWSet(Widget w)
{
BitmapWidget BW = (BitmapWidget) w;
register Position x, y;
int i, length;
length = Length(BW->bitmap.image->width, BW->bitmap.image->height);
for (x = 0; x < BW->bitmap.image->width; x++)
for (y = 0; y < BW->bitmap.image->height; y++)
if (!GetBit(BW->bitmap.image, x, y))
DrawSquare(BW, x, y);
for (i = 0; i < length; i++)
BW->bitmap.image->data[i] = (char)255;
}
void
BWRedraw(Widget w)
{
BitmapWidget BW = (BitmapWidget) w;
XClearArea(XtDisplay(BW), XtWindow(BW),
0, 0, BW->core.width, BW->core.height,
True);
}
void
BWInvert(Widget w)
{
BitmapWidget BW = (BitmapWidget) w;
int i, length;
length = Length(BW->bitmap.image->width, BW->bitmap.image->height);
XFillRectangle(XtDisplay(BW), XtWindow(BW),
BW->bitmap.drawing_gc,
InWindowX(BW, 0), InWindowY(BW, 0),
InWindowX(BW, BW->bitmap.image->width) - InWindowX(BW, 0),
InWindowY(BW, BW->bitmap.image->height) - InWindowY(BW, 0));
for (i = 0; i < length; i++)
BW->bitmap.image->data[i] ^= 255;
}
void
BWFlipHoriz(Widget w)
{
BitmapWidget BW = (BitmapWidget) w;
register Position x, y;
Position from_x, from_y, to_x, to_y;
float half;
if (BWQueryMarked(w)) {
from_x = BW->bitmap.mark.from_x;
from_y = BW->bitmap.mark.from_y;
to_x = BW->bitmap.mark.to_x;
to_y = BW->bitmap.mark.to_y;
}
else {
from_x = 0;
from_y = 0;
to_x = BW->bitmap.width - 1;
to_y = BW->bitmap.height - 1;
}
half = (float) (to_y - from_y) / 2.0 + 0.5;
if (half == 0.0)
return;
for (x = from_x; x <= to_x; x++)
for (y = 0; y < half; y++)
if (GetBit(BW->bitmap.image, x, from_y + y) !=
GetBit(BW->bitmap.image, x, to_y - y)) {
InvertPoint(BW, x, from_y + y);
InvertPoint(BW, x, to_y - y);
}
if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
&&
!BWQueryMarked(w))
BWSetHotSpot(w,
BW->bitmap.hot.x,
BW->bitmap.image->height - 1 - BW->bitmap.hot.y);
}
void
BWFlipVert(Widget w)
{
BitmapWidget BW = (BitmapWidget) w;
register Position x, y;
Position from_x, from_y, to_x, to_y;
float half;
if (BWQueryMarked(w)) {
from_x = BW->bitmap.mark.from_x;
from_y = BW->bitmap.mark.from_y;
to_x = BW->bitmap.mark.to_x;
to_y = BW->bitmap.mark.to_y;
}
else {
from_x = 0;
from_y = 0;
to_x = BW->bitmap.width - 1;
to_y = BW->bitmap.height - 1;
}
half = (float) (to_x - from_x) / 2.0 + 0.5;
if (half == 0)
return;
for (y = from_y; y <= to_y; y++)
for (x = 0; x < half; x++)
if (GetBit(BW->bitmap.image, from_x + x, y) !=
GetBit(BW->bitmap.image, to_x - x, y)) {
InvertPoint(BW, from_x + x, y);
InvertPoint(BW, to_x - x, y);
}
if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
&&
!BWQueryMarked(w))
BWSetHotSpot(w,
BW->bitmap.image->width - 1 - BW->bitmap.hot.x,
BW->bitmap.hot.y);
}
void
BWRotateRight(Widget w)
{
BitmapWidget BW = (BitmapWidget) w;
Position x, y, delta, shift, tmp;
Position half_width, half_height;
XPoint hot;
bit quad1, quad2, quad3, quad4;
Position from_x, from_y, to_x, to_y;
if (BWQueryMarked(w)) {
from_x = BW->bitmap.mark.from_x;
from_y = BW->bitmap.mark.from_y;
to_x = BW->bitmap.mark.to_x;
to_y = BW->bitmap.mark.to_y;
}
else {
from_x = 0;
from_y = 0;
to_x = BW->bitmap.width - 1;
to_y = BW->bitmap.height - 1;
}
half_width = floor((to_x - from_x) / 2.0 + 0.5);
half_height = floor((to_y - from_y ) / 2.0 + 0.5);
shift = min((Position)(to_x - from_x), (Position)(to_y - from_y )) % 2;
delta = min((Position) half_width, (Position) half_height) - shift;
for (x = 0; x <= delta; x++) {
for (y = 1 - shift; y <= delta; y++) {
quad1 = GetBit(BW->bitmap.image,
from_x + (Position)half_width + x,
from_y + (Position)half_height + y);
quad2 = GetBit(BW->bitmap.image,
from_x + (Position)half_width + y,
from_y + (Position)half_height - shift - x);
quad3 = GetBit(BW->bitmap.image,
from_x + (Position)half_width - shift - x,
from_y + (Position)half_height - shift - y);
quad4 = GetBit(BW->bitmap.image,
from_x + (Position)half_width - shift - y,
from_y + (Position)half_height + x);
if (quad1 != quad2)
InvertPoint(BW,
from_x + (Position)half_width + x,
from_y + (Position)half_height + y);
if (quad2 != quad3)
InvertPoint(BW,
from_x + (Position)half_width + y,
from_y + (Position)half_height - shift - x);
if (quad3 != quad4)
InvertPoint(BW,
from_x + (Position)half_width - shift - x,
from_y + (Position)half_height - shift - y);
if (quad4 != quad1)
InvertPoint(BW,
from_x + (Position)half_width - shift - y,
from_y + (Position)half_height + x);
}
}
if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
&&
!BWQueryMarked(w)) {
hot.x = BW->bitmap.hot.x - half_width;
hot.y = BW->bitmap.hot.y - half_height;
if (hot.x >= 0) hot.x += shift;
if (hot.y >= 0) hot.y += shift;
tmp = hot.x;
hot.x = - hot.y;
hot.y = tmp;
if (hot.x > 0) hot.x -= shift;
if (hot.y > 0) hot.y -= shift;
hot.x += half_width;
hot.y += half_height;
if (QueryInBitmap(BW, hot.x, hot.y))
BWSetHotSpot(w, hot.x, hot.y);
}
}
void
BWRotateLeft(Widget w)
{
BitmapWidget BW = (BitmapWidget) w;
Position x, y,delta, shift, tmp;
Position half_width, half_height;
XPoint hot;
bit quad1, quad2, quad3, quad4;
Position from_x, from_y, to_x, to_y;
if (BWQueryMarked(w)) {
from_x = BW->bitmap.mark.from_x;
from_y = BW->bitmap.mark.from_y;
to_x = BW->bitmap.mark.to_x;
to_y = BW->bitmap.mark.to_y;
}
else {
from_x = 0;
from_y = 0;
to_x = BW->bitmap.width - 1;
to_y = BW->bitmap.height - 1;
}
half_width = floor((to_x - from_x) / 2.0 + 0.5);
half_height = floor((to_y - from_y ) / 2.0 + 0.5);
shift = min((Position)(to_x - from_x), (Position)(to_y - from_y )) % 2;
delta = min((Position) half_width, (Position) half_height) - shift;
for (x = 0; x <= delta; x++) {
for (y = 1 - shift; y <= delta; y++) {
quad1 = GetBit(BW->bitmap.image,
from_x + (Position)half_width + x,
from_y + (Position)half_height + y);
quad2 = GetBit(BW->bitmap.image,
from_x + (Position)half_width + y,
from_y + (Position)half_height - shift - x);
quad3 = GetBit(BW->bitmap.image,
from_x + (Position)half_width - shift - x,
from_y + (Position)half_height - shift - y);
quad4 = GetBit(BW->bitmap.image,
from_x + (Position)half_width - shift - y,
from_y + (Position)half_height + x);
if (quad1 != quad4)
InvertPoint(BW,
from_x + (Position)half_width + x,
from_y + (Position)half_height + y);
if (quad2 != quad1)
InvertPoint(BW,
from_x + (Position)half_width + y,
from_y + (Position)half_height - shift - x);
if (quad3 != quad2)
InvertPoint(BW,
from_x + (Position)half_width - shift - x,
from_y + (Position)half_height - shift - y);
if (quad4 != quad3)
InvertPoint(BW,
from_x + (Position)half_width - shift - y,
from_y + (Position)half_height + x);
}
}
if (QuerySet(BW->bitmap.hot.x, BW->bitmap.hot.y)
&&
!BWQueryMarked(w)) {
hot.x = BW->bitmap.hot.x - half_width;
hot.y = BW->bitmap.hot.y - half_height;
if (hot.x >= 0) hot.x += shift;
if (hot.y >= 0) hot.y += shift;
tmp = hot.x;
hot.x = hot.y;
hot.y = - tmp;
if (hot.x > 0) hot.x -= shift;
if (hot.y > 0) hot.y -= shift;
hot.x += half_width;
hot.y += half_height;
if (QueryInBitmap(BW, hot.x, hot.y))
BWSetHotSpot(w, hot.x, hot.y);
}
}
void
CopyImageData(XImage *source, XImage *destination,
Position from_x, Position from_y,
Position to_x, Position to_y,
Position at_x, Position at_y)
{
Position x, y, delta_x, delta_y;
delta_x = to_x - from_x + 1;
delta_y = to_y - from_y + 1;
for (x = 0; x < delta_x; x++)
for (y = 0; y < delta_y; y++)
if (GetBit(source, from_x + x, from_y + y))
SetBit(destination, at_x + x, at_y + y);
else
ClearBit(destination, at_x + x, at_y + y);
}
XImage *
ConvertToBitmapImage(BitmapWidget BW, XImage *image)
{
XImage *bitmap_image;
char *data;
Position x, y;
data = CreateCleanData(Length(image->width, image->height));
bitmap_image = CreateBitmapImage(BW, data,
(Dimension) image->width,
(Dimension) image->height);
for (x = 0; x < min(image->width, bitmap_image->width); x++)
for (y = 0; y < min(image->height, bitmap_image->height); y++)
if ((XGetPixel(image, x, y) != 0) != GetBit(bitmap_image, x, y))
InvertBit(bitmap_image, x, y);
return bitmap_image;
}
void
TransferImageData(XImage *source, XImage *destination)
{
Position x, y;
for (x = 0; x < min(source->width, destination->width); x++)
for (y = 0; y < min(source->height, destination->height); y++)
if (GetBit(source, x, y) != GetBit(destination, x, y))
InvertBit(destination, x, y);
}
void
BWStore(Widget w)
{
BitmapWidget BW = (BitmapWidget) w;
Dimension width, height;
char *storage_data;
if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y)) {
DestroyBitmapImage(&BW->bitmap.storage);
width = BW->bitmap.mark.to_x - BW->bitmap.mark.from_x + 1;
height = BW->bitmap.mark.to_y - BW->bitmap.mark.from_y + 1;
storage_data = CreateCleanData(Length(width, height));
BW->bitmap.storage = CreateBitmapImage(BW,
storage_data,
width, height);
CopyImageData(BW->bitmap.image, BW->bitmap.storage,
BW->bitmap.mark.from_x, BW->bitmap.mark.from_y,
BW->bitmap.mark.to_x, BW->bitmap.mark.to_y,
0, 0);
}
}
void
BWClearMarked(Widget w)
{
BitmapWidget BW = (BitmapWidget) w;
if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y))
BWDrawFilledRectangle(w,
BW->bitmap.mark.from_x,
BW->bitmap.mark.from_y,
BW->bitmap.mark.to_x,
BW->bitmap.mark.to_y,
Clear);
}
void
BWDragMarked(Widget w, Position at_x, Position at_y)
{
BitmapWidget BW = (BitmapWidget) w;
if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y))
BWDrawRectangle(w,
at_x, at_y,
at_x + BW->bitmap.mark.to_x - BW->bitmap.mark.from_x,
at_y + BW->bitmap.mark.to_y - BW->bitmap.mark.from_y,
Highlight);
}
void
BWDragStored(Widget w, Position at_x, Position at_y)
{
BitmapWidget BW = (BitmapWidget) w;
if (BW->bitmap.storage)
BWDrawRectangle(w,
at_x, at_y,
at_x + BW->bitmap.storage->width - 1,
at_y + BW->bitmap.storage->height - 1,
Highlight);
}
static void
DrawImageData(BitmapWidget BW, XImage *image,
Position at_x, Position at_y, int value)
{
Position x, y;
Boolean C, S, I, H;
bit A, B;
C = value == Clear;
S = value == Set;
I = value == Invert;
H = value == Highlight;
for (x = 0; x < image->width; x++)
for (y = 0; y < image->height; y++) {
A = GetBit(image, x, y);
B = GetBit(BW->bitmap.image, at_x + x, at_y + y);
if ((A & C) | ((A | B) & S) | ((A ^ B) & I) | ((A | B) & H))
value = (A & H) ? Highlight : Set;
else
value = Clear;
BWDrawPoint((Widget) BW,
at_x + x, at_y + y,
value);
}
}
void
BWRestore(Widget w, Position at_x, Position at_y, int value)
{
BitmapWidget BW = (BitmapWidget) w;
if (BW->bitmap.storage) {
DrawImageData(BW, BW->bitmap.storage, at_x, at_y, value);
}
}
void
BWCopy(Widget w, Position at_x, Position at_y, int value)
{
BitmapWidget BW = (BitmapWidget) w;
XImage *storage;
char *storage_data;
Dimension width, height;
if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y)) {
width = BW->bitmap.mark.to_x - BW->bitmap.mark.from_x + 1;
height = BW->bitmap.mark.to_y - BW->bitmap.mark.from_y + 1;
storage_data = CreateCleanData(Length(width, height));
storage = CreateBitmapImage(BW, storage_data, width, height);
CopyImageData(BW->bitmap.image, storage,
BW->bitmap.mark.from_x, BW->bitmap.mark.from_y,
BW->bitmap.mark.to_x, BW->bitmap.mark.to_y,
0, 0);
DrawImageData(BW, storage, at_x, at_y, value);
DestroyBitmapImage(&storage);
}
}
void
BWMove(Widget w, Position at_x, Position at_y, int value)
{
BitmapWidget BW = (BitmapWidget) w;
XImage *storage;
char *storage_data;
Dimension width, height;
if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y)) {
width = BW->bitmap.mark.to_x - BW->bitmap.mark.from_x + 1;
height = BW->bitmap.mark.to_y - BW->bitmap.mark.from_y + 1;
storage_data = CreateCleanData(Length(width, height));
storage = CreateBitmapImage(BW, storage_data, width, height);
CopyImageData(BW->bitmap.image, storage,
BW->bitmap.mark.from_x, BW->bitmap.mark.from_y,
BW->bitmap.mark.to_x, BW->bitmap.mark.to_y,
0, 0);
BWDrawFilledRectangle(w,
BW->bitmap.mark.from_x, BW->bitmap.mark.from_y,
BW->bitmap.mark.to_x, BW->bitmap.mark.to_y,
Clear);
DrawImageData(BW, storage, at_x, at_y, value);
BWMark(w, at_x, at_y,
at_x + BW->bitmap.mark.to_x - BW->bitmap.mark.from_x,
at_y + BW->bitmap.mark.to_y - BW->bitmap.mark.from_y);
DestroyBitmapImage(&storage);
}
}
void
BWRedrawMark(Widget w)
{
BitmapWidget BW = (BitmapWidget) w;
if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y))
XFillRectangle(XtDisplay(BW), XtWindow(BW), BW->bitmap.highlighting_gc,
InWindowX(BW, BW->bitmap.mark.from_x),
InWindowY(BW, BW->bitmap.mark.from_y),
InWindowX(BW, BW->bitmap.mark.to_x + 1) -
InWindowX(BW, BW->bitmap.mark.from_x),
InWindowY(BW, BW->bitmap.mark.to_y + 1) -
InWindowY(BW, BW->bitmap.mark.from_y));
}
void
BWStoreToBuffer(Widget w)
{
BitmapWidget BW = (BitmapWidget) w;
memmove( BW->bitmap.buffer->data, BW->bitmap.image->data,
Length(BW->bitmap.image->width, BW->bitmap.image->height));
BW->bitmap.buffer_hot = BW->bitmap.hot;
BW->bitmap.buffer_mark = BW->bitmap.mark;
}
void
BWUnmark(Widget w)
{
BitmapWidget BW = (BitmapWidget) w;
BW->bitmap.buffer_mark = BW->bitmap.mark;
if (QuerySet(BW->bitmap.mark.from_x, BW->bitmap.mark.from_y)) {
XFillRectangle(XtDisplay(BW), XtWindow(BW), BW->bitmap.highlighting_gc,
InWindowX(BW, BW->bitmap.mark.from_x),
InWindowY(BW, BW->bitmap.mark.from_y),
InWindowX(BW, BW->bitmap.mark.to_x + 1) -
InWindowX(BW, BW->bitmap.mark.from_x),
InWindowY(BW, BW->bitmap.mark.to_y + 1) -
InWindowY(BW, BW->bitmap.mark.from_y));
BW->bitmap.mark.from_x = BW->bitmap.mark.from_y = NotSet;
BW->bitmap.mark.to_x = BW->bitmap.mark.to_y = NotSet;
}
}
void
BWMark(Widget w, Position from_x, Position from_y,
Position to_x, Position to_y)
{
BitmapWidget BW = (BitmapWidget) w;
BWUnmark(w);
if (QuerySet(from_x, from_y)) {
if ((from_x == to_x) && (from_y == to_y)) {
return;
}
else {
QuerySwap(from_x, to_x);
QuerySwap(from_y, to_y);
from_x = max(0, from_x);
from_y = max(0, from_y);
to_x = min(BW->bitmap.image->width - 1, to_x);
to_y = min(BW->bitmap.image->height - 1, to_y);
BW->bitmap.mark.from_x = from_x;
BW->bitmap.mark.from_y = from_y;
BW->bitmap.mark.to_x = to_x;
BW->bitmap.mark.to_y = to_y;
}
XFillRectangle(XtDisplay(BW), XtWindow(BW), BW->bitmap.highlighting_gc,
InWindowX(BW, BW->bitmap.mark.from_x),
InWindowY(BW, BW->bitmap.mark.from_y),
InWindowX(BW, BW->bitmap.mark.to_x + 1) -
InWindowX(BW, BW->bitmap.mark.from_x),
InWindowY(BW, BW->bitmap.mark.to_y +1) -
InWindowY(BW, BW->bitmap.mark.from_y));
}
}
void
BWMarkAll(Widget w)
{
BitmapWidget BW = (BitmapWidget) w;
BWMark(w, 0, 0, BW->bitmap.image->width - 1, BW->bitmap.image->height - 1);
}
void
BWUndo(Widget w)
{
BitmapWidget BW = (BitmapWidget) w;
Position x, y;
char *tmp_data;
XPoint tmp_hot;
BWArea tmp_mark;
tmp_data = BW->bitmap.image->data;
BW->bitmap.image->data = BW->bitmap.buffer->data;
BW->bitmap.buffer->data = tmp_data;
tmp_hot = BW->bitmap.hot;
tmp_mark = BW->bitmap.mark;
for (x = 0; x < BW->bitmap.image->width; x++)
for (y = 0; y < BW->bitmap.image->height; y++)
if (GetBit(BW->bitmap.image, x, y) != GetBit(BW->bitmap.buffer, x, y))
DrawSquare(BW, x, y);
BWSetHotSpot(w, BW->bitmap.buffer_hot.x, BW->bitmap.buffer_hot.y);
BW->bitmap.buffer_hot = tmp_hot;
BW->bitmap.buffer_mark= tmp_mark;
}
void
BWHighlightAxes(Widget w)
{
BitmapWidget BW = (BitmapWidget) w;
XDrawLine(XtDisplay(BW), XtWindow(BW),
BW->bitmap.axes_gc,
InWindowX(BW, 0),
InWindowY(BW, 0),
InWindowX(BW, BW->bitmap.width),
InWindowY(BW, BW->bitmap.height));
XDrawLine(XtDisplay(BW), XtWindow(BW),
BW->bitmap.axes_gc,
InWindowX(BW, BW->bitmap.width),
InWindowY(BW, 0),
InWindowX(BW, 0),
InWindowY(BW, BW->bitmap.height));
XDrawLine(XtDisplay(BW), XtWindow(BW),
BW->bitmap.axes_gc,
InWindowX(BW, 0),
InWindowY(BW, (float)BW->bitmap.height / 2.0),
InWindowX(BW, BW->bitmap.width),
InWindowY(BW, (float)BW->bitmap.height / 2.0));
XDrawLine(XtDisplay(BW), XtWindow(BW),
BW->bitmap.axes_gc,
InWindowX(BW, (float)BW->bitmap.width / 2.0),
InWindowY(BW, 0),
InWindowX(BW, (float)BW->bitmap.width / 2.0),
InWindowY(BW, BW->bitmap.height));
}
typedef struct {
Position *x, *y;
Dimension *width, *height;
} Table;
XImage *
ScaleBitmapImage(BitmapWidget BW, XImage *src,
double scale_x, double scale_y)
{
char *data;
XImage *dst;
Table table;
Position x, y, w, h;
Dimension width, height;
bit pixel;
width = max(rint(scale_x * src->width), 1);
height = max(rint(scale_y * src->height), 1);
data = CreateCleanData(Length(width, height));
dst = CreateBitmapImage(BW, data, width, height);
if (scale_x == 1.0 && scale_y == 1.0)
memmove( dst->data, src->data, Length(width, height));
else {
table.x = (Position *) XtMalloc(sizeof(Position) * src->width);
table.y = (Position *) XtMalloc(sizeof(Position) * src->height);
table.width = (Dimension *) XtMalloc(sizeof(Dimension) * src->width);
table.height = (Dimension *) XtMalloc(sizeof(Dimension) * src->height);
for (x = 0; x < src->width; x++) {
table.x[x] = rint(scale_x * x);
table.width[x] = rint(scale_x * (x + 1)) - rint(scale_x * x);
}
for (y = 0; y < src->height; y++) {
table.y[y] = rint(scale_y * y);
table.height[y] = rint(scale_y * (y + 1)) - rint(scale_y * y);
}
for (x = 0; x < src->width; x++)
for (y = 0; y < src->height; y++) {
pixel = GetBit(src, x, y);
for (w = 0; (int)w < (int)table.width[x]; w++)
for (h = 0; (int)h < (int)table.height[y]; h++)
if (pixel) SetBit(dst,
table.x[x] + w,
table.y[y] + h);
}
XtFree((char *)table.x);
XtFree((char *)table.y);
XtFree((char *)table.width);
XtFree((char *)table.height);
}
return (dst);
}