Add full emoji support

This commit is contained in:
Konstantinos Sideris 2017-04-23 21:31:08 +03:00
parent ebbce440bf
commit 42bb9bb63a
40 changed files with 2715 additions and 17 deletions

View File

@ -71,6 +71,11 @@ endif()
set(SRC_FILES
src/ChatPage.cc
src/Deserializable.cc
src/EmojiCategory.cc
src/EmojiItemDelegate.cc
src/EmojiPanel.cc
src/EmojiPickButton.cc
src/EmojiProvider.cc
src/HistoryView.cc
src/HistoryViewItem.cc
src/HistoryViewManager.cc
@ -116,6 +121,10 @@ qt5_wrap_ui (UI_HEADERS
qt5_wrap_cpp(MOC_HEADERS
include/ChatPage.h
include/EmojiCategory.h
include/EmojiItemDelegate.h
include/EmojiPanel.h
include/EmojiPickButton.h
include/HistoryView.h
include/HistoryViewItem.h
include/HistoryViewManager.h

62
include/EmojiCategory.h Normal file
View File

@ -0,0 +1,62 @@
/*
* 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/>.
*/
#ifndef EMOJI_CATEGORY_H
#define EMOJI_CATEGORY_H
#include <QHBoxLayout>
#include <QLabel>
#include <QListView>
#include <QStandardItemModel>
#include <QVBoxLayout>
#include <QWidget>
#include "EmojiItemDelegate.h"
#include "EmojiProvider.h"
class EmojiCategory : public QWidget
{
Q_OBJECT
public:
EmojiCategory(QString category, QList<Emoji> emoji, QWidget *parent = nullptr);
~EmojiCategory();
signals:
void emojiSelected(const QString &emoji);
private slots:
inline void clickIndex(const QModelIndex &);
private:
QVBoxLayout *mainLayout_;
QStandardItemModel *itemModel_;
QListView *emojiListView_;
Emoji *data_;
EmojiItemDelegate *delegate_;
QLabel *category_;
};
inline void EmojiCategory::clickIndex(const QModelIndex &index)
{
emit emojiSelected(index.data(Qt::UserRole).toString());
}
#endif // EMOJI_CATEGORY_H

View File

@ -0,0 +1,41 @@
/*
* 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/>.
*/
#ifndef EMOJI_ITEM_DELEGATE_H
#define EMOJI_ITEM_DELEGATE_H
#include <QModelIndex>
#include <QStandardItemModel>
#include <QStyledItemDelegate>
#include "EmojiProvider.h"
class EmojiItemDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
explicit EmojiItemDelegate(QObject *parent = nullptr);
~EmojiItemDelegate();
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
private:
Emoji *data_;
};
#endif // EMOJI_ITEM_DELEGATE_H

60
include/EmojiPanel.h Normal file
View File

@ -0,0 +1,60 @@
/*
* 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/>.
*/
#ifndef EMOJI_PANEL_H
#define EMOJI_PANEL_H
#include <QFrame>
#include <QGraphicsOpacityEffect>
#include <QPropertyAnimation>
#include <QScrollArea>
#include <QWidget>
#include "EmojiCategory.h"
#include "EmojiProvider.h"
class EmojiPanel : public QFrame
{
Q_OBJECT
public:
EmojiPanel(QWidget *parent = nullptr);
void fadeOut();
void fadeIn();
signals:
void mouseLeft();
void emojiSelected(const QString &emoji);
protected:
void leaveEvent(QEvent *event);
private:
void showEmojiCategory(const EmojiCategory *category);
QPropertyAnimation *animation_;
QGraphicsOpacityEffect *opacity_;
EmojiProvider emoji_provider_;
QScrollArea *scroll_area_;
const int category_icon_size_ = 20;
};
#endif // EMOJI_PANEL_H

50
include/EmojiPickButton.h Normal file
View File

@ -0,0 +1,50 @@
/*
* 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/>.
*/
#ifndef EMOJI_PICK_BUTTON_H
#define EMOJI_PICK_BUTTON_H
#include <QEvent>
#include <QWidget>
#include "EmojiPanel.h"
#include "FlatButton.h"
class EmojiPickButton : public FlatButton
{
Q_OBJECT
public:
explicit EmojiPickButton(QWidget *parent = nullptr);
signals:
void emojiSelected(const QString &emoji);
protected:
void enterEvent(QEvent *e) override;
void leaveEvent(QEvent *e) override;
private:
// Vertical distance from panel's bottom.
int vertical_distance_ = 10;
// Horizontal distance from panel's bottom right corner.
int horizontal_distance_ = 70;
EmojiPanel *panel_;
};
#endif // EMOJI_PICK_BUTTON_H

45
include/EmojiProvider.h Normal file
View File

@ -0,0 +1,45 @@
/*
* 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/>.
*/
#ifndef EMOJI_PROVIDER_H
#define EMOJI_PROVIDER_H
#include <QFile>
#include <QList>
#include <QMap>
struct Emoji {
// Unicode code.
QString unicode;
// Keyboard shortcut e.g :emoji:
QString shortname;
};
class EmojiProvider
{
public:
static const QList<Emoji> people;
static const QList<Emoji> nature;
static const QList<Emoji> food;
static const QList<Emoji> activity;
static const QList<Emoji> travel;
static const QList<Emoji> objects;
static const QList<Emoji> symbols;
static const QList<Emoji> flags;
};
#endif // EMOJI_PROVIDER_H

View File

@ -19,12 +19,24 @@
#define TEXT_INPUT_WIDGET_H
#include <QHBoxLayout>
#include <QLineEdit>
#include <QPaintEvent>
#include <QTextEdit>
#include <QWidget>
#include "EmojiPickButton.h"
#include "FlatButton.h"
class FilteredTextEdit : public QTextEdit
{
Q_OBJECT
public:
explicit FilteredTextEdit(QWidget *parent = nullptr);
void keyPressEvent(QKeyEvent *event);
signals:
void enterPressed();
};
class TextInputWidget : public QWidget
{
Q_OBJECT
@ -36,6 +48,9 @@ public:
public slots:
void onSendButtonClicked();
private slots:
void addSelectedEmoji(const QString &emoji);
signals:
void sendTextMessage(QString msg);
@ -44,10 +59,11 @@ protected:
private:
QHBoxLayout *top_layout_;
QLineEdit *input_;
FilteredTextEdit *input_;
FlatButton *send_file_button_;
FlatButton *send_message_button_;
EmojiPickButton *emoji_button_;
};
#endif // TEXT_INPUT_WIDGET_H

View File

@ -133,7 +133,7 @@ public:
protected:
enum {
IconPadding = 12
IconPadding = 0
};
void checkStateSet() override;

1
resources/emoji.json Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 659 B

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xml:space="preserve"
enable-background="new 0 0 24 24"
viewBox="0 0 24 24"
height="24px"
width="24px"
y="0px"
x="0px"
id="Слой_1"
version="1.1"><metadata
id="metadata4213"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs4211" /><g
id="g4205"><path
style="fill:#000000;fill-opacity:1"
id="path4207"
d="M12,0C5.373,0,0,5.372,0,12c0,6.627,5.373,12,12,12c6.628,0,12-5.373,12-12C24,5.372,18.628,0,12,0 M21.949,11H17.05c0.224-2.527,1.232-4.773,1.968-6.113C20.634,6.481,21.712,8.618,21.949,11 M13,11V2.051 c1.623,0.162,3.13,0.719,4.432,1.564C16.574,5.106,15.276,7.835,15.04,11H13z M11,11H8.961C8.723,7.835,7.425,5.106,6.568,3.615 C7.871,2.77,9.377,2.213,11,2.051V11z M11,13v8.949c-1.623-0.162-3.129-0.718-4.432-1.564C7.425,18.893,8.723,16.164,8.961,13H11z M15.04,13c0.236,3.164,1.534,5.893,2.392,7.385c-1.302,0.847-2.809,1.402-4.432,1.564V13H15.04z M4.982,4.887 C5.718,6.227,6.726,8.473,6.951,11h-4.9C2.289,8.618,3.367,6.481,4.982,4.887 M2.051,13h4.9c-0.226,2.527-1.233,4.771-1.969,6.113 C3.367,17.52,2.289,15.383,2.051,13 M19.018,19.113c-0.735-1.342-1.744-3.586-1.968-6.113h4.899 C21.712,15.383,20.634,17.52,19.018,19.113"
fill="#010202" /></g></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
id="svg2"
viewBox="0 0 32 32"
height="32"
width="32"
version="1.1">
<metadata
id="metadata10">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs8" />
<path
id="path4"
d="M14 8c0-1.105 0.895-2 2-2s2 0.895 2 2c0 1.105-0.895 2-2 2s-2-0.895-2-2zM16 0c-8.837 0-16 7.163-16 16s7.163 16 16 16 16-7.163 16-16-7.163-16-16-16zM16 26c-1.105 0-2-0.895-2-2s0.895-2 2-2c1.105 0 2 0.895 2 2s-0.895 2-2 2zM16 16c-3.59 0-6.5 2.91-6.5 6.5s2.91 6.5 6.5 6.5c-7.18 0-13-5.82-13-13s5.82-13 13-13c3.59 0 6.5 2.91 6.5 6.5s-2.91 6.5-6.5 6.5z" />
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 472 B

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xml:space="preserve"
enable-background="new 0 0 24 24"
viewBox="0 0 24 24"
height="24px"
width="24px"
y="0px"
x="0px"
id="Слой_1"
version="1.1"><metadata
id="metadata6641"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs6639" /><g
id="g6631"><polygon
style="fill:#000000;fill-opacity:1"
id="polygon6633"
points="0,0 6.084,24 8,24 1.916,0 "
fill="#010202" /><path
style="fill:#000000;fill-opacity:1"
id="path6635"
d="M21,5h-4l-1-4H4l3,12h3l1,4h2h11L21,5z M6.563,3h7.875l2,8H8.563L6.563,3z M15.395,13l-2.856,1.904 L12.063,13H15.395z M19,13l-1.5-6h1.938l2,8H16L19,13z"
fill="#010202" /></g></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 599 B

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xml:space="preserve"
enable-background="new 0 0 24 24"
viewBox="0 0 24 24"
height="24px"
width="24px"
y="0px"
x="0px"
id="Слой_1"
version="1.1"><metadata
id="metadata4164"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs4162" /><g
id="g4156"><path
style="fill:#000000;fill-opacity:1"
id="path4158"
d="M17,4.978c-1.838,0-2.876,0.396-3.68,0.934c0.513-1.172,1.768-2.934,4.68-2.934c0.552,0,1-0.448,1-1 s-0.448-1-1-1c-2.921,0-4.629,1.365-5.547,2.512c-0.064,0.078-0.119,0.162-0.18,0.244c-0.543-1.896-1.475-3.711-3.066-3.711 C8.579,0.022,7.85,0.306,7,0.978C5.027,2.54,5.329,3.902,6.492,4.999C3.609,5.222,0,7.352,0,12.969c0,4.582,4.961,11.009,9,11.009 c1.975,0,2.371-0.486,3-1c0.629,0.514,1.025,1,3,1c4.039,0,9-6.418,9-11C24,7.025,19.945,4.978,17,4.978 M8.242,2.546 c0.641-0.508,0.943-0.523,0.965-0.523c0.426,0.169,0.975,1.405,1.357,3.055c-1.527-0.629-2.741-1.352-2.98-1.846 C7.643,3.12,7.825,2.876,8.242,2.546 M15,21.978c-1.08,0-1.21-0.109-1.559-0.402l-0.176-0.146 c-0.367-0.302-0.816-0.452-1.266-0.452s-0.898,0.15-1.266,0.452l-0.176,0.146C10.21,21.868,10.08,21.978,9,21.978 c-2.813,0-7-5.389-7-9.009c0-5.823,4.488-5.991,5-5.991c1.939,0,2.484,0.471,3.387,1.251c0.107,0.092,0.215,0.185,0.323,0.276 C11.083,8.82,11.541,8.978,12,8.978s0.917-0.157,1.29-0.473c0.108-0.092,0.216-0.185,0.323-0.276 c0.902-0.78,1.447-1.251,3.387-1.251c0.512,0,5,0.168,5,6C22,16.595,17.813,21.978,15,21.978"
fill="#010202" /></g></svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 725 B

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xml:space="preserve"
enable-background="new 0 0 24 24"
viewBox="0 0 24 24"
height="24px"
width="24px"
y="0px"
x="0px"
id="Слой_1"
version="1.1"><metadata
id="metadata6036"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs6034" /><g
id="g6024"><g
id="g6578"><g
id="g6583"><path
style="fill:#000000;fill-opacity:1"
id="path6028"
d="M15.5,8C14.672,8,14,8.672,14,9.5s0.672,1.5,1.5,1.5S17,10.329,17,9.5S16.328,8,15.5,8"
fill="#010202" /><g
id="g6588"><path
fill="#010202"
d="M8.5,8C7.672,8,7,8.672,7,9.5S7.672,11,8.5,11S10,10.329,10,9.5S9.329,8,8.5,8"
id="path6026"
style="fill:#000000;fill-opacity:1" /><path
fill="#010202"
d="M18.933,0h-0.027c-0.97,0-2.138,0.787-3.018,1.497c-1.274-0.374-2.612-0.51-3.887-0.51 c-1.285,0-2.616,0.133-3.874,0.517C7.245,0.79,6.069,0,5.093,0H5.066C3.352,0,0.07,2.67,0.002,7.026 c-0.039,2.479,0.276,4.238,1.04,5.013c0.254,0.258,0.882,0.677,1.295,0.882c0.191,3.177,0.922,5.238,2.536,6.38 c0.897,0.637,2.187,0.949,3.2,1.102C8.04,20.6,8,20.795,8,21c0,1.773,2.35,3,4,3c1.648,0,4-1.227,4-3 c0-0.201-0.038-0.393-0.072-0.586c2.573-0.385,5.435-1.877,5.925-7.587c0.396-0.22,0.887-0.568,1.104-0.788 c0.763-0.774,1.079-2.534,1.04-5.013C23.929,2.67,20.646,0,18.933,0 M3.223,9.135c-0.237,0.281-0.837,1.155-0.884,1.238 c-0.15-0.41-0.368-1.349-0.337-3.291C2.053,3.801,4.48,2.11,5.093,2.051c0.256,0.015,0.731,0.27,1.265,0.646 c-1.11,1.171-2.275,2.915-2.352,5.125C3.873,8.368,3.608,8.68,3.223,9.135 M12,22c-0.901,0-1.954-0.693-2-1 c0-0.654,0.475-1.236,1-1.602V20c0,0.553,0.447,1,1,1s1-0.447,1-1v-0.602c0.524,0.365,1,0.947,1,1.602 C13.954,21.307,12.901,22,12,22 M15,18.52v0.02c-0.366-0.418-0.798-0.762-1.262-1.02c1.092-0.516,2.239-1.334,2.239-2.217 c0-1.842-1.781-2.195-3.977-2.195c-2.196,0-3.978,0.354-3.978,2.195c0,0.883,1.148,1.701,2.238,2.217 C9.799,17.777,9.368,18.121,9,18.539v-0.025c-1-0.076-2.182-0.281-2.973-0.842c-1.301-0.92-1.838-3.045-1.853-6.478 c0.008-0.014,0.016-0.028,0.023-0.041c0.496-0.826,1.49-1.45,1.804-3.102c0-2.047,1.357-3.631,2.362-4.522 C9.37,3.178,10.555,3,11.948,3c1.447,0,2.685,0.192,3.733,0.57c1,0.9,2.316,2.465,2.316,4.48c0.313,1.651,1.307,2.275,1.803,3.102 c0.035,0.058,0.068,0.117,0.102,0.178C19.843,17.297,17.953,18.34,15,18.52 M21.628,10.318c-0.037-0.065-0.074-0.13-0.113-0.195 c-0.233-0.387-0.502-0.706-0.739-0.987c-0.385-0.455-0.648-0.768-0.782-1.313c-0.076-2.209-1.241-3.954-2.353-5.124 c0.531-0.376,1.004-0.63,1.261-0.647c0.636,0.071,3.044,1.764,3.096,5.031C22.025,8.893,21.651,10.301,21.628,10.318"
id="path6030"
style="fill:#000000;fill-opacity:1" /></g></g></g></g></svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 640 B

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xml:space="preserve"
enable-background="new 0 0 24 24"
viewBox="0 0 24 24"
height="24px"
width="24px"
y="0px"
x="0px"
id="Слой_1"
version="1.1"><metadata
id="metadata4838"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs4836" /><g
id="g4820"><g
id="g4822" /><g
id="g4830"><g
id="g5383"><path
style="fill:#000000;fill-opacity:1"
d="M 12 0 C 7.029 0 3 4.029 3 9 C 3 12.120081 4.5888411 14.867862 7 16.482422 L 7 21 C 7 21 9.035 24 12 24 C 14.965 24 17 21 17 21 L 17 16.482422 C 19.411159 14.867862 21 12.120081 21 9 C 21 4.029 16.971 0 12 0 z M 12 2 C 15.86 2 19 5.141 19 9 C 19 12.859 15.86 16 12 16 C 8.14 16 5 12.859 5 9 C 5 5.141 8.14 2 12 2 z M 9 17.476562 C 9.9397054 17.809261 10.946226 18 12 18 C 13.053774 18 14.060295 17.809261 15 17.476562 L 15 18.310547 C 14.089581 18.746635 13.074971 19 12 19 C 10.925029 19 9.9104192 18.746635 9 18.310547 L 9 17.476562 z M 9.2363281 20.546875 C 10.108023 20.832252 11.032636 21 12 21 C 12.965197 21 13.887813 20.832689 14.757812 20.548828 C 14.155076 21.173162 13.152816 22 12 22 C 10.89775 22 9.8827458 21.211335 9.2363281 20.546875 z "
id="path4824" /><path
fill="#010202"
d="M14.745,12.449h-0.004c-0.852-0.024-1.188-0.858-1.577-1.824c-0.421-1.061-0.703-1.561-1.182-1.566h-0.009 c-0.481,0-0.783,0.497-1.235,1.537c-0.436,0.982-0.801,1.811-1.636,1.791l-0.276-0.043c-0.565-0.171-0.853-0.691-1.284-1.794 c-0.125-0.313-0.202-0.632-0.27-0.913C7.221,9.424,7.145,9.107,7.077,9.003C7.067,9.004,7.039,9,6.99,9 C6.438,8.994,5.994,8.543,6,7.99C6.006,7.441,6.452,7,7,7h0.01c1.662,0.017,2.015,1.373,2.198,2.134 c0.486-0.981,1.304-2.058,2.797-2.075c1.531,0.018,2.28,1.153,2.731,2.141c0-0.002,0.001-0.006,0.002-0.008 C14.944,8.424,15.327,7,16.979,7h0.032C17.563,7.007,18.006,7.459,18,8.012C17.994,8.56,17.547,9,17,9h-0.011 c-0.149,0.076-0.256,0.474-0.319,0.709c-0.079,0.295-0.169,0.629-0.311,0.951C15.93,11.633,15.569,12.449,14.745,12.449"
id="path4832" /></g></g></g></svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 637 B

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xml:space="preserve"
enable-background="new 0 0 24 24"
viewBox="0 0 24 24"
height="24px"
width="24px"
y="0px"
x="0px"
id="Слой_1"
version="1.1"><metadata
id="metadata7236"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs7234" /><g
id="g7222"><path
style="fill:#000000;fill-opacity:1"
id="path7224"
d="M12,0C5.373,0,0,5.373,0,12s5.373,12,12,12s12-5.373,12-12S18.627,0,12,0 M12,22C6.486,22,2,17.514,2,12 S6.486,2,12,2s10,4.486,10,10S17.514,22,12,22"
fill="#010202" /><path
style="fill:#000000;fill-opacity:1"
id="path7226"
d="M8,7C6.895,7,6,7.895,6,9s0.895,2,2,2s2-0.895,2-2S9.105,7,8,7"
fill="#010202" /><path
style="fill:#000000;fill-opacity:1"
id="path7228"
d="M16,7c-1.105,0-2,0.895-2,2s0.895,2,2,2s2-0.895,2-2S17.105,7,16,7"
fill="#010202" /><path
style="fill:#000000;fill-opacity:1"
id="path7230"
d="M15.232,15c-0.693,1.195-1.87,2-3.349,2c-1.477,0-2.655-0.805-3.347-2H15 M18,13H6c0,3.314,2.686,6,6,6 S18,16.314,18,13"
fill="#010202" /></g></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xml:space="preserve"
enable-background="new 0 0 24 24"
viewBox="0 0 24 24"
height="24px"
width="24px"
y="0px"
x="0px"
id="Слой_1"
version="1.1"><metadata
id="metadata8433"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs8431" /><g
id="g8421"><path
id="polygon8423"
d="M 13,4 11,4 10.999,11 9,11 l 0,2 2,0 0,2 2,0 0,-2 4,0 0,-2 -4,0 z"
style="fill:#000000;fill-opacity:1" /><g
id="g8425"><path
style="fill:#000000;fill-opacity:1"
id="path8427"
d="M12,0C5.373,0,0,5.373,0,12s5.373,12,12,12s12-5.373,12-12S18.627,0,12,0 M12,22C6.486,22,2,17.514,2,12 S6.486,2,12,2s10,4.486,10,10S17.514,22,12,22"
fill="#010202" /></g></g></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 560 B

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xml:space="preserve"
enable-background="new 0 0 24 24"
viewBox="0 0 24 24"
height="24px"
width="24px"
y="0px"
x="0px"
id="Слой_1"
version="1.1"><metadata
id="metadata7837"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs7835" /><g
id="g7817"><path
id="rect7819"
d="M 0,0 11,0 11,2 0,2 Z"
style="fill:#000000;fill-opacity:1" /><path
id="polygon7821"
d="M 4,11 7,11 7,6 11,6 11,4 0,4 0,6 4,6 Z"
style="fill:#000000;fill-opacity:1" /><path
style="fill:#000000;fill-opacity:1"
id="path7823"
d="M15.5,17c1.381,0,2.5-1.116,2.5-2.493s-1.119-2.493-2.5-2.493S13,13.13,13,14.507S14.119,17,15.5,17 M15.5,14.014c0.276,0,0.5,0.222,0.5,0.493C16,14.779,15.776,15,15.5,15S15,14.779,15,14.507C15,14.235,15.224,14.014,15.5,14.014"
fill="#010202" /><path
style="fill:#000000;fill-opacity:1"
id="path7825"
d="M21.5,19.014c-1.381,0-2.5,1.116-2.5,2.493S20.119,24,21.5,24s2.5-1.116,2.5-2.493 S22.881,19.014,21.5,19.014 M21.5,22c-0.276,0-0.5-0.221-0.5-0.493c0-0.271,0.224-0.493,0.5-0.493s0.5,0.222,0.5,0.493 C22,21.779,21.776,22,21.5,22"
fill="#010202" /><path
id="polygon7827"
d="m 22,13 -9,9 1.513,1.5 8.99,-9.009 z"
style="fill:#000000;fill-opacity:1" /><path
style="fill:#000000;fill-opacity:1"
id="path7829"
d="M17,11c2.209,0,4-1.119,4-2.5V2c0,0,0.985-0.161,1.498,0.949C23.01,4.055,23,6,23,6s1-1.119,1-3.135 C24-0.02,21,0,21,0h-2v6.347C18.41,6.132,17.732,6,17,6c-2.209,0-4,1.119-4,2.5S14.791,11,17,11"
fill="#010202" /><path
style="fill:#000000;fill-opacity:1"
id="path7831"
d="M10.297,20.482l-1.475-1.585c-0.773,0.619-1.254,0.995-1.442,1.129c-0.307-0.288-0.989-1.016-2.045-2.183 c0.902-0.836,1.479-1.466,1.729-1.892s0.376-0.871,0.376-1.336c0-0.592-0.273-1.178-0.818-1.759 c-0.546-0.581-1.329-0.871-2.349-0.871c-1.008,0-1.79,0.293-2.344,0.879c-0.556,0.587-0.832,1.181-0.832,1.784 c0,0.813,0.419,1.748,1.256,2.805c-0.847,0.614-1.444,1.208-1.794,1.784c-0.35,0.575-0.523,1.186-0.523,1.833 c0,0.857,0.308,1.56,0.924,2.107C1.576,23.726,2.383,24,3.38,24c1.173,0,2.444-0.379,3.813-1.137L8.235,24h2.819l-2.09-2.383 L10.297,20.482z M3.561,14.093c0.199-0.19,0.443-0.286,0.73-0.286c0.31,0,0.559,0.085,0.747,0.254 c0.189,0.171,0.283,0.391,0.283,0.659c0,0.518-0.419,1.112-1.257,1.784c-0.536-0.651-0.805-1.231-0.805-1.742 C3.26,14.508,3.36,14.284,3.561,14.093 M3.74,22c-0.427,0-0.778-0.116-1.057-0.349c-0.279-0.232-0.418-0.487-0.418-0.766 c0-0.594,0.509-1.288,1.527-2.083c0.968,1.134,1.717,1.946,2.248,2.438C5.119,21.747,4.354,22,3.74,22"
fill="#010202" /></g></svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 535 B

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xml:space="preserve"
enable-background="new 0 0 24 24"
viewBox="0 0 24 24"
height="24px"
width="24px"
y="0px"
x="0px"
id="Слой_1"
version="1.1"><metadata
id="metadata5438"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs5436" /><g
id="g5426"><g
id="g5980"><path
fill="#010202"
d="M6.5,12C5.122,12,4,13.121,4,14.5S5.122,17,6.5,17S9,15.879,9,14.5S7.878,12,6.5,12 M6.5,15 C6.225,15,6,14.775,6,14.5S6.225,14,6.5,14S7,14.225,7,14.5S6.775,15,6.5,15"
id="path5428"
style="fill:#000000;fill-opacity:1" /><path
fill="#010202"
d="M17.5,12c-1.378,0-2.5,1.121-2.5,2.5s1.122,2.5,2.5,2.5s2.5-1.121,2.5-2.5S18.878,12,17.5,12 M17.5,15 c-0.275,0-0.5-0.225-0.5-0.5s0.225-0.5,0.5-0.5s0.5,0.225,0.5,0.5S17.775,15,17.5,15"
id="path5430"
style="fill:#000000;fill-opacity:1" /><path
fill="#010202"
d="M22.482,9.494l-1.039-0.346L21.4,9H22c0.552,0,1-0.439,1-0.992C23,8.002,22.997,8,22.997,8H23 c0-1-0.889-2-1.984-2h-0.642l-0.731-1.717C19.262,3.012,18.091,2,16.764,2H7.236C5.909,2,4.738,3.012,4.357,4.283L3.626,6H2.984 C1.889,6,1,7,1,8h0.003C1.003,8,1,8.002,1,8.008C1,8.561,1.448,9,2,9h0.6L2.557,9.148L1.518,9.494 C0.63,9.79,0.066,10.661,0.159,11.591l0.751,7.508C0.961,19.611,1.391,20,1.904,20H3v1c0,1.103,0.896,2,2,2h2c1.104,0,2-0.897,2-2 v-1h6v1c0,1.103,0.896,2,2,2h2c1.104,0,2-0.897,2-2v-1h1.096c0.514,0,0.943-0.389,0.994-0.901l0.751-7.508 C23.934,10.661,23.37,9.79,22.482,9.494 M6.273,4.857C6.402,4.43,6.788,4,7.236,4h9.527c0.448,0,0.834,0.43,0.963,0.857L19.313,9 H4.688L6.273,4.857z M7,21H5v-1h2V21z M19,21h-2v-1h2V21z M21.189,18H21h-6H9H3H2.811l-0.662-6.607L3,11h18l0.852,0.393L21.189,18z "
id="path5432"
style="fill:#000000;fill-opacity:1" /></g></g></svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
id="svg2"
viewBox="0 0 32 32"
height="32"
width="32"
version="1.1">
<metadata
id="metadata10">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs8" />
<path
id="path4"
d="M20 12.667v-2.688h-2.688v2.688h2.688zM20 7.354c1.438 0 2.688 1.125 2.688 2.625v8c0 1.5-1.25 2.688-2.688 2.688h-5.313v-2.688h5.313v-2.625h-2.688c-1.438 0-2.625-1.188-2.625-2.688v-2.688c0-1.5 1.188-2.625 2.625-2.625h2.688zM28 23.354v-18.688h-18.688v18.688h18.688zM28 1.979c1.438 0 2.688 1.25 2.688 2.688v18.688c0 1.438-1.25 2.625-2.688 2.625h-18.688c-1.438 0-2.625-1.188-2.625-2.625v-18.688c0-1.438 1.188-2.688 2.625-2.688h18.688zM4 7.354v21.313h21.313v2.688h-21.313c-1.438 0-2.688-1.25-2.688-2.688v-21.313h2.688z" />
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
resources/icons/smile.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 631 B

View File

@ -11,6 +11,17 @@
<file>icons/share-dark.png</file>
<file>icons/user-shape.png</file>
<file>icons/power-button-off.png</file>
<file>icons/smile.png</file>
<file>icons/emoji-categories/people.png</file>
<file>icons/emoji-categories/nature.png</file>
<file>icons/emoji-categories/foods.png</file>
<file>icons/emoji-categories/activity.png</file>
<file>icons/emoji-categories/travel.png</file>
<file>icons/emoji-categories/objects.png</file>
<file>icons/emoji-categories/symbols.png</file>
<file>icons/emoji-categories/flags.png</file>
</qresource>
<qresource prefix="/logos">

89
scripts/emoji_codegen.py Executable file
View File

@ -0,0 +1,89 @@
#!/usr/bin/env python3
import sys
import json
from jinja2 import Template
class Emoji(object):
def __init__(self, code, shortname, category, order):
self.code = ''.join(list(map(code_to_bytes, code.split('-'))))
self.shortname = shortname
self.category = category
self.order = int(order)
def code_to_bytes(codepoint):
'''
Convert hex unicode codepoint to hex byte array.
'''
bytes = chr(int(codepoint, 16)).encode('utf-8')
return str(bytes)[1:].strip("'")
def generate_code(emojis, category):
tmpl = Template('''
const QList<Emoji> EmojiProvider::{{ category }} = {
{%- for e in emoji %}
Emoji{QString::fromUtf8("{{ e.code }}"), "{{ e.shortname }}"},
{%- endfor %}
};
''')
d = dict(category=category, emoji=emojis)
print(tmpl.render(d))
if __name__ == '__main__':
if len(sys.argv) < 2:
print('usage: emoji_codegen.py /path/to/emoji.json')
sys.exit(1)
filename = sys.argv[1]
data = {}
with open(filename, 'r') as filename:
data = json.loads(filename.read())
emojis = []
for emoji_name in data:
tmp = data[emoji_name]
l = len(tmp['unicode'].split('-'))
if l > 1 and tmp['category'] == 'people':
continue
emojis.append(
Emoji(
tmp['unicode'],
tmp['shortname'],
tmp['category'],
tmp['emoji_order']
)
)
emojis.sort(key=lambda x: x.order)
people = list(filter(lambda x: x.category == "people", emojis))
nature = list(filter(lambda x: x.category == "nature", emojis))
food = list(filter(lambda x: x.category == "food", emojis))
activity = list(filter(lambda x: x.category == "activity", emojis))
travel = list(filter(lambda x: x.category == "travel", emojis))
objects = list(filter(lambda x: x.category == "objects", emojis))
symbols = list(filter(lambda x: x.category == "symbols", emojis))
flags = list(filter(lambda x: x.category == "flags", emojis))
# Use xclip to pipe the output to clipboard.
# e.g ./codegen.py emoji.json | xclip -sel clip
generate_code(people, 'people')
generate_code(nature, 'nature')
generate_code(food, 'food')
generate_code(activity, 'activity')
generate_code(travel, 'travel')
generate_code(objects, 'objects')
generate_code(symbols, 'symbols')
generate_code(flags, 'flags')

84
src/EmojiCategory.cc Normal file
View File

@ -0,0 +1,84 @@
/*
* 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 <QScrollBar>
#include "EmojiCategory.h"
EmojiCategory::EmojiCategory(QString category, QList<Emoji> emoji, QWidget *parent)
: QWidget(parent)
{
mainLayout_ = new QVBoxLayout(this);
mainLayout_->setMargin(0);
emojiListView_ = new QListView();
itemModel_ = new QStandardItemModel(this);
delegate_ = new EmojiItemDelegate(this);
data_ = new Emoji;
emojiListView_->setItemDelegate(delegate_);
emojiListView_->setSpacing(5);
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);
}
category_ = new QLabel(category, this);
category_->setStyleSheet(
"color: #ccc;"
"margin: 20px 0px 15px 8px;"
"font-weight: 500;"
"font-size: 12px;");
auto labelLayout_ = new QHBoxLayout();
labelLayout_->addWidget(category_);
labelLayout_->addStretch(1);
mainLayout_->addLayout(labelLayout_);
mainLayout_->addWidget(emojiListView_);
connect(emojiListView_, &QListView::clicked, this, &EmojiCategory::clickIndex);
}
EmojiCategory::~EmojiCategory()
{
}

47
src/EmojiItemDelegate.cc Normal file
View File

@ -0,0 +1,47 @@
/*
* 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 "EmojiItemDelegate.h"
EmojiItemDelegate::EmojiItemDelegate(QObject *parent)
: QStyledItemDelegate(parent)
{
data_ = new Emoji;
}
EmojiItemDelegate::~EmojiItemDelegate()
{
delete data_;
}
void EmojiItemDelegate::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");
font.setPixelSize(19);
painter->setFont(font);
painter->drawText(viewOption.rect, emoji);
}

247
src/EmojiPanel.cc Normal file
View File

@ -0,0 +1,247 @@
/*
* 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 <QLabel>
#include <QPushButton>
#include <QScrollArea>
#include <QScrollBar>
#include <QVBoxLayout>
#include "Avatar.h"
#include "EmojiCategory.h"
#include "EmojiPanel.h"
#include "FlatButton.h"
EmojiPanel::EmojiPanel(QWidget *parent)
: QFrame(parent)
{
setStyleSheet(
"QWidget {background: #f8fbfe; color: #e8e8e8; border: none;}"
"QScrollBar:vertical { background-color: #f8fbfe; width: 8px; border-radius: 20px; margin: 0px 2px 0 2px; }"
"QScrollBar::handle:vertical { border-radius : 50px; background-color : #d6dde3; }"
"QScrollBar::add-line:vertical { border: none; background: none; }"
"QScrollBar::sub-line:vertical { border: none; background: none; }");
setParent(0); // Create TopLevel-Widget
setAttribute(Qt::WA_NoSystemBackground, true);
setAttribute(Qt::WA_TranslucentBackground, true);
setWindowFlags(Qt::FramelessWindowHint | Qt::ToolTip);
// TODO: Make it MainWindow aware
auto main_frame_ = new QFrame(this);
main_frame_->setMinimumSize(370, 350);
main_frame_->setMaximumSize(370, 350);
auto top_layout = new QVBoxLayout(this);
top_layout->addWidget(main_frame_);
top_layout->setMargin(0);
auto content_layout = new QVBoxLayout(main_frame_);
content_layout->setMargin(0);
auto emoji_categories = new QFrame(main_frame_);
emoji_categories->setStyleSheet("background-color: #f2f2f2");
auto categories_layout = new QHBoxLayout(emoji_categories);
categories_layout->setSpacing(6);
categories_layout->setMargin(5);
auto people_category = new FlatButton(emoji_categories);
people_category->setIcon(QIcon(":/icons/icons/emoji-categories/people.png"));
people_category->setIconSize(QSize(category_icon_size_, category_icon_size_));
people_category->setForegroundColor("gray");
auto nature_category = new FlatButton(emoji_categories);
nature_category->setIcon(QIcon(":/icons/icons/emoji-categories/nature.png"));
nature_category->setIconSize(QSize(category_icon_size_, category_icon_size_));
nature_category->setForegroundColor("gray");
auto food_category = new FlatButton(emoji_categories);
food_category->setIcon(QIcon(":/icons/icons/emoji-categories/foods.png"));
food_category->setIconSize(QSize(category_icon_size_, category_icon_size_));
food_category->setForegroundColor("gray");
auto activity_category = new FlatButton(emoji_categories);
activity_category->setIcon(QIcon(":/icons/icons/emoji-categories/activity.png"));
activity_category->setIconSize(QSize(category_icon_size_, category_icon_size_));
activity_category->setForegroundColor("gray");
auto travel_category = new FlatButton(emoji_categories);
travel_category->setIcon(QIcon(":/icons/icons/emoji-categories/travel.png"));
travel_category->setIconSize(QSize(category_icon_size_, category_icon_size_));
travel_category->setForegroundColor("gray");
auto objects_category = new FlatButton(emoji_categories);
objects_category->setIcon(QIcon(":/icons/icons/emoji-categories/objects.png"));
objects_category->setIconSize(QSize(category_icon_size_, category_icon_size_));
objects_category->setForegroundColor("gray");
auto symbols_category = new FlatButton(emoji_categories);
symbols_category->setIcon(QIcon(":/icons/icons/emoji-categories/symbols.png"));
symbols_category->setIconSize(QSize(category_icon_size_, category_icon_size_));
symbols_category->setForegroundColor("gray");
auto flags_category = new FlatButton(emoji_categories);
flags_category->setIcon(QIcon(":/icons/icons/emoji-categories/flags.png"));
flags_category->setIconSize(QSize(category_icon_size_, category_icon_size_));
flags_category->setForegroundColor("gray");
categories_layout->addWidget(people_category);
categories_layout->addWidget(nature_category);
categories_layout->addWidget(food_category);
categories_layout->addWidget(activity_category);
categories_layout->addWidget(travel_category);
categories_layout->addWidget(objects_category);
categories_layout->addWidget(symbols_category);
categories_layout->addWidget(flags_category);
scroll_area_ = new QScrollArea(this);
scroll_area_->setWidgetResizable(true);
scroll_area_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
auto scroll_widget_ = new QWidget(this);
auto scroll_layout_ = new QVBoxLayout(scroll_widget_);
scroll_layout_->setMargin(0);
scroll_area_->setWidget(scroll_widget_);
auto people_emoji = new EmojiCategory("Smileys & People", emoji_provider_.people, scroll_widget_);
scroll_layout_->addWidget(people_emoji);
auto nature_emoji = new EmojiCategory("Animals & Nature", emoji_provider_.nature, scroll_widget_);
scroll_layout_->addWidget(nature_emoji);
auto food_emoji = new EmojiCategory("Food & Drink", emoji_provider_.food, scroll_widget_);
scroll_layout_->addWidget(food_emoji);
auto activity_emoji = new EmojiCategory("Activity", emoji_provider_.activity, scroll_widget_);
scroll_layout_->addWidget(activity_emoji);
auto travel_emoji = new EmojiCategory("Travel & Places", emoji_provider_.travel, scroll_widget_);
scroll_layout_->addWidget(travel_emoji);
auto objects_emoji = new EmojiCategory("Objects", emoji_provider_.objects, scroll_widget_);
scroll_layout_->addWidget(objects_emoji);
auto symbols_emoji = new EmojiCategory("Symbols", emoji_provider_.symbols, scroll_widget_);
scroll_layout_->addWidget(symbols_emoji);
auto flags_emoji = new EmojiCategory("Flags", emoji_provider_.flags, scroll_widget_);
scroll_layout_->addWidget(flags_emoji);
content_layout->addStretch(1);
content_layout->addWidget(scroll_area_);
content_layout->addWidget(emoji_categories);
setLayout(top_layout);
// TODO: Add parallel animation with geometry
opacity_ = new QGraphicsOpacityEffect(this);
opacity_->setOpacity(1.0);
setGraphicsEffect(opacity_);
animation_ = new QPropertyAnimation(opacity_, "opacity", this);
animation_->setDuration(180);
animation_->setStartValue(1.0);
animation_->setEndValue(0.0);
connect(people_emoji, &EmojiCategory::emojiSelected, this, &EmojiPanel::emojiSelected);
connect(people_category, &QPushButton::clicked, [this, people_emoji]() {
this->showEmojiCategory(people_emoji);
});
connect(nature_emoji, &EmojiCategory::emojiSelected, this, &EmojiPanel::emojiSelected);
connect(nature_category, &QPushButton::clicked, [this, nature_emoji]() {
this->showEmojiCategory(nature_emoji);
});
connect(food_emoji, &EmojiCategory::emojiSelected, this, &EmojiPanel::emojiSelected);
connect(food_category, &QPushButton::clicked, [this, food_emoji]() {
this->showEmojiCategory(food_emoji);
});
connect(activity_emoji, &EmojiCategory::emojiSelected, this, &EmojiPanel::emojiSelected);
connect(activity_category, &QPushButton::clicked, [this, activity_emoji]() {
this->showEmojiCategory(activity_emoji);
});
connect(travel_emoji, &EmojiCategory::emojiSelected, this, &EmojiPanel::emojiSelected);
connect(travel_category, &QPushButton::clicked, [this, travel_emoji]() {
this->showEmojiCategory(travel_emoji);
});
connect(objects_emoji, &EmojiCategory::emojiSelected, this, &EmojiPanel::emojiSelected);
connect(objects_category, &QPushButton::clicked, [this, objects_emoji]() {
this->showEmojiCategory(objects_emoji);
});
connect(symbols_emoji, &EmojiCategory::emojiSelected, this, &EmojiPanel::emojiSelected);
connect(symbols_category, &QPushButton::clicked, [this, symbols_emoji]() {
this->showEmojiCategory(symbols_emoji);
});
connect(flags_emoji, &EmojiCategory::emojiSelected, this, &EmojiPanel::emojiSelected);
connect(flags_category, &QPushButton::clicked, [this, flags_emoji]() {
this->showEmojiCategory(flags_emoji);
});
connect(animation_, &QPropertyAnimation::finished, [this]() {
if (animation_->direction() == QAbstractAnimation::Forward)
this->hide();
});
}
void EmojiPanel::showEmojiCategory(const EmojiCategory *category)
{
auto posToGo = category->mapToParent(QPoint()).y();
auto current = scroll_area_->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->scroll_area_->ensureVisible(0, 0, 0, 0);
posToGo += 6 * 50;
this->scroll_area_->ensureVisible(0, posToGo, 0, 0);
}
void EmojiPanel::leaveEvent(QEvent *event)
{
Q_UNUSED(event);
fadeOut();
}
void EmojiPanel::fadeOut()
{
animation_->setDirection(QAbstractAnimation::Forward);
animation_->start();
}
void EmojiPanel::fadeIn()
{
animation_->setDirection(QAbstractAnimation::Backward);
animation_->start();
}

65
src/EmojiPickButton.cc Normal file
View File

@ -0,0 +1,65 @@
/*
* 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 "EmojiPickButton.h"
EmojiPickButton::EmojiPickButton(QWidget *parent)
: FlatButton(parent)
, panel_{nullptr}
{
}
void EmojiPickButton::enterEvent(QEvent *e)
{
Q_UNUSED(e);
if (panel_ == nullptr) {
panel_ = new EmojiPanel(this);
connect(panel_, &EmojiPanel::emojiSelected, this, &EmojiPickButton::emojiSelected);
}
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_->fadeIn();
panel_->show();
}
void EmojiPickButton::leaveEvent(QEvent *e)
{
Q_UNUSED(e);
if (panel_->underMouse())
return;
auto pos = QCursor::pos();
auto panel_geometry = panel_->geometry();
panel_geometry.adjust(0, 0, 0, vertical_distance_);
if (panel_geometry.contains(pos))
return;
panel_->fadeOut();
}

1470
src/EmojiProvider.cc Normal file

File diff suppressed because it is too large Load Diff

View File

@ -142,10 +142,10 @@ QString HistoryViewItem::replaceEmoji(const QString &body)
QString fmtBody = "";
for (auto &c : body) {
auto code = c.unicode();
int code = c.unicode();
// TODO: A map should be used with the unicode codes supported by emoji one
if (code > 127)
// TODO: Be more precise here.
if (code > 9000)
fmtBody += "<span style=\"font-family: Emoji One; font-size: 16px\">" + QString(c) + "</span>";
else
fmtBody += c;

View File

@ -16,11 +16,25 @@
*/
#include <QDebug>
#include <QFile>
#include <QPainter>
#include <QStyleOption>
#include "TextInputWidget.h"
FilteredTextEdit::FilteredTextEdit(QWidget *parent)
: QTextEdit(parent)
{
}
void FilteredTextEdit::keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)
emit enterPressed();
else
QTextEdit::keyPressEvent(event);
}
TextInputWidget::TextInputWidget(QWidget *parent)
: QWidget(parent)
{
@ -31,8 +45,8 @@ TextInputWidget::TextInputWidget(QWidget *parent)
setStyleSheet("background-color: #f8fbfe; height: 45px;");
top_layout_ = new QHBoxLayout();
top_layout_->setSpacing(6);
top_layout_->setContentsMargins(6, 0, 0, 0);
top_layout_->setSpacing(0);
top_layout_->setMargin(0);
send_file_button_ = new FlatButton(this);
send_file_button_->setCursor(Qt::PointingHandCursor);
@ -43,9 +57,10 @@ TextInputWidget::TextInputWidget(QWidget *parent)
send_file_button_->setIcon(send_file_icon);
send_file_button_->setIconSize(QSize(24, 24));
input_ = new QLineEdit(this);
input_ = new FilteredTextEdit(this);
input_->setFixedHeight(45);
input_->setPlaceholderText("Write a message...");
input_->setStyleSheet("color: black; font-size: 10pt; border-radius: 0; padding: 2px; margin-bottom: 4px;");
input_->setStyleSheet("color: #333333; font-size: 13px; border-radius: 0; padding-top: 10px;");
send_message_button_ = new FlatButton(this);
send_message_button_->setCursor(Qt::PointingHandCursor);
@ -56,24 +71,59 @@ TextInputWidget::TextInputWidget(QWidget *parent)
send_message_button_->setIcon(send_message_icon);
send_message_button_->setIconSize(QSize(24, 24));
emoji_button_ = new EmojiPickButton(this);
emoji_button_->setCursor(Qt::PointingHandCursor);
emoji_button_->setForegroundColor(QColor("#acc7dc"));
QIcon emoji_icon;
emoji_icon.addFile(":/icons/icons/smile.png", QSize(), QIcon::Normal, QIcon::Off);
emoji_button_->setIcon(emoji_icon);
emoji_button_->setIconSize(QSize(24, 24));
top_layout_->addWidget(send_file_button_);
top_layout_->addWidget(input_);
top_layout_->addWidget(emoji_button_);
top_layout_->addWidget(send_message_button_);
setLayout(top_layout_);
connect(send_message_button_, SIGNAL(clicked()), this, SLOT(onSendButtonClicked()));
connect(input_, SIGNAL(returnPressed()), send_message_button_, SIGNAL(clicked()));
connect(input_, SIGNAL(enterPressed()), send_message_button_, SIGNAL(clicked()));
connect(emoji_button_, SIGNAL(emojiSelected(const QString &)), this, SLOT(addSelectedEmoji(const QString &)));
}
void TextInputWidget::addSelectedEmoji(const QString &emoji)
{
QTextCursor cursor = input_->textCursor();
QFont emoji_font("Emoji One");
emoji_font.setPixelSize(18);
QFont text_font("Open Sans");
text_font.setPixelSize(13);
QTextCharFormat charfmt;
charfmt.setFont(emoji_font);
input_->setCurrentCharFormat(charfmt);
input_->insertPlainText(emoji);
cursor.movePosition(QTextCursor::End);
charfmt.setFont(text_font);
input_->setCurrentCharFormat(charfmt);
input_->show();
}
void TextInputWidget::onSendButtonClicked()
{
auto msg_text = input_->text().trimmed();
auto msg_text = input_->document()->toPlainText().trimmed();
if (msg_text.isEmpty())
return;
emit sendTextMessage(msg_text);
input_->clear();
}

View File

@ -472,11 +472,11 @@ void FlatButton::paintForeground(QPainter *painter)
QRect textGeometry(pos + QPoint(0, base.height() / 2), textSize);
QRect iconGeometry(pos + QPoint(0, (height() - iconSize().height()) / 2), iconSize());
if (ui::LeftIcon == icon_placement_) {
textGeometry.translate(iw, 0);
} else {
iconGeometry.translate(textSize.width() + IconPadding, 0);
}
/* if (ui::LeftIcon == icon_placement_) { */
/* textGeometry.translate(iw, 0); */
/* } else { */
/* iconGeometry.translate(textSize.width() + IconPadding, 0); */
/* } */
painter->drawText(textGeometry, Qt::AlignCenter, text());