more ketmar patches

This commit is contained in:
Adam D. Ruppe 2018-02-28 23:11:50 -05:00
parent a1c57fa9eb
commit 6ed8ab8a4f
2 changed files with 88 additions and 39 deletions

View File

@ -2035,7 +2035,7 @@ public:
// Call delegate [dg] for each path under the specified position (in no particular order). // Call delegate [dg] for each path under the specified position (in no particular order).
// Returns the id of the path for which delegate [dg] returned true or -1. // Returns the id of the path for which delegate [dg] returned true or -1.
// dg is: `bool delegate (int id, int order)` -- [order] is path ordering (ascending). // dg is: `bool delegate (int id, int order)` -- [order] is path ordering (ascending).
int hitTestDG(DG) (in float x, in float y, uint kind, scope DG dg) if (IsGoodHitTestDG!DG || IsGoodHitTestInternalDG!DG) { int hitTestDG(bool bestOrder=false, DG) (in float x, in float y, NVGPickKind kind, scope DG dg) if (IsGoodHitTestDG!DG || IsGoodHitTestInternalDG!DG) {
if (pickscene is null) return -1; if (pickscene is null) return -1;
NVGpickScene* ps = pickscene; NVGpickScene* ps = pickscene;
@ -2079,13 +2079,13 @@ public:
// Fills ids with a list of the top most hit ids under the specified position. // Fills ids with a list of the top most hit ids under the specified position.
// Returns the slice of [ids]. // Returns the slice of [ids].
int[] hitTestAll (in float x, in float y, uint kind, int[] ids) nothrow @trusted @nogc { int[] hitTestAll (in float x, in float y, NVGPickKind kind, int[] ids) nothrow @trusted @nogc {
if (pickscene is null || ids.length == 0) return ids[0..0]; if (pickscene is null || ids.length == 0) return ids[0..0];
int npicked = 0; int npicked = 0;
NVGpickScene* ps = pickscene; NVGpickScene* ps = pickscene;
hitTestDG(x, y, kind, delegate (NVGpickPath* pp) nothrow @trusted @nogc { hitTestDG!false(x, y, kind, delegate (NVGpickPath* pp) nothrow @trusted @nogc {
if (npicked == ps.cpicked) { if (npicked == ps.cpicked) {
int cpicked = ps.cpicked+ps.cpicked; int cpicked = ps.cpicked+ps.cpicked;
NVGpickPath** picked = cast(NVGpickPath**)realloc(ps.picked, (NVGpickPath*).sizeof*ps.cpicked); NVGpickPath** picked = cast(NVGpickPath**)realloc(ps.picked, (NVGpickPath*).sizeof*ps.cpicked);
@ -2108,13 +2108,13 @@ public:
} }
// Returns the id of the pickable shape containing x,y or -1 if no shape was found. // Returns the id of the pickable shape containing x,y or -1 if no shape was found.
int hitTest (in float x, in float y, uint kind) nothrow @trusted @nogc { int hitTest (in float x, in float y, NVGPickKind kind) nothrow @trusted @nogc {
if (pickscene is null) return -1; if (pickscene is null) return -1;
int bestOrder = -1; int bestOrder = -1;
int bestID = -1; int bestID = -1;
hitTestDG(x, y, kind, delegate (NVGpickPath* pp) nothrow @trusted @nogc { hitTestDG!true(x, y, kind, delegate (NVGpickPath* pp) nothrow @trusted @nogc {
if (pp.order > bestOrder) { if (pp.order > bestOrder) {
bestOrder = pp.order; bestOrder = pp.order;
bestID = pp.id; bestID = pp.id;
@ -5267,11 +5267,11 @@ private template IsGoodHitTestInternalDG(DG) {
} }
/// Call delegate [dg] for each path under the specified position (in no particular order). /// Call delegate [dg] for each path under the specified position (in no particular order).
/// Returns the id of the path for which delegate [dg] returned true or -1. /// Returns the id of the path for which delegate [dg] returned true or [NVGNoPick].
/// dg is: `bool delegate (int id, int order)` -- [order] is path ordering (ascending). /// dg is: `bool delegate (int id, int order)` -- [order] is path ordering (ascending).
/// Group: picking_api /// Group: picking_api
public int hitTestDG(DG) (NVGContext ctx, in float x, in float y, uint kind, scope DG dg) if (IsGoodHitTestDG!DG || IsGoodHitTestInternalDG!DG) { public int hitTestDG(bool bestOrder=false, DG) (NVGContext ctx, in float x, in float y, NVGPickKind kind, scope DG dg) if (IsGoodHitTestDG!DG || IsGoodHitTestInternalDG!DG) {
if (ctx.pickScene is null || ctx.pickScene.npaths == 0) return -1; if (ctx.pickScene is null || ctx.pickScene.npaths == 0 || (kind&NVGPickKind.All) == 0) return -1;
NVGpickScene* ps = ctx.pickScene; NVGpickScene* ps = ctx.pickScene;
int levelwidth = 1<<(ps.nlevels-1); int levelwidth = 1<<(ps.nlevels-1);
@ -5279,18 +5279,31 @@ public int hitTestDG(DG) (NVGContext ctx, in float x, in float y, uint kind, sco
int celly = nvg__clamp(cast(int)(y/ps.ydim), 0, levelwidth); int celly = nvg__clamp(cast(int)(y/ps.ydim), 0, levelwidth);
int npicked = 0; int npicked = 0;
// if we are interested only in most-toplevel path, there is no reason to check pathes with worser order.
// but we cannot just get out on the first path found, 'cause we are using quad tree to speed up bounds
// checking, so path walking order is not guaranteed.
static if (bestOrder) {
int lastBestOrder = int.min;
}
//{ import core.stdc.stdio; printf("npaths=%d\n", ps.npaths); } //{ import core.stdc.stdio; printf("npaths=%d\n", ps.npaths); }
for (int lvl = ps.nlevels-1; lvl >= 0; --lvl) { for (int lvl = ps.nlevels-1; lvl >= 0; --lvl) {
NVGpickPath* pp = ps.levels[lvl][celly*levelwidth+cellx]; for (NVGpickPath* pp = ps.levels[lvl][celly*levelwidth+cellx]; pp !is null; pp = pp.next) {
while (pp !is null) { //{ import core.stdc.stdio; printf("... pos=(%g,%g); bounds=(%g,%g)-(%g,%g); flags=0x%02x; kind=0x%02x; kpx=0x%02x\n", x, y, pp.bounds[0], pp.bounds[1], pp.bounds[2], pp.bounds[3], pp.flags, kind, kind&pp.flags&3); }
//{ import core.stdc.stdio; printf("... pos=(%g,%g); bounds=(%g,%g)-(%g,%g); flags=0x%02x; kind=0x%02x\n", x, y, pp.bounds[0], pp.bounds[1], pp.bounds[2], pp.bounds[3], pp.flags, kind); } static if (bestOrder) {
if (nvg__pickPathTestBounds(ctx, ps, pp, x, y)) { // reject earlier paths
if (pp.order <= lastBestOrder) continue; // not interesting
}
immutable uint kpx = kind&pp.flags&3;
if (kpx == 0) continue; // not interesting
if (!nvg__pickPathTestBounds(ctx, ps, pp, x, y)) continue; // not interesting
//{ import core.stdc.stdio; printf("in bounds!\n"); } //{ import core.stdc.stdio; printf("in bounds!\n"); }
int hit = 0; int hit = 0;
if ((kind&NVGPickKind.Stroke) && (pp.flags&NVGPathFlags.Stroke)) hit = nvg__pickPathStroke(ps, pp, x, y); if (kpx&NVGPickKind.Stroke) hit = nvg__pickPathStroke(ps, pp, x, y);
if (!hit && (kind&NVGPickKind.Fill) && (pp.flags&NVGPathFlags.Fill)) hit = nvg__pickPath(ps, pp, x, y); if (!hit && (kpx&NVGPickKind.Fill)) hit = nvg__pickPath(ps, pp, x, y);
if (hit) { if (!hit) continue;
//{ import core.stdc.stdio; printf(" HIT!\n"); } //{ import core.stdc.stdio; printf(" HIT!\n"); }
static if (bestOrder) lastBestOrder = pp.order;
static if (IsGoodHitTestDG!DG) { static if (IsGoodHitTestDG!DG) {
static if (__traits(compiles, (){ DG dg; bool res = dg(cast(int)42, cast(int)666); })) { static if (__traits(compiles, (){ DG dg; bool res = dg(cast(int)42, cast(int)666); })) {
if (dg(pp.id, cast(int)pp.order)) return pp.id; if (dg(pp.id, cast(int)pp.order)) return pp.id;
@ -5305,9 +5318,6 @@ public int hitTestDG(DG) (NVGContext ctx, in float x, in float y, uint kind, sco
} }
} }
} }
}
pp = pp.next;
}
cellx >>= 1; cellx >>= 1;
celly >>= 1; celly >>= 1;
levelwidth >>= 1; levelwidth >>= 1;
@ -5316,16 +5326,16 @@ public int hitTestDG(DG) (NVGContext ctx, in float x, in float y, uint kind, sco
return -1; return -1;
} }
/// Fills ids with a list of the top most hit ids under the specified position. /// Fills ids with a list of the top most hit ids (from bottom to top) under the specified position.
/// Returns the slice of [ids]. /// Returns the slice of [ids].
/// Group: picking_api /// Group: picking_api
public int[] hitTestAll (NVGContext ctx, in float x, in float y, uint kind, int[] ids) nothrow @trusted @nogc { public int[] hitTestAll (NVGContext ctx, in float x, in float y, NVGPickKind kind, int[] ids) nothrow @trusted @nogc {
if (ctx.pickScene is null || ids.length == 0) return ids[0..0]; if (ctx.pickScene is null || ids.length == 0) return ids[0..0];
int npicked = 0; int npicked = 0;
NVGpickScene* ps = ctx.pickScene; NVGpickScene* ps = ctx.pickScene;
ctx.hitTestDG(x, y, kind, delegate (NVGpickPath* pp) nothrow @trusted @nogc { ctx.hitTestDG!false(x, y, kind, delegate (NVGpickPath* pp) nothrow @trusted @nogc {
if (npicked == ps.cpicked) { if (npicked == ps.cpicked) {
int cpicked = ps.cpicked+ps.cpicked; int cpicked = ps.cpicked+ps.cpicked;
NVGpickPath** picked = cast(NVGpickPath**)realloc(ps.picked, (NVGpickPath*).sizeof*ps.cpicked); NVGpickPath** picked = cast(NVGpickPath**)realloc(ps.picked, (NVGpickPath*).sizeof*ps.cpicked);
@ -5347,15 +5357,15 @@ public int[] hitTestAll (NVGContext ctx, in float x, in float y, uint kind, int[
return ids[0..npicked]; return ids[0..npicked];
} }
/// Returns the id of the pickable shape containing x,y or -1 if no shape was found. /// Returns the id of the pickable shape containing x,y or [NVGNoPick] if no shape was found.
/// Group: picking_api /// Group: picking_api
public int hitTest (NVGContext ctx, in float x, in float y, uint kind) nothrow @trusted @nogc { public int hitTest (NVGContext ctx, in float x, in float y, NVGPickKind kind=NVGPickKind.All) nothrow @trusted @nogc {
if (ctx.pickScene is null) return -1; if (ctx.pickScene is null) return -1;
int bestOrder = -1; int bestOrder = int.min;
int bestID = -1; int bestID = -1;
ctx.hitTestDG(x, y, kind, delegate (NVGpickPath* pp) { ctx.hitTestDG!true(x, y, kind, delegate (NVGpickPath* pp) {
if (pp.order > bestOrder) { if (pp.order > bestOrder) {
bestOrder = pp.order; bestOrder = pp.order;
bestID = pp.id; bestID = pp.id;
@ -5422,10 +5432,10 @@ enum NVGSegmentFlags {
} }
// Path flags // Path flags
enum NVGPathFlags { enum NVGPathFlags : ushort {
Scissor = 1, Fill = NVGPickKind.Fill,
Stroke = 2, Stroke = NVGPickKind.Stroke,
Fill = 4, Scissor = 0x80,
} }
struct NVGsegment { struct NVGsegment {
@ -5674,7 +5684,7 @@ void nvg__pickSubPathAddStrokeSupports (NVGpickScene* ps, NVGpickSubPath* psp, f
supportingPoints.ptr[ns++] = points[lastPoint]+seg.endDir.ptr[1]*strokeWidth; supportingPoints.ptr[ns++] = points[lastPoint]+seg.endDir.ptr[1]*strokeWidth;
supportingPoints.ptr[ns++] = points[lastPoint+1]-seg.endDir.ptr[0]*strokeWidth; supportingPoints.ptr[ns++] = points[lastPoint+1]-seg.endDir.ptr[0]*strokeWidth;
if (seg.flags&NVGSegmentFlags.Corner && prevseg !is null) { if ((seg.flags&NVGSegmentFlags.Corner) && prevseg !is null) {
seg.miterDir.ptr[0] = 0.5f*(-prevseg.endDir.ptr[1]-seg.startDir.ptr[1]); seg.miterDir.ptr[0] = 0.5f*(-prevseg.endDir.ptr[1]-seg.startDir.ptr[1]);
seg.miterDir.ptr[1] = 0.5f*(prevseg.endDir.ptr[0]+seg.startDir.ptr[0]); seg.miterDir.ptr[1] = 0.5f*(prevseg.endDir.ptr[0]+seg.startDir.ptr[0]);
@ -9464,8 +9474,8 @@ public int fonsAddFont (FONScontext* stash, const(char)[] name, const(char)[] pa
} }
} }
version(Windows) { version(Windows) {
// special shitdows check // special shitdows check: this will reject fontconfig font names (but still allow things like "c:myfont")
foreach (immutable char ch; path) if (ch == ':') return FONS_INVALID; foreach (immutable char ch; path[(path.length >= 2 && path[1] == ':' ? 2 : 0)..$]) if (ch == ':') return FONS_INVALID;
} }
// either no such font, or different path // either no such font, or different path
//{ import core.stdc.stdio; printf("trying font [%.*s] from file [%.*s]\n", cast(uint)blen, fontnamebuf.ptr, cast(uint)path.length, path.ptr); } //{ import core.stdc.stdio; printf("trying font [%.*s] from file [%.*s]\n", cast(uint)blen, fontnamebuf.ptr, cast(uint)path.length, path.ptr); }

View File

@ -1420,7 +1420,7 @@ class SimpleWindow : CapableOfHandlingNativeEvent, CapableOfBeingDrawnUpon {
/// This will be called when window becomes visible for the first time. /// This will be called when window becomes visible for the first time.
/// You can do OpenGL initialization here. Note that in X11 you can't call /// You can do OpenGL initialization here. Note that in X11 you can't call
/// `setAsCurrentOpenGlContext()` right after window creation, or X11 may /// [setAsCurrentOpenGlContext] right after window creation, or X11 may
/// fail to send reparent and map events (hit that with proprietary NVidia drivers). /// fail to send reparent and map events (hit that with proprietary NVidia drivers).
private bool _visibleForTheFirstTimeCalled; private bool _visibleForTheFirstTimeCalled;
void delegate () visibleForTheFirstTime; void delegate () visibleForTheFirstTime;
@ -7725,9 +7725,26 @@ version(Windows) {
if(windowResized !is null) if(windowResized !is null)
windowResized(width, height); windowResized(width, height);
break; break;
//case WM_ERASEBKGND: case WM_ERASEBKGND:
// no need since we double buffer // call `visibleForTheFirstTime` here, so we can do initialization as early as possible
//break; if (!this._visibleForTheFirstTimeCalled) {
this._visibleForTheFirstTimeCalled = true;
if (this.visibleForTheFirstTime !is null) {
version(without_opengl) {} else {
if(openglMode == OpenGlOptions.yes) {
this.setAsCurrentOpenGlContextNT();
glViewport(0, 0, width, height);
}
}
this.visibleForTheFirstTime();
}
}
// block it in OpenGL mode, 'cause no sane person will (or should) draw windows controls over OpenGL scene
version(without_opengl) {} else {
if (openglMode == OpenGlOptions.yes) return 1;
}
// call windows default handler, so it can paint standard controls
goto default;
case WM_CTLCOLORBTN: case WM_CTLCOLORBTN:
case WM_CTLCOLORSTATIC: case WM_CTLCOLORSTATIC:
SetBkMode(cast(HDC) wParam, TRANSPARENT); SetBkMode(cast(HDC) wParam, TRANSPARENT);
@ -7736,16 +7753,32 @@ version(Windows) {
break; break;
case WM_SHOWWINDOW: case WM_SHOWWINDOW:
this._visible = (wParam != 0); this._visible = (wParam != 0);
if (!this._visibleForTheFirstTimeCalled) { if (!this._visibleForTheFirstTimeCalled && this._visible) {
this._visibleForTheFirstTimeCalled = true; this._visibleForTheFirstTimeCalled = true;
if (this.visibleForTheFirstTime !is null) this.visibleForTheFirstTime(); if (this.visibleForTheFirstTime !is null) {
version(without_opengl) {} else {
if(openglMode == OpenGlOptions.yes) {
this.setAsCurrentOpenGlContextNT();
glViewport(0, 0, width, height);
}
}
this.visibleForTheFirstTime();
}
} }
if (this.visibilityChanged !is null) this.visibilityChanged(this._visible); if (this.visibilityChanged !is null) this.visibilityChanged(this._visible);
break; break;
case WM_PAINT: { case WM_PAINT: {
if (!this._visibleForTheFirstTimeCalled) { if (!this._visibleForTheFirstTimeCalled) {
this._visibleForTheFirstTimeCalled = true; this._visibleForTheFirstTimeCalled = true;
if (this.visibleForTheFirstTime !is null) this.visibleForTheFirstTime(); if (this.visibleForTheFirstTime !is null) {
version(without_opengl) {} else {
if(openglMode == OpenGlOptions.yes) {
this.setAsCurrentOpenGlContextNT();
glViewport(0, 0, width, height);
}
}
this.visibleForTheFirstTime();
}
} }
BITMAP bm; BITMAP bm;
@ -9491,6 +9524,12 @@ version(X11) {
if ((*win).visibleForTheFirstTime !is null) { if ((*win).visibleForTheFirstTime !is null) {
XUnlockDisplay(display); XUnlockDisplay(display);
scope(exit) XLockDisplay(display); scope(exit) XLockDisplay(display);
version(without_opengl) {} else {
if((*win).openglMode == OpenGlOptions.yes) {
(*win).setAsCurrentOpenGlContextNT();
glViewport(0, 0, (*win).width, (*win).height);
}
}
(*win).visibleForTheFirstTime(); (*win).visibleForTheFirstTime();
} }
} }