opt: generate dictionary icon from dictionary name (#2025)
Some checks are pending
SonarCloud / Build and analyze (push) Waiting to run

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: shenleban tongying <shenlebantongying@gmail.com>
This commit is contained in:
xiaoyifang 2024-12-17 20:30:04 +08:00 committed by GitHub
parent 3cc379e2d5
commit b7a27d724d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 120 additions and 34 deletions

View file

@ -0,0 +1,32 @@
#include "dictionary_icon_name.hh"
#include <QMutexLocker>
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;
}

View file

@ -0,0 +1,24 @@
#pragma once
#include <string>
#include <QMap>
#include <vector>
#include <mutex>
#include <QString>
#include <QMutex>
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

View file

@ -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

View file

@ -5,6 +5,7 @@
#include "config.hh"
#include "pronounceengine.hh"
#include <QCache>
#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 );

View file

@ -19,6 +19,7 @@
#include <QRegularExpression>
#include "utils.hh"
#include "zipfile.hh"
#include <array>
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 )

View file

@ -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() );