File indexing completed on 2025-02-02 04:11:22
0001 /* 0002 * SPDX-FileCopyrightText: 2019-2023 Mattia Basaglia <dev@dragon.best> 0003 * 0004 * SPDX-License-Identifier: GPL-3.0-or-later 0005 */ 0006 0007 #include "glaxnimate_window_p.hpp" 0008 0009 #include <QShortcut> 0010 #include <QJsonDocument> 0011 #include <QTemporaryFile> 0012 #include <QDomDocument> 0013 #include <QFontDatabase> 0014 0015 #include "app/utils/desktop.hpp" 0016 #include "app/debug/model.hpp" 0017 0018 #include "io/base.hpp" 0019 #include "io/glaxnimate/glaxnimate_format.hpp" 0020 #include "io/rive/rive_format.hpp" 0021 #include "io/lottie/lottie_format.hpp" 0022 #include "utils/gzip.hpp" 0023 #include "model/custom_font.hpp" 0024 0025 #include "widgets/timeline/timeline_widget.hpp" 0026 #include "widgets/dialogs/clipboard_inspector.hpp" 0027 0028 #include "glaxnimate_app.hpp" 0029 0030 namespace { 0031 0032 void screenshot_widget(const QString& path, QWidget* widget) 0033 { 0034 widget->show(); 0035 QString base = widget->objectName(); 0036 QString name = path + base.mid(base.indexOf("_")+1); 0037 QPixmap pic(widget->size()); 0038 widget->render(&pic); 0039 name += ".png"; 0040 pic.save(name); 0041 } 0042 0043 QString pretty_json(const QJsonDocument& input) 0044 { 0045 QTemporaryFile tempf(GlaxnimateApp::temp_path() + "/XXXXXX.json"); 0046 tempf.setAutoRemove(false); 0047 tempf.open(); 0048 tempf.write(input.toJson(QJsonDocument::Indented)); 0049 return tempf.fileName(); 0050 } 0051 0052 QString pretty_json(const QByteArray& input) 0053 { 0054 return pretty_json(QJsonDocument::fromJson(input)); 0055 } 0056 0057 QString pretty_xml(const QByteArray& xml) 0058 { 0059 QTemporaryFile tempf(GlaxnimateApp::temp_path() + "/XXXXXX.json"); 0060 tempf.setAutoRemove(false); 0061 tempf.open(); 0062 QDomDocument doc; 0063 doc.setContent(xml, false); 0064 tempf.write(doc.toByteArray(4)); 0065 return tempf.fileName(); 0066 } 0067 0068 QString pretty_rive(const QByteArray& input) 0069 { 0070 return pretty_json(glaxnimate::io::rive::RiveFormat().to_json(input)); 0071 } 0072 0073 void json_to_pretty_temp(const QJsonDocument& doc) 0074 { 0075 QTemporaryFile tempf(GlaxnimateApp::temp_path() + "/XXXXXX.json"); 0076 tempf.setAutoRemove(false); 0077 tempf.open(); 0078 tempf.write(doc.toJson(QJsonDocument::Indented)); 0079 tempf.close(); 0080 app::desktop::open_file(tempf.fileName()); 0081 } 0082 0083 } // namespace 0084 0085 void GlaxnimateWindow::Private::init_debug() 0086 { 0087 QMenu* menu_debug = new QMenu("Debug", parent); 0088 0089 auto shortcut = new QShortcut(QKeySequence(Qt::META|Qt::Key_D), ui.canvas); 0090 connect(shortcut, &QShortcut::activated, parent, [menu_debug]{ 0091 menu_debug->exec(QCursor::pos()); 0092 }); 0093 0094 // Models 0095 QMenu* menu_print_model = new QMenu("Print Model", menu_debug); 0096 menu_debug->addAction(menu_print_model->menuAction()); 0097 0098 menu_print_model->addAction("Document Node - Full", [this]{ 0099 app::debug::print_model(&document_node_model, {1}, false); 0100 }); 0101 0102 menu_print_model->addAction("Document Node - Layers", [this]{ 0103 app::debug::print_model(ui.view_document_node->model(), {1}, false); 0104 }); 0105 0106 menu_print_model->addAction("Document Node - Assets", [this]{ 0107 app::debug::print_model(&asset_model, {0}, false); 0108 }); 0109 0110 menu_print_model->addSeparator(); 0111 0112 menu_print_model->addAction("Properties - Single", [this]{ 0113 app::debug::print_model(&property_model, {0}, false); 0114 }); 0115 0116 menu_print_model->addAction("Properties - Full", [this]{ 0117 app::debug::print_model(ui.timeline_widget->raw_model(), {0}, false); 0118 }); 0119 0120 menu_print_model->addAction("Properties - Full (Filtered)", [this]{ 0121 app::debug::print_model(ui.timeline_widget->filtered_model(), {0}, false); 0122 }); 0123 0124 QMenu* menu_model_signals = new QMenu("Show Model Signals", menu_debug); 0125 menu_debug->addAction(menu_model_signals->menuAction()); 0126 menu_model_signals->addAction("Document Node - Full", [this]{ 0127 app::debug::connect_debug(&document_node_model, "Document Node - Full"); 0128 }); 0129 menu_model_signals->addAction("Document Node - Layers", [this]{ 0130 app::debug::connect_debug(ui.view_document_node->model(), "Document Node - Layers"); 0131 }); 0132 0133 menu_debug->addAction("Current index", [this]{ 0134 0135 auto layers_index = ui.view_document_node->currentIndex(); 0136 qDebug() << "Layers" << layers_index << ui.view_document_node->current_node() << ui.view_document_node->node(layers_index); 0137 0138 0139 qDebug() << "Timeline" << ui.timeline_widget->current_index_raw() << ui.timeline_widget->current_index_filtered() << ui.timeline_widget->current_node(); 0140 }); 0141 0142 // Timeline 0143 QMenu* menu_timeline = new QMenu("Timeline", menu_debug); 0144 menu_debug->addAction(menu_timeline->menuAction()); 0145 menu_timeline->addAction("Print lines", [this]{ 0146 ui.timeline_widget->timeline()->debug_lines(); 0147 }); 0148 QAction* toggle_timeline_debug = menu_timeline->addAction("Debug view"); 0149 toggle_timeline_debug->setCheckable(true); 0150 connect(toggle_timeline_debug, &QAction::toggled, parent, [this](bool on){ 0151 ui.timeline_widget->timeline()->toggle_debug(on); 0152 app::settings::set("internal", "debug_timeline", on); 0153 }); 0154 toggle_timeline_debug->setChecked(app::settings::define("internal", "debug_timeline", false)); 0155 0156 // Timeline 0157 QMenu* menu_canvas = new QMenu("Canvas", menu_debug); 0158 menu_debug->addAction(menu_canvas->menuAction()); 0159 menu_canvas->addAction("Debug Scene", [this]{ scene.debug();}); 0160 0161 // Screenshot 0162 QMenu* menu_screenshot = new QMenu("Screenshot", menu_debug); 0163 menu_debug->addAction(menu_screenshot->menuAction()); 0164 menu_screenshot->addAction("Menus", [this]{ 0165 QDir("/tmp/").mkpath("glaxnimate/menus"); 0166 for ( auto widget : this->parent->findChildren<QMenu*>() ) 0167 screenshot_widget("/tmp/glaxnimate/menus/", widget); 0168 }); 0169 menu_screenshot->addAction("Toolbars", [this]{ 0170 QDir("/tmp/").mkpath("glaxnimate/toolbars"); 0171 for ( auto widget : this->parent->findChildren<QToolBar*>() ) 0172 screenshot_widget("/tmp/glaxnimate/toolbars/", widget); 0173 }); 0174 menu_screenshot->addAction("Docks", [this]{ 0175 auto state = parent->saveState(); 0176 0177 QDir("/tmp/").mkpath("glaxnimate/docks"); 0178 for ( auto widget : this->parent->findChildren<QDockWidget*>() ) 0179 { 0180 widget->setFloating(true); 0181 screenshot_widget("/tmp/glaxnimate/docks/", widget); 0182 } 0183 0184 parent->restoreState(state); 0185 }); 0186 0187 // Source View 0188 QMenu* menu_source = new QMenu("View Source", menu_debug); 0189 menu_debug->addAction(menu_source->menuAction()); 0190 menu_source->addAction("Raw", [this]{ 0191 app::desktop::open_file(current_document->io_options().filename); 0192 }); 0193 menu_source->addAction("Pretty", [this]{ 0194 QString filename = current_document->io_options().filename; 0195 auto fmt = current_document->io_options().format; 0196 if ( !fmt ) 0197 return; 0198 0199 QFile file(filename); 0200 if ( !file.open(QIODevice::ReadOnly) ) 0201 return; 0202 QByteArray data = file.readAll(); 0203 0204 0205 if ( fmt->slug() == "lottie" || fmt->slug() == "glaxnimate" ) 0206 { 0207 app::desktop::open_file(pretty_json(data)); 0208 } 0209 else if ( fmt->slug() == "tgs" ) 0210 { 0211 QByteArray decomp; 0212 utils::gzip::decompress(data, decomp, {}); 0213 app::desktop::open_file(pretty_json(decomp)); 0214 } 0215 else if ( fmt->slug() == "svg" ) 0216 { 0217 if ( utils::gzip::is_compressed(data) ) 0218 { 0219 QByteArray decomp; 0220 utils::gzip::decompress(data, decomp, {}); 0221 data = std::move(decomp); 0222 } 0223 0224 app::desktop::open_file(pretty_xml(data)); 0225 } 0226 else if ( fmt->slug() == "rive" ) 0227 { 0228 app::desktop::open_file(pretty_rive(data)); 0229 } 0230 else 0231 { 0232 app::desktop::open_file(filename); 0233 } 0234 }); 0235 menu_source->addAction("Current (Rawr)", [this]{ 0236 json_to_pretty_temp(io::glaxnimate::GlaxnimateFormat().to_json(current_document.get())); 0237 }); 0238 menu_source->addAction("Current (Lottie)", [this]{ 0239 json_to_pretty_temp( 0240 QJsonDocument(io::lottie::LottieFormat().to_json(comp).toJsonObject()) 0241 ); 0242 }); 0243 menu_source->addAction("Current (RIVE)", [this]{ 0244 QBuffer buffer; 0245 buffer.open(QIODevice::WriteOnly); 0246 io::rive::RiveFormat().save(buffer, "", comp, {}); 0247 json_to_pretty_temp(io::rive::RiveFormat().to_json(buffer.data())); 0248 }); 0249 0250 // Misc 0251 menu_debug->addAction("Inspect Clipboard", []{ 0252 auto dialog = new ClipboardInspector(); 0253 dialog->show(); 0254 connect(dialog, &QDialog::finished, dialog, &QObject::deleteLater); 0255 }); 0256 menu_debug->addAction("Fonts", []{ 0257 qDebug() << "---- Fonts ----"; 0258 #if QT_VERSION_MAJOR < 6 0259 auto families = QFontDatabase().families(); 0260 #else 0261 auto families = QFontDatabase::families(); 0262 #endif 0263 for ( const auto& family : families ) 0264 qDebug() << family; 0265 0266 qDebug() << "---- Custom ----"; 0267 for ( const auto& font : model::CustomFontDatabase::instance().fonts() ) 0268 qDebug() << font.family() << ":" << font.style_name(); 0269 0270 qDebug() << "---- Aliases ----"; 0271 for ( const auto& p : model::CustomFontDatabase::instance().aliases() ) 0272 { 0273 auto db = qDebug(); 0274 db << p.first << "->"; 0275 for ( const auto& n : p.second ) 0276 db << n; 0277 } 0278 qDebug() << "----"; 0279 }); 0280 menu_debug->addAction("Force Autosave", [this]{autosave(true);}); 0281 //menu_debug->addAction("Crash", []{volatile int* np = nullptr;*np = 123;}); 0282 }