Decoupled History from QML
This commit is contained in:
parent
54363b25bc
commit
2dc9234b22
10 changed files with 239 additions and 191 deletions
|
@ -76,18 +76,16 @@ MenuBar {
|
|||
Action {
|
||||
text: qsTr("&Undo")
|
||||
shortcut: StandardKey.Undo
|
||||
onTriggered: history.undo()
|
||||
onTriggered: Modules.History.undo()
|
||||
icon.name: 'edit-undo'
|
||||
icon.color: enabled ? sysPalette.windowText : sysPaletteIn.windowText
|
||||
enabled: history.undoCount > 0
|
||||
}
|
||||
Action {
|
||||
text: qsTr("&Redo")
|
||||
shortcut: StandardKey.Redo
|
||||
onTriggered: history.redo()
|
||||
onTriggered: Modules.History.redo()
|
||||
icon.name: 'edit-redo'
|
||||
icon.color: enabled ? sysPalette.windowText : sysPaletteIn.windowText
|
||||
enabled: history.redoCount > 0
|
||||
}
|
||||
Action {
|
||||
text: qsTr("&Copy plot")
|
||||
|
|
|
@ -64,10 +64,7 @@ Item {
|
|||
Clears both undo and redo stacks completly.
|
||||
*/
|
||||
function clear() {
|
||||
undoCount = 0
|
||||
redoCount = 0
|
||||
undoStack = []
|
||||
redoStack = []
|
||||
Modules.History.clear()
|
||||
}
|
||||
|
||||
|
||||
|
@ -76,18 +73,7 @@ Item {
|
|||
Serializes history into JSON-able content.
|
||||
*/
|
||||
function serialize() {
|
||||
let undoSt = [], redoSt = [];
|
||||
for(let i = 0; i < undoCount; i++)
|
||||
undoSt.push([
|
||||
undoStack[i].type(),
|
||||
undoStack[i].export()
|
||||
]);
|
||||
for(let i = 0; i < redoCount; i++)
|
||||
redoSt.push([
|
||||
redoStack[i].type(),
|
||||
redoStack[i].export()
|
||||
]);
|
||||
return [undoSt, redoSt]
|
||||
return Modules.History.serialize()
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -95,14 +81,7 @@ Item {
|
|||
Unserializes both \c undoSt stack and \c redoSt stack from serialized content.
|
||||
*/
|
||||
function unserialize(undoSt, redoSt) {
|
||||
clear();
|
||||
for(let i = 0; i < undoSt.length; i++)
|
||||
undoStack.push(new JS.HistoryLib.Actions[undoSt[i][0]](...undoSt[i][1]))
|
||||
for(let i = 0; i < redoSt.length; i++)
|
||||
redoStack.push(new JS.HistoryLib.Actions[redoSt[i][0]](...redoSt[i][1]))
|
||||
undoCount = undoSt.length;
|
||||
redoCount = redoSt.length;
|
||||
objectLists.update()
|
||||
Modules.History.unserialize(undoSt, redoSt)
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -110,16 +89,7 @@ Item {
|
|||
Adds an instance of HistoryLib.Action to history.
|
||||
*/
|
||||
function addToHistory(action) {
|
||||
if(action instanceof JS.HistoryLib.Action) {
|
||||
console.log("Added new entry to history: " + action.getReadableString())
|
||||
undoStack.push(action)
|
||||
undoCount++;
|
||||
if(Helper.getSettingBool("reset_redo_stack")) {
|
||||
redoStack = []
|
||||
redoCount = 0
|
||||
}
|
||||
saved = false
|
||||
}
|
||||
Modules.History.addToHistory(action)
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -128,16 +98,7 @@ Item {
|
|||
By default, will update the graph and the object list. This behavior can be disabled by setting the \c updateObjectList to false.
|
||||
*/
|
||||
function undo(updateObjectList = true) {
|
||||
if(undoStack.length > 0) {
|
||||
var action = undoStack.pop()
|
||||
action.undo()
|
||||
if(updateObjectList)
|
||||
objectLists.update()
|
||||
redoStack.push(action)
|
||||
undoCount--;
|
||||
redoCount++;
|
||||
saved = false
|
||||
}
|
||||
Modules.History.undo()
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -146,77 +107,6 @@ Item {
|
|||
By default, will update the graph and the object list. This behavior can be disabled by setting the \c updateObjectList to false.
|
||||
*/
|
||||
function redo(updateObjectList = true) {
|
||||
if(redoStack.length > 0) {
|
||||
var action = redoStack.pop()
|
||||
action.redo()
|
||||
if(updateObjectList)
|
||||
objectLists.update()
|
||||
undoStack.push(action)
|
||||
undoCount++;
|
||||
redoCount--;
|
||||
saved = false
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\qmlmethod void History::undoMultipleDefered(int toUndoCount)
|
||||
Undoes several HistoryLib.Action at the top of the undo stack and pushes them to the top of the redo stack.
|
||||
It undoes them deferedly to avoid overwhelming the computer while creating a cool short accelerated summary of all changes.
|
||||
*/
|
||||
function undoMultipleDefered(toUndoCount) {
|
||||
undoTimer.toUndoCount = toUndoCount;
|
||||
undoTimer.start()
|
||||
if(toUndoCount > 0)
|
||||
saved = false
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
\qmlmethod void History::redoMultipleDefered(int toRedoCount)
|
||||
Redoes several HistoryLib.Action at the top of the redo stack and pushes them to the top of the undo stack.
|
||||
It redoes them deferedly to avoid overwhelming the computer while creating a cool short accelerated summary of all changes.
|
||||
*/
|
||||
function redoMultipleDefered(toRedoCount) {
|
||||
redoTimer.toRedoCount = toRedoCount;
|
||||
redoTimer.start()
|
||||
if(toRedoCount > 0)
|
||||
saved = false
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: undoTimer
|
||||
interval: 5; running: false; repeat: true
|
||||
property int toUndoCount: 0
|
||||
onTriggered: {
|
||||
if(toUndoCount > 0) {
|
||||
historyObj.undo(toUndoCount % 4 == 1) // Only redraw once every 4 changes.
|
||||
toUndoCount--;
|
||||
} else {
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: redoTimer
|
||||
interval: 5; running: false; repeat: true
|
||||
property int toRedoCount: 0
|
||||
onTriggered: {
|
||||
if(toRedoCount > 0) {
|
||||
historyObj.redo(toRedoCount % 4 == 1) // Only redraw once every 4 changes.
|
||||
toRedoCount--;
|
||||
} else {
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
Modules.History.initialize({
|
||||
historyObj,
|
||||
themeTextColor: sysPalette.windowText.toString(),
|
||||
imageDepth: Screen.devicePixelRatio,
|
||||
fontSize: 14
|
||||
})
|
||||
Modules.History.redo()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick.Controls
|
||||
import QtQuick
|
||||
import eu.ad5001.LogarithmPlotter.Setting 1.0 as Setting
|
||||
|
@ -46,6 +48,18 @@ Item {
|
|||
true when the system is running with a dark theme, false otherwise.
|
||||
*/
|
||||
property bool darkTheme: isDarkTheme()
|
||||
|
||||
/*!
|
||||
\qmlproperty int HistoryBrowser::undoCount
|
||||
Number of actions in the undo stack.
|
||||
*/
|
||||
property int undoCount: 0
|
||||
|
||||
/*!
|
||||
\qmlproperty int HistoryBrowser::redoCount
|
||||
Number of actions in the redo stack.
|
||||
*/
|
||||
property int redoCount: 0
|
||||
|
||||
Setting.TextSetting {
|
||||
id: filterInput
|
||||
|
@ -76,19 +90,22 @@ Item {
|
|||
id: redoColumn
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
width: actionWidth
|
||||
width: historyBrowser.actionWidth
|
||||
|
||||
Repeater {
|
||||
model: history.redoCount
|
||||
model: historyBrowser.redoCount
|
||||
|
||||
HistoryItem {
|
||||
id: redoButton
|
||||
width: actionWidth
|
||||
width: historyBrowser.actionWidth
|
||||
//height: actionHeight
|
||||
isRedo: true
|
||||
idx: index
|
||||
darkTheme: historyBrowser.darkTheme
|
||||
hidden: !(filterInput.value == "" || content.includes(filterInput.value))
|
||||
onClicked: {
|
||||
redoTimer.toRedoCount = Modules.History.redoStack.length-index
|
||||
redoTimer.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -101,14 +118,14 @@ Item {
|
|||
transform: Rotation { origin.x: 30; origin.y: 30; angle: 270}
|
||||
height: 70
|
||||
width: 20
|
||||
visible: history.redoCount > 0
|
||||
visible: historyBrowser.redoCount > 0
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: nowRect
|
||||
anchors.right: parent.right
|
||||
anchors.top: redoColumn.bottom
|
||||
width: actionWidth
|
||||
width: historyBrowser.actionWidth
|
||||
height: 40
|
||||
color: sysPalette.highlight
|
||||
Text {
|
||||
|
@ -124,20 +141,24 @@ Item {
|
|||
id: undoColumn
|
||||
anchors.right: parent.right
|
||||
anchors.top: nowRect.bottom
|
||||
width: actionWidth
|
||||
width: historyBrowser.actionWidth
|
||||
|
||||
Repeater {
|
||||
model: history.undoCount
|
||||
model: historyBrowser.undoCount
|
||||
|
||||
|
||||
HistoryItem {
|
||||
id: undoButton
|
||||
width: actionWidth
|
||||
width: historyBrowser.actionWidth
|
||||
//height: actionHeight
|
||||
isRedo: false
|
||||
idx: index
|
||||
darkTheme: historyBrowser.darkTheme
|
||||
hidden: !(filterInput.value == "" || content.includes(filterInput.value))
|
||||
|
||||
onClicked: {
|
||||
undoTimer.toUndoCount = +index+1
|
||||
undoTimer.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -150,7 +171,39 @@ Item {
|
|||
transform: Rotation { origin.x: 30; origin.y: 30; angle: 270}
|
||||
height: 60
|
||||
width: 20
|
||||
visible: history.undoCount > 0
|
||||
visible: historyBrowser.undoCount > 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: undoTimer
|
||||
interval: 5; running: false; repeat: true
|
||||
property int toUndoCount: 0
|
||||
onTriggered: {
|
||||
if(toUndoCount > 0) {
|
||||
Modules.History.undo()
|
||||
if(toUndoCount % 3 === 1)
|
||||
Modules.Canvas.requestPaint()
|
||||
toUndoCount--;
|
||||
} else {
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: redoTimer
|
||||
interval: 5; running: false; repeat: true
|
||||
property int toRedoCount: 0
|
||||
onTriggered: {
|
||||
if(toRedoCount > 0) {
|
||||
Modules.History.redo()
|
||||
if(toRedoCount % 3 === 1)
|
||||
Modules.Canvas.requestPaint()
|
||||
toRedoCount--;
|
||||
} else {
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -163,6 +216,18 @@ Item {
|
|||
let hex = sysPalette.windowText.toString()
|
||||
// We only check the first parameter, as on all normal OSes, text color is grayscale.
|
||||
return parseInt(hex.substr(1,2), 16) > 128
|
||||
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
Modules.History.initialize({
|
||||
helper: Helper,
|
||||
themeTextColor: sysPalette.windowText.toString(),
|
||||
imageDepth: Screen.devicePixelRatio,
|
||||
fontSize: 14
|
||||
})
|
||||
Modules.History.on("updated undone redone", () => {
|
||||
undoCount = Modules.History.undoStack.length
|
||||
redoCount = Modules.History.redoStack.length
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,17 +41,17 @@ Button {
|
|||
\qmlproperty bool HistoryItem::isRedo
|
||||
true if the action is in the redo stack, false othewise.
|
||||
*/
|
||||
property bool isRedo
|
||||
required property bool isRedo
|
||||
/*!
|
||||
\qmlproperty int HistoryItem::idx
|
||||
\qmlproperty int HistoryItem::index
|
||||
Index of the item within the HistoryBrowser list.
|
||||
*/
|
||||
property int idx
|
||||
required property int index
|
||||
/*!
|
||||
\qmlproperty bool HistoryItem::darkTheme
|
||||
true when the system is running with a dark theme, false otherwise.
|
||||
*/
|
||||
property bool darkTheme
|
||||
required property bool darkTheme
|
||||
/*!
|
||||
\qmlproperty bool HistoryItem::hidden
|
||||
true when the item is filtered out, false otherwise.
|
||||
|
@ -61,7 +61,7 @@ Button {
|
|||
\qmlproperty int HistoryItem::historyAction
|
||||
Associated history action.
|
||||
*/
|
||||
readonly property var historyAction: isRedo ? history.redoStack[idx] : history.undoStack[history.undoCount-idx-1]
|
||||
readonly property var historyAction: isRedo ? Modules.History.redoStack.at(index) : Modules.History.undoStack.at(-index-1)
|
||||
|
||||
/*!
|
||||
\qmlproperty int HistoryItem::actionHeight
|
||||
|
@ -147,13 +147,6 @@ Button {
|
|||
ToolTip.visible: hovered
|
||||
ToolTip.delay: 200
|
||||
ToolTip.text: content
|
||||
|
||||
onClicked: {
|
||||
if(isRedo)
|
||||
history.redoMultipleDefered(history.redoCount-idx)
|
||||
else
|
||||
history.undoMultipleDefered(+idx+1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue