From b7a27d724dc13406c65ae42c4ea726f4264964de Mon Sep 17 00:00:00 2001 From: xiaoyifang <105986+xiaoyifang@users.noreply.github.com> Date: Tue, 17 Dec 2024 20:30:04 +0800 Subject: [PATCH] opt: generate dictionary icon from dictionary name (#2025) --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: shenleban tongying --- src/common/dictionary_icon_name.cc | 32 ++++++++++++++ src/common/dictionary_icon_name.hh | 24 ++++++++++ src/common/globalbroadcaster.cc | 18 ++++++++ src/common/globalbroadcaster.hh | 3 ++ src/dict/dictionary.cc | 71 +++++++++++++++++------------- src/dict/dictionary.hh | 6 +-- 6 files changed, 120 insertions(+), 34 deletions(-) create mode 100644 src/common/dictionary_icon_name.cc create mode 100644 src/common/dictionary_icon_name.hh diff --git a/src/common/dictionary_icon_name.cc b/src/common/dictionary_icon_name.cc new file mode 100644 index 00000000..add0fc7c --- /dev/null +++ b/src/common/dictionary_icon_name.cc @@ -0,0 +1,32 @@ +#include "dictionary_icon_name.hh" +#include + + +QString Icons::DictionaryIconName::getIconName( const QString & dictionaryName ) +{ + if ( dictionaryName.isEmpty() ) { + return {}; + } + QMutexLocker _( &_mutex ); + + auto it = _dictionaryIconNames.contains( dictionaryName ); + if ( it ) { + return _dictionaryIconNames.value( dictionaryName ); + } + //get the first character of the dictionary name + QString name = dictionaryName.at( 0 ).toUpper(); + auto it1 = _iconDictionaryNames.contains( name ); + std::vector< QString > vector = {}; + if ( it1 ) { + vector = _iconDictionaryNames.value( name ); + vector.emplace_back( dictionaryName ); + } + else { + vector.emplace_back( dictionaryName ); + _iconDictionaryNames.insert( name, vector ); + } + + name = name + QString::number( vector.size() ); + _dictionaryIconNames.insert( dictionaryName, name ); + return name; +} \ No newline at end of file diff --git a/src/common/dictionary_icon_name.hh b/src/common/dictionary_icon_name.hh new file mode 100644 index 00000000..6906044b --- /dev/null +++ b/src/common/dictionary_icon_name.hh @@ -0,0 +1,24 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace Icons { +//use dictionary name's (first character + the order number) to represent the dictionary name in the icon image. +class DictionaryIconName +{ + //map icon name to dictionary names; + QMap< QString, std::vector< QString > > _iconDictionaryNames; + //map dictionary name to icon name; + QMap< QString, QString > _dictionaryIconNames; + + QMutex _mutex; + +public: + QString getIconName( const QString & dictionaryName ); +}; +} // namespace Icons \ No newline at end of file diff --git a/src/common/globalbroadcaster.cc b/src/common/globalbroadcaster.cc index 5fb63979..c5accf79 100644 --- a/src/common/globalbroadcaster.cc +++ b/src/common/globalbroadcaster.cc @@ -38,4 +38,22 @@ bool GlobalBroadcaster::existedInWhitelist( QString url ) const { return whitelist.contains( url ); } + + +QString GlobalBroadcaster::getAbbrName( QString const & text ) +{ + if ( text.isEmpty() ) { + return {}; + } + //remove whitespace,number,mark,puncuation,symbol + QString simplified = text; + simplified.remove( + QRegularExpression( R"([\p{Z}\p{N}\p{M}\p{P}\p{S}])", QRegularExpression::UseUnicodePropertiesOption ) ); + + if ( simplified.isEmpty() ) { + return {}; + } + + return _icon_names.getIconName( simplified ); +} // namespace global diff --git a/src/common/globalbroadcaster.hh b/src/common/globalbroadcaster.hh index c1d985d0..0be64a5c 100644 --- a/src/common/globalbroadcaster.hh +++ b/src/common/globalbroadcaster.hh @@ -5,6 +5,7 @@ #include "config.hh" #include "pronounceengine.hh" #include +#include "dictionary_icon_name.hh" struct ActiveDictIds { @@ -25,6 +26,7 @@ class GlobalBroadcaster: public QObject Config::Preferences * preference; QSet< QString > whitelist; + Icons::DictionaryIconName _icon_names; public: void setPreference( Config::Preferences * _pre ); @@ -40,6 +42,7 @@ public: QMap< QString, QSet< QString > > folderFavoritesMap; QMap< unsigned, QString > groupFolderMap; PronounceEngine pronounce_engine; + QString getAbbrName( QString const & text ); signals: void dictionaryChanges( ActiveDictIds ad ); void dictionaryClear( ActiveDictIds ad ); diff --git a/src/dict/dictionary.cc b/src/dict/dictionary.cc index 1181b7f7..d05df52c 100644 --- a/src/dict/dictionary.cc +++ b/src/dict/dictionary.cc @@ -19,6 +19,7 @@ #include #include "utils.hh" #include "zipfile.hh" +#include namespace Dictionary { @@ -291,7 +292,7 @@ bool Class::loadIconFromFile( QString const & _filename, bool isFullName ) return false; } -bool Class::loadIconFromText( QString iconUrl, QString const & text ) +bool Class::loadIconFromText( const QString & iconUrl, QString const & text ) { if ( text.isEmpty() ) { return false; @@ -308,7 +309,7 @@ bool Class::loadIconFromText( QString iconUrl, QString const & text ) painter.setCompositionMode( QPainter::CompositionMode_SourceAtop ); QFont font = painter.font(); - //the text should be a little smaller than the icon + //the orderNum should be a little smaller than the icon font.setPixelSize( iconSize * 0.6 ); font.setWeight( QFont::Bold ); painter.setFont( font ); @@ -318,8 +319,21 @@ bool Class::loadIconFromText( QString iconUrl, QString const & text ) //select a single char. auto abbrName = getAbbrName( text ); - painter.setPen( QColor( 4, 57, 108, 200 ) ); - painter.drawText( rectangle, Qt::AlignCenter, abbrName ); + painter.setPen( intToFixedColor( qHash( abbrName ) ) ); + + // Draw first character + painter.drawText( rectangle, Qt::AlignCenter, abbrName.at( 0 ) ); + + //the orderNum should be a little smaller than the icon + font.setPixelSize( iconSize * 0.4 ); + QFontMetrics fm1( font ); + const QString & orderNum = abbrName.mid( 1 ); + int orderNumberWidth = fm1.horizontalAdvance( orderNum ); + + painter.setFont( font ); + painter.drawText( rectangle.x() + rectangle.width() - orderNumberWidth * 1.2, + rectangle.y() + rectangle.height(), + orderNum ); painter.end(); @@ -330,35 +344,30 @@ bool Class::loadIconFromText( QString iconUrl, QString const & text ) return false; } +QColor Class::intToFixedColor( int index ) +{ + // Predefined list of colors + static const std::array colors = { + QColor( 255, 0, 0, 200 ), // Red + QColor( 4, 57, 108, 200 ), //Custom + QColor( 0, 255, 0, 200 ), // Green + QColor( 0, 0, 255, 200 ), // Blue + QColor( 255, 255, 0, 200 ), // Yellow + QColor( 0, 255, 255, 200 ), // Cyan + QColor( 255, 0, 255, 200 ), // Magenta + QColor( 192, 192, 192, 200 ), // Gray + QColor( 255, 165, 0, 200 ), // Orange + QColor( 128, 0, 128, 200 ), // Violet + QColor( 128, 128, 0, 200 ) // Olive + }; + + // Use modulo operation to ensure index is within the range of the color list + return colors[ index % colors.size() ]; +} + QString Class::getAbbrName( QString const & text ) { - if ( text.isEmpty() ) { - return {}; - } - //remove whitespace,number,mark,puncuation,symbol - QString simplified = text; - simplified.remove( - QRegularExpression( R"([\p{Z}\p{N}\p{M}\p{P}\p{S}])", QRegularExpression::UseUnicodePropertiesOption ) ); - - if ( simplified.isEmpty() ) { - return {}; - } - int index = qHash( simplified ) % simplified.size(); - - QString abbrName; - if ( !Utils::isCJKChar( simplified.at( index ).unicode() ) ) { - // take two chars. - abbrName = simplified.mid( index, 2 ); - if ( abbrName.size() == 1 ) { - //make up two characters. - abbrName = abbrName + simplified.at( 0 ); - } - } - else { - abbrName = simplified.mid( index, 1 ); - } - - return abbrName; + return GlobalBroadcaster::instance()->getAbbrName( text ); } void Class::isolateCSS( QString & css, QString const & wrapperSelector ) diff --git a/src/dict/dictionary.hh b/src/dict/dictionary.hh index e290162d..71e13eb1 100644 --- a/src/dict/dictionary.hh +++ b/src/dict/dictionary.hh @@ -318,10 +318,10 @@ protected: // Load icon from filename directly if isFullName == true // else treat filename as name without extension bool loadIconFromFile( QString const & filename, bool isFullName = false ); - bool loadIconFromText( QString iconUrl, QString const & text ); - - QString getAbbrName( QString const & text ); + bool loadIconFromText( const QString & iconUrl, QString const & text ); + static QString getAbbrName( QString const & text ); + static QColor intToFixedColor( int index ); /// Make css content usable only for articles from this dictionary void isolateCSS( QString & css, QString const & wrapperSelector = QString() );