File indexing completed on 2025-02-02 04:11:26

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 "startup_dialog.hpp"
0008 #include "ui_startup_dialog.h"
0009 
0010 #include <QEvent>
0011 
0012 #include "app/settings/settings.hpp"
0013 #include "settings/document_templates.hpp"
0014 #include <model/assets/assets.hpp>
0015 
0016 using namespace glaxnimate::gui;
0017 using namespace glaxnimate;
0018 
0019 class StartupDialog::Private
0020 {
0021 public:
0022     Ui::StartupDialog ui;
0023 
0024     model::FrameTime duration_frames()
0025     {
0026         if ( ui.combo_time_units->currentIndex() == 0 )
0027             return ui.spin_duration->value();
0028         return ui.spin_duration->value() * ui.spin_fps->value();
0029     }
0030 
0031     float duration(model::FrameTime time, float fps)
0032     {
0033         if ( ui.combo_time_units->currentIndex() == 0 || fps <= 0 )
0034             return time;
0035         return time / fps;
0036     }
0037 
0038     QString time_suffix()
0039     {
0040         if ( ui.combo_time_units->currentIndex() == 0 )
0041             return "f";
0042         return "'";
0043     }
0044 
0045     QString format_duration(const settings::DocumentTemplate& templ)
0046     {
0047         return QString::number(duration(templ.duration(), templ.fps())) + time_suffix();
0048     }
0049 
0050     void adjust_duration_spin()
0051     {
0052         ui.spin_duration->setSuffix(time_suffix());
0053         if ( ui.combo_time_units->currentIndex() == 0 )
0054             ui.spin_duration->setDecimals(0);
0055         else
0056             ui.spin_duration->setDecimals(2);
0057     }
0058 
0059     void apply_to_document(model::Document* doc)
0060     {
0061         auto last_frame = duration_frames();
0062         for ( const auto& comp : doc->assets()->compositions->values )
0063         {
0064             comp->width.set(ui.spin_size->x());
0065             comp->height.set(ui.spin_size->y());
0066             comp->fps.set(ui.spin_fps->value());
0067             comp->animation->last_frame.set(last_frame);
0068             for ( auto lay : comp->docnode_find_by_type_name<model::Layer>("Layer") )
0069                 lay->animation->last_frame.set(last_frame);
0070         }
0071     }
0072 };
0073 
0074 StartupDialog::StartupDialog(QWidget* parent)
0075     : QDialog(parent), d(std::make_unique<Private>())
0076 {
0077     d->ui.setupUi(this);
0078     reload_presets();
0079     connect(&settings::DocumentTemplates::instance(), &settings::DocumentTemplates::loaded, this, &StartupDialog::reload_presets);
0080     connect(d->ui.button_open_browse, &QPushButton::clicked, this, &StartupDialog::open_browse);
0081 
0082     d->ui.spin_size->enable_ratio_lock();
0083     d->ui.spin_size->set_decimals(0);
0084     d->ui.spin_size->set_value(
0085         app::settings::get<int>("defaults", "width"),
0086         app::settings::get<int>("defaults", "height")
0087     );
0088     float fps = app::settings::get<float>("defaults", "fps");
0089     d->ui.spin_fps->setValue(fps);
0090     d->adjust_duration_spin();
0091     d->ui.spin_duration->setValue(app::settings::get<float>("defaults", "duration"));
0092 
0093     for ( const auto& recent : app::settings::get<QStringList>("open_save", "recent_files") )
0094     {
0095         QFileInfo finfo(recent);
0096         if ( !finfo.exists() || !finfo.isReadable() )
0097             continue;
0098         auto item = new QListWidgetItem(QIcon::fromTheme("document-open-recent"), finfo.fileName());
0099         item->setData(Qt::ToolTipRole, recent);
0100         d->ui.view_recent->addItem(item);
0101     }
0102 
0103     d->ui.view_presets->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
0104     for ( int i = 1; i < d->ui.view_presets->columnCount(); i++ )
0105     {
0106         d->ui.view_presets->horizontalHeader()->setSectionResizeMode(i, QHeaderView::ResizeToContents);
0107     }
0108 
0109     d->ui.check_show_at_startup->setChecked(app::settings::get<bool>("ui", "startup_dialog"));
0110 }
0111 
0112 StartupDialog::~StartupDialog() = default;
0113 
0114 void StartupDialog::changeEvent ( QEvent* e )
0115 {
0116     QDialog::changeEvent(e);
0117 
0118     if ( e->type() == QEvent::LanguageChange)
0119     {
0120         d->ui.retranslateUi(this);
0121     }
0122 }
0123 
0124 void StartupDialog::reload_presets()
0125 {
0126     d->ui.view_presets->clearContents();
0127     int row = 0;
0128     for ( const auto& templ : settings::DocumentTemplates::instance().templates() )
0129     {
0130         d->ui.view_presets->insertRow(row);
0131         int col = 0;
0132         d->ui.view_presets->setItem(row, col++, new QTableWidgetItem(QIcon::fromTheme("document-new-from-template"), templ.name()));
0133 
0134         auto item = new QTableWidgetItem(QString("%1x%2").arg(templ.size().width()).arg(templ.size().height()));
0135         item->setTextAlignment(Qt::AlignCenter);
0136         d->ui.view_presets->setItem(row, col++, item);
0137 
0138         item = new QTableWidgetItem(QString("%1 fps").arg(templ.fps()));
0139         item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
0140         d->ui.view_presets->setItem(row, col++, item);
0141 
0142         item = new QTableWidgetItem(templ.aspect_ratio());
0143         item->setTextAlignment(Qt::AlignCenter);
0144         d->ui.view_presets->setItem(row, col++, item);
0145 
0146         item = new QTableWidgetItem(d->format_duration(templ));
0147         item->setTextAlignment(Qt::AlignRight|Qt::AlignVCenter);
0148         d->ui.view_presets->setItem(row, col++, item);
0149         row++;
0150     }
0151 }
0152 
0153 void StartupDialog::select_preset(const QModelIndex& index)
0154 {
0155     const auto& templ = settings::DocumentTemplates::instance().templates()[index.row()];
0156     d->ui.spin_size->set_value(templ.size());
0157     d->ui.spin_fps->setValue(templ.fps());
0158     d->ui.spin_duration->setValue(d->duration(templ.duration(), templ.fps()));
0159 }
0160 
0161 void StartupDialog::click_recent(const QModelIndex& index)
0162 {
0163     Q_EMIT open_recent(index.data(Qt::ToolTipRole).toString());
0164     reject();
0165 }
0166 
0167 std::unique_ptr<model::Document> StartupDialog::create() const
0168 {
0169     auto index = d->ui.view_presets->currentIndex();
0170     if ( index.isValid() )
0171     {
0172         const auto& templ = settings::DocumentTemplates::instance().templates()[index.row()];
0173         bool ok = false;
0174         auto doc = templ.create(&ok);
0175         if ( ok )
0176         {
0177             d->apply_to_document(doc.get());
0178             return doc;
0179         }
0180     }
0181 
0182     auto doc = std::make_unique<model::Document>("");
0183     auto comp = doc->assets()->add_comp_no_undo();
0184     d->apply_to_document(doc.get());
0185 
0186     auto layer = std::make_unique<model::Layer>(doc.get());
0187     layer->animation->last_frame.set(d->duration_frames());
0188     layer->name.set(layer->type_name_human());
0189     QPointF pos(
0190         d->ui.spin_size->x() / 2.0,
0191         d->ui.spin_size->y() / 2.0
0192     );
0193     layer->transform.get()->anchor_point.set(pos);
0194     layer->transform.get()->position.set(pos);
0195     comp->shapes.insert(std::move(layer), 0);
0196 
0197     return doc;
0198 }
0199 
0200 void StartupDialog::update_time_units()
0201 {
0202     d->adjust_duration_spin();
0203 
0204     // seconds * fps = frames
0205     float mult = d->ui.spin_fps->value();
0206 
0207     // fps -> seconds
0208     if ( d->ui.combo_time_units->currentIndex() == 1 )
0209         mult = 1/mult;
0210 
0211     d->ui.spin_duration->setValue(d->ui.spin_duration->value() * mult);
0212 
0213     int row = 0;
0214     for ( const auto& templ : settings::DocumentTemplates::instance().templates() )
0215     {
0216         d->ui.view_presets->item(row, 4)->setData(Qt::DisplayRole, d->format_duration(templ));
0217         row++;
0218     }
0219 }
0220 
0221 void StartupDialog::update_startup_enabled(bool checked)
0222 {
0223     app::settings::set("ui", "startup_dialog", checked);
0224 }