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

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 "google_fonts_widget.hpp"
0008 #include "ui_google_fonts_widget.h"
0009 
0010 #include <QEvent>
0011 #include <QSortFilterProxyModel>
0012 
0013 #include "io/svg/font_weight.hpp"
0014 
0015 namespace  {
0016 
0017 class SortFilterGoogleFont : public QSortFilterProxyModel
0018 {
0019 public:
0020 
0021     void set_search(const QString& query)
0022     {
0023         search = query.toLower();
0024         invalidateFilter();
0025     }
0026 
0027     void set_subset(const QString& subset)
0028     {
0029         this->subset = subset;
0030         invalidateFilter();
0031     }
0032 
0033     void set_category(glaxnimate::gui::font::GoogleFontsModel::GoogleFont::Category category)
0034     {
0035         this->category = category;
0036         invalidateFilter();
0037     }
0038 
0039 
0040     bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override
0041     {
0042         if ( source_row < 0 || source_row >= sourceModel()->rowCount(source_parent) )
0043             return false;
0044 
0045         auto source = static_cast<glaxnimate::gui::font::GoogleFontsModel*>(sourceModel());
0046 
0047         QModelIndex index = source->index(source_row, 0, source_parent);
0048 
0049         if ( !search.isEmpty() )
0050         {
0051             if ( !source->data(index, Qt::DisplayRole).toString().toLower().contains(search) )
0052                 return false;
0053         }
0054 
0055         if ( !subset.isEmpty() )
0056         {
0057             if ( !source->has_subset(index, subset) )
0058                 return false;
0059         }
0060 
0061         if ( category != glaxnimate::gui::font::GoogleFontsModel::GoogleFont::Any )
0062         {
0063             if ( !source->has_category(index, category) )
0064                 return false;
0065         }
0066 
0067         return true;
0068 
0069     }
0070 private:
0071     QString search;
0072     QString subset;
0073     glaxnimate::gui::font::GoogleFontsModel::GoogleFont::Category category = glaxnimate::gui::font::GoogleFontsModel::GoogleFont::Any;
0074 };
0075 
0076 } // namespace
0077 
0078 class glaxnimate::gui::font::GoogleFontsWidget::Private
0079 {
0080 public:
0081     GoogleFontsWidget* parent;
0082     Ui::GoogleFontsWidget ui;
0083     GoogleFontsModel model;
0084     SortFilterGoogleFont proxy_model;
0085     QFont current_font;
0086     int current_weight = 400;
0087     bool current_italic = false;
0088 
0089     void set_active_font(const GoogleFontsModel::GoogleFont* font)
0090     {
0091         ui.view_style->clear();
0092 
0093         QListWidgetItem* best_item = nullptr;
0094         int best_score = 0;
0095         const GoogleFontsModel::GoogleFont::Style* best_style = nullptr;
0096 
0097         for ( const auto& style : font->styles )
0098         {
0099             auto item = new QListWidgetItem(style.font.style_name());
0100 //             item->setData(Qt::UserRole, style.weight);
0101 //             item->setData(Qt::UserRole+1, style.italic);
0102             ui.view_style->addItem(item);
0103             int score = style.score(current_weight, current_italic);
0104 
0105             if ( score > best_score )
0106             {
0107                 best_item = item;
0108                 best_score = score;
0109                 best_style = &style;
0110             }
0111         }
0112 
0113         current_weight = best_style->weight;
0114         current_italic = best_style->italic;
0115         ui.view_style->setCurrentItem(best_item);
0116 
0117         current_font.setFamily(font->family);
0118         using io::svg::WeightConverter;
0119         current_font.setWeight(QFont::Weight(WeightConverter::convert(current_weight, WeightConverter::css, WeightConverter::qt)));
0120         current_font.setItalic(current_italic);
0121 
0122         Q_EMIT parent->font_changed(current_font);
0123     }
0124 
0125     void update_writing_systems()
0126     {
0127         auto current = ui.combo_system->currentText();
0128         ui.combo_system->clear();
0129         ui.combo_system->addItem("");
0130         for ( const auto& subset : model.subsets() )
0131             ui.combo_system->addItem(subset);
0132         ui.combo_system->setCurrentText(current);
0133     }
0134 
0135     void add_category(GoogleFontsModel::GoogleFont::Category cat)
0136     {
0137         ui.combo_category->addItem(model.category_name(cat), int(cat));
0138     }
0139 
0140     void add_categories()
0141     {
0142         add_category(GoogleFontsModel::GoogleFont::Any);
0143         add_category(GoogleFontsModel::GoogleFont::Serif);
0144         add_category(GoogleFontsModel::GoogleFont::SansSerif);
0145         add_category(GoogleFontsModel::GoogleFont::Monospace);
0146         add_category(GoogleFontsModel::GoogleFont::Display);
0147         add_category(GoogleFontsModel::GoogleFont::Handwriting);
0148     }
0149 };
0150 
0151 glaxnimate::gui::font::GoogleFontsWidget::GoogleFontsWidget(QWidget* parent)
0152     : QWidget(parent), d(std::make_unique<Private>())
0153 {
0154     d->parent = this;
0155     d->ui.setupUi(this);
0156 
0157     d->proxy_model.setSourceModel(&d->model);
0158     d->ui.view_google_fonts->setModel(&d->proxy_model);
0159     d->ui.view_google_fonts->verticalHeader()->setVisible(false);
0160     d->ui.view_google_fonts->horizontalHeader()->setSectionResizeMode(GoogleFontsModel::Column::Family, QHeaderView::ResizeToContents);
0161     d->ui.view_google_fonts->horizontalHeader()->setSectionResizeMode(GoogleFontsModel::Column::Popularity, QHeaderView::ResizeToContents);
0162     d->ui.view_google_fonts->horizontalHeader()->setSectionResizeMode(GoogleFontsModel::Column::Category, QHeaderView::ResizeToContents);
0163     d->ui.view_google_fonts->horizontalHeader()->setSectionResizeMode(GoogleFontsModel::Column::Status, QHeaderView::Stretch);
0164 
0165     d->proxy_model.setSortRole(GoogleFontsModel::SortRole);
0166     d->ui.view_google_fonts->setSortingEnabled(true);
0167     d->ui.view_google_fonts->sortByColumn(GoogleFontsModel::Column::Popularity, Qt::AscendingOrder);
0168 
0169     connect(&d->model, &GoogleFontsModel::max_progress_changed, this, [this](int max){
0170         d->ui.google_fonts_progress->setMaximum(max);
0171         d->ui.google_fonts_progress->setVisible(max);
0172         d->ui.button_google_refresh->setEnabled(max == 0);
0173         if ( max == 0 )
0174             d->ui.label_google_error->setText("");
0175     });
0176     connect(&d->model, &GoogleFontsModel::progress_changed, d->ui.google_fonts_progress, &QProgressBar::setValue);
0177     connect(d->ui.button_google_refresh, &QAbstractButton::clicked, this, [this]{
0178         d->model.refresh();
0179         d->ui.label_google_error->setText("");
0180     });
0181     connect(&d->model, &GoogleFontsModel::error, d->ui.label_google_error, &QLabel::setText);
0182     connect(&d->model, &GoogleFontsModel::download_finished, this, [this](int row){
0183         if ( auto font = d->model.font(row) )
0184             d->set_active_font(font);
0185     });
0186 
0187     connect(d->ui.view_google_fonts, &QTableView::clicked, this, [this](const QModelIndex& index){
0188         int row = d->proxy_model.mapToSource(index).row();
0189         auto font = d->model.font(row);
0190 
0191         d->ui.view_style->clear();
0192 
0193         if ( !font )
0194             return;
0195 
0196         if ( font->status == GoogleFontsModel::GoogleFont::Available || font->status == GoogleFontsModel::GoogleFont::Broken )
0197             d->model.download_font(row);
0198         else
0199             d->set_active_font(font);
0200     });
0201 
0202     connect(d->ui.view_style->selectionModel(), &QItemSelectionModel::currentChanged, this, &GoogleFontsWidget::change_style);
0203 
0204     connect(&d->model, &GoogleFontsModel::refresh_finished, this, [this](){
0205         d->update_writing_systems();
0206     });
0207     connect(d->ui.combo_system, &QComboBox::currentTextChanged, &d->proxy_model, &SortFilterGoogleFont::set_subset);
0208     connect(d->ui.edit_family, &QLineEdit::textChanged, &d->proxy_model, &SortFilterGoogleFont::set_search);
0209 
0210     d->add_categories();
0211     connect(d->ui.combo_category, qOverload<int>(&QComboBox::currentIndexChanged), this, [this](){
0212         d->proxy_model.set_category(GoogleFontsModel::GoogleFont::Category(d->ui.combo_category->currentData().toInt()));
0213     });
0214 
0215     connect(d->ui.size_widget, &FontSizeWidget::font_size_changed, this, [this](double size){
0216         d->current_font.setPointSizeF(size);
0217         Q_EMIT font_changed(d->current_font);
0218     });
0219 
0220 }
0221 
0222 glaxnimate::gui::font::GoogleFontsWidget::~GoogleFontsWidget() = default;
0223 
0224 void glaxnimate::gui::font::GoogleFontsWidget::changeEvent ( QEvent* e )
0225 {
0226     QWidget::changeEvent(e);
0227 
0228     if ( e->type() == QEvent::LanguageChange)
0229     {
0230         d->ui.retranslateUi(this);
0231     }
0232 }
0233 
0234 void glaxnimate::gui::font::GoogleFontsWidget::showEvent(QShowEvent* e)
0235 {
0236     QWidget::showEvent(e);
0237     if ( d->model.has_token() && d->model.rowCount() == 0 )
0238         d->model.refresh();
0239 }
0240 
0241 const glaxnimate::gui::font::GoogleFontsModel & glaxnimate::gui::font::GoogleFontsWidget::model() const
0242 {
0243     return d->model;
0244 }
0245 
0246 void glaxnimate::gui::font::GoogleFontsWidget::change_style(const QModelIndex& index)
0247 {
0248     if ( index.isValid() )
0249     {
0250         d->current_font.setStyleName(index.data(Qt::DisplayRole).toString());
0251         Q_EMIT font_changed(d->current_font);
0252     }
0253 }
0254 
0255 void glaxnimate::gui::font::GoogleFontsWidget::set_font_size(double size)
0256 {
0257     d->ui.size_widget->set_font_size(size);
0258 }
0259 
0260 glaxnimate::model::CustomFont glaxnimate::gui::font::GoogleFontsWidget::custom_font() const
0261 {
0262     int font_row = d->proxy_model.mapToSource(d->ui.view_google_fonts->currentIndex()).row();
0263     auto font = d->model.font(font_row);
0264     if ( !font )
0265         return {};
0266 
0267     auto style_row = d->ui.view_style->currentRow();
0268     if ( style_row < 0 || style_row >= int(font->styles.size()) )
0269         return {};
0270 
0271     return font->styles[style_row].font;
0272 }
0273 
0274 const QFont & glaxnimate::gui::font::GoogleFontsWidget::selected_font() const
0275 {
0276     return d->current_font;
0277 }