Android: adding and fixing to the graphics clipping code

Android has no classic window manager, so FLTK has to
make sure that popup windows, dialog boxes and multi
window interfaces work as expectd.



git-svn-id: file:///fltk/svn/fltk/branches/branch-1.4@12729 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
Matthias Melcher
2018-03-10 13:17:41 +00:00
parent 2adaadbd94
commit 5591ba811a
5 changed files with 136 additions and 46 deletions
+9 -6
View File
@@ -52,21 +52,24 @@ public:
Fl_Rect(int X, int Y, int W, int H) Fl_Rect(int X, int Y, int W, int H)
: x_(X), y_(Y), w_(W), h_(H) {} : x_(X), y_(Y), w_(W), h_(H) {}
/** This constructor creates a rectangle based on a widget's position and size. */ /** This constructor creates a rectangle based on a widget's position and size. */
Fl_Rect (const Fl_Widget& widget) Fl_Rect (const Fl_Widget& widget)
: x_(widget.x()), y_(widget.y()), w_(widget.w()), h_(widget.h()) {} : x_(widget.x()), y_(widget.y()), w_(widget.w()), h_(widget.h()) {}
/** This constructor creates a rectangle based on a widget's position and size. */ /** This constructor creates a rectangle based on a widget's position and size. */
Fl_Rect (const Fl_Widget* const widget) Fl_Rect (const Fl_Widget* const widget)
: x_(widget->x()), y_(widget->y()), w_(widget->w()), h_(widget->h()) {} : x_(widget->x()), y_(widget->y()), w_(widget->w()), h_(widget->h()) {}
/** Return 1 if the rectangle is empty, width or height are 0 */ /** Return 1 if the rectangle is empty, width or height are 0 */
int is_empty() { return (w_==0)||(h_==0); } int is_empty() { return (w_<=0)||(h_<=0); }
/** Set the position and size */ /** Set the position and size */
void set(int x, int y, int w, int h) { x_=x; y_=y; w_=w; h_=h; } void set(int x, int y, int w, int h) { x_=x; y_=y; w_=w; h_=h; }
/** return 0 if the rectangles are different, or 1 if they are the same */ /** Clone another rectangle */
void set(Fl_Rect *r) { x_=r->x_; y_=r->y_; w_=r->w_; h_=r->h_; }
/** return 0 if the rectangles are different, or 1 if they are the same */
int equals(int x, int y, int w, int h) { return ( (x_==x) && (y_==y) && (w_==w) && (h_==h) ); } int equals(int x, int y, int w, int h) { return ( (x_==x) && (y_==y) && (w_==w) && (h_==h) ); }
/** Set the position and size to zero, making this rect empty */ /** Set the position and size to zero, making this rect empty */
+5 -2
View File
@@ -114,8 +114,11 @@ struct dirent {char d_name[1];};
#elif defined(__ANDROID__) #elif defined(__ANDROID__)
// see: src/driver/Android/Fl_Android_Graphics_Driver_region.cxx #ifdef __cplusplus
typedef struct Fl_Clip_Rect *Fl_Region; typedef class Fl_Rect_Region *Fl_Region;
#else
typedef struct Fl_Rect_Region *Fl_Region;
#endif
// TODO: the types below have not yet been ported // TODO: the types below have not yet been ported
typedef unsigned long Fl_Offscreen; typedef unsigned long Fl_Offscreen;
@@ -30,18 +30,61 @@
#include <limits.h> #include <limits.h>
struct Fl_Clip_Rect /**
* The Fl_Rect_Region is based on Fl_Rect with additional functionality for clipping.
*/
class Fl_Rect_Region : public Fl_Rect
{ {
Fl_Clip_Rect() : pRect() {} public:
Fl_Clip_Rect(int x, int y, int w, int h) : pRect(x, y, w, h) {} enum {
int x() { return pRect.x(); } EMPTY = 0, SAME, LESS, MORE
int y() { return pRect.y(); } };
int w() { return pRect.w(); }
int h() { return pRect.h(); } /**
int intersect_with(Fl_Clip_Rect *r); * Create an empty clipping region.
*/
Fl_Rect_Region() {}
/**
* Create a clipping region based on position and size.
* @param x, y position
* @param w, h size
*/
Fl_Rect_Region(int x, int y, int w, int h) : Fl_Rect(x, y, w, h) {}
int intersect_with(Fl_Rect_Region *r);
static int min(int a, int b) { return (a<b) ? a : b; } static int min(int a, int b) { return (a<b) ? a : b; }
static int max(int a, int b) { return (a>b) ? a : b; } static int max(int a, int b) { return (a>b) ? a : b; }
Fl_Rect pRect; };
/**
* The Fl_Complex_Region represents a clipping region of any shape.
*
* This class is organized in a tree-like structure. If the region is
* rectangular, is_simple() returns 1 and the rectangle can be used just
* as in Fl_Rect_Region.
*
* If a more complex representation is needed, the first list of
* subregions is organizen in horizontal strips. The root region rect
* will contain the outline of all subregions, and the subregions
* will either be simple rectangles, or they will contain a second
* level of subregions, subdividing the horizontal region into vertical
* columns.
*
* When reading, the tree can be easily walked using recursion.
*/
class Fl_Complex_Region : public Fl_Rect_Region
{
public:
Fl_Complex_Region() : Fl_Rect_Region(), pSubregion(0L), pNext(0L) { }
Fl_Complex_Region(int x, int y, int w, int h) : Fl_Rect_Region(x, y, w, h), pSubregion(0L), pNext(0L) { }
~Fl_Complex_Region();
void set(Fl_Rect *rect);
char is_simple() { return pSubregion==0; }
char is_complex() { return pSubregion!=0; }
protected:
Fl_Complex_Region *pSubregion;
Fl_Complex_Region *pNext;
}; };
@@ -144,7 +187,7 @@ protected:
void restore_clip(); void restore_clip();
void clip_region(Fl_Region r); void clip_region(Fl_Region r);
Fl_Region clip_region(); Fl_Region clip_region();
static Fl_Clip_Rect pClipRect; static Fl_Complex_Region pWindowRegion;
#if 0 #if 0
virtual Fl_Region scale_clip(float f); virtual Fl_Region scale_clip(float f);
// --- implementation is in src/fl_vertex.cxx which includes src/cfg_gfx/xxx_rect.cxx // --- implementation is in src/fl_vertex.cxx which includes src/cfg_gfx/xxx_rect.cxx
@@ -55,10 +55,32 @@ static uint16_t make565(Fl_Color crgba)
void Fl_Android_Graphics_Driver::rectf_unscaled(float x, float y, float w, float h) { void Fl_Android_Graphics_Driver::rectf_unscaled(float x, float y, float w, float h) {
Fl_Android_Application::log_w("rectf %g %g %g %g", x, y, w, h); Fl_Android_Application::log_w("rectf %g %g %g %g", x, y, w, h);
Fl_Clip_Rect r(x, y, w, h); Fl_Rect_Region r(x, y, w, h);
if (r.intersect_with(&pClipRect)) { if (r.intersect_with(&pWindowRegion)) {
rectf_unclipped(r.x(), r.y(), r.w(), r.h()); rectf_unclipped(r.x(), r.y(), r.w(), r.h());
} }
/*
* rectf(x, y, w, h) {
* rectf(complex_window_region, drawing_rect(x, y, w, h))
* }
*
* rectf( complexRgn, drawRgn) {
* // B: start of iterator
* if (intersect(rect_of_complexRgn, drawRgn) {
* if (complexRgn->is_complex() {
* rectf(complexRgn->subregion, drawRect);
* } else {
* rawRect = intersection(rect_of_complexRgn, drawRgn);
* rawDrawRect(rawRect);
* }
* }
* // A: recursion
* if (complexRgn->next)
* rectf(complexRgn->next, drawRgn);
* // B: end of iterator
* }
*/
} }
void Fl_Android_Graphics_Driver::rectf_unclipped(float x, float y, float w, float h) { void Fl_Android_Graphics_Driver::rectf_unclipped(float x, float y, float w, float h) {
@@ -23,38 +23,56 @@
#include <FL/platform.H> #include <FL/platform.H>
Fl_Clip_Rect Fl_Android_Graphics_Driver::pClipRect; Fl_Complex_Region Fl_Android_Graphics_Driver::pWindowRegion;
// return 0 for empty, 1 for same, 2 if intersecting // return 0 for empty, 1 for same, 2 if intersecting
int Fl_Clip_Rect::intersect_with(Fl_Clip_Rect *a) int Fl_Rect_Region::intersect_with(Fl_Rect_Region *a)
{ {
if (pRect.is_empty()) { if (is_empty()) {
return 0; return EMPTY;
} }
if (a->pRect.is_empty()) { if (a->is_empty()) {
pRect.clear(); clear();
return 0; return EMPTY;
} }
int x = max(pRect.x(), a->pRect.x()); int lx = max(x(), a->x());
int y = max(pRect.y(), a->pRect.y()); int ly = max(y(), a->y());
int r = min(pRect.r(), a->pRect.r()); int lr = min(r(), a->r());
int b = min(pRect.b(), a->pRect.b()); int lb = min(b(), a->b());
int w = r-x; int lw = lr-lx;
int h = b-y; int lh = lb-ly;
if (pRect.equals(x, y, w, h)) { if (equals(lx, ly, lw, lh)) {
return 1; return SAME;
} }
pRect.set(x, y, w, h); set(lx, ly, lw, lh);
if ( (pRect.w()<=0) || (pRect.h()<=0) ) { if ( (w()<=0) || (h()<=0) ) {
pRect.clear(); clear();
return 0; return EMPTY;
} }
return 2; return LESS;
} }
Fl_Complex_Region::~Fl_Complex_Region()
{
delete pSubregion; // recursively delete all subregions
delete pNext; // recursively delete all following regions
}
void Fl_Complex_Region::set(Fl_Rect *rect)
{
delete pSubregion;
pSubregion = 0L;
delete pNext;
pNext = 0L;
Fl_Rect_Region::set(rect);
}
void Fl_Android_Graphics_Driver::clip_region(Fl_Region r) void Fl_Android_Graphics_Driver::clip_region(Fl_Region r)
{ {
Fl_Region oldr = rstack[rstackptr]; Fl_Region oldr = rstack[rstackptr];
@@ -73,27 +91,28 @@ void Fl_Android_Graphics_Driver::restore_clip()
{ {
fl_clip_state_number++; fl_clip_state_number++;
Fl_Window *win = Fl_Window::current(); Fl_Window *win = Fl_Window::current();
Fl_Clip_Rect a(0, 0, win->w(), win->h()); Fl_Rect_Region a(0, 0, win->w(), win->h());
Fl_Region b = rstack[rstackptr]; Fl_Region b = rstack[rstackptr];
if (b) { if (b) {
// FIXME: scaling! // FIXME: scaling!
a.intersect_with(b); a.intersect_with(b);
} }
pClipRect = a; pWindowRegion.set(b);
// FIXME: intersect with complex window region
} }
void Fl_Android_Graphics_Driver::push_clip(int x, int y, int w, int h) void Fl_Android_Graphics_Driver::push_clip(int x, int y, int w, int h)
{ {
Fl_Region r; Fl_Region r;
if (w > 0 && h > 0) { if (w > 0 && h > 0) {
r = new Fl_Clip_Rect(x,y,w,h); r = new Fl_Rect_Region(x,y,w,h);
Fl_Region current = rstack[rstackptr]; Fl_Region current = rstack[rstackptr];
if (current) { if (current) {
r->intersect_with(current); r->intersect_with(current);
} }
} else { // make empty clip region: } else { // make empty clip region:
r = new Fl_Clip_Rect(); r = new Fl_Rect_Region();
} }
if (rstackptr < region_stack_max) rstack[++rstackptr] = r; if (rstackptr < region_stack_max) rstack[++rstackptr] = r;
else Fl::warning("Fl_Android_Graphics_Driver::push_clip: clip stack overflow!\n"); else Fl::warning("Fl_Android_Graphics_Driver::push_clip: clip stack overflow!\n");
@@ -136,7 +155,7 @@ int Fl_Android_Graphics_Driver::clip_box(int x, int y, int w, int h, int& X, int
return 0; return 0;
} }
Fl_Clip_Rect a(x, y, w, h); Fl_Rect_Region a(x, y, w, h);
int ret = a.intersect_with(r); // return 0 for empty, 1 for same, 2 if intersecting int ret = a.intersect_with(r); // return 0 for empty, 1 for same, 2 if intersecting
X = a.x(); X = a.x();
Y = a.y(); Y = a.y();
@@ -161,7 +180,7 @@ int Fl_Android_Graphics_Driver::not_clipped(int x, int y, int w, int h) {
Fl_Region r = rstack[rstackptr]; Fl_Region r = rstack[rstackptr];
if (!r) return 1; if (!r) return 1;
Fl_Clip_Rect a(x, y, w, h); // return 0 for empty, 1 for same, 2 if intersecting Fl_Rect_Region a(x, y, w, h); // return 0 for empty, 1 for same, 2 if intersecting
return a.intersect_with(r); return a.intersect_with(r);
} }