mirror of https://github.com/buggins/dlangui.git
rework resources destroy
This commit is contained in:
parent
5b358236f2
commit
e76394c5da
|
@ -43,7 +43,10 @@ extern (C) int UIAppMain(string[] args) {
|
|||
LinearLayout layout = new LinearLayout();
|
||||
layout.addChild((new TextWidget()).textColor(0x00802000).text("Text widget 0"));
|
||||
layout.addChild((new TextWidget()).textColor(0x40FF4000).text("Text widget"));
|
||||
layout.addChild((new Button()).text("Button1")); //.textColor(0x40FF4000)
|
||||
layout.addChild((new Button("BTN1")).text("Button1")); //.textColor(0x40FF4000)
|
||||
|
||||
|
||||
|
||||
|
||||
LinearLayout hlayout = new HorizontalLayout();
|
||||
//hlayout.addChild((new Button()).text("<<")); //.textColor(0x40FF4000)
|
||||
|
@ -62,13 +65,16 @@ extern (C) int UIAppMain(string[] args) {
|
|||
vlayout.addChild((new TextWidget()).text("VLayout line 2").textColor(0x40FFFF00));
|
||||
layout.addChild(vlayout);
|
||||
|
||||
layout.addChild((new Button()).textColor(0x000000FF).text("Button2"));
|
||||
layout.addChild((new Button("BTN2")).textColor(0x000000FF).text("Button2"));
|
||||
layout.addChild((new TextWidget()).textColor(0x40FF4000).text("Text widget"));
|
||||
layout.addChild((new ImageWidget()).drawableId("exit").padding(Rect(5,5,5,5)));
|
||||
layout.addChild((new TextWidget()).textColor(0xFF4000).text("Text widget2").padding(Rect(5,5,5,5)).margins(Rect(5,5,5,5)).backgroundColor(0xA0A0A0));
|
||||
layout.addChild((new Button()).textColor(0x000000FF).text("Button3").layoutHeight(FILL_PARENT));
|
||||
layout.addChild((new Button("BTN3")).textColor(0x000000FF).text("Button3").layoutHeight(FILL_PARENT));
|
||||
layout.addChild((new TextWidget()).textColor(0x004000).text("Text widget3 with very long text"));
|
||||
|
||||
layout.childById("BTN1").onClickListener(delegate (Widget w) { Log.d("onClick ", w.id); return true; });
|
||||
layout.childById("BTN2").onClickListener(delegate (Widget w) { Log.d("onClick ", w.id); return true; });
|
||||
layout.childById("BTN3").onClickListener(delegate (Widget w) { Log.d("onClick ", w.id); return true; });
|
||||
|
||||
layout.layoutHeight(FILL_PARENT).layoutWidth(FILL_PARENT);
|
||||
|
||||
|
|
|
@ -670,6 +670,13 @@ class ColorDrawBuf : ColorDrawBufBase {
|
|||
}
|
||||
|
||||
class Drawable : RefCountedObject {
|
||||
private static int _instanceCount;
|
||||
this() {
|
||||
Log.d("Created drawable, count=", ++_instanceCount);
|
||||
}
|
||||
~this() {
|
||||
Log.d("Destroyed drawable, count=", --_instanceCount);
|
||||
}
|
||||
abstract void drawTo(DrawBuf buf, Rect rc, int tilex0 = 0, int tiley0 = 0);
|
||||
@property abstract int width();
|
||||
@property abstract int height();
|
||||
|
|
|
@ -146,9 +146,19 @@ struct FontList {
|
|||
FontRef[] _list;
|
||||
uint _len;
|
||||
~this() {
|
||||
clear();
|
||||
}
|
||||
|
||||
@property uint length() {
|
||||
return _len;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
for (uint i = 0; i < _len; i++) {
|
||||
_list[i].clear();
|
||||
_list[i] = null;
|
||||
}
|
||||
_len = 0;
|
||||
}
|
||||
// returns item by index
|
||||
ref FontRef get(int index) {
|
||||
|
@ -216,6 +226,8 @@ class FontManager {
|
|||
static __gshared FontManager _instance;
|
||||
/// sets new font manager singleton instance
|
||||
static @property void instance(FontManager manager) {
|
||||
if (_instance !is null)
|
||||
destroy(_instance);
|
||||
_instance = manager;
|
||||
}
|
||||
/// returns font manager singleton instance
|
||||
|
@ -232,5 +244,7 @@ class FontManager {
|
|||
/// removes entries not used after last call of checkpoint() or cleanup()
|
||||
abstract void cleanup();
|
||||
|
||||
~this() {}
|
||||
~this() {
|
||||
Log.d("Destroying font manager");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,6 +99,7 @@ private class FreeTypeFontFile {
|
|||
@property int weight() { return _weight; }
|
||||
@property bool italic() { return _italic; }
|
||||
|
||||
private static int _instanceCount;
|
||||
this(FT_Library library, string filename) {
|
||||
_library = library;
|
||||
_filename = filename;
|
||||
|
@ -106,6 +107,12 @@ private class FreeTypeFontFile {
|
|||
_matrix.yy = 0x10000;
|
||||
_matrix.xy = 0;
|
||||
_matrix.yx = 0;
|
||||
Log.d("Created FreeTypeFontFile, count=", ++_instanceCount);
|
||||
}
|
||||
|
||||
~this() {
|
||||
clear();
|
||||
Log.d("Destroyed FreeTypeFontFile, count=", --_instanceCount);
|
||||
}
|
||||
|
||||
private static string familyName(FT_Face face)
|
||||
|
@ -273,9 +280,6 @@ private class FreeTypeFontFile {
|
|||
_face = null;
|
||||
}
|
||||
|
||||
~this() {
|
||||
clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -285,11 +289,19 @@ class FreeTypeFont : Font {
|
|||
private FontFileItem _fontItem;
|
||||
private FreeTypeFontFile[] _files;
|
||||
|
||||
static int _instanceCount;
|
||||
/// need to call create() after construction to initialize font
|
||||
this(FontFileItem item, int size) {
|
||||
_fontItem = item;
|
||||
_size = size;
|
||||
_height = size;
|
||||
Log.d("Created font, count=", ++_instanceCount);
|
||||
}
|
||||
|
||||
/// do cleanup
|
||||
~this() {
|
||||
clear();
|
||||
Log.d("Destroyed font, count=", --_instanceCount);
|
||||
}
|
||||
|
||||
private int _size;
|
||||
|
@ -297,10 +309,6 @@ class FreeTypeFont : Font {
|
|||
|
||||
private GlyphCache _glyphCache;
|
||||
|
||||
/// do cleanup
|
||||
~this() {
|
||||
clear();
|
||||
}
|
||||
|
||||
/// cleanup resources
|
||||
override void clear() {
|
||||
|
@ -482,6 +490,13 @@ class FreeTypeFontManager : FontManager {
|
|||
}
|
||||
}
|
||||
~this() {
|
||||
Log.d("FreeTypeFontManager ~this() active fonts: ", _activeFonts.length);
|
||||
_activeFonts.clear();
|
||||
foreach(ref FontFileItem item; _fontFiles) {
|
||||
destroy(item);
|
||||
item = null;
|
||||
}
|
||||
_fontFiles.length = 0;
|
||||
// uninit library
|
||||
if (_library)
|
||||
FT_Done_FreeType(_library);
|
||||
|
|
|
@ -78,10 +78,22 @@ class ImageCache {
|
|||
__gshared ImageCache _imageCache;
|
||||
/// image cache singleton
|
||||
@property ImageCache imageCache() { return _imageCache; }
|
||||
/// image cache singleton
|
||||
@property void imageCache(ImageCache cache) {
|
||||
if (_imageCache !is null)
|
||||
destroy(_imageCache);
|
||||
_imageCache = cache;
|
||||
}
|
||||
|
||||
__gshared DrawableCache _drawableCache;
|
||||
/// drawable cache singleton
|
||||
@property DrawableCache drawableCache() { return _drawableCache; }
|
||||
/// drawable cache singleton
|
||||
@property void drawableCache(DrawableCache cache) {
|
||||
if (_drawableCache !is null)
|
||||
destroy(_drawableCache);
|
||||
_drawableCache = cache;
|
||||
}
|
||||
|
||||
shared static this() {
|
||||
_imageCache = new ImageCache();
|
||||
|
@ -102,6 +114,9 @@ class DrawableCache {
|
|||
_tiled = tiled;
|
||||
_error = filename is null;
|
||||
}
|
||||
~this() {
|
||||
_drawable.clear();
|
||||
}
|
||||
/// remove from memory, will cause reload on next access
|
||||
void compact() {
|
||||
if (!_drawable.isNull)
|
||||
|
@ -133,6 +148,7 @@ class DrawableCache {
|
|||
}
|
||||
}
|
||||
void clear() {
|
||||
Log.d("DrawableCache.clear()");
|
||||
_idToFileMap.clear();
|
||||
foreach(DrawableCacheItem item; _idToDrawableMap)
|
||||
item.drawable.clear();
|
||||
|
|
|
@ -42,6 +42,12 @@ class Window {
|
|||
this() {
|
||||
_backgroundColor = 0xFFFFFF;
|
||||
}
|
||||
~this() {
|
||||
if (_mainWidget !is null) {
|
||||
destroy(_mainWidget);
|
||||
_mainWidget = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void animate(Widget root, long interval) {
|
||||
if (root.visibility != Visibility.Visible)
|
||||
|
|
|
@ -17,6 +17,8 @@ version(linux) {
|
|||
import dlangui.graphics.drawbuf;
|
||||
import dlangui.graphics.fonts;
|
||||
import dlangui.graphics.ftfonts;
|
||||
import dlangui.graphics.images;
|
||||
import dlangui.widgets.styles;
|
||||
import dlangui.platforms.common.platform;
|
||||
|
||||
class XCBWindow : Window {
|
||||
|
@ -301,6 +303,11 @@ version(linux) {
|
|||
this() {
|
||||
}
|
||||
~this() {
|
||||
foreach(ref XCBWindow wnd; _windowMap) {
|
||||
destroy(wnd);
|
||||
wnd = null;
|
||||
}
|
||||
_windowMap.clear();
|
||||
disconnect();
|
||||
}
|
||||
void disconnect() {
|
||||
|
@ -523,6 +530,8 @@ version(linux) {
|
|||
ft.registerFont("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", FontFamily.SansSerif, "DejaVu", false, FontWeight.Normal);
|
||||
FontManager.instance = ft;
|
||||
|
||||
currentTheme = createDefaultTheme();
|
||||
|
||||
XCBPlatform xcb = new XCBPlatform();
|
||||
if (!xcb.connect()) {
|
||||
return 1;
|
||||
|
@ -541,8 +550,15 @@ version(linux) {
|
|||
}
|
||||
|
||||
Platform.setInstance(null);
|
||||
Log.d("Destroying XCB platform");
|
||||
destroy(xcb);
|
||||
|
||||
currentTheme = null;
|
||||
drawableCache = null;
|
||||
imageCache = null;
|
||||
FontManager.instance = null;
|
||||
|
||||
Log.d("Exiting main");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@ module dlangui.widgets.controls;
|
|||
|
||||
import dlangui.widgets.widget;
|
||||
|
||||
|
||||
|
||||
/// static text widget
|
||||
class TextWidget : Widget {
|
||||
this(string ID = null) {
|
||||
|
@ -121,6 +123,7 @@ class Button : Widget {
|
|||
Point sz = font.textSize(text);
|
||||
measuredContent(parentWidth, parentHeight, sz.x, sz.y);
|
||||
}
|
||||
|
||||
override void onDraw(DrawBuf buf) {
|
||||
super.onDraw(buf);
|
||||
Rect rc = _pos;
|
||||
|
@ -134,26 +137,4 @@ class Button : Widget {
|
|||
font.drawText(buf, rc.left, rc.top, text, textColor);
|
||||
}
|
||||
|
||||
override bool onMouseEvent(MouseEvent event) {
|
||||
if (event.action == MouseAction.ButtonDown && event.button == MouseButton.Left) {
|
||||
setState(State.Pressed);
|
||||
Log.d("Button state: ", state);
|
||||
return true;
|
||||
}
|
||||
if (event.action == MouseAction.ButtonUp && event.button == MouseButton.Left) {
|
||||
resetState(State.Pressed);
|
||||
Log.d("Button state: ", state);
|
||||
return true;
|
||||
}
|
||||
if (event.action == MouseAction.FocusOut || event.action == MouseAction.Cancel) {
|
||||
resetState(State.Pressed);
|
||||
return true;
|
||||
}
|
||||
if (event.action == MouseAction.FocusIn) {
|
||||
setState(State.Pressed);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -386,10 +386,29 @@ class Style {
|
|||
return this;
|
||||
}
|
||||
|
||||
private static int _instanceCount;
|
||||
this(Theme theme, string id) {
|
||||
_theme = theme;
|
||||
_parentStyle = theme;
|
||||
_id = id;
|
||||
Log.d("Created style ", _id, ", count=", ++_instanceCount);
|
||||
}
|
||||
|
||||
~this() {
|
||||
foreach(ref Style item; _substates) {
|
||||
Log.d("Destroying substate");
|
||||
destroy(item);
|
||||
item = null;
|
||||
}
|
||||
_substates.clear();
|
||||
foreach(ref Style item; _children) {
|
||||
destroy(item);
|
||||
item = null;
|
||||
}
|
||||
_children.clear();
|
||||
_backgroundDrawable.clear();
|
||||
_font.clear();
|
||||
Log.d("Destroyed style ", _id, ", parentId=", _parentId, ", state=", _stateMask, ", count=", --_instanceCount);
|
||||
}
|
||||
|
||||
/// create named substyle of this style
|
||||
|
@ -403,7 +422,9 @@ class Style {
|
|||
/// create state substyle for this style
|
||||
Style createState(uint stateMask = 0, uint stateValue = 0) {
|
||||
assert(stateMask != 0);
|
||||
Style child = createSubstyle(null);
|
||||
Log.d("Creating substate ", stateMask);
|
||||
Style child = (_theme !is null ? _theme : currentTheme).createSubstyle(null);
|
||||
child._parentStyle = this;
|
||||
child._stateMask = stateMask;
|
||||
child._stateValue = stateValue;
|
||||
child._backgroundColor = COLOR_UNSPECIFIED;
|
||||
|
@ -424,6 +445,7 @@ class Style {
|
|||
}
|
||||
return this; // fallback to current style
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// Theme - root for style hierarhy.
|
||||
|
@ -448,6 +470,10 @@ class Theme : Style {
|
|||
_layoutWeight = 1;
|
||||
}
|
||||
|
||||
~this() {
|
||||
Log.d("Theme destructor");
|
||||
}
|
||||
|
||||
/// create wrapper style which will have currentTheme.get(id) as parent instead of fixed parent - to modify some base style properties in widget
|
||||
Style modifyStyle(string id) {
|
||||
Style style = new Style(null, null);
|
||||
|
@ -499,13 +525,26 @@ class Theme : Style {
|
|||
/// to access current theme
|
||||
private __gshared Theme _currentTheme;
|
||||
@property Theme currentTheme() { return _currentTheme; }
|
||||
@property void currentTheme(Theme theme) {
|
||||
if (_currentTheme !is null) {
|
||||
destroy(_currentTheme);
|
||||
}
|
||||
_currentTheme = theme;
|
||||
}
|
||||
|
||||
static this() {
|
||||
_currentTheme = new Theme("default");
|
||||
Style button = _currentTheme.createSubstyle("BUTTON").backgroundImageId("btn_default_small_normal").alignment(Align.Center);
|
||||
Style text = _currentTheme.createSubstyle("TEXT").margins(Rect(3,3,3,3)).padding(Rect(3,3,3,3));
|
||||
|
||||
Theme createDefaultTheme() {
|
||||
Log.d("Creating default theme");
|
||||
Theme res = new Theme("default");
|
||||
Style button = res.createSubstyle("BUTTON").backgroundImageId("btn_default_small_normal").alignment(Align.Center);
|
||||
Style text = res.createSubstyle("TEXT").margins(Rect(3,3,3,3)).padding(Rect(3,3,3,3));
|
||||
button.createState(State.Disabled | State.Focused, State.Disabled | State.Focused).backgroundImageId("btn_default_small_normal_disable_focused");
|
||||
button.createState(State.Disabled, State.Disabled).backgroundImageId("btn_default_small_normal_disable");
|
||||
button.createState(State.Pressed, State.Pressed).backgroundImageId("btn_default_small_pressed");
|
||||
button.createState(State.Focused, State.Focused).backgroundImageId("btn_default_small_selected");
|
||||
return res;
|
||||
}
|
||||
|
||||
shared static ~this() {
|
||||
currentTheme = null;
|
||||
}
|
|
@ -7,10 +7,14 @@ public import dlangui.graphics.drawbuf;
|
|||
public import dlangui.graphics.images;
|
||||
public import dlangui.graphics.fonts;
|
||||
|
||||
public import std.signals;
|
||||
|
||||
import dlangui.platforms.common.platform;
|
||||
|
||||
import std.algorithm;
|
||||
|
||||
alias onClick_t = bool delegate(Widget);
|
||||
|
||||
|
||||
/// Visibility (see Android View Visibility)
|
||||
enum Visibility : ubyte {
|
||||
|
@ -50,8 +54,17 @@ class Widget {
|
|||
/// window (to be used for top level widgets only!)
|
||||
protected Window _window;
|
||||
|
||||
private static int _instanceCount = 0;
|
||||
/// create widget, with optional id
|
||||
this(string ID = null) {
|
||||
_id = id;
|
||||
_id = ID;
|
||||
Log.d("Created widget, count = ", ++_instanceCount);
|
||||
}
|
||||
~this() {
|
||||
if (_ownStyle !is null)
|
||||
destroy(_ownStyle);
|
||||
_ownStyle = null;
|
||||
Log.d("Destroyed widget, count = ", --_instanceCount);
|
||||
}
|
||||
|
||||
/// accessor to style - by lookup in theme by styleId (if style id is not set, theme base style will be used).
|
||||
|
@ -90,7 +103,7 @@ class Widget {
|
|||
}
|
||||
|
||||
/// returns widget id, null if not set
|
||||
@property string id() const { return _styleId; }
|
||||
@property string id() const { return _id; }
|
||||
/// set widget id
|
||||
@property void id(string id) { _id = id; }
|
||||
/// compare widget id with specified value, returs true if matches
|
||||
|
@ -266,9 +279,35 @@ class Widget {
|
|||
|
||||
/// process mouse event; return true if event is processed by widget.
|
||||
bool onMouseEvent(MouseEvent event) {
|
||||
// support onClick
|
||||
if (_onClickListener !is null) {
|
||||
if (event.action == MouseAction.ButtonDown && event.button == MouseButton.Left) {
|
||||
setState(State.Pressed);
|
||||
return true;
|
||||
}
|
||||
if (event.action == MouseAction.ButtonUp && event.button == MouseButton.Left) {
|
||||
resetState(State.Pressed);
|
||||
_onClickListener(this);
|
||||
return true;
|
||||
}
|
||||
if (event.action == MouseAction.FocusOut || event.action == MouseAction.Cancel) {
|
||||
resetState(State.Pressed);
|
||||
return true;
|
||||
}
|
||||
if (event.action == MouseAction.FocusIn) {
|
||||
setState(State.Pressed);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected onClick_t _onClickListener;
|
||||
/// on click event listener (bool delegate(Widget))
|
||||
@property onClick_t onClickListener() { return _onClickListener; }
|
||||
/// set on click event listener (bool delegate(Widget))
|
||||
@property Widget onClickListener(onClick_t listener) { _onClickListener = listener; return this; }
|
||||
|
||||
// =======================================================
|
||||
// Layout and measurement methods
|
||||
|
||||
|
@ -455,6 +494,7 @@ class Widget {
|
|||
/// sets window (to be used for top level widget from Window implementation). TODO: hide it from API?
|
||||
@property void window(Window window) { _window = window; }
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// widget list holder
|
||||
|
|
Loading…
Reference in New Issue