mirror of https://github.com/buggins/dlangui.git
collections: crash fixed; editors: notify about modified state change; tabs: allow renaming tab:
This commit is contained in:
parent
d46febac11
commit
90e6d7e49c
|
@ -137,8 +137,8 @@ struct Collection(T, bool ownItems = false) {
|
||||||
T result = _items[index];
|
T result = _items[index];
|
||||||
for (size_t i = index; i + 1 < _len; i++)
|
for (size_t i = index; i + 1 < _len; i++)
|
||||||
_items[i] = _items[i + 1];
|
_items[i] = _items[i + 1];
|
||||||
_items[_len] = T.init;
|
|
||||||
_len--;
|
_len--;
|
||||||
|
_items[_len] = T.init;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
/// remove single item by value - if present in collection, returning true if item was found and removed
|
/// remove single item by value - if present in collection, returning true if item was found and removed
|
||||||
|
@ -185,6 +185,13 @@ struct Collection(T, bool ownItems = false) {
|
||||||
return remove(0);
|
return remove(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// peek first item
|
||||||
|
@property T peekFront() {
|
||||||
|
if (empty)
|
||||||
|
return T.init; // no items
|
||||||
|
return _items[0];
|
||||||
|
}
|
||||||
|
|
||||||
/// insert item at beginning of collection
|
/// insert item at beginning of collection
|
||||||
void pushFront(T item) {
|
void pushFront(T item) {
|
||||||
add(item, 0);
|
add(item, 0);
|
||||||
|
@ -197,6 +204,13 @@ struct Collection(T, bool ownItems = false) {
|
||||||
return remove(length - 1);
|
return remove(length - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// peek last item
|
||||||
|
@property T peekBack() {
|
||||||
|
if (empty)
|
||||||
|
return T.init; // no items
|
||||||
|
return _items[length - 1];
|
||||||
|
}
|
||||||
|
|
||||||
/// insert item at end of collection
|
/// insert item at end of collection
|
||||||
void pushBack(T item) {
|
void pushBack(T item) {
|
||||||
add(item);
|
add(item);
|
||||||
|
|
|
@ -325,6 +325,8 @@ enum EditAction {
|
||||||
|
|
||||||
/// replace whole content
|
/// replace whole content
|
||||||
ReplaceContent,
|
ReplaceContent,
|
||||||
|
/// saved content
|
||||||
|
SaveContent,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// edit operation details for EditableContent
|
/// edit operation details for EditableContent
|
||||||
|
@ -451,6 +453,18 @@ class UndoBuffer {
|
||||||
void clear() {
|
void clear() {
|
||||||
_undoList.clear();
|
_undoList.clear();
|
||||||
_redoList.clear();
|
_redoList.clear();
|
||||||
|
_savedState = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected EditOperation _savedState;
|
||||||
|
|
||||||
|
/// current state is saved
|
||||||
|
void saved() {
|
||||||
|
_savedState = _undoList.peekBack;
|
||||||
|
}
|
||||||
|
/// returns true if content has been changed since last saved() or clear() call
|
||||||
|
@property bool modified() {
|
||||||
|
return _savedState !is _undoList.peekBack;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -459,6 +473,11 @@ interface EditableContentListener {
|
||||||
void onContentChange(EditableContent content, EditOperation operation, ref TextRange rangeBefore, ref TextRange rangeAfter, Object source);
|
void onContentChange(EditableContent content, EditOperation operation, ref TextRange rangeBefore, ref TextRange rangeAfter, Object source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Modified state change listener
|
||||||
|
interface ModifiedStateListener {
|
||||||
|
void onModifiedStateChange(Widget source, bool modified);
|
||||||
|
}
|
||||||
|
|
||||||
alias TokenPropString = ubyte[];
|
alias TokenPropString = ubyte[];
|
||||||
|
|
||||||
/// interface for custom syntax highlight
|
/// interface for custom syntax highlight
|
||||||
|
@ -476,6 +495,10 @@ class EditableContent {
|
||||||
_undoBuffer = new UndoBuffer();
|
_undoBuffer = new UndoBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@property bool modified() {
|
||||||
|
return _undoBuffer.modified;
|
||||||
|
}
|
||||||
|
|
||||||
protected UndoBuffer _undoBuffer;
|
protected UndoBuffer _undoBuffer;
|
||||||
|
|
||||||
protected SyntaxHighlighter _syntaxHighlighter;
|
protected SyntaxHighlighter _syntaxHighlighter;
|
||||||
|
@ -547,6 +570,14 @@ class EditableContent {
|
||||||
handleContentChange(new EditOperation(EditAction.ReplaceContent), rangeBefore, rangeAfter, this);
|
handleContentChange(new EditOperation(EditAction.ReplaceContent), rangeBefore, rangeAfter, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// call listener to say that content is saved
|
||||||
|
void notifyContentSaved() {
|
||||||
|
TextRange rangeBefore;
|
||||||
|
TextRange rangeAfter;
|
||||||
|
// notify about content change
|
||||||
|
handleContentChange(new EditOperation(EditAction.SaveContent), rangeBefore, rangeAfter, this);
|
||||||
|
}
|
||||||
|
|
||||||
protected void updateTokenProps(int startLine, int endLine) {
|
protected void updateTokenProps(int startLine, int endLine) {
|
||||||
clearTokenProps(startLine, endLine);
|
clearTokenProps(startLine, endLine);
|
||||||
if (_syntaxHighlighter) {
|
if (_syntaxHighlighter) {
|
||||||
|
@ -926,8 +957,8 @@ class EditableContent {
|
||||||
op.newRange = rangeAfter;
|
op.newRange = rangeAfter;
|
||||||
op.oldContent = oldcontent;
|
op.oldContent = oldcontent;
|
||||||
replaceRange(rangeBefore, rangeAfter, newcontent);
|
replaceRange(rangeBefore, rangeAfter, newcontent);
|
||||||
handleContentChange(op, rangeBefore, rangeAfter, source);
|
|
||||||
_undoBuffer.saveForUndo(op);
|
_undoBuffer.saveForUndo(op);
|
||||||
|
handleContentChange(op, rangeBefore, rangeAfter, source);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -1013,6 +1044,7 @@ class EditableContent {
|
||||||
}
|
}
|
||||||
// EOF
|
// EOF
|
||||||
_format = lines.textFormat;
|
_format = lines.textFormat;
|
||||||
|
_undoBuffer.clear();
|
||||||
notifyContentReplaced();
|
notifyContentReplaced();
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -1047,7 +1079,8 @@ class EditableContent {
|
||||||
for (int i = 0; i < _lines.length; i++) {
|
for (int i = 0; i < _lines.length; i++) {
|
||||||
writer.writeLine(_lines[i]);
|
writer.writeLine(_lines[i]);
|
||||||
}
|
}
|
||||||
// EOF
|
_undoBuffer.saved();
|
||||||
|
notifyContentSaved();
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e("Exception while trying to write file ", filename, " ", e.toString);
|
Log.e("Exception while trying to write file ", filename, " ", e.toString);
|
||||||
|
@ -1116,6 +1149,9 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction
|
||||||
protected uint _foldingPaneWidth = 16;
|
protected uint _foldingPaneWidth = 16;
|
||||||
protected uint _modificationMarksPaneWidth = 8;
|
protected uint _modificationMarksPaneWidth = 8;
|
||||||
|
|
||||||
|
/// Modified state change listener
|
||||||
|
Signal!ModifiedStateListener onModifiedStateChangeListener;
|
||||||
|
|
||||||
/// override to support modification of client rect after change, e.g. apply offset
|
/// override to support modification of client rect after change, e.g. apply offset
|
||||||
override protected void handleClientRectLayout(ref Rect rc) {
|
override protected void handleClientRectLayout(ref Rect rc) {
|
||||||
updateLeftPaneWidth();
|
updateLeftPaneWidth();
|
||||||
|
@ -1470,6 +1506,8 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction
|
||||||
ensureCaretVisible();
|
ensureCaretVisible();
|
||||||
correctCaretPos();
|
correctCaretPos();
|
||||||
requestLayout();
|
requestLayout();
|
||||||
|
} else if (operation.action == EditAction.SaveContent) {
|
||||||
|
// saved
|
||||||
} else {
|
} else {
|
||||||
_caretPos = rangeAfter.end;
|
_caretPos = rangeAfter.end;
|
||||||
_selectionRange.start = _caretPos;
|
_selectionRange.start = _caretPos;
|
||||||
|
@ -1481,9 +1519,15 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction
|
||||||
// TODO: do something better (e.g. take into account ranges when correcting)
|
// TODO: do something better (e.g. take into account ranges when correcting)
|
||||||
}
|
}
|
||||||
invalidate();
|
invalidate();
|
||||||
|
if (onModifiedStateChangeListener.assigned) {
|
||||||
|
if (_lastReportedModifiedState != content.modified) {
|
||||||
|
_lastReportedModifiedState = content.modified;
|
||||||
|
onModifiedStateChangeListener(this, content.modified);
|
||||||
|
}
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
protected bool _lastReportedModifiedState;
|
||||||
|
|
||||||
/// get widget text
|
/// get widget text
|
||||||
override @property dstring text() { return _content.text; }
|
override @property dstring text() { return _content.text; }
|
||||||
|
|
|
@ -122,7 +122,10 @@ class TabItemWidget : HorizontalLayout {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
protected void setItem(TabItem item) {
|
@property TabItem item() {
|
||||||
|
return _item;
|
||||||
|
}
|
||||||
|
@property void setItem(TabItem item) {
|
||||||
_item = item;
|
_item = item;
|
||||||
if (item.iconId !is null) {
|
if (item.iconId !is null) {
|
||||||
_icon.visibility = Visibility.Visible;
|
_icon.visibility = Visibility.Visible;
|
||||||
|
@ -304,6 +307,29 @@ class TabControl : WidgetGroupDefaultDrawing {
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// change name of tab
|
||||||
|
void renameTab(string ID, dstring name) {
|
||||||
|
int index = _items.indexById(id);
|
||||||
|
if (index >= 0) {
|
||||||
|
renameTab(index, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// change name of tab
|
||||||
|
void renameTab(int index, dstring name) {
|
||||||
|
_items[index].text = name;
|
||||||
|
for (int i = 0; i < _children.count; i++) {
|
||||||
|
TabItemWidget widget = cast (TabItemWidget)_children[i];
|
||||||
|
if (widget && widget.item is _items[index]) {
|
||||||
|
widget.setItem(_items[index]);
|
||||||
|
requestLayout();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// add new tab
|
/// add new tab
|
||||||
TabControl addTab(TabItem item, int index = -1, bool enableCloseButton = false) {
|
TabControl addTab(TabItem item, int index = -1, bool enableCloseButton = false) {
|
||||||
_items.insert(item, index);
|
_items.insert(item, index);
|
||||||
|
@ -587,6 +613,16 @@ class TabWidget : VerticalLayout, TabHandler {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// change name of tab
|
||||||
|
void renameTab(string ID, dstring name) {
|
||||||
|
_tabControl.renameTab(ID, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// change name of tab
|
||||||
|
void renameTab(int index, dstring name) {
|
||||||
|
_tabControl.renameTab(index, name);
|
||||||
|
}
|
||||||
|
|
||||||
/// select tab
|
/// select tab
|
||||||
void selectTab(string ID, bool updateAccess = true) {
|
void selectTab(string ID, bool updateAccess = true) {
|
||||||
_tabHost.selectTab(ID, updateAccess);
|
_tabHost.selectTab(ID, updateAccess);
|
||||||
|
|
Loading…
Reference in New Issue