#include <config.h>
#include <FL/Fl.H>
#include <FL/Fl_Widget.H>
#include <FL/fl_draw.H>
#include <FL/platform.H>
#include "Fl_Xlib_Graphics_Driver.H"
int Fl_Xlib_Graphics_Driver::clip_line(int &x1, int &y1, int &x2, int &y2) {
float p1 = float(-(x2 - x1));
float p2 = float(-p1);
float p3 = float(-(y2 - y1));
float p4 = float(-p3);
float q1 = float(x1 - clip_min());
float q2 = float(clip_max() - x1);
float q3 = float(y1 - clip_min());
float q4 = float(clip_max() - y1);
float posmin = 1; float negmax = 0;
if ((p1 == 0 && q1 < 0) || (p3 == 0 && q3 < 0)) {
return 1; }
if (p1 != 0) {
float r1 = q1 / p1;
float r2 = q2 / p2;
if (p1 < 0) {
if (r1 > negmax) negmax = r1;
if (r2 < posmin) posmin = r2;
} else {
if (r2 > negmax) negmax = r2;
if (r1 < posmin) posmin = r1;
}
}
if (p3 != 0) {
float r3 = q3 / p3;
float r4 = q4 / p4;
if (p3 < 0) {
if (r3 > negmax) negmax = r3;
if (r4 < posmin) posmin = r4;
} else {
if (r4 > negmax) negmax = r4;
if (r3 < posmin) posmin = r3;
}
}
if (negmax > posmin) return 1;
x2 = int(x1 + p2 * posmin);
y2 = int(y1 + p4 * posmin);
x1 = int(x1 + p2 * negmax);
y1 = int(y1 + p4 * negmax);
return 0;
}
int Fl_Xlib_Graphics_Driver::clip_rect(int &x, int &y, int &w, int &h) {
if (w <= 0 || h <= 0) return 1; if (x+w < clip_min() || y+h < clip_min()) return 1; if (x > clip_max() || y > clip_max()) return 1;
if (x < clip_min()) { w -= (clip_min()-x); x = clip_min(); }
if (y < clip_min()) { h -= (clip_min()-y); y = clip_min(); }
if (x+w > clip_max()) w = clip_max() - x;
if (y+h > clip_max()) h = clip_max() - y;
return 0;
}
Fl_Region Fl_Xlib_Graphics_Driver::XRectangleRegion(int x, int y, int w, int h) {
XRectangle R;
Region r = XCreateRegion(); if (clip_rect(x, y, w, h)) return r; R.x = x; R.y = y; R.width = w; R.height = h;
XUnionRectWithRegion(&R, r, r);
return r;
}
void Fl_Xlib_Graphics_Driver::XDestroyRegion(Fl_Region r) {
::XDestroyRegion((Region)r);
}
void Fl_Xlib_Graphics_Driver::focus_rect(int x, int y, int w, int h) {
w = this->floor(x + w) - this->floor(x);
h = this->floor(y + h) - this->floor(y);
x = this->floor(x) + floor(offset_x_);
y = this->floor(y) + floor(offset_y_);
if (!clip_rect(x, y, w, h)) {
int lw_save = line_width_; if (line_width_ == 0)
line_style(FL_DOT, 1);
else
line_style(FL_DOT);
XDrawRectangle(fl_display, fl_window, gc_, x, y, w, h);
if (lw_save == 0)
line_style(FL_SOLID, 0); else
line_style(FL_SOLID);
}
}
void Fl_Xlib_Graphics_Driver::rect_unscaled(int x, int y, int w, int h) {
void *old = NULL;
if (line_width_ == 0) old = change_pen_width(1); XDrawRectangle(fl_display, fl_window, gc_, x, y, w, h);
if (old) reset_pen_width(old);
}
void Fl_Xlib_Graphics_Driver::rectf_unscaled(int x, int y, int w, int h) {
x += floor(offset_x_);
y += floor(offset_y_);
if (!clip_rect(x, y, w, h))
XFillRectangle(fl_display, fl_window, gc_, x, y, w, h);
}
void Fl_Xlib_Graphics_Driver::line_unscaled(int x, int y, int x1, int y1) {
draw_clipped_line(x + this->floor(offset_x_) , y + this->floor(offset_y_) ,
x1 + this->floor(offset_x_) , y1 + this->floor(offset_y_) );
}
void Fl_Xlib_Graphics_Driver::line_unscaled(int x, int y, int x1, int y1, int x2, int y2) {
if (!clip_line(x1, y1, x, y) && !clip_line(x1, y1, x2, y2)) {
XPoint p[3];
int x_offset = floor(offset_x_);
int y_offset = floor(offset_y_);
p[0].x = x + x_offset; p[0].y = y + y_offset;
p[1].x = x1 + x_offset; p[1].y = y1 + y_offset;
p[2].x = x2 + x_offset; p[2].y = y2 + y_offset;
XDrawLines(fl_display, fl_window, gc_, p, 3, 0);
}
}
void Fl_Xlib_Graphics_Driver::xyline_unscaled(int x, int y, int x1) {
if (line_width_ >= 2) x1++;
x += floor(offset_x_) ;
y += floor(offset_y_) ;
x1 += floor(offset_x_) ;
draw_clipped_line(x, y, x1, y);
}
void Fl_Xlib_Graphics_Driver::yxline_unscaled(int x, int y, int y1) {
if (line_width_ >= 2) y1++;
x += floor(offset_x_) ;
y += floor(offset_y_) ;
y1 += floor(offset_y_) ;
draw_clipped_line(x, y, x, y1);
}
void Fl_Xlib_Graphics_Driver::loop_unscaled(int x, int y, int x1, int y1, int x2, int y2) {
XPoint p[4];
p[0].x = x + floor(offset_x_) ; p[0].y = y + floor(offset_y_) ;
p[1].x = x1 + floor(offset_x_) ; p[1].y = y1 + floor(offset_y_) ;
p[2].x = x2 + floor(offset_x_) ; p[2].y = y2 + floor(offset_y_) ;
p[3].x = p[0].x; p[3].y = p[0].y;
XDrawLines(fl_display, fl_window, gc_, p, 4, 0);
}
void Fl_Xlib_Graphics_Driver::loop_unscaled(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) {
XPoint p[5];
p[0].x = x + floor(offset_x_) ; p[0].y = y + floor(offset_y_) ;
p[1].x = x1 + floor(offset_x_) ; p[1].y = y1 + floor(offset_y_) ;
p[2].x = x2 + floor(offset_x_) ; p[2].y = y2 + floor(offset_y_) ;
p[3].x = x3 + floor(offset_x_) ; p[3].y = y3 + floor(offset_y_) ;
p[4].x = p[0].x; p[4].y = p[0].y;
XDrawLines(fl_display, fl_window, gc_, p, 5, 0);
}
void Fl_Xlib_Graphics_Driver::polygon_unscaled(int x, int y, int x1, int y1, int x2, int y2) {
XPoint p[4];
p[0].x = x + floor(offset_x_) ; p[0].y = y + floor(offset_y_) ;
p[1].x = x1 + floor(offset_x_) ; p[1].y = y1 + floor(offset_y_) ;
p[2].x = x2 + floor(offset_x_) ; p[2].y = y2 + floor(offset_y_) ;
p[3].x = p[0].x; p[3].y = p[0].y;
XFillPolygon(fl_display, fl_window, gc_, p, 3, Convex, 0);
XDrawLines(fl_display, fl_window, gc_, p, 4, 0);
}
void Fl_Xlib_Graphics_Driver::polygon_unscaled(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) {
XPoint p[5];
p[0].x = x + floor(offset_x_) ; p[0].y = y + floor(offset_y_) ;
p[1].x = x1 + floor(offset_x_) ; p[1].y = y1 + floor(offset_y_) ;
p[2].x = x2 + floor(offset_x_) ; p[2].y = y2 + floor(offset_y_) ;
p[3].x = x3 + floor(offset_x_) ; p[3].y = y3 + floor(offset_y_) ;
p[4].x = p[0].x; p[4].y = p[0].y;
XFillPolygon(fl_display, fl_window, gc_, p, 4, Convex, 0);
XDrawLines(fl_display, fl_window, gc_, p, 5, 0);
}
void Fl_Xlib_Graphics_Driver::draw_clipped_line(int x1, int y1, int x2, int y2) {
if (!clip_line(x1, y1, x2, y2))
XDrawLine(fl_display, fl_window, gc_, x1, y1, x2, y2);
}
void Fl_Xlib_Graphics_Driver::push_clip(int x, int y, int w, int h) {
Region r;
if (w > 0 && h > 0) {
r = (Region)XRectangleRegion(x, y, w, h); Region current = (Region)rstack[rstackptr];
if (current) {
Region temp = XCreateRegion();
XIntersectRegion(current, r, temp);
XDestroyRegion(r);
r = temp;
}
} else { r = XCreateRegion();
}
if (rstackptr < region_stack_max) rstack[++rstackptr] = r;
else Fl::warning("Fl_Xlib_Graphics_Driver::push_clip: clip stack overflow!\n");
restore_clip();
}
int Fl_Xlib_Graphics_Driver::clip_box(int x, int y, int w, int h, int& X, int& Y, int& W, int& H) {
X = x; Y = y; W = w; H = h;
if (clip_rect(X, Y, W, H)) { W = H = 0;
return 2;
}
Region r = (Region)rstack[rstackptr];
if (!r) { if (X != x || Y != y || W != w || H != h) return 1; return 0;
}
switch (XRectInRegion(r, X, Y, W, H)) {
case 0: W = H = 0;
return 2;
case 1: return 0;
default: break;
}
Region rr = (Region)XRectangleRegion(X, Y, W, H);
Region temp = XCreateRegion();
XIntersectRegion(r, rr, temp);
XRectangle rect;
XClipBox(temp, &rect);
X = rect.x; Y = rect.y; W = rect.width; H = rect.height;
XDestroyRegion(temp);
XDestroyRegion(rr);
return 1;
}
int Fl_Xlib_Graphics_Driver::not_clipped(int x, int y, int w, int h) {
if (x+w <= 0 || y+h <= 0) return 0;
Region r = (Region)rstack[rstackptr];
if (!r) return 1;
if (clip_rect(x,y,w,h)) return 0; return XRectInRegion(r, x, y, w, h);
}
void Fl_Xlib_Graphics_Driver::restore_clip() {
fl_clip_state_number++;
if (gc_) {
Region r = (Region)rstack[rstackptr];
if (r) {
Region r2 = (Region)scale_clip(scale());
XSetRegion(fl_display, gc_, (Region)rstack[rstackptr]);
unscale_clip(r2);
}
else XSetClipMask(fl_display, gc_, 0);
}
}