Advance Wayland and KDE package bring-up
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
configure_file(config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
|
||||
|
||||
add_subdirectory(tools/kiconfinder)
|
||||
if (KICONTHEMES_USE_QTQUICK)
|
||||
####################### add_subdirectory(qml)
|
||||
endif()
|
||||
if (APPLE)
|
||||
add_subdirectory(tools/ksvg2icns)
|
||||
endif()
|
||||
|
||||
add_subdirectory(widgets)
|
||||
|
||||
add_library(KF6IconThemes)
|
||||
add_library(KF6::IconThemes ALIAS KF6IconThemes)
|
||||
|
||||
set_target_properties(KF6IconThemes PROPERTIES
|
||||
VERSION ${KICONTHEMES_VERSION}
|
||||
SOVERSION ${KICONTHEMES_SOVERSION}
|
||||
EXPORT_NAME IconThemes
|
||||
)
|
||||
|
||||
target_sources(KF6IconThemes PRIVATE
|
||||
kiconcolors.cpp
|
||||
kiconcolors.h
|
||||
kiconeffect.cpp
|
||||
kiconeffect.h
|
||||
kiconengine.cpp
|
||||
kiconengine.h
|
||||
kiconengineplugin.cpp
|
||||
kiconloader.cpp
|
||||
kiconloader.h
|
||||
kicontheme.cpp
|
||||
kicontheme.h
|
||||
kquickiconprovider.h
|
||||
|
||||
hicolor.qrc
|
||||
)
|
||||
|
||||
ecm_qt_declare_logging_category(KF6IconThemes
|
||||
HEADER debug.h
|
||||
IDENTIFIER KICONTHEMES
|
||||
CATEGORY_NAME kf.iconthemes
|
||||
OLD_CATEGORY_NAMES kf5.kiconthemes
|
||||
DESCRIPTION "KIconThemes"
|
||||
EXPORT KICONTHEMES
|
||||
)
|
||||
|
||||
ecm_generate_export_header(KF6IconThemes
|
||||
BASE_NAME KIconThemes
|
||||
GROUP_BASE_NAME KF
|
||||
VERSION ${KF_VERSION}
|
||||
USE_VERSION_HEADER
|
||||
DEPRECATED_BASE_VERSION 0
|
||||
DEPRECATION_VERSIONS 5.0 6.5
|
||||
EXCLUDE_DEPRECATED_BEFORE_AND_AT ${EXCLUDE_DEPRECATED_BEFORE_AND_AT}
|
||||
)
|
||||
|
||||
target_include_directories(KF6IconThemes INTERFACE "$<INSTALL_INTERFACE:${KDE_INSTALL_INCLUDEDIR_KF}/KIconThemes>")
|
||||
|
||||
target_link_libraries(KF6IconThemes
|
||||
PUBLIC
|
||||
Qt6::Gui
|
||||
PRIVATE
|
||||
Qt6::GuiPrivate
|
||||
Qt6::Svg
|
||||
KF6::Archive # for KCompressionDevice
|
||||
KF6::I18n # for KLocalizedString::localizedFilePath in KIconTheme
|
||||
KF6::ColorScheme
|
||||
)
|
||||
if (HAVE_QTDBUS)
|
||||
target_compile_definitions(KF6IconThemes PRIVATE WITH_QTDBUS)
|
||||
target_link_libraries(KF6IconThemes PRIVATE Qt6::DBus)
|
||||
endif()
|
||||
|
||||
if(TARGET KF6::BreezeIcons)
|
||||
target_link_libraries(KF6IconThemes
|
||||
PRIVATE
|
||||
KF6::BreezeIcons
|
||||
)
|
||||
endif ()
|
||||
|
||||
ecm_generate_headers(KIconThemes_HEADERS
|
||||
HEADER_NAMES
|
||||
KIconColors
|
||||
KIconEffect
|
||||
KIconLoader
|
||||
KIconTheme
|
||||
KIconEngine
|
||||
KQuickIconProvider
|
||||
|
||||
REQUIRED_HEADERS KIconThemes_HEADERS
|
||||
)
|
||||
|
||||
install(TARGETS KF6IconThemes EXPORT KF6IconThemesTargets ${KF_INSTALL_TARGETS_DEFAULT_ARGS})
|
||||
|
||||
install(FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/kiconthemes_export.h
|
||||
${KIconThemes_HEADERS}
|
||||
DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF}/KIconThemes COMPONENT Devel
|
||||
)
|
||||
|
||||
if(BUILD_QCH)
|
||||
ecm_add_qch(
|
||||
KF6IconThemes_QCH
|
||||
NAME KIconThemes
|
||||
BASE_NAME KF6IconThemes
|
||||
VERSION ${KF_VERSION}
|
||||
ORG_DOMAIN org.kde
|
||||
SOURCES # using only public headers, to cover only public API
|
||||
${KIconThemes_HEADERS}
|
||||
MD_MAINPAGE "${CMAKE_SOURCE_DIR}/README.md"
|
||||
IMAGE_DIRS "${CMAKE_SOURCE_DIR}/docs/pics"
|
||||
LINK_QCHS
|
||||
Qt6Widgets_QCH
|
||||
INCLUDE_DIRS
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
BLANK_MACROS
|
||||
KICONTHEMES_EXPORT
|
||||
KICONTHEMES_DEPRECATED
|
||||
KICONTHEMES_DEPRECATED_EXPORT
|
||||
"KICONTHEMES_DEPRECATED_VERSION(x, y, t)"
|
||||
"KICONTHEMES_DEPRECATED_VERSION_BELATED(x, y, xt, yt, t)"
|
||||
"KICONTHEMES_ENUMERATOR_DEPRECATED_VERSION(x, y, t)"
|
||||
"KICONTHEMES_ENUMERATOR_DEPRECATED_VERSION_BELATED(x, y, xt, yt, t)"
|
||||
TAGFILE_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR}
|
||||
QCH_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR}
|
||||
COMPONENT Devel
|
||||
)
|
||||
endif()
|
||||
|
||||
add_library(KIconEnginePlugin MODULE kiconengineplugin.cpp)
|
||||
|
||||
target_link_libraries(KIconEnginePlugin
|
||||
PRIVATE
|
||||
Qt6::Gui
|
||||
KF6::IconThemes
|
||||
)
|
||||
|
||||
# install in an extra directory we will add to the plugin path later just for this one engine
|
||||
# we can overwrite the system one with that trick
|
||||
install(TARGETS KIconEnginePlugin DESTINATION ${KDE_INSTALL_QTPLUGINDIR}/kiconthemes6/iconengines)
|
||||
|
||||
ecm_qt_install_logging_categories(
|
||||
EXPORT KICONTHEMES
|
||||
FILE kiconthemes.categories
|
||||
DESTINATION ${KDE_INSTALL_LOGGINGCATEGORIESDIR}
|
||||
)
|
||||
@@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Invoke the extractrc script on all .ui, .rc, and .kcfg files in the sources.
|
||||
# The results are stored in a pseudo .cpp file to be picked up by xgettext.
|
||||
lst=`find . -name \*.rc -o -name \*.ui -o -name \*.kcfg`
|
||||
if [ -n "$lst" ] ; then
|
||||
$EXTRACTRC $lst >> rc.cpp
|
||||
fi
|
||||
|
||||
# Extract strings from all source files.
|
||||
# If your framework depends on KI18n, use $XGETTEXT. If it uses Qt translation
|
||||
# system, use $EXTRACT_TR_STRINGS.
|
||||
$XGETTEXT `find . -name \*.cpp -o -name \*.h -o -name \*.qml` -o $podir/kiconthemes6.pot
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#cmakedefine01 USE_BreezeIcons
|
||||
@@ -0,0 +1,5 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource>
|
||||
<file alias="icons/hicolor/index.theme">hicolor.theme</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
|
||||
This file is part of the KDE project, module kdecore.
|
||||
SPDX-FileCopyrightText: 2000 Geert Jansen <jansen@kde.org>
|
||||
SPDX-FileCopyrightText: 2000 Antonio Larrosa <larrosa@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-only
|
||||
*/
|
||||
|
||||
#include "kiconcolors.h"
|
||||
#include <KColorScheme>
|
||||
|
||||
static QString STYLESHEET_TEMPLATE()
|
||||
{
|
||||
/* clang-format off */
|
||||
return QStringLiteral(".ColorScheme-Text { color:%1; }\
|
||||
.ColorScheme-Background{ color:%2; }\
|
||||
.ColorScheme-Highlight{ color:%3; }\
|
||||
.ColorScheme-HighlightedText{ color:%4; }\
|
||||
.ColorScheme-PositiveText{ color:%5; }\
|
||||
.ColorScheme-NeutralText{ color:%6; }\
|
||||
.ColorScheme-NegativeText{ color:%7; }\
|
||||
.ColorScheme-ActiveText{ color:%8; }\
|
||||
.ColorScheme-Complement{ color:%9; }\
|
||||
.ColorScheme-Contrast{ color:%10; }\
|
||||
.ColorScheme-Accent{ color:%11; }\
|
||||
");
|
||||
/* clang-format on */
|
||||
}
|
||||
|
||||
class KIconColorsPrivate : public QSharedData
|
||||
{
|
||||
public:
|
||||
KIconColorsPrivate()
|
||||
{
|
||||
}
|
||||
KIconColorsPrivate(const KIconColorsPrivate &other)
|
||||
: QSharedData(other)
|
||||
, text(other.text)
|
||||
, background(other.background)
|
||||
, highlight(other.highlight)
|
||||
, highlightedText(other.highlightedText)
|
||||
, accent(other.accent)
|
||||
, positiveText(other.positiveText)
|
||||
, neutralText(other.neutralText)
|
||||
, negativeText(other.negativeText)
|
||||
{
|
||||
}
|
||||
~KIconColorsPrivate()
|
||||
{
|
||||
}
|
||||
|
||||
QColor text;
|
||||
QColor background;
|
||||
QColor highlight;
|
||||
QColor highlightedText;
|
||||
QColor accent;
|
||||
QColor positiveText;
|
||||
QColor neutralText;
|
||||
QColor negativeText;
|
||||
QColor activeText;
|
||||
static std::optional<QPalette> lastPalette;
|
||||
static std::optional<KColorScheme> lastColorScheme;
|
||||
};
|
||||
|
||||
std::optional<QPalette> KIconColorsPrivate::lastPalette;
|
||||
std::optional<KColorScheme> KIconColorsPrivate::lastColorScheme;
|
||||
|
||||
KIconColors::KIconColors()
|
||||
: KIconColors(QPalette())
|
||||
{
|
||||
}
|
||||
|
||||
KIconColors::KIconColors(const KIconColors &other)
|
||||
: d_ptr(other.d_ptr)
|
||||
{
|
||||
}
|
||||
|
||||
KIconColors KIconColors::operator=(const KIconColors &other)
|
||||
{
|
||||
if (d_ptr != other.d_ptr) {
|
||||
d_ptr = other.d_ptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
KIconColors::KIconColors(const QColor &colors)
|
||||
: d_ptr(new KIconColorsPrivate)
|
||||
{
|
||||
Q_D(KIconColors);
|
||||
d->text = colors;
|
||||
d->background = colors;
|
||||
d->highlight = colors;
|
||||
d->highlightedText = colors;
|
||||
d->positiveText = colors;
|
||||
d->neutralText = colors;
|
||||
d->negativeText = colors;
|
||||
d->accent = colors;
|
||||
}
|
||||
|
||||
KIconColors::KIconColors(const QPalette &palette)
|
||||
: d_ptr(new KIconColorsPrivate)
|
||||
{
|
||||
Q_D(KIconColors);
|
||||
d->text = palette.windowText().color();
|
||||
d->background = palette.window().color();
|
||||
d->highlight = palette.highlight().color();
|
||||
d->highlightedText = palette.highlightedText().color();
|
||||
d->accent = palette.accent().color();
|
||||
|
||||
if (!d->lastColorScheme || !d->lastPalette || palette != d->lastPalette) {
|
||||
d->lastPalette = palette;
|
||||
d->lastColorScheme = KColorScheme(QPalette::Active, KColorScheme::Window);
|
||||
}
|
||||
|
||||
d->positiveText = d->lastColorScheme->foreground(KColorScheme::PositiveText).color().name();
|
||||
d->neutralText = d->lastColorScheme->foreground(KColorScheme::NeutralText).color().name();
|
||||
d->negativeText = d->lastColorScheme->foreground(KColorScheme::NegativeText).color().name();
|
||||
d->activeText = d->lastColorScheme->foreground(KColorScheme::ActiveText).color().name();
|
||||
}
|
||||
|
||||
KIconColors::~KIconColors()
|
||||
{
|
||||
}
|
||||
|
||||
qreal luma(const QColor &color) {
|
||||
return (0.299 * color.red() + 0.587 * color.green() + 0.114 * color.blue()) / 255;
|
||||
}
|
||||
|
||||
QString KIconColors::stylesheet(KIconLoader::States state) const
|
||||
{
|
||||
Q_D(const KIconColors);
|
||||
|
||||
const QColor complement =
|
||||
luma(d->background) > 0.5 ? Qt::white : Qt::black;
|
||||
|
||||
const QColor contrast =
|
||||
luma(d->background) > 0.5 ? Qt::black : Qt::white;
|
||||
|
||||
QColor accentColor = d->accent;
|
||||
// When selected, tint the accent color with a small portion of highlighted text color,
|
||||
// because since the accent color used to be the same as the highlight color, it might cause
|
||||
// icons, especially folders to "disappear" against the background
|
||||
if (state == KIconLoader::SelectedState) {
|
||||
const qreal tintRatio = 0.85;
|
||||
const qreal r = accentColor.redF() * tintRatio + d->highlightedText.redF() * (1.0 - tintRatio);
|
||||
const qreal g = accentColor.greenF() * tintRatio + d->highlightedText.greenF() * (1.0 - tintRatio);
|
||||
const qreal b = accentColor.blueF() * tintRatio + d->highlightedText.blueF() * (1.0 - tintRatio);
|
||||
accentColor.setRgbF(r, g, b, accentColor.alphaF());
|
||||
}
|
||||
|
||||
return STYLESHEET_TEMPLATE()
|
||||
.arg(state == KIconLoader::SelectedState ? d->highlightedText.name() : d->text.name())
|
||||
.arg(state == KIconLoader::SelectedState ? d->highlight.name() : d->background.name())
|
||||
.arg(state == KIconLoader::SelectedState ? d->highlightedText.name() : d->highlight.name())
|
||||
.arg(state == KIconLoader::SelectedState ? d->highlight.name() : d->highlightedText.name())
|
||||
.arg(state == KIconLoader::SelectedState ? d->highlightedText.name() : d->positiveText.name())
|
||||
.arg(state == KIconLoader::SelectedState ? d->highlightedText.name() : d->neutralText.name())
|
||||
.arg(state == KIconLoader::SelectedState ? d->highlightedText.name() : d->negativeText.name())
|
||||
.arg(state == KIconLoader::SelectedState ? d->highlightedText.name() : d->activeText.name())
|
||||
.arg(complement.name())
|
||||
.arg(contrast.name())
|
||||
.arg(accentColor.name());
|
||||
}
|
||||
|
||||
QColor KIconColors::highlight() const
|
||||
{
|
||||
Q_D(const KIconColors);
|
||||
return d->highlight;
|
||||
}
|
||||
|
||||
QColor KIconColors::highlightedText() const
|
||||
{
|
||||
Q_D(const KIconColors);
|
||||
return d->highlightedText;
|
||||
}
|
||||
|
||||
QColor KIconColors::accent() const
|
||||
{
|
||||
Q_D(const KIconColors);
|
||||
return d->accent;
|
||||
}
|
||||
|
||||
QColor KIconColors::background() const
|
||||
{
|
||||
Q_D(const KIconColors);
|
||||
return d->background;
|
||||
}
|
||||
|
||||
QColor KIconColors::text() const
|
||||
{
|
||||
Q_D(const KIconColors);
|
||||
return d->text;
|
||||
}
|
||||
|
||||
QColor KIconColors::negativeText() const
|
||||
{
|
||||
Q_D(const KIconColors);
|
||||
return d->negativeText;
|
||||
}
|
||||
|
||||
QColor KIconColors::positiveText() const
|
||||
{
|
||||
Q_D(const KIconColors);
|
||||
return d->positiveText;
|
||||
}
|
||||
|
||||
QColor KIconColors::neutralText() const
|
||||
{
|
||||
Q_D(const KIconColors);
|
||||
return d->neutralText;
|
||||
}
|
||||
|
||||
QColor KIconColors::activeText() const
|
||||
{
|
||||
Q_D(const KIconColors);
|
||||
return d->activeText;
|
||||
}
|
||||
|
||||
void KIconColors::setText(const QColor &color)
|
||||
{
|
||||
Q_D(KIconColors);
|
||||
d->text = color;
|
||||
}
|
||||
|
||||
void KIconColors::setBackground(const QColor &color)
|
||||
{
|
||||
Q_D(KIconColors);
|
||||
d->background = color;
|
||||
}
|
||||
|
||||
void KIconColors::setHighlight(const QColor &color)
|
||||
{
|
||||
Q_D(KIconColors);
|
||||
d->highlight = color;
|
||||
}
|
||||
|
||||
void KIconColors::setHighlightedText(const QColor &color)
|
||||
{
|
||||
Q_D(KIconColors);
|
||||
d->highlightedText = color;
|
||||
}
|
||||
|
||||
void KIconColors::setAccent(const QColor &color)
|
||||
{
|
||||
Q_D(KIconColors);
|
||||
d->accent = color;
|
||||
}
|
||||
|
||||
void KIconColors::setNegativeText(const QColor &color)
|
||||
{
|
||||
Q_D(KIconColors);
|
||||
d->negativeText = color;
|
||||
}
|
||||
|
||||
void KIconColors::setNeutralText(const QColor &color)
|
||||
{
|
||||
Q_D(KIconColors);
|
||||
d->neutralText = color;
|
||||
}
|
||||
|
||||
void KIconColors::setPositiveText(const QColor &color)
|
||||
{
|
||||
Q_D(KIconColors);
|
||||
d->positiveText = color;
|
||||
}
|
||||
|
||||
void KIconColors::setActiveText(const QColor &color)
|
||||
{
|
||||
Q_D(KIconColors);
|
||||
d->activeText = color;
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
|
||||
This file is part of the KDE project, module kdecore.
|
||||
SPDX-FileCopyrightText: 2000 Geert Jansen <jansen@kde.org>
|
||||
SPDX-FileCopyrightText: 2000 Antonio Larrosa <larrosa@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-only
|
||||
*/
|
||||
|
||||
#ifndef KICONCOLORS_H
|
||||
#define KICONCOLORS_H
|
||||
|
||||
#include "kiconloader.h"
|
||||
#include <QPalette>
|
||||
#include <QSharedDataPointer>
|
||||
|
||||
class KIconColorsPrivate;
|
||||
|
||||
/**
|
||||
* @class KIconColors
|
||||
*
|
||||
* Sepecifies which colors will be used when recoloring icons as its stylesheet.
|
||||
*
|
||||
* KIconLoader supports re-coloring svg icons based on a set of colors. This
|
||||
* class will define them.
|
||||
*
|
||||
* @see KIconEngine
|
||||
* @see KDE::icon
|
||||
*/
|
||||
class KICONTHEMES_EXPORT KIconColors
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Will fill the colors based on the default QPalette() constructor.
|
||||
*/
|
||||
KIconColors();
|
||||
|
||||
/**
|
||||
* Makes all the color property be @p colors
|
||||
*/
|
||||
explicit KIconColors(const QColor &colors);
|
||||
|
||||
/**
|
||||
* Uses @palette to define text, highlight, highlightedText, accent and background.
|
||||
* The rest being positiveText, negativeText and neutralText are filled from
|
||||
* KColorScheme(QPalette::Active, KColorScheme::Window);
|
||||
*/
|
||||
explicit KIconColors(const QPalette &palette);
|
||||
|
||||
KIconColors(const KIconColors &other);
|
||||
~KIconColors();
|
||||
KIconColors operator=(const KIconColors &other);
|
||||
|
||||
QColor text() const;
|
||||
QColor highlight() const;
|
||||
QColor highlightedText() const;
|
||||
QColor accent() const;
|
||||
QColor background() const;
|
||||
QColor neutralText() const;
|
||||
QColor positiveText() const;
|
||||
QColor negativeText() const;
|
||||
QColor activeText() const;
|
||||
|
||||
void setText(const QColor &color);
|
||||
void setHighlight(const QColor &color);
|
||||
void setHighlightedText(const QColor &color);
|
||||
void setAccent(const QColor &color);
|
||||
void setBackground(const QColor &color);
|
||||
void setNeutralText(const QColor &color);
|
||||
void setPositiveText(const QColor &color);
|
||||
void setNegativeText(const QColor &color);
|
||||
void setActiveText(const QColor& color);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @returns a CSS stylesheet to be used SVG icon files.
|
||||
* @param state defines the state we are rendering the stylesheet for
|
||||
*
|
||||
* Specifies: .ColorScheme-Text, .ColorScheme-Background, .ColorScheme-Highlight,
|
||||
* .ColorScheme-HighlightedText, .ColorScheme-PositiveText, .ColorScheme-NeutralText
|
||||
* .ColorScheme-NegativeText, .ColorScheme-ActiveText, .ColorScheme-Complement,
|
||||
* .ColorScheme-Contrast, .ColorScheme-Accent,
|
||||
*/
|
||||
QString stylesheet(KIconLoader::States state) const;
|
||||
|
||||
private:
|
||||
Q_DECLARE_PRIVATE(KIconColors)
|
||||
friend class KIconLoaderPrivate;
|
||||
|
||||
QExplicitlySharedDataPointer<KIconColorsPrivate> d_ptr;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,724 @@
|
||||
/*
|
||||
|
||||
This file is part of the KDE project, module kdecore.
|
||||
SPDX-FileCopyrightText: 2000 Geert Jansen <jansen@kde.org>
|
||||
SPDX-FileCopyrightText: 2007 Daniel M. Duley <daniel.duley@verizon.net>
|
||||
|
||||
with minor additions and based on ideas from
|
||||
SPDX-FileContributor: Torsten Rahn <torsten@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-only
|
||||
*/
|
||||
|
||||
#include "kiconeffect.h"
|
||||
#include "debug.h"
|
||||
#include "kiconloader.h"
|
||||
|
||||
#include <KColorScheme>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QPalette>
|
||||
#include <QSysInfo>
|
||||
|
||||
#include <qplatformdefs.h>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
class KIconEffectPrivate
|
||||
{
|
||||
public:
|
||||
// http://en.cppreference.com/w/cpp/language/zero_initialization
|
||||
KIconEffectPrivate()
|
||||
: effect{{}}
|
||||
, value{{}}
|
||||
, trans{{}}
|
||||
, key{{}}
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
int effect[KIconLoader::LastGroup][KIconLoader::LastState];
|
||||
float value[KIconLoader::LastGroup][KIconLoader::LastState];
|
||||
bool trans[KIconLoader::LastGroup][KIconLoader::LastState];
|
||||
QString key[KIconLoader::LastGroup][KIconLoader::LastState];
|
||||
};
|
||||
|
||||
#if KICONTHEMES_BUILD_DEPRECATED_SINCE(6, 5)
|
||||
KIconEffect::KIconEffect()
|
||||
: d(new KIconEffectPrivate)
|
||||
{
|
||||
init();
|
||||
}
|
||||
#endif
|
||||
|
||||
KIconEffect::~KIconEffect() = default;
|
||||
|
||||
#if KICONTHEMES_BUILD_DEPRECATED_SINCE(6, 5)
|
||||
void KIconEffect::init()
|
||||
{
|
||||
int i;
|
||||
// FIXME: this really should be using KIconLoader::metaObject() to guarantee synchronization
|
||||
// performance wise it's also practically guaranteed to be faster
|
||||
QStringList groups;
|
||||
groups += QStringLiteral("Desktop");
|
||||
groups += QStringLiteral("Toolbar");
|
||||
groups += QStringLiteral("MainToolbar");
|
||||
groups += QStringLiteral("Small");
|
||||
groups += QStringLiteral("Panel");
|
||||
groups += QStringLiteral("Dialog");
|
||||
|
||||
QStringList states;
|
||||
states += QStringLiteral("Default");
|
||||
states += QStringLiteral("Active");
|
||||
states += QStringLiteral("Disabled");
|
||||
|
||||
QStringList::ConstIterator it;
|
||||
|
||||
for (it = groups.constBegin(), i = 0; it != groups.constEnd(); ++it, ++i) {
|
||||
d->effect[i][KIconLoader::DefaultState] = NoEffect;
|
||||
d->effect[i][KIconLoader::ActiveState] = ((i == KIconLoader::Desktop) || (KIconLoader::Panel == 4)) ? ToGamma : NoEffect;
|
||||
d->effect[i][KIconLoader::DisabledState] = ToGray;
|
||||
|
||||
d->trans[i][KIconLoader::DefaultState] = false;
|
||||
d->trans[i][KIconLoader::ActiveState] = false;
|
||||
d->trans[i][KIconLoader::DisabledState] = true;
|
||||
d->value[i][KIconLoader::DefaultState] = 1.0;
|
||||
d->value[i][KIconLoader::ActiveState] = ((i == KIconLoader::Desktop) || (KIconLoader::Panel == 4)) ? 0.7 : 1.0;
|
||||
d->value[i][KIconLoader::DisabledState] = 1.0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if KICONTHEMES_BUILD_DEPRECATED_SINCE(6, 5)
|
||||
bool KIconEffect::hasEffect(int group, int state) const
|
||||
{
|
||||
if (group < 0 || group >= KIconLoader::LastGroup //
|
||||
|| state < 0 || state >= KIconLoader::LastState) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return d->effect[group][state] != NoEffect;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if KICONTHEMES_BUILD_DEPRECATED_SINCE(6, 5)
|
||||
QString KIconEffect::fingerprint(int group, int state) const
|
||||
{
|
||||
if (group < 0 || group >= KIconLoader::LastGroup //
|
||||
|| state < 0 || state >= KIconLoader::LastState) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString cached = d->key[group][state];
|
||||
if (cached.isEmpty()) {
|
||||
QString tmp;
|
||||
cached = tmp.setNum(d->effect[group][state]);
|
||||
cached += QLatin1Char(':');
|
||||
cached += tmp.setNum(d->value[group][state]);
|
||||
cached += QLatin1Char(':');
|
||||
cached += d->trans[group][state] ? QLatin1String("trans") : QLatin1String("notrans");
|
||||
|
||||
d->key[group][state] = cached;
|
||||
}
|
||||
|
||||
return cached;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if KICONTHEMES_BUILD_DEPRECATED_SINCE(6, 5)
|
||||
QImage KIconEffect::apply(const QImage &image, int group, int state) const
|
||||
{
|
||||
if (state >= KIconLoader::LastState) {
|
||||
qCWarning(KICONTHEMES) << "Invalid icon state:" << state << ", should be one of KIconLoader::States";
|
||||
return image;
|
||||
}
|
||||
if (group >= KIconLoader::LastGroup) {
|
||||
qCWarning(KICONTHEMES) << "Invalid icon group:" << group << ", should be one of KIconLoader::Group";
|
||||
return image;
|
||||
}
|
||||
return apply(image, d->effect[group][state], d->value[group][state], QColor(), QColor(), d->trans[group][state]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if KICONTHEMES_BUILD_DEPRECATED_SINCE(6, 5)
|
||||
QImage KIconEffect::apply(const QImage &image, int effect, float value, const QColor &col, bool trans) const
|
||||
{
|
||||
return apply(image, effect, value, col, KColorScheme(QPalette::Active, KColorScheme::View).background().color(), trans);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if KICONTHEMES_BUILD_DEPRECATED_SINCE(6, 5)
|
||||
QImage KIconEffect::apply(const QImage &img, int effect, float value, const QColor &col, const QColor &col2, bool trans) const
|
||||
{
|
||||
QImage image = img;
|
||||
if (effect >= LastEffect) {
|
||||
qCWarning(KICONTHEMES) << "Invalid icon effect:" << effect << ", should be one of KIconLoader::Effects";
|
||||
return image;
|
||||
}
|
||||
if (value > 1.0) {
|
||||
value = 1.0;
|
||||
} else if (value < 0.0) {
|
||||
value = 0.0;
|
||||
}
|
||||
switch (effect) {
|
||||
case ToGray:
|
||||
toGray(image, value);
|
||||
break;
|
||||
case DeSaturate:
|
||||
deSaturate(image, value);
|
||||
break;
|
||||
case Colorize:
|
||||
colorize(image, col, value);
|
||||
break;
|
||||
case ToGamma:
|
||||
toGamma(image, value);
|
||||
break;
|
||||
case ToMonochrome:
|
||||
toMonochrome(image, col, col2, value);
|
||||
break;
|
||||
}
|
||||
if (trans == true) {
|
||||
semiTransparent(image);
|
||||
}
|
||||
return image;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if KICONTHEMES_BUILD_DEPRECATED_SINCE(6, 5)
|
||||
QPixmap KIconEffect::apply(const QPixmap &pixmap, int group, int state) const
|
||||
{
|
||||
if (state >= KIconLoader::LastState) {
|
||||
qCWarning(KICONTHEMES) << "Invalid icon state:" << state << ", should be one of KIconLoader::States";
|
||||
return pixmap;
|
||||
}
|
||||
if (group >= KIconLoader::LastGroup) {
|
||||
qCWarning(KICONTHEMES) << "Invalid icon group:" << group << ", should be one of KIconLoader::Group";
|
||||
return pixmap;
|
||||
}
|
||||
return apply(pixmap, d->effect[group][state], d->value[group][state], QColor(), QColor(), d->trans[group][state]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if KICONTHEMES_BUILD_DEPRECATED_SINCE(6, 5)
|
||||
QPixmap KIconEffect::apply(const QPixmap &pixmap, int effect, float value, const QColor &col, bool trans) const
|
||||
{
|
||||
return apply(pixmap, effect, value, col, KColorScheme(QPalette::Active, KColorScheme::View).background().color(), trans);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if KICONTHEMES_BUILD_DEPRECATED_SINCE(6, 5)
|
||||
QPixmap KIconEffect::apply(const QPixmap &pixmap, int effect, float value, const QColor &col, const QColor &col2, bool trans) const
|
||||
{
|
||||
QPixmap result;
|
||||
|
||||
if (effect >= LastEffect) {
|
||||
qCWarning(KICONTHEMES) << "Invalid icon effect:" << effect << ", should be one of KIconLoader::Effects";
|
||||
return result;
|
||||
}
|
||||
|
||||
if ((trans == true) && (effect == NoEffect)) {
|
||||
result = pixmap;
|
||||
semiTransparent(result);
|
||||
} else if (effect != NoEffect) {
|
||||
QImage tmpImg = pixmap.toImage();
|
||||
tmpImg = apply(tmpImg, effect, value, col, col2, trans);
|
||||
result = QPixmap::fromImage(std::move(tmpImg));
|
||||
} else {
|
||||
result = pixmap;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct KIEImgEdit {
|
||||
QImage &img;
|
||||
QList<QRgb> colors;
|
||||
unsigned int *data;
|
||||
unsigned int pixels;
|
||||
|
||||
KIEImgEdit(QImage &_img)
|
||||
: img(_img)
|
||||
{
|
||||
if (img.depth() > 8) {
|
||||
// Code using data and pixels assumes that the pixels are stored
|
||||
// in 32bit values and that the image is not premultiplied
|
||||
if ((img.format() != QImage::Format_ARGB32) //
|
||||
&& (img.format() != QImage::Format_RGB32)) {
|
||||
img.convertTo(QImage::Format_ARGB32);
|
||||
}
|
||||
data = (unsigned int *)img.bits();
|
||||
pixels = img.width() * img.height();
|
||||
} else {
|
||||
pixels = img.colorCount();
|
||||
colors = img.colorTable();
|
||||
data = (unsigned int *)colors.data();
|
||||
}
|
||||
}
|
||||
|
||||
~KIEImgEdit()
|
||||
{
|
||||
if (img.depth() <= 8) {
|
||||
img.setColorTable(colors);
|
||||
}
|
||||
}
|
||||
|
||||
KIEImgEdit(const KIEImgEdit &) = delete;
|
||||
KIEImgEdit &operator=(const KIEImgEdit &) = delete;
|
||||
};
|
||||
|
||||
// Taken from KImageEffect. We don't want to link kdecore to kdeui! As long
|
||||
// as this code is not too big, it doesn't seem much of a problem to me.
|
||||
|
||||
void KIconEffect::toGray(QImage &img, float value)
|
||||
{
|
||||
if (value == 0.0) {
|
||||
return;
|
||||
}
|
||||
|
||||
KIEImgEdit ii(img);
|
||||
QRgb *data = ii.data;
|
||||
QRgb *end = data + ii.pixels;
|
||||
|
||||
unsigned char gray;
|
||||
if (value == 1.0) {
|
||||
while (data != end) {
|
||||
gray = qGray(*data);
|
||||
*data = qRgba(gray, gray, gray, qAlpha(*data));
|
||||
++data;
|
||||
}
|
||||
} else {
|
||||
unsigned char val = (unsigned char)(255.0 * value);
|
||||
while (data != end) {
|
||||
gray = qGray(*data);
|
||||
*data = qRgba((val * gray + (0xFF - val) * qRed(*data)) >> 8,
|
||||
(val * gray + (0xFF - val) * qGreen(*data)) >> 8,
|
||||
(val * gray + (0xFF - val) * qBlue(*data)) >> 8,
|
||||
qAlpha(*data));
|
||||
++data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KIconEffect::colorize(QImage &img, const QColor &col, float value)
|
||||
{
|
||||
if (value == 0.0) {
|
||||
return;
|
||||
}
|
||||
|
||||
KIEImgEdit ii(img);
|
||||
QRgb *data = ii.data;
|
||||
QRgb *end = data + ii.pixels;
|
||||
|
||||
float rcol = col.red();
|
||||
float gcol = col.green();
|
||||
float bcol = col.blue();
|
||||
unsigned char red;
|
||||
unsigned char green;
|
||||
unsigned char blue;
|
||||
unsigned char gray;
|
||||
unsigned char val = (unsigned char)(255.0 * value);
|
||||
while (data != end) {
|
||||
gray = qGray(*data);
|
||||
if (gray < 128) {
|
||||
red = static_cast<unsigned char>(rcol / 128 * gray);
|
||||
green = static_cast<unsigned char>(gcol / 128 * gray);
|
||||
blue = static_cast<unsigned char>(bcol / 128 * gray);
|
||||
} else if (gray > 128) {
|
||||
red = static_cast<unsigned char>((gray - 128) * (2 - rcol / 128) + rcol - 1);
|
||||
green = static_cast<unsigned char>((gray - 128) * (2 - gcol / 128) + gcol - 1);
|
||||
blue = static_cast<unsigned char>((gray - 128) * (2 - bcol / 128) + bcol - 1);
|
||||
} else {
|
||||
red = static_cast<unsigned char>(rcol);
|
||||
green = static_cast<unsigned char>(gcol);
|
||||
blue = static_cast<unsigned char>(bcol);
|
||||
}
|
||||
|
||||
*data = qRgba((val * red + (0xFF - val) * qRed(*data)) >> 8,
|
||||
(val * green + (0xFF - val) * qGreen(*data)) >> 8,
|
||||
(val * blue + (0xFF - val) * qBlue(*data)) >> 8,
|
||||
qAlpha(*data));
|
||||
++data;
|
||||
}
|
||||
}
|
||||
|
||||
void KIconEffect::toMonochrome(QImage &img, const QColor &black, const QColor &white, float value)
|
||||
{
|
||||
if (value == 0.0) {
|
||||
return;
|
||||
}
|
||||
|
||||
KIEImgEdit ii(img);
|
||||
QRgb *data = ii.data;
|
||||
QRgb *end = data + ii.pixels;
|
||||
|
||||
// Step 1: determine the average brightness
|
||||
double values = 0.0;
|
||||
double sum = 0.0;
|
||||
bool grayscale = true;
|
||||
while (data != end) {
|
||||
sum += qGray(*data) * qAlpha(*data) + 255 * (255 - qAlpha(*data));
|
||||
values += 255;
|
||||
if ((qRed(*data) != qGreen(*data)) || (qGreen(*data) != qBlue(*data))) {
|
||||
grayscale = false;
|
||||
}
|
||||
++data;
|
||||
}
|
||||
double medium = sum / values;
|
||||
|
||||
// Step 2: Modify the image
|
||||
unsigned char val = (unsigned char)(255.0 * value);
|
||||
int rw = white.red();
|
||||
int gw = white.green();
|
||||
int bw = white.blue();
|
||||
int rb = black.red();
|
||||
int gb = black.green();
|
||||
int bb = black.blue();
|
||||
data = ii.data;
|
||||
|
||||
if (grayscale) {
|
||||
while (data != end) {
|
||||
if (qRed(*data) <= medium) {
|
||||
*data = qRgba((val * rb + (0xFF - val) * qRed(*data)) >> 8,
|
||||
(val * gb + (0xFF - val) * qGreen(*data)) >> 8,
|
||||
(val * bb + (0xFF - val) * qBlue(*data)) >> 8,
|
||||
qAlpha(*data));
|
||||
} else {
|
||||
*data = qRgba((val * rw + (0xFF - val) * qRed(*data)) >> 8,
|
||||
(val * gw + (0xFF - val) * qGreen(*data)) >> 8,
|
||||
(val * bw + (0xFF - val) * qBlue(*data)) >> 8,
|
||||
qAlpha(*data));
|
||||
}
|
||||
++data;
|
||||
}
|
||||
} else {
|
||||
while (data != end) {
|
||||
if (qGray(*data) <= medium) {
|
||||
*data = qRgba((val * rb + (0xFF - val) * qRed(*data)) >> 8,
|
||||
(val * gb + (0xFF - val) * qGreen(*data)) >> 8,
|
||||
(val * bb + (0xFF - val) * qBlue(*data)) >> 8,
|
||||
qAlpha(*data));
|
||||
} else {
|
||||
*data = qRgba((val * rw + (0xFF - val) * qRed(*data)) >> 8,
|
||||
(val * gw + (0xFF - val) * qGreen(*data)) >> 8,
|
||||
(val * bw + (0xFF - val) * qBlue(*data)) >> 8,
|
||||
qAlpha(*data));
|
||||
}
|
||||
++data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KIconEffect::deSaturate(QImage &img, float value)
|
||||
{
|
||||
if (value == 0.0) {
|
||||
return;
|
||||
}
|
||||
|
||||
KIEImgEdit ii(img);
|
||||
QRgb *data = ii.data;
|
||||
QRgb *end = data + ii.pixels;
|
||||
|
||||
QColor color;
|
||||
int h;
|
||||
int s;
|
||||
int v;
|
||||
while (data != end) {
|
||||
color.setRgb(*data);
|
||||
color.getHsv(&h, &s, &v);
|
||||
color.setHsv(h, (int)(s * (1.0 - value) + 0.5), v);
|
||||
*data = qRgba(color.red(), color.green(), color.blue(), qAlpha(*data));
|
||||
++data;
|
||||
}
|
||||
}
|
||||
|
||||
void KIconEffect::toGamma(QImage &img, float value)
|
||||
{
|
||||
KIEImgEdit ii(img);
|
||||
QRgb *data = ii.data;
|
||||
QRgb *end = data + ii.pixels;
|
||||
|
||||
float gamma = 1 / (2 * value + 0.5);
|
||||
while (data != end) {
|
||||
*data = qRgba(static_cast<unsigned char>(pow(static_cast<float>(qRed(*data)) / 255, gamma) * 255),
|
||||
static_cast<unsigned char>(pow(static_cast<float>(qGreen(*data)) / 255, gamma) * 255),
|
||||
static_cast<unsigned char>(pow(static_cast<float>(qBlue(*data)) / 255, gamma) * 255),
|
||||
qAlpha(*data));
|
||||
++data;
|
||||
}
|
||||
}
|
||||
|
||||
void KIconEffect::semiTransparent(QImage &img)
|
||||
{
|
||||
if (img.depth() == 32) {
|
||||
if (img.format() == QImage::Format_ARGB32_Premultiplied) {
|
||||
img.convertTo(QImage::Format_ARGB32);
|
||||
}
|
||||
int width = img.width();
|
||||
int height = img.height();
|
||||
|
||||
unsigned char *line;
|
||||
for (int y = 0; y < height; ++y) {
|
||||
if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
|
||||
line = img.scanLine(y);
|
||||
} else {
|
||||
line = img.scanLine(y) + 3;
|
||||
}
|
||||
for (int x = 0; x < width; ++x) {
|
||||
*line >>= 1;
|
||||
line += 4;
|
||||
}
|
||||
}
|
||||
} else if (img.depth() == 8) {
|
||||
// not running on 8 bit, we can safely install a new colorTable
|
||||
QList<QRgb> colorTable = img.colorTable();
|
||||
for (int i = 0; i < colorTable.size(); ++i) {
|
||||
colorTable[i] = (colorTable[i] & 0x00ffffff) | ((colorTable[i] & 0xfe000000) >> 1);
|
||||
}
|
||||
img.setColorTable(colorTable);
|
||||
} else {
|
||||
// Insert transparent pixel into the clut.
|
||||
int transColor = -1;
|
||||
|
||||
// search for a color that is already transparent
|
||||
for (int x = 0; x < img.colorCount(); ++x) {
|
||||
// try to find already transparent pixel
|
||||
if (qAlpha(img.color(x)) < 127) {
|
||||
transColor = x;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: image must have transparency
|
||||
if (transColor < 0 || transColor >= img.colorCount()) {
|
||||
return;
|
||||
}
|
||||
|
||||
img.setColor(transColor, 0);
|
||||
unsigned char *line;
|
||||
if (img.depth() == 8) {
|
||||
for (int y = 0; y < img.height(); ++y) {
|
||||
line = img.scanLine(y);
|
||||
for (int x = (y % 2); x < img.width(); x += 2) {
|
||||
line[x] = transColor;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const bool setOn = (transColor != 0);
|
||||
if (img.format() == QImage::Format_MonoLSB) {
|
||||
for (int y = 0; y < img.height(); ++y) {
|
||||
line = img.scanLine(y);
|
||||
for (int x = (y % 2); x < img.width(); x += 2) {
|
||||
if (!setOn) {
|
||||
*(line + (x >> 3)) &= ~(1 << (x & 7));
|
||||
} else {
|
||||
*(line + (x >> 3)) |= (1 << (x & 7));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int y = 0; y < img.height(); ++y) {
|
||||
line = img.scanLine(y);
|
||||
for (int x = (y % 2); x < img.width(); x += 2) {
|
||||
if (!setOn) {
|
||||
*(line + (x >> 3)) &= ~(1 << (7 - (x & 7)));
|
||||
} else {
|
||||
*(line + (x >> 3)) |= (1 << (7 - (x & 7)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KIconEffect::semiTransparent(QPixmap &pix)
|
||||
{
|
||||
QImage img = pix.toImage();
|
||||
semiTransparent(img);
|
||||
pix = QPixmap::fromImage(img);
|
||||
}
|
||||
|
||||
QImage KIconEffect::doublePixels(const QImage &src) const
|
||||
{
|
||||
int w = src.width();
|
||||
int h = src.height();
|
||||
|
||||
QImage dst(w * 2, h * 2, src.format());
|
||||
|
||||
if (src.depth() == 1) {
|
||||
qWarning() << "image depth 1 not supported";
|
||||
return QImage();
|
||||
}
|
||||
|
||||
int x;
|
||||
int y;
|
||||
if (src.depth() == 32) {
|
||||
QRgb *l1;
|
||||
QRgb *l2;
|
||||
for (y = 0; y < h; ++y) {
|
||||
l1 = (QRgb *)src.scanLine(y);
|
||||
l2 = (QRgb *)dst.scanLine(y * 2);
|
||||
for (x = 0; x < w; ++x) {
|
||||
l2[x * 2] = l2[x * 2 + 1] = l1[x];
|
||||
}
|
||||
memcpy(dst.scanLine(y * 2 + 1), l2, dst.bytesPerLine());
|
||||
}
|
||||
} else {
|
||||
for (x = 0; x < src.colorCount(); ++x) {
|
||||
dst.setColor(x, src.color(x));
|
||||
}
|
||||
|
||||
const unsigned char *l1;
|
||||
unsigned char *l2;
|
||||
for (y = 0; y < h; ++y) {
|
||||
l1 = src.scanLine(y);
|
||||
l2 = dst.scanLine(y * 2);
|
||||
for (x = 0; x < w; ++x) {
|
||||
l2[x * 2] = l1[x];
|
||||
l2[x * 2 + 1] = l1[x];
|
||||
}
|
||||
memcpy(dst.scanLine(y * 2 + 1), l2, dst.bytesPerLine());
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
void KIconEffect::overlay(QImage &src, QImage &overlay)
|
||||
{
|
||||
if (src.depth() != overlay.depth()) {
|
||||
qWarning() << "Image depth src (" << src.depth() << ") != overlay "
|
||||
<< "(" << overlay.depth() << ")!";
|
||||
return;
|
||||
}
|
||||
if (src.size() != overlay.size()) {
|
||||
qWarning() << "Image size src != overlay";
|
||||
return;
|
||||
}
|
||||
if (src.format() == QImage::Format_ARGB32_Premultiplied) {
|
||||
src.convertTo(QImage::Format_ARGB32);
|
||||
}
|
||||
|
||||
if (overlay.format() == QImage::Format_RGB32) {
|
||||
qWarning() << "Overlay doesn't have alpha buffer!";
|
||||
return;
|
||||
} else if (overlay.format() == QImage::Format_ARGB32_Premultiplied) {
|
||||
overlay.convertTo(QImage::Format_ARGB32);
|
||||
}
|
||||
|
||||
int i;
|
||||
int j;
|
||||
|
||||
// We don't do 1 bpp
|
||||
|
||||
if (src.depth() == 1) {
|
||||
qWarning() << "1bpp not supported!";
|
||||
return;
|
||||
}
|
||||
|
||||
// Overlay at 8 bpp doesn't use alpha blending
|
||||
|
||||
if (src.depth() == 8) {
|
||||
if (src.colorCount() + overlay.colorCount() > 255) {
|
||||
qWarning() << "Too many colors in src + overlay!";
|
||||
return;
|
||||
}
|
||||
|
||||
// Find transparent pixel in overlay
|
||||
int trans;
|
||||
for (trans = 0; trans < overlay.colorCount(); trans++) {
|
||||
if (qAlpha(overlay.color(trans)) == 0) {
|
||||
qWarning() << "transparent pixel found at " << trans;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (trans == overlay.colorCount()) {
|
||||
qWarning() << "transparent pixel not found!";
|
||||
return;
|
||||
}
|
||||
|
||||
// Merge color tables
|
||||
int nc = src.colorCount();
|
||||
src.setColorCount(nc + overlay.colorCount());
|
||||
for (i = 0; i < overlay.colorCount(); ++i) {
|
||||
src.setColor(nc + i, overlay.color(i));
|
||||
}
|
||||
|
||||
// Overwrite nontransparent pixels.
|
||||
unsigned char *oline;
|
||||
unsigned char *sline;
|
||||
for (i = 0; i < src.height(); ++i) {
|
||||
oline = overlay.scanLine(i);
|
||||
sline = src.scanLine(i);
|
||||
for (j = 0; j < src.width(); ++j) {
|
||||
if (oline[j] != trans) {
|
||||
sline[j] = oline[j] + nc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Overlay at 32 bpp does use alpha blending
|
||||
|
||||
if (src.depth() == 32) {
|
||||
QRgb *oline;
|
||||
QRgb *sline;
|
||||
int r1;
|
||||
int g1;
|
||||
int b1;
|
||||
int a1;
|
||||
int r2;
|
||||
int g2;
|
||||
int b2;
|
||||
int a2;
|
||||
|
||||
for (i = 0; i < src.height(); ++i) {
|
||||
oline = (QRgb *)overlay.scanLine(i);
|
||||
sline = (QRgb *)src.scanLine(i);
|
||||
|
||||
for (j = 0; j < src.width(); ++j) {
|
||||
r1 = qRed(oline[j]);
|
||||
g1 = qGreen(oline[j]);
|
||||
b1 = qBlue(oline[j]);
|
||||
a1 = qAlpha(oline[j]);
|
||||
|
||||
r2 = qRed(sline[j]);
|
||||
g2 = qGreen(sline[j]);
|
||||
b2 = qBlue(sline[j]);
|
||||
a2 = qAlpha(sline[j]);
|
||||
|
||||
r2 = (a1 * r1 + (0xff - a1) * r2) >> 8;
|
||||
g2 = (a1 * g1 + (0xff - a1) * g2) >> 8;
|
||||
b2 = (a1 * b1 + (0xff - a1) * b2) >> 8;
|
||||
a2 = qMax(a1, a2);
|
||||
|
||||
sline[j] = qRgba(r2, g2, b2, a2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KIconEffect::toDisabled(QImage &image)
|
||||
{
|
||||
KIconEffect::toGray(image, 1);
|
||||
KIconEffect::semiTransparent(image);
|
||||
}
|
||||
|
||||
void KIconEffect::toDisabled(QPixmap &pixmap)
|
||||
{
|
||||
QImage img = pixmap.toImage();
|
||||
toDisabled(img);
|
||||
pixmap = QPixmap::fromImage(img);
|
||||
}
|
||||
|
||||
void KIconEffect::toActive(QImage &image)
|
||||
{
|
||||
KIconEffect::toGamma(image, 0.7);
|
||||
}
|
||||
|
||||
void KIconEffect::toActive(QPixmap &pixmap)
|
||||
{
|
||||
QImage img = pixmap.toImage();
|
||||
KIconEffect::toGamma(img, 0.7);
|
||||
pixmap = QPixmap::fromImage(img);
|
||||
}
|
||||
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
|
||||
This file is part of the KDE project, module kdecore.
|
||||
SPDX-FileCopyrightText: 2000 Geert Jansen <jansen@kde.org>
|
||||
SPDX-FileCopyrightText: 2007 Daniel M. Duley <daniel.duley@verizon.net>
|
||||
|
||||
with minor additions and based on ideas from
|
||||
SPDX-FileContributor: Torsten Rahn <torsten@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-only
|
||||
*/
|
||||
|
||||
#ifndef KICONEFFECT_H
|
||||
#define KICONEFFECT_H
|
||||
|
||||
#include <kiconthemes_export.h>
|
||||
|
||||
#include <QColor>
|
||||
#include <QImage>
|
||||
#include <QPixmap>
|
||||
|
||||
#include <memory>
|
||||
|
||||
class KIconEffectPrivate;
|
||||
|
||||
/**
|
||||
* @class KIconEffect kiconeffect.h KIconEffect
|
||||
*
|
||||
* Applies effects to icons.
|
||||
*
|
||||
* This class applies effects to icons depending on their state and
|
||||
* group. For example, it can be used to make all disabled icons
|
||||
* in a toolbar gray.
|
||||
*
|
||||
* \image html kiconeffect-apply.png "Various Effects applied to an image"
|
||||
*
|
||||
* @see QIcon::fromTheme
|
||||
*/
|
||||
class KICONTHEMES_EXPORT KIconEffect
|
||||
{
|
||||
public:
|
||||
#if KICONTHEMES_ENABLE_DEPRECATED_SINCE(6, 5)
|
||||
/**
|
||||
* Create a new KIconEffect.
|
||||
* You will most likely never have to use this to create a new KIconEffect
|
||||
* yourself, as you can use the KIconEffect provided by the global KIconLoader
|
||||
* (which itself is accessible by KIconLoader::global()) through its
|
||||
* iconEffect() function.
|
||||
*
|
||||
* @deprecated since 6.5, use the static API
|
||||
*
|
||||
*/
|
||||
KICONTHEMES_DEPRECATED_VERSION(6, 5, "Use static API")
|
||||
KIconEffect();
|
||||
#endif
|
||||
~KIconEffect();
|
||||
|
||||
KIconEffect(const KIconEffect &) = delete;
|
||||
KIconEffect &operator=(const KIconEffect &) = delete;
|
||||
|
||||
#if KICONTHEMES_ENABLE_DEPRECATED_SINCE(6, 5)
|
||||
/**
|
||||
* This is the enumeration of all possible icon effects.
|
||||
* Note that 'LastEffect' is no valid icon effect but only
|
||||
* used internally to check for invalid icon effects.
|
||||
*
|
||||
* @li NoEffect: Do not apply any icon effect
|
||||
* @li ToGray: Tints the icon gray
|
||||
* @li Colorize: Tints the icon with a specific color
|
||||
* @li ToGamma: Change the gamma value of the icon
|
||||
* @li DeSaturate: Reduce the saturation of the icon
|
||||
* @li ToMonochrome: Produces a monochrome icon
|
||||
*
|
||||
* @deprecated since 6.5, use the static API
|
||||
*/
|
||||
KICONTHEMES_DEPRECATED_VERSION(6, 5, "Use static API")
|
||||
enum Effects {
|
||||
NoEffect,
|
||||
ToGray,
|
||||
Colorize,
|
||||
ToGamma,
|
||||
DeSaturate,
|
||||
ToMonochrome,
|
||||
LastEffect,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if KICONTHEMES_ENABLE_DEPRECATED_SINCE(6, 5)
|
||||
/**
|
||||
* Rereads configuration.
|
||||
*
|
||||
* @deprecated since 6.5, use the static API
|
||||
*/
|
||||
KICONTHEMES_DEPRECATED_VERSION(6, 5, "Use static API")
|
||||
void init();
|
||||
#endif
|
||||
|
||||
#if KICONTHEMES_ENABLE_DEPRECATED_SINCE(6, 5)
|
||||
/**
|
||||
* Tests whether an effect has been configured for the given icon group.
|
||||
* @param group the group to check, see KIconLoader::Group
|
||||
* @param state the state to check, see KIconLoader::States
|
||||
* @returns true if an effect is configured for the given @p group
|
||||
* in @p state, otherwise false.
|
||||
* @see KIconLoader::Group
|
||||
* KIconLoader::States
|
||||
*
|
||||
* @deprecated since 6.5, use the static API
|
||||
*/
|
||||
KICONTHEMES_DEPRECATED_VERSION(6, 5, "Use static API")
|
||||
bool hasEffect(int group, int state) const;
|
||||
#endif
|
||||
|
||||
#if KICONTHEMES_ENABLE_DEPRECATED_SINCE(6, 5)
|
||||
/**
|
||||
* Returns a fingerprint for the effect by encoding
|
||||
* the given @p group and @p state into a QString. This
|
||||
* is useful for caching.
|
||||
* @param group the group, see KIconLoader::Group
|
||||
* @param state the state, see KIconLoader::States
|
||||
* @return the fingerprint of the given @p group+@p state
|
||||
*
|
||||
* @deprecated since 6.5, use the static API
|
||||
*/
|
||||
KICONTHEMES_DEPRECATED_VERSION(6, 5, "Use static API")
|
||||
QString fingerprint(int group, int state) const;
|
||||
#endif
|
||||
|
||||
#if KICONTHEMES_ENABLE_DEPRECATED_SINCE(6, 5)
|
||||
/**
|
||||
* Applies an effect to an image. The effect to apply depends on the
|
||||
* @p group and @p state parameters, and is configured by the user.
|
||||
* @param src The image.
|
||||
* @param group The group for the icon, see KIconLoader::Group
|
||||
* @param state The icon's state, see KIconLoader::States
|
||||
* @return An image with the effect applied.
|
||||
*
|
||||
* @deprecated since 6.5, use the static API
|
||||
*/
|
||||
KICONTHEMES_DEPRECATED_VERSION(6, 5, "Use static API")
|
||||
QImage apply(const QImage &src, int group, int state) const;
|
||||
#endif
|
||||
|
||||
#if KICONTHEMES_ENABLE_DEPRECATED_SINCE(6, 5)
|
||||
/**
|
||||
* Applies an effect to an image.
|
||||
* @param src The image.
|
||||
* @param effect The effect to apply, one of KIconEffect::Effects.
|
||||
* @param value Strength of the effect. 0 <= @p value <= 1.
|
||||
* @param rgb Color parameter for effects that need one.
|
||||
* @param trans Add Transparency if trans = true.
|
||||
* @return An image with the effect applied.
|
||||
*
|
||||
* @deprecated since 6.5, use the static API
|
||||
*/
|
||||
KICONTHEMES_DEPRECATED_VERSION(6, 5, "Use static API")
|
||||
QImage apply(const QImage &src, int effect, float value, const QColor &rgb, bool trans) const;
|
||||
QImage apply(const QImage &src, int effect, float value, const QColor &rgb, const QColor &rgb2, bool trans) const;
|
||||
#endif
|
||||
|
||||
#if KICONTHEMES_ENABLE_DEPRECATED_SINCE(6, 5)
|
||||
/**
|
||||
* Applies an effect to a pixmap.
|
||||
* @param src The pixmap.
|
||||
* @param group The group for the icon, see KIconLoader::Group
|
||||
* @param state The icon's state, see KIconLoader::States
|
||||
* @return A pixmap with the effect applied.
|
||||
*
|
||||
* @deprecated since 6.5, use the static API
|
||||
*/
|
||||
KICONTHEMES_DEPRECATED_VERSION(6, 5, "Use static API")
|
||||
QPixmap apply(const QPixmap &src, int group, int state) const;
|
||||
#endif
|
||||
|
||||
#if KICONTHEMES_ENABLE_DEPRECATED_SINCE(6, 5)
|
||||
/**
|
||||
* Applies an effect to a pixmap.
|
||||
* @param src The pixmap.
|
||||
* @param effect The effect to apply, one of KIconEffect::Effects.
|
||||
* @param value Strength of the effect. 0 <= @p value <= 1.
|
||||
* @param rgb Color parameter for effects that need one.
|
||||
* @param trans Add Transparency if trans = true.
|
||||
* @return A pixmap with the effect applied.
|
||||
*
|
||||
* @deprecated since 6.5, use the static API
|
||||
*/
|
||||
KICONTHEMES_DEPRECATED_VERSION(6, 5, "Use static API")
|
||||
QPixmap apply(const QPixmap &src, int effect, float value, const QColor &rgb, bool trans) const;
|
||||
KICONTHEMES_DEPRECATED_VERSION(6, 5, "Use static API")
|
||||
QPixmap apply(const QPixmap &src, int effect, float value, const QColor &rgb, const QColor &rgb2, bool trans) const;
|
||||
#endif
|
||||
|
||||
#if KICONTHEMES_ENABLE_DEPRECATED_SINCE(6, 5)
|
||||
/**
|
||||
* Returns an image twice as large, consisting of 2x2 pixels.
|
||||
* @param src the image.
|
||||
* @return the scaled image.
|
||||
*
|
||||
* @deprecated since 6.5, use the static API
|
||||
*/
|
||||
KICONTHEMES_DEPRECATED_VERSION(6, 5, "Use static API")
|
||||
QImage doublePixels(const QImage &src) const;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Tints an image gray.
|
||||
*
|
||||
* @param image The image
|
||||
* @param value Strength of the effect. 0 <= @p value <= 1
|
||||
*/
|
||||
static void toGray(QImage &image, float value);
|
||||
|
||||
/**
|
||||
* Colorizes an image with a specific color.
|
||||
*
|
||||
* @param image The image
|
||||
* @param col The color with which the @p image is tinted
|
||||
* @param value Strength of the effect. 0 <= @p value <= 1
|
||||
*/
|
||||
static void colorize(QImage &image, const QColor &col, float value);
|
||||
|
||||
/**
|
||||
* Produces a monochrome icon with a given foreground and background color
|
||||
*
|
||||
* @param image The image
|
||||
* @param white The color with which the white parts of @p image are painted
|
||||
* @param black The color with which the black parts of @p image are painted
|
||||
* @param value Strength of the effect. 0 <= @p value <= 1
|
||||
*/
|
||||
static void toMonochrome(QImage &image, const QColor &black, const QColor &white, float value);
|
||||
|
||||
/**
|
||||
* Desaturates an image.
|
||||
*
|
||||
* @param image The image
|
||||
* @param value Strength of the effect. 0 <= @p value <= 1
|
||||
*/
|
||||
static void deSaturate(QImage &image, float value);
|
||||
|
||||
/**
|
||||
* Changes the gamma value of an image.
|
||||
*
|
||||
* @param image The image
|
||||
* @param value Strength of the effect. 0 <= @p value <= 1
|
||||
*/
|
||||
static void toGamma(QImage &image, float value);
|
||||
|
||||
/**
|
||||
* Renders an image semi-transparent.
|
||||
*
|
||||
* @param image The image
|
||||
*/
|
||||
static void semiTransparent(QImage &image);
|
||||
|
||||
/**
|
||||
* Renders a pixmap semi-transparent.
|
||||
*
|
||||
* @param pixmap The pixmap
|
||||
*/
|
||||
static void semiTransparent(QPixmap &pixmap);
|
||||
|
||||
/**
|
||||
* Overlays an image with an other image.
|
||||
*
|
||||
* @param src The image
|
||||
* @param overlay The image to overlay @p src with
|
||||
*/
|
||||
static void overlay(QImage &src, QImage &overlay);
|
||||
|
||||
/**
|
||||
* Applies a disabled effect
|
||||
*
|
||||
* @param image The image
|
||||
*
|
||||
* @since 6.5
|
||||
*/
|
||||
static void toDisabled(QImage &image);
|
||||
|
||||
/**
|
||||
* Applies a disabled effect
|
||||
*
|
||||
* @param pixmap The image
|
||||
*
|
||||
* @since 6.5
|
||||
*/
|
||||
static void toDisabled(QPixmap &pixmap);
|
||||
|
||||
/**
|
||||
* Applies an effect for an icon that is in an 'active' state
|
||||
*
|
||||
* @param image The image
|
||||
*
|
||||
* @since 6.5
|
||||
*/
|
||||
static void toActive(QImage &image);
|
||||
|
||||
/**
|
||||
* Applies an effect for an icon that is in an 'active' state
|
||||
*
|
||||
* @param pixmap The image
|
||||
*
|
||||
* @since 6.5
|
||||
*/
|
||||
static void toActive(QPixmap &pixmap);
|
||||
|
||||
private:
|
||||
std::unique_ptr<KIconEffectPrivate> const d;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2006 Hamish Rodda <rodda@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-only
|
||||
*/
|
||||
|
||||
#include "kiconengine.h"
|
||||
|
||||
#include "kiconloader_p.h"
|
||||
#include <kiconloader.h>
|
||||
|
||||
#include "kiconcolors.h"
|
||||
#include <KIconTheme>
|
||||
#include <QFileInfo>
|
||||
#include <QLibraryInfo>
|
||||
#include <QPainter>
|
||||
#include <qscopeguard.h>
|
||||
|
||||
class KIconEnginePrivate
|
||||
{
|
||||
public:
|
||||
QPointer<KIconLoader> mIconLoader;
|
||||
bool mCustomColors = false;
|
||||
KIconColors mColors;
|
||||
QString mActualIconName;
|
||||
};
|
||||
|
||||
KIconEngine::KIconEngine(const QString &iconName, KIconLoader *iconLoader, const QStringList &overlays)
|
||||
: mIconName(iconName)
|
||||
, mOverlays(overlays)
|
||||
, d(new KIconEnginePrivate{iconLoader, false, {}, {}})
|
||||
{
|
||||
}
|
||||
|
||||
KIconEngine::KIconEngine(const QString &iconName, KIconLoader *iconLoader)
|
||||
: mIconName(iconName)
|
||||
, d(new KIconEnginePrivate{iconLoader, false, {}, {}})
|
||||
{
|
||||
}
|
||||
|
||||
KIconEngine::KIconEngine(const QString &iconName, const KIconColors &colors, KIconLoader *iconLoader)
|
||||
: mIconName(iconName)
|
||||
, d(new KIconEnginePrivate{iconLoader, true, colors, {}})
|
||||
{
|
||||
}
|
||||
|
||||
KIconEngine::KIconEngine(const QString &iconName, const KIconColors &colors, KIconLoader *iconLoader, const QStringList &overlays)
|
||||
: mIconName(iconName)
|
||||
, mOverlays(overlays)
|
||||
, d(new KIconEnginePrivate{iconLoader, true, colors, {}})
|
||||
{
|
||||
}
|
||||
|
||||
KIconEngine::~KIconEngine()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
static inline int qIconModeToKIconState(QIcon::Mode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case QIcon::Normal:
|
||||
return KIconLoader::DefaultState;
|
||||
case QIcon::Active:
|
||||
return KIconLoader::ActiveState;
|
||||
case QIcon::Disabled:
|
||||
return KIconLoader::DisabledState;
|
||||
case QIcon::Selected:
|
||||
return KIconLoader::SelectedState;
|
||||
default:
|
||||
return KIconLoader::DefaultState;
|
||||
}
|
||||
}
|
||||
|
||||
QSize KIconEngine::actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state)
|
||||
{
|
||||
return QIconEngine::actualSize(size, mode, state);
|
||||
}
|
||||
|
||||
void KIconEngine::paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state)
|
||||
{
|
||||
if (!d->mIconLoader) {
|
||||
return;
|
||||
}
|
||||
|
||||
const qreal dpr = painter->device()->devicePixelRatioF();
|
||||
const QPixmap pix = createPixmap(rect.size(), dpr, mode, state);
|
||||
painter->drawPixmap(rect, pix);
|
||||
}
|
||||
|
||||
QPixmap KIconEngine::createPixmap(const QSize &logicalSize, qreal scale, QIcon::Mode mode, QIcon::State state)
|
||||
{
|
||||
Q_UNUSED(state)
|
||||
|
||||
if (scale < 1) {
|
||||
scale = 1;
|
||||
}
|
||||
|
||||
if (logicalSize.isEmpty()) {
|
||||
return QPixmap();
|
||||
}
|
||||
|
||||
if (!d->mIconLoader) {
|
||||
QPixmap pm(logicalSize * scale);
|
||||
pm.setDevicePixelRatio(scale);
|
||||
pm.fill(Qt::transparent);
|
||||
return pm;
|
||||
}
|
||||
|
||||
QString iconPath;
|
||||
|
||||
const int kstate = qIconModeToKIconState(mode);
|
||||
QPixmap pix = d->mIconLoader->loadScaledIcon(mIconName,
|
||||
KIconLoader::Desktop,
|
||||
scale,
|
||||
logicalSize,
|
||||
kstate,
|
||||
mOverlays,
|
||||
&iconPath,
|
||||
false,
|
||||
d->mCustomColors ? std::make_optional(d->mColors) : std::nullopt);
|
||||
|
||||
if (!iconPath.isEmpty() && !d->mActualIconName.isEmpty()) {
|
||||
d->mActualIconName = QFileInfo(iconPath).completeBaseName();
|
||||
}
|
||||
|
||||
if (pix.size() == logicalSize * scale) {
|
||||
return pix;
|
||||
}
|
||||
|
||||
QPixmap pix2(logicalSize * scale);
|
||||
pix2.setDevicePixelRatio(scale);
|
||||
pix2.fill(QColor(0, 0, 0, 0));
|
||||
|
||||
QPainter painter(&pix2);
|
||||
painter.setRenderHint(QPainter::SmoothPixmapTransform);
|
||||
const QSizeF targetSize = pix.size().scaled(logicalSize, Qt::KeepAspectRatio);
|
||||
QRectF targetRect({0, 0}, targetSize);
|
||||
targetRect.moveCenter(QRectF(pix2.rect()).center() / scale);
|
||||
painter.drawPixmap(targetRect, pix, pix.rect());
|
||||
|
||||
return pix2;
|
||||
}
|
||||
|
||||
QPixmap KIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state)
|
||||
{
|
||||
return createPixmap(size, 1 /*scale*/, mode, state);
|
||||
}
|
||||
|
||||
QPixmap KIconEngine::scaledPixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale)
|
||||
{
|
||||
// Since https://codereview.qt-project.org/c/qt/qtbase/+/563553 size is in logical pixels
|
||||
if (QLibraryInfo::version() >= QVersionNumber(6, 8, 0)) {
|
||||
return createPixmap(size, scale, mode, state);
|
||||
} else {
|
||||
return createPixmap(size / scale, scale, mode, state);
|
||||
}
|
||||
}
|
||||
|
||||
QString KIconEngine::iconName()
|
||||
{
|
||||
if (!d->mActualIconName.isEmpty()) {
|
||||
return d->mActualIconName;
|
||||
}
|
||||
|
||||
if (!d->mIconLoader) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
const QString iconPath = KIconLoaderPrivate::get(d->mIconLoader)->preferredIconPath(mIconName);
|
||||
if (iconPath.isEmpty()) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
d->mActualIconName = QFileInfo(iconPath).completeBaseName();
|
||||
return d->mActualIconName;
|
||||
}
|
||||
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QList<QSize>,
|
||||
sSizes,
|
||||
(QList<QSize>() << QSize(16, 16) << QSize(22, 22) << QSize(32, 32) << QSize(48, 48) << QSize(64, 64) << QSize(128, 128)
|
||||
<< QSize(256, 256)))
|
||||
|
||||
QList<QSize> KIconEngine::availableSizes(QIcon::Mode mode, QIcon::State state)
|
||||
{
|
||||
Q_UNUSED(mode);
|
||||
Q_UNUSED(state);
|
||||
|
||||
if (!d->mIconLoader) {
|
||||
return QList<QSize>();
|
||||
}
|
||||
|
||||
const bool found = d->mIconLoader->hasIcon(mIconName);
|
||||
return found ? *sSizes : QList<QSize>();
|
||||
}
|
||||
|
||||
QString KIconEngine::key() const
|
||||
{
|
||||
return QStringLiteral("KIconEngine");
|
||||
}
|
||||
|
||||
QIconEngine *KIconEngine::clone() const
|
||||
{
|
||||
return new KIconEngine(mIconName, d->mIconLoader, mOverlays);
|
||||
}
|
||||
|
||||
bool KIconEngine::read(QDataStream &in)
|
||||
{
|
||||
in >> mIconName >> mOverlays;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KIconEngine::write(QDataStream &out) const
|
||||
{
|
||||
out << mIconName << mOverlays;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KIconEngine::isNull()
|
||||
{
|
||||
return !d->mIconLoader || !d->mIconLoader->hasIcon(mIconName);
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
This file is part of the KDE libraries
|
||||
SPDX-FileCopyrightText: 2006 Hamish Rodda <rodda@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-only
|
||||
*/
|
||||
|
||||
#ifndef KICONENGINE_H
|
||||
#define KICONENGINE_H
|
||||
|
||||
#include "kiconthemes_export.h"
|
||||
#include <QIconEngine>
|
||||
#include <QPointer>
|
||||
|
||||
class KIconColors;
|
||||
class KIconLoader;
|
||||
class KIconEnginePrivate;
|
||||
|
||||
/**
|
||||
* @class KIconEngine kiconengine.h KIconEngine
|
||||
*
|
||||
* \short A class to provide rendering of KDE icons.
|
||||
*
|
||||
* This is mostly used to provide Qt's icon loading in plasma-integration
|
||||
*
|
||||
* Application developers should use QIcon::fromTheme instead of using it directly.
|
||||
*/
|
||||
class KICONTHEMES_EXPORT KIconEngine : public QIconEngine // exported for plasma-integration
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructs an icon engine for a named icon.
|
||||
*
|
||||
* @param iconName the name of the icon to load
|
||||
* @param iconLoader The icon loader that this engine is to use.
|
||||
* @param overlays Add one or more overlays to the icon. See KIconLoader::Overlays.
|
||||
*
|
||||
* @sa KIconLoader
|
||||
*/
|
||||
KIconEngine(const QString &iconName, KIconLoader *iconLoader, const QStringList &overlays);
|
||||
|
||||
/**
|
||||
* \overload
|
||||
*/
|
||||
KIconEngine(const QString &iconName, KIconLoader *iconLoader);
|
||||
|
||||
/**
|
||||
* Constructs an icon engine for a KDE named icon with a specific palette.
|
||||
*
|
||||
* @param iconName the name of the icon to load
|
||||
* @param colors defines the colors we want to be applied on this icon
|
||||
* @param iconLoader The KDE icon loader that this engine is to use.
|
||||
*/
|
||||
KIconEngine(const QString &iconName, const KIconColors &colors, KIconLoader *iconLoader);
|
||||
|
||||
/**
|
||||
* Constructs an icon engine for a KDE named icon with a specific palette and overlays.
|
||||
*
|
||||
* @param iconName the name of the icon to load
|
||||
* @param colors defines the colors we want to be applied on this icon
|
||||
* @param iconLoader The KDE icon loader that this engine is to use.
|
||||
* @param overlays Add one or more overlays to the icon. See KIconLoader::Overlays.
|
||||
*
|
||||
* @since 6.1
|
||||
*/
|
||||
KIconEngine(const QString &iconName, const KIconColors &colors, KIconLoader *iconLoader, const QStringList &overlays);
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~KIconEngine() override;
|
||||
|
||||
/// Reimplementation
|
||||
QSize actualSize(const QSize &size, QIcon::Mode mode, QIcon::State state) override;
|
||||
/// Reimplementation
|
||||
void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) override;
|
||||
/// Reimplementation
|
||||
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override;
|
||||
QPixmap scaledPixmap(const QSize &size, QIcon::Mode mode, QIcon::State state, qreal scale) override;
|
||||
|
||||
/// Reimplementation
|
||||
QString iconName() override;
|
||||
/// Reimplementation
|
||||
QList<QSize> availableSizes(QIcon::Mode mode, QIcon::State state) override;
|
||||
|
||||
bool isNull() override;
|
||||
|
||||
QString key() const override;
|
||||
QIconEngine *clone() const override;
|
||||
bool read(QDataStream &in) override;
|
||||
bool write(QDataStream &out) const override;
|
||||
|
||||
private:
|
||||
// TODO KF6: move those into the d-pointer
|
||||
QPixmap createPixmap(const QSize &size, qreal scale, QIcon::Mode mode, QIcon::State state);
|
||||
QString mIconName;
|
||||
QStringList mOverlays;
|
||||
KIconEnginePrivate *const d;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
kiconengineplugin.cpp: Qt plugin providing the ability to create a KIconEngine
|
||||
|
||||
This file is part of the KDE project, module kdeui.
|
||||
SPDX-FileCopyrightText: 2018 Fabian Vogt <fabian@ritter-vogt.de>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-only
|
||||
*/
|
||||
|
||||
#include <QIconEnginePlugin>
|
||||
|
||||
#include <KIconEngine>
|
||||
#include <KIconLoader>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class KIconEnginePlugin : public QIconEnginePlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QIconEngineFactoryInterface" FILE "kiconengineplugin.json")
|
||||
|
||||
public:
|
||||
QIconEngine *create(const QString &file) override
|
||||
{
|
||||
return new KIconEngine(file, KIconLoader::global());
|
||||
}
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#include "kiconengineplugin.moc"
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"Keys": [ "KIconEngine", "svg", "svgz", "svg.gz" ]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,708 @@
|
||||
/*
|
||||
|
||||
This file is part of the KDE project, module kdecore.
|
||||
SPDX-FileCopyrightText: 2000 Geert Jansen <jansen@kde.org>
|
||||
SPDX-FileCopyrightText: 2000 Antonio Larrosa <larrosa@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-only
|
||||
*/
|
||||
|
||||
#ifndef KICONLOADER_H
|
||||
#define KICONLOADER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QSize>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <memory>
|
||||
|
||||
#if __has_include(<optional>) && __cplusplus >= 201703L
|
||||
#include <optional>
|
||||
#endif
|
||||
|
||||
#include <kiconthemes_export.h>
|
||||
|
||||
class QIcon;
|
||||
class QMovie;
|
||||
class QPixmap;
|
||||
|
||||
class KIconColors;
|
||||
class KIconLoaderPrivate;
|
||||
class KIconEffect;
|
||||
class KIconTheme;
|
||||
|
||||
/**
|
||||
* @class KIconLoader kiconloader.h KIconLoader
|
||||
*
|
||||
* Iconloader for KDE.
|
||||
*
|
||||
* @note For most icon loading use cases perfer using QIcon::fromTheme
|
||||
*
|
||||
* KIconLoader will load the current icon theme and all its base themes.
|
||||
* Icons will be searched in any of these themes. Additionally, it caches
|
||||
* icons and applies effects according to the user's preferences.
|
||||
*
|
||||
* In KDE, it is encouraged to load icons by "Group". An icon group is a
|
||||
* location on the screen where icons are being used. Standard groups are:
|
||||
* Desktop, Toolbar, MainToolbar, Small and Panel. Each group can have some
|
||||
* centrally-configured effects applied to its icons. This makes it possible
|
||||
* to offer a consistent icon look in all KDE applications.
|
||||
*
|
||||
* The standard groups are defined below.
|
||||
*
|
||||
* @li KIconLoader::Desktop: Icons in the iconview of konqueror, kdesktop and similar apps.
|
||||
* @li KIconLoader::Toolbar: Icons in toolbars.
|
||||
* @li KIconLoader::MainToolbar: Icons in the main toolbars.
|
||||
* @li KIconLoader::Small: Various small (typical 16x16) places: titlebars, listviews
|
||||
* and menu entries.
|
||||
* @li KIconLoader::Panel: Icons in kicker's panel
|
||||
*
|
||||
* The icons are stored on disk in an icon theme or in a standalone
|
||||
* directory. The icon theme directories contain multiple sizes and/or
|
||||
* depths for the same icon. The iconloader will load the correct one based
|
||||
* on the icon group and the current theme. Icon themes are stored globally
|
||||
* in share/icons, or, application specific in share/apps/$appdir/icons.
|
||||
*
|
||||
* The standalone directories contain just one version of an icon. The
|
||||
* directories that are searched are: $appdir/pics and $appdir/toolbar.
|
||||
* Icons in these directories can be loaded by using the special group
|
||||
* "User".
|
||||
*
|
||||
*/
|
||||
class KICONTHEMES_EXPORT KIconLoader : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/**
|
||||
* Defines the context of the icon.
|
||||
*/
|
||||
enum Context {
|
||||
Any, ///< Some icon with unknown purpose.
|
||||
Action, ///< An action icon (e.g. 'save', 'print').
|
||||
Application, ///< An icon that represents an application.
|
||||
Device, ///< An icon that represents a device.
|
||||
MimeType, ///< An icon that represents a mime type (or file type).
|
||||
Animation, ///< An icon that is animated.
|
||||
Category, ///< An icon that represents a category.
|
||||
Emblem, ///< An icon that adds information to an existing icon.
|
||||
Emote, ///< An icon that expresses an emotion.
|
||||
International, ///< An icon that represents a country's flag.
|
||||
Place, ///< An icon that represents a location (e.g. 'home', 'trash').
|
||||
StatusIcon, ///< An icon that represents an event.
|
||||
};
|
||||
Q_ENUM(Context)
|
||||
|
||||
/**
|
||||
* The type of the icon.
|
||||
*/
|
||||
enum Type {
|
||||
Fixed, ///< Fixed-size icon.
|
||||
Scalable, ///< Scalable-size icon.
|
||||
Threshold, ///< A threshold icon.
|
||||
};
|
||||
Q_ENUM(Type)
|
||||
|
||||
/**
|
||||
* The type of a match.
|
||||
*/
|
||||
enum MatchType {
|
||||
MatchExact, ///< Only try to find an exact match.
|
||||
MatchBest, ///< Take the best match if there is no exact match.
|
||||
MatchBestOrGreaterSize, ///< Take the best match or the match with a greater size if there is no exact match. @since 6.0
|
||||
};
|
||||
Q_ENUM(MatchType)
|
||||
|
||||
/**
|
||||
* The group of the icon.
|
||||
*/
|
||||
enum Group {
|
||||
/// No group
|
||||
NoGroup = -1,
|
||||
/// Desktop icons
|
||||
Desktop = 0,
|
||||
/// First group
|
||||
FirstGroup = 0,
|
||||
/// Toolbar icons
|
||||
Toolbar,
|
||||
/// Main toolbar icons
|
||||
MainToolbar,
|
||||
/// Small icons, e.g. for buttons
|
||||
Small,
|
||||
/// Panel (Plasma Taskbar) icons
|
||||
// TODO KF6: remove this (See https://phabricator.kde.org/T14340)
|
||||
Panel,
|
||||
/// Icons for use in dialog titles, page lists, etc
|
||||
Dialog,
|
||||
/// Last group
|
||||
LastGroup,
|
||||
/// User icons
|
||||
User,
|
||||
};
|
||||
Q_ENUM(Group)
|
||||
|
||||
/**
|
||||
* These are the standard sizes for icons.
|
||||
*/
|
||||
enum StdSizes {
|
||||
/// small icons for menu entries
|
||||
SizeSmall = 16,
|
||||
/// slightly larger small icons for toolbars, panels, etc
|
||||
SizeSmallMedium = 22,
|
||||
/// medium sized icons for the desktop
|
||||
SizeMedium = 32,
|
||||
/// large sized icons for the panel
|
||||
SizeLarge = 48,
|
||||
/// huge sized icons for iconviews
|
||||
SizeHuge = 64,
|
||||
/// enormous sized icons for iconviews
|
||||
SizeEnormous = 128,
|
||||
};
|
||||
Q_ENUM(StdSizes)
|
||||
|
||||
/**
|
||||
* Defines the possible states of an icon.
|
||||
*/
|
||||
enum States {
|
||||
DefaultState, ///< The default state.
|
||||
ActiveState, ///< Icon is active.
|
||||
DisabledState, ///< Icon is disabled.
|
||||
SelectedState, ///< Icon is selected. @since 5.22
|
||||
LastState, ///< Last state (last constant)
|
||||
};
|
||||
Q_ENUM(States)
|
||||
|
||||
/**
|
||||
* Constructs an iconloader.
|
||||
* @param appname Add the data directories of this application to the
|
||||
* icon search path for the "User" group. The default argument adds the
|
||||
* directories of the current application.
|
||||
* @param extraSearchPaths additional search paths, either absolute or relative to GenericDataLocation
|
||||
*
|
||||
* Usually, you use the default iconloader, which can be accessed via
|
||||
* KIconLoader::global(), so you hardly ever have to create an
|
||||
* iconloader object yourself. That one is the application's iconloader.
|
||||
*/
|
||||
explicit KIconLoader(const QString &appname = QString(), const QStringList &extraSearchPaths = QStringList(), QObject *parent = nullptr);
|
||||
|
||||
/**
|
||||
* Cleanup
|
||||
*/
|
||||
~KIconLoader() override;
|
||||
|
||||
/**
|
||||
* Returns the global icon loader initialized with the application name.
|
||||
* @return global icon loader
|
||||
*/
|
||||
static KIconLoader *global();
|
||||
|
||||
/**
|
||||
* Adds @p appname to the list of application specific directories with @p themeBaseDir as its base directory.
|
||||
* Assume the icons are in /home/user/app/icons/hicolor/48x48/my_app.png, the base directory would be
|
||||
* /home/user/app/icons; KIconLoader automatically searches @p themeBaseDir + "/hicolor"
|
||||
* This directory must contain a dir structure as defined by the XDG icons specification
|
||||
* @param appname The application name.
|
||||
* @param themeBaseDir The base directory of the application's theme (eg. "/home/user/app/icons")
|
||||
*/
|
||||
void addAppDir(const QString &appname, const QString &themeBaseDir = QString());
|
||||
|
||||
/**
|
||||
* Loads an icon. It will try very hard to find an icon which is
|
||||
* suitable. If no exact match is found, a close match is searched.
|
||||
* If neither an exact nor a close match is found, a null pixmap or
|
||||
* the "unknown" pixmap is returned, depending on the value of the
|
||||
* @p canReturnNull parameter.
|
||||
*
|
||||
* @param name The name of the icon, without extension.
|
||||
* @param group The icon group. This will specify the size of and effects to
|
||||
* be applied to the icon.
|
||||
* @param size If nonzero, this overrides the size specified by @p group.
|
||||
* See KIconLoader::StdSizes.
|
||||
* @param state The icon state: @p DefaultState, @p ActiveState or
|
||||
* @p DisabledState. Depending on the user's preferences, the iconloader
|
||||
* may apply a visual effect to hint about its state.
|
||||
* @param overlays a list of emblem icons to overlay, by name
|
||||
* @see drawOverlays
|
||||
* @param path_store If not null, the path of the icon is stored here,
|
||||
* if the icon was found. If the icon was not found @p path_store
|
||||
* is unaltered even if the "unknown" pixmap was returned.
|
||||
* @param canReturnNull Can return a null pixmap? If false, the
|
||||
* "unknown" pixmap is returned when no appropriate icon has been
|
||||
* found. <em>Note:</em> a null pixmap can still be returned in the
|
||||
* event of invalid parameters, such as empty names, negative sizes,
|
||||
* and etc.
|
||||
* @return the QPixmap. Can be null when not found, depending on
|
||||
* @p canReturnNull.
|
||||
*/
|
||||
QPixmap loadIcon(const QString &name,
|
||||
KIconLoader::Group group,
|
||||
int size = 0,
|
||||
int state = KIconLoader::DefaultState,
|
||||
const QStringList &overlays = QStringList(),
|
||||
QString *path_store = nullptr,
|
||||
bool canReturnNull = false) const;
|
||||
|
||||
/**
|
||||
* Loads an icon. It will try very hard to find an icon which is
|
||||
* suitable. If no exact match is found, a close match is searched.
|
||||
* If neither an exact nor a close match is found, a null pixmap or
|
||||
* the "unknown" pixmap is returned, depending on the value of the
|
||||
* @p canReturnNull parameter.
|
||||
*
|
||||
* @param name The name of the icon, without extension.
|
||||
* @param group The icon group. This will specify the size of and effects to
|
||||
* be applied to the icon.
|
||||
* @param scale The scale of the icon group to use. If no icon exists in the
|
||||
* scaled group, a 1x icon with its size multiplied by the scale will be
|
||||
* loaded instead.
|
||||
* @param size If nonzero, this overrides the size specified by @p group.
|
||||
* See KIconLoader::StdSizes.
|
||||
* @param state The icon state: @p DefaultState, @p ActiveState or
|
||||
* @p DisabledState. Depending on the user's preferences, the iconloader
|
||||
* may apply a visual effect to hint about its state.
|
||||
* @param overlays a list of emblem icons to overlay, by name
|
||||
* @see drawOverlays
|
||||
* @param path_store If not null, the path of the icon is stored here,
|
||||
* if the icon was found. If the icon was not found @p path_store
|
||||
* is unaltered even if the "unknown" pixmap was returned.
|
||||
* @param canReturnNull Can return a null pixmap? If false, the
|
||||
* "unknown" pixmap is returned when no appropriate icon has been
|
||||
* found. <em>Note:</em> a null pixmap can still be returned in the
|
||||
* event of invalid parameters, such as empty names, negative sizes,
|
||||
* and etc.
|
||||
* @return the QPixmap. Can be null when not found, depending on
|
||||
* @p canReturnNull.
|
||||
* @since 5.48
|
||||
*/
|
||||
// TODO KF6 merge loadIcon() and loadScaledIcon()
|
||||
QPixmap loadScaledIcon(const QString &name,
|
||||
KIconLoader::Group group,
|
||||
qreal scale,
|
||||
int size = 0,
|
||||
int state = KIconLoader::DefaultState,
|
||||
const QStringList &overlays = QStringList(),
|
||||
QString *path_store = nullptr,
|
||||
bool canReturnNull = false) const;
|
||||
|
||||
/**
|
||||
* Loads an icon. It will try very hard to find an icon which is
|
||||
* suitable. If no exact match is found, a close match is searched.
|
||||
* If neither an exact nor a close match is found, a null pixmap or
|
||||
* the "unknown" pixmap is returned, depending on the value of the
|
||||
* @p canReturnNull parameter.
|
||||
*
|
||||
* @param name The name of the icon, without extension.
|
||||
* @param group The icon group. This will specify the size of and effects to
|
||||
* be applied to the icon.
|
||||
* @param scale The scale of the icon group to use. If no icon exists in the
|
||||
* scaled group, a 1x icon with its size multiplied by the scale will be
|
||||
* loaded instead.
|
||||
* @param size If nonzero, this overrides the size specified by @p group.
|
||||
* See KIconLoader::StdSizes. The icon will be fit into @p size
|
||||
* without changing the aspect ratio, which particularly matters
|
||||
* for non-square icons.
|
||||
* @param state The icon state: @p DefaultState, @p ActiveState or
|
||||
* @p DisabledState. Depending on the user's preferences, the iconloader
|
||||
* may apply a visual effect to hint about its state.
|
||||
* @param overlays a list of emblem icons to overlay, by name
|
||||
* @see drawOverlays
|
||||
* @param path_store If not null, the path of the icon is stored here,
|
||||
* if the icon was found. If the icon was not found @p path_store
|
||||
* is unaltered even if the "unknown" pixmap was returned.
|
||||
* @param canReturnNull Can return a null pixmap? If false, the
|
||||
* "unknown" pixmap is returned when no appropriate icon has been
|
||||
* found. <em>Note:</em> a null pixmap can still be returned in the
|
||||
* event of invalid parameters, such as empty names, negative sizes,
|
||||
* and etc.
|
||||
* @return the QPixmap. Can be null when not found, depending on
|
||||
* @p canReturnNull.
|
||||
* @since 5.81
|
||||
*/
|
||||
QPixmap loadScaledIcon(const QString &name,
|
||||
KIconLoader::Group group,
|
||||
qreal scale,
|
||||
const QSize &size = {},
|
||||
int state = KIconLoader::DefaultState,
|
||||
const QStringList &overlays = QStringList(),
|
||||
QString *path_store = nullptr,
|
||||
bool canReturnNull = false) const;
|
||||
|
||||
#if __has_include(<optional>) && __cplusplus >= 201703L
|
||||
/**
|
||||
* Loads an icon. It will try very hard to find an icon which is
|
||||
* suitable. If no exact match is found, a close match is searched.
|
||||
* If neither an exact nor a close match is found, a null pixmap or
|
||||
* the "unknown" pixmap is returned, depending on the value of the
|
||||
* @p canReturnNull parameter.
|
||||
*
|
||||
* @param name The name of the icon, without extension.
|
||||
* @param group The icon group. This will specify the size of and effects to
|
||||
* be applied to the icon.
|
||||
* @param scale The scale of the icon group to use. If no icon exists in the
|
||||
* scaled group, a 1x icon with its size multiplied by the scale will be
|
||||
* loaded instead.
|
||||
* @param size If nonzero, this overrides the size specified by @p group.
|
||||
* See KIconLoader::StdSizes. The icon will be fit into @p size
|
||||
* without changing the aspect ratio, which particularly matters
|
||||
* for non-square icons.
|
||||
* @param state The icon state: @p DefaultState, @p ActiveState or
|
||||
* @p DisabledState. Depending on the user's preferences, the iconloader
|
||||
* may apply a visual effect to hint about its state.
|
||||
* @param overlays a list of emblem icons to overlay, by name
|
||||
* @see drawOverlays
|
||||
* @param path_store If not null, the path of the icon is stored here,
|
||||
* if the icon was found. If the icon was not found @p path_store
|
||||
* is unaltered even if the "unknown" pixmap was returned.
|
||||
* @param canReturnNull Can return a null pixmap? If false, the
|
||||
* "unknown" pixmap is returned when no appropriate icon has been
|
||||
* found. <em>Note:</em> a null pixmap can still be returned in the
|
||||
* event of invalid parameters, such as empty names, negative sizes,
|
||||
* and etc.
|
||||
* @param colorScheme will define the stylesheet used to color this icon.
|
||||
* Note this will only work if @p name is an svg file.
|
||||
* @return the QPixmap. Can be null when not found, depending on
|
||||
* @p canReturnNull.
|
||||
* @since 5.88
|
||||
*/
|
||||
QPixmap loadScaledIcon(const QString &name,
|
||||
KIconLoader::Group group,
|
||||
qreal scale,
|
||||
const QSize &size,
|
||||
int state,
|
||||
const QStringList &overlays,
|
||||
QString *path_store,
|
||||
bool canReturnNull,
|
||||
const std::optional<KIconColors> &colorScheme) const;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Loads an icon for a mimetype.
|
||||
* This is basically like loadIcon except that extra desktop themes are loaded if necessary.
|
||||
*
|
||||
* Consider using QIcon::fromTheme() with a fallback to "application-octet-stream" instead.
|
||||
*
|
||||
* @param iconName The name of the icon, without extension, usually from KMimeType.
|
||||
* @param group The icon group. This will specify the size of and effects to
|
||||
* be applied to the icon.
|
||||
* @param size If nonzero, this overrides the size specified by @p group.
|
||||
* See KIconLoader::StdSizes.
|
||||
* @param state The icon state: @p DefaultState, @p ActiveState or
|
||||
* @p DisabledState. Depending on the user's preferences, the iconloader
|
||||
* may apply a visual effect to hint about its state.
|
||||
* @param path_store If not null, the path of the icon is stored here.
|
||||
* @param overlays a list of emblem icons to overlay, by name
|
||||
* @see drawOverlays
|
||||
* @return the QPixmap. Can not be null, the
|
||||
* "unknown" pixmap is returned when no appropriate icon has been found.
|
||||
*/
|
||||
QPixmap loadMimeTypeIcon(const QString &iconName,
|
||||
KIconLoader::Group group,
|
||||
int size = 0,
|
||||
int state = KIconLoader::DefaultState,
|
||||
const QStringList &overlays = QStringList(),
|
||||
QString *path_store = nullptr) const;
|
||||
|
||||
/**
|
||||
* Returns the path of an icon.
|
||||
* @param name The name of the icon, without extension. If an absolute
|
||||
* path is supplied for this parameter, iconPath will return it
|
||||
* directly.
|
||||
* @param group_or_size If positive, search icons whose size is
|
||||
* specified by the icon group @p group_or_size. If negative, search
|
||||
* icons whose size is - @p group_or_size.
|
||||
* See KIconLoader::Group and KIconLoader::StdSizes
|
||||
* @param canReturnNull Can return a null string? If not, a path to the
|
||||
* "unknown" icon will be returned.
|
||||
* @return the path of an icon, can be null or the "unknown" icon when
|
||||
* not found, depending on @p canReturnNull.
|
||||
*/
|
||||
QString iconPath(const QString &name, int group_or_size, bool canReturnNull = false) const;
|
||||
|
||||
/**
|
||||
* Returns the path of an icon.
|
||||
* @param name The name of the icon, without extension. If an absolute
|
||||
* path is supplied for this parameter, iconPath will return it
|
||||
* directly.
|
||||
* @param group_or_size If positive, search icons whose size is
|
||||
* specified by the icon group @p group_or_size. If negative, search
|
||||
* icons whose size is - @p group_or_size.
|
||||
* See KIconLoader::Group and KIconLoader::StdSizes
|
||||
* @param canReturnNull Can return a null string? If not, a path to the
|
||||
* "unknown" icon will be returned.
|
||||
* @param scale The scale of the icon group.
|
||||
* @return the path of an icon, can be null or the "unknown" icon when
|
||||
* not found, depending on @p canReturnNull.
|
||||
* @since 5.48
|
||||
*/
|
||||
// TODO KF6 merge iconPath() with and without "scale" and move that argument after "group_or_size"
|
||||
QString iconPath(const QString &name, int group_or_size, bool canReturnNull, qreal scale) const;
|
||||
|
||||
#if KICONTHEMES_ENABLE_DEPRECATED_SINCE(6, 5)
|
||||
/**
|
||||
* Loads an animated icon.
|
||||
* @param name The name of the icon.
|
||||
* @param group The icon group. See loadIcon().
|
||||
* @param size Override the default size for @p group.
|
||||
* See KIconLoader::StdSizes.
|
||||
* @param parent The parent object of the returned QMovie.
|
||||
* @return A QMovie object. Can be null if not found or not valid.
|
||||
* Ownership is passed to the caller.
|
||||
* @deprecated since 6.5, use QMovie API
|
||||
*/
|
||||
KICONTHEMES_DEPRECATED_VERSION(6, 5, "Use QMovie API")
|
||||
QMovie *loadMovie(const QString &name, KIconLoader::Group group, int size = 0, QObject *parent = nullptr) const;
|
||||
#endif
|
||||
|
||||
#if KICONTHEMES_ENABLE_DEPRECATED_SINCE(6, 5)
|
||||
/**
|
||||
* Returns the path to an animated icon.
|
||||
* @param name The name of the icon.
|
||||
* @param group The icon group. See loadIcon().
|
||||
* @param size Override the default size for @p group.
|
||||
* See KIconLoader::StdSizes.
|
||||
* @return the full path to the movie, ready to be passed to QMovie's constructor.
|
||||
* Empty string if not found.
|
||||
* @deprecated since 6.5, use QMovie API
|
||||
*/
|
||||
KICONTHEMES_DEPRECATED_VERSION(6, 5, "Use QMovie API")
|
||||
QString moviePath(const QString &name, KIconLoader::Group group, int size = 0) const;
|
||||
#endif
|
||||
|
||||
#if KICONTHEMES_ENABLE_DEPRECATED_SINCE(6, 5)
|
||||
/**
|
||||
* Loads an animated icon as a series of still frames. If you want to load
|
||||
* a .mng animation as QMovie instead, please use loadMovie() instead.
|
||||
* @param name The name of the icon.
|
||||
* @param group The icon group. See loadIcon().
|
||||
* @param size Override the default size for @p group.
|
||||
* See KIconLoader::StdSizes.
|
||||
* @return A QStringList containing the absolute path of all the frames
|
||||
* making up the animation.
|
||||
*
|
||||
* @deprecated since 6.5, use QMovie API
|
||||
*/
|
||||
KICONTHEMES_DEPRECATED_VERSION(6, 5, "Use QMovie API")
|
||||
QStringList loadAnimated(const QString &name, KIconLoader::Group group, int size = 0) const;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Queries all available icons for a specific group, having a specific
|
||||
* context.
|
||||
* @param group_or_size If positive, search icons whose size is
|
||||
* specified by the icon group @p group_or_size. If negative, search
|
||||
* icons whose size is - @p group_or_size.
|
||||
* See KIconLoader::Group and KIconLoader::StdSizes
|
||||
* @param context The icon context.
|
||||
* @return a list of all icons
|
||||
*/
|
||||
QStringList queryIcons(int group_or_size, KIconLoader::Context context = KIconLoader::Any) const;
|
||||
|
||||
/**
|
||||
* Queries all available icons for a specific context.
|
||||
* @param group_or_size The icon preferred group or size. If available
|
||||
* at this group or size, those icons will be returned, in other case,
|
||||
* icons of undefined size will be returned. Positive numbers are groups,
|
||||
* negative numbers are negated sizes. See KIconLoader::Group and
|
||||
* KIconLoader::StdSizes
|
||||
* @param context The icon context.
|
||||
* @return A QStringList containing the icon names
|
||||
* available for that context
|
||||
*/
|
||||
QStringList queryIconsByContext(int group_or_size, KIconLoader::Context context = KIconLoader::Any) const;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
bool hasContext(KIconLoader::Context context) const;
|
||||
|
||||
/**
|
||||
* Returns a list of all icons (*.png or *.xpm extension) in the
|
||||
* given directory.
|
||||
* @param iconsDir the directory to search in
|
||||
* @return A QStringList containing the icon paths
|
||||
*/
|
||||
QStringList queryIconsByDir(const QString &iconsDir) const;
|
||||
|
||||
/**
|
||||
* Returns all the search paths for this icon loader, either absolute or
|
||||
* relative to GenericDataLocation.
|
||||
* Mostly internal (for KIconDialog).
|
||||
* \since 5.0
|
||||
*/
|
||||
QStringList searchPaths() const;
|
||||
|
||||
/**
|
||||
* Returns the size of the specified icon group.
|
||||
* Using e.g. KIconLoader::SmallIcon will return 16.
|
||||
* @param group the group to check.
|
||||
* @return the current size for an icon group.
|
||||
*/
|
||||
int currentSize(KIconLoader::Group group) const;
|
||||
|
||||
/**
|
||||
* Returns a pointer to the current theme. Can be used to query
|
||||
* available and default sizes for groups.
|
||||
* @note The KIconTheme will change if reconfigure() is called and
|
||||
* therefore it's not recommended to store the pointer anywhere.
|
||||
* @return a pointer to the current theme. 0 if no theme set.
|
||||
*/
|
||||
KIconTheme *theme() const;
|
||||
|
||||
#if KICONTHEMES_ENABLE_DEPRECATED_SINCE(6, 5)
|
||||
/**
|
||||
* Returns a pointer to the KIconEffect object used by the icon loader.
|
||||
* @return the KIconEffect.
|
||||
*
|
||||
* @deprecated since 6.5, use the static KIconEffect API
|
||||
*/
|
||||
KICONTHEMES_DEPRECATED_VERSION(6, 5, "Use static KIconEffect API")
|
||||
KIconEffect *iconEffect() const;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Reconfigure the icon loader, for instance to change the associated app name or extra search paths.
|
||||
* This also clears the in-memory pixmap cache (even if the appname didn't change, which is useful for unittests)
|
||||
* @param appname the application name (empty for the global iconloader)
|
||||
* @param extraSearchPaths additional search paths, either absolute or relative to GenericDataLocation
|
||||
*/
|
||||
void reconfigure(const QString &appname, const QStringList &extraSearchPaths = QStringList());
|
||||
|
||||
/**
|
||||
* Returns the unknown icon. An icon that is used when no other icon
|
||||
* can be found.
|
||||
* @return the unknown pixmap
|
||||
*/
|
||||
static QPixmap unknown();
|
||||
|
||||
#if KICONTHEMES_ENABLE_DEPRECATED_SINCE(6, 5)
|
||||
/**
|
||||
* Draws overlays on the specified pixmap, it takes the width and height
|
||||
* of the pixmap into consideration
|
||||
* @param overlays List of up to 4 overlays to blend over the pixmap. The first overlay
|
||||
* will be in the bottom right corner, followed by bottom left, top left
|
||||
* and top right. An empty QString can be used to leave the specific position
|
||||
* blank.
|
||||
* @param pixmap to draw on
|
||||
* @since 4.7
|
||||
* @deprecated since 6.5, use KIconUtils::addOverlays from KGuiAddons
|
||||
*/
|
||||
KICONTHEMES_DEPRECATED_VERSION(6, 5, "Use KIconUtils::addOverlays from KGuiAddons")
|
||||
void drawOverlays(const QStringList &overlays, QPixmap &pixmap, KIconLoader::Group group, int state = KIconLoader::DefaultState) const;
|
||||
#endif
|
||||
|
||||
bool hasIcon(const QString &iconName) const;
|
||||
|
||||
/**
|
||||
* Sets the colors for this KIconLoader.
|
||||
* NOTE: if you set a custom palette, if you are using some colors from
|
||||
* application's palette, you need to track the application palette changes by yourself.
|
||||
* If you no longer wish to use a custom palette, use resetPalette()
|
||||
* @see resetPalette
|
||||
* @since 5.39
|
||||
*/
|
||||
void setCustomPalette(const QPalette &palette);
|
||||
|
||||
/**
|
||||
* The colors that will be used for the svg stylesheet in case the
|
||||
* loaded icons are svg-based, icons can be colored in different ways in
|
||||
* different areas of the application
|
||||
* @return the palette, if any, an invalid one if the user didn't set it
|
||||
* @since 5.39
|
||||
*/
|
||||
QPalette customPalette() const;
|
||||
|
||||
/**
|
||||
* Resets the custom palette used by the KIconLoader to use the
|
||||
* QGuiApplication::palette() again (and to follow it in case the
|
||||
* application's palette changes)
|
||||
* @since 5.39
|
||||
*/
|
||||
void resetPalette();
|
||||
|
||||
/**
|
||||
* @returns whether we have set a custom palette using @f setCustomPalette
|
||||
*
|
||||
* @since 5.85
|
||||
* @see resetPalette, setCustomPalette
|
||||
*/
|
||||
bool hasCustomPalette() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
// TODO: while marked as deprecated, newIconLoader() is still used:
|
||||
// internally by KIconLoadeer as well as by Plasma's Icons kcm module (state: 5.17)
|
||||
// this needs some further cleanup work before removing it from the API with KICONTHEMES_ENABLE_DEPRECATED_SINCE
|
||||
/**
|
||||
* Re-initialize the global icon loader
|
||||
*
|
||||
* @todo Check deprecation, still used internally.
|
||||
* @deprecated Since 5.0, use emitChange(Group)
|
||||
*/
|
||||
KICONTHEMES_DEPRECATED_VERSION(5, 0, "Use KIconLoader::emitChange(Group)") // TODO KF6 remove
|
||||
void newIconLoader();
|
||||
|
||||
/**
|
||||
* Emits an iconChanged() signal on all the KIconLoader instances in the system
|
||||
* indicating that a system's icon group has changed in some way. It will also trigger
|
||||
* a reload in all of them to update to the new theme.
|
||||
*
|
||||
* @p group indicates the group that has changed
|
||||
*
|
||||
* @since 5.0
|
||||
*/
|
||||
static void emitChange(Group group);
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Emitted by newIconLoader once the new settings have been loaded
|
||||
*/
|
||||
void iconLoaderSettingsChanged();
|
||||
|
||||
/**
|
||||
* Emitted when the system icon theme changes
|
||||
*
|
||||
* @since 5.0
|
||||
*/
|
||||
void iconChanged(int group);
|
||||
|
||||
private:
|
||||
friend class KIconLoaderPrivate;
|
||||
// @internal the data object
|
||||
std::unique_ptr<KIconLoaderPrivate> const d;
|
||||
|
||||
Q_PRIVATE_SLOT(d, void _k_refreshIcons(int group))
|
||||
};
|
||||
|
||||
namespace KDE
|
||||
{
|
||||
/**
|
||||
* \relates KIconLoader
|
||||
* Returns a QIcon with an appropriate
|
||||
* KIconEngine to perform loading and rendering. KIcons thus adhere to
|
||||
* KDE style and effect standards.
|
||||
* @since 5.0
|
||||
*/
|
||||
KICONTHEMES_EXPORT QIcon icon(const QString &iconName, KIconLoader *iconLoader = nullptr);
|
||||
KICONTHEMES_EXPORT QIcon icon(const QString &iconName, const KIconColors &colors, KIconLoader *iconLoader = nullptr);
|
||||
|
||||
/**
|
||||
* \relates KIconLoader
|
||||
* Returns a QIcon for the given icon, with additional overlays.
|
||||
* @since 5.0
|
||||
*/
|
||||
KICONTHEMES_EXPORT QIcon icon(const QString &iconName, const QStringList &overlays, KIconLoader *iconLoader = nullptr);
|
||||
|
||||
}
|
||||
|
||||
inline KIconLoader::Group &operator++(KIconLoader::Group &group)
|
||||
{
|
||||
group = static_cast<KIconLoader::Group>(group + 1);
|
||||
return group;
|
||||
}
|
||||
inline KIconLoader::Group operator++(KIconLoader::Group &group, int)
|
||||
{
|
||||
KIconLoader::Group ret = group;
|
||||
++group;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif // KICONLOADER_H
|
||||
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
This file is part of the KDE project, module kdecore.
|
||||
SPDX-FileCopyrightText: 2000 Geert Jansen <jansen@kde.org>
|
||||
SPDX-FileCopyrightText: 2000 Antonio Larrosa <larrosa@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-only
|
||||
*/
|
||||
|
||||
#ifndef KICONLOADER_P_H
|
||||
#define KICONLOADER_P_H
|
||||
|
||||
#include <QCache>
|
||||
#include <QElapsedTimer>
|
||||
#include <QPixmap>
|
||||
#include <QSize>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
#include "kiconcolors.h"
|
||||
#include "kiconeffect.h"
|
||||
#include "kiconloader.h"
|
||||
|
||||
class KIconThemeNode;
|
||||
|
||||
/*** KIconGroup: Icon type description. ***/
|
||||
|
||||
struct KIconGroup {
|
||||
int size;
|
||||
};
|
||||
|
||||
/**
|
||||
* Holds a QPixmap for this process, along with its associated path on disk.
|
||||
*/
|
||||
struct PixmapWithPath {
|
||||
QPixmap pixmap;
|
||||
QString path;
|
||||
};
|
||||
|
||||
/*** d pointer for KIconLoader. ***/
|
||||
class KIconLoaderPrivate
|
||||
{
|
||||
public:
|
||||
KIconLoaderPrivate(const QString &_appname, const QStringList &extraSearchPaths, KIconLoader *qq);
|
||||
~KIconLoaderPrivate();
|
||||
|
||||
static KIconLoaderPrivate *get(KIconLoader *loader);
|
||||
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
void init(const QString &_appname, const QStringList &extraSearchPaths = QStringList());
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
void initIconThemes();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* tries to find an icon with the name. It tries some extension and
|
||||
* match strategies
|
||||
*/
|
||||
QString findMatchingIcon(const QString &name, int size, qreal scale) const;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* tries to find an icon with the name.
|
||||
* This is one layer above findMatchingIcon -- it also implements generic fallbacks
|
||||
* such as generic icons for mimetypes.
|
||||
*/
|
||||
QString findMatchingIconWithGenericFallbacks(const QString &name, int size, qreal scale) const;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* returns the preferred icon path for an icon with the name.
|
||||
* Can be used for a quick "hasIcon" check since it caches
|
||||
* that an icon was not found.
|
||||
*/
|
||||
QString preferredIconPath(const QString &name);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Adds themes installed in the application's directory.
|
||||
**/
|
||||
void addAppThemes(const QString &appname, const QString &themeBaseDir = QString());
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Adds all themes that are part of this node and the themes
|
||||
* below (the fallbacks of the theme) into the tree.
|
||||
*/
|
||||
void addBaseThemes(KIconThemeNode *node, const QString &appname);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Recursively adds all themes that are specified in the "Inherits"
|
||||
* property of the given theme into the tree.
|
||||
*/
|
||||
void addInheritedThemes(KIconThemeNode *node, const QString &appname);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Creates a KIconThemeNode out of a theme name, and adds this theme
|
||||
* as well as all its inherited themes into the tree. Themes that already
|
||||
* exist in the tree will be ignored and not added twice.
|
||||
*/
|
||||
void addThemeByName(const QString &themename, const QString &appname);
|
||||
|
||||
/**
|
||||
* Adds all the default themes from other desktops at the end of
|
||||
* the list of icon themes.
|
||||
*/
|
||||
void addExtraDesktopThemes();
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* return the path for the unknown icon in that size
|
||||
*/
|
||||
QString unknownIconPath(int size, qreal scale) const;
|
||||
|
||||
/**
|
||||
* Checks if name ends in one of the supported icon formats (i.e. .png)
|
||||
* and returns the name without the extension if it does.
|
||||
*/
|
||||
QString removeIconExtension(const QString &name) const;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Used with KIconLoader::loadIcon to convert the given name, size, group,
|
||||
* and icon state information to valid states. All parameters except the
|
||||
* name can be modified as well to be valid.
|
||||
*/
|
||||
void normalizeIconMetadata(KIconLoader::Group &group, QSize &size, int &state) const;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Used with KIconLoader::loadIcon to get a base key name from the given
|
||||
* icon metadata. Ensure the metadata is normalized first.
|
||||
*/
|
||||
QString makeCacheKey(const QString &name,
|
||||
KIconLoader::Group group,
|
||||
const QStringList &overlays,
|
||||
const QSize &size,
|
||||
qreal scale,
|
||||
int state,
|
||||
const KIconColors &colors) const;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* If the icon is an SVG file, process it generating a stylesheet
|
||||
* following the current color scheme. in this case the icon can use named colors
|
||||
* as text color, background color, highlight color, positive/neutral/negative color
|
||||
* @see KColorScheme
|
||||
*/
|
||||
QByteArray processSvg(const QString &path, KIconLoader::States state, const KIconColors &colors) const;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Creates the QImage for @p path, using SVG rendering as appropriate.
|
||||
* @p size is only used for scalable images, but if non-zero non-scalable
|
||||
* images will be resized anyways.
|
||||
*/
|
||||
QImage createIconImage(const QString &path, const QSize &size, qreal scale, KIconLoader::States state, const KIconColors &colors);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Adds an QPixmap with its associated path to the shared icon cache.
|
||||
*/
|
||||
void insertCachedPixmapWithPath(const QString &key, const QPixmap &data, const QString &path);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Retrieves the path and pixmap of the given key from the shared
|
||||
* icon cache.
|
||||
*/
|
||||
bool findCachedPixmapWithPath(const QString &key, QPixmap &data, QString &path);
|
||||
|
||||
/**
|
||||
* Find the given file in the search paths.
|
||||
*/
|
||||
QString locate(const QString &fileName);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* React to a global icon theme change
|
||||
*/
|
||||
void _k_refreshIcons(int group);
|
||||
|
||||
bool shouldCheckForUnknownIcons();
|
||||
|
||||
KIconLoader *const q;
|
||||
|
||||
QStringList mThemesInTree;
|
||||
KIconGroup *mpGroups = nullptr;
|
||||
KIconThemeNode *mpThemeRoot = nullptr;
|
||||
QStringList searchPaths;
|
||||
#if KICONTHEMES_BUILD_DEPRECATED_SINCE(6, 5)
|
||||
KIconEffect mpEffect;
|
||||
#endif
|
||||
QList<KIconThemeNode *> links;
|
||||
|
||||
// This caches rendered QPixmaps in just this process.
|
||||
QCache<QString, PixmapWithPath> mPixmapCache;
|
||||
|
||||
bool extraDesktopIconsLoaded : 1;
|
||||
// lazy loading: initIconThemes() is only needed when the "links" list is needed
|
||||
// mIconThemeInited is used inside initIconThemes() to init only once
|
||||
bool mIconThemeInited : 1;
|
||||
QString m_appname;
|
||||
|
||||
void drawOverlays(const KIconLoader *loader, KIconLoader::Group group, int state, QPixmap &pix, const QStringList &overlays);
|
||||
|
||||
QHash<QString, QString> mIconAvailability; // icon name -> actual icon name (not null if known to be available)
|
||||
QElapsedTimer mLastUnknownIconCheck; // recheck for unknown icons after kiconloader_ms_between_checks
|
||||
// the colors used to recolor svg icons stylesheets
|
||||
KIconColors mColors;
|
||||
QPalette mPalette;
|
||||
// to keep track if we are using a custom palette or just falling back to qApp;
|
||||
bool mCustomColors = false;
|
||||
};
|
||||
|
||||
#endif // KICONLOADER_P_H
|
||||
@@ -0,0 +1,846 @@
|
||||
/*
|
||||
|
||||
kicontheme.cpp: Lowlevel icon theme handling.
|
||||
|
||||
This file is part of the KDE project, module kdecore.
|
||||
SPDX-FileCopyrightText: 2000 Geert Jansen <jansen@kde.org>
|
||||
SPDX-FileCopyrightText: 2000 Antonio Larrosa <larrosa@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-only
|
||||
*/
|
||||
|
||||
#include "kicontheme.h"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#include <KColorSchemeManager>
|
||||
#include <KConfigGroup>
|
||||
#include <KLocalizedString> // KLocalizedString::localizedFilePath. Need such functionality in, hmm, QLocale? QStandardPaths?
|
||||
#include <KSharedConfig>
|
||||
|
||||
#include <QAction>
|
||||
#include <QCoreApplication>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QMap>
|
||||
#include <QResource>
|
||||
#include <QSet>
|
||||
#include <QTimer>
|
||||
|
||||
#include <private/qguiapplication_p.h>
|
||||
#include <qpa/qplatformtheme.h>
|
||||
|
||||
#include <qplatformdefs.h>
|
||||
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
Q_GLOBAL_STATIC(QString, _themeOverride)
|
||||
|
||||
#if !USE_BreezeIcons
|
||||
|
||||
// on Android icon theme loading works differently and is managed by code in Kirigami
|
||||
// so don't actually touch anything icon-related here
|
||||
static void initThemeHelper()
|
||||
{
|
||||
// postpone until QGuiApplication applies initial palette
|
||||
QTimer::singleShot(0, [] {
|
||||
// follow the system color, construct the global manager for that
|
||||
(void)KColorSchemeManager::instance();
|
||||
});
|
||||
}
|
||||
|
||||
void KIconTheme::initTheme()
|
||||
{
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <BreezeIcons>
|
||||
|
||||
// do init only once and avoid later helpers to mess with it again
|
||||
static bool initThemeUsed = false;
|
||||
|
||||
// startup function to set theme once the app got constructed
|
||||
static void initThemeHelper()
|
||||
{
|
||||
// make sure we add application install path to search path, for e.g. bundles on Windows
|
||||
if (initThemeUsed) {
|
||||
// do that similar to QCoreApplicationPrivate::appendApplicationPathToLibraryPaths() with minimal extra API use
|
||||
QString path = QCoreApplication::applicationFilePath();
|
||||
path.truncate(path.lastIndexOf(QLatin1Char('/')));
|
||||
if (const QString ourPath = path + QStringLiteral("/kiconthemes6"); QFile::exists(ourPath)) {
|
||||
QCoreApplication::addLibraryPath(ourPath);
|
||||
}
|
||||
}
|
||||
|
||||
// Makes sure the icon theme fallback is set to breeze or one of its
|
||||
// variants. Most of our apps use "lots" of icons that most of the times
|
||||
// are only available with breeze, we still honour the user icon theme
|
||||
// but if the icon is not found there, we go to breeze since it's almost
|
||||
// sure it'll be there
|
||||
BreezeIcons::initIcons();
|
||||
|
||||
// ensure lib call above did the job
|
||||
Q_ASSERT(!QIcon::fallbackThemeName().isEmpty());
|
||||
|
||||
// only do further stuff if we requested it
|
||||
if (!initThemeUsed) {
|
||||
return;
|
||||
}
|
||||
|
||||
// do nothing if we have the proper platform theme already
|
||||
if (QGuiApplicationPrivate::platformTheme() && QGuiApplicationPrivate::platformTheme()->name() == QLatin1String("kde")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// get config, with fallback to kdeglobals
|
||||
const auto config = KSharedConfig::openConfig();
|
||||
|
||||
// enforce the theme configured by the user, with kdeglobals fallback
|
||||
// if not set, use Breeze
|
||||
const QString themeToUse = KConfigGroup(config, "Icons").readEntry("Theme", QStringLiteral("breeze"));
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 8, 0)
|
||||
// set our theme, Qt internally will still not fully use our engine and lookup
|
||||
QIcon::setThemeName(themeToUse);
|
||||
#else
|
||||
// use Qt API to really fully override the engine, if we set KIconEngine the Key in our plugin will
|
||||
// enforce that our engine is used
|
||||
// https://codereview.qt-project.org/c/qt/qtbase/+/563241
|
||||
QIcon::setThemeName(QStringLiteral("KIconEngine"));
|
||||
#endif
|
||||
|
||||
// Tell KIconTheme about the theme, in case KIconLoader is used directly
|
||||
*_themeOverride() = themeToUse;
|
||||
qCDebug(KICONTHEMES) << "KIconTheme::initTheme() enforces the icon theme:" << themeToUse;
|
||||
|
||||
// postpone until QGuiApplication applies initial palette
|
||||
QTimer::singleShot(0, [] {
|
||||
// follow the system color, construct the global manager for that
|
||||
(void)KColorSchemeManager::instance();
|
||||
});
|
||||
}
|
||||
|
||||
void KIconTheme::initTheme()
|
||||
{
|
||||
// inject paths only once
|
||||
if (!initThemeUsed) {
|
||||
// inject our icon engine in the search path
|
||||
// it will be used as the first found engine for a suffix will be taken
|
||||
// this must be done before the QCoreApplication is constructed
|
||||
const auto paths = QCoreApplication::libraryPaths();
|
||||
for (const auto &path : paths) {
|
||||
if (const QString ourPath = path + QStringLiteral("/kiconthemes6"); QFile::exists(ourPath)) {
|
||||
QCoreApplication::addLibraryPath(ourPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// initThemeHelper will do the remaining work via Q_COREAPP_STARTUP_FUNCTION(initThemeHelper) above
|
||||
initThemeUsed = true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Q_COREAPP_STARTUP_FUNCTION(initThemeHelper)
|
||||
|
||||
class KIconThemeDir;
|
||||
class KIconThemePrivate
|
||||
{
|
||||
public:
|
||||
QString example, screenshot;
|
||||
bool hidden;
|
||||
KSharedConfig::Ptr sharedConfig;
|
||||
|
||||
struct GroupInfo {
|
||||
KIconLoader::Group type;
|
||||
const char *name;
|
||||
int defaultSize;
|
||||
QList<int> availableSizes{};
|
||||
};
|
||||
std::array<GroupInfo, KIconLoader::LastGroup> m_iconGroups = {{
|
||||
{KIconLoader::Desktop, "Desktop", 32},
|
||||
{KIconLoader::Toolbar, "Toolbar", 22},
|
||||
{KIconLoader::MainToolbar, "MainToolbar", 22},
|
||||
{KIconLoader::Small, "Small", 16},
|
||||
{KIconLoader::Panel, "Panel", 48},
|
||||
{KIconLoader::Dialog, "Dialog", 32},
|
||||
}};
|
||||
|
||||
int mDepth;
|
||||
QString mDir, mName, mInternalName, mDesc;
|
||||
QStringList mInherits;
|
||||
QStringList mExtensions;
|
||||
QList<KIconThemeDir *> mDirs;
|
||||
QList<KIconThemeDir *> mScaledDirs;
|
||||
bool followsColorScheme : 1;
|
||||
|
||||
/// Searches the given dirs vector for a matching icon
|
||||
QString iconPath(const QList<KIconThemeDir *> &dirs, const QString &name, int size, qreal scale, KIconLoader::MatchType match) const;
|
||||
};
|
||||
Q_GLOBAL_STATIC(QString, _theme)
|
||||
Q_GLOBAL_STATIC(QStringList, _theme_list)
|
||||
|
||||
/**
|
||||
* A subdirectory in an icon theme.
|
||||
*/
|
||||
class KIconThemeDir
|
||||
{
|
||||
public:
|
||||
KIconThemeDir(const QString &basedir, const QString &themedir, const KConfigGroup &config);
|
||||
|
||||
bool isValid() const
|
||||
{
|
||||
return mbValid;
|
||||
}
|
||||
QString iconPath(const QString &name) const;
|
||||
QStringList iconList() const;
|
||||
QString constructFileName(const QString &file) const
|
||||
{
|
||||
return mBaseDir + mThemeDir + QLatin1Char('/') + file;
|
||||
}
|
||||
|
||||
KIconLoader::Context context() const
|
||||
{
|
||||
return mContext;
|
||||
}
|
||||
KIconLoader::Type type() const
|
||||
{
|
||||
return mType;
|
||||
}
|
||||
int size() const
|
||||
{
|
||||
return mSize;
|
||||
}
|
||||
int scale() const
|
||||
{
|
||||
return mScale;
|
||||
}
|
||||
int minSize() const
|
||||
{
|
||||
return mMinSize;
|
||||
}
|
||||
int maxSize() const
|
||||
{
|
||||
return mMaxSize;
|
||||
}
|
||||
int threshold() const
|
||||
{
|
||||
return mThreshold;
|
||||
}
|
||||
|
||||
private:
|
||||
bool mbValid = false;
|
||||
KIconLoader::Type mType = KIconLoader::Fixed;
|
||||
KIconLoader::Context mContext;
|
||||
int mSize = 0;
|
||||
int mScale = 1;
|
||||
int mMinSize = 1;
|
||||
int mMaxSize = 50;
|
||||
int mThreshold = 2;
|
||||
|
||||
const QString mBaseDir;
|
||||
const QString mThemeDir;
|
||||
};
|
||||
|
||||
QString KIconThemePrivate::iconPath(const QList<KIconThemeDir *> &dirs, const QString &name, int size, qreal scale, KIconLoader::MatchType match) const
|
||||
{
|
||||
QString path;
|
||||
QString tempPath; // used to cache icon path if it exists
|
||||
|
||||
int delta = -INT_MAX; // current icon size delta of 'icon'
|
||||
int dw = INT_MAX; // icon size delta of current directory
|
||||
|
||||
// Rather downsample than upsample
|
||||
int integerScale = std::ceil(scale);
|
||||
|
||||
// Search the directory that contains the icon which matches best to the requested
|
||||
// size. If there is no directory which matches exactly to the requested size, the
|
||||
// following criteria get applied:
|
||||
// - Take a directory having icons with a minimum difference to the requested size.
|
||||
// - Prefer directories that allow a downscaling even if the difference to
|
||||
// the requested size is bigger than a directory where an upscaling is required.
|
||||
for (KIconThemeDir *dir : dirs) {
|
||||
if (dir->scale() != integerScale) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (match == KIconLoader::MatchExact) {
|
||||
if ((dir->type() == KIconLoader::Fixed) && (dir->size() != size)) {
|
||||
continue;
|
||||
}
|
||||
if ((dir->type() == KIconLoader::Scalable) //
|
||||
&& ((size < dir->minSize()) || (size > dir->maxSize()))) {
|
||||
continue;
|
||||
}
|
||||
if ((dir->type() == KIconLoader::Threshold) //
|
||||
&& (abs(dir->size() - size) > dir->threshold())) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// dw < 0 means need to scale up to get an icon of the requested size.
|
||||
// Upscaling should only be done if no larger icon is available.
|
||||
if (dir->type() == KIconLoader::Fixed) {
|
||||
dw = dir->size() - size;
|
||||
} else if (dir->type() == KIconLoader::Scalable) {
|
||||
if (size < dir->minSize()) {
|
||||
dw = dir->minSize() - size;
|
||||
} else if (size > dir->maxSize()) {
|
||||
dw = dir->maxSize() - size;
|
||||
} else {
|
||||
dw = 0;
|
||||
}
|
||||
} else if (dir->type() == KIconLoader::Threshold) {
|
||||
if (size < dir->size() - dir->threshold()) {
|
||||
dw = dir->size() - dir->threshold() - size;
|
||||
} else if (size > dir->size() + dir->threshold()) {
|
||||
dw = dir->size() + dir->threshold() - size;
|
||||
} else {
|
||||
dw = 0;
|
||||
}
|
||||
}
|
||||
// Usually if the delta (= 'dw') of the current directory is
|
||||
// not smaller than the delta (= 'delta') of the currently best
|
||||
// matching icon, this candidate can be skipped. But skipping
|
||||
// the candidate may only be done, if this does not imply
|
||||
// in an upscaling of the icon (it is OK to use a directory with
|
||||
// smaller icons that what we've already found, however).
|
||||
if ((abs(dw) >= abs(delta)) && ((dw < 0) || (delta > 0))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (match == KIconLoader::MatchBestOrGreaterSize && dw < 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// cache the result of iconPath() call which checks if file exists
|
||||
tempPath = dir->iconPath(name);
|
||||
|
||||
if (tempPath.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
path = tempPath;
|
||||
|
||||
// if we got in MatchExact that far, we find no better
|
||||
if (match == KIconLoader::MatchExact) {
|
||||
return path;
|
||||
}
|
||||
delta = dw;
|
||||
if (delta == 0) {
|
||||
return path; // We won't find a better match anyway
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
KIconTheme::KIconTheme(const QString &name, const QString &appName, const QString &basePathHint)
|
||||
: d(new KIconThemePrivate)
|
||||
{
|
||||
d->mInternalName = name;
|
||||
|
||||
QStringList themeDirs;
|
||||
|
||||
// Applications can have local additions to the global "locolor" and
|
||||
// "hicolor" icon themes. For these, the _global_ theme description
|
||||
// files are used..
|
||||
|
||||
/* clang-format off */
|
||||
if (!appName.isEmpty()
|
||||
&& (name == defaultThemeName()
|
||||
|| name == QLatin1String("hicolor")
|
||||
|| name == QLatin1String("locolor"))) { /* clang-format on */
|
||||
const QString suffix = QLatin1Char('/') + appName + QLatin1String("/icons/") + name + QLatin1Char('/');
|
||||
QStringList dataDirs = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
|
||||
for (auto &cDir : dataDirs) {
|
||||
cDir += suffix;
|
||||
if (QFileInfo::exists(cDir)) {
|
||||
themeDirs += cDir;
|
||||
}
|
||||
}
|
||||
|
||||
if (!basePathHint.isEmpty()) {
|
||||
// Checks for dir existing are done below
|
||||
themeDirs += basePathHint + QLatin1Char('/') + name + QLatin1Char('/');
|
||||
}
|
||||
}
|
||||
|
||||
// Find the theme description file. These are either locally in the :/icons resource path or global.
|
||||
QStringList icnlibs;
|
||||
|
||||
// local embedded icons have preference
|
||||
icnlibs << QStringLiteral(":/icons");
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
// Android icon theme installed by Kirigami
|
||||
icnlibs << QStringLiteral("assets:/qml/org/kde/kirigami");
|
||||
#endif
|
||||
|
||||
// global icons
|
||||
icnlibs += QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("icons"), QStandardPaths::LocateDirectory);
|
||||
|
||||
// These are not in the icon spec, but e.g. GNOME puts some icons there anyway.
|
||||
icnlibs += QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("pixmaps"), QStandardPaths::LocateDirectory);
|
||||
|
||||
QString fileName;
|
||||
QString mainSection;
|
||||
const QString pathSuffix = QLatin1Char('/') + name + QLatin1Char('/');
|
||||
const QLatin1String indexTheme("index.theme");
|
||||
const QLatin1String indexDesktop("theme.desktop");
|
||||
for (auto &iconDir : icnlibs) {
|
||||
iconDir += pathSuffix;
|
||||
const QFileInfo fi(iconDir);
|
||||
if (!fi.exists() || !fi.isDir()) {
|
||||
continue;
|
||||
}
|
||||
themeDirs.append(iconDir);
|
||||
|
||||
if (d->mDir.isEmpty()) {
|
||||
QString possiblePath;
|
||||
if (possiblePath = iconDir + indexTheme; QFileInfo::exists(possiblePath)) {
|
||||
d->mDir = iconDir;
|
||||
fileName = possiblePath;
|
||||
mainSection = QStringLiteral("Icon Theme");
|
||||
} else if (possiblePath = iconDir + indexDesktop; QFileInfo::exists(possiblePath)) {
|
||||
d->mDir = iconDir;
|
||||
fileName = possiblePath;
|
||||
mainSection = QStringLiteral("KDE Icon Theme");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (d->mDir.isEmpty()) {
|
||||
qCDebug(KICONTHEMES) << "Icon theme" << name << "not found.";
|
||||
return;
|
||||
}
|
||||
|
||||
// Use KSharedConfig to avoid parsing the file many times, from each component.
|
||||
// Need to keep a ref to it to make this useful
|
||||
d->sharedConfig = KSharedConfig::openConfig(fileName, KConfig::SimpleConfig);
|
||||
|
||||
KConfigGroup cfg(d->sharedConfig, mainSection);
|
||||
d->mName = cfg.readEntry("Name");
|
||||
d->mDesc = cfg.readEntry("Comment");
|
||||
d->mDepth = cfg.readEntry("DisplayDepth", 32);
|
||||
d->mInherits = cfg.readEntry("Inherits", QStringList());
|
||||
if (name != defaultThemeName()) {
|
||||
for (auto &inheritedTheme : d->mInherits) {
|
||||
if (inheritedTheme == QLatin1String("default")) {
|
||||
inheritedTheme = defaultThemeName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
d->hidden = cfg.readEntry("Hidden", false);
|
||||
d->followsColorScheme = cfg.readEntry("FollowsColorScheme", false);
|
||||
d->example = cfg.readPathEntry("Example", QString());
|
||||
d->screenshot = cfg.readPathEntry("ScreenShot", QString());
|
||||
d->mExtensions =
|
||||
cfg.readEntry("KDE-Extensions", QStringList{QStringLiteral(".png"), QStringLiteral(".svgz"), QStringLiteral(".svg"), QStringLiteral(".xpm")});
|
||||
|
||||
QSet<QString> addedDirs; // Used for avoiding duplicates.
|
||||
const QStringList dirs = cfg.readPathEntry("Directories", QStringList()) + cfg.readPathEntry("ScaledDirectories", QStringList());
|
||||
for (const auto &dirName : dirs) {
|
||||
KConfigGroup cg(d->sharedConfig, dirName);
|
||||
for (const auto &themeDir : std::as_const(themeDirs)) {
|
||||
const QString currentDir(themeDir + dirName + QLatin1Char('/'));
|
||||
if (!addedDirs.contains(currentDir) && QFileInfo::exists(currentDir)) {
|
||||
addedDirs.insert(currentDir);
|
||||
KIconThemeDir *dir = new KIconThemeDir(themeDir, dirName, cg);
|
||||
if (dir->isValid()) {
|
||||
if (dir->scale() > 1) {
|
||||
d->mScaledDirs.append(dir);
|
||||
} else {
|
||||
d->mDirs.append(dir);
|
||||
}
|
||||
} else {
|
||||
delete dir;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
KConfigGroup cg(d->sharedConfig, mainSection);
|
||||
for (auto &iconGroup : d->m_iconGroups) {
|
||||
iconGroup.defaultSize = cg.readEntry(iconGroup.name + QLatin1String("Default"), iconGroup.defaultSize);
|
||||
iconGroup.availableSizes = cg.readEntry(iconGroup.name + QLatin1String("Sizes"), QList<int>());
|
||||
}
|
||||
}
|
||||
|
||||
KIconTheme::~KIconTheme()
|
||||
{
|
||||
qDeleteAll(d->mDirs);
|
||||
qDeleteAll(d->mScaledDirs);
|
||||
}
|
||||
|
||||
QString KIconTheme::name() const
|
||||
{
|
||||
return d->mName;
|
||||
}
|
||||
|
||||
QString KIconTheme::internalName() const
|
||||
{
|
||||
return d->mInternalName;
|
||||
}
|
||||
|
||||
QString KIconTheme::description() const
|
||||
{
|
||||
return d->mDesc;
|
||||
}
|
||||
|
||||
QString KIconTheme::example() const
|
||||
{
|
||||
return d->example;
|
||||
}
|
||||
|
||||
QString KIconTheme::screenshot() const
|
||||
{
|
||||
return d->screenshot;
|
||||
}
|
||||
|
||||
QString KIconTheme::dir() const
|
||||
{
|
||||
return d->mDir;
|
||||
}
|
||||
|
||||
QStringList KIconTheme::inherits() const
|
||||
{
|
||||
return d->mInherits;
|
||||
}
|
||||
|
||||
bool KIconTheme::isValid() const
|
||||
{
|
||||
return !d->mDirs.isEmpty() || !d->mScaledDirs.isEmpty();
|
||||
}
|
||||
|
||||
bool KIconTheme::isHidden() const
|
||||
{
|
||||
return d->hidden;
|
||||
}
|
||||
|
||||
int KIconTheme::depth() const
|
||||
{
|
||||
return d->mDepth;
|
||||
}
|
||||
|
||||
int KIconTheme::defaultSize(KIconLoader::Group group) const
|
||||
{
|
||||
if (group < 0 || group >= KIconLoader::LastGroup) {
|
||||
qCWarning(KICONTHEMES) << "Invalid icon group:" << group << ", should be one of KIconLoader::Group";
|
||||
return -1;
|
||||
}
|
||||
return d->m_iconGroups[group].defaultSize;
|
||||
}
|
||||
|
||||
QList<int> KIconTheme::querySizes(KIconLoader::Group group) const
|
||||
{
|
||||
if (group < 0 || group >= KIconLoader::LastGroup) {
|
||||
qCWarning(KICONTHEMES) << "Invalid icon group:" << group << ", should be one of KIconLoader::Group";
|
||||
return QList<int>();
|
||||
}
|
||||
return d->m_iconGroups[group].availableSizes;
|
||||
}
|
||||
|
||||
static bool isAnyOrDirContext(const KIconThemeDir *dir, KIconLoader::Context context)
|
||||
{
|
||||
return context == KIconLoader::Any || context == dir->context();
|
||||
}
|
||||
|
||||
QStringList KIconTheme::queryIcons(int size, KIconLoader::Context context) const
|
||||
{
|
||||
// Try to find exact match
|
||||
QStringList result;
|
||||
const QList<KIconThemeDir *> listDirs = d->mDirs + d->mScaledDirs;
|
||||
for (const KIconThemeDir *dir : listDirs) {
|
||||
if (!isAnyOrDirContext(dir, context)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const int dirSize = dir->size();
|
||||
if ((dir->type() == KIconLoader::Fixed && dirSize == size) //
|
||||
|| (dir->type() == KIconLoader::Scalable && size >= dir->minSize() && size <= dir->maxSize())
|
||||
|| (dir->type() == KIconLoader::Threshold && abs(size - dirSize) < dir->threshold())) {
|
||||
result += dir->iconList();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QStringList KIconTheme::queryIconsByContext(int size, KIconLoader::Context context) const
|
||||
{
|
||||
int dw;
|
||||
|
||||
// We want all the icons for a given context, but we prefer icons
|
||||
// of size "size" . Note that this may (will) include duplicate icons
|
||||
// QStringList iconlist[34]; // 33 == 48-16+1
|
||||
QStringList iconlist[128]; // 33 == 48-16+1
|
||||
// Usually, only the 0, 6 (22-16), 10 (32-22), 16 (48-32 or 32-16),
|
||||
// 26 (48-22) and 32 (48-16) will be used, but who knows if someone
|
||||
// will make icon themes with different icon sizes.
|
||||
const auto listDirs = d->mDirs + d->mScaledDirs;
|
||||
for (KIconThemeDir *dir : listDirs) {
|
||||
if (!isAnyOrDirContext(dir, context)) {
|
||||
continue;
|
||||
}
|
||||
dw = abs(dir->size() - size);
|
||||
iconlist[(dw < 127) ? dw : 127] += dir->iconList();
|
||||
}
|
||||
|
||||
QStringList iconlistResult;
|
||||
for (int i = 0; i < 128; i++) {
|
||||
iconlistResult += iconlist[i];
|
||||
}
|
||||
|
||||
return iconlistResult;
|
||||
}
|
||||
|
||||
bool KIconTheme::hasContext(KIconLoader::Context context) const
|
||||
{
|
||||
const auto listDirs = d->mDirs + d->mScaledDirs;
|
||||
for (KIconThemeDir *dir : listDirs) {
|
||||
if (isAnyOrDirContext(dir, context)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QString KIconTheme::iconPathByName(const QString &iconName, int size, KIconLoader::MatchType match) const
|
||||
{
|
||||
return iconPathByName(iconName, size, match, 1 /*scale*/);
|
||||
}
|
||||
|
||||
QString KIconTheme::iconPathByName(const QString &iconName, int size, KIconLoader::MatchType match, qreal scale) const
|
||||
{
|
||||
for (const QString ¤t : std::as_const(d->mExtensions)) {
|
||||
const QString path = iconPath(iconName + current, size, match, scale);
|
||||
if (!path.isEmpty()) {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
bool KIconTheme::followsColorScheme() const
|
||||
{
|
||||
return d->followsColorScheme;
|
||||
}
|
||||
|
||||
QString KIconTheme::iconPath(const QString &name, int size, KIconLoader::MatchType match) const
|
||||
{
|
||||
return iconPath(name, size, match, 1 /*scale*/);
|
||||
}
|
||||
|
||||
QString KIconTheme::iconPath(const QString &name, int size, KIconLoader::MatchType match, qreal scale) const
|
||||
{
|
||||
// first look for a scaled image at exactly the requested size
|
||||
QString path = d->iconPath(d->mScaledDirs, name, size, scale, KIconLoader::MatchExact);
|
||||
|
||||
// then look for an unscaled one but request it at larger size so it doesn't become blurry
|
||||
if (path.isEmpty()) {
|
||||
path = d->iconPath(d->mDirs, name, size * scale, 1, match);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
// static
|
||||
QString KIconTheme::current()
|
||||
{
|
||||
// Static pointers because of unloading problems wrt DSO's.
|
||||
if (_themeOverride && !_themeOverride->isEmpty()) {
|
||||
*_theme() = *_themeOverride();
|
||||
}
|
||||
if (!_theme()->isEmpty()) {
|
||||
return *_theme();
|
||||
}
|
||||
|
||||
QString theme;
|
||||
// Check application specific config for a theme setting.
|
||||
KConfigGroup app_cg(KSharedConfig::openConfig(QString(), KConfig::NoGlobals), "Icons");
|
||||
theme = app_cg.readEntry("Theme", QString());
|
||||
if (theme.isEmpty() || theme == QLatin1String("hicolor")) {
|
||||
// No theme, try to use Qt's. A Platform plugin might have set
|
||||
// a good theme there.
|
||||
theme = QIcon::themeName();
|
||||
}
|
||||
if (theme.isEmpty() || theme == QLatin1String("hicolor")) {
|
||||
// Still no theme, try config with kdeglobals.
|
||||
KConfigGroup cg(KSharedConfig::openConfig(), "Icons");
|
||||
theme = cg.readEntry("Theme", QStringLiteral("breeze"));
|
||||
}
|
||||
if (theme.isEmpty() || theme == QLatin1String("hicolor")) {
|
||||
// Still no good theme, use default.
|
||||
theme = defaultThemeName();
|
||||
}
|
||||
*_theme() = theme;
|
||||
return *_theme();
|
||||
}
|
||||
|
||||
void KIconTheme::forceThemeForTests(const QString &themeName)
|
||||
{
|
||||
*_themeOverride() = themeName;
|
||||
_theme()->clear(); // ::current sets this again based on conditions
|
||||
}
|
||||
|
||||
// static
|
||||
QStringList KIconTheme::list()
|
||||
{
|
||||
// Static pointer because of unloading problems wrt DSO's.
|
||||
if (!_theme_list()->isEmpty()) {
|
||||
return *_theme_list();
|
||||
}
|
||||
|
||||
// Find the theme description file. These are either locally in the :/icons resource path or global.
|
||||
QStringList icnlibs;
|
||||
|
||||
// local embedded icons have preference
|
||||
icnlibs << QStringLiteral(":/icons");
|
||||
|
||||
// global icons
|
||||
icnlibs += QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("icons"), QStandardPaths::LocateDirectory);
|
||||
|
||||
// These are not in the icon spec, but e.g. GNOME puts some icons there anyway.
|
||||
icnlibs += QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("pixmaps"), QStandardPaths::LocateDirectory);
|
||||
|
||||
for (const QString &iconDir : std::as_const(icnlibs)) {
|
||||
QDir dir(iconDir);
|
||||
const QStringList themeDirs = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||
for (const auto &theme : themeDirs) {
|
||||
if (theme.startsWith(QLatin1String("default."))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const QString prefix = iconDir + QLatin1Char('/') + theme;
|
||||
if (!QFileInfo::exists(prefix + QLatin1String("/index.desktop")) //
|
||||
&& !QFileInfo::exists(prefix + QLatin1String("/index.theme"))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!KIconTheme(theme).isValid()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!_theme_list()->contains(theme)) {
|
||||
_theme_list()->append(theme);
|
||||
}
|
||||
}
|
||||
}
|
||||
return *_theme_list();
|
||||
}
|
||||
|
||||
// static
|
||||
void KIconTheme::reconfigure()
|
||||
{
|
||||
_theme()->clear();
|
||||
_theme_list()->clear();
|
||||
}
|
||||
|
||||
// static
|
||||
QString KIconTheme::defaultThemeName()
|
||||
{
|
||||
return QStringLiteral("hicolor");
|
||||
}
|
||||
|
||||
/*** KIconThemeDir ***/
|
||||
|
||||
KIconThemeDir::KIconThemeDir(const QString &basedir, const QString &themedir, const KConfigGroup &config)
|
||||
: mSize(config.readEntry("Size", 0))
|
||||
, mScale(config.readEntry("Scale", 1))
|
||||
, mBaseDir(basedir)
|
||||
, mThemeDir(themedir)
|
||||
{
|
||||
if (mSize == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString tmp = config.readEntry("Context", QString());
|
||||
if (tmp == QLatin1String("Devices")) {
|
||||
mContext = KIconLoader::Device;
|
||||
} else if (tmp == QLatin1String("MimeTypes")) {
|
||||
mContext = KIconLoader::MimeType;
|
||||
} else if (tmp == QLatin1String("Applications")) {
|
||||
mContext = KIconLoader::Application;
|
||||
} else if (tmp == QLatin1String("Actions")) {
|
||||
mContext = KIconLoader::Action;
|
||||
} else if (tmp == QLatin1String("Animations")) {
|
||||
mContext = KIconLoader::Animation;
|
||||
} else if (tmp == QLatin1String("Categories")) {
|
||||
mContext = KIconLoader::Category;
|
||||
} else if (tmp == QLatin1String("Emblems")) {
|
||||
mContext = KIconLoader::Emblem;
|
||||
} else if (tmp == QLatin1String("Emotes")) {
|
||||
mContext = KIconLoader::Emote;
|
||||
} else if (tmp == QLatin1String("International")) {
|
||||
mContext = KIconLoader::International;
|
||||
} else if (tmp == QLatin1String("Places")) {
|
||||
mContext = KIconLoader::Place;
|
||||
} else if (tmp == QLatin1String("Status")) {
|
||||
mContext = KIconLoader::StatusIcon;
|
||||
} else if (tmp == QLatin1String("Stock")) { // invalid, but often present context, skip warning
|
||||
return;
|
||||
} else if (tmp == QLatin1String("FileSystems")) { // invalid, but present context for hicolor, skip warning
|
||||
return;
|
||||
} else if (tmp == QLatin1String("Legacy")) { // invalid, but often present context for Adwaita, skip warning
|
||||
return;
|
||||
} else if (tmp == QLatin1String("UI")) { // invalid, but often present context for Adwaita, skip warning
|
||||
return;
|
||||
} else if (tmp.isEmpty()) {
|
||||
// do nothing. key not required
|
||||
} else {
|
||||
qCDebug(KICONTHEMES) << "Invalid Context=" << tmp << "line for icon theme: " << constructFileName(QString());
|
||||
return;
|
||||
}
|
||||
tmp = config.readEntry("Type", QStringLiteral("Threshold"));
|
||||
if (tmp == QLatin1String("Fixed")) {
|
||||
mType = KIconLoader::Fixed;
|
||||
} else if (tmp == QLatin1String("Scalable")) {
|
||||
mType = KIconLoader::Scalable;
|
||||
} else if (tmp == QLatin1String("Threshold")) {
|
||||
mType = KIconLoader::Threshold;
|
||||
} else {
|
||||
qCDebug(KICONTHEMES) << "Invalid Type=" << tmp << "line for icon theme: " << constructFileName(QString());
|
||||
return;
|
||||
}
|
||||
if (mType == KIconLoader::Scalable) {
|
||||
mMinSize = config.readEntry("MinSize", mSize);
|
||||
mMaxSize = config.readEntry("MaxSize", mSize);
|
||||
} else if (mType == KIconLoader::Threshold) {
|
||||
mThreshold = config.readEntry("Threshold", 2);
|
||||
}
|
||||
mbValid = true;
|
||||
}
|
||||
|
||||
QString KIconThemeDir::iconPath(const QString &name) const
|
||||
{
|
||||
if (!mbValid) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
const QString file = constructFileName(name);
|
||||
if (QFileInfo::exists(file)) {
|
||||
return KLocalizedString::localizedFilePath(file);
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
QStringList KIconThemeDir::iconList() const
|
||||
{
|
||||
const QDir icondir = constructFileName(QString());
|
||||
|
||||
const QStringList formats = QStringList() << QStringLiteral("*.png") << QStringLiteral("*.svg") << QStringLiteral("*.svgz") << QStringLiteral("*.xpm");
|
||||
const QStringList lst = icondir.entryList(formats, QDir::Files);
|
||||
|
||||
QStringList result;
|
||||
result.reserve(lst.size());
|
||||
for (const QString &file : lst) {
|
||||
result += constructFileName(file);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
|
||||
This file is part of the KDE project, module kdecore.
|
||||
SPDX-FileCopyrightText: 2000 Geert Jansen <jansen@kde.org>
|
||||
SPDX-FileCopyrightText: 2000 Antonio Larrosa <larrosa@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-only
|
||||
*/
|
||||
|
||||
#ifndef KICONTHEME_H
|
||||
#define KICONTHEME_H
|
||||
|
||||
#include <kiconthemes_export.h>
|
||||
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "kiconloader.h"
|
||||
|
||||
class QAction;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Class to use/access icon themes in KDE. This class is used by the
|
||||
* iconloader but can be used by others too.
|
||||
* @warning You should not use this class externally. This class is exported because
|
||||
* the KCM needs it.
|
||||
* @see KIconLoader
|
||||
*/
|
||||
class KICONTHEMES_EXPORT KIconTheme
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Load an icon theme by name.
|
||||
* @param name the name of the theme (e.g. "hicolor" or "keramik")
|
||||
* @param appName the name of the application. Can be null. This argument
|
||||
* allows applications to have themed application icons.
|
||||
* @param basePathHint optional hint where to search the app themes.
|
||||
* This is appended at the end of the search paths
|
||||
*/
|
||||
explicit KIconTheme(const QString &name, const QString &appName = QString(), const QString &basePathHint = QString());
|
||||
~KIconTheme();
|
||||
|
||||
KIconTheme(const KIconTheme &) = delete;
|
||||
KIconTheme &operator=(const KIconTheme &) = delete;
|
||||
|
||||
/**
|
||||
* The stylized name of the icon theme.
|
||||
* @return the (human-readable) name of the theme
|
||||
*/
|
||||
QString name() const;
|
||||
|
||||
/**
|
||||
* The internal name of the icon theme (same as the name argument passed
|
||||
* to the constructor).
|
||||
* @return the internal name of the theme
|
||||
*/
|
||||
QString internalName() const;
|
||||
|
||||
/**
|
||||
* A description for the icon theme.
|
||||
* @return a human-readable description of the theme, QString()
|
||||
* if there is none
|
||||
*/
|
||||
QString description() const;
|
||||
|
||||
/**
|
||||
* Return the name of the "example" icon. This can be used to
|
||||
* present the theme to the user.
|
||||
* @return the name of the example icon, QString() if there is none
|
||||
*/
|
||||
QString example() const;
|
||||
|
||||
/**
|
||||
* Return the name of the screenshot.
|
||||
* @return the name of the screenshot, QString() if there is none
|
||||
*/
|
||||
QString screenshot() const;
|
||||
|
||||
/**
|
||||
* Returns the toplevel theme directory.
|
||||
* @return the directory of the theme
|
||||
*/
|
||||
QString dir() const;
|
||||
|
||||
/**
|
||||
* The themes this icon theme falls back on.
|
||||
* @return a list of icon themes that are used as fall-backs
|
||||
*/
|
||||
QStringList inherits() const;
|
||||
|
||||
/**
|
||||
* The icon theme exists?
|
||||
* @return true if the icon theme is valid
|
||||
*/
|
||||
bool isValid() const;
|
||||
|
||||
/**
|
||||
* The icon theme should be hidden to the user?
|
||||
* @return true if the icon theme is hidden
|
||||
*/
|
||||
bool isHidden() const;
|
||||
|
||||
/**
|
||||
* The minimum display depth required for this theme. This can either
|
||||
* be 8 or 32.
|
||||
* @return the minimum bpp (8 or 32)
|
||||
*/
|
||||
int depth() const;
|
||||
|
||||
/**
|
||||
* The default size of this theme for a certain icon group.
|
||||
* @param group The icon group. See KIconLoader::Group.
|
||||
* @return The default size in pixels for the given icon group.
|
||||
*/
|
||||
int defaultSize(KIconLoader::Group group) const;
|
||||
|
||||
/**
|
||||
* Query available sizes for a group.
|
||||
* @param group The icon group. See KIconLoader::Group.
|
||||
* @return a list of available sizes for the given group
|
||||
*/
|
||||
QList<int> querySizes(KIconLoader::Group group) const;
|
||||
|
||||
/**
|
||||
* Query available icons for a size and context.
|
||||
* @param size the size of the icons
|
||||
* @param context the context of the icons
|
||||
* @return the list of icon names
|
||||
*/
|
||||
QStringList queryIcons(int size, KIconLoader::Context context = KIconLoader::Any) const;
|
||||
|
||||
/**
|
||||
* Query available icons for a context and preferred size.
|
||||
* @param size the size of the icons
|
||||
* @param context the context of the icons
|
||||
* @return the list of icon names
|
||||
*/
|
||||
QStringList queryIconsByContext(int size, KIconLoader::Context context = KIconLoader::Any) const;
|
||||
|
||||
/**
|
||||
* Lookup an icon in the theme.
|
||||
* @param name The name of the icon, with extension.
|
||||
* @param size The desired size of the icon.
|
||||
* @param match The matching mode. KIconLoader::MatchExact returns an icon
|
||||
* only if matches exactly. KIconLoader::MatchBest returns the best matching
|
||||
* icon.
|
||||
* @return An absolute path to the file of the icon if it's found, QString() otherwise.
|
||||
* @see KIconLoader::isValid will return true, and false otherwise.
|
||||
*/
|
||||
QString iconPath(const QString &name, int size, KIconLoader::MatchType match) const;
|
||||
|
||||
/**
|
||||
* Lookup an icon in the theme.
|
||||
* @param name The name of the icon, with extension.
|
||||
* @param size The desired size of the icon.
|
||||
* @param match The matching mode. KIconLoader::MatchExact returns an icon
|
||||
* only if matches exactly. KIconLoader::MatchBest returns the best matching
|
||||
* icon.
|
||||
* @param scale The scale of the icon group.
|
||||
* @return An absolute path to the file of the icon if it's found, QString() otherwise.
|
||||
* @see KIconLoader::isValid will return true, and false otherwise.
|
||||
* @since 5.48
|
||||
*/
|
||||
// TODO KF6 merge iconPath() with and without "scale" and move that argument after "size"
|
||||
QString iconPath(const QString &name, int size, KIconLoader::MatchType match, qreal scale) const;
|
||||
|
||||
/**
|
||||
* Lookup an icon in the theme.
|
||||
* @param name The name of the icon, without extension.
|
||||
* @param size The desired size of the icon.
|
||||
* @param match The matching mode. KIconLoader::MatchExact returns an icon
|
||||
* only if matches exactly. KIconLoader::MatchBest returns the best matching
|
||||
* icon.
|
||||
* @return An absolute path to the file of the icon if it's found, QString() otherwise.
|
||||
* @see KIconLoader::isValid will return true, and false otherwise.
|
||||
*
|
||||
* @since 5.22
|
||||
*/
|
||||
QString iconPathByName(const QString &name, int size, KIconLoader::MatchType match) const;
|
||||
|
||||
/**
|
||||
* Lookup an icon in the theme.
|
||||
* @param name The name of the icon, without extension.
|
||||
* @param size The desired size of the icon.
|
||||
* @param match The matching mode. KIconLoader::MatchExact returns an icon
|
||||
* only if matches exactly. KIconLoader::MatchBest returns the best matching
|
||||
* icon.
|
||||
* @param scale The scale of the icon group.
|
||||
* @return An absolute path to the file of the icon if it's found, QString() otherwise.
|
||||
* @see KIconLoader::isValid will return true, and false otherwise.
|
||||
*
|
||||
* @since 5.48
|
||||
*/
|
||||
// TODO KF6 merge iconPathByName() with and without "scale" and move that argument after "size"
|
||||
QString iconPathByName(const QString &name, int size, KIconLoader::MatchType match, qreal scale) const;
|
||||
|
||||
/**
|
||||
* Returns true if the theme has any icons for the given context.
|
||||
*/
|
||||
bool hasContext(KIconLoader::Context context) const;
|
||||
|
||||
/**
|
||||
* If true, this theme is made of SVG icons that will be colorized following the system
|
||||
* color scheme. This is necessary for monochrome themes that should look visible on both
|
||||
* light and dark color schemes.
|
||||
* @return true if the SVG will be colorized with a stylesheet.
|
||||
* @since 5.22
|
||||
*/
|
||||
bool followsColorScheme() const;
|
||||
|
||||
/**
|
||||
* List all icon themes installed on the system, global and local.
|
||||
* @return the list of all icon themes
|
||||
*/
|
||||
static QStringList list();
|
||||
|
||||
/**
|
||||
* Returns the current icon theme.
|
||||
* @return the name of the current theme
|
||||
*/
|
||||
static QString current();
|
||||
|
||||
/**
|
||||
* Force a current theme and disable automatic resolution of the current
|
||||
* theme in favor of the forced theme.
|
||||
*
|
||||
* To reset a forced theme, simply set an empty themeName.
|
||||
*
|
||||
* @param themeName name of the theme to force as current theme, or an
|
||||
* empty string to unset theme forcing.
|
||||
*
|
||||
* @note This should only be used when a very precise expectation about
|
||||
* the current theme is present. Most notably in unit tests
|
||||
* this can be used to force a given theme.
|
||||
*
|
||||
* @warning A forced theme persists across reconfigure() calls!
|
||||
*
|
||||
* @see current
|
||||
* @since 5.23
|
||||
*/
|
||||
static void forceThemeForTests(const QString &themeName);
|
||||
|
||||
/**
|
||||
* Reconfigure the theme.
|
||||
*/
|
||||
static void reconfigure();
|
||||
|
||||
/**
|
||||
* Returns the default icon theme.
|
||||
* @return the name of the default theme name
|
||||
*/
|
||||
static QString defaultThemeName();
|
||||
|
||||
/**
|
||||
* Enforces the Breeze icon theme (including our KIconEngine for re-coloring).
|
||||
*
|
||||
* If the user has configured a different icon set, that one will be taken.
|
||||
*
|
||||
* (following the settings in the application configuration with fallback to kdeglobals)
|
||||
*
|
||||
* Must be called before the construction of the first Q(Core)Application, as it
|
||||
* might need to modify plugin loading and installs a startup function.
|
||||
*
|
||||
* If the application is already using the KDE platform theme, the icon set will not
|
||||
* be touched and the platform theme will ensure proper theming.
|
||||
*
|
||||
* Does setup the needed KColorSchemeManager to follow the system color mode starting
|
||||
* with version 6.6.
|
||||
*
|
||||
* @since 6.3
|
||||
*/
|
||||
static void initTheme();
|
||||
|
||||
private:
|
||||
std::unique_ptr<class KIconThemePrivate> const d;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2011 Artur Duque de Souza <asouza@kde.org>
|
||||
SPDX-FileCopyrightText: 2022 Alexander Lohnau <alexander.lohnau@gmx.de>
|
||||
SPDX-License-Identifier: LGPL-2.0-only
|
||||
*/
|
||||
|
||||
#ifndef KQUICK_ICON_PROVIDER_H
|
||||
#define KQUICK_ICON_PROVIDER_H
|
||||
|
||||
#include <KIconEffect>
|
||||
#include <KIconLoader>
|
||||
#include <QIcon>
|
||||
#include <QPixmap>
|
||||
#include <QQuickImageProvider>
|
||||
#include <QSize>
|
||||
|
||||
/**
|
||||
* Class which exposes the KIcon* functioality to QML.
|
||||
* For dependency reasons, this is a header-only class.
|
||||
*
|
||||
* This needs to be registered in the engine using the following code:
|
||||
* @code
|
||||
* engine->addImageProvider(QStringLiteral("icon"), new KQuickIconProvider);
|
||||
* @endcode
|
||||
* @since 5.98
|
||||
*/
|
||||
class KQuickIconProvider : public QQuickImageProvider
|
||||
{
|
||||
public:
|
||||
KQuickIconProvider()
|
||||
: QQuickImageProvider(QQuickImageProvider::Pixmap)
|
||||
{
|
||||
}
|
||||
|
||||
QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) override
|
||||
{
|
||||
// We need to handle QIcon::state
|
||||
const QStringList source = id.split(QLatin1Char('/'));
|
||||
|
||||
QPixmap pixmap;
|
||||
if (requestedSize.isValid()) {
|
||||
pixmap = QIcon::fromTheme(source.at(0)).pixmap(requestedSize);
|
||||
} else if (size->isValid()) {
|
||||
pixmap = QIcon::fromTheme(source.at(0)).pixmap(*size);
|
||||
} else {
|
||||
pixmap = QIcon::fromTheme(source.at(0)).pixmap(KIconLoader::global()->currentSize(KIconLoader::Desktop));
|
||||
}
|
||||
|
||||
if (source.size() == 2) {
|
||||
const QString state(source.at(1));
|
||||
int finalState = KIconLoader::DefaultState;
|
||||
|
||||
if (state == QLatin1String("active")) {
|
||||
finalState = KIconLoader::ActiveState;
|
||||
} else if (state == QLatin1String("disabled")) {
|
||||
finalState = KIconLoader::DisabledState;
|
||||
} else if (state == QLatin1String("last")) {
|
||||
finalState = KIconLoader::LastState;
|
||||
}
|
||||
|
||||
// apply the effect for state
|
||||
if (finalState == KIconLoader::ActiveState) {
|
||||
KIconEffect::toActive(pixmap);
|
||||
}
|
||||
|
||||
if (finalState == KIconLoader::DisabledState) {
|
||||
KIconEffect::toDisabled(pixmap);
|
||||
}
|
||||
}
|
||||
|
||||
if (!pixmap.isNull() && size) {
|
||||
*size = pixmap.size();
|
||||
}
|
||||
|
||||
return pixmap;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,5 @@
|
||||
ecm_add_qml_module(iconthemesplugin URI "org.kde.iconthemes" VERSION 1.0 GENERATE_PLUGIN_SOURCE)
|
||||
target_sources(iconthemesplugin PRIVATE icondialog.cpp)
|
||||
target_link_libraries(iconthemesplugin PRIVATE Qt6::Qml Qt6::Quick KF6::IconWidgets)
|
||||
ecm_finalize_qml_module(iconthemesplugin DESTINATION ${KDE_INSTALL_QMLDIR})
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2015 Kai Uwe Broulik <kde@privat.broulik.de>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "icondialog_p.h"
|
||||
|
||||
#include <QQuickItem>
|
||||
#include <QQuickWindow>
|
||||
|
||||
#include <KIconDialog>
|
||||
#include <KIconLoader>
|
||||
#include <QApplication>
|
||||
|
||||
IconDialog::IconDialog(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_dialog(nullptr)
|
||||
, m_iconSize(0)
|
||||
, m_user(false)
|
||||
, m_modality(Qt::WindowModal)
|
||||
{
|
||||
if (qobject_cast<QApplication *>(QCoreApplication::instance())) {
|
||||
m_dialog.reset(new KIconDialog());
|
||||
connect(m_dialog.data(), &KIconDialog::newIconName, this, [this](const QString &newIconName) {
|
||||
if (m_iconName != newIconName) {
|
||||
m_iconName = newIconName;
|
||||
Q_EMIT iconNameChanged(newIconName);
|
||||
}
|
||||
});
|
||||
|
||||
m_dialog->installEventFilter(this);
|
||||
}
|
||||
}
|
||||
|
||||
IconDialog::~IconDialog()
|
||||
{
|
||||
if (m_dialog) {
|
||||
m_dialog->close();
|
||||
}
|
||||
}
|
||||
|
||||
QString IconDialog::iconName() const
|
||||
{
|
||||
return m_iconName;
|
||||
}
|
||||
|
||||
int IconDialog::iconSize() const
|
||||
{
|
||||
return m_iconSize;
|
||||
}
|
||||
|
||||
void IconDialog::setIconSize(int iconSize)
|
||||
{
|
||||
if (m_dialog->iconSize() != iconSize) {
|
||||
m_iconSize = iconSize;
|
||||
Q_EMIT iconSizeChanged(iconSize);
|
||||
}
|
||||
}
|
||||
|
||||
QString IconDialog::title() const
|
||||
{
|
||||
return m_dialog->windowTitle();
|
||||
}
|
||||
|
||||
void IconDialog::setTitle(const QString &title)
|
||||
{
|
||||
if (m_dialog->windowTitle() != title) {
|
||||
m_dialog->setWindowTitle(title);
|
||||
Q_EMIT titleChanged(title);
|
||||
}
|
||||
}
|
||||
|
||||
bool IconDialog::user() const
|
||||
{
|
||||
return m_user;
|
||||
}
|
||||
|
||||
void IconDialog::setUser(bool user)
|
||||
{
|
||||
if (m_user != user) {
|
||||
m_user = user;
|
||||
Q_EMIT userChanged(user);
|
||||
}
|
||||
}
|
||||
|
||||
QString IconDialog::customLocation() const
|
||||
{
|
||||
return m_customLocation;
|
||||
}
|
||||
|
||||
void IconDialog::setCustomLocation(const QString &customLocation)
|
||||
{
|
||||
if (m_customLocation != customLocation) {
|
||||
m_dialog->setCustomLocation(customLocation);
|
||||
|
||||
m_customLocation = customLocation;
|
||||
Q_EMIT customLocationChanged(customLocation);
|
||||
}
|
||||
}
|
||||
|
||||
Qt::WindowModality IconDialog::modality() const
|
||||
{
|
||||
return m_modality;
|
||||
}
|
||||
|
||||
void IconDialog::setModality(Qt::WindowModality modality)
|
||||
{
|
||||
if (m_modality != modality) {
|
||||
m_modality = modality;
|
||||
Q_EMIT modalityChanged(modality);
|
||||
}
|
||||
}
|
||||
|
||||
bool IconDialog::visible() const
|
||||
{
|
||||
return m_dialog->isVisible();
|
||||
}
|
||||
|
||||
void IconDialog::setVisible(bool visible)
|
||||
{
|
||||
if (visible) {
|
||||
open();
|
||||
} else {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
void IconDialog::open()
|
||||
{
|
||||
if (m_dialog->isVisible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QQuickItem *parentItem = qobject_cast<QQuickItem *>(parent());
|
||||
QQuickWindow *parentWindow = (parentItem ? parentItem->window() : qobject_cast<QQuickWindow *>(parent()));
|
||||
|
||||
if (m_modality == Qt::NonModal) {
|
||||
m_dialog->setModal(false);
|
||||
} else if (m_modality == Qt::WindowModal) {
|
||||
m_dialog->winId(); // needed to get the windowHandle prior to showing
|
||||
m_dialog->windowHandle()->setTransientParent(parentWindow);
|
||||
m_dialog->setModal(false); // WindowModal does not unset the overall modality
|
||||
} else if (m_modality == Qt::ApplicationModal) {
|
||||
m_dialog->setModal(true);
|
||||
}
|
||||
|
||||
m_dialog->setWindowModality(m_modality);
|
||||
|
||||
m_dialog->setup(KIconLoader::Desktop, KIconLoader::Application, false, m_iconSize, m_user);
|
||||
|
||||
m_dialog->show();
|
||||
}
|
||||
|
||||
void IconDialog::close()
|
||||
{
|
||||
if (!m_dialog->isVisible()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_dialog->hide();
|
||||
}
|
||||
|
||||
bool IconDialog::eventFilter(QObject *watched, QEvent *event)
|
||||
{
|
||||
if (watched == m_dialog.data() && (event->type() == QEvent::Show || event->type() == QEvent::Hide)) {
|
||||
Q_EMIT visibleChanged();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#include "moc_icondialog_p.cpp"
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2015 Kai Uwe Broulik <kde@privat.broulik.de>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef ICONDIALOG_H
|
||||
#define ICONDIALOG_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <qqmlregistration.h>
|
||||
|
||||
class KIconDialog;
|
||||
|
||||
class IconDialog : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_ELEMENT
|
||||
|
||||
/**
|
||||
* The name or path of the icon the user has selected
|
||||
*/
|
||||
Q_PROPERTY(QString iconName READ iconName NOTIFY iconNameChanged)
|
||||
/**
|
||||
* The desired size of icons
|
||||
*/
|
||||
Q_PROPERTY(int iconSize READ iconSize WRITE setIconSize NOTIFY iconSizeChanged)
|
||||
/**
|
||||
* The title to use for the dialog
|
||||
*/
|
||||
Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged)
|
||||
/**
|
||||
* Begin with the "user icons" instead of "system icons"
|
||||
*/
|
||||
Q_PROPERTY(bool user READ user WRITE setUser NOTIFY userChanged)
|
||||
/**
|
||||
* Use a custom location, only local directory paths are allowed
|
||||
*/
|
||||
Q_PROPERTY(QString customLocation READ customLocation WRITE setCustomLocation NOTIFY customLocationChanged)
|
||||
/**
|
||||
* Window modality, default is Qt.NonModal
|
||||
*/
|
||||
Q_PROPERTY(Qt::WindowModality modality READ modality WRITE setModality NOTIFY modalityChanged)
|
||||
/**
|
||||
* Whether the dialog is currently visible, setting this property to true
|
||||
* is the same as calling show()
|
||||
*/
|
||||
Q_PROPERTY(bool visible READ visible WRITE setVisible NOTIFY visibleChanged)
|
||||
|
||||
public:
|
||||
explicit IconDialog(QObject *parent = nullptr);
|
||||
~IconDialog() override;
|
||||
|
||||
QString iconName() const;
|
||||
|
||||
int iconSize() const;
|
||||
void setIconSize(int iconSize);
|
||||
|
||||
QString title() const;
|
||||
void setTitle(const QString &title);
|
||||
|
||||
bool user() const;
|
||||
void setUser(bool user);
|
||||
|
||||
QString customLocation() const;
|
||||
void setCustomLocation(const QString &customLocation);
|
||||
|
||||
Qt::WindowModality modality() const;
|
||||
void setModality(Qt::WindowModality modality);
|
||||
|
||||
bool visible() const;
|
||||
void setVisible(bool visible);
|
||||
|
||||
Q_INVOKABLE void open();
|
||||
Q_INVOKABLE void close();
|
||||
|
||||
Q_SIGNALS:
|
||||
void iconNameChanged(const QString &iconName);
|
||||
void iconSizeChanged(int iconSize);
|
||||
void titleChanged(const QString &title);
|
||||
void userChanged(bool user);
|
||||
void customLocationChanged(const QString &customLocation);
|
||||
void modalityChanged(Qt::WindowModality modality);
|
||||
void visibleChanged();
|
||||
|
||||
private:
|
||||
bool eventFilter(QObject *watched, QEvent *event) override;
|
||||
|
||||
QScopedPointer<KIconDialog> m_dialog;
|
||||
|
||||
QString m_iconName;
|
||||
int m_iconSize;
|
||||
bool m_user;
|
||||
QString m_customLocation;
|
||||
Qt::WindowModality m_modality;
|
||||
};
|
||||
|
||||
#endif // ICONDIALOG_H
|
||||
@@ -0,0 +1,5 @@
|
||||
add_executable(kiconfinder6 kiconfinder.cpp)
|
||||
ecm_mark_nongui_executable(kiconfinder6)
|
||||
target_link_libraries(kiconfinder6 Qt6::Gui KF6IconThemes)
|
||||
|
||||
install(TARGETS kiconfinder6 ${KF_INSTALL_TARGETS_DEFAULT_ARGS})
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
This file is part of the KDE project
|
||||
SPDX-FileCopyrightText: 2008 David Faure <faure@kde.org>
|
||||
|
||||
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
|
||||
*/
|
||||
|
||||
#include <kiconloader.h>
|
||||
#include <kiconthemes_version.h>
|
||||
|
||||
#include <QCommandLineParser>
|
||||
#include <QGuiApplication>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QGuiApplication app(argc, argv);
|
||||
app.setApplicationName(QStringLiteral("kiconfinder"));
|
||||
app.setApplicationVersion(QStringLiteral(KICONTHEMES_VERSION_STRING));
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription(app.translate("main", "Finds an icon based on its name"));
|
||||
parser.addPositionalArgument(QStringLiteral("iconname"), app.translate("main", "The icon name to look for"));
|
||||
parser.addHelpOption();
|
||||
|
||||
parser.process(app);
|
||||
if (parser.positionalArguments().isEmpty()) {
|
||||
parser.showHelp();
|
||||
}
|
||||
|
||||
for (const QString &iconName : parser.positionalArguments()) {
|
||||
const QString icon = KIconLoader::global()->iconPath(iconName, KIconLoader::Desktop /*TODO configurable*/, true);
|
||||
if (!icon.isEmpty()) {
|
||||
printf("%s\n", icon.toLocal8Bit().constData());
|
||||
} else {
|
||||
return 1; // error
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
add_executable(ksvg2icns ksvg2icns.cpp)
|
||||
ecm_mark_nongui_executable(ksvg2icns)
|
||||
target_link_libraries(ksvg2icns Qt6::Gui Qt6::Svg)
|
||||
|
||||
install(TARGETS ksvg2icns ${KF_INSTALL_TARGETS_DEFAULT_ARGS})
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Harald Fernengel <harry@kdevelop.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
|
||||
/* This tool converts an svg to a Mac OS X icns file.
|
||||
* Note: Requires the 'iconutil' Mac OS X binary
|
||||
*/
|
||||
|
||||
#include <QCommandLineParser>
|
||||
#include <QFileInfo>
|
||||
#include <QProcess>
|
||||
#include <QTemporaryDir>
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <QPainter>
|
||||
#include <QStandardPaths>
|
||||
#include <QSvgRenderer>
|
||||
|
||||
#include "../../kiconthemes_version.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* clang-format off */
|
||||
#define EXIT_ON_ERROR(isOk, ...) \
|
||||
do { \
|
||||
if (!(isOk)) { \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
return 1; \
|
||||
} \
|
||||
} while (false);
|
||||
/* clang-format on */
|
||||
|
||||
static bool writeImage(QSvgRenderer &svg, int size, const QString &outFile1, const QString &outFile2 = QString())
|
||||
{
|
||||
QImage out(size, size, QImage::Format_ARGB32);
|
||||
out.fill(Qt::transparent);
|
||||
|
||||
QPainter painter(&out);
|
||||
svg.setAspectRatioMode(Qt::KeepAspectRatio);
|
||||
svg.render(&painter);
|
||||
painter.end();
|
||||
|
||||
if (!out.save(outFile1)) {
|
||||
fprintf(stderr, "Unable to write %s\n", qPrintable(outFile1));
|
||||
return false;
|
||||
}
|
||||
if (!outFile2.isEmpty() && !out.save(outFile2)) {
|
||||
fprintf(stderr, "Unable to write %s\n", qPrintable(outFile2));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QGuiApplication app(argc, argv);
|
||||
|
||||
app.setApplicationName(QStringLiteral("ksvg2icns"));
|
||||
app.setApplicationVersion(QStringLiteral(KICONTHEMES_VERSION_STRING));
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription(app.translate("main", "Creates an icns file from an svg image"));
|
||||
parser.addPositionalArgument("iconname", app.translate("main", "The svg icon to convert"));
|
||||
parser.addHelpOption();
|
||||
|
||||
parser.process(app);
|
||||
if (parser.positionalArguments().isEmpty()) {
|
||||
parser.showHelp();
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool isOk;
|
||||
|
||||
// create a temporary dir to create an iconset
|
||||
QTemporaryDir tmpDir(QDir::tempPath() + QStringLiteral("/ksvg2icns"));
|
||||
|
||||
isOk = tmpDir.isValid();
|
||||
EXIT_ON_ERROR(isOk, "Unable to create temporary directory\n");
|
||||
|
||||
const QString outPath = tmpDir.filePath(QStringLiteral("out.iconset"));
|
||||
|
||||
isOk = QDir(tmpDir.path()).mkpath(outPath);
|
||||
EXIT_ON_ERROR(isOk, "Unable to create out.iconset directory\n");
|
||||
|
||||
const QStringList &args = app.arguments();
|
||||
EXIT_ON_ERROR(args.size() == 2, "Usage: %s svg-image\n", qPrintable(args.value(0)));
|
||||
|
||||
const QString &svgFileName = args.at(1);
|
||||
|
||||
// open the actual svg file
|
||||
QSvgRenderer svg;
|
||||
isOk = svg.load(svgFileName);
|
||||
EXIT_ON_ERROR(isOk, "Unable to load %s\n", qPrintable(svgFileName));
|
||||
|
||||
// The sizes are from:
|
||||
// https://developer.apple.com/library/mac/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Optimizing/Optimizing.html
|
||||
|
||||
struct OutFiles {
|
||||
int size;
|
||||
QString out1;
|
||||
QString out2;
|
||||
};
|
||||
|
||||
// create the pngs in various resolutions
|
||||
const OutFiles outFiles[] = {{1024, outPath + QStringLiteral("/icon_512x512@2x.png"), QString()},
|
||||
{512, outPath + QStringLiteral("/icon_512x512.png"), outPath + QStringLiteral("/icon_256x256@2x.png")},
|
||||
{256, outPath + QStringLiteral("/icon_256x256.png"), outPath + QStringLiteral("/icon_128x128@2x.png")},
|
||||
{128, outPath + QStringLiteral("/icon_128x128.png"), QString()},
|
||||
{64, outPath + QStringLiteral("/icon_32x32@2x.png"), QString()},
|
||||
{32, outPath + QStringLiteral("/icon_32x32.png"), outPath + QStringLiteral("/icon_16x16@2x.png")},
|
||||
{16, outPath + QStringLiteral("/icon_16x16.png"), QString()}};
|
||||
|
||||
for (const OutFiles &outFile : outFiles) {
|
||||
isOk = writeImage(svg, outFile.size, outFile.out1, outFile.out2);
|
||||
if (!isOk) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// convert the iconset to icns using the "iconutil" command
|
||||
const QString iconutilExec = QStandardPaths::findExecutable(QStringLiteral("iconutil"));
|
||||
if (iconutilExec.isEmpty()) {
|
||||
EXIT_ON_ERROR(false, "Could not find iconutil executable in PATH.\n");
|
||||
}
|
||||
|
||||
const QString outIcns = QFileInfo(svgFileName).baseName() + QStringLiteral(".icns");
|
||||
|
||||
const QStringList utilArgs = QStringList() << "-c"
|
||||
<< "icns"
|
||||
<< "-o" << outIcns << outPath;
|
||||
|
||||
QProcess iconUtil;
|
||||
|
||||
iconUtil.start(iconutilExec, utilArgs, QIODevice::ReadOnly);
|
||||
isOk = iconUtil.waitForFinished(-1);
|
||||
EXIT_ON_ERROR(isOk, "Unable to launch iconutil: %s\n", qPrintable(iconUtil.errorString()));
|
||||
|
||||
EXIT_ON_ERROR(iconUtil.exitStatus() == QProcess::NormalExit, "iconutil crashed!\n");
|
||||
EXIT_ON_ERROR(iconUtil.exitCode() == 0, "iconutil returned %d\n", iconUtil.exitCode());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
add_library(KF6IconWidgets)
|
||||
add_library(KF6::IconWidgets ALIAS KF6IconWidgets)
|
||||
|
||||
set_target_properties(KF6IconWidgets PROPERTIES
|
||||
VERSION ${KICONTHEMES_VERSION}
|
||||
SOVERSION ${KICONTHEMES_SOVERSION}
|
||||
EXPORT_NAME IconWidgets
|
||||
)
|
||||
|
||||
target_sources(KF6IconWidgets PRIVATE
|
||||
kiconbutton.cpp
|
||||
kiconbutton.h
|
||||
kicondialog.cpp
|
||||
kicondialog.h
|
||||
kicondialogmodel_p.h
|
||||
kicondialog_p.h
|
||||
kpixmapsequenceloader.h
|
||||
kpixmapsequenceloader.cpp
|
||||
)
|
||||
|
||||
ki18n_wrap_ui(KF6IconWidgets kicondialog.ui)
|
||||
|
||||
ecm_generate_export_header(KF6IconWidgets
|
||||
BASE_NAME KIconWidgets
|
||||
GROUP_BASE_NAME KF
|
||||
VERSION ${KF_VERSION}
|
||||
USE_VERSION_HEADER
|
||||
VERSION_BASE_NAME KIconThemes
|
||||
DEPRECATED_BASE_VERSION 0
|
||||
DEPRECATION_VERSIONS
|
||||
EXCLUDE_DEPRECATED_BEFORE_AND_AT ${EXCLUDE_DEPRECATED_BEFORE_AND_AT}
|
||||
)
|
||||
|
||||
target_include_directories(KF6IconWidgets INTERFACE "$<INSTALL_INTERFACE:${KDE_INSTALL_INCLUDEDIR_KF}/KIconWidgets>")
|
||||
|
||||
target_link_libraries(KF6IconWidgets
|
||||
PUBLIC
|
||||
Qt6::Widgets
|
||||
KF6::IconThemes
|
||||
PRIVATE
|
||||
Qt6::GuiPrivate
|
||||
Qt6::Svg
|
||||
KF6::I18n # for i18n in KIconDialog
|
||||
KF6::ConfigGui # for KStandardActions
|
||||
KF6::WidgetsAddons # for KPixmapSequence
|
||||
)
|
||||
|
||||
ecm_generate_headers(KIconWidgets_HEADERS
|
||||
HEADER_NAMES
|
||||
KIconButton
|
||||
KIconDialog
|
||||
KPixmapSequenceLoader
|
||||
|
||||
REQUIRED_HEADERS KIconWidgets_HEADERS
|
||||
)
|
||||
|
||||
install(TARGETS KF6IconWidgets EXPORT KF6IconThemesTargets ${KF_INSTALL_TARGETS_DEFAULT_ARGS})
|
||||
|
||||
install(FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/kiconwidgets_export.h
|
||||
${KIconWidgets_HEADERS}
|
||||
DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF}/KIconWidgets COMPONENT Devel
|
||||
)
|
||||
|
||||
if(BUILD_DESIGNERPLUGIN)
|
||||
add_subdirectory(designer)
|
||||
endif()
|
||||
|
||||
if(BUILD_QCH)
|
||||
ecm_add_qch(
|
||||
KF6IconWidgets_QCH
|
||||
NAME KIconWidgets
|
||||
BASE_NAME KF6IconWidgets
|
||||
VERSION ${KF_VERSION}
|
||||
ORG_DOMAIN org.kde
|
||||
SOURCES # using only public headers, to cover only public API
|
||||
${KIconWidgets_HEADERS}
|
||||
MD_MAINPAGE "${CMAKE_SOURCE_DIR}/README.md"
|
||||
IMAGE_DIRS "${CMAKE_SOURCE_DIR}/docs/pics"
|
||||
LINK_QCHS
|
||||
Qt6Widgets_QCH
|
||||
INCLUDE_DIRS
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
BLANK_MACROS
|
||||
KICONWIDGETS_EXPORT
|
||||
KICONWIDGETS_DEPRECATED
|
||||
KICONWIDGETS_DEPRECATED_EXPORT
|
||||
"KICONWIDGETS_DEPRECATED_VERSION(x, y, t)"
|
||||
"KICONWIDGETS_DEPRECATED_VERSION_BELATED(x, y, xt, yt, t)"
|
||||
"KICONWIDGETS_ENUMERATOR_DEPRECATED_VERSION(x, y, t)"
|
||||
"KICONWIDGETS_ENUMERATOR_DEPRECATED_VERSION_BELATED(x, y, xt, yt, t)"
|
||||
TAGFILE_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR}
|
||||
QCH_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR}
|
||||
COMPONENT Devel
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
include(ECMAddQtDesignerPlugin)
|
||||
|
||||
ecm_qtdesignerplugin_widget(KIconButton
|
||||
TOOLTIP "Button for selecting an icon (KF6)"
|
||||
GROUP "Buttons (KF6)"
|
||||
)
|
||||
|
||||
ecm_add_qtdesignerplugin(kiconthemeswidgets
|
||||
NAME KIconThemesWidgets
|
||||
OUTPUT_NAME kiconthemes6widgets
|
||||
WIDGETS
|
||||
KIconButton
|
||||
LINK_LIBRARIES
|
||||
KF6::IconWidgets
|
||||
INSTALL_DESTINATION "${KDE_INSTALL_QTPLUGINDIR}/designer"
|
||||
COMPONENT Devel
|
||||
)
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
|
||||
This file is part of the KDE project, module kfile.
|
||||
SPDX-FileCopyrightText: 2000 Geert Jansen <jansen@kde.org>
|
||||
SPDX-FileCopyrightText: 2000 Kurt Granroth <granroth@kde.org>
|
||||
SPDX-FileCopyrightText: 1997 Christoph Neerfeld <chris@kde.org>
|
||||
SPDX-FileCopyrightText: 2002 Carsten Pfeiffer <pfeiffer@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-only
|
||||
*/
|
||||
|
||||
#include "kiconbutton.h"
|
||||
|
||||
#include <QFileInfo>
|
||||
|
||||
#include <KLocalizedString>
|
||||
|
||||
#include "kicondialog.h"
|
||||
|
||||
class KIconButtonPrivate
|
||||
{
|
||||
public:
|
||||
KIconButtonPrivate(KIconButton *qq, KIconLoader *loader);
|
||||
~KIconButtonPrivate();
|
||||
|
||||
KIconDialog *dialog();
|
||||
|
||||
// slots
|
||||
void _k_slotChangeIcon();
|
||||
void _k_newIconName(const QString &);
|
||||
|
||||
KIconButton *q;
|
||||
|
||||
int iconSize;
|
||||
int buttonIconSize;
|
||||
bool m_bStrictIconSize;
|
||||
|
||||
bool mbUser;
|
||||
KIconLoader::Group mGroup;
|
||||
KIconLoader::Context mContext;
|
||||
|
||||
QString mIcon;
|
||||
KIconDialog *mpDialog;
|
||||
KIconLoader *mpLoader;
|
||||
};
|
||||
|
||||
/*
|
||||
* KIconButton: A "choose icon" pushbutton.
|
||||
*/
|
||||
|
||||
KIconButton::KIconButton(QWidget *parent)
|
||||
: QPushButton(parent)
|
||||
, d(new KIconButtonPrivate(this, KIconLoader::global()))
|
||||
{
|
||||
QPushButton::setIconSize(QSize(48, 48));
|
||||
}
|
||||
|
||||
KIconButtonPrivate::KIconButtonPrivate(KIconButton *qq, KIconLoader *loader)
|
||||
: q(qq)
|
||||
{
|
||||
m_bStrictIconSize = false;
|
||||
iconSize = 0; // let KIconLoader choose the default
|
||||
buttonIconSize = -1; // When buttonIconSize is -1, iconSize will be used for the button
|
||||
|
||||
mGroup = KIconLoader::Desktop;
|
||||
mContext = KIconLoader::Application;
|
||||
mbUser = false;
|
||||
|
||||
mpLoader = loader;
|
||||
mpDialog = nullptr;
|
||||
QObject::connect(q, &KIconButton::clicked, q, [this]() {
|
||||
_k_slotChangeIcon();
|
||||
});
|
||||
|
||||
q->setToolTip(i18nc("@info:tooltip", "Select Icon…"));
|
||||
}
|
||||
|
||||
KIconButtonPrivate::~KIconButtonPrivate()
|
||||
{
|
||||
delete mpDialog;
|
||||
}
|
||||
|
||||
KIconDialog *KIconButtonPrivate::dialog()
|
||||
{
|
||||
if (!mpDialog) {
|
||||
mpDialog = new KIconDialog(q);
|
||||
QObject::connect(mpDialog, &KIconDialog::newIconName, q, [this](const QString &iconName) {
|
||||
_k_newIconName(iconName);
|
||||
});
|
||||
}
|
||||
|
||||
return mpDialog;
|
||||
}
|
||||
|
||||
KIconButton::~KIconButton() = default;
|
||||
|
||||
void KIconButton::setStrictIconSize(bool b)
|
||||
{
|
||||
d->m_bStrictIconSize = b;
|
||||
}
|
||||
|
||||
bool KIconButton::strictIconSize() const
|
||||
{
|
||||
return d->m_bStrictIconSize;
|
||||
}
|
||||
|
||||
void KIconButton::setIconSize(int size)
|
||||
{
|
||||
if (d->buttonIconSize == -1) {
|
||||
QPushButton::setIconSize(QSize(size, size));
|
||||
}
|
||||
|
||||
d->iconSize = size;
|
||||
}
|
||||
|
||||
int KIconButton::iconSize() const
|
||||
{
|
||||
return d->iconSize;
|
||||
}
|
||||
|
||||
void KIconButton::setButtonIconSize(int size)
|
||||
{
|
||||
QPushButton::setIconSize(QSize(size, size));
|
||||
d->buttonIconSize = size;
|
||||
}
|
||||
|
||||
int KIconButton::buttonIconSize() const
|
||||
{
|
||||
return QPushButton::iconSize().height();
|
||||
}
|
||||
|
||||
void KIconButton::setIconType(KIconLoader::Group group, KIconLoader::Context context, bool user)
|
||||
{
|
||||
d->mGroup = group;
|
||||
d->mContext = context;
|
||||
d->mbUser = user;
|
||||
}
|
||||
|
||||
void KIconButton::setIcon(const QString &icon)
|
||||
{
|
||||
d->mIcon = icon;
|
||||
setIcon(QIcon::fromTheme(d->mIcon));
|
||||
|
||||
if (d->mbUser) {
|
||||
d->dialog()->setCustomLocation(QFileInfo(d->mpLoader->iconPath(d->mIcon, d->mGroup, true)).absolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
void KIconButton::setIcon(const QIcon &icon)
|
||||
{
|
||||
QPushButton::setIcon(icon);
|
||||
}
|
||||
|
||||
void KIconButton::resetIcon()
|
||||
{
|
||||
d->mIcon.clear();
|
||||
setIcon(QIcon());
|
||||
}
|
||||
|
||||
const QString &KIconButton::icon() const
|
||||
{
|
||||
return d->mIcon;
|
||||
}
|
||||
|
||||
void KIconButtonPrivate::_k_slotChangeIcon()
|
||||
{
|
||||
dialog()->setup(mGroup, mContext, m_bStrictIconSize, iconSize, mbUser);
|
||||
dialog()->setSelectedIcon(mIcon);
|
||||
dialog()->showDialog();
|
||||
}
|
||||
|
||||
void KIconButtonPrivate::_k_newIconName(const QString &name)
|
||||
{
|
||||
if (name.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
q->setIcon(QIcon::fromTheme(name));
|
||||
mIcon = name;
|
||||
|
||||
if (mbUser) {
|
||||
mpDialog->setCustomLocation(QFileInfo(mpLoader->iconPath(mIcon, mGroup, true)).absolutePath());
|
||||
}
|
||||
|
||||
Q_EMIT q->iconChanged(name);
|
||||
}
|
||||
|
||||
#include "moc_kiconbutton.cpp"
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
|
||||
This file is part of the KDE project, module kfile.
|
||||
SPDX-FileCopyrightText: 2000 Geert Jansen <jansen@kde.org>
|
||||
SPDX-FileCopyrightText: 2000 Kurt Granroth <granroth@kde.org>
|
||||
SPDX-FileCopyrightText: 1997 Christoph Neerfeld <chris@kde.org>
|
||||
SPDX-FileCopyrightText: 2002 Carsten Pfeiffer <pfeiffer@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-only
|
||||
*/
|
||||
|
||||
#ifndef KICONBUTTON_H
|
||||
#define KICONBUTTON_H
|
||||
|
||||
#include "kiconwidgets_export.h"
|
||||
|
||||
#include <QPushButton>
|
||||
#include <memory>
|
||||
|
||||
#include <kiconloader.h>
|
||||
|
||||
/**
|
||||
* @class KIconButton kiconbutton.h KIconButton
|
||||
*
|
||||
* A pushbutton for choosing an icon. Pressing on the button will open a
|
||||
* KIconDialog for the user to select an icon. The current icon will be
|
||||
* displayed on the button.
|
||||
*
|
||||
* @see KIconDialog
|
||||
* @short A push button that allows selection of an icon.
|
||||
*/
|
||||
class KICONWIDGETS_EXPORT KIconButton : public QPushButton
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString icon READ icon WRITE setIcon RESET resetIcon NOTIFY iconChanged USER true)
|
||||
Q_PROPERTY(int iconSize READ iconSize WRITE setIconSize)
|
||||
Q_PROPERTY(bool strictIconSize READ strictIconSize WRITE setStrictIconSize)
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructs a KIconButton using the global icon loader.
|
||||
*
|
||||
* @param parent The parent widget.
|
||||
*/
|
||||
explicit KIconButton(QWidget *parent = nullptr);
|
||||
|
||||
/**
|
||||
* Destructs the button.
|
||||
*/
|
||||
~KIconButton() override;
|
||||
|
||||
/**
|
||||
* Sets a strict icon size policy for allowed icons. When true,
|
||||
* only icons of the specified group's size in setIconType() are allowed,
|
||||
* and only icons of that size will be shown in the icon dialog.
|
||||
*/
|
||||
void setStrictIconSize(bool b);
|
||||
/**
|
||||
* Returns true if a strict icon size policy is set.
|
||||
*/
|
||||
bool strictIconSize() const;
|
||||
|
||||
/**
|
||||
* Sets the icon group and context. Use KIconLoader::NoGroup if you want to
|
||||
* allow icons for any group in the given context.
|
||||
*/
|
||||
void setIconType(KIconLoader::Group group, KIconLoader::Context context, bool user = false);
|
||||
|
||||
/**
|
||||
* Sets the button's initial icon.
|
||||
*/
|
||||
void setIcon(const QString &icon);
|
||||
|
||||
void setIcon(const QIcon &icon);
|
||||
|
||||
/**
|
||||
* Resets the icon (reverts to an empty button).
|
||||
*/
|
||||
void resetIcon();
|
||||
|
||||
/**
|
||||
* Returns the name of the selected icon.
|
||||
*/
|
||||
const QString &icon() const;
|
||||
|
||||
/**
|
||||
* Sets the size of the icon to be shown / selected.
|
||||
* @see KIconLoader::StdSizes
|
||||
* @see iconSize
|
||||
*/
|
||||
void setIconSize(int size);
|
||||
/**
|
||||
* Returns the icon size set via setIconSize() or 0, if the default
|
||||
* icon size will be used.
|
||||
*/
|
||||
int iconSize() const;
|
||||
|
||||
/**
|
||||
* Sets the size of the icon to be shown on the button.
|
||||
* @see KIconLoader::StdSizes
|
||||
* @see buttonIconSize
|
||||
* @since 4.1
|
||||
*/
|
||||
void setButtonIconSize(int size);
|
||||
/**
|
||||
* Returns the button's icon size.
|
||||
* @since 4.1
|
||||
*/
|
||||
int buttonIconSize() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Emitted when the icon has changed.
|
||||
*/
|
||||
void iconChanged(const QString &icon);
|
||||
|
||||
private:
|
||||
std::unique_ptr<class KIconButtonPrivate> const d;
|
||||
|
||||
Q_DISABLE_COPY(KIconButton)
|
||||
};
|
||||
|
||||
#endif // KICONBUTTON_H
|
||||
@@ -0,0 +1,754 @@
|
||||
/*
|
||||
|
||||
This file is part of the KDE project, module kfile.
|
||||
SPDX-FileCopyrightText: 2000 Geert Jansen <jansen@kde.org>
|
||||
SPDX-FileCopyrightText: 2000 Kurt Granroth <granroth@kde.org>
|
||||
SPDX-FileCopyrightText: 1997 Christoph Neerfeld <chris@kde.org>
|
||||
SPDX-FileCopyrightText: 2002 Carsten Pfeiffer <pfeiffer@kde.org>
|
||||
SPDX-FileCopyrightText: 2021 Kai Uwe Broulik <kde@broulik.de>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-only
|
||||
*/
|
||||
|
||||
#include "kicondialog.h"
|
||||
#include "kicondialog_p.h"
|
||||
#include "kicondialogmodel_p.h"
|
||||
|
||||
#include <KLazyLocalizedString>
|
||||
#include <KLocalizedString>
|
||||
#include <KStandardActions>
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QActionGroup>
|
||||
#include <QApplication>
|
||||
#include <QComboBox>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QFileInfo>
|
||||
#include <QGraphicsOpacityEffect>
|
||||
#include <QLabel>
|
||||
#include <QList>
|
||||
#include <QMenu>
|
||||
#include <QPainter>
|
||||
#include <QScrollBar>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QStandardItemModel> // for manipulatig QComboBox
|
||||
#include <QStandardPaths>
|
||||
#include <QSvgRenderer>
|
||||
|
||||
#include <algorithm>
|
||||
#include <math.h>
|
||||
|
||||
static const int s_edgePad = 3;
|
||||
|
||||
class KIconDialogSortFilterProxyModel : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit KIconDialogSortFilterProxyModel(QObject *parent);
|
||||
|
||||
enum SymbolicIcons { AllSymbolicIcons, OnlySymbolicIcons, NoSymbolicIcons };
|
||||
|
||||
void setSymbolicIcons(SymbolicIcons symbolicIcons);
|
||||
void setHasSymbolicIcon(bool hasSymbolicIcon);
|
||||
|
||||
protected:
|
||||
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
|
||||
|
||||
private:
|
||||
SymbolicIcons m_symbolicIcons = AllSymbolicIcons;
|
||||
bool m_hasSymbolicIcon = false;
|
||||
};
|
||||
|
||||
KIconDialogSortFilterProxyModel::KIconDialogSortFilterProxyModel(QObject *parent)
|
||||
: QSortFilterProxyModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void KIconDialogSortFilterProxyModel::setSymbolicIcons(SymbolicIcons symbolicIcons)
|
||||
{
|
||||
if (m_symbolicIcons == symbolicIcons) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_symbolicIcons = symbolicIcons;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void KIconDialogSortFilterProxyModel::setHasSymbolicIcon(bool hasSymbolicIcon)
|
||||
{
|
||||
if (m_hasSymbolicIcon == hasSymbolicIcon) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_hasSymbolicIcon = hasSymbolicIcon;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
bool KIconDialogSortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
|
||||
{
|
||||
if (m_hasSymbolicIcon) {
|
||||
if (m_symbolicIcons == OnlySymbolicIcons || m_symbolicIcons == NoSymbolicIcons) {
|
||||
const QString display = sourceModel()->index(source_row, 0, source_parent).data(Qt::DisplayRole).toString();
|
||||
const bool isSymbolic = display.endsWith(KIconDialogModel::symbolicSuffix());
|
||||
if ((m_symbolicIcons == OnlySymbolicIcons && !isSymbolic) || (m_symbolicIcons == NoSymbolicIcons && isSymbolic)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
|
||||
}
|
||||
|
||||
KIconDialogModel::KIconDialogModel(KIconLoader *loader, QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
, m_loader(loader)
|
||||
{
|
||||
}
|
||||
|
||||
KIconDialogModel::~KIconDialogModel() = default;
|
||||
|
||||
qreal KIconDialogModel::devicePixelRatio() const
|
||||
{
|
||||
return m_dpr;
|
||||
}
|
||||
|
||||
void KIconDialogModel::setDevicePixelRatio(qreal dpr)
|
||||
{
|
||||
m_dpr = dpr;
|
||||
}
|
||||
|
||||
QSize KIconDialogModel::iconSize() const
|
||||
{
|
||||
return m_iconSize;
|
||||
}
|
||||
|
||||
void KIconDialogModel::setIconSize(const QSize &iconSize)
|
||||
{
|
||||
m_iconSize = iconSize;
|
||||
}
|
||||
|
||||
QLatin1String KIconDialogModel::symbolicSuffix()
|
||||
{
|
||||
return QLatin1String("-symbolic");
|
||||
}
|
||||
|
||||
bool KIconDialogModel::hasSymbolicIcon() const
|
||||
{
|
||||
return m_hasSymbolicIcon;
|
||||
}
|
||||
|
||||
void KIconDialogModel::load(const QStringList &paths)
|
||||
{
|
||||
beginResetModel();
|
||||
|
||||
const bool oldSymbolic = m_hasSymbolicIcon;
|
||||
m_hasSymbolicIcon = false;
|
||||
|
||||
m_data.clear();
|
||||
m_data.reserve(paths.count());
|
||||
|
||||
for (const QString &path : paths) {
|
||||
const QFileInfo fi(path);
|
||||
|
||||
KIconDialogModelData item;
|
||||
item.name = fi.completeBaseName();
|
||||
item.path = path;
|
||||
// pixmap is created on demand
|
||||
|
||||
if (!m_hasSymbolicIcon && item.name.endsWith(symbolicSuffix())) {
|
||||
m_hasSymbolicIcon = true;
|
||||
}
|
||||
|
||||
m_data.append(item);
|
||||
}
|
||||
|
||||
endResetModel();
|
||||
|
||||
if (oldSymbolic != m_hasSymbolicIcon) {
|
||||
Q_EMIT hasSymbolicIconChanged(m_hasSymbolicIcon);
|
||||
}
|
||||
}
|
||||
|
||||
int KIconDialogModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.isValid()) {
|
||||
return 0;
|
||||
}
|
||||
return m_data.count();
|
||||
}
|
||||
|
||||
QVariant KIconDialogModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid)) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
const auto &item = m_data.at(index.row());
|
||||
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
return item.name;
|
||||
case Qt::DecorationRole:
|
||||
if (item.pixmap.isNull()) {
|
||||
const_cast<KIconDialogModel *>(this)->loadPixmap(index);
|
||||
}
|
||||
return item.pixmap;
|
||||
case Qt::ToolTipRole:
|
||||
return item.name;
|
||||
case PathRole:
|
||||
return item.path;
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void KIconDialogModel::loadPixmap(const QModelIndex &index)
|
||||
{
|
||||
Q_ASSERT(index.isValid());
|
||||
|
||||
auto &item = m_data[index.row()];
|
||||
Q_ASSERT(item.pixmap.isNull());
|
||||
|
||||
const auto dpr = devicePixelRatio();
|
||||
|
||||
item.pixmap = m_loader->loadScaledIcon(item.path, KIconLoader::Desktop, dpr, iconSize(), KIconLoader::DefaultState, {}, nullptr, true);
|
||||
item.pixmap.setDevicePixelRatio(dpr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Qt allocates very little horizontal space for the icon name,
|
||||
* even if the gridSize width is large. This delegate allocates
|
||||
* the gridSize width (minus some padding) for the icon and icon name.
|
||||
*/
|
||||
class KIconCanvasDelegate : public QAbstractItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
KIconCanvasDelegate(QListView *parent, QAbstractItemDelegate *defaultDelegate);
|
||||
~KIconCanvasDelegate() override
|
||||
{
|
||||
}
|
||||
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
||||
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
||||
|
||||
private:
|
||||
QAbstractItemDelegate *m_defaultDelegate = nullptr;
|
||||
};
|
||||
|
||||
KIconCanvasDelegate::KIconCanvasDelegate(QListView *parent, QAbstractItemDelegate *defaultDelegate)
|
||||
: QAbstractItemDelegate(parent)
|
||||
{
|
||||
m_defaultDelegate = defaultDelegate;
|
||||
}
|
||||
|
||||
void KIconCanvasDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||
{
|
||||
auto *canvas = static_cast<QListView *>(parent());
|
||||
const int gridWidth = canvas->gridSize().width();
|
||||
QStyleOptionViewItem newOption = option;
|
||||
newOption.displayAlignment = Qt::AlignHCenter | Qt::AlignTop;
|
||||
newOption.features.setFlag(QStyleOptionViewItem::WrapText);
|
||||
// Manipulate the width available.
|
||||
newOption.rect.setX((option.rect.x() / gridWidth) * gridWidth + s_edgePad);
|
||||
newOption.rect.setY(option.rect.y() + s_edgePad);
|
||||
newOption.rect.setWidth(gridWidth - 2 * s_edgePad);
|
||||
newOption.rect.setHeight(option.rect.height() - 2 * s_edgePad);
|
||||
m_defaultDelegate->paint(painter, newOption, index);
|
||||
}
|
||||
|
||||
QSize KIconCanvasDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||
{
|
||||
auto *canvas = static_cast<QListView *>(parent());
|
||||
|
||||
// TODO can we set wrap text and display alignment somewhere globally?
|
||||
QStyleOptionViewItem newOption = option;
|
||||
newOption.displayAlignment = Qt::AlignHCenter | Qt::AlignTop;
|
||||
newOption.features.setFlag(QStyleOptionViewItem::WrapText);
|
||||
|
||||
QSize size = m_defaultDelegate->sizeHint(newOption, index);
|
||||
const int gridWidth = canvas->gridSize().width();
|
||||
const int gridHeight = canvas->gridSize().height();
|
||||
size.setWidth(gridWidth - 2 * s_edgePad);
|
||||
size.setHeight(gridHeight - 2 * s_edgePad);
|
||||
QFontMetrics metrics(option.font);
|
||||
size.setHeight(gridHeight + metrics.height() * 3);
|
||||
return size;
|
||||
}
|
||||
|
||||
KIconDialogPrivate::KIconDialogPrivate(KIconDialog *qq)
|
||||
: q(qq)
|
||||
, mpLoader(KIconLoader::global())
|
||||
, model(new KIconDialogModel(mpLoader, qq))
|
||||
, proxyModel(new KIconDialogSortFilterProxyModel(qq))
|
||||
, filterSymbolicAction(new QAction(qq))
|
||||
, filterSymbolicGroup(new QActionGroup(qq))
|
||||
{
|
||||
proxyModel->setSourceModel(model);
|
||||
proxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||
|
||||
filterSymbolicGroup->setExclusive(true);
|
||||
|
||||
QObject::connect(model, &KIconDialogModel::hasSymbolicIconChanged, filterSymbolicAction, &QAction::setVisible);
|
||||
QObject::connect(model, &KIconDialogModel::hasSymbolicIconChanged, proxyModel, &KIconDialogSortFilterProxyModel::setHasSymbolicIcon);
|
||||
}
|
||||
|
||||
/*
|
||||
* KIconDialog: Dialog for selecting icons. Both system and user
|
||||
* specified icons can be chosen.
|
||||
*/
|
||||
|
||||
KIconDialog::KIconDialog(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, d(new KIconDialogPrivate(this))
|
||||
{
|
||||
setModal(true);
|
||||
|
||||
d->init();
|
||||
}
|
||||
|
||||
void KIconDialogPrivate::init()
|
||||
{
|
||||
mGroupOrSize = KIconLoader::Desktop;
|
||||
mContext = KIconLoader::Any;
|
||||
|
||||
ui.setupUi(q);
|
||||
|
||||
auto updatePlaceholder = [this] {
|
||||
updatePlaceholderLabel();
|
||||
};
|
||||
QObject::connect(proxyModel, &QSortFilterProxyModel::modelReset, q, updatePlaceholder);
|
||||
QObject::connect(proxyModel, &QSortFilterProxyModel::rowsInserted, q, updatePlaceholder);
|
||||
QObject::connect(proxyModel, &QSortFilterProxyModel::rowsRemoved, q, updatePlaceholder);
|
||||
|
||||
QAction *findAction = KStandardActions::find(ui.searchLine, qOverload<>(&QWidget::setFocus), q);
|
||||
q->addAction(findAction);
|
||||
|
||||
QMenu *filterSymbolicMenu = new QMenu(q);
|
||||
|
||||
QAction *filterSymbolicAll = filterSymbolicMenu->addAction(i18nc("@item:inmenu All icons", "All"));
|
||||
filterSymbolicAll->setData(KIconDialogSortFilterProxyModel::AllSymbolicIcons);
|
||||
filterSymbolicAll->setChecked(true); // Start with "All" icons.
|
||||
filterSymbolicAll->setCheckable(true);
|
||||
|
||||
QAction *filterSymbolicOnly = filterSymbolicMenu->addAction(i18nc("@item:inmenu Show only symbolic icons", "Only Symbolic"));
|
||||
filterSymbolicOnly->setData(KIconDialogSortFilterProxyModel::OnlySymbolicIcons);
|
||||
filterSymbolicOnly->setCheckable(true);
|
||||
|
||||
QAction *filterSymbolicNone = filterSymbolicMenu->addAction(i18nc("@item:inmenu Hide symbolic icons", "No Symbolic"));
|
||||
filterSymbolicNone->setData(KIconDialogSortFilterProxyModel::NoSymbolicIcons);
|
||||
filterSymbolicNone->setCheckable(true);
|
||||
|
||||
filterSymbolicAction->setIcon(QIcon::fromTheme(QStringLiteral("view-filter")));
|
||||
filterSymbolicAction->setCheckable(true);
|
||||
filterSymbolicAction->setChecked(true);
|
||||
filterSymbolicAction->setMenu(filterSymbolicMenu);
|
||||
|
||||
filterSymbolicGroup->addAction(filterSymbolicAll);
|
||||
filterSymbolicGroup->addAction(filterSymbolicOnly);
|
||||
filterSymbolicGroup->addAction(filterSymbolicNone);
|
||||
QObject::connect(filterSymbolicGroup, &QActionGroup::triggered, q, [this](QAction *action) {
|
||||
proxyModel->setSymbolicIcons(static_cast<KIconDialogSortFilterProxyModel::SymbolicIcons>(action->data().toInt()));
|
||||
});
|
||||
|
||||
ui.searchLine->addAction(filterSymbolicAction, QLineEdit::TrailingPosition);
|
||||
|
||||
QObject::connect(ui.searchLine, &QLineEdit::textChanged, proxyModel, &QSortFilterProxyModel::setFilterFixedString);
|
||||
|
||||
static const KLazyLocalizedString context_text[] = {
|
||||
kli18n("All"),
|
||||
kli18n("Actions"),
|
||||
kli18n("Applications"),
|
||||
kli18n("Categories"),
|
||||
kli18n("Devices"),
|
||||
kli18n("Emblems"),
|
||||
kli18n("Emotes"),
|
||||
kli18n("Mimetypes"),
|
||||
kli18n("Places"),
|
||||
kli18n("Status"),
|
||||
};
|
||||
static const KIconLoader::Context context_id[] = {
|
||||
KIconLoader::Any,
|
||||
KIconLoader::Action,
|
||||
KIconLoader::Application,
|
||||
KIconLoader::Category,
|
||||
KIconLoader::Device,
|
||||
KIconLoader::Emblem,
|
||||
KIconLoader::Emote,
|
||||
KIconLoader::MimeType,
|
||||
KIconLoader::Place,
|
||||
KIconLoader::StatusIcon,
|
||||
};
|
||||
const int cnt = sizeof(context_text) / sizeof(context_text[0]);
|
||||
for (int i = 0; i < cnt; ++i) {
|
||||
if (mpLoader->hasContext(context_id[i])) {
|
||||
ui.contextCombo->addItem(context_text[i].toString(), context_id[i]);
|
||||
if (i == 0) {
|
||||
ui.contextCombo->insertSeparator(i + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
ui.contextCombo->insertSeparator(ui.contextCombo->count());
|
||||
ui.contextCombo->addItem(i18nc("Other icons", "Other"));
|
||||
ui.contextCombo->setMaxVisibleItems(ui.contextCombo->count());
|
||||
ui.contextCombo->setFixedSize(ui.contextCombo->sizeHint());
|
||||
|
||||
QObject::connect(ui.contextCombo, qOverload<int>(&QComboBox::activated), q, [this]() {
|
||||
const auto currentData = ui.contextCombo->currentData();
|
||||
if (currentData.isValid()) {
|
||||
mContext = static_cast<KIconLoader::Context>(ui.contextCombo->currentData().toInt());
|
||||
} else {
|
||||
mContext = static_cast<KIconLoader::Context>(-1);
|
||||
}
|
||||
showIcons();
|
||||
});
|
||||
|
||||
auto *delegate = new KIconCanvasDelegate(ui.canvas, ui.canvas->itemDelegate());
|
||||
ui.canvas->setItemDelegate(delegate);
|
||||
|
||||
ui.canvas->setModel(proxyModel);
|
||||
|
||||
QObject::connect(ui.canvas, &QAbstractItemView::activated, q, [this]() {
|
||||
custom.clear();
|
||||
q->slotOk();
|
||||
});
|
||||
|
||||
// You can't just stack widgets on top of each other in Qt Designer
|
||||
auto *placeholderLayout = new QVBoxLayout(ui.canvas);
|
||||
|
||||
placeholderLabel = new QLabel();
|
||||
QFont placeholderLabelFont;
|
||||
// To match the size of a level 2 Heading/KTitleWidget
|
||||
placeholderLabelFont.setPointSize(qRound(placeholderLabelFont.pointSize() * 1.3));
|
||||
placeholderLabel->setFont(placeholderLabelFont);
|
||||
placeholderLabel->setTextInteractionFlags(Qt::NoTextInteraction);
|
||||
placeholderLabel->setWordWrap(true);
|
||||
placeholderLabel->setAlignment(Qt::AlignCenter);
|
||||
|
||||
// Match opacity of QML placeholder label component
|
||||
auto *effect = new QGraphicsOpacityEffect(placeholderLabel);
|
||||
effect->setOpacity(0.5);
|
||||
placeholderLabel->setGraphicsEffect(effect);
|
||||
|
||||
placeholderLayout->addWidget(placeholderLabel);
|
||||
placeholderLayout->setAlignment(placeholderLabel, Qt::AlignCenter);
|
||||
|
||||
updatePlaceholderLabel();
|
||||
|
||||
// TODO I bet there is a KStandardAction for that?
|
||||
browseButton = new QPushButton(QIcon::fromTheme(QStringLiteral("folder-open")), i18n("Browse…"));
|
||||
// TODO does this have implicatons? I just want the "Browse" button on the left side :)
|
||||
ui.buttonBox->addButton(browseButton, QDialogButtonBox::HelpRole);
|
||||
QObject::connect(browseButton, &QPushButton::clicked, q, [this] {
|
||||
browse();
|
||||
});
|
||||
|
||||
QObject::connect(ui.buttonBox, &QDialogButtonBox::accepted, q, &KIconDialog::slotOk);
|
||||
QObject::connect(ui.buttonBox, &QDialogButtonBox::rejected, q, &QDialog::reject);
|
||||
|
||||
q->adjustSize();
|
||||
}
|
||||
|
||||
KIconDialog::~KIconDialog() = default;
|
||||
|
||||
static bool sortByFileName(const QString &path1, const QString &path2)
|
||||
{
|
||||
const QString fileName1 = path1.mid(path1.lastIndexOf(QLatin1Char('/')) + 1);
|
||||
const QString fileName2 = path2.mid(path2.lastIndexOf(QLatin1Char('/')) + 1);
|
||||
return QString::compare(fileName1, fileName2, Qt::CaseInsensitive) < 0;
|
||||
}
|
||||
|
||||
void KIconDialogPrivate::showIcons()
|
||||
{
|
||||
QStringList filelist;
|
||||
if (isSystemIconsContext()) {
|
||||
if (m_bStrictIconSize) {
|
||||
filelist = mpLoader->queryIcons(mGroupOrSize, mContext);
|
||||
} else {
|
||||
filelist = mpLoader->queryIconsByContext(mGroupOrSize, mContext);
|
||||
}
|
||||
} else if (!customLocation.isEmpty()) {
|
||||
filelist = mpLoader->queryIconsByDir(customLocation);
|
||||
} else {
|
||||
// List PNG files found directly in the kiconload search paths.
|
||||
const QStringList pngNameFilter(QStringLiteral("*.png"));
|
||||
for (const QString &relDir : KIconLoader::global()->searchPaths()) {
|
||||
const QStringList dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, relDir, QStandardPaths::LocateDirectory);
|
||||
for (const QString &dir : dirs) {
|
||||
const auto files = QDir(dir).entryList(pngNameFilter);
|
||||
for (const QString &fileName : files) {
|
||||
filelist << dir + QLatin1Char('/') + fileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(filelist.begin(), filelist.end(), sortByFileName);
|
||||
|
||||
// The KIconCanvas has uniformItemSizes set which really expects
|
||||
// all added icons to be the same size, otherwise weirdness ensues :)
|
||||
// Ensure all SVGs are scaled to the desired size and that as few icons
|
||||
// need to be padded as possible by specifying a sensible size.
|
||||
if (mGroupOrSize < -1) {
|
||||
// mGroupOrSize can be -1 if NoGroup is chosen.
|
||||
// Explicit size.
|
||||
ui.canvas->setIconSize(QSize(-mGroupOrSize, -mGroupOrSize));
|
||||
} else {
|
||||
// Icon group.
|
||||
int groupSize = mpLoader->currentSize(static_cast<KIconLoader::Group>(mGroupOrSize));
|
||||
ui.canvas->setIconSize(QSize(groupSize, groupSize));
|
||||
}
|
||||
|
||||
// Try to make room for three lines of text...
|
||||
QFontMetrics metrics(ui.canvas->font());
|
||||
const int frameHMargin = ui.canvas->style()->pixelMetric(QStyle::PM_FocusFrameHMargin, nullptr, ui.canvas) + 1;
|
||||
const int lineCount = 3;
|
||||
ui.canvas->setGridSize(QSize(100, ui.canvas->iconSize().height() + lineCount * metrics.height() + 3 * frameHMargin));
|
||||
|
||||
// Set a minimum size of 6x3 icons
|
||||
const int columnCount = 6;
|
||||
const int rowCount = 3;
|
||||
QStyleOption opt;
|
||||
opt.initFrom(ui.canvas);
|
||||
int width = columnCount * ui.canvas->gridSize().width();
|
||||
width += ui.canvas->verticalScrollBar()->sizeHint().width() + 1;
|
||||
width += 2 * ui.canvas->frameWidth();
|
||||
if (ui.canvas->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents, &opt, ui.canvas)) {
|
||||
width += ui.canvas->style()->pixelMetric(QStyle::PM_ScrollView_ScrollBarSpacing, &opt, ui.canvas);
|
||||
}
|
||||
int height = rowCount * ui.canvas->gridSize().height() + 1;
|
||||
height += 2 * ui.canvas->frameWidth();
|
||||
|
||||
ui.canvas->setMinimumSize(QSize(width, height));
|
||||
|
||||
model->setIconSize(ui.canvas->iconSize());
|
||||
model->setDevicePixelRatio(q->devicePixelRatioF());
|
||||
model->load(filelist);
|
||||
|
||||
if (!pendingSelectedIcon.isEmpty()) {
|
||||
selectIcon(pendingSelectedIcon);
|
||||
pendingSelectedIcon.clear();
|
||||
}
|
||||
}
|
||||
|
||||
bool KIconDialogPrivate::selectIcon(const QString &iconName)
|
||||
{
|
||||
for (int i = 0; i < proxyModel->rowCount(); ++i) {
|
||||
const QModelIndex idx = proxyModel->index(i, 0);
|
||||
|
||||
QString name = idx.data(KIconDialogModel::PathRole).toString();
|
||||
if (!name.isEmpty() && isSystemIconsContext()) {
|
||||
const QFileInfo fi(name);
|
||||
name = fi.completeBaseName();
|
||||
}
|
||||
|
||||
if (iconName == name) {
|
||||
ui.canvas->setCurrentIndex(idx);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void KIconDialog::setStrictIconSize(bool b)
|
||||
{
|
||||
d->m_bStrictIconSize = b;
|
||||
}
|
||||
|
||||
bool KIconDialog::strictIconSize() const
|
||||
{
|
||||
return d->m_bStrictIconSize;
|
||||
}
|
||||
|
||||
void KIconDialog::setIconSize(int size)
|
||||
{
|
||||
// see KIconLoader, if you think this is weird
|
||||
if (size == 0) {
|
||||
d->mGroupOrSize = KIconLoader::Desktop; // default Group
|
||||
} else {
|
||||
d->mGroupOrSize = -size; // yes, KIconLoader::queryIconsByContext is weird
|
||||
}
|
||||
}
|
||||
|
||||
int KIconDialog::iconSize() const
|
||||
{
|
||||
// 0 or any other value ==> mGroupOrSize is a group, so we return 0
|
||||
return (d->mGroupOrSize < 0) ? -d->mGroupOrSize : 0;
|
||||
}
|
||||
|
||||
void KIconDialog::setSelectedIcon(const QString &iconName)
|
||||
{
|
||||
// TODO Update live when dialog is already open
|
||||
d->pendingSelectedIcon = iconName;
|
||||
}
|
||||
|
||||
void KIconDialog::setup(KIconLoader::Group group, KIconLoader::Context context, bool strictIconSize, int iconSize, bool user, bool lockUser, bool lockCustomDir)
|
||||
{
|
||||
d->m_bStrictIconSize = strictIconSize;
|
||||
d->m_bLockUser = lockUser;
|
||||
d->m_bLockCustomDir = lockCustomDir;
|
||||
if (iconSize == 0) {
|
||||
if (group == KIconLoader::NoGroup) {
|
||||
// NoGroup has numeric value -1, which should
|
||||
// not really be used with KIconLoader::queryIcons*(...);
|
||||
// pick a proper group.
|
||||
d->mGroupOrSize = KIconLoader::Small;
|
||||
} else {
|
||||
d->mGroupOrSize = group;
|
||||
}
|
||||
} else {
|
||||
d->mGroupOrSize = -iconSize;
|
||||
}
|
||||
|
||||
if (user) {
|
||||
d->ui.contextCombo->setCurrentIndex(d->ui.contextCombo->count() - 1);
|
||||
} else {
|
||||
d->setContext(context);
|
||||
}
|
||||
|
||||
d->ui.contextCombo->setEnabled(!user || !lockUser);
|
||||
|
||||
// Disable "Other" entry when user is locked
|
||||
auto *model = qobject_cast<QStandardItemModel *>(d->ui.contextCombo->model());
|
||||
auto *otherItem = model->item(model->rowCount() - 1);
|
||||
auto flags = otherItem->flags();
|
||||
flags.setFlag(Qt::ItemIsEnabled, !lockUser);
|
||||
otherItem->setFlags(flags);
|
||||
|
||||
// Only allow browsing when explicitly allowed and user icons are allowed
|
||||
// An app may not expect a path when asking only about system icons
|
||||
d->browseButton->setVisible(!lockCustomDir && (!user || !lockUser));
|
||||
}
|
||||
|
||||
void KIconDialogPrivate::setContext(KIconLoader::Context context)
|
||||
{
|
||||
mContext = context;
|
||||
const int index = ui.contextCombo->findData(context);
|
||||
if (index > -1) {
|
||||
ui.contextCombo->setCurrentIndex(index);
|
||||
}
|
||||
}
|
||||
|
||||
void KIconDialogPrivate::updatePlaceholderLabel()
|
||||
{
|
||||
if (proxyModel->rowCount() > 0) {
|
||||
placeholderLabel->hide();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ui.searchLine->text().isEmpty()) {
|
||||
placeholderLabel->setText(i18n("No icons matching the search"));
|
||||
} else {
|
||||
placeholderLabel->setText(i18n("No icons in this category"));
|
||||
}
|
||||
|
||||
placeholderLabel->show();
|
||||
}
|
||||
|
||||
void KIconDialog::setCustomLocation(const QString &location)
|
||||
{
|
||||
d->customLocation = location;
|
||||
}
|
||||
|
||||
QString KIconDialog::openDialog()
|
||||
{
|
||||
if (exec() == Accepted) {
|
||||
if (!d->custom.isEmpty()) {
|
||||
return d->custom;
|
||||
}
|
||||
|
||||
const QString name = d->ui.canvas->currentIndex().data(KIconDialogModel::PathRole).toString();
|
||||
if (name.isEmpty() || !d->ui.contextCombo->currentData().isValid()) {
|
||||
return name;
|
||||
}
|
||||
|
||||
QFileInfo fi(name);
|
||||
return fi.completeBaseName();
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
void KIconDialog::showDialog()
|
||||
{
|
||||
setModal(false);
|
||||
show();
|
||||
}
|
||||
|
||||
void KIconDialog::slotOk()
|
||||
{
|
||||
QString name;
|
||||
if (!d->custom.isEmpty()) {
|
||||
name = d->custom;
|
||||
} else {
|
||||
name = d->ui.canvas->currentIndex().data(KIconDialogModel::PathRole).toString();
|
||||
if (!name.isEmpty() && d->isSystemIconsContext()) {
|
||||
const QFileInfo fi(name);
|
||||
name = fi.completeBaseName();
|
||||
}
|
||||
}
|
||||
|
||||
Q_EMIT newIconName(name);
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void KIconDialog::showEvent(QShowEvent *event)
|
||||
{
|
||||
QDialog::showEvent(event);
|
||||
d->showIcons();
|
||||
d->ui.searchLine->setFocus();
|
||||
}
|
||||
|
||||
QString KIconDialog::getIcon(KIconLoader::Group group,
|
||||
KIconLoader::Context context,
|
||||
bool strictIconSize,
|
||||
int iconSize,
|
||||
bool user,
|
||||
QWidget *parent,
|
||||
const QString &title)
|
||||
{
|
||||
KIconDialog dlg(parent);
|
||||
dlg.setup(group, context, strictIconSize, iconSize, user);
|
||||
if (!title.isEmpty()) {
|
||||
dlg.setWindowTitle(title);
|
||||
}
|
||||
|
||||
return dlg.openDialog();
|
||||
}
|
||||
|
||||
void KIconDialogPrivate::browse()
|
||||
{
|
||||
if (browseDialog) {
|
||||
browseDialog.data()->show();
|
||||
browseDialog.data()->raise();
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a file dialog to select an ICO, PNG, XPM or SVG file,
|
||||
// with the image previewer shown.
|
||||
QFileDialog *dlg = new QFileDialog(q, i18n("Select Icon"), QString(), i18n("*.ico *.png *.xpm *.svg *.svgz|Icon Files (*.ico *.png *.xpm *.svg *.svgz)"));
|
||||
// TODO This was deliberately modal before, why? Or just because "window modal" wasn't a thing?
|
||||
dlg->setWindowModality(Qt::WindowModal);
|
||||
dlg->setFileMode(QFileDialog::ExistingFile);
|
||||
QObject::connect(dlg, &QFileDialog::fileSelected, q, [this](const QString &path) {
|
||||
if (!path.isEmpty()) {
|
||||
custom = path;
|
||||
if (isSystemIconsContext()) {
|
||||
customLocation = QFileInfo(custom).absolutePath();
|
||||
}
|
||||
q->slotOk();
|
||||
}
|
||||
});
|
||||
browseDialog = dlg;
|
||||
dlg->show();
|
||||
}
|
||||
|
||||
bool KIconDialogPrivate::isSystemIconsContext() const
|
||||
{
|
||||
return ui.contextCombo->currentData().isValid();
|
||||
}
|
||||
|
||||
#include "kicondialog.moc"
|
||||
#include "moc_kicondialog.cpp"
|
||||
#include "moc_kicondialogmodel_p.cpp"
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
|
||||
This file is part of the KDE project, module kfile.
|
||||
SPDX-FileCopyrightText: 2000 Geert Jansen <jansen@kde.org>
|
||||
SPDX-FileCopyrightText: 2000 Kurt Granroth <granroth@kde.org>
|
||||
SPDX-FileCopyrightText: 1997 Christoph Neerfeld <chris@kde.org>
|
||||
SPDX-FileCopyrightText: 2002 Carsten Pfeiffer <pfeiffer@kde.org>
|
||||
SPDX-FileCopyrightText: 2021 Kai Uwe Broulik <kde@broulik.de>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-only
|
||||
*/
|
||||
|
||||
#ifndef KICONDIALOG_H
|
||||
#define KICONDIALOG_H
|
||||
|
||||
#include "kiconwidgets_export.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <QPushButton>
|
||||
#include <memory>
|
||||
|
||||
#include <kiconloader.h>
|
||||
|
||||
/**
|
||||
* @class KIconDialog kicondialog.h KIconDialog
|
||||
*
|
||||
* Dialog for interactive selection of icons. Use the function
|
||||
* getIcon() to let the user select an icon.
|
||||
*
|
||||
* @short An icon selection dialog.
|
||||
*/
|
||||
class KICONWIDGETS_EXPORT KIconDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructs an icon selection dialog using the global icon loader.
|
||||
*
|
||||
* @param parent The parent widget.
|
||||
*/
|
||||
explicit KIconDialog(QWidget *parent = nullptr);
|
||||
|
||||
/**
|
||||
* Destructs the dialog.
|
||||
*/
|
||||
~KIconDialog() override;
|
||||
|
||||
/**
|
||||
* Sets a strict icon size policy for allowed icons.
|
||||
*
|
||||
* @param policy When true, only icons of the specified group's
|
||||
* size in getIcon() are shown.
|
||||
* When false, icons not available at the desired group's size will
|
||||
* also be selectable.
|
||||
*/
|
||||
void setStrictIconSize(bool policy);
|
||||
/**
|
||||
* Returns true if a strict icon size policy is set.
|
||||
*/
|
||||
bool strictIconSize() const;
|
||||
|
||||
/**
|
||||
* Sets the location of the custom icon directory. Only local directory
|
||||
* paths are allowed.
|
||||
*/
|
||||
void setCustomLocation(const QString &location);
|
||||
|
||||
/**
|
||||
* Sets the size of the icons to be shown / selected.
|
||||
* @see KIconLoader::StdSizes
|
||||
* @see iconSize
|
||||
*/
|
||||
void setIconSize(int size);
|
||||
/**
|
||||
* Returns the icon size set via setIconSize() or 0, if the default
|
||||
* icon size will be used.
|
||||
*/
|
||||
int iconSize() const;
|
||||
|
||||
/**
|
||||
* Sets the icon that is initially selected in the dialog.
|
||||
*
|
||||
* @note Changing this after the dialog has been shown has no effect.
|
||||
* @note If the given icon cannot be found in the current context,
|
||||
* no icon will be selected.
|
||||
* @param iconName The name of the icon to select
|
||||
* @since 5.89
|
||||
*/
|
||||
void setSelectedIcon(const QString &iconName);
|
||||
|
||||
/**
|
||||
* Allows you to set the same parameters as in the class method
|
||||
* getIcon(), as well as two additional parameters to lock
|
||||
* the choice between system and user directories and to lock the
|
||||
* custom icon directory itself.
|
||||
*/
|
||||
void setup(KIconLoader::Group group,
|
||||
KIconLoader::Context context = KIconLoader::Application,
|
||||
bool strictIconSize = false,
|
||||
int iconSize = 0,
|
||||
bool user = false,
|
||||
bool lockUser = false,
|
||||
bool lockCustomDir = false);
|
||||
|
||||
/**
|
||||
* exec()utes this modal dialog and returns the name of the selected icon,
|
||||
* or QString() if the dialog was aborted.
|
||||
* @returns the name of the icon, suitable for loading with KIconLoader.
|
||||
* @see getIcon
|
||||
*/
|
||||
QString openDialog();
|
||||
|
||||
/**
|
||||
* show()s this dialog and emits a newIconName(const QString&) signal when
|
||||
* successful. QString() will be emitted if the dialog was aborted.
|
||||
*/
|
||||
void showDialog();
|
||||
|
||||
/**
|
||||
* Pops up the dialog an lets the user select an icon.
|
||||
*
|
||||
* @param group The icon group this icon is intended for. Providing the
|
||||
* group shows the icons in the dialog with the same appearance as when
|
||||
* used outside the dialog.
|
||||
* @param context The initial icon context. Initially, the icons having
|
||||
* this context are shown in the dialog. The user can change this.
|
||||
* @param strictIconSize When true, only icons of the specified group's size
|
||||
* are shown, otherwise icon not available in the desired group's size
|
||||
* will also be selectable.
|
||||
* @param iconSize the size of the icons -- the default of the icon group
|
||||
* if set to 0
|
||||
* @param user Begin with the "user icons" instead of "system icons".
|
||||
* @param parent The parent widget of the dialog.
|
||||
* @param title The title to use for the dialog.
|
||||
* @return The name of the icon, suitable for loading with KIconLoader.
|
||||
*/
|
||||
static QString getIcon(KIconLoader::Group group = KIconLoader::Desktop,
|
||||
KIconLoader::Context context = KIconLoader::Application,
|
||||
bool strictIconSize = false,
|
||||
int iconSize = 0,
|
||||
bool user = false,
|
||||
QWidget *parent = nullptr,
|
||||
const QString &title = QString());
|
||||
|
||||
Q_SIGNALS:
|
||||
void newIconName(const QString &iconName);
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *event) override;
|
||||
|
||||
protected Q_SLOTS:
|
||||
void slotOk();
|
||||
|
||||
private:
|
||||
std::unique_ptr<class KIconDialogPrivate> const d;
|
||||
|
||||
friend class KIconDialogPrivate;
|
||||
|
||||
Q_DISABLE_COPY(KIconDialog)
|
||||
};
|
||||
|
||||
#endif // KICONDIALOG_H
|
||||
@@ -0,0 +1,88 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>IconDialog</class>
|
||||
<widget class="QWidget" name="IconDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Select Icon</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QComboBox" name="contextCombo">
|
||||
<property name="accessibleName">
|
||||
<string>Icon category</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="searchLine">
|
||||
<property name="placeholderText">
|
||||
<string>Search Icons...</string>
|
||||
</property>
|
||||
<property name="clearButtonEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListView" name="canvas">
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>60</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="movement">
|
||||
<enum>QListView::Static</enum>
|
||||
</property>
|
||||
<property name="resizeMode">
|
||||
<enum>QListView::Adjust</enum>
|
||||
</property>
|
||||
<property name="viewMode">
|
||||
<enum>QListView::IconMode</enum>
|
||||
</property>
|
||||
<property name="uniformItemSizes">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
|
||||
This file is part of the KDE project, module kfile.
|
||||
SPDX-FileCopyrightText: 2000 Geert Jansen <jansen@kde.org>
|
||||
SPDX-FileCopyrightText: 2000 Kurt Granroth <granroth@kde.org>
|
||||
SPDX-FileCopyrightText: 1997 Christoph Neerfeld <chris@kde.org>
|
||||
SPDX-FileCopyrightText: 2002 Carsten Pfeiffer <pfeiffer@kde.org>
|
||||
SPDX-FileCopyrightText: 2021 Kai Uwe Broulik <kde@broulik.de>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-only
|
||||
*/
|
||||
|
||||
#ifndef KICONDIALOG_P_H
|
||||
#define KICONDIALOG_P_H
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QPointer>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include <kiconloader.h>
|
||||
|
||||
#include "kicondialogmodel_p.h"
|
||||
|
||||
#include "ui_kicondialog.h"
|
||||
|
||||
class QLabel;
|
||||
class QPushButton;
|
||||
|
||||
class KIconDialog;
|
||||
class KIconDialogSortFilterProxyModel;
|
||||
|
||||
class KIconDialogPrivate
|
||||
{
|
||||
public:
|
||||
KIconDialogPrivate(KIconDialog *qq);
|
||||
|
||||
void init();
|
||||
void showIcons();
|
||||
bool selectIcon(const QString &iconName);
|
||||
void setContext(KIconLoader::Context context);
|
||||
void updatePlaceholderLabel();
|
||||
|
||||
void browse();
|
||||
|
||||
bool isSystemIconsContext() const;
|
||||
|
||||
KIconDialog *q;
|
||||
|
||||
KIconLoader *mpLoader;
|
||||
|
||||
KIconDialogModel *model;
|
||||
KIconDialogSortFilterProxyModel *proxyModel;
|
||||
|
||||
int mGroupOrSize;
|
||||
KIconLoader::Context mContext;
|
||||
|
||||
QLabel *placeholderLabel;
|
||||
QPushButton *browseButton;
|
||||
|
||||
QAction *filterSymbolicAction;
|
||||
QActionGroup *filterSymbolicGroup;
|
||||
|
||||
bool m_bStrictIconSize = true;
|
||||
bool m_bLockUser = false;
|
||||
bool m_bLockCustomDir = false;
|
||||
QString custom;
|
||||
QString customLocation;
|
||||
QString pendingSelectedIcon;
|
||||
QPointer<QFileDialog> browseDialog;
|
||||
|
||||
Ui::IconDialog ui;
|
||||
};
|
||||
|
||||
#endif // KICONDIALOG_P_H
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2021 Kai Uwe Broulik <kde@broulik.de>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef KICONDIALOGMODEL_P_H
|
||||
#define KICONDIALOGMODEL_P_H
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QList>
|
||||
#include <QPixmap>
|
||||
#include <QSize>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
class KIconLoader;
|
||||
|
||||
struct KIconDialogModelData {
|
||||
QString name;
|
||||
QString path;
|
||||
QPixmap pixmap;
|
||||
};
|
||||
Q_DECLARE_TYPEINFO(KIconDialogModelData, Q_RELOCATABLE_TYPE);
|
||||
|
||||
class KIconDialogModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
KIconDialogModel(KIconLoader *loader, QObject *parent);
|
||||
~KIconDialogModel() override;
|
||||
|
||||
enum Roles { PathRole = Qt::UserRole };
|
||||
|
||||
qreal devicePixelRatio() const;
|
||||
void setDevicePixelRatio(qreal dpr);
|
||||
|
||||
QSize iconSize() const;
|
||||
void setIconSize(const QSize &iconSize);
|
||||
|
||||
static QLatin1String symbolicSuffix();
|
||||
bool hasSymbolicIcon() const;
|
||||
|
||||
void load(const QStringList &paths);
|
||||
|
||||
int rowCount(const QModelIndex &parent) const override;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
|
||||
Q_SIGNALS:
|
||||
void hasSymbolicIconChanged(bool hasSymbolicIcon);
|
||||
|
||||
private:
|
||||
void loadPixmap(const QModelIndex &index);
|
||||
|
||||
QList<KIconDialogModelData> m_data;
|
||||
|
||||
KIconLoader *m_loader;
|
||||
qreal m_dpr = 1;
|
||||
QSize m_iconSize;
|
||||
bool m_hasSymbolicIcon = false;
|
||||
};
|
||||
|
||||
#endif // KICONDIALOGMODEL_P_H
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2000 Geert Jansen <jansen@kde.org>
|
||||
SPDX-FileCopyrightText: 2000 Antonio Larrosa <larrosa@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-only
|
||||
*/
|
||||
|
||||
#include "kpixmapsequenceloader.h"
|
||||
|
||||
#include <KIconLoader>
|
||||
|
||||
namespace KPixmapSequenceLoader
|
||||
{
|
||||
|
||||
KPixmapSequence load(const QString &iconName, int size)
|
||||
{
|
||||
return KPixmapSequence(KIconLoader::global()->iconPath(iconName, -size), size);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2000 Geert Jansen <jansen@kde.org>
|
||||
SPDX-FileCopyrightText: 2000 Antonio Larrosa <larrosa@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-only
|
||||
*/
|
||||
|
||||
#ifndef KPIXMAPSEQUENCELOADER_H
|
||||
#define KPIXMAPSEQUENCELOADER_H
|
||||
|
||||
#include <KPixmapSequence>
|
||||
|
||||
#include "kiconwidgets_export.h"
|
||||
|
||||
namespace KPixmapSequenceLoader
|
||||
{
|
||||
|
||||
/**
|
||||
* Loads a pixmapSequence given the xdg icon name
|
||||
*
|
||||
* @param iconName The name of the icon, without extension.
|
||||
* @param size the size to be used
|
||||
* @since 6.0
|
||||
*/
|
||||
KICONWIDGETS_EXPORT KPixmapSequence load(const QString &iconName, int size);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user