Skip to content

Commit

Permalink
backports from im-emoji-picker
Browse files Browse the repository at this point in the history
  • Loading branch information
GaZaTu committed Jan 27, 2023
1 parent 853ae3c commit 095aee6
Show file tree
Hide file tree
Showing 19 changed files with 1,222 additions and 1,725 deletions.
5 changes: 3 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"files.associations": {
"*.qrc": "xml",
"*.qss": "css",
"*.qrc": "xml",
"string": "cpp",
"cwchar": "cpp",
"iostream": "cpp",
Expand Down Expand Up @@ -112,7 +112,8 @@
"span": "cpp",
"stop_token": "cpp",
"typeindex": "cpp",
"valarray": "cpp"
"valarray": "cpp",
"qcoreapplication": "cpp"
},
"cmake.sourceDirectory": "${workspaceFolder}/.",
"files.exclude": {
Expand Down
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ set(COMMON_SRC_FILES
src/main.qrc
src/emojis.cpp
src/emojis.qrc
src/kaomojis.cpp
src/EmojiLineEdit.cpp
src/EmojiLabel.cpp
src/EmojiPicker.cpp
src/EmojiPickerWindow.cpp
src/EmojiPickerSettings.cpp
src/EmojiTranslator.cpp
src/flowlayout.cpp
)

if (UNIX AND NOT APPLE) # LINUX
Expand Down
22 changes: 3 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,11 +121,9 @@ When you've selected your emoji you can press the **return key** to write it.
- `Arrow keys` => navigate through shown emojis
- `Return` => write emoji to previously active window
- `Shift+Return` => write emoji to previously active window and close emoji picker
- `F1` => show recently used emojis (default view)
- `F2` => show list of all emojis (if you press this while searching, the view will jump to the currently selected emoji aswell)
- `F4` => close emoji picker and open settings file
- `F5` => toggle input method for current process (press [`F5` and then `Return`] a few times if emojis don't get written into the window; there are 4 different modes)
- `Tab` => toggle between emoji and kaomoji
- `Tab` => toggle between MRU, list and kaomoji

### AppImage

Expand All @@ -142,23 +140,18 @@ I recommend running it (in the keybind) using the following command instead:
The settings file should be located at `$XDG_CONFIG_HOME/gazatu.xyz/emoji-picker.ini`. (usually in `~/.config`)

- `[General] | activateWindowBeforeWritingByDefault` => `true` to activate windows by default before writing to them
- `[General] | aliasExactMatching` => `true` to only show aliased emojis when the search matches completely
- `[General] | closeOnFocusLost` => `true` to close the window after it lost focus
- `[General] | customQssFilePath` => custom styling (colors and shit) for the emoji picker (refer to [src/main.qss](src/main.qss) for examples); useful if you don't like the dark theme
- `[General] | enableEmojiIncludesSearch` => `true` to enable sub-string search (for example: `joy` to find face_with_tears_of_joy); you need to enter 3 or more characters
- `[General] | gendersDisabled` => `true` if you only want to see gender neutral emojis (jobs or family or w/e)
- `[General] | hideInputMethod` => `true` if you don't want to see the input method
- `[General] | localeKey` => the emoji translation you want to use (en, de, fr, nl, da, it, pt, es, sv, pl, hr, cs, fi, el, hu) or empty if you want to use english with underscores
- `[General] | maxEmojiVersion` => set this to for example 12 to exclude emojis released after that or -1 to show all emojis
- `[General] | openAtMouseLocation` => `true` if you want to open the emoji picker dialog at the current mouse cursor
- `[General] | previewTextLeftMargin` => change the number of this setting if the preview text is blurry
- `[General] | skinTonesDisabled` => `true` if you only want to see skin-tone neutral emojis (hands or jobs or family or w/e)
- `[General] | surroundAliasesWithColons` => `true` if you want emoji aliases to be in colons (:joy: for example)
- `[General] | swapEnterAndShiftEnter` => `true` if you want `Return` to close the window
- `[General] | useClipboardHackByDefault` => `true` to write emojis using `ctrl+v` by default (qt5 apps for example)
- `[General] | useSystemEmojiFont` => `true` if you want to use the system emoji font instead of the bundled twemoji images
- `[General] | useSystemEmojiFontWidthHeuristics` => `true` if you want to scale/hide unsupported emojis (may lead to false positives)
- `[General] | useSystemQtTheme` => `true` if you want to use the system qt theme (not recommended, usually only works with kde i think)
- `[General] | useSystemQtTheme` => `true` if you want to use the system qt theme
- `[General] | windowOpacity` => how seethrough the emoji picker is supposed to be (0 = invisible)
- `[activateWindowBeforeWritingExceptions]` => list of executables that should be an exception to the `[General] | activateWindowBeforeWritingByDefault` setting
- `[emojiAliasesIniFilePaths]` => list of custom emoji codes (refer to [src/aliases/github-emojis.ini](src/aliases/github-emojis.ini) for examples); points to the builtin list of github emojis by default ([https://github.com/ikatyang/emoji-cheat-sheet](https://github.com/ikatyang/emoji-cheat-sheet/blob/master/README.md)); also points to the builtin list of gitmoji emojis by default ([https://gitmoji.dev/](https://gitmoji.dev/))
Expand All @@ -175,9 +168,6 @@ Some things such as recently used emojis are written to `$XDG_CACHE_HOME/gazatu.
If you enabled `useSystemEmojiFont` to display emojis inside the emoji picker: it's possible that your installed emoji font does not support all emojis (for example: at the time of writing noto-fonts-emoji does not support `heart_mending`) which will likely result in some emojis being either invisible or displayed as 2 separate emojis. To "fix" this behavior you can either set `maxEmojiVersion` to the version supported by your emoji font (for example: 12) or set `useSystemEmojiFontWidthHeuristics` to `true` (which is the default) to automatically figure it out.

Regarding kaomoji mode:
- Check [src/kaomojis.hpp](src/kaomojis.hpp) for a list of kaomoji
- `F2` (list of all emoji (or kaomoji in this case)) does not work yet
- `useSystemEmojiFont=true` does not work with kaomoji mode
- required font localizations:
- cjk (tc, sc, kr, jp)
- kannada
Expand All @@ -190,19 +180,13 @@ Regarding kaomoji mode:
```ini
[General]
activateWindowBeforeWritingByDefault=false
aliasExactMatching=false
closeOnFocusLost=false
customQssFilePath=
enableEmojiIncludesSearch=true
gendersDisabled=false
hideInputMethod=false
localeKey=
maxEmojiVersion=-1
openAtMouseLocation=false
previewTextLeftMargin=0
skinTonesDisabled=false
startInKaomojiMode=false
surroundAliasesWithColons=true
swapEnterAndShiftEnter=false
useClipboardHackByDefault=false
useSystemEmojiFont=false
Expand All @@ -217,7 +201,7 @@ windowOpacity=0.9
4\processName=chromium
5\processName=kate
6\processName=brave
size=5
size=6

[emojiAliasesIniFilePaths]
1\path=:/aliases/github-emojis.ini
Expand Down
77 changes: 49 additions & 28 deletions src/EmojiLabel.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
#include "EmojiLabel.hpp"
#include "EmojiPickerSettings.hpp"
#include <QApplication>
#include <QScreen>
#include <QWindow>
#include <sstream>
#include <unicode/schriter.h>
#include <unicode/unistr.h>

EmojiLabel::EmojiLabel(QWidget* parent) : QLabel(parent) {
EmojiLabel::EmojiLabel(QWidget* parent, const EmojiPickerSettings& settings) : QLabel(parent), _settings(settings) {
setProperty("class", "EmojiLabel");
setGraphicsEffect(_shadowEffect);
setMouseTracking(true);

Expand All @@ -24,12 +24,11 @@ EmojiLabel::EmojiLabel(QWidget* parent) : QLabel(parent) {
_devicePixelRatio = QApplication::primaryScreen()->devicePixelRatio();
}

EmojiLabel::EmojiLabel(QWidget* parent, const Emoji& emoji) : EmojiLabel(parent) {
EmojiLabel::EmojiLabel(QWidget* parent, const EmojiPickerSettings& settings, const Emoji& emoji) : EmojiLabel(parent, settings) {
setEmoji(emoji);
}

void getCodepointsByEmojiStr(
const std::string& emojiStr, const std::string& separator, std::stringstream& emojiHexCodeStream) {
void getCodepointsByEmojiStr(const std::string& emojiStr, const std::string& separator, std::stringstream& emojiHexCodeStream) {
bool firstCodepoint = true;
icu::UnicodeString emojiUStr(emojiStr.data(), emojiStr.length(), "utf-8");
icu::StringCharacterIterator emojiUStrIterator(emojiUStr);
Expand All @@ -45,6 +44,7 @@ void getCodepointsByEmojiStr(
emojiHexCodeStream << std::hex << codepoint;
}
}

std::string getCodepointsByEmojiStr(const std::string& emojiStr, const std::string& separator) {
std::stringstream emojiHexCodeStream;
getCodepointsByEmojiStr(emojiStr, separator, emojiHexCodeStream);
Expand All @@ -66,34 +66,35 @@ QPixmap getPixmapByEmojiStr(const std::string& emojiStr) {
return QPixmap(QString::fromStdString(getPixmapPathByEmojiStr(emojiStr)), "PNG");
}

int calculateTextWidth(const QFontMetrics& metrics, const QString& text) {
#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
return metrics.horizontalAdvance(text);
#else
return metrics.width(text);
#endif
}

int defaultEmojiWidth = 0;
int invalidEmojiWidth = 0;

bool fontSupportsEmoji(const QFontMetrics& metrics, int textWidth) {
if (invalidEmojiWidth == 0) {
invalidEmojiWidth = calculateTextWidth(metrics, u8"\U0001FFFD");
#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
invalidEmojiWidth = metrics.horizontalAdvance(u8"\U0001FFFD");
#else
invalidEmojiWidth = metrics.width(u8"\U0001FFFD");
#endif
}

return textWidth != invalidEmojiWidth;
}

bool fontSupportsEmoji(const QFontMetrics& metrics, const QString& text) {
int textWidth = calculateTextWidth(metrics, text);
#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
int textWidth = metrics.horizontalAdvance(text);
#else
int textWidth = metrics.width(text);
#endif

return fontSupportsEmoji(metrics, textWidth);
}

const Emoji& EmojiLabel::emoji() const {
return _emoji;
}

void EmojiLabel::setEmoji(const Emoji& emoji, int w, int h) {
_emoji = emoji;

Expand All @@ -102,18 +103,34 @@ void EmojiLabel::setEmoji(const Emoji& emoji, int w, int h) {

setAccessibleName(QString::fromStdString(_emoji.name));

if (EmojiPickerSettings::snapshot().useSystemEmojiFont()) {
QPixmap emojiPixmap = getPixmapByEmojiStr(_emoji.code);
_hasRealEmoji = !emojiPixmap.isNull();

if (_hasRealEmoji && !_settings.useSystemEmojiFont()) {
emojiPixmap = emojiPixmap.scaled(w, h, Qt::KeepAspectRatio, Qt::SmoothTransformation);
emojiPixmap.setDevicePixelRatio(_devicePixelRatio);

setPixmap(emojiPixmap);
} else if (_hasRealEmoji) {
QString text = QString::fromStdString(_emoji.code);

QFont textFont = font();
textFont.setPixelSize(28);
textFont.setPixelSize(w);

if (EmojiPickerSettings::snapshot().useSystemEmojiFontWidthHeuristics()) {
if (_settings.useSystemEmojiFontWidthHeuristics()) {
if (defaultEmojiWidth == 0) {
defaultEmojiWidth = calculateTextWidth(fontMetrics(), u8"\U0001F600");
#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
defaultEmojiWidth = fontMetrics().horizontalAdvance(u8"\U0001F600");
#else
defaultEmojiWidth = fontMetrics().width(u8"\U0001F600");
#endif
}

int textWidth = calculateTextWidth(fontMetrics(), text);
#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
int textWidth = fontMetrics().horizontalAdvance(text);
#else
int textWidth = fontMetrics().width(text);
#endif
if (textWidth > defaultEmojiWidth) {
double multiplier = (double)defaultEmojiWidth / (double)textWidth;
textFont.setPixelSize((double)textFont.pixelSize() * multiplier);
Expand All @@ -122,17 +139,16 @@ void EmojiLabel::setEmoji(const Emoji& emoji, int w, int h) {

setFont(textFont);
setText(text);
setMaximumSize(w * 1.10, h * 1.10);
} else {
QPixmap emojiPixmap = getPixmapByEmojiStr(_emoji.code);
if (emojiPixmap.isNull()) {
setText(QString::fromStdString(_emoji.code));
return;
}
QString text = QString::fromStdString(_emoji.code);

emojiPixmap = emojiPixmap.scaled(w, h, Qt::KeepAspectRatio, Qt::SmoothTransformation);
emojiPixmap.setDevicePixelRatio(_devicePixelRatio);
QFont textFont = font();
textFont.setPixelSize(w * 0.45);

setPixmap(emojiPixmap);
setFont(textFont);
setText(text);
setMaximumSize(w * 2.45, h * 1.10);
}
}

Expand All @@ -143,6 +159,7 @@ bool EmojiLabel::highlighted() const {

return _shadowEffect->isEnabled();
}

void EmojiLabel::setHighlighted(bool highlighted) {
// QGraphicsDropShadowEffect breaks QPixmap::setDevicePixelRatio
// https://bugreports.qt.io/browse/QTBUG-65035
Expand Down Expand Up @@ -174,3 +191,7 @@ void EmojiLabel::mouseMoveEvent(QMouseEvent* ev) {

QLabel::mouseMoveEvent(ev);
}

bool EmojiLabel::hasRealEmoji() const {
return _hasRealEmoji;
}
12 changes: 9 additions & 3 deletions src/EmojiLabel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,23 @@
#include <QGraphicsDropShadowEffect>
#include <QLabel>
#include <QPixmap>
#include "EmojiPickerSettings.hpp"

class EmojiLabel : public QLabel {
Q_OBJECT

public:
explicit EmojiLabel(QWidget* parent = nullptr);
explicit EmojiLabel(QWidget* parent, const Emoji& emoji);
explicit EmojiLabel(QWidget* parent, const EmojiPickerSettings& settings);
explicit EmojiLabel(QWidget* parent, const EmojiPickerSettings& settings, const Emoji& emoji);

const Emoji& emoji() const;
void setEmoji(const Emoji& emoji, int w = 24, int h = 24);

bool highlighted() const;
void setHighlighted(bool highlighted);

bool hasRealEmoji() const;

signals:
void mousePressed(QMouseEvent* ev);

Expand All @@ -27,9 +30,12 @@ class EmojiLabel : public QLabel {

private:
Emoji _emoji;
bool _hasRealEmoji = false;
double _devicePixelRatio;

QGraphicsDropShadowEffect* _shadowEffect = new QGraphicsDropShadowEffect();
QGraphicsDropShadowEffect* _shadowEffect = new QGraphicsDropShadowEffect(this);

const EmojiPickerSettings& _settings;
};

bool fontSupportsEmoji(const QFontMetrics& metrics, const QString& text);
Loading

0 comments on commit 095aee6

Please sign in to comment.