summary refs log tree commit diff
path: root/src/emoji
diff options
context:
space:
mode:
authorredsky17 <joedonofry@gmail.com>2019-01-26 18:17:08 +0000
committerredsky17 <joedonofry@gmail.com>2019-01-26 18:17:08 +0000
commitdf5d24c87f46f42b8bc73710bcdcb1a3f5f27b49 (patch)
tree1a82673a6e345bfa651def94687fc9f8539795c6 /src/emoji
parentFix lint issues in last commit (diff)
downloadnheko-df5d24c87f46f42b8bc73710bcdcb1a3f5f27b49.tar.xz
Revert "Remove built-in emoji picker"
This reverts commit 4b807229aa20d6f4891e35f08d489da427d3d0b6.
Diffstat (limited to 'src/emoji')
-rw-r--r--src/emoji/Category.cpp90
-rw-r--r--src/emoji/Category.h59
-rw-r--r--src/emoji/ItemDelegate.cpp48
-rw-r--r--src/emoji/ItemDelegate.h43
-rw-r--r--src/emoji/Panel.cpp236
-rw-r--r--src/emoji/Panel.h66
-rw-r--r--src/emoji/PickButton.cpp82
-rw-r--r--src/emoji/PickButton.h55
8 files changed, 679 insertions, 0 deletions
diff --git a/src/emoji/Category.cpp b/src/emoji/Category.cpp
new file mode 100644

index 00000000..fbfbf4fc --- /dev/null +++ b/src/emoji/Category.cpp
@@ -0,0 +1,90 @@ +/* + * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <QPainter> +#include <QScrollBar> +#include <QStyleOption> + +#include "Config.h" + +#include "emoji/Category.h" + +using namespace emoji; + +Category::Category(QString category, std::vector<Emoji> emoji, QWidget *parent) + : QWidget(parent) +{ + mainLayout_ = new QVBoxLayout(this); + mainLayout_->setMargin(0); + mainLayout_->setSpacing(0); + + emojiListView_ = new QListView(); + itemModel_ = new QStandardItemModel(this); + + delegate_ = new ItemDelegate(this); + data_ = new Emoji; + + emojiListView_->setItemDelegate(delegate_); + emojiListView_->setModel(itemModel_); + emojiListView_->setViewMode(QListView::IconMode); + emojiListView_->setFlow(QListView::LeftToRight); + emojiListView_->setResizeMode(QListView::Adjust); + emojiListView_->verticalScrollBar()->setEnabled(false); + emojiListView_->horizontalScrollBar()->setEnabled(false); + + const int cols = 7; + const int rows = emoji.size() / 7; + + // TODO: Be precise here. Take the parent into consideration. + emojiListView_->setFixedSize(cols * 50 + 20, rows * 50 + 20); + emojiListView_->setGridSize(QSize(50, 50)); + emojiListView_->setDragEnabled(false); + emojiListView_->setEditTriggers(QAbstractItemView::NoEditTriggers); + + for (const auto &e : emoji) { + data_->unicode = e.unicode; + + auto item = new QStandardItem; + item->setSizeHint(QSize(24, 24)); + + QVariant unicode(data_->unicode); + item->setData(unicode.toString(), Qt::UserRole); + + itemModel_->appendRow(item); + } + + QFont font; + font.setWeight(QFont::Medium); + + category_ = new QLabel(category, this); + category_->setFont(font); + category_->setStyleSheet("margin: 20px 0 20px 8px;"); + + mainLayout_->addWidget(category_); + mainLayout_->addWidget(emojiListView_); + + connect(emojiListView_, &QListView::clicked, this, &Category::clickIndex); +} + +void +Category::paintEvent(QPaintEvent *) +{ + QStyleOption opt; + opt.init(this); + QPainter p(this); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); +} diff --git a/src/emoji/Category.h b/src/emoji/Category.h new file mode 100644
index 00000000..a14029c8 --- /dev/null +++ b/src/emoji/Category.h
@@ -0,0 +1,59 @@ +/* + * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include <QLabel> +#include <QLayout> +#include <QListView> +#include <QStandardItemModel> + +#include "ItemDelegate.h" + +namespace emoji { + +class Category : public QWidget +{ + Q_OBJECT + +public: + Category(QString category, std::vector<Emoji> emoji, QWidget *parent = nullptr); + +signals: + void emojiSelected(const QString &emoji); + +protected: + void paintEvent(QPaintEvent *event) override; + +private slots: + void clickIndex(const QModelIndex &index) + { + emit emojiSelected(index.data(Qt::UserRole).toString()); + }; + +private: + QVBoxLayout *mainLayout_; + + QStandardItemModel *itemModel_; + QListView *emojiListView_; + + emoji::Emoji *data_; + emoji::ItemDelegate *delegate_; + + QLabel *category_; +}; +} // namespace emoji diff --git a/src/emoji/ItemDelegate.cpp b/src/emoji/ItemDelegate.cpp new file mode 100644
index 00000000..50a1b7ed --- /dev/null +++ b/src/emoji/ItemDelegate.cpp
@@ -0,0 +1,48 @@ +/* + * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <QDebug> +#include <QPainter> + +#include "emoji/ItemDelegate.h" + +using namespace emoji; + +ItemDelegate::ItemDelegate(QObject *parent) + : QStyledItemDelegate(parent) +{ + data_ = new Emoji; +} + +ItemDelegate::~ItemDelegate() { delete data_; } + +void +ItemDelegate::paint(QPainter *painter, + const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + Q_UNUSED(index); + + QStyleOptionViewItem viewOption(option); + + auto emoji = index.data(Qt::UserRole).toString(); + + QFont font("Emoji One"); + + painter->setFont(font); + painter->drawText(viewOption.rect, Qt::AlignCenter, emoji); +} diff --git a/src/emoji/ItemDelegate.h b/src/emoji/ItemDelegate.h new file mode 100644
index 00000000..e0456308 --- /dev/null +++ b/src/emoji/ItemDelegate.h
@@ -0,0 +1,43 @@ +/* + * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include <QModelIndex> +#include <QStandardItemModel> +#include <QStyledItemDelegate> + +#include "Provider.h" + +namespace emoji { + +class ItemDelegate : public QStyledItemDelegate +{ + Q_OBJECT + +public: + explicit ItemDelegate(QObject *parent = nullptr); + ~ItemDelegate(); + + void paint(QPainter *painter, + const QStyleOptionViewItem &option, + const QModelIndex &index) const override; + +private: + Emoji *data_; +}; +} // namespace emoji diff --git a/src/emoji/Panel.cpp b/src/emoji/Panel.cpp new file mode 100644
index 00000000..710b501e --- /dev/null +++ b/src/emoji/Panel.cpp
@@ -0,0 +1,236 @@ +/* + * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <QPushButton> +#include <QScrollBar> +#include <QVBoxLayout> + +#include "ui/DropShadow.h" +#include "ui/FlatButton.h" + +#include "emoji/Category.h" +#include "emoji/Panel.h" + +using namespace emoji; + +Panel::Panel(QWidget *parent) + : QWidget(parent) + , shadowMargin_{2} + , width_{370} + , height_{350} + , categoryIconSize_{20} +{ + setStyleSheet("QWidget {border: none;}" + "QScrollBar:vertical { width: 0px; margin: 0px; }" + "QScrollBar::handle:vertical { min-height: 30px; }"); + + setAttribute(Qt::WA_ShowWithoutActivating, true); + setWindowFlags(Qt::Tool | Qt::FramelessWindowHint | Qt::NoDropShadowWindowHint); + + auto mainWidget = new QWidget(this); + mainWidget->setMaximumSize(width_, height_); + + auto topLayout = new QVBoxLayout(this); + topLayout->addWidget(mainWidget); + topLayout->setMargin(shadowMargin_); + topLayout->setSpacing(0); + + auto contentLayout = new QVBoxLayout(mainWidget); + contentLayout->setMargin(0); + contentLayout->setSpacing(0); + + auto emojiCategories = new QFrame(mainWidget); + + auto categoriesLayout = new QHBoxLayout(emojiCategories); + categoriesLayout->setSpacing(0); + categoriesLayout->setMargin(0); + + QIcon icon; + + auto peopleCategory = new FlatButton(emojiCategories); + icon.addFile(":/icons/icons/emoji-categories/people.png"); + peopleCategory->setIcon(icon); + peopleCategory->setIconSize(QSize(categoryIconSize_, categoryIconSize_)); + + auto natureCategory_ = new FlatButton(emojiCategories); + icon.addFile(":/icons/icons/emoji-categories/nature.png"); + natureCategory_->setIcon(icon); + natureCategory_->setIconSize(QSize(categoryIconSize_, categoryIconSize_)); + + auto foodCategory_ = new FlatButton(emojiCategories); + icon.addFile(":/icons/icons/emoji-categories/foods.png"); + foodCategory_->setIcon(icon); + foodCategory_->setIconSize(QSize(categoryIconSize_, categoryIconSize_)); + + auto activityCategory = new FlatButton(emojiCategories); + icon.addFile(":/icons/icons/emoji-categories/activity.png"); + activityCategory->setIcon(icon); + activityCategory->setIconSize(QSize(categoryIconSize_, categoryIconSize_)); + + auto travelCategory = new FlatButton(emojiCategories); + icon.addFile(":/icons/icons/emoji-categories/travel.png"); + travelCategory->setIcon(icon); + travelCategory->setIconSize(QSize(categoryIconSize_, categoryIconSize_)); + + auto objectsCategory = new FlatButton(emojiCategories); + icon.addFile(":/icons/icons/emoji-categories/objects.png"); + objectsCategory->setIcon(icon); + objectsCategory->setIconSize(QSize(categoryIconSize_, categoryIconSize_)); + + auto symbolsCategory = new FlatButton(emojiCategories); + icon.addFile(":/icons/icons/emoji-categories/symbols.png"); + symbolsCategory->setIcon(icon); + symbolsCategory->setIconSize(QSize(categoryIconSize_, categoryIconSize_)); + + auto flagsCategory = new FlatButton(emojiCategories); + icon.addFile(":/icons/icons/emoji-categories/flags.png"); + flagsCategory->setIcon(icon); + flagsCategory->setIconSize(QSize(categoryIconSize_, categoryIconSize_)); + + categoriesLayout->addWidget(peopleCategory); + categoriesLayout->addWidget(natureCategory_); + categoriesLayout->addWidget(foodCategory_); + categoriesLayout->addWidget(activityCategory); + categoriesLayout->addWidget(travelCategory); + categoriesLayout->addWidget(objectsCategory); + categoriesLayout->addWidget(symbolsCategory); + categoriesLayout->addWidget(flagsCategory); + + scrollArea_ = new QScrollArea(this); + scrollArea_->setWidgetResizable(true); + scrollArea_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + auto scrollWidget = new QWidget(this); + auto scrollLayout = new QVBoxLayout(scrollWidget); + + scrollLayout->setMargin(0); + scrollLayout->setSpacing(0); + scrollArea_->setWidget(scrollWidget); + + auto peopleEmoji = + new Category(tr("Smileys & People"), emoji_provider_.people, scrollWidget); + scrollLayout->addWidget(peopleEmoji); + + auto natureEmoji = + new Category(tr("Animals & Nature"), emoji_provider_.nature, scrollWidget); + scrollLayout->addWidget(natureEmoji); + + auto foodEmoji = new Category(tr("Food & Drink"), emoji_provider_.food, scrollWidget); + scrollLayout->addWidget(foodEmoji); + + auto activityEmoji = new Category(tr("Activity"), emoji_provider_.activity, scrollWidget); + scrollLayout->addWidget(activityEmoji); + + auto travelEmoji = + new Category(tr("Travel & Places"), emoji_provider_.travel, scrollWidget); + scrollLayout->addWidget(travelEmoji); + + auto objectsEmoji = new Category(tr("Objects"), emoji_provider_.objects, scrollWidget); + scrollLayout->addWidget(objectsEmoji); + + auto symbolsEmoji = new Category(tr("Symbols"), emoji_provider_.symbols, scrollWidget); + scrollLayout->addWidget(symbolsEmoji); + + auto flagsEmoji = new Category(tr("Flags"), emoji_provider_.flags, scrollWidget); + scrollLayout->addWidget(flagsEmoji); + + contentLayout->addWidget(scrollArea_); + contentLayout->addWidget(emojiCategories); + + connect(peopleEmoji, &Category::emojiSelected, this, &Panel::emojiSelected); + connect(peopleCategory, &QPushButton::clicked, [this, peopleEmoji]() { + this->showCategory(peopleEmoji); + }); + + connect(natureEmoji, &Category::emojiSelected, this, &Panel::emojiSelected); + connect(natureCategory_, &QPushButton::clicked, [this, natureEmoji]() { + this->showCategory(natureEmoji); + }); + + connect(foodEmoji, &Category::emojiSelected, this, &Panel::emojiSelected); + connect(foodCategory_, &QPushButton::clicked, [this, foodEmoji]() { + this->showCategory(foodEmoji); + }); + + connect(activityEmoji, &Category::emojiSelected, this, &Panel::emojiSelected); + connect(activityCategory, &QPushButton::clicked, [this, activityEmoji]() { + this->showCategory(activityEmoji); + }); + + connect(travelEmoji, &Category::emojiSelected, this, &Panel::emojiSelected); + connect(travelCategory, &QPushButton::clicked, [this, travelEmoji]() { + this->showCategory(travelEmoji); + }); + + connect(objectsEmoji, &Category::emojiSelected, this, &Panel::emojiSelected); + connect(objectsCategory, &QPushButton::clicked, [this, objectsEmoji]() { + this->showCategory(objectsEmoji); + }); + + connect(symbolsEmoji, &Category::emojiSelected, this, &Panel::emojiSelected); + connect(symbolsCategory, &QPushButton::clicked, [this, symbolsEmoji]() { + this->showCategory(symbolsEmoji); + }); + + connect(flagsEmoji, &Category::emojiSelected, this, &Panel::emojiSelected); + connect(flagsCategory, &QPushButton::clicked, [this, flagsEmoji]() { + this->showCategory(flagsEmoji); + }); +} + +void +Panel::showCategory(const Category *category) +{ + auto posToGo = category->mapToParent(QPoint()).y(); + auto current = scrollArea_->verticalScrollBar()->value(); + + if (current == posToGo) + return; + + // HACK + // If we want to go to a previous category and position the label at the top + // the 6*50 offset won't work because not all the categories have the same + // height. To ensure the category is at the top, we move to the top and go as + // normal to the next category. + if (current > posToGo) + this->scrollArea_->ensureVisible(0, 0, 0, 0); + + posToGo += 6 * 50; + this->scrollArea_->ensureVisible(0, posToGo, 0, 0); +} + +void +Panel::paintEvent(QPaintEvent *event) +{ + Q_UNUSED(event); + + QStyleOption opt; + opt.init(this); + QPainter p(this); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); + + DropShadow::draw(p, + shadowMargin_, + 4.0, + QColor(120, 120, 120, 92), + QColor(255, 255, 255, 0), + 0.0, + 1.0, + 0.6, + width(), + height()); +} diff --git a/src/emoji/Panel.h b/src/emoji/Panel.h new file mode 100644
index 00000000..ad233c27 --- /dev/null +++ b/src/emoji/Panel.h
@@ -0,0 +1,66 @@ +/* + * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include <QScrollArea> + +#include "Provider.h" + +namespace emoji { + +class Category; + +class Panel : public QWidget +{ + Q_OBJECT + +public: + Panel(QWidget *parent = nullptr); + +signals: + void mouseLeft(); + void emojiSelected(const QString &emoji); + +protected: + void leaveEvent(QEvent *event) override + { + emit leaving(); + QWidget::leaveEvent(event); + } + + void paintEvent(QPaintEvent *event) override; + +signals: + void leaving(); + +private: + void showCategory(const Category *category); + + Provider emoji_provider_; + + QScrollArea *scrollArea_; + + int shadowMargin_; + + // Panel dimensions. + int width_; + int height_; + + int categoryIconSize_; +}; +} // namespace emoji diff --git a/src/emoji/PickButton.cpp b/src/emoji/PickButton.cpp new file mode 100644
index 00000000..608b4fa2 --- /dev/null +++ b/src/emoji/PickButton.cpp
@@ -0,0 +1,82 @@ +/* + * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <QDebug> + +#include "emoji/Panel.h" +#include "emoji/PickButton.h" + +using namespace emoji; + +// Number of milliseconds after which the panel will be hidden +// if the mouse cursor is not on top of the widget. +constexpr int HIDE_TIMEOUT = 300; + +PickButton::PickButton(QWidget *parent) + : FlatButton(parent) + , panel_{nullptr} +{ + connect(&hideTimer_, &QTimer::timeout, this, &PickButton::hidePanel); + connect(this, &QPushButton::clicked, this, [this]() { + if (panel_ && panel_->isVisible()) { + hidePanel(); + return; + } + + showPanel(); + }); +} + +void +PickButton::hidePanel() +{ + if (panel_ && !panel_->underMouse()) { + hideTimer_.stop(); + panel_->hide(); + } +} + +void +PickButton::showPanel() +{ + if (panel_.isNull()) { + panel_ = QSharedPointer<Panel>(new Panel(this)); + connect(panel_.data(), &Panel::emojiSelected, this, &PickButton::emojiSelected); + connect(panel_.data(), &Panel::leaving, this, [this]() { panel_->hide(); }); + } + + if (panel_->isVisible()) + return; + + QPoint pos(rect().x(), rect().y()); + pos = this->mapToGlobal(pos); + + auto panel_size = panel_->sizeHint(); + + auto x = pos.x() - panel_size.width() + horizontal_distance_; + auto y = pos.y() - panel_size.height() - vertical_distance_; + + panel_->move(x, y); + panel_->show(); +} + +void +PickButton::leaveEvent(QEvent *e) +{ + hideTimer_.start(HIDE_TIMEOUT); + FlatButton::leaveEvent(e); +} diff --git a/src/emoji/PickButton.h b/src/emoji/PickButton.h new file mode 100644
index 00000000..97ed8c37 --- /dev/null +++ b/src/emoji/PickButton.h
@@ -0,0 +1,55 @@ +/* + * nheko Copyright (C) 2017 Konstantinos Sideris <siderisk@auth.gr> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include <QEvent> +#include <QTimer> +#include <QWidget> + +#include "ui/FlatButton.h" + +namespace emoji { + +class Panel; + +class PickButton : public FlatButton +{ + Q_OBJECT +public: + explicit PickButton(QWidget *parent = nullptr); + +signals: + void emojiSelected(const QString &emoji); + +protected: + void leaveEvent(QEvent *e) override; + +private: + void showPanel(); + void hidePanel(); + + // Vertical distance from panel's bottom. + int vertical_distance_ = 10; + + // Horizontal distance from panel's bottom right corner. + int horizontal_distance_ = 70; + + QSharedPointer<Panel> panel_; + QTimer hideTimer_; +}; +} // namespace emoji