mirror of https://github.com/buggins/dlangui.git
Merge pull request #491 from dayllenger/memoize
Powerful optimization: memoize
This commit is contained in:
commit
33a7501bb9
|
@ -74,11 +74,11 @@ enum FontWeight : int {
|
|||
Bold = 800
|
||||
}
|
||||
|
||||
immutable dchar UNICODE_SOFT_HYPHEN_CODE = 0x00ad;
|
||||
immutable dchar UNICODE_ZERO_WIDTH_SPACE = 0x200b;
|
||||
immutable dchar UNICODE_NO_BREAK_SPACE = 0x00a0;
|
||||
immutable dchar UNICODE_HYPHEN = 0x2010;
|
||||
immutable dchar UNICODE_NB_HYPHEN = 0x2011;
|
||||
enum dchar UNICODE_SOFT_HYPHEN_CODE = 0x00ad;
|
||||
enum dchar UNICODE_ZERO_WIDTH_SPACE = 0x200b;
|
||||
enum dchar UNICODE_NO_BREAK_SPACE = 0x00a0;
|
||||
enum dchar UNICODE_HYPHEN = 0x2010;
|
||||
enum dchar UNICODE_NB_HYPHEN = 0x2011;
|
||||
|
||||
/// custom character properties - for char-by-char drawing of text string with different character color and style
|
||||
struct CustomCharProps {
|
||||
|
@ -124,7 +124,7 @@ static if (ENABLE_OPENGL) {
|
|||
}
|
||||
|
||||
/// constant for measureText maxWidth paramenter - to tell that all characters of text string should be measured.
|
||||
immutable int MAX_WIDTH_UNSPECIFIED = int.max;
|
||||
enum int MAX_WIDTH_UNSPECIFIED = int.max;
|
||||
|
||||
/** Instance of font with specific size, weight, face, etc.
|
||||
*
|
||||
|
@ -322,13 +322,20 @@ class Font : RefCountedObject {
|
|||
* tabOffset = when string is drawn not from left position, use to move tab stops left/right
|
||||
* textFlags = TextFlag bit set - to control underline, hotkey label processing, etc...
|
||||
************************************************************************/
|
||||
Point textSize(const dchar[] text, int maxWidth = MAX_WIDTH_UNSPECIFIED, int tabSize = 4, int tabOffset = 0, uint textFlags = 0) {
|
||||
if (_textSizeBuffer.length < text.length + 1)
|
||||
_textSizeBuffer.length = text.length + 1;
|
||||
int charsMeasured = measureText(text, _textSizeBuffer, maxWidth, tabSize, tabOffset, textFlags);
|
||||
Point textSize(dstring text, int maxWidth = MAX_WIDTH_UNSPECIFIED, int tabSize = 4, int tabOffset = 0, uint textFlags = 0) {
|
||||
return textSizeMemoized(this, text, maxWidth, tabSize, tabOffset, textFlags);
|
||||
}
|
||||
|
||||
import std.functional;
|
||||
alias textSizeMemoized = memoize!(Font.textSizeImpl);
|
||||
|
||||
static Point textSizeImpl(Font font, const dchar[] text, int maxWidth = MAX_WIDTH_UNSPECIFIED, int tabSize = 4, int tabOffset = 0, uint textFlags = 0) {
|
||||
if (font._textSizeBuffer.length < text.length + 1)
|
||||
font._textSizeBuffer.length = text.length + 1;
|
||||
int charsMeasured = font.measureText(text, font._textSizeBuffer, maxWidth, tabSize, tabOffset, textFlags);
|
||||
if (charsMeasured < 1)
|
||||
return Point(0,0);
|
||||
return Point(_textSizeBuffer[charsMeasured - 1], height);
|
||||
return Point(font._textSizeBuffer[charsMeasured - 1], font.height);
|
||||
}
|
||||
|
||||
/*****************************************************************************************
|
||||
|
|
|
@ -622,7 +622,11 @@ private void FillColor(uint color, Color[] buf_slice) {
|
|||
}
|
||||
}
|
||||
|
||||
private float[] convertColors(uint[] cols) pure nothrow {
|
||||
|
||||
import std.functional;
|
||||
alias convertColors = memoize!(convertColorsImpl);
|
||||
|
||||
float[] convertColorsImpl(uint[] cols) pure nothrow {
|
||||
float[] colors;
|
||||
colors.length = cols.length * 4;
|
||||
foreach(i; 0 .. cols.length) {
|
||||
|
|
|
@ -410,7 +410,7 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction
|
|||
foreach(ref ch; s)
|
||||
ch = '9';
|
||||
FontRef fnt = font;
|
||||
Point sz = fnt.textSize(s);
|
||||
Point sz = fnt.textSize(cast(immutable)s);
|
||||
_lineNumbersWidth = sz.x;
|
||||
}
|
||||
_leftPaneWidth = _lineNumbersWidth + _modificationMarksWidth + _foldingWidth + _iconsWidth;
|
||||
|
@ -765,7 +765,7 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction
|
|||
return _wantTabs;
|
||||
}
|
||||
|
||||
/// sets tab size (in number of spaces)
|
||||
/// ditto
|
||||
@property EditWidgetBase wantTabs(bool wantTabs) {
|
||||
_wantTabs = wantTabs;
|
||||
return this;
|
||||
|
@ -1884,7 +1884,6 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction
|
|||
EditOperation op = new EditOperation(EditAction.Replace, _selectionRange, [event.text]);
|
||||
_content.performOperation(op, this);
|
||||
}
|
||||
if (focused) startCaretBlinking();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1894,9 +1893,7 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction
|
|||
//if (event.keyCode == KeyCode.RETURN && !readOnly && !_content.multiline) {
|
||||
// return true;
|
||||
//}
|
||||
bool res = super.onKeyEvent(event);
|
||||
//if (focused) startCaretBlinking();
|
||||
return res;
|
||||
return super.onKeyEvent(event);
|
||||
}
|
||||
|
||||
/// Handle Ctrl + Left mouse click on text
|
||||
|
@ -2166,6 +2163,9 @@ class EditLine : EditWidgetBase {
|
|||
|
||||
/// measure
|
||||
override void measure(int parentWidth, int parentHeight) {
|
||||
if (visibility == Visibility.Gone)
|
||||
return;
|
||||
|
||||
updateFontProps();
|
||||
measureVisibleText();
|
||||
measureTextToSetWidgetSize();
|
||||
|
@ -2242,11 +2242,9 @@ class EditLine : EditWidgetBase {
|
|||
// line inside selection
|
||||
Rect startrc = textPosToClient(_selectionRange.start);
|
||||
Rect endrc = textPosToClient(_selectionRange.end);
|
||||
int startx = startrc.left + _clientRect.left;
|
||||
int endx = endrc.left + _clientRect.left;
|
||||
Rect rc = lineRect;
|
||||
rc.left = startx;
|
||||
rc.right = endx;
|
||||
rc.left = startrc.left + _clientRect.left;
|
||||
rc.right = endrc.left + _clientRect.left;
|
||||
if (!rc.empty) {
|
||||
// draw selection rect for line
|
||||
buf.fillRect(rc, focused ? _selectionColorFocused : _selectionColorNormal);
|
||||
|
@ -2269,17 +2267,11 @@ class EditLine : EditWidgetBase {
|
|||
applyMargins(rc);
|
||||
applyPadding(rc);
|
||||
auto saver = ClipRectSaver(buf, rc, alpha);
|
||||
|
||||
FontRef font = font();
|
||||
dstring txt = applyPasswordChar(text);
|
||||
Point sz = font.textSize(txt);
|
||||
//applyAlign(rc, sz);
|
||||
Rect lineRect = _clientRect;
|
||||
lineRect.left = _clientRect.left - _scrollPos.x;
|
||||
lineRect.right = lineRect.left + calcLineWidth(txt);
|
||||
Rect visibleRect = lineRect;
|
||||
visibleRect.left = _clientRect.left;
|
||||
visibleRect.right = _clientRect.right;
|
||||
drawLineBackground(buf, lineRect, visibleRect);
|
||||
|
||||
drawLineBackground(buf, _clientRect, _clientRect);
|
||||
font.drawText(buf, rc.left - _scrollPos.x, rc.top, txt, textColor, tabSize);
|
||||
|
||||
drawCaret(buf);
|
||||
|
@ -2366,9 +2358,9 @@ class EditBox : EditWidgetBase {
|
|||
|
||||
/// Set widget rectangle to specified value and layout widget contents. (Step 2 of two phase layout).
|
||||
override void layout(Rect rc) {
|
||||
if (visibility == Visibility.Gone) {
|
||||
if (visibility == Visibility.Gone)
|
||||
return;
|
||||
}
|
||||
|
||||
if (rc != _pos)
|
||||
_contentChanged = true;
|
||||
Rect contentRc = rc;
|
||||
|
@ -2928,9 +2920,9 @@ class EditBox : EditWidgetBase {
|
|||
|
||||
/// measure
|
||||
override void measure(int parentWidth, int parentHeight) {
|
||||
if (visibility == Visibility.Gone) {
|
||||
if (visibility == Visibility.Gone)
|
||||
return;
|
||||
}
|
||||
|
||||
updateFontProps();
|
||||
updateMaxLineWidth();
|
||||
int findPanelHeight;
|
||||
|
@ -3341,7 +3333,7 @@ class EditBox : EditWidgetBase {
|
|||
FontRef font = font();
|
||||
for (int i = 0; i < _visibleLines.length; i++) {
|
||||
dstring txt = _visibleLines[i];
|
||||
Rect lineRect = rc;
|
||||
Rect lineRect;
|
||||
lineRect.left = _clientRect.left - _scrollPos.x;
|
||||
lineRect.right = lineRect.left + calcLineWidth(_content[_firstVisibleLine + i]);
|
||||
lineRect.top = _clientRect.top + i * _lineHeight;
|
||||
|
@ -3558,9 +3550,9 @@ class LogWidget : EditBox {
|
|||
|
||||
/// Set widget rectangle to specified value and layout widget contents. (Step 2 of two phase layout).
|
||||
override void layout(Rect rc) {
|
||||
if (visibility == Visibility.Gone) {
|
||||
if (visibility == Visibility.Gone)
|
||||
return;
|
||||
}
|
||||
|
||||
super.layout(rc);
|
||||
if (_scrollLock) {
|
||||
measureVisibleText();
|
||||
|
|
|
@ -53,6 +53,7 @@ class TabItem {
|
|||
private UIString _label;
|
||||
private UIString _tooltipText;
|
||||
private long _lastAccessTs;
|
||||
|
||||
this(string id, string labelRes, string iconRes = null, dstring tooltipText = null) {
|
||||
_id = id;
|
||||
_label.id = labelRes;
|
||||
|
@ -73,6 +74,7 @@ class TabItem {
|
|||
_lastAccessTs = _lastAccessCounter++;
|
||||
_tooltipText = UIString.fromRaw(tooltipText);
|
||||
}
|
||||
|
||||
@property string iconId() const { return _iconRes; }
|
||||
@property string id() const { return _id; }
|
||||
@property ref UIString text() { return _label; }
|
||||
|
@ -83,6 +85,7 @@ class TabItem {
|
|||
void updateAccessTs() {
|
||||
_lastAccessTs = _lastAccessCounter++; //std.datetime.Clock.currStdTime;
|
||||
}
|
||||
|
||||
/// tooltip text
|
||||
@property dstring tooltipText() {
|
||||
if (_tooltipText.empty)
|
||||
|
@ -123,6 +126,7 @@ class TabItemWidget : HorizontalLayout {
|
|||
Signal!TabCloseHandler tabClose;
|
||||
@property TabItem tabItem() { return _item; }
|
||||
@property TabControl tabControl() { return cast(TabControl)parent; }
|
||||
|
||||
this(TabItem item, bool enableCloseButton = true) {
|
||||
styleId = STYLE_TAB_UP_BUTTON;
|
||||
_enableCloseButton = enableCloseButton;
|
||||
|
@ -153,6 +157,7 @@ class TabItemWidget : HorizontalLayout {
|
|||
if (_closeButton)
|
||||
_closeButton.tooltipText = _item.tooltipText;
|
||||
}
|
||||
|
||||
/// tooltip text - when not empty, widget will show tooltips automatically; for advanced tooltips - override hasTooltip and createTooltip
|
||||
override @property dstring tooltipText() { return _item.tooltipText; }
|
||||
/// tooltip text - when not empty, widget will show tooltips automatically; for advanced tooltips - override hasTooltip and createTooltip
|
||||
|
@ -180,10 +185,12 @@ class TabItemWidget : HorizontalLayout {
|
|||
styleId = tabButtonStyle;
|
||||
_label.styleId = tabButtonTextStyle;
|
||||
}
|
||||
|
||||
override void onDraw(DrawBuf buf) {
|
||||
//debug Log.d("TabWidget.onDraw ", id);
|
||||
super.onDraw(buf);
|
||||
}
|
||||
|
||||
protected bool onClick(Widget source) {
|
||||
if (source.compareId("CLOSE")) {
|
||||
Log.d("tab close button pressed");
|
||||
|
@ -192,6 +199,7 @@ class TabItemWidget : HorizontalLayout {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@property TabItem item() {
|
||||
return _item;
|
||||
}
|
||||
|
@ -334,6 +342,7 @@ class TabControl : WidgetGroupDefaultDrawing {
|
|||
styleId = _tabStyle;
|
||||
addChild(_moreButton); // first child is always MORE button, the rest corresponds to tab list
|
||||
}
|
||||
|
||||
void setStyles(string tabStyle, string tabButtonStyle, string tabButtonTextStyle) {
|
||||
_tabStyle = tabStyle;
|
||||
_tabButtonStyle = tabButtonStyle;
|
||||
|
@ -533,6 +542,7 @@ class TabControl : WidgetGroupDefaultDrawing {
|
|||
TabItem item = new TabItem(id, label, iconId, tooltipText);
|
||||
return addTab(item, -1, enableCloseButton);
|
||||
}
|
||||
|
||||
protected MenuItem getMoreButtonPopupMenu() {
|
||||
if (moreButtonPopupMenu.assigned) {
|
||||
if (auto menu = moreButtonPopupMenu(this)) {
|
||||
|
@ -553,6 +563,7 @@ class TabControl : WidgetGroupDefaultDrawing {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// try to invoke popup menu, return true if popup menu is shown
|
||||
protected bool handleMorePopupMenu() {
|
||||
if (auto menu = getMoreButtonPopupMenu()) {
|
||||
|
@ -567,6 +578,7 @@ class TabControl : WidgetGroupDefaultDrawing {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// override to handle specific actions
|
||||
override bool handleAction(const Action a) {
|
||||
if (a.id == StandardAction.TabSelectItem) {
|
||||
|
@ -575,6 +587,7 @@ class TabControl : WidgetGroupDefaultDrawing {
|
|||
}
|
||||
return super.handleAction(a);
|
||||
}
|
||||
|
||||
protected bool onMouse(Widget source, MouseEvent event) {
|
||||
if (event.action == MouseAction.ButtonDown && event.button == MouseButton.Left) {
|
||||
if (source.compareId("MORE")) {
|
||||
|
@ -594,6 +607,7 @@ class TabControl : WidgetGroupDefaultDrawing {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Measure widget according to desired width and height constraints. (Step 1 of two phase layout).
|
||||
override void measure(int parentWidth, int parentHeight) {
|
||||
//Log.d("tabControl.measure enter");
|
||||
|
@ -627,6 +641,7 @@ class TabControl : WidgetGroupDefaultDrawing {
|
|||
measuredContent(parentWidth, parentHeight, sz.x, sz.y);
|
||||
//Log.d("tabControl.measure exit");
|
||||
}
|
||||
|
||||
/// Set widget rectangle to specified value and layout widget contents. (Step 2 of two phase layout).
|
||||
override void layout(Rect rc) {
|
||||
//Log.d("tabControl.layout enter");
|
||||
|
@ -736,7 +751,6 @@ class TabControl : WidgetGroupDefaultDrawing {
|
|||
if (tabChanged.assigned)
|
||||
tabChanged(_selectedTabId, previousSelectedTab);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// container for widgets controlled by TabControl
|
||||
|
@ -799,6 +813,7 @@ class TabHost : FrameLayout, TabHandler {
|
|||
requestLayout();
|
||||
return this;
|
||||
}
|
||||
|
||||
/// add new tab by id and label string
|
||||
TabHost addTab(Widget widget, dstring label, string iconId = null, bool enableCloseButton = false, dstring tooltipText = null) {
|
||||
assert(_tabControl !is null, "No TabControl set for TabHost");
|
||||
|
@ -810,6 +825,7 @@ class TabHost : FrameLayout, TabHandler {
|
|||
addChild(widget);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// add new tab by id and label string resource id
|
||||
TabHost addTab(Widget widget, string labelResourceId, string iconId = null, bool enableCloseButton = false, dstring tooltipText = null) {
|
||||
assert(_tabControl !is null, "No TabControl set for TabHost");
|
||||
|
|
|
@ -366,7 +366,7 @@ public:
|
|||
requestLayout();
|
||||
return this;
|
||||
}
|
||||
immutable static int FOCUS_RECT_PADDING = 2;
|
||||
static enum FOCUS_RECT_PADDING = 2;
|
||||
/// get padding (between background bounds and content of widget)
|
||||
@property Rect padding() const {
|
||||
// get max padding from style padding and background drawable padding
|
||||
|
@ -640,16 +640,16 @@ public:
|
|||
/// returns widget visibility (Visible, Invisible, Gone)
|
||||
@property Visibility visibility() { return _visibility; }
|
||||
/// sets widget visibility (Visible, Invisible, Gone)
|
||||
@property Widget visibility(Visibility visible) {
|
||||
if (_visibility != visible) {
|
||||
if ((_visibility == Visibility.Gone) || (visible == Visibility.Gone)) {
|
||||
@property Widget visibility(Visibility newVisibility) {
|
||||
if (_visibility != newVisibility) {
|
||||
if ((_visibility == Visibility.Gone) || (newVisibility == Visibility.Gone)) {
|
||||
if (parent)
|
||||
parent.requestLayout();
|
||||
else
|
||||
requestLayout();
|
||||
} else
|
||||
invalidate();
|
||||
_visibility = visible;
|
||||
_visibility = newVisibility;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
@ -868,9 +868,9 @@ public:
|
|||
this.rect = widget.pos;
|
||||
}
|
||||
static if (BACKEND_GUI) {
|
||||
static immutable int NEAR_THRESHOLD = 10;
|
||||
static enum NEAR_THRESHOLD = 10;
|
||||
} else {
|
||||
static immutable int NEAR_THRESHOLD = 1;
|
||||
static enum NEAR_THRESHOLD = 1;
|
||||
}
|
||||
bool nearX(TabOrderInfo v) {
|
||||
return v.rect.left >= rect.left - NEAR_THRESHOLD && v.rect.left <= rect.left + NEAR_THRESHOLD;
|
||||
|
|
Loading…
Reference in New Issue