GH-1197 add console log color adaptation
rainbow library was part of KDE - KGuiAddons
This commit is contained in:
parent
9681f724e5
commit
6858f1dd62
@ -112,6 +112,10 @@ include_directories(${XZ_INCLUDE_DIR})
|
|||||||
add_subdirectory(depends/pack200)
|
add_subdirectory(depends/pack200)
|
||||||
include_directories(${PACK200_INCLUDE_DIR})
|
include_directories(${PACK200_INCLUDE_DIR})
|
||||||
|
|
||||||
|
# Add color thingy
|
||||||
|
add_subdirectory(depends/rainbow)
|
||||||
|
include_directories(${RAINBOW_INCLUDE_DIR})
|
||||||
|
|
||||||
######## MultiMC Libs ########
|
######## MultiMC Libs ########
|
||||||
|
|
||||||
# Add the util library.
|
# Add the util library.
|
||||||
|
@ -129,6 +129,8 @@ SET(MULTIMC_SOURCES
|
|||||||
InstanceProxyModel.cpp
|
InstanceProxyModel.cpp
|
||||||
VersionProxyModel.h
|
VersionProxyModel.h
|
||||||
VersionProxyModel.cpp
|
VersionProxyModel.cpp
|
||||||
|
Colors.h
|
||||||
|
Colors.cpp
|
||||||
|
|
||||||
# GUI - windows
|
# GUI - windows
|
||||||
MainWindow.h
|
MainWindow.h
|
||||||
@ -325,7 +327,6 @@ else()
|
|||||||
list(APPEND MULTIMC_SOURCES Platform_Other.cpp)
|
list(APPEND MULTIMC_SOURCES Platform_Other.cpp)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
# Link additional libraries
|
# Link additional libraries
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
set(MultiMC_LINK_ADDITIONAL_LIBS ${MultiMC_LINK_ADDITIONAL_LIBS} Qt5::WinMain)
|
set(MultiMC_LINK_ADDITIONAL_LIBS ${MultiMC_LINK_ADDITIONAL_LIBS} Qt5::WinMain)
|
||||||
@ -341,8 +342,8 @@ qt5_add_resources(MULTIMC_RESOURCES ${MULTIMC_QRCS})
|
|||||||
add_executable(MultiMC MACOSX_BUNDLE WIN32 ${MULTIMC_SOURCES} ${MULTIMC_UI} ${MULTIMC_RESOURCES} ${MULTIMC_RCS})
|
add_executable(MultiMC MACOSX_BUNDLE WIN32 ${MULTIMC_SOURCES} ${MULTIMC_UI} ${MULTIMC_RESOURCES} ${MULTIMC_RCS})
|
||||||
target_link_libraries(MultiMC MultiMC_logic xz-embedded unpack200 iconfix libUtil LogicalGui
|
target_link_libraries(MultiMC MultiMC_logic xz-embedded unpack200 iconfix libUtil LogicalGui
|
||||||
${QUAZIP_LIBRARIES} Qt5::Core Qt5::Xml Qt5::Widgets Qt5::Network Qt5::Concurrent
|
${QUAZIP_LIBRARIES} Qt5::Core Qt5::Xml Qt5::Widgets Qt5::Network Qt5::Concurrent
|
||||||
hoedown
|
hoedown rainbow
|
||||||
${MultiMC_LINK_ADDITIONAL_LIBS})
|
${MultiMC_LINK_ADDITIONAL_LIBS})
|
||||||
|
|
||||||
################################ INSTALLATION AND PACKAGING ################################
|
################################ INSTALLATION AND PACKAGING ################################
|
||||||
|
|
||||||
|
26
application/Colors.cpp
Normal file
26
application/Colors.cpp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#include "Colors.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blend the color with the front color, adapting to the back color
|
||||||
|
*/
|
||||||
|
QColor Color::blend(QColor front, QColor back, QColor color, uchar ratio)
|
||||||
|
{
|
||||||
|
Q_ASSERT(front.isValid());
|
||||||
|
Q_ASSERT(back.isValid());
|
||||||
|
if (Rainbow::luma(front) > Rainbow::luma(back))
|
||||||
|
{
|
||||||
|
// for dark color schemes, produce a fitting color first
|
||||||
|
color = Rainbow::tint(front, color, 0.5);
|
||||||
|
}
|
||||||
|
// adapt contrast
|
||||||
|
return Rainbow::mix(front, color, float(ratio) / float(0xff));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blend the color with the back color
|
||||||
|
*/
|
||||||
|
QColor Color::blendBackground(QColor back, QColor color, uchar ratio)
|
||||||
|
{
|
||||||
|
// adapt contrast
|
||||||
|
return Rainbow::mix(back, color, float(ratio) / float(0xff));
|
||||||
|
}
|
15
application/Colors.h
Normal file
15
application/Colors.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <QtGui/QColor>
|
||||||
|
#include <rainbow.h>
|
||||||
|
namespace Color
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Blend the color with the front color, adapting to the back color
|
||||||
|
*/
|
||||||
|
QColor blend(QColor front, QColor back, QColor color, uchar ratio);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blend the color with the back color
|
||||||
|
*/
|
||||||
|
QColor blendBackground(QColor back, QColor color, uchar ratio);
|
||||||
|
}
|
@ -10,6 +10,7 @@
|
|||||||
#include "launch/LaunchTask.h"
|
#include "launch/LaunchTask.h"
|
||||||
#include <settings/Setting.h>
|
#include <settings/Setting.h>
|
||||||
#include "GuiUtil.h"
|
#include "GuiUtil.h"
|
||||||
|
#include <Colors.h>
|
||||||
|
|
||||||
LogPage::LogPage(std::shared_ptr<LaunchTask> proc, QWidget *parent)
|
LogPage::LogPage(std::shared_ptr<LaunchTask> proc, QWidget *parent)
|
||||||
: QWidget(parent), ui(new Ui::LogPage), m_process(proc)
|
: QWidget(parent), ui(new Ui::LogPage), m_process(proc)
|
||||||
@ -203,31 +204,38 @@ void LogPage::write(QString data, MessageLevel::Enum mode)
|
|||||||
QListIterator<QString> iter(filtered);
|
QListIterator<QString> iter(filtered);
|
||||||
QTextCharFormat format(*defaultFormat);
|
QTextCharFormat format(*defaultFormat);
|
||||||
|
|
||||||
|
auto origForeground = ui->text->palette().color(ui->text->foregroundRole());
|
||||||
|
auto origBackground = ui->text->palette().color(ui->text->backgroundRole());
|
||||||
|
auto foreground = [&](QColor foreColor)
|
||||||
|
{
|
||||||
|
format.setForeground(Color::blend(origForeground, origBackground, foreColor, 255));
|
||||||
|
};
|
||||||
switch(mode)
|
switch(mode)
|
||||||
{
|
{
|
||||||
case MessageLevel::MultiMC:
|
case MessageLevel::MultiMC:
|
||||||
{
|
{
|
||||||
format.setForeground(QColor("blue"));
|
foreground(QColor("purple"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MessageLevel::Debug:
|
case MessageLevel::Debug:
|
||||||
{
|
{
|
||||||
format.setForeground(QColor("green"));
|
foreground(QColor("green"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MessageLevel::Warning:
|
case MessageLevel::Warning:
|
||||||
{
|
{
|
||||||
format.setForeground(QColor("orange"));
|
foreground(QColor("orange"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MessageLevel::Error:
|
case MessageLevel::Error:
|
||||||
{
|
{
|
||||||
format.setForeground(QColor("red"));
|
foreground(QColor("red"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MessageLevel::Fatal:
|
case MessageLevel::Fatal:
|
||||||
{
|
{
|
||||||
format.setForeground(QColor("red"));
|
origBackground = QColor("black");
|
||||||
|
foreground(QColor("red"));
|
||||||
format.setBackground(QColor("black"));
|
format.setBackground(QColor("black"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -235,7 +243,7 @@ void LogPage::write(QString data, MessageLevel::Enum mode)
|
|||||||
case MessageLevel::Message:
|
case MessageLevel::Message:
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// do nothing, keep original
|
foreground(QColor("black"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
20
depends/rainbow/CMakeLists.txt
Normal file
20
depends/rainbow/CMakeLists.txt
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
cmake_minimum_required(VERSION 2.8.11)
|
||||||
|
project(rainbow)
|
||||||
|
|
||||||
|
find_package(Qt5Core REQUIRED QUIET)
|
||||||
|
find_package(Qt5Gui REQUIRED QUIET)
|
||||||
|
|
||||||
|
include_directories(${Qt5Core_INCLUDE_DIRS})
|
||||||
|
include_directories(${Qt5Gui_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
set(RAINBOW_SOURCES
|
||||||
|
include/rainbow_config.h
|
||||||
|
include/rainbow.h
|
||||||
|
src/rainbow.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_definitions(-DRAINBOW_LIBRARY)
|
||||||
|
set(RAINBOW_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include" PARENT_SCOPE)
|
||||||
|
add_library(rainbow SHARED ${RAINBOW_SOURCES})
|
||||||
|
|
||||||
|
qt5_use_modules(rainbow Core Gui)
|
0
depends/rainbow/COPYING.LIB
Normal file
0
depends/rainbow/COPYING.LIB
Normal file
160
depends/rainbow/include/rainbow.h
Normal file
160
depends/rainbow/include/rainbow.h
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
/* This was part of the KDE project - see KGuiAddons
|
||||||
|
* Copyright (C) 2007 Matthew Woehlke <mw_triad@users.sourceforge.net>
|
||||||
|
* Copyright (C) 2007 Olaf Schmidt <ojschmidt@kde.org>
|
||||||
|
* Copyright (C) 2007 Thomas Zander <zander@kde.org>
|
||||||
|
* Copyright (C) 2007 Zack Rusin <zack@kde.org>
|
||||||
|
* Copyright (C) 2015 Petr Mrazek <peterix@gmail.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public License
|
||||||
|
* along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "rainbow_config.h"
|
||||||
|
|
||||||
|
#include <QPainter>
|
||||||
|
class QColor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A set of methods used to work with colors.
|
||||||
|
*/
|
||||||
|
namespace Rainbow
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Calculate the luma of a color. Luma is weighted sum of gamma-adjusted
|
||||||
|
* R'G'B' components of a color. The result is similar to qGray. The range
|
||||||
|
* is from 0.0 (black) to 1.0 (white).
|
||||||
|
*
|
||||||
|
* Rainbow::darken(), Rainbow::lighten() and Rainbow::shade()
|
||||||
|
* operate on the luma of a color.
|
||||||
|
*
|
||||||
|
* @see http://en.wikipedia.org/wiki/Luma_(video)
|
||||||
|
*/
|
||||||
|
RAINBOW_EXPORT qreal luma(const QColor &);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate hue, chroma and luma of a color in one call.
|
||||||
|
* @since 5.0
|
||||||
|
*/
|
||||||
|
RAINBOW_EXPORT void getHcy(const QColor &, qreal *hue, qreal *chroma, qreal *luma,
|
||||||
|
qreal *alpha = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the contrast ratio between two colors, according to the
|
||||||
|
* W3C/WCAG2.0 algorithm, (Lmax + 0.05)/(Lmin + 0.05), where Lmax and Lmin
|
||||||
|
* are the luma values of the lighter color and the darker color,
|
||||||
|
* respectively.
|
||||||
|
*
|
||||||
|
* A contrast ration of 5:1 (result == 5.0) is the minimum for "normal"
|
||||||
|
* text to be considered readable (large text can go as low as 3:1). The
|
||||||
|
* ratio ranges from 1:1 (result == 1.0) to 21:1 (result == 21.0).
|
||||||
|
*
|
||||||
|
* @see Rainbow::luma
|
||||||
|
*/
|
||||||
|
RAINBOW_EXPORT qreal contrastRatio(const QColor &, const QColor &);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adjust the luma of a color by changing its distance from white.
|
||||||
|
*
|
||||||
|
* @li amount == 1.0 gives white
|
||||||
|
* @li amount == 0.5 results in a color whose luma is halfway between 1.0
|
||||||
|
* and that of the original color
|
||||||
|
* @li amount == 0.0 gives the original color
|
||||||
|
* @li amount == -1.0 gives a color that is 'twice as far from white' as
|
||||||
|
* the original color, that is luma(result) == 1.0 - 2*(1.0 - luma(color))
|
||||||
|
*
|
||||||
|
* @param amount factor by which to adjust the luma component of the color
|
||||||
|
* @param chromaInverseGain (optional) factor by which to adjust the chroma
|
||||||
|
* component of the color; 1.0 means no change, 0.0 maximizes chroma
|
||||||
|
* @see Rainbow::shade
|
||||||
|
*/
|
||||||
|
RAINBOW_EXPORT QColor
|
||||||
|
lighten(const QColor &, qreal amount = 0.5, qreal chromaInverseGain = 1.0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adjust the luma of a color by changing its distance from black.
|
||||||
|
*
|
||||||
|
* @li amount == 1.0 gives black
|
||||||
|
* @li amount == 0.5 results in a color whose luma is halfway between 0.0
|
||||||
|
* and that of the original color
|
||||||
|
* @li amount == 0.0 gives the original color
|
||||||
|
* @li amount == -1.0 gives a color that is 'twice as far from black' as
|
||||||
|
* the original color, that is luma(result) == 2*luma(color)
|
||||||
|
*
|
||||||
|
* @param amount factor by which to adjust the luma component of the color
|
||||||
|
* @param chromaGain (optional) factor by which to adjust the chroma
|
||||||
|
* component of the color; 1.0 means no change, 0.0 minimizes chroma
|
||||||
|
* @see Rainbow::shade
|
||||||
|
*/
|
||||||
|
RAINBOW_EXPORT QColor darken(const QColor &, qreal amount = 0.5, qreal chromaGain = 1.0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adjust the luma and chroma components of a color. The amount is added
|
||||||
|
* to the corresponding component.
|
||||||
|
*
|
||||||
|
* @param lumaAmount amount by which to adjust the luma component of the
|
||||||
|
* color; 0.0 results in no change, -1.0 turns anything black, 1.0 turns
|
||||||
|
* anything white
|
||||||
|
* @param chromaAmount (optional) amount by which to adjust the chroma
|
||||||
|
* component of the color; 0.0 results in no change, -1.0 minimizes chroma,
|
||||||
|
* 1.0 maximizes chroma
|
||||||
|
* @see Rainbow::luma
|
||||||
|
*/
|
||||||
|
RAINBOW_EXPORT QColor shade(const QColor &, qreal lumaAmount, qreal chromaAmount = 0.0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new color by tinting one color with another. This function is
|
||||||
|
* meant for creating additional colors withings the same class (background,
|
||||||
|
* foreground) from colors in a different class. Therefore when @p amount
|
||||||
|
* is low, the luma of @p base is mostly preserved, while the hue and
|
||||||
|
* chroma of @p color is mostly inherited.
|
||||||
|
*
|
||||||
|
* @param base color to be tinted
|
||||||
|
* @param color color with which to tint
|
||||||
|
* @param amount how strongly to tint the base; 0.0 gives @p base,
|
||||||
|
* 1.0 gives @p color
|
||||||
|
*/
|
||||||
|
RAINBOW_EXPORT QColor tint(const QColor &base, const QColor &color, qreal amount = 0.3);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blend two colors into a new color by linear combination.
|
||||||
|
* @code
|
||||||
|
QColor lighter = Rainbow::mix(myColor, Qt::white)
|
||||||
|
* @endcode
|
||||||
|
* @param c1 first color.
|
||||||
|
* @param c2 second color.
|
||||||
|
* @param bias weight to be used for the mix. @p bias <= 0 gives @p c1,
|
||||||
|
* @p bias >= 1 gives @p c2. @p bias == 0.5 gives a 50% blend of @p c1
|
||||||
|
* and @p c2.
|
||||||
|
*/
|
||||||
|
RAINBOW_EXPORT QColor mix(const QColor &c1, const QColor &c2, qreal bias = 0.5);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blend two colors into a new color by painting the second color over the
|
||||||
|
* first using the specified composition mode.
|
||||||
|
* @code
|
||||||
|
QColor white(Qt::white);
|
||||||
|
white.setAlphaF(0.5);
|
||||||
|
QColor lighter = Rainbow::overlayColors(myColor, white);
|
||||||
|
@endcode
|
||||||
|
* @param base the base color (alpha channel is ignored).
|
||||||
|
* @param paint the color to be overlayed onto the base color.
|
||||||
|
* @param comp the CompositionMode used to do the blending.
|
||||||
|
*/
|
||||||
|
RAINBOW_EXPORT QColor
|
||||||
|
overlayColors(const QColor &base, const QColor &paint,
|
||||||
|
QPainter::CompositionMode comp = QPainter::CompositionMode_SourceOver);
|
||||||
|
}
|
22
depends/rainbow/include/rainbow_config.h
Normal file
22
depends/rainbow/include/rainbow_config.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
/* Copyright 2013-2015 MultiMC Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <QtCore/QtGlobal>
|
||||||
|
|
||||||
|
#ifdef RAINBOW_LIBRARY
|
||||||
|
#define RAINBOW_EXPORT Q_DECL_EXPORT
|
||||||
|
#else
|
||||||
|
#define RAINBOW_EXPORT Q_DECL_IMPORT
|
||||||
|
#endif
|
365
depends/rainbow/src/rainbow.cpp
Normal file
365
depends/rainbow/src/rainbow.cpp
Normal file
@ -0,0 +1,365 @@
|
|||||||
|
/* This was part of the KDE project - see KGuiAddons
|
||||||
|
* Copyright (C) 2007 Matthew Woehlke <mw_triad@users.sourceforge.net>
|
||||||
|
* Copyright (C) 2007 Olaf Schmidt <ojschmidt@kde.org>
|
||||||
|
* Copyright (C) 2007 Thomas Zander <zander@kde.org>
|
||||||
|
* Copyright (C) 2007 Zack Rusin <zack@kde.org>
|
||||||
|
* Copyright (C) 2015 Petr Mrazek <peterix@gmail.com>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Library General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Library General Public License
|
||||||
|
* along with this library; see the file COPYING.LIB. If not, write to
|
||||||
|
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../include/rainbow.h"
|
||||||
|
|
||||||
|
#include <QColor>
|
||||||
|
#include <QImage>
|
||||||
|
#include <QtNumeric> // qIsNaN
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
//BEGIN internal helper functions
|
||||||
|
|
||||||
|
static inline qreal wrap(qreal a, qreal d = 1.0)
|
||||||
|
{
|
||||||
|
qreal r = fmod(a, d);
|
||||||
|
return (r < 0.0 ? d + r : (r > 0.0 ? r : 0.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
// normalize: like qBound(a, 0.0, 1.0) but without needing the args and with
|
||||||
|
// "safer" behavior on NaN (isnan(a) -> return 0.0)
|
||||||
|
static inline qreal normalize(qreal a)
|
||||||
|
{
|
||||||
|
return (a < 1.0 ? (a > 0.0 ? a : 0.0) : 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// HCY color space
|
||||||
|
|
||||||
|
#define HCY_REC 709 // use 709 for now
|
||||||
|
#if HCY_REC == 601
|
||||||
|
static const qreal yc[3] = {0.299, 0.587, 0.114};
|
||||||
|
#elif HCY_REC == 709
|
||||||
|
static const qreal yc[3] = {0.2126, 0.7152, 0.0722};
|
||||||
|
#else // use Qt values
|
||||||
|
static const qreal yc[3] = {0.34375, 0.5, 0.15625};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class KHCY
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit KHCY(const QColor &color)
|
||||||
|
{
|
||||||
|
qreal r = gamma(color.redF());
|
||||||
|
qreal g = gamma(color.greenF());
|
||||||
|
qreal b = gamma(color.blueF());
|
||||||
|
a = color.alphaF();
|
||||||
|
|
||||||
|
// luma component
|
||||||
|
y = lumag(r, g, b);
|
||||||
|
|
||||||
|
// hue component
|
||||||
|
qreal p = qMax(qMax(r, g), b);
|
||||||
|
qreal n = qMin(qMin(r, g), b);
|
||||||
|
qreal d = 6.0 * (p - n);
|
||||||
|
if (n == p)
|
||||||
|
{
|
||||||
|
h = 0.0;
|
||||||
|
}
|
||||||
|
else if (r == p)
|
||||||
|
{
|
||||||
|
h = ((g - b) / d);
|
||||||
|
}
|
||||||
|
else if (g == p)
|
||||||
|
{
|
||||||
|
h = ((b - r) / d) + (1.0 / 3.0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
h = ((r - g) / d) + (2.0 / 3.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// chroma component
|
||||||
|
if (r == g && g == b)
|
||||||
|
{
|
||||||
|
c = 0.0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
c = qMax((y - n) / y, (p - y) / (1 - y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
explicit KHCY(qreal h_, qreal c_, qreal y_, qreal a_ = 1.0)
|
||||||
|
{
|
||||||
|
h = h_;
|
||||||
|
c = c_;
|
||||||
|
y = y_;
|
||||||
|
a = a_;
|
||||||
|
}
|
||||||
|
|
||||||
|
QColor qColor() const
|
||||||
|
{
|
||||||
|
// start with sane component values
|
||||||
|
qreal _h = wrap(h);
|
||||||
|
qreal _c = normalize(c);
|
||||||
|
qreal _y = normalize(y);
|
||||||
|
|
||||||
|
// calculate some needed variables
|
||||||
|
qreal _hs = _h * 6.0, th, tm;
|
||||||
|
if (_hs < 1.0)
|
||||||
|
{
|
||||||
|
th = _hs;
|
||||||
|
tm = yc[0] + yc[1] * th;
|
||||||
|
}
|
||||||
|
else if (_hs < 2.0)
|
||||||
|
{
|
||||||
|
th = 2.0 - _hs;
|
||||||
|
tm = yc[1] + yc[0] * th;
|
||||||
|
}
|
||||||
|
else if (_hs < 3.0)
|
||||||
|
{
|
||||||
|
th = _hs - 2.0;
|
||||||
|
tm = yc[1] + yc[2] * th;
|
||||||
|
}
|
||||||
|
else if (_hs < 4.0)
|
||||||
|
{
|
||||||
|
th = 4.0 - _hs;
|
||||||
|
tm = yc[2] + yc[1] * th;
|
||||||
|
}
|
||||||
|
else if (_hs < 5.0)
|
||||||
|
{
|
||||||
|
th = _hs - 4.0;
|
||||||
|
tm = yc[2] + yc[0] * th;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
th = 6.0 - _hs;
|
||||||
|
tm = yc[0] + yc[2] * th;
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate RGB channels in sorted order
|
||||||
|
qreal tn, to, tp;
|
||||||
|
if (tm >= _y)
|
||||||
|
{
|
||||||
|
tp = _y + _y * _c * (1.0 - tm) / tm;
|
||||||
|
to = _y + _y * _c * (th - tm) / tm;
|
||||||
|
tn = _y - (_y * _c);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tp = _y + (1.0 - _y) * _c;
|
||||||
|
to = _y + (1.0 - _y) * _c * (th - tm) / (1.0 - tm);
|
||||||
|
tn = _y - (1.0 - _y) * _c * tm / (1.0 - tm);
|
||||||
|
}
|
||||||
|
|
||||||
|
// return RGB channels in appropriate order
|
||||||
|
if (_hs < 1.0)
|
||||||
|
{
|
||||||
|
return QColor::fromRgbF(igamma(tp), igamma(to), igamma(tn), a);
|
||||||
|
}
|
||||||
|
else if (_hs < 2.0)
|
||||||
|
{
|
||||||
|
return QColor::fromRgbF(igamma(to), igamma(tp), igamma(tn), a);
|
||||||
|
}
|
||||||
|
else if (_hs < 3.0)
|
||||||
|
{
|
||||||
|
return QColor::fromRgbF(igamma(tn), igamma(tp), igamma(to), a);
|
||||||
|
}
|
||||||
|
else if (_hs < 4.0)
|
||||||
|
{
|
||||||
|
return QColor::fromRgbF(igamma(tn), igamma(to), igamma(tp), a);
|
||||||
|
}
|
||||||
|
else if (_hs < 5.0)
|
||||||
|
{
|
||||||
|
return QColor::fromRgbF(igamma(to), igamma(tn), igamma(tp), a);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return QColor::fromRgbF(igamma(tp), igamma(tn), igamma(to), a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal h, c, y, a;
|
||||||
|
static qreal luma(const QColor &color)
|
||||||
|
{
|
||||||
|
return lumag(gamma(color.redF()), gamma(color.greenF()), gamma(color.blueF()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static qreal gamma(qreal n)
|
||||||
|
{
|
||||||
|
return pow(normalize(n), 2.2);
|
||||||
|
}
|
||||||
|
static qreal igamma(qreal n)
|
||||||
|
{
|
||||||
|
return pow(normalize(n), 1.0 / 2.2);
|
||||||
|
}
|
||||||
|
static qreal lumag(qreal r, qreal g, qreal b)
|
||||||
|
{
|
||||||
|
return r * yc[0] + g * yc[1] + b * yc[2];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline qreal mixQreal(qreal a, qreal b, qreal bias)
|
||||||
|
{
|
||||||
|
return a + (b - a) * bias;
|
||||||
|
}
|
||||||
|
//END internal helper functions
|
||||||
|
|
||||||
|
qreal Rainbow::luma(const QColor &color)
|
||||||
|
{
|
||||||
|
return KHCY::luma(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Rainbow::getHcy(const QColor &color, qreal *h, qreal *c, qreal *y, qreal *a)
|
||||||
|
{
|
||||||
|
if (!c || !h || !y)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
KHCY khcy(color);
|
||||||
|
*c = khcy.c;
|
||||||
|
*h = khcy.h;
|
||||||
|
*y = khcy.y;
|
||||||
|
if (a)
|
||||||
|
{
|
||||||
|
*a = khcy.a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static qreal contrastRatioForLuma(qreal y1, qreal y2)
|
||||||
|
{
|
||||||
|
if (y1 > y2)
|
||||||
|
{
|
||||||
|
return (y1 + 0.05) / (y2 + 0.05);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return (y2 + 0.05) / (y1 + 0.05);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal Rainbow::contrastRatio(const QColor &c1, const QColor &c2)
|
||||||
|
{
|
||||||
|
return contrastRatioForLuma(luma(c1), luma(c2));
|
||||||
|
}
|
||||||
|
|
||||||
|
QColor Rainbow::lighten(const QColor &color, qreal ky, qreal kc)
|
||||||
|
{
|
||||||
|
KHCY c(color);
|
||||||
|
c.y = 1.0 - normalize((1.0 - c.y) * (1.0 - ky));
|
||||||
|
c.c = 1.0 - normalize((1.0 - c.c) * kc);
|
||||||
|
return c.qColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
QColor Rainbow::darken(const QColor &color, qreal ky, qreal kc)
|
||||||
|
{
|
||||||
|
KHCY c(color);
|
||||||
|
c.y = normalize(c.y * (1.0 - ky));
|
||||||
|
c.c = normalize(c.c * kc);
|
||||||
|
return c.qColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
QColor Rainbow::shade(const QColor &color, qreal ky, qreal kc)
|
||||||
|
{
|
||||||
|
KHCY c(color);
|
||||||
|
c.y = normalize(c.y + ky);
|
||||||
|
c.c = normalize(c.c + kc);
|
||||||
|
return c.qColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
static QColor tintHelper(const QColor &base, qreal baseLuma, const QColor &color, qreal amount)
|
||||||
|
{
|
||||||
|
KHCY result(Rainbow::mix(base, color, pow(amount, 0.3)));
|
||||||
|
result.y = mixQreal(baseLuma, result.y, amount);
|
||||||
|
|
||||||
|
return result.qColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
QColor Rainbow::tint(const QColor &base, const QColor &color, qreal amount)
|
||||||
|
{
|
||||||
|
if (amount <= 0.0)
|
||||||
|
{
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
if (amount >= 1.0)
|
||||||
|
{
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
if (qIsNaN(amount))
|
||||||
|
{
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal baseLuma = luma(base); // cache value because luma call is expensive
|
||||||
|
double ri = contrastRatioForLuma(baseLuma, luma(color));
|
||||||
|
double rg = 1.0 + ((ri + 1.0) * amount * amount * amount);
|
||||||
|
double u = 1.0, l = 0.0;
|
||||||
|
QColor result;
|
||||||
|
for (int i = 12; i; --i)
|
||||||
|
{
|
||||||
|
double a = 0.5 * (l + u);
|
||||||
|
result = tintHelper(base, baseLuma, color, a);
|
||||||
|
double ra = contrastRatioForLuma(baseLuma, luma(result));
|
||||||
|
if (ra > rg)
|
||||||
|
{
|
||||||
|
u = a;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
l = a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
QColor Rainbow::mix(const QColor &c1, const QColor &c2, qreal bias)
|
||||||
|
{
|
||||||
|
if (bias <= 0.0)
|
||||||
|
{
|
||||||
|
return c1;
|
||||||
|
}
|
||||||
|
if (bias >= 1.0)
|
||||||
|
{
|
||||||
|
return c2;
|
||||||
|
}
|
||||||
|
if (qIsNaN(bias))
|
||||||
|
{
|
||||||
|
return c1;
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal r = mixQreal(c1.redF(), c2.redF(), bias);
|
||||||
|
qreal g = mixQreal(c1.greenF(), c2.greenF(), bias);
|
||||||
|
qreal b = mixQreal(c1.blueF(), c2.blueF(), bias);
|
||||||
|
qreal a = mixQreal(c1.alphaF(), c2.alphaF(), bias);
|
||||||
|
|
||||||
|
return QColor::fromRgbF(r, g, b, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
QColor Rainbow::overlayColors(const QColor &base, const QColor &paint,
|
||||||
|
QPainter::CompositionMode comp)
|
||||||
|
{
|
||||||
|
// This isn't the fastest way, but should be "fast enough".
|
||||||
|
// It's also the only safe way to use QPainter::CompositionMode
|
||||||
|
QImage img(1, 1, QImage::Format_ARGB32_Premultiplied);
|
||||||
|
QPainter p(&img);
|
||||||
|
QColor start = base;
|
||||||
|
start.setAlpha(255); // opaque
|
||||||
|
p.fillRect(0, 0, 1, 1, start);
|
||||||
|
p.setCompositionMode(comp);
|
||||||
|
p.fillRect(0, 0, 1, 1, paint);
|
||||||
|
p.end();
|
||||||
|
return img.pixel(0, 0);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user