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 }