This commit is contained in:
Adam D. Ruppe 2020-04-24 09:54:48 -04:00
parent c2e8c8bcce
commit 5419cfed70
6 changed files with 105 additions and 5 deletions

47
color.d
View File

@ -1577,6 +1577,8 @@ struct Rectangle {
Implements a flood fill algorithm, like the bucket tool in
MS Paint.
Note it assumes `what.length == width*height`.
Params:
what = the canvas to work with, arranged as top to bottom, left to right elements
width = the width of the canvas
@ -1585,13 +1587,17 @@ struct Rectangle {
replacement = the replacement value
x = the x-coordinate to start the fill (think of where the user clicked in Paint)
y = the y-coordinate to start the fill
additionalCheck = A custom additional check to perform on each square before continuing. Returning true means keep flooding, returning false means stop.
additionalCheck = A custom additional check to perform on each square before continuing. Returning true means keep flooding, returning false means stop. If null, it is not used.
+/
void floodFill(T)(
T[] what, int width, int height, // the canvas to inspect
T target, T replacement, // fill params
int x, int y, bool delegate(int x, int y) @safe additionalCheck) // the node
// in(what.length == width * height) // gdc doesn't support this syntax yet so not gonna use it until that comes out.
{
assert(what.length == width * height); // will use the contract above when gdc supports it
T node = what[y * width + x];
if(target == replacement) return;
@ -1604,6 +1610,44 @@ void floodFill(T)(
if(!additionalCheck(x, y))
return;
Point[] queue;
queue ~= Point(x, y);
while(queue.length) {
auto n = queue[0];
queue = queue[1 .. $];
//queue.assumeSafeAppend(); // lol @safe breakage
auto w = n;
int offset = cast(int) (n.y * width + n.x);
auto e = n;
auto eoffset = offset;
w.x--;
offset--;
while(w.x >= 0 && what[offset] == target && additionalCheck(w.x, w.y)) {
w.x--;
offset--;
}
while(e.x < width && what[eoffset] == target && additionalCheck(e.x, e.y)) {
e.x++;
eoffset++;
}
// to make it inclusive again
w.x++;
offset++;
foreach(o ; offset .. eoffset) {
what[o] = replacement;
if(w.y && what[o - width] == target && additionalCheck(w.x, w.y))
queue ~= Point(w.x, w.y - 1);
if(w.y + 1 < height && what[o + width] == target && additionalCheck(w.x, w.y))
queue ~= Point(w.x, w.y + 1);
w.x++;
}
}
/+
what[y * width + x] = replacement;
if(x)
@ -1621,6 +1665,7 @@ void floodFill(T)(
if(y != height - 1)
floodFill(what, width, height, target, replacement,
x, y + 1, additionalCheck);
+/
}
// for scripting, so you can tag it without strictly needing to import arsd.jsvar

View File

@ -394,6 +394,7 @@ final class OpenGlTexture {
/// After you delete it with dispose, you may rebind it to something else with this.
void bindFrom(TrueColorImage from) {
assert(from !is null);
assert(from.width > 0 && from.height > 0);
import core.stdc.stdlib;

56
jsvar.d
View File

@ -549,6 +549,7 @@ struct var {
}
}
/// `if(some_var)` will call this and give behavior based on the dynamic type. Shouldn't be too surprising.
public bool opCast(T:bool)() {
final switch(this._type) {
case Type.Object:
@ -568,6 +569,7 @@ struct var {
}
}
/// You can foreach over a var.
public int opApply(scope int delegate(ref var) dg) {
foreach(i, item; this)
if(auto result = dg(item))
@ -575,6 +577,7 @@ struct var {
return 0;
}
/// ditto
public int opApply(scope int delegate(var, ref var) dg) {
if(this.payloadType() == Type.Array) {
foreach(i, ref v; this._payload._array)
@ -606,15 +609,30 @@ struct var {
}
/// Alias for [get]. e.g. `string s = cast(string) v;`
public T opCast(T)() {
return this.get!T;
}
/// Calls [get] for a type automatically. `int a; var b; b.putInto(a);` will auto-convert to `int`.
public auto ref putInto(T)(ref T t) {
return t = this.get!T;
}
// if it is var, we'll just blit it over
/++
Assigns a value to the var. It will do necessary implicit conversions
and wrapping.
You can make a method `toArsdJsvar` on your own objects to override this
default. It should return a [var].
History:
On April 20, 2020, I changed the default mode for class assignment
to [wrapNativeObject]. Previously it was [wrapOpaquely].
With the new [wrapNativeObject] behavior, you can mark methods
@[scriptable] to expose them to the script.
+/
public var opAssign(T)(T t) if(!is(T == var)) {
static if(__traits(compiles, this = t.toArsdJsvar())) {
static if(__traits(compiles, t is null)) {
@ -661,7 +679,10 @@ struct var {
// so prewrapped stuff can be easily passed.
this._type = Type.Object;
this._payload._object = t;
} else static if(is(T == class) || .isScriptableOpaque!T) {
} else static if(is(T == class)) {
this._type = Type.Object;
this._payload._object = wrapNativeObject(t);
} else static if(.isScriptableOpaque!T) {
// auto-wrap other classes with reference semantics
this._type = Type.Object;
this._payload._object = wrapOpaquely(t);
@ -846,6 +867,31 @@ struct var {
return null;
}
/++
Gets the var converted to type `T` as best it can. `T` may be constructed
from `T.fromJsVar`, or through type conversions (coercing as needed). If
`T` happens to be a struct, it will automatically introspect to convert
the var object member-by-member.
History:
On April 21, 2020, I changed the behavior of
---
var a = null;
string b = a.get!string;
---
Previously, `b == "null"`, which would print the word
when writeln'd. Now, `b is null`, which prints the empty string,
which is a bit less user-friendly, but more consistent with
converting to/from D strings in general.
If you are printing, you can check `a.get!string is null` and print
null at that point if you like.
I also wrote the first draft of this documentation at that time,
even though the function has been public since the beginning.
+/
public T get(T)() if(!is(T == void)) {
static if(is(T == var)) {
return this;
@ -920,7 +966,7 @@ struct var {
} else static if(isSomeString!T) {
if(this._object !is null)
return this._object.toString();
return "null";
return null;// "null";
} else
return T.init;
case Type.Integral:
@ -1126,18 +1172,22 @@ struct var {
return var(null);
}
/// Forwards to [opIndex]
public @property ref var opDispatch(string name, string file = __FILE__, size_t line = __LINE__)() {
return this[name];
}
/// Forwards to [opIndexAssign]
public @property ref var opDispatch(string name, string file = __FILE__, size_t line = __LINE__, T)(T r) {
return this.opIndexAssign!T(r, name);
}
/// Looks up a sub-property of the object
public ref var opIndex(var name, string file = __FILE__, size_t line = __LINE__) {
return opIndex(name.get!string, file, line);
}
/// Sets a sub-property of the object
public ref var opIndexAssign(T)(T t, var name, string file = __FILE__, size_t line = __LINE__) {
return opIndexAssign(t, name.get!string, file, line);
}

View File

@ -3150,7 +3150,7 @@ class TabWidget : Widget {
}
override int marginTop() { return 4; }
override int marginBottom() { return 4; }
override int paddingBottom() { return 4; }
override int minHeight() {
int max = 0;

View File

@ -13459,6 +13459,8 @@ extern(System) nothrow @nogc {
uint/*GLenum*/ format, uint/*GLenum*/ type, in void* pixels);
void glTexEnvf(uint/*GLenum*/ target, uint/*GLenum*/ pname, float param);
void glLineWidth(int);
void glTexCoord2f(float, float);
void glVertex2i(int, int);

2
ttf.d
View File

@ -16,6 +16,8 @@ module arsd.ttf;
// here's some D convenience functions
// need to do some print glyphs t it....
///
struct TtfFont {