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];
|
||||
for (size_t i = index; i + 1 < _len; i++)
|
||||
_items[i] = _items[i + 1];
|
||||
_items[_len] = T.init;
|
||||
_len--;
|
||||
_items[_len] = T.init;
|
||||
return result;
|
||||
}
|
||||
/// 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);
|
||||
}
|
||||
|
||||
/// peek first item
|
||||
@property T peekFront() {
|
||||
if (empty)
|
||||
return T.init; // no items
|
||||
return _items[0];
|
||||
}
|
||||
|
||||
/// insert item at beginning of collection
|
||||
void pushFront(T item) {
|
||||
add(item, 0);
|
||||
|
@ -197,6 +204,13 @@ struct Collection(T, bool ownItems = false) {
|
|||
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
|
||||
void pushBack(T item) {
|
||||
add(item);
|
||||
|
|
|
@ -325,6 +325,8 @@ enum EditAction {
|
|||
|
||||
/// replace whole content
|
||||
ReplaceContent,
|
||||
/// saved content
|
||||
SaveContent,
|
||||
}
|
||||
|
||||
/// edit operation details for EditableContent
|
||||
|
@ -451,6 +453,18 @@ class UndoBuffer {
|
|||
void clear() {
|
||||
_undoList.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);
|
||||
}
|
||||
|
||||
/// Modified state change listener
|
||||
interface ModifiedStateListener {
|
||||
void onModifiedStateChange(Widget source, bool modified);
|
||||
}
|
||||
|
||||
alias TokenPropString = ubyte[];
|
||||
|
||||
/// interface for custom syntax highlight
|
||||
|
@ -476,6 +495,10 @@ class EditableContent {
|
|||
_undoBuffer = new UndoBuffer();
|
||||
}
|
||||
|
||||
@property bool modified() {
|
||||
return _undoBuffer.modified;
|
||||
}
|
||||
|
||||
protected UndoBuffer _undoBuffer;
|
||||
|
||||
protected SyntaxHighlighter _syntaxHighlighter;
|
||||
|
@ -547,6 +570,14 @@ class EditableContent {
|
|||
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) {
|
||||
clearTokenProps(startLine, endLine);
|
||||
if (_syntaxHighlighter) {
|
||||
|
@ -926,8 +957,8 @@ class EditableContent {
|
|||
op.newRange = rangeAfter;
|
||||
op.oldContent = oldcontent;
|
||||
replaceRange(rangeBefore, rangeAfter, newcontent);
|
||||
handleContentChange(op, rangeBefore, rangeAfter, source);
|
||||
_undoBuffer.saveForUndo(op);
|
||||
handleContentChange(op, rangeBefore, rangeAfter, source);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -1013,6 +1044,7 @@ class EditableContent {
|
|||
}
|
||||
// EOF
|
||||
_format = lines.textFormat;
|
||||
_undoBuffer.clear();
|
||||
notifyContentReplaced();
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
|
@ -1047,7 +1079,8 @@ class EditableContent {
|
|||
for (int i = 0; i < _lines.length; i++) {
|
||||
writer.writeLine(_lines[i]);
|
||||
}
|
||||
// EOF
|
||||
_undoBuffer.saved();
|
||||
notifyContentSaved();
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
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 _modificationMarksPaneWidth = 8;
|
||||
|
||||
/// Modified state change listener
|
||||
Signal!ModifiedStateListener onModifiedStateChangeListener;
|
||||
|
||||
/// override to support modification of client rect after change, e.g. apply offset
|
||||
override protected void handleClientRectLayout(ref Rect rc) {
|
||||
updateLeftPaneWidth();
|
||||
|
@ -1470,6 +1506,8 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction
|
|||
ensureCaretVisible();
|
||||
correctCaretPos();
|
||||
requestLayout();
|
||||
} else if (operation.action == EditAction.SaveContent) {
|
||||
// saved
|
||||
} else {
|
||||
_caretPos = rangeAfter.end;
|
||||
_selectionRange.start = _caretPos;
|
||||
|
@ -1481,9 +1519,15 @@ class EditWidgetBase : ScrollWidgetBase, EditableContentListener, MenuItemAction
|
|||
// TODO: do something better (e.g. take into account ranges when correcting)
|
||||
}
|
||||
invalidate();
|
||||
if (onModifiedStateChangeListener.assigned) {
|
||||
if (_lastReportedModifiedState != content.modified) {
|
||||
_lastReportedModifiedState = content.modified;
|
||||
onModifiedStateChangeListener(this, content.modified);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
protected bool _lastReportedModifiedState;
|
||||
|
||||
/// get widget text
|
||||
override @property dstring text() { return _content.text; }
|
||||
|
|
|
@ -122,7 +122,10 @@ class TabItemWidget : HorizontalLayout {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
protected void setItem(TabItem item) {
|
||||
@property TabItem item() {
|
||||
return _item;
|
||||
}
|
||||
@property void setItem(TabItem item) {
|
||||
_item = item;
|
||||
if (item.iconId !is null) {
|
||||
_icon.visibility = Visibility.Visible;
|
||||
|
@ -304,6 +307,29 @@ class TabControl : WidgetGroupDefaultDrawing {
|
|||
}
|
||||
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
|
||||
TabControl addTab(TabItem item, int index = -1, bool enableCloseButton = false) {
|
||||
_items.insert(item, index);
|
||||
|
@ -587,6 +613,16 @@ class TabWidget : VerticalLayout, TabHandler {
|
|||
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
|
||||
void selectTab(string ID, bool updateAccess = true) {
|
||||
_tabHost.selectTab(ID, updateAccess);
|
||||
|
|
Loading…
Reference in New Issue