mirror of https://github.com/buggins/dlangui.git
working drawable cache and resized image drawing
This commit is contained in:
parent
aef01a1044
commit
6764fe17eb
|
@ -55,6 +55,10 @@ extern (C) int UIAppMain(string[] args) {
|
||||||
Log.d("Some debug message");
|
Log.d("Some debug message");
|
||||||
Log.e("Sample error #", 22);
|
Log.e("Sample error #", 22);
|
||||||
|
|
||||||
|
string[] imageDirs = [
|
||||||
|
resourceDir
|
||||||
|
];
|
||||||
|
drawableCache.resourcePaths = imageDirs;
|
||||||
Window window = Platform.instance().createWindow("My Window", null);
|
Window window = Platform.instance().createWindow("My Window", null);
|
||||||
Widget myWidget = (new TextWidget()).textColor(0x40FF4000);
|
Widget myWidget = (new TextWidget()).textColor(0x40FF4000);
|
||||||
myWidget.text = "Some strange text string. 1234567890";
|
myWidget.text = "Some strange text string. 1234567890";
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
module dlangui.core.types;
|
module dlangui.core.types;
|
||||||
|
|
||||||
|
import std.algorithm;
|
||||||
|
|
||||||
struct Point {
|
struct Point {
|
||||||
int x;
|
int x;
|
||||||
int y;
|
int y;
|
||||||
|
@ -136,3 +138,14 @@ wstring fromWStringz(const(wchar[]) s) {
|
||||||
return cast(wstring)(s[0..i].dup);
|
return cast(wstring)(s[0..i].dup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool startsWith(string str, string prefix) {
|
||||||
|
if (str.length >= prefix.length)
|
||||||
|
return equal(str[0..prefix.length], prefix);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool endsWith(string str, string suffix) {
|
||||||
|
if (str.length >= suffix.length)
|
||||||
|
return equal(str[$-suffix.length .. $], suffix);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
module dlangui.graphics.drawbuf;
|
module dlangui.graphics.drawbuf;
|
||||||
|
|
||||||
public import dlangui.core.types;
|
public import dlangui.core.types;
|
||||||
|
import dlangui.core.logger;
|
||||||
|
|
||||||
/// blend two RGB pixels using alpha
|
/// blend two RGB pixels using alpha
|
||||||
uint blendARGB(uint dst, uint src, uint alpha) {
|
uint blendARGB(uint dst, uint src, uint alpha) {
|
||||||
|
@ -244,7 +245,7 @@ class ColorDrawBufBase : DrawBuf {
|
||||||
int sd = src1 - src0;
|
int sd = src1 - src0;
|
||||||
int[] res = new int[dd];
|
int[] res = new int[dd];
|
||||||
for (int i = 0; i < dd; i++)
|
for (int i = 0; i < dd; i++)
|
||||||
res[i] = src0 + i * dd / sd;
|
res[i] = src0 + i * sd / dd;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
/// draw source buffer rectangle contents to destination buffer rectangle applying rescaling
|
/// draw source buffer rectangle contents to destination buffer rectangle applying rescaling
|
||||||
|
@ -403,7 +404,7 @@ class ColorDrawBuf : ColorDrawBufBase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Drawable {
|
class Drawable : RefCountedObject {
|
||||||
abstract void drawTo(DrawBuf buf, Rect rc, int tilex0 = 0, int tiley0 = 0);
|
abstract void drawTo(DrawBuf buf, Rect rc, int tilex0 = 0, int tiley0 = 0);
|
||||||
@property abstract int width();
|
@property abstract int width();
|
||||||
@property abstract int height();
|
@property abstract int height();
|
||||||
|
@ -465,3 +466,5 @@ class ImageDrawable : Drawable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
alias DrawableRef = Ref!Drawable;
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
module dlangui.graphics.images;
|
module dlangui.graphics.images;
|
||||||
|
|
||||||
import dlangui.core.logger;
|
import dlangui.core.logger;
|
||||||
|
import dlangui.core.types;
|
||||||
import dlangui.graphics.drawbuf;
|
import dlangui.graphics.drawbuf;
|
||||||
import std.stream;
|
import std.stream;
|
||||||
|
import std.file;
|
||||||
import libpng.png;
|
import libpng.png;
|
||||||
|
|
||||||
/// decoded image cache
|
/// decoded image cache
|
||||||
|
@ -72,6 +74,130 @@ class ImageCache {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__gshared ImageCache _imageCache;
|
||||||
|
/// image cache singleton
|
||||||
|
@property ImageCache imageCache() { return _imageCache; }
|
||||||
|
|
||||||
|
__gshared DrawableCache _drawableCache;
|
||||||
|
/// drawable cache singleton
|
||||||
|
@property DrawableCache drawableCache() { return _drawableCache; }
|
||||||
|
|
||||||
|
static this() {
|
||||||
|
_imageCache = new ImageCache();
|
||||||
|
_drawableCache = new DrawableCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
class DrawableCache {
|
||||||
|
static class DrawableCacheItem {
|
||||||
|
string _id;
|
||||||
|
string _filename;
|
||||||
|
bool _tiled;
|
||||||
|
bool _error;
|
||||||
|
bool _used;
|
||||||
|
DrawableRef _drawable;
|
||||||
|
this(string id, string filename, bool tiled) {
|
||||||
|
_id = id;
|
||||||
|
_filename = filename;
|
||||||
|
_tiled = tiled;
|
||||||
|
_error = filename is null;
|
||||||
|
}
|
||||||
|
/// remove from memory, will cause reload on next access
|
||||||
|
void compact() {
|
||||||
|
if (!_drawable.isNull)
|
||||||
|
_drawable.clear();
|
||||||
|
}
|
||||||
|
/// mark as not used
|
||||||
|
void checkpoint() {
|
||||||
|
_used = false;
|
||||||
|
}
|
||||||
|
/// cleanup if unused since last checkpoint
|
||||||
|
void cleanup() {
|
||||||
|
if (!_used)
|
||||||
|
compact();
|
||||||
|
}
|
||||||
|
@property ref DrawableRef drawable() {
|
||||||
|
_used = true;
|
||||||
|
if (!_drawable.isNull || _error)
|
||||||
|
return _drawable;
|
||||||
|
if (_filename !is null) {
|
||||||
|
// reload from file
|
||||||
|
DrawBufRef image = imageCache.get(_filename);
|
||||||
|
if (!image.isNull)
|
||||||
|
_drawable = new ImageDrawable(image, _tiled);
|
||||||
|
else
|
||||||
|
_error = true;
|
||||||
|
}
|
||||||
|
return _drawable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void clear() {
|
||||||
|
_idToFileMap.clear();
|
||||||
|
foreach(DrawableCacheItem item; _idToDrawableMap)
|
||||||
|
item.drawable.clear();
|
||||||
|
_idToDrawableMap.clear();
|
||||||
|
}
|
||||||
|
// clear usage flags for all entries
|
||||||
|
void checkpoint() {
|
||||||
|
foreach (item; _idToDrawableMap)
|
||||||
|
item.checkpoint();
|
||||||
|
}
|
||||||
|
// removes entries not used after last call of checkpoint() or cleanup()
|
||||||
|
void cleanup() {
|
||||||
|
foreach (item; _idToDrawableMap)
|
||||||
|
item.cleanup();
|
||||||
|
}
|
||||||
|
string[] _resourcePaths;
|
||||||
|
string[string] _idToFileMap;
|
||||||
|
DrawableCacheItem[string] _idToDrawableMap;
|
||||||
|
ref DrawableRef get(string id) {
|
||||||
|
if (id in _idToDrawableMap)
|
||||||
|
return _idToDrawableMap[id].drawable;
|
||||||
|
string resourceId = id;
|
||||||
|
bool tiled = false;
|
||||||
|
if (id.endsWith(".tiled")) {
|
||||||
|
resourceId = id[0..$-6]; // remove .tiled
|
||||||
|
tiled = true;
|
||||||
|
}
|
||||||
|
string filename = findResource(resourceId);
|
||||||
|
DrawableCacheItem item = new DrawableCacheItem(id, filename, tiled);
|
||||||
|
_idToDrawableMap[id] = item;
|
||||||
|
return item.drawable;
|
||||||
|
}
|
||||||
|
@property string[] resourcePaths() {
|
||||||
|
return _resourcePaths;
|
||||||
|
}
|
||||||
|
@property void resourcePaths(string[] paths) {
|
||||||
|
_resourcePaths = paths;
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
string findResource(string id) {
|
||||||
|
if (id in _idToFileMap)
|
||||||
|
return _idToFileMap[id];
|
||||||
|
foreach(string path; _resourcePaths) {
|
||||||
|
char[] name = path.dup;
|
||||||
|
name ~= id;
|
||||||
|
name ~= ".png";
|
||||||
|
if (!exists(name)) {
|
||||||
|
name = path.dup;
|
||||||
|
name ~= id;
|
||||||
|
name ~= ".9.png";
|
||||||
|
}
|
||||||
|
if (exists(name) && isFile(name)) {
|
||||||
|
string filename = name.dup;
|
||||||
|
_idToFileMap[id] = filename;
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
this() {
|
||||||
|
Log.i("Creating DrawableCache");
|
||||||
|
}
|
||||||
|
~this() {
|
||||||
|
Log.i("Destroying DrawableCache");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// load and decode image from file to ColorDrawBuf, returns null if loading or decoding is failed
|
/// load and decode image from file to ColorDrawBuf, returns null if loading or decoding is failed
|
||||||
ColorDrawBuf loadImage(string filename) {
|
ColorDrawBuf loadImage(string filename) {
|
||||||
Log.d("Loading image from file " ~ filename);
|
Log.d("Loading image from file " ~ filename);
|
||||||
|
|
|
@ -3,6 +3,7 @@ module dlangui.widgets.widget;
|
||||||
public import dlangui.core.types;
|
public import dlangui.core.types;
|
||||||
public import dlangui.widgets.styles;
|
public import dlangui.widgets.styles;
|
||||||
public import dlangui.graphics.drawbuf;
|
public import dlangui.graphics.drawbuf;
|
||||||
|
public import dlangui.graphics.images;
|
||||||
public import dlangui.graphics.fonts;
|
public import dlangui.graphics.fonts;
|
||||||
import dlangui.platforms.common.platform;
|
import dlangui.platforms.common.platform;
|
||||||
|
|
||||||
|
@ -151,6 +152,9 @@ class Widget {
|
||||||
applyPadding(rc);
|
applyPadding(rc);
|
||||||
buf.fillRect(Rect(rc.left + rc.width / 2, rc.top, rc.left + rc.width / 2 + 2, rc.bottom), 0xFF8000);
|
buf.fillRect(Rect(rc.left + rc.width / 2, rc.top, rc.left + rc.width / 2 + 2, rc.bottom), 0xFF8000);
|
||||||
buf.fillRect(Rect(rc.left, rc.top + rc.height / 2, rc.right, rc.top + rc.height / 2 + 2), 0xFF80FF);
|
buf.fillRect(Rect(rc.left, rc.top + rc.height / 2, rc.right, rc.top + rc.height / 2 + 2), 0xFF80FF);
|
||||||
|
DrawableRef img = drawableCache.get("exit");
|
||||||
|
if (!img.isNull)
|
||||||
|
img.drawTo(buf, Rect(50, 50, 50+64, 50+64));
|
||||||
_needDraw = false;
|
_needDraw = false;
|
||||||
}
|
}
|
||||||
/// Applies alignment for content of size sz - set rectangle rc to aligned value of content inside of initial value of rc.
|
/// Applies alignment for content of size sz - set rectangle rc to aligned value of content inside of initial value of rc.
|
||||||
|
|
Loading…
Reference in New Issue