Skip to content
Pokered Save Editor 2
Pokemon Red & Blue save file editor - Qt 6 C++/QML
Loading...
Searching...
No Matches
debuglaunch.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2026 Twilight
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15*/
16
34
35#include <QApplication>
36
37#ifdef QT_DEBUG
38
39#include <QCommandLineParser>
40#include <QCommandLineOption>
41#include <QStringList>
42#include <QTimer>
43#include <QDebug>
44
46#include <QStringList>
47#include "../bridge/bridge.h"
48#include "../bridge/router.h"
50
51void applyDebugLaunch(QApplication* app)
52{
53 QCommandLineParser parser;
54 QCommandLineOption savOpt(QStringList() << "sav" << "save",
55 QStringLiteral("DEBUG: load this .sav file on startup."), QStringLiteral("path"));
56 QCommandLineOption screenOpt(QStringList() << "screen",
57 QStringLiteral("DEBUG: jump to this screen after load "
58 "(trainerCard, pokedex, bag, pokemart, pokemon, rival, maps, home)."),
59 QStringLiteral("name"));
60 QCommandLineOption selectOpt(QStringList() << "select",
61 QStringLiteral("DEBUG: selection for screens that need one -- 'random' or 'source:id'."),
62 QStringLiteral("spec"));
63 QCommandLineOption shotOpt(QStringList() << "shot",
64 QStringLiteral("DEBUG: after navigating, grab the screen to this PNG file."),
65 QStringLiteral("path"));
66 parser.addOption(savOpt);
67 parser.addOption(screenOpt);
68 parser.addOption(selectOpt);
69 parser.addOption(shotOpt);
70
71 // parse() (not process()): tolerate Qt's own args + unknown flags, never exit.
72 parser.parse(app->arguments());
73
74 const QString sav = parser.value(savOpt);
75 const QString screen = parser.value(screenOpt);
76 const QString select = parser.value(selectOpt);
77 const QString shot = parser.value(shotOpt);
78
79 if(sav.isEmpty() && screen.isEmpty() && shot.isEmpty())
80 return; // nothing requested -> normal startup
81
82 // App.qml seats its startup stack (home + the New File modal) on an event-loop
83 // tick, NOT necessarily before ours -- if we navigate too early, that modal lands
84 // on top of us. So poll until the startup stack is seated (>= 2 entries), then act
85 // exactly once. onCompleted runs atomically w.r.t. the loop, so size>=2 means the
86 // modal is already up and closeScreen() below can dismiss it.
87 QTimer* timer = new QTimer(app);
88 int* tries = new int(0);
89 QObject::connect(timer, &QTimer::timeout, app, [timer, tries, sav, screen, select, shot]() {
91 const bool ready = (brg != nullptr) && Router::stack.size() >= 2;
92 if(!ready && ++(*tries) < 200) // wait up to ~10s (50ms x 200)
93 return;
94
95 timer->stop();
96 timer->deleteLater();
97 delete tries;
98
99 if(brg == nullptr) {
100 qWarning() << "[debug-launch] Bridge not ready; skipping.";
101 return;
102 }
103
104 if(!sav.isEmpty()) {
105 qInfo() << "[debug-launch] loading save:" << sav;
106 brg->file->setPath(sav); // set the active path (does NOT read the file)
107 brg->file->reopenFile(); // read + adopt the data from disk for that path
108 qInfo() << "[debug-launch] loaded path=" << brg->file->getPath();
109 }
110
111 if(!screen.isEmpty()) {
112 if(!Router::screens.contains(screen)) {
113 qWarning() << "[debug-launch] unknown screen:" << screen
114 << "-- known:" << Router::screens.keys();
115 return;
116 }
117
118 // Dismiss the startup New File modal, then navigate to the target screen.
119 qInfo() << "[debug-launch] pre-nav stack size=" << Router::stack.size();
120 brg->router->closeScreen();
121 qInfo() << "[debug-launch] post-close stack size=" << Router::stack.size();
122 qInfo() << "[debug-launch] screen:" << screen
123 << (select.isEmpty() ? QString() : QStringLiteral("select=") + select);
124 if(screen == QStringLiteral("pokemonDetails")) {
125 // Needs a selected mon -- open party slot N (default 0; --select party:N).
126 const int idx = select.startsWith(QStringLiteral("party:"))
127 ? select.mid(6).toInt() : 0;
128 qInfo() << "[debug-launch] pokemonDetails party index" << idx;
131 } else {
132 brg->router->changeScreen(screen);
133 }
134 qInfo() << "[debug-launch] post-change stack size=" << Router::stack.size()
135 << "title=" << brg->router->title;
136
137 // TODO(next step): screens that need a selection (pokemonDetails / mapDetails)
138 // should honour --select here -- pick a random owned entity, or a specific
139 // 'source:id'. Not yet wired.
140 }
141
142 // Optional off-screen screenshot once the target screen has had a moment to
143 // render. Grabs the QQuickWidget framebuffer, so it works with the window
144 // occluded / unfocused (no need to raise or steal focus).
145 if(!shot.isEmpty()) {
146 QTimer::singleShot(600, qApp, [shot]() {
147 if(auto* mw = MainWindow::getInstance()) {
148 const bool ok = mw->saveShot(shot);
149 qInfo() << "[debug-launch] shot" << (ok ? "saved:" : "FAILED:") << shot;
150 }
151 });
152 }
153 });
154 timer->setInterval(50);
155 timer->start();
156}
157
158#else
159
160void applyDebugLaunch(QApplication*) {}
161
162#endif
The single QML<->C++ doorway – everything the UI touches hangs off here.
Definition bridge.h:71
FileManagement * file
Definition bridge.h:149
Router * router
Definition bridge.h:153
void setPath(QString path)
Set the active path (backs the path property).
void reopenFile()
Reload the current path from disk, discarding edits.
QString getPath()
Current file path.
bool debugOpenPartyDetails(int index)
DEBUG: open the details editor for party mon index (drives the QML AppWindow.debugOpenPartyDetails).
static MainWindow * getInstance()
The single MainWindow instance.
static Bridge * bridge
The brg aggregate (created here, injected into QML).
Definition mainwindow.h:62
void changeScreen(QString name)
Navigate to the registered screen name.
Definition router.cpp:35
static QVector< Screen * > stack
The live navigation stack.
Definition router.h:103
void closeScreen()
Close the top screen.
Definition router.cpp:78
static QHash< QString, Screen * > screens
The registry of named screens.
Definition router.h:104
QString title
Definition router.h:98
void applyDebugLaunch(QApplication *)