Warning, file /graphics/glaxnimate/src/gui/emoji/emoji_dialog.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
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 "emoji_dialog.hpp" 0008 0009 #include <QToolButton> 0010 #include <QVBoxLayout> 0011 #include <QMouseEvent> 0012 #include <QLabel> 0013 #include <QScrollBar> 0014 #include <QGraphicsView> 0015 #include <QGuiApplication> 0016 #include <QScreen> 0017 #include <QScroller> 0018 #include <QGraphicsSimpleTextItem> 0019 #include <QtGlobal> 0020 0021 #include <KLocalizedString> 0022 0023 #include "emoji_data.hpp" 0024 #include "style/scroll_area_event_filter.hpp" 0025 #include "emoji_set.hpp" 0026 0027 class glaxnimate::emoji::EmojiDialog::Private 0028 { 0029 public: 0030 Private(EmojiDialog* parent) : parent(parent) 0031 { 0032 parent->setWindowTitle(i18nc("@title:window", "Select Emoji")); 0033 0034 QVBoxLayout* lay = new QVBoxLayout(parent); 0035 parent->setLayout(lay); 0036 0037 title = new QHBoxLayout; 0038 lay->addLayout(title); 0039 0040 font.setPixelSize(cell_size); 0041 int pad = 10; 0042 0043 scene_width = columns * (cell_size + cell_margin) + pad; 0044 0045 section_font.setBold(true); 0046 0047 table = new QGraphicsView(parent); 0048 table->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 0049 table->setRenderHint(QPainter::Antialiasing); 0050 table->setRenderHint(QPainter::SmoothPixmapTransform); 0051 #ifdef Q_OS_ANDROID 0052 table->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 0053 #else 0054 table->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); 0055 #endif 0056 lay->addWidget(table); 0057 table->setScene(&scene); 0058 0059 0060 scroller.set_target(table); 0061 table->viewport()->installEventFilter(&scroller); 0062 connect(&scroller, &gui::ScrollAreaEventFilter::clicked, parent, 0063 [parent, this](const QPoint& pos){ 0064 if ( auto item = scene.itemAt(table->mapToScene(pos), table->viewportTransform()) ) 0065 { 0066 for ( auto lab : section_headers ) 0067 if ( lab == item ) 0068 return; 0069 0070 current_unicode = item->data(0).toString(); 0071 current_slug = item->data(1).toString(); 0072 parent->accept(); 0073 } 0074 }); 0075 0076 #ifndef Q_OS_ANDROID 0077 parent->resize(parent->width(), 1024); 0078 table->viewport()->setMinimumWidth(scene_width); 0079 auto margins = table->contentsMargins(); 0080 auto scroll_width = table->verticalScrollBar()->sizeHint().width(); 0081 table->setMinimumWidth(scene_width + scroll_width + margins.left() + margins.right()); 0082 #endif 0083 0084 connect( 0085 QGuiApplication::primaryScreen(), 0086 &QScreen::primaryOrientationChanged, 0087 parent, 0088 [this]{on_rotate();} 0089 ); 0090 0091 } 0092 0093 void on_rotate() 0094 { 0095 qreal factor = 1; 0096 factor = table->viewport()->width() / scene_width; 0097 factor /= table->transform().m11(); 0098 table->scale(factor, factor); 0099 } 0100 0101 QGraphicsItem* create_item(const Emoji& emoji) 0102 { 0103 switch ( mode ) 0104 { 0105 case Text: 0106 { 0107 auto item = scene.addSimpleText(emoji.unicode); 0108 item->setFont(font); 0109 0110 auto rect = item->boundingRect(); 0111 0112 if ( rect.width() > font.pixelSize() * 1.25 ) 0113 { 0114 delete item; 0115 return nullptr; 0116 } 0117 0118 return item; 0119 } 0120 0121 case Image: 0122 { 0123 auto name = image_slug.slug(emoji.hex_slug) + image_suffix; 0124 if ( !image_path.exists(name) ) 0125 return nullptr; 0126 0127 QPixmap pix; 0128 pix.load(image_path.absoluteFilePath(name)); 0129 if ( pix.isNull() || pix.width() == 0) 0130 return nullptr; 0131 0132 QGraphicsPixmapItem* item = new QGraphicsPixmapItem(pix); 0133 item->setShapeMode(QGraphicsPixmapItem::BoundingRectShape); 0134 item->setScale(cell_size / pix.width()); 0135 scene.addItem(item); 0136 return item; 0137 } 0138 } 0139 0140 return nullptr; 0141 } 0142 0143 void load_step() 0144 { 0145 const auto& grp = *EmojiGroup::table[curr_group]; 0146 0147 0148 if ( curr_subgroup == 0 ) 0149 { 0150 section_headers[curr_group]->setVisible(true); 0151 section_headers[curr_group]->setPos(0, y); 0152 y += section_headers[curr_group]->boundingRect().height(); 0153 } 0154 0155 const auto& sub = grp.children[curr_subgroup]; 0156 0157 for ( const auto& emoji : sub->emoji ) 0158 { 0159 auto item = create_item(emoji); 0160 0161 if ( !item ) 0162 continue; 0163 0164 item->setData(0, emoji.unicode); 0165 item->setData(1, emoji.hex_slug); 0166 auto rect = item->boundingRect(); 0167 item->setPos(QPointF(column*(cell_size+cell_margin), y) - rect.topLeft()); 0168 0169 column++; 0170 if ( column == columns ) 0171 { 0172 y += cell_size+cell_margin; 0173 column = 0; 0174 } 0175 } 0176 0177 curr_subgroup++; 0178 0179 if ( curr_subgroup >= int(grp.children.size()) ) 0180 { 0181 curr_subgroup = 0; 0182 curr_group++; 0183 0184 y += cell_size+cell_margin; 0185 column = 0; 0186 } 0187 } 0188 0189 void load_start() 0190 { 0191 for ( const auto& grp : EmojiGroup::table ) 0192 { 0193 auto first = grp->children[0]->emoji[0]; 0194 auto group_label = scene.addSimpleText(grp->name); 0195 section_headers.push_back(group_label); 0196 group_label->setVisible(false); 0197 group_label->setFont(font); 0198 if ( group_label->boundingRect().width() > scene_width ) 0199 group_label->setScale(scene_width / group_label->boundingRect().width()); 0200 QToolButton* btn = new QToolButton(parent); 0201 if ( mode == Text ) 0202 { 0203 btn->setText(first.unicode); 0204 } 0205 else 0206 { 0207 btn->setIcon(QIcon( 0208 image_path.absoluteFilePath(image_slug.slug(first) + image_suffix) 0209 )); 0210 btn->setIconSize(QSize(cell_size * 0.6, cell_size * 0.6)); 0211 } 0212 connect(btn, &QAbstractButton::clicked, parent, [this, group_label]{ 0213 scroller.scroll_to(group_label->pos() * table->transform().m11()); 0214 }); 0215 title->addWidget(btn); 0216 } 0217 } 0218 0219 QString current_unicode; 0220 QString current_slug; 0221 gui::ScrollAreaEventFilter scroller; 0222 EmojiDialog* parent; 0223 0224 QFont font; 0225 QFont section_font; 0226 0227 QHBoxLayout* title; 0228 QGraphicsView* table; 0229 std::vector<QGraphicsSimpleTextItem*> section_headers; 0230 QGraphicsScene scene; 0231 0232 qreal y = 0; 0233 int column = 0; 0234 int columns = 8; 0235 int curr_group = 0; 0236 int curr_subgroup = 0; 0237 qreal scene_width; 0238 qreal cell_size = 72; 0239 qreal cell_margin = 10; 0240 0241 DisplayMode mode; 0242 QDir image_path; 0243 QString image_suffix = ".png"; 0244 EmojiSetSlugFormat image_slug; 0245 }; 0246 0247 glaxnimate::emoji::EmojiDialog::EmojiDialog(QWidget *parent) 0248 : QDialog(parent), d(std::make_unique<Private>(this)) 0249 { 0250 #ifdef Q_OS_ANDROID 0251 d->cell_margin = 0; 0252 #endif 0253 } 0254 0255 glaxnimate::emoji::EmojiDialog::~EmojiDialog() 0256 {} 0257 0258 QString glaxnimate::emoji::EmojiDialog::current_unicode() const 0259 { 0260 return d->current_unicode; 0261 } 0262 0263 void glaxnimate::emoji::EmojiDialog::timerEvent(QTimerEvent *event) 0264 { 0265 d->load_step(); 0266 if ( d->curr_group >= int(EmojiGroup::table.size()) ) 0267 killTimer(event->timerId()); 0268 } 0269 0270 void glaxnimate::emoji::EmojiDialog::showEvent(QShowEvent *e) 0271 { 0272 QDialog::showEvent(e); 0273 d->on_rotate(); 0274 #ifdef Q_OS_ANDROID 0275 d->table->verticalScrollBar()->setValue(0); 0276 #endif 0277 } 0278 0279 QString glaxnimate::emoji::EmojiDialog::current_slug() const 0280 { 0281 return d->current_slug; 0282 } 0283 0284 void glaxnimate::emoji::EmojiDialog::load_emoji(glaxnimate::emoji::EmojiDialog::DisplayMode mode) 0285 { 0286 d->mode = mode; 0287 d->load_start(); 0288 d->load_step(); 0289 startTimer(20); 0290 } 0291 0292 void glaxnimate::emoji::EmojiDialog::set_emoji_font(const QFont& font) 0293 { 0294 d->font = font; 0295 } 0296 0297 const QFont & glaxnimate::emoji::EmojiDialog::emoji_font() const 0298 { 0299 return d->font; 0300 } 0301 0302 void glaxnimate::emoji::EmojiDialog::set_image_path(const QDir& path) 0303 { 0304 d->image_path = path; 0305 } 0306 0307 const QDir & glaxnimate::emoji::EmojiDialog::image_path() const 0308 { 0309 return d->image_path; 0310 } 0311 0312 void glaxnimate::emoji::EmojiDialog::set_image_suffix(const QString& suffix) 0313 { 0314 d->image_suffix = suffix; 0315 } 0316 0317 const QString & glaxnimate::emoji::EmojiDialog::image_suffix() const 0318 { 0319 return d->image_suffix; 0320 } 0321 0322 void glaxnimate::emoji::EmojiDialog::set_image_slug_format(const glaxnimate::emoji::EmojiSetSlugFormat& slug) 0323 { 0324 d->image_slug = slug; 0325 } 0326 0327 const glaxnimate::emoji::EmojiSetSlugFormat & glaxnimate::emoji::EmojiDialog::image_slug_format() const 0328 { 0329 return d->image_slug; 0330 } 0331 0332 void glaxnimate::emoji::EmojiDialog::from_emoji_set(const glaxnimate::emoji::EmojiSet& set, int size) 0333 { 0334 const auto& path = set.download.paths.at(size); 0335 set_image_path(set.image_path(size)); 0336 set_image_slug_format(set.slug); 0337 set_image_suffix("." + path.format); 0338 } 0339 0340 void glaxnimate::emoji::EmojiDialog::resizeEvent(QResizeEvent* event) 0341 { 0342 QDialog::resizeEvent(event); 0343 #ifndef Q_OS_ANDROID 0344 d->on_rotate(); 0345 #endif 0346 }