Commit b0358ed6 authored by Carl Schwan's avatar Carl Schwan 🚴
Browse files

Initial commit

parents
cmake_minimum_required(VERSION 3.0)
project(kontrast)
include(FeatureSummary)
################# set KDE specific information #################
find_package(ECM 0.0.8 REQUIRED NO_MODULE)
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH})
include(KDEInstallDirs)
include(KDECMakeSettings)
include(KDECompilerSettings NO_POLICY_SCOPE)
include(ECMSetupVersion)
include(ECMGenerateHeaders)
include(ECMPoQmTools)
################# Find dependencies #################
find_package(Qt5 REQUIRED COMPONENTS Core Gui Qml QuickControls2 Svg)
find_package(KF5 REQUIRED COMPONENTS Kirigami2 I18n CoreAddons)
################# Enable C++11 features for clang and gcc #################
set(CMAKE_CXX_STANDARD 11)
################# build and install #################
add_subdirectory(src)
install(PROGRAMS org.kde.kontrast.desktop DESTINATION ${KDE_INSTALL_APPDIR})
install(FILES org.kde.kontrast.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR})
feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES)
<?xml version="1.0" encoding="utf-8"?>
<component type="desktop-application">
<id>org.kde.kontrast</id>
<name>Kirigami Application</name>
<summary>A short summary describing what this software is about</summary>
<metadata_license>A permissive license for this metadata, e.g. "FSFAP"</metadata_license>
<project_license>The license of this software as SPDX string, e.g. "GPL-3+"</project_license>
<developer_name>The software vendor name, e.g. "ACME Corporation"</developer_name>
<description>
<p>Multiple paragraphs of long description, describing this software component.</p>
<p>You can also use ordered and unordered lists:</p>
<ul>
<li>Feature 1</li>
<li>Feature 2</li>
</ul>
<p>Keep in mind to XML-escape characters, and that this is not HTML markup.</p>
</description>
</component>
[Desktop Entry]
Name=kontrast
Comment=kontrast Kirigami Application
Version=1.0
Exec=kontrast
MimeType=application/x-kontrast;
Icon=applications-development
Type=Application
Terminal=false
Categories=Qt;KDE;
qt5_add_resources(kontrast_SRCS resources.qrc)
add_executable(kontrast
main.cpp
kontrast.cpp
savedcolormodel.cpp
${kontrast_SRCS})
target_link_libraries(kontrast
Qt5::Core
Qt5::Gui
Qt5::Qml
Qt5::Quick
Qt5::QuickControls2
Qt5::Svg
KF5::I18n
KF5::CoreAddons)
target_compile_features(kontrast PRIVATE cxx_std_17)
install(TARGETS kontrast ${KF5_INSTALL_TARGETS_DEFAULT_ARGS})
/**
* SPDX-FileCopyrightText: (C) 2020 Carl Schwan <carl@carlschwan.eu>
*
* SPDX-LicenseRef: GPL-3.0-or-later
*/
import QtQuick 2.1
import org.kde.kirigami 2.14 as Kirigami
import QtQuick.Controls 2.14 as QQC2
import QtQuick.Window 2.14
import QtQuick.Layouts 1.14
import org.kde.kontrast.private 1.0
Kirigami.AboutPage {
aboutData: Kontrast.about
}
/**
* SPDX-FileCopyrightText: (C) 2020 Carl Schwan <carl@carlschwan.eu>
*
* SPDX-LicenseRef: GPL-3.0-or-later
*/
import QtQuick 2.1
import org.kde.kirigami 2.14 as Kirigami
import QtQuick.Controls 2.14 as QQC2
import QtQuick.Window 2.14
import QtQuick.Layouts 1.14
import org.kde.kontrast.private 1.0
Kirigami.ScrollablePage {
id: root
title: i18n("Saved colors")
ListView {
model: SavedColors
delegate: Kirigami.AbstractListItem {
background: Rectangle {
anchors.fill: parent
color: backgroundColor
}
ColumnLayout {
Text {
Layout.fillWidth: true
font.pointSize: 30
text: "Lorem Impsum"
color: textColor
}
Text {
Layout.fillWidth: true
font.pointSize: 20
text: "Lorem Impsum reroie joirej je roje oijre oijeo"
wrapMode: Text.WordWrap
color: textColor
}
RowLayout {
Layout.fillWidth: true
Text {
Layout.fillWidth: true
text: i18n("Text: %1", textColor)
color: textColor
}
Text {
Layout.fillWidth: true
text: i18n("Background: %1", backgroundColor)
color: textColor
}
}
}
}
}
}
/**
* SPDX-FileCopyrightText: (C) 2020 Carl Schwan <carl@carlschwan.eu>
*
* SPDX-LicenseRef: GPL-3.0-or-later
*/
import QtQuick 2.1
import org.kde.kirigami 2.11 as Kirigami
import QtQuick.Controls 2.14 as QQC2
import QtQuick.Window 2.14
import QtQuick.Layouts 1.14
import org.kde.kontrast.private 1.0
Kirigami.ScrollablePage {
id: mainPage
property bool isMobile: Window.width <= Kirigami.Units.gridUnit * 30
title: i18n("kontrast")
background: Rectangle {
color: Kontrast.backgroundColor
}
ColumnLayout {
Text {
font.pointSize: 45
font.bold: true
text: "Aa " + Kontrast.contrast.toFixed(2)
color: Kontrast.textColor
Layout.fillWidth: true
}
Text {
font.pointSize: mainPage.isMobile ? 15 : 20
font.bold: true
Layout.fillWidth: true
wrapMode: Text.WordWrap
text: i18n("Contrast is the difference in luminance or color that makes an object (or its representation in an image or display) distinguishable. In visual perception of the real world, contrast is determined by the difference in the color and brightness of the object and other objects within the same field of view.")
color: Kontrast.textColor
}
GridLayout {
Layout.fillWidth: true
columns: mainPage.isMobile ? 1 : 3
rowSpacing: Kirigami.Units.gridUnit
ColumnLayout {
Layout.fillWidth: true
Text {
Layout.topMargin: Kirigami.Units.largeSpacing
text: i18n("Text")
color: Kontrast.displayTextColor
}
TextEdit {
text: Kontrast.textColor
font.pointSize: 35
color: Kontrast.textColor
Layout.fillWidth: true
}
Text {
Layout.topMargin: Kirigami.Units.largeSpacing
text: i18n("Hue %1°", Kontrast.textHue)
color: Kontrast.displayTextColor
}
QQC2.Slider {
from: 0
value: Kontrast.textHue
to: 360
onMoved: Kontrast.textHue = value
Layout.fillWidth: true
}
Text {
Layout.topMargin: Kirigami.Units.largeSpacing
text: i18n("Saturation %1", (Kontrast.textSaturation / 255))
color: Kontrast.displayTextColor
}
QQC2.Slider {
from: 0
value: Kontrast.textSaturation
to: 255
onMoved: Kontrast.textSaturation = value
Layout.fillWidth: true
}
Text {
Layout.topMargin: Kirigami.Units.largeSpacing
text: i18n("Lightness %1", (Kontrast.textLightness / 255))
color: Kontrast.displayTextColor
}
QQC2.Slider {
from: 0
value: Kontrast.textLightness
to: 255
onMoved: Kontrast.textLightness = value
Layout.fillWidth: true
}
}
Kirigami.Separator {
visible: mainPage.isMobile
Layout.fillWidth: true
color: Kontrast.displayTextColor
}
ColumnLayout {
Layout.fillWidth: true
Text {
Layout.topMargin: Kirigami.Units.largeSpacing
text: i18n("Background")
color: Kontrast.displayTextColor
}
TextEdit {
text: Kontrast.backgroundColor
font.pointSize: 35
color: Kontrast.textColor
Layout.fillWidth: true
}
Text {
Layout.topMargin: Kirigami.Units.largeSpacing
text: i18n("Hue %1°", Kontrast.backgroundHue)
color: Kontrast.displayTextColor
}
QQC2.Slider {
from: 0
value: Kontrast.backgroundHue
to: 360
onMoved: Kontrast.backgroundHue = value
Layout.fillWidth: true
}
Text {
Layout.topMargin: Kirigami.Units.largeSpacing
text: i18n("Saturation %1", (Kontrast.backgroundSaturation / 255))
color: Kontrast.displayTextColor
}
QQC2.Slider {
from: 0
value: Kontrast.backgroundSaturation
to: 255
onMoved: Kontrast.backgroundSaturation = value
Layout.fillWidth: true
}
Text {
Layout.topMargin: Kirigami.Units.largeSpacing
text: i18n("Saturation %1", (Kontrast.backgroundLightness / 255))
color: Kontrast.displayTextColor
}
QQC2.Slider {
from: 0
value: Kontrast.backgroundLightness
to: 255
onMoved: Kontrast.backgroundLightness = value
Layout.fillWidth: true
}
}
}
RowLayout {
Layout.topMargin: Kirigami.Units.gridUnit * 2
QQC2.Button {
text: i18n("Reverse")
onClicked: Kontrast.reverse()
}
QQC2.Button {
text: i18n("Random")
onClicked: Kontrast.random()
}
}
}
}
/**
* SPDX-FileCopyrightText: (C) 2020 Carl Schwan <carl@carlschwan.eu>
*
* SPDX-LicenseRef: GPL-3.0-or-later
*/
import QtQuick 2.1
import org.kde.kirigami 2.12 as Kirigami
import QtQuick.Controls 2.14 as QQC2
import QtQuick.Window 2.14
import QtQuick.Layouts 1.14
Kirigami.ApplicationWindow {
id: root
title: i18n("kontrast")
Kirigami.PagePool {
id: mainPagePool
}
globalDrawer: Kirigami.GlobalDrawer {
title: i18n("kontrast")
titleIcon: "applications-graphics"
actions: [
Kirigami.PagePoolAction {
text: i18n("Home")
icon.name: "go-home"
pagePool: mainPagePool
page: "MainPage.qml"
},
Kirigami.PagePoolAction {
text: i18n("Saved Colors")
icon.name: "star"
pagePool: mainPagePool
page: "FavoritePage.qml"
},
Kirigami.PagePoolAction {
text: i18n("About")
icon.name: "about"
pagePool: mainPagePool
page: "AboutPage.qml"
}
]
}
contextDrawer: Kirigami.ContextDrawer {
id: contextDrawer
}
pageStack.initialPage: mainPagePool.loadPage("MainPage.qml")
}
/*
* SPDX-FileCopyrightText: (C) 2020 Carl Schwan <carl@carlschwan.eu>
*
* SPDX-LicenseRef: AGPL-3.0-or-later
*/
#include "kontrast.h"
#include <QtMath>
#include <QRandomGenerator>
#include <QDebug>
Kontrast::Kontrast(KAboutData about, QObject *parent)
: QObject(parent)
, m_about(about)
{
setObjectName("Kontrast");
}
QColor Kontrast::textColor() const
{
return m_textColor;
}
void Kontrast::setTextColor(const QColor textColor)
{
if (textColor == m_textColor) {
return;
}
m_textColor = textColor;
Q_EMIT textColorChanged();
Q_EMIT contrastChanged();
}
int Kontrast::textHue() const
{
return m_textColor.hslHue();
}
void Kontrast::setTextHue(int hue)
{
if (m_textColor.hslHue() == hue) {
return;
}
m_textColor.setHsl(hue, m_textColor.hslSaturation(), m_textColor.lightness());
Q_EMIT textColorChanged();
Q_EMIT contrastChanged();
}
int Kontrast::textLightness() const
{
return m_textColor.lightness();
}
void Kontrast::setTextLightness(int lightness)
{
if (m_textColor.lightness() == lightness) {
return;
}
m_textColor.setHsl(m_textColor.hslHue(), m_textColor.hslSaturation(), lightness);
Q_EMIT textColorChanged();
Q_EMIT contrastChanged();
}
int Kontrast::textSaturation() const
{
return m_textColor.saturation();
}
void Kontrast::setTextSaturation(int saturation)
{
if (m_textColor.saturation() == saturation) {
return;
}
m_textColor.setHsl(m_textColor.hslHue(), saturation, m_textColor.lightness());
Q_EMIT textColorChanged();
Q_EMIT contrastChanged();
}
QColor Kontrast::backgroundColor() const
{
return m_backgroundColor;
}
void Kontrast::setBackgroundColor(const QColor backgroundColor)
{
if (backgroundColor == m_backgroundColor) {
return;
}
m_backgroundColor = backgroundColor;
Q_EMIT backgroundColorChanged();
Q_EMIT contrastChanged();
}
int Kontrast::backgroundHue() const
{
return m_backgroundColor.hslHue();
}
void Kontrast::setBackgroundHue(int hue)
{
if (m_backgroundColor.hslHue() == hue) {
return;
}
m_backgroundColor.setHsl(hue, m_backgroundColor.hslSaturation(), m_backgroundColor.lightness());
Q_EMIT backgroundColorChanged();
Q_EMIT contrastChanged();
}
int Kontrast::backgroundLightness() const
{
return m_backgroundColor.lightness();
}
void Kontrast::setBackgroundLightness(int lightness)
{
if (m_backgroundColor.lightness() == lightness) {
return;
}
m_backgroundColor.setHsl(m_backgroundColor.hslHue(), m_backgroundColor.hslSaturation(), lightness);
Q_EMIT backgroundColorChanged();
Q_EMIT contrastChanged();
}
int Kontrast::backgroundSaturation() const
{
return m_backgroundColor.saturation();
}
void Kontrast::setBackgroundSaturation(int saturation)
{
if (m_backgroundColor.saturation() == saturation) {
return;
}
m_backgroundColor.setHsl(m_backgroundColor.hslHue(), saturation, m_backgroundColor.lightness());
Q_EMIT backgroundColorChanged();
Q_EMIT contrastChanged();
}
qreal luminosity(const QColor color)
{
// http://www.w3.org/TR/WCAG20/#relativeluminancedef
const qreal red = color.redF();
const qreal green = color.greenF();
const qreal blue = color.blueF();
const qreal redLum = (red <= 0.03928) ? red / 12.92 : qPow(((red + 0.055) / 1.055), 2.4);
const qreal greenLum = (green <= 0.03928) ? green / 12.92 : qPow(((green + 0.055) / 1.055), 2.4);
const qreal blueLum = (blue <= 0.03928) ? blue / 12.92 : qPow(((blue + 0.055) / 1.055), 2.4);
return 0.2126 * redLum + 0.7152 * greenLum + 0.0722 * blueLum;
}
qreal Kontrast::contrast() const
{
const qreal lum1 = luminosity(m_textColor);
const qreal lum2 = luminosity(m_backgroundColor);
if (lum1 > lum2) {
return (lum1 + 0.05) / (lum2 + 0.05);
}
return (lum2 + 0.05) / (lum1 + 0.05);
}
void Kontrast::random()
{
do {
m_textColor = QColor::fromRgb(QRandomGenerator::global()->generate());
m_backgroundColor = QColor::fromRgb(QRandomGenerator::global()->generate());
qDebug() << m_textColor << m_backgroundColor;
} while (contrast() < 3.5);
Q_EMIT backgroundColorChanged();
Q_EMIT textColorChanged();
Q_EMIT contrastChanged();
}
void Kontrast::reverse()
{
const QColor temp = m_textColor;
m_textColor = m_backgroundColor;
m_backgroundColor = temp;
Q_EMIT backgroundColorChanged();
Q_EMIT textColorChanged();
Q_EMIT contrastChanged();
}
QColor Kontrast::displayTextColor() const
{
if (contrast() > 3.0) {
return m_textColor;
}
if (luminosity(m_backgroundColor) > 0.5) {
return QColor("black");
}
return QColor("white");
}
KAboutData Kontrast::about() const
{
return m_about;
}
/*
* SPDX-FileCopyrightText: (C) 2020 Carl Schwan <carl@carlschwan.eu>
*
* SPDX-LicenseRef: AGPL-3.0-or-later
*/
#pragma once
#include <QObject>
#include <QColor>
#include <KAboutData>