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
|
#ifndef MODORGANIZER_CREATEINSTANCEDIALOG_INCLUDED
#define MODORGANIZER_CREATEINSTANCEDIALOG_INCLUDED
#include <QDialog>
namespace MOBase
{
class IPluginGame;
}
namespace Ui
{
class CreateInstanceDialog;
};
namespace cid
{
class Page;
}
class PluginContainer;
class Settings;
// this is a wizard for creating a new instance, it is made out of Page objects,
// see createinstancedialogpages.h
//
// each page can give back one or more pieces of information that is collected
// in creationInfo() and used by finish() to do the actual creation
//
// pages can be disabled if they return true in skip(), which happens globally
// for some (IntroPage has a setting in the registry), depending on context
// (NexusPage is skipped if the Nexus authorization already exists) or explicitly (when
// only some info about the instance is missing on startup, such as a game
// variant)
//
class CreateInstanceDialog : public QDialog
{
Q_OBJECT
public:
enum class Actions
{
Find = 1
};
// instance type
//
enum Types
{
NoType = 0,
Global,
Portable
};
// all the paths required by the instance, some may be empty, such as
// basically all of them except for `base` when the user doesn't use the
// "Advanced" part of the paths page
//
struct Paths
{
QString base;
QString downloads;
QString mods;
QString profiles;
QString overwrite;
QString ini;
auto operator<=>(const Paths&) const = default;
};
struct ProfileSettings
{
bool localInis;
bool localSaves;
bool archiveInvalidation;
auto operator<=>(const ProfileSettings&) const = default;
};
// all the info filled in the various pages
//
struct CreationInfo
{
Types type;
MOBase::IPluginGame* game;
QString gameLocation;
QString gameVariant;
QString instanceName;
QString dataPath;
QString iniPath;
Paths paths;
ProfileSettings profileSettings;
};
CreateInstanceDialog(const PluginContainer& pc, Settings* s,
QWidget* parent = nullptr);
~CreateInstanceDialog();
Ui::CreateInstanceDialog* getUI();
const PluginContainer& pluginContainer();
Settings* settings();
// disables all the pages except for the given one, used on startup when some
// specific info is missing
template <class Page>
void setSinglePage(const QString& instanceName)
{
for (auto&& p : m_pages) {
if (auto* tp = dynamic_cast<Page*>(p.get())) {
tp->setSkip(false);
} else {
p->setSkip(true);
}
}
setSinglePageImpl(instanceName);
}
// returns the page having the give path, or null
//
template <class Page>
Page* getPage()
{
for (auto&& p : m_pages) {
if (auto* tp = dynamic_cast<Page*>(p.get())) {
return tp;
}
}
return nullptr;
}
// moves to the next page; if `allowFinish` is true, calls finish() if
// currently on the last page
//
void next(bool allowFinish = true);
// moves to the previous page, if any
//
void back();
// whether the current page reports that it is ready; if this is the last
// page, next() would call finish()
//
bool canNext() const;
// whether the current page is not the first one and there is an enabled page
// prior
//
bool canBack() const;
// selects the given page by index; this doesn't check if the page should be
// skipped
//
void selectPage(std::size_t i);
// moves by `d` pages, can be negative to move back
//
void changePage(int d);
// creates the instance and closes the dialog
//
void finish();
// updates the navigation buttons based on the current page
//
void updateNavigation();
// whether this is the last enabled page
//
bool isOnLastPage() const;
// returns whether the user has requested to switch to the new instance
//
bool switching() const;
// gathers the info from all the pages as it appears, paths are not fixed;
// see creationInfo()
//
CreationInfo rawCreationInfo() const;
// gathers the info from all the pages: paths are converted to absolute and
// the base dir variable is expanded everywhere; see rawCreationInfo()
//
CreationInfo creationInfo() const;
private:
std::unique_ptr<Ui::CreateInstanceDialog> ui;
const PluginContainer& m_pc;
Settings* m_settings;
std::vector<std::unique_ptr<cid::Page>> m_pages;
QString m_originalNext;
bool m_switching;
bool m_singlePage;
// creates a shortcut for the given sequence
//
void addShortcut(QKeySequence seq, std::function<void()> f);
// creates a shortcut for the given sequence and executes the action when
// activated
//
void addShortcutAction(QKeySequence seq, Actions a);
// calls action() with the given action on the selected page, if any
//
void doAction(Actions a);
// called from setSinglePage(), does whatever doesn't need the T
//
void setSinglePageImpl(const QString& instanceName);
// adds a line to the creation log
//
void logCreation(const QString& s);
void logCreation(const std::wstring& s);
// calls the given member function on all pages until one returns an object
// that's not empty; used by gatherInfo()
//
template <class MF, class... Args>
auto getSelected(MF mf, Args&&... args) const
{
// return type
using T = decltype((std::declval<cid::Page>().*mf)(std::forward<Args>(args)...));
for (auto&& p : m_pages) {
const auto t = (p.get()->*mf)(std::forward<Args>(args)...);
if (t != T()) {
return t;
}
}
return T();
}
};
#endif // MODORGANIZER_CREATEINSTANCEDIALOG_INCLUDED
|