Browse Source

UI: Initial Undo/Redo

Starting to develop Undo/Redo. This just implmements the undo/redo stack
and its api.
Ford Smith 4 years ago
parent
commit
eced5a320b
3 changed files with 175 additions and 0 deletions
  1. 28 0
      UI/data/locale/en-US.ini
  2. 101 0
      UI/undo-stack-obs.cpp
  3. 46 0
      UI/undo-stack-obs.hpp

+ 28 - 0
UI/data/locale/en-US.ini

@@ -262,6 +262,34 @@ Basic.SceneTransitions="Scene Transitions"
 Basic.TransitionDuration="Duration"
 Basic.TogglePreviewProgramMode="Studio Mode"
 
+# undo
+Undo.Undo="Undo"
+Undo.Redo="Redo"
+Undo.Add="Add '%1'"
+Undo.Delete="Delete '%1'"
+Undo.Rename="Rename '%1'"
+Undo.SceneCollection.Switch="Switch to '%1'"
+Undo.Item.Undo="Undo %1"
+Undo.Item.Redo="Redo %1"
+Undo.Sources.Multi="Delete %1 Sources"
+Undo.Filters="Filter Changes on '%1'"
+Undo.Transform="Transform source(s) In '%1'"
+Undo.Transform.Paste="Paste Transformation in '%1'"
+Undo.Transform.Rotate="Rotation In '%1'"
+Undo.Transform.Reset="Transform Reset In '%1'"
+Undo.Transform.HFlip="Horizontal Flip In '%1'"
+Undo.Transform.VFlip="Vertical Flip In '%1'"
+Undo.Transform.FitToScren="Fit to Screen In '%1'"
+Undo.Transform.StretchToScreen="Stretch to Screen in '%1'"
+Undo.Transform.Center="Center to Screen in '%1'"
+Undo.Transform.VCenter="Vertical Center to Screen in '%1'"
+Undo.Transform.HCenter="Horizontal Center to Screen in '%1'"
+Undo.Volume.Change="Volume Change on '%1'"
+Undo.Audio="Audio Changes"
+Undo.Properties="Property Change on '%1'"
+Undo.Scene.Duplicate="Duplicate Scene '%1'"
+
+
 # transition name dialog
 TransitionNameDlg.Text="Please enter the name of the transition"
 TransitionNameDlg.Title="Transition Name"

+ 101 - 0
UI/undo-stack-obs.cpp

@@ -0,0 +1,101 @@
+#include "undo-stack-obs.hpp"
+
+#include <util/util.hpp>
+
+undo_stack::undo_stack(ui_ptr ui) : ui(ui) {}
+
+void undo_stack::release()
+{
+	for (auto f : undo_items)
+		if (f.d)
+			f.d(true);
+
+	for (auto f : redo_items)
+		if (f.d)
+			f.d(false);
+}
+
+void undo_stack::add_action(const QString &name, undo_redo_cb undo,
+			    undo_redo_cb redo, std::string undo_data,
+			    std::string redo_data, func d)
+{
+	undo_redo_t n = {name, undo_data, redo_data, undo, redo, d};
+
+	undo_items.push_front(n);
+	clear_redo();
+
+	ui->actionMainUndo->setText(QTStr("Undo.Item.Undo").arg(name));
+	ui->actionMainUndo->setEnabled(true);
+
+	ui->actionMainRedo->setText(QTStr("Undo.Redo"));
+	ui->actionMainRedo->setDisabled(true);
+}
+
+void undo_stack::undo()
+{
+	if (undo_items.size() == 0 || disabled)
+		return;
+
+	undo_redo_t temp = undo_items.front();
+	temp.undo(temp.undo_data);
+	redo_items.push_front(temp);
+	undo_items.pop_front();
+
+	ui->actionMainRedo->setText(QTStr("Undo.Item.Redo").arg(temp.name));
+	ui->actionMainRedo->setEnabled(true);
+
+	if (undo_items.size() == 0) {
+		ui->actionMainUndo->setDisabled(true);
+		ui->actionMainUndo->setText(QTStr("Undo.Undo"));
+	} else {
+		ui->actionMainUndo->setText(
+			QTStr("Undo.Item.Undo").arg(undo_items.front().name));
+	}
+}
+
+void undo_stack::redo()
+{
+	if (redo_items.size() == 0 || disabled)
+		return;
+
+	undo_redo_t temp = redo_items.front();
+	temp.redo(temp.redo_data);
+	undo_items.push_front(temp);
+	redo_items.pop_front();
+
+	ui->actionMainUndo->setText(QTStr("Undo.Item.Undo").arg(temp.name));
+	ui->actionMainUndo->setEnabled(true);
+
+	if (redo_items.size() == 0) {
+		ui->actionMainRedo->setDisabled(true);
+		ui->actionMainRedo->setText(QTStr("Undo.Redo"));
+	} else {
+		ui->actionMainRedo->setText(
+			QTStr("Undo.Item.Redo").arg(redo_items.front().name));
+	}
+}
+
+void undo_stack::enable_undo_redo()
+{
+	disabled = false;
+
+	ui->actionMainUndo->setDisabled(false);
+	ui->actionMainRedo->setDisabled(false);
+}
+
+void undo_stack::disable_undo_redo()
+{
+	disabled = true;
+
+	ui->actionMainUndo->setDisabled(true);
+	ui->actionMainRedo->setDisabled(true);
+}
+
+void undo_stack::clear_redo()
+{
+	for (auto f : redo_items)
+		if (f.d)
+			f.d(false);
+
+	redo_items.clear();
+}

+ 46 - 0
UI/undo-stack-obs.hpp

@@ -0,0 +1,46 @@
+#pragma once
+
+#include <QString>
+
+#include <deque>
+#include <functional>
+#include <string>
+#include <memory>
+
+#include "ui_OBSBasic.h"
+
+typedef std::function<void(const std::string &data)> undo_redo_cb;
+typedef std::function<void(bool is_undo)> func;
+typedef std::unique_ptr<Ui::OBSBasic> &ui_ptr;
+
+struct undo_redo_t {
+	QString name;
+	std::string undo_data;
+	std::string redo_data;
+	undo_redo_cb undo;
+	undo_redo_cb redo;
+	func d;
+};
+
+class undo_stack {
+private:
+	ui_ptr ui;
+	std::deque<undo_redo_t> undo_items;
+	std::deque<undo_redo_t> redo_items;
+	bool disabled = false;
+
+	void clear_redo();
+
+public:
+	undo_stack(ui_ptr ui);
+
+	void enable_undo_redo();
+	void disable_undo_redo();
+
+	void release();
+	void add_action(const QString &name, undo_redo_cb undo,
+			undo_redo_cb redo, std::string undo_data,
+			std::string redo_data, func d);
+	void undo();
+	void redo();
+};