File indexing completed on 2025-02-02 04:11:08
0001 /* 0002 * SPDX-FileCopyrightText: 2019-2023 Mattia Basaglia <dev@dragon.best> 0003 * 0004 * SPDX-License-Identifier: GPL-3.0-or-later 0005 */ 0006 0007 #pragma once 0008 0009 #include <QRawFont> 0010 #include <QFontMetricsF> 0011 0012 #include "model/property/sub_object_property.hpp" 0013 #include "model/property/option_list_property.hpp" 0014 #include "model/property/reference_property.hpp" 0015 #include "shape.hpp" 0016 0017 namespace glaxnimate::model { 0018 0019 class Font : public Object 0020 { 0021 GLAXNIMATE_OBJECT(Font) 0022 GLAXNIMATE_PROPERTY_OPTIONS(QString, family, "", QStringList, 0023 &Font::families, &Font::on_family_changed, {}, PropertyTraits::Visual, OptionListPropertyBase::FontCombo) 0024 GLAXNIMATE_PROPERTY_OPTIONS(float, size, 32, QList<int>, 0025 &Font::standard_sizes, &Font::on_font_changed, {}, PropertyTraits::Visual, OptionListPropertyBase::LaxValues) 0026 GLAXNIMATE_PROPERTY_OPTIONS(QString, style, "", QStringList, 0027 &Font::styles, &Font::on_font_changed, &Font::valid_style, PropertyTraits::Visual) 0028 GLAXNIMATE_PROPERTY(float, line_height, 1, &Font::on_font_changed, {}, PropertyTraits::Visual|PropertyTraits::Percent) 0029 0030 public: 0031 struct CharData 0032 { 0033 quint32 glyph; 0034 QPointF position; 0035 }; 0036 0037 struct LineData 0038 { 0039 std::vector<CharData> glyphs; 0040 QRectF bounds; 0041 QPointF baseline; 0042 QPointF advance; 0043 QString text; 0044 }; 0045 0046 using ParagraphData = std::vector<LineData>; 0047 0048 using CharDataCache = std::unordered_map<quint32, QPainterPath>; 0049 0050 explicit Font(Document* doc); 0051 ~Font(); 0052 0053 const QRawFont& raw_font() const; 0054 const QFont& query() const; 0055 const QFontMetricsF& metrics() const; 0056 0057 void from_qfont(const QFont& f); 0058 0059 QStringList styles() const; 0060 QStringList families() const; 0061 QList<int> standard_sizes() const; 0062 0063 QString type_name_human() const override; 0064 0065 ParagraphData layout(const QString& string) const; 0066 0067 /** 0068 * \brief Distance between two baselines 0069 */ 0070 qreal line_spacing() const; 0071 0072 /** 0073 * \brief Distance between two baselines for a line_height of 1 0074 */ 0075 qreal line_spacing_unscaled() const; 0076 0077 QPainterPath path_for_glyph(quint32 glyph, CharDataCache& cache, bool fix_paint) const; 0078 0079 Q_SIGNALS: 0080 void font_changed(); 0081 0082 protected: 0083 void on_transfer(model::Document* doc) override; 0084 0085 private: 0086 void on_family_changed(); 0087 void on_font_changed(); 0088 void refresh_data(bool update_styles); 0089 bool valid_style(const QString& style); 0090 0091 class Private; 0092 std::unique_ptr<Private> d; 0093 }; 0094 0095 class TextShape : public ShapeElement 0096 { 0097 GLAXNIMATE_OBJECT(TextShape) 0098 GLAXNIMATE_PROPERTY(QString, text, {}, &TextShape::on_text_changed, {}, PropertyTraits::Visual) 0099 GLAXNIMATE_ANIMATABLE(QPointF, position, QPointF()) 0100 GLAXNIMATE_SUBOBJECT(Font, font) 0101 GLAXNIMATE_PROPERTY_REFERENCE(model::ShapeElement, path, &TextShape::valid_paths, &TextShape::is_valid_path, &TextShape::path_changed) 0102 GLAXNIMATE_ANIMATABLE(float, path_offset, 0, &TextShape::on_text_changed) 0103 0104 public: 0105 explicit TextShape(model::Document* document); 0106 0107 void add_shapes(FrameTime t, math::bezier::MultiBezier& bez, const QTransform& transform) const override; 0108 0109 QPainterPath shape_data(FrameTime t) const; 0110 0111 QIcon tree_icon() const override; 0112 QRectF local_bounding_rect(FrameTime t) const override; 0113 QString type_name_human() const override; 0114 std::unique_ptr<ShapeElement> to_path() const override; 0115 0116 /** 0117 * \brief Position where the next character would be 0118 * 0119 * ie: where to add another TextShape to make them flow together 0120 */ 0121 QPointF offset_to_next_character() const; 0122 0123 protected: 0124 QPainterPath to_painter_path_impl(FrameTime t) const override; 0125 0126 private: 0127 void on_font_changed(); 0128 void on_text_changed(); 0129 const QPainterPath& untranslated_path(FrameTime t) const; 0130 0131 std::vector<DocumentNode*> valid_paths() const; 0132 bool is_valid_path(DocumentNode* node) const; 0133 void path_changed(model::ShapeElement* new_path, model::ShapeElement* old_path); 0134 0135 mutable Font::CharDataCache cache; 0136 mutable QPainterPath shape_cache; 0137 }; 0138 0139 } // namespace glaxnimate::model