forked from Aegisub/Aegisub
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathauto4_base.h
291 lines (233 loc) · 10.3 KB
/
auto4_base.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
// Copyright (c) 2006, Niels Martin Hansen
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Aegisub Project http://www.aegisub.org/
/// @file auto4_base.h
/// @see auto4_base.cpp
/// @ingroup scripting
///
#pragma once
#include <libaegisub/background_runner.h>
#include <libaegisub/exception.h>
#include <libaegisub/fs_fwd.h>
#include <libaegisub/signal.h>
#include "ass_export_filter.h"
#include <boost/filesystem/path.hpp>
#include <memory>
#include <vector>
class AssStyle;
class DialogProgress;
class wxWindow;
class wxDialog;
namespace agi { struct Context; }
namespace cmd { class Command; }
namespace Automation4 {
DEFINE_EXCEPTION(AutomationError, agi::Exception);
DEFINE_EXCEPTION(ScriptLoadError, AutomationError);
DEFINE_EXCEPTION(MacroRunError, AutomationError);
// Calculate the extents of a text string given a style
bool CalculateTextExtents(AssStyle *style, std::string const& text, double &width, double &height, double &descent, double &extlead);
class ScriptDialog;
class ExportFilter : public AssExportFilter {
std::unique_ptr<ScriptDialog> config_dialog;
/// subclasses should implement this, producing a new ScriptDialog
virtual std::unique_ptr<ScriptDialog> GenerateConfigDialog(wxWindow *parent, agi::Context *c) = 0;
protected:
std::string GetScriptSettingsIdentifier();
public:
ExportFilter(std::string const& name, std::string const& description, int priority);
wxWindow* GetConfigDialogWindow(wxWindow *parent, agi::Context *c) override;
void LoadSettings(bool is_default, agi::Context *c) override;
// Subclasses must implement ProcessSubs from AssExportFilter
};
/// A "dialog" which actually generates a non-top-level window that is then
/// either inserted into a dialog or into the export filter configuration
/// panel
class ScriptDialog {
public:
virtual ~ScriptDialog() = default;
/// Create a window with the given parent
virtual wxWindow *CreateWindow(wxWindow *parent) = 0;
/// Serialize the values of the controls in this dialog to a string
/// suitable for storage in the subtitle script
virtual std::string Serialise() { return ""; }
/// Restore the values of the controls in this dialog from a string
/// stored in the subtitle script
virtual void Unserialise(std::string const& serialised) { }
};
class ProgressSink;
class BackgroundScriptRunner {
std::unique_ptr<DialogProgress> impl;
public:
wxWindow *GetParentWindow() const;
std::string GetTitle() const;
void Run(std::function<void(ProgressSink*)> task);
BackgroundScriptRunner(wxWindow *parent, std::string const& title);
~BackgroundScriptRunner();
};
/// A wrapper around agi::ProgressSink which adds the ability to open
/// dialogs on the GUI thread
class ProgressSink final : public agi::ProgressSink {
agi::ProgressSink *impl;
BackgroundScriptRunner *bsr;
int trace_level;
public:
void SetIndeterminate() override { impl->SetIndeterminate(); }
void SetTitle(std::string const& title) override { impl->SetTitle(title); }
void SetMessage(std::string const& msg) override { impl->SetMessage(msg); }
void SetProgress(int64_t cur, int64_t max) override { impl->SetProgress(cur, max); }
void Log(std::string const& str) override { impl->Log(str); }
bool IsCancelled() override { return impl->IsCancelled(); }
/// Show the passed dialog on the GUI thread, blocking the calling
/// thread until it closes
void ShowDialog(ScriptDialog *config_dialog);
int ShowDialog(wxDialog *dialog);
wxWindow *GetParentWindow() const { return bsr->GetParentWindow(); }
/// Get the current automation trace level
int GetTraceLevel() const { return trace_level; }
ProgressSink(agi::ProgressSink *impl, BackgroundScriptRunner *bsr);
};
class Script {
agi::fs::path filename;
protected:
/// The automation include path, consisting of the user-specified paths
/// along with the script's path
std::vector<agi::fs::path> include_path;
Script(agi::fs::path const& filename);
public:
virtual ~Script() = default;
/// Reload this script
virtual void Reload() = 0;
/// The script's file name with path
agi::fs::path GetFilename() const { return filename; }
/// The script's file name without path
agi::fs::path GetPrettyFilename() const { return filename.filename(); }
/// The script's name. Not required to be unique.
virtual std::string GetName() const=0;
/// A short description of the script
virtual std::string GetDescription() const=0;
/// The author of the script
virtual std::string GetAuthor() const=0;
/// A version string that should not be used for anything but display
virtual std::string GetVersion() const=0;
/// Did the script load correctly?
virtual bool GetLoadedState() const=0;
/// Get a list of commands provided by this script
virtual std::vector<cmd::Command*> GetMacros() const=0;
/// Get a list of export filters provided by this script
virtual std::vector<ExportFilter*> GetFilters() const=0;
};
/// A manager of loaded automation scripts
class ScriptManager {
protected:
std::vector<std::unique_ptr<Script>> scripts;
std::vector<cmd::Command*> macros;
agi::signal::Signal<> ScriptsChanged;
public:
/// Deletes all scripts managed
virtual ~ScriptManager() = default;
/// Add a script to the manager.
void Add(std::unique_ptr<Script> script);
/// Remove a script from the manager, and delete the Script object.
void Remove(Script *script);
/// Deletes all scripts managed
void RemoveAll();
/// Reload all scripts managed
virtual void Reload() = 0;
/// Reload a single managed script
virtual void Reload(Script *script);
/// Get all managed scripts (both loaded and invalid)
const std::vector<std::unique_ptr<Script>>& GetScripts() const { return scripts; }
const std::vector<cmd::Command*>& GetMacros();
// No need to have getters for the other kinds of features, I think.
// They automatically register themselves in the relevant places.
DEFINE_SIGNAL_ADDERS(ScriptsChanged, AddScriptChangeListener)
};
/// Manager for scripts specified by a subtitle file
class LocalScriptManager final : public ScriptManager {
agi::Context *context;
agi::signal::Connection file_open_connection;
void SaveLoadedList();
public:
LocalScriptManager(agi::Context *context);
void Reload() override;
};
/// Manager for scripts in the autoload directory
class AutoloadScriptManager final : public ScriptManager {
std::string path;
public:
AutoloadScriptManager(std::string path);
void Reload() override;
};
/// Both a base class for script factories and a manager of registered
/// script factories
class ScriptFactory {
std::string engine_name;
std::string filename_pattern;
/// Load a file, or return nullptr if the file is not in a supported
/// format. If the file is in a supported format but is invalid, a
/// script should be returned which returns false from IsLoaded and
/// an appropriate error message from GetDescription.
///
/// This is private as it should only ever be called through
/// CreateFromFile
virtual std::unique_ptr<Script> Produce(agi::fs::path const& filename) const = 0;
static std::vector<std::unique_ptr<ScriptFactory>>& Factories();
protected:
ScriptFactory(std::string engine_name, std::string filename_pattern);
public:
virtual ~ScriptFactory() = default;
/// Name of this automation engine
const std::string& GetEngineName() const { return engine_name; }
/// Extension which this engine supports
const std::string& GetFilenamePattern() const { return filename_pattern; }
/// Register an automation engine.
static void Register(std::unique_ptr<ScriptFactory> factory);
/// Get the full wildcard string for all loaded engines
static std::string GetWildcardStr();
/// Load a script from a file
/// @param filename Script to load
/// @param complain_about_unrecognised Should an error be displayed for files that aren't automation scripts?
/// @param create_unknown Create a placeholder rather than returning nullptr if no script engine supports the file
static std::unique_ptr<Script> CreateFromFile(agi::fs::path const& filename, bool complain_about_unrecognised, bool create_unknown=true);
static const std::vector<std::unique_ptr<ScriptFactory>>& GetFactories();
};
/// A script which represents a file not recognized by any registered
/// automation engines
class UnknownScript final : public Script {
public:
UnknownScript(agi::fs::path const& filename) : Script(filename) { }
void Reload() override { }
std::string GetName() const override { return GetFilename().stem().string(); }
std::string GetDescription() const override;
std::string GetAuthor() const override { return ""; }
std::string GetVersion() const override { return ""; }
bool GetLoadedState() const override { return false; }
std::vector<cmd::Command*> GetMacros() const override { return {}; }
std::vector<ExportFilter*> GetFilters() const override { return {}; }
};
}