File indexing completed on 2024-05-12 04:44:32
0001 // SPDX-FileCopyrightText: Lukas Sommer <sommerluk@gmail.com> 0002 // SPDX-License-Identifier: BSD-2-Clause OR MIT 0003 0004 // This file contains the following documentation: 0005 // – All the @page documentation. Putting all @page documentation in this 0006 // single file allows that they show up in the documentation in 0007 // alphabetical order. 0008 // – The namespace documentation 0009 0010 /** @page build Build instructions and requirements 0011 * 0012 * Build-time dependencies: 0013 * - LittleCMS 2 (minimum version: 2.0) 0014 * - Qt 5 (minimum version: 5.15) <!-- Qt 5.15 has an API that is close 0015 * to Qt 6. It introduces some new functions we are using to avoid 0016 * deprecated older functions. --> or Qt 6 (minimum version: 6.0.0). 0017 Components: Core, Gui, Widgets, DBus, Concurrent, Test, Svg. 0018 * - CMake 0019 * - ECM (Extra CMake Modules from KDE) 0020 * - C++17 0021 * - Both, the input character set and the execution character set, have 0022 * to be UTF8. (See @ref compilercharacterset for more details.) 0023 * <!-- 0024 * Qt 5.6 (which is the minimum Qt version required 0025 * by this library) only requires C++03. Only starting 0026 * with Qt 5.7, Qt itself requires C++11. Source: 0027 * https://doc.qt.io/qt-5.9/cmake-manual.html#using-qt-5-with-cmake-older-than-3-1-0 0028 * 0029 * Qt 6 requires minimum C++17, as 0030 * https://doc-snapshots.qt.io/qt6-dev/cmake-get-started.html 0031 * explains. 0032 * 0033 * Our library code uses C++11 features, for example “constexpr”. 0034 * 0035 * In the CMakeLists.txt file, we set -std=c++17 and we set 0036 * also -Wpedantic and -pedantic-errors to enforce it. That is 0037 * a useful option for this library if we decide to make it Qt-6-only. 0038 * But it is even be useful if we support Qt 5, so we have future-proof 0039 * requirements that we do not have to raise soon, and that are a 0040 * good base for LTS. 0041 * --> 0042 * - Optional: There is also a LittleCMS plugin called 0043 * <em>fast_float plug-in</em> that you can include into the 0044 * source code of your application and load it in your main function 0045 * before using this library. This can make color management faster. 0046 * (Note that this plugin has a different license than LittleCMS itself.) 0047 * 0048 * Additional mandatory run-time dependencies: 0049 * - QSvgIconEnginePlugin. Available plugins are loaded 0050 * automatically by Qt. Therefore, just make sure that this plugin is 0051 * present. On Linux, it seems possible to enforce this by linking 0052 * dynamically to the plugin itself, if you want to. This forces Linux 0053 * package managers to produce packages of your application that depend 0054 * not only on Qt base, but also on the SVG plugin. A typical file name of 0055 * the plugin is <tt>plugins/iconengines/libqsvgicon.so</tt>. 0056 * 0057 * Please make sure that you comply with the licences of used libraries. 0058 * 0059 * To prepare the build, run cmake. We provide plenty of CMake options 0060 * that control the build type (shared/dynamic vs. static), IPO/LPO and 0061 * much more. The options are self-documenting. When you run CMake, 0062 * the options are listed with their values and a description of them. 0063 * 0064 * Then, to build and install the library: 0065 * @code{.unparsed} 0066 * make && sudo make install 0067 * @endcode 0068 * 0069 * To do unit testing: 0070 * @code{.unparsed} 0071 * make build_test test 0072 * @endcode */ 0073 0074 /** @internal 0075 * 0076 * @page codingstyle Coding style 0077 * 0078 * Always document your code. 0079 * 0080 * @section codingstylecpp C++ 0081 * 0082 * - Provide unit tests for your code. 0083 * - If working with children within Qt’s object hierarchy, allocate on the 0084 * heap and use raw pointers or guarded pointers (`QPointer`). If not, 0085 * allocate on the stack or use smart pointers. Prefer Qt’s smart pointers 0086 * over the <tt>std</tt> smart pointers of C++. 0087 * - Use KDE’s 0088 * <a href="https://community.kde.org/Policies/Frameworks_Coding_Style"> 0089 * Frameworks Coding Style</a>. This can be done automatically with 0090 * clang-format. 0091 * - Comments within the code should have this form: <tt>// comment</tt> 0092 * <br/> This allows to comment out quickly large parts of the code for 0093 * testing purposes. 0094 * - Comments for Doxygen should have this form: <tt>/** Comment */</tt> 0095 * 0096 * @section codingstylecmake CMake 0097 * 0098 * @subsection codingstylecmakeusefuldocumentation Useful documentation 0099 * 0100 * - <a href="https://preshing.com/20170522/learn-cmakes-scripting-language-in-15-minutes/"> 0101 * Introduction to the CMake script language</a> 0102 * - <a href="https://github.com/onqtam/awesome-cmake"> 0103 * Curated list of awesome CMake scripts, modules, examples and others</a> 0104 * - <a href="https://llvm.org/docs/CMakePrimer.html">General introduction 0105 * into CMake (both, the script language and the commands)</a> 0106 * 0107 * @subsection codingstylecmakemodern Use “Modern CMake” 0108 * 0109 * Use <em>Modern CMake</em>: Avoid global settings like 0110 * <tt>include_directories()</tt>. Use target-based commands like 0111 * <tt>target_include_directories()</tt> instead. Use 0112 * <tt>target_link_libraries()</tt> to pull in dependencies, which gives you 0113 * automatically the correct include directories, compile options etc. 0114 * When using <tt>target_link_libraries()</tt>, always specify 0115 * <tt>PUBLIC</tt> or <tt>PRIVATE</tt> or <tt>INTERFACE</tt> explicitly. 0116 * 0117 * @subsection codingstylecmakeindent Indent 0118 * 0119 * Use 4 spaces for indenting. Do not use tabs. 0120 * 0121 * @subsection codingstylecmakequotationmarks Quotation marks 0122 * 0123 * Use quotation marks when you want to represent a string. 0124 * Do not use quotation marks when you mean a keyword. Example: 0125 * 0126 * @code{.unparsed} 0127 * set(myvar "foo") 0128 * @endcode 0129 * 0130 * Particularly, always quote strings within control structures: 0131 * 0132 * @code{.unparsed} 0133 * if("${myvar}" STREQUAL "bar") 0134 * @endcode 0135 * 0136 * @subsection codingstylecmakeboolean Boolean 0137 * 0138 * CMake allows various representations of boolean. Use only the forms 0139 * <tt>TRUE</tt> and <tt>FALSE</tt>. Do not quote them. 0140 * 0141 * @subsection codingstylevariablecheck Check if a variable exists 0142 * 0143 * Check if a variable exists like this: 0144 * 0145 * @code{.unparsed} 0146 * if(DEFINED varname) 0147 * @endcode 0148 * 0149 * @subsection codingstylecmakenaming Naming 0150 * 0151 * Functions and macros: 0152 * 0153 * @code{.unparsed} 0154 * lower_case() 0155 * @endcode 0156 * 0157 * Control structures: <tt>lower_case()</tt>, with empty <tt>else()</tt>, 0158 * <tt>endif()</tt>, <tt>endfunction()</tt>… 0159 * 0160 * Operators/keywords/directives/extra options: <tt>UPPER_CASE</tt> without 0161 * quotes. Examples: 0162 * 0163 * @code{.unparsed} 0164 * if(condition STREQUAL "") 0165 * @endcode 0166 * 0167 * @code{.unparsed} 0168 * do_something(... USE_THIS) 0169 * @endcode 0170 * 0171 * @code{.unparsed} 0172 * file(COPY ...) 0173 * @endcode 0174 * 0175 * @subsection codingstyleparenthesis Parenthesis 0176 * 0177 * Multi-line calls have trailing parenthesis on the same line as 0178 * last parameter, not on separate line: 0179 * 0180 * @code{.unparsed} 0181 * set(my_variable 0182 * "value1" 0183 * "value2" 0184 * "value3) 0185 * @endcode 0186 * 0187 * @subsection codingstyleorder Order 0188 * 0189 * Source and header lists should be ordered alphabetically, 0190 * subdirectories last, preferably separated by a single empty line. 0191 * 0192 * @subsection codingstylelinelength Line length 0193 * 0194 * Keep the length of the line below 80 characters when possible. 0195 * No trailing whitespace. 0196 * 0197 * @subsection codingstyledirectories Directories 0198 * 0199 * A directory path may not have a trailing <tt>/</tt>. This is to avoid 0200 * duplicates like <tt>//</tt> when composing paths: 0201 * 0202 * @code{.unparsed} 0203 * set(my_path "/usr/bin/") # BAD 0204 * set(my_path "/usr/bin") # GOOD 0205 * set(my_file "${my_path}/my_file") 0206 * @endcode 0207 * 0208 * @subsection codingstylelists Lists 0209 * 0210 * Declaring an empty list: 0211 * 0212 * @code{.unparsed} 0213 * set(mylist) 0214 * @endcode 0215 * 0216 * Declaring and initializing a list at the same time: 0217 * 0218 * @code{.unparsed} 0219 * set(mylist 0220 * "first item" 0221 * "second item" 0222 * "third item") 0223 * @endcode 0224 * 0225 * Append to a list: 0226 * 0227 * @code{.unparsed} 0228 * list(APPEND mylist "last item") 0229 * @endcode 0230 * 0231 * @subsection codingstyleprojectname ${PROJECT_NAME} 0232 * 0233 * Use <tt>${PROJECT_NAME}</tt> for global variables, targets and labels 0234 * instead of repeating the project name manually or using fixed names: 0235 * 0236 * @code{.unparsed} 0237 * add_executable(${PROJECT_NAME} …) 0238 * @endcode */ 0239 0240 /** @page compilercharacterset Compiler character sets 0241 * 0242 * @section compilercharacterset_ Compiler character sets 0243 * 0244 * Compilers have three different character sets: 0245 * - Input character set (the character set of the source code) 0246 * - Narrow execution character set 0247 * (for <tt>char</tt> and for string literals without prefix) 0248 * - Wide execution character set 0249 * (for <tt>wchar_t</tt> and for string literals with <tt>L</tt> prefix) 0250 * 0251 * @subsection inputcharacterset Input character set 0252 * 0253 * This source code of this library is encoded in UTF8. Therefore, your 0254 * compiler must treat is also as UTF-8. 0255 * 0256 * Why are we using UTF-8 instead of ASCII? 0257 * - UTF-8 is more complete than ASCII. ASCII does not even provide basic 0258 * typographic symbols like en-dash, em-dash or non-breaking space 0259 * characters or quotes. 0260 * - Unicode exists since 1991, UTF-8 since 1993. It’s time to get rid of 0261 * the insufficient ASCII character. It’s time to use Unicode. 0262 * - We use non-ASCII characters for (typographically 0263 * correct) Doxygen documentation and partially also for non-Doxygen 0264 * source code comments. It would be quite annoying to use HTML 0265 * entities for each non-ASCII character in the Doxygen documentation; 0266 * and it would be pointless to do it for non-Doxygen source code 0267 * comments. 0268 * - <tt>i18n()</tt> and <tt>ki18n()</tt> and <tt>tr()</tt> require both, 0269 * the source file and <tt>char*</tt> to be encoded in UTF-8; no other 0270 * encodings are supported. (Only ASCII would be UTF-8 compatible, 0271 * but in practice this encoding is not supported, but only 8859-Latin 0272 * encodings, which allow code points higher than 127, which risks to 0273 * introduce incompatibilities. Therefore, this would not be a good 0274 * option.) 0275 * - The C++ identifiers of library symbols are however (currently) 0276 * ASCII-only. 0277 * 0278 * So we use a <tt>static_assert</tt> statement to control this. 0279 * 0280 * @subsection narowexecutioncharacterset Narrow execution character set 0281 * 0282 * Why are we using UTF-8 as narrow execution character set? 0283 * - <tt>i18n()</tt> and <tt>ki18n()</tt> and <tt>tr()</tt> require both, 0284 * the source file and <tt>char*</tt> to be encoded in UTF-8; no other 0285 * encodings are supported. 0286 * - Implicit conversion from <tt>char*</tt> to <tt>QString</tt> assumes 0287 * that <tt>char*</tt> is UTF-8 encoded. Thus we disable this implicit 0288 * conversion in <tt>CMakeLists.txt</tt>, it’s wise to stay compatible. 0289 * 0290 * Therefore, a static assert controls that really UTF-8 is used 0291 * as narrow execution character set. 0292 * 0293 * @subsection wideexecutioncharacterset Wide execution character set 0294 * 0295 * We do not use actively the wide execution character set. There is 0296 * a usage when communicating with LittleCMS, but there we depend anyway 0297 * from LittleCMS. Therefore, currently, no static assert forces a specific 0298 * wide execution character set. 0299 * 0300 * @internal 0301 * 0302 * @note The static asserts that enforce the character sets are located 0303 * in @ref staticasserts.cpp. */ 0304 0305 /** @internal 0306 * 0307 * @page datatypes Data types 0308 * 0309 * The library uses in general <tt>int</tt> for integer values, because 0310 * <tt>QSize()</tt> and <tt>QPoint()</tt> also do. As the library relies 0311 * heavily on the usage of <tt>QSize()</tt> and <tt>QPoint()</tt>, this 0312 * seems reasonable. 0313 * 0314 * For the same reason, it uses generally <tt>qreal</tt> 0315 * for floating point values, because <tt>QPointF()</tt> also does. 0316 * 0317 * Output colors that are shown on the screen, are usually 8-bit-per-channel 0318 * colors. For internal transformation, usually <tt>qreal</tt> 0319 * is used for each channel, giving a better precision and reducing rounding 0320 * errors. */ 0321 0322 /** @internal 0323 * 0324 * @page generaltodolist General TODO list 0325 * 0326 * This is a TODO list that contains general ideas or issues of this 0327 * library. 0328 * 0329 * @todo Use words as hints for color ranges? Muted/dull colors have a low 0330 * chroma value. The dark ones (getrübte/gebrochene Farben) are created by 0331 * adding black (and possibly a bit of white) and include warm tones (the 0332 * browns) and cool tones (the olives). The light ones are called Pastel 0333 * colors and are created by adding white (and possibly a bit of 0334 * black) and include warm tones (like baby pink) and cool 0335 * tones (like baby blue). Warm colors are located at a color angle of 0336 * about 45°, cool colors at about 225°. Could we mark this in the diagrams? 0337 * Cold and warm could be marked by a text outside the color wheel at the 0338 * given position. The other ones seem to be more complicated: These specific 0339 * color terms do not have a translation in all languages. (For “muted colors”, 0340 * there is no good German translation, and for “getrübte Farben”, there is 0341 * no good English translation. 0342 * 0343 * @todo A design question: Following KDE’s HIG, if the command requires 0344 * additional user interaction to complete, at the end its label there 0345 * should be an elipsis sfs (…). Currently, this only seems to apply 0346 * to @ref PerceptualColor::ColorDialogPrivate::m_screenColorPickerButton. 0347 * 0348 * @todo https://invent.kde.org/plasma/kdeplasma-addons/-/merge_requests/249 0349 * allows the user to drag and drop an image file. The image’s average color 0350 * is calculated and set as current color of Plasma’s color picker widget. 0351 * Furthermore, it seems that Plasma’s color picker widget also accepts 0352 * color codes for drag-and-drop. (Which ones? Maybe the #128945 style?) 0353 * Would this make sense also for our library? 0354 * 0355 * @todo ITUR profile: Minimum widget size must be smaller! On high sizes, the 0356 * inner focus indicator of color wheel too narrow to hue circle. 0357 * On RGB 255 0 0 no value indicator is visible. The high-chroma values 0358 * are empty in the diagram! 0359 * 0360 * @todo Touch friendly: @ref PerceptualColor::ColorPatch, 0361 * @ref PerceptualColor::GradientSlider etc. at least 0362 * as thick as (normal) buttons. Qt6 replaces QTouchDevice by 0363 * QInputDevice::devices()… 0364 * 0365 * @todo For all diagram images: No abort during first interlacing pass. (See 0366 * @ref PerceptualColor::AsyncImageProvider for details.) 0367 * 0368 * @todo All scripts (both, local and CI scripts) should break and stop 0369 * on every error. When implementing this, be beware of side effects 0370 * (some local scripts are also called from the CI and so on…). 0371 * 0372 * @todo Review @ref PerceptualColor::RgbColorSpace. And change 0373 * it in order to allow support for Oklab. And maybe Googles 0374 * <a href="https://github.com/material-foundation/material-color-utilities"> 0375 * HTC</a>. 0376 * 0377 * @todo A design question: In the chroma-lightness diagram, the color 0378 * wheel is a slider and reacts as such. However, in the chroma-hue-diagram, 0379 * the same color wheel is just decoration (for orientation). Isn’t this 0380 * different behaviour of two visually identical elements confusing? 0381 * 0382 * @todo A design question: Should we use 0383 * <a href="https://doc.qt.io/qt-6/qt.html#CursorShape-enum"> 0384 * <tt>Qt::CrossCursor</tt></a> for two-dimensional selections like 0385 * @ref PerceptualColor::ChromaHueDiagram? And should we use 0386 * <a href="https://doc.qt.io/qt-6/qt.html#CursorShape-enum"><tt> 0387 * Qt::UpArrowCursor</tt></a> for one-dimensional selections like 0388 * @ref PerceptualColor::GradientSlider? 0389 * 0390 * @todo Remove things form the public API, leaving only the absolutely 0391 * minimal API that is required by the user. 0392 * 0393 * @todo Avoid “final” in the public API (or even altogether?). Implement 0394 * a codecheck for this. 0395 * 0396 * @todo <a href="https://valgrind.org/docs/manual/quick-start.html"> Test with 0397 * valgrind.org</a> 0398 * 0399 * @todo Most widgets of this library allocate in each paint event a new 0400 * buffer to paint on, before painting on the widget. This is also done 0401 * because only <tt>QImage</tt> guarantees the same result on all platforms, 0402 * while <tt>QPixmap</tt> is platform-dependent and Qt does not guarantee that 0403 * for example <tt>QPainter::Antialiasing</tt> is available on all platforms. 0404 * However, not using a buffer would save memory! Can we know if the current 0405 * platform supports <tt>QPainter::Antialiasing</tt> and buffer only if 0406 * necessary? Or could we at least instantiate only one single buffer per 0407 * application, that is than shared between all the widgets of our library? 0408 * This buffer would never be freed, so it will always occupy memory. But 0409 * this avoids the time-consuming memory allocations at each paint event! 0410 * 0411 * @todo Use <tt>QCache</tt> where is makes sense. Maybe 0412 * @ref PerceptualColor::RgbColorSpace::reduceCielchD50ChromaToFitIntoGamut() or 0413 * @ref PerceptualColor::RgbColorSpace::isCielchD50InGamut() or 0414 * @ref PerceptualColor::RgbColorSpace::isCielabD50InGamut() or 0415 * @ref PerceptualColor::ChromaLightnessDiagramPrivate::nearestInGamutColorByAdjustingChromaLightness((). 0416 * 0417 * @todo Switch AbstractDiagram::handleOutlineThickness() and 0418 * handleRadius() and spaceForFocusIndicator() to use PM_DefaultFrameWidth. 0419 * (PM_DefaultFrameWidth seems to be used yet in ColorPatch.) 0420 * 0421 * @todo QColor is ambiguous: It allows different types of color system, 0422 * or even various versions of the same color system at different 0423 * precisions (RGB). This makes it difficult to communicate in the API 0424 * which is the type of color (model) it contains. Therefore, we should 0425 * eliminate all its usage within this library (except where it is necessary 0426 * for API compatibility with Qt). 0427 * 0428 * @todo If using the Motif style, the @ref PerceptualColor::ChromaHueDiagram 0429 * widget, which has circular look-and-feel, has a rectangular focus 0430 * indicator corresponding the rectangular widget geometry, which looks 0431 * quite ugly. On the other hand, @ref PerceptualColor::WheelColorPicker 0432 * has also circular look-and-feel, but no rectangular focus indicator 0433 * corresponding the rectangular widget geometry, which looks better. 0434 * Why doesn’t @ref PerceptualColor::ChromaHueDiagram also behave 0435 * like @ref PerceptualColor::WheelColorPicker? And 0436 * how does @ref PerceptualColor::ColorWheel behave? 0437 * 0438 * @todo Idea: Provide QColorWidget (like QColorDialog, but inheriting 0439 * from QWidget, and no buttons). Does this make sense? 0440 * 0441 * @todo Use implicit data sharing in @ref PerceptualColor::RgbColorSpace 0442 * instead of <tt>QSharedPointer\< @ref PerceptualColor::RgbColorSpace \></tt>. 0443 * But: Wouldn’t this require to make the declaration 0444 * of @ref PerceptualColor::RgbColorSpace, which was secret until today, 0445 * public? If so, this would not be good… 0446 * 0447 * @todo Dual-Licence with Apache2 and/or Boost licence? 0448 * 0449 * @todo Reduce number of exported symbols. 0450 * 0451 * @todo Rename main.cpp. 0452 * 0453 * @todo Currently, we consider that a mouse clicks click a pixel, but mean 0454 * the coordinate point in the middle of this pixel. This seems an approach 0455 * that other widgets (including Qt itself) do not use. And maybe is meant also 0456 * the coordinate at the top of the mouse cursor, so no offset by (0.5, 0.5) 0457 * would be necessary. This would give better results (at least on LTR 0458 * mouse cursors, but what's about crosshair cursors and RTL cursors?) 0459 * 0460 * @todo We do some hacks to get circle-like (instead of rectangular) 0461 * feeling for our circular widgets, which is not perfect when talking 0462 * about mouse events. It seems that QWidget::setMask() offers an 0463 * alternative, restricting mouse events (and painting) to a given 0464 * mask. Does this actually work also for mouse focus management? 0465 * If so: Has it performance penalties? If not, we should probably use 0466 * it! And document that those widgets are circular widgets and from 0467 * a user perspective behave like circular widgets (both paint event 0468 * and mouse cursor reactions/usage feeling), though from an application 0469 * programmer (that uses this library) perspective, they are of course 0470 * rectangular in the layout system. And: Post the results on 0471 * <a href="https://forum.qt.io/topic/118547/accept-reject-focus-coming-by-mouse-click-based-on-coordinates"> 0472 * this Qt Forum thread</a>. 0473 * 0474 * @todo Support more of Qt Style Sheets, for example allow 0475 * customizing the neutral-gray background of diagrams? If 0476 * so, @ref PerceptualColor::drawQWidgetStyleSheetAware() 0477 * is available. Otherwise, remove the currently not used 0478 * @ref PerceptualColor::drawQWidgetStyleSheetAware() from 0479 * this library. 0480 * 0481 * @todo Unit tests for endianess. Maybe QtEndian can help… 0482 * 0483 * @todo General library properties: 0484 * - test cross-platform support and different byte-orders 0485 * - Could we integrate more with QStyle? Apparently 0486 * <a href="https://api.kde.org/frameworks/frameworkintegration/html/classKStyle.html"> 0487 * KStyle</a> is a QCommonStyle-based class that provides 0488 * support for QString-based query for custom style hints, 0489 * control elements and sub elements. There is also 0490 * <a href="https://api.kde.org/frameworks/kwidgetsaddons/html/namespaceKStyleExtensions.html"> 0491 * KStyleExtensions</a> that allows apparently custom widgets to query 0492 * for these QString-based custom support, which allows to make the same 0493 * query independently of the actual style, without the need to hard-code 0494 * individual custom enum values for QStyle::ControlElement (and similar 0495 * enum) for each individual style. KStyleExtensions works for all 0496 * styles, also for these that are <em>not</em> subclasses of 0497 * <tt>KStyle</tt>. It reports if a given query is supported or not 0498 * by the underlying style. However, even Breeze, KDE’s default style, 0499 * seems not to inherit from KStyle, so the question is if KStyle is 0500 * not rather deprecated yet. An alternative would be if a style 0501 * has special functions just for PerceptualColor rendering, like 0502 * <tt>renderColorWheel</tt>. Than, we could cast the current QStyle 0503 * of the application to this style (if the actual current 0504 * style <em>is</em> this style), and call these functions. Big 0505 * disadvantage: We would have to <em>link</em> against all styles 0506 * that we want to support, which makes our library <em>depend</em> 0507 * on them, which is not reasonable. 0508 * - More work on accessibility. [This includes to work well with bigger 0509 * fonts. Should then the gradient be thicker and the marker 0510 * thicker? setAccessibleName().] The application Accerciser provides 0511 * inspection possibilities. 0512 * 0513 * @todo From KDE’s binary compatibility info page: In order to make a class 0514 * to extend in the future you should follow these rules: 0515 * - add non-inline virtual destructor even if the body is empty. 0516 * - re-implement event in QObject-derived classes, even if the body for 0517 * the function is just calling the base class' implementation. This is 0518 * specifically to avoid problems caused by adding a reimplemented virtual 0519 * function as discussed below. 0520 * 0521 * @todo Following the recommendation of the C++ core guidelines, all 0522 * destructors should be noexcept. 0523 * 0524 * @todo Make genereatescreenshots and the unit tests run on hardware 0525 * without graphic card. This would be good for Continuous Integration. 0526 * The XVFB Virtual framebuffer (https://de.m.wikipedia.org/wiki/Xvfb) 0527 * can do this for X apps. Also, it is possible to start X apps on 0528 * terminal without a window manager, see 0529 * https://linuxconfig.org/how-to-run-x-applications-without-a-desktop-or-a-wm 0530 * but I suppose an X server is still required? There seem to exist also 0531 * possibilities for Wayland 0532 * https://unix.stackexchange.com/questions/653672/virtual-wayland-display-server-possible 0533 * Also, there seems to be a Qt Platform Abstraction called “minimal” 0534 * (https://doc.qt.io/qt-6/qpa.html) for testing purposes. Elsewhere, 0535 * if I remember correctly, it was described as useful for testing without X. 0536 * 0537 * @todo The missing 3rd diagram (hue-lightness? But: Impossible to model 0538 * the circular behaviour of the LCH color space: It cannot be a cut through 0539 * the gamut body, but has to be a curve within the gamut body – not so 0540 * nice. And: The diagram width has to change with the selected hue if we want 0541 * to have correct scaling between x axis and y axis… 0542 * 0543 * @todo In https://phabricator.kde.org/T12359 is recommended to provide 0544 * RESET statements for all properties for better compatibility with QML. 0545 * As we provide widgets, this should not be too important. Are there also 0546 * good arguments for widgets to provide RESET? 0547 * 0548 * @todo Provide an init() function that calls qRegisterMetaType() for 0549 * all our types? 0550 * 0551 * @todo We prevent division by 0 in 0552 * @ref PerceptualColor::ChromaLightnessDiagramPrivate::fromWidgetPixelPositionToColor(). 0553 * We should make sure this happens also in the other diagram widgets! 0554 * 0555 * @todo Add a @ref PerceptualColor::ConstPropagatingUniquePointer to 0556 * all classes, including the non-pimpl classes, to allow for later 0557 * enhancements. 0558 * 0559 * @todo Remove setDevicePixelRatioF from all *Image classes. (It is 0560 * confusing, and at the same time there is no real need/benefit.) 0561 * Complete list: @ref PerceptualColor::ChromaHueImageParameters, 0562 * @ref PerceptualColor::ColorWheelImage, 0563 * @ref PerceptualColor::GradientImageParameters. 0564 * 0565 * @todo Test also on Windows. (Does it work well with VisualStudio?) 0566 * 0567 * @todo Test also Big-Endian compatibility using s390x Linux via Qemu? 0568 * KDE Invent does not support this out-of-the-box, but with a custom 0569 * script? 0570 * 0571 * @todo Test opaque RGB color space object with a non-export-all version 0572 * of this library to make sure it actually works for third-party developers. 0573 * 0574 * @todo Sometimes, on dual-screen setup, one screen has another DPI than 0575 * the other screen. Does this library behave correctly in these situations? 0576 * 0577 * @todo Would it make sense for @ref PerceptualColor::ChromaHueDiagram and 0578 * @ref PerceptualColor::ChromaLightnessDiagram to split up their property 0579 * <tt>currentColor</tt> into two properties: A two-dimensional property 0580 * for what the user can change, and a one-dimensional property 0581 * for what only the programmer can change? Or at least provide 0582 * a Q_INVOKABLE getter and maybe also setter support? So 0583 * @ref PerceptualColor::WheelColorPicker could use this 0584 * instead of a lambda expression to set the hue of the 0585 * @ref PerceptualColor::ChromaLightnessDiagram. And: Also when we don’t do 0586 * that: When setting <tt>currentColor</tt> to an out-of-gamut color, 0587 * what happens? Does @ref PerceptualColor::ChromaHueDiagram preserve 0588 * lightness, while @ref PerceptualColor::ChromaLightnessDiagram preserves 0589 * hue? Would this make sense? 0590 * 0591 * @todo Paint grayed-out handles for all widgets when setEnabled(false) 0592 * is used! For example 25% lightness instead of black. And 75% lightness 0593 * instead of white. But: Provide this information 0594 * in @ref PerceptualColor::AbstractDiagram! 0595 * 0596 * @todo It might be interesting to use <tt>QStyle::PM_FocusFrameHMargin</tt> 0597 * <em>(Horizontal margin that the focus frame will outset the widget 0598 * by.)</em> Or: <tt>QStyle::PM_FocusFrameVMargin</tt>. Using this for the 0599 * distance between the focus indicator and the actual content of the widget 0600 * maybe give a more <tt>QStyle</tt> compliant look. But: If using this, 0601 * ensurePolished() must be called before! 0602 * 0603 * @todo Use <tt>explicit</tt> on all constructors? 0604 * 0605 * @todo Screen picker with magnifier glass in two steps 0606 * similar to https://colorsnapper.com ? Or like in Firefox 0607 * (Menu → Weitere Werkzeuge → Farbpalette)? 0608 * 0609 * @todo Multi-licensing? Add Boost licence and Unlicense as an additional 0610 * choice? 0611 * 0612 * @todo The image cache for the gamut widgets should be updated 0613 * asynchronously (in its own thread or even various own threads 0614 * in parallel). While waiting for the result, an empty image could be used. 0615 * Or it might be useful to provide first a low-resolution version, and only 0616 * later-on a high-resolution version. Anyway, KDE provides an interesting 0617 * recommendation: <tt>int Units::humanMoment = 2000;</tt> <em>Time in 0618 * milliseconds equivalent to the theoretical human moment, which can be 0619 * used to determine whether how long to wait until the user should be 0620 * informed of something, or can be used as the limit for how long something 0621 * should wait before being automatically initiated. / Some examples: / 0622 * When the user types text in a search field, wait no longer than this 0623 * duration after the user completes typing before starting the search / 0624 * When loading data which would commonly arrive rapidly enough to not 0625 * require interaction, wait this long before showing a spinner</em> See 0626 * https://api.kde.org/frameworks/plasma-framework/html/classUnits.html#ab22ad7033b2e3d00a862650e82f5ba5e 0627 * for details. 0628 * 0629 * @todo HLC @ref PerceptualColor::MultiSpinBox Allow entering (on the 0630 * keyboard) of too big hues (361°), negative hues (-1°), negative chroma (-20) 0631 * and too big chroma (201 or 256) – but do not allow this with the arrows 0632 * (and how do the arrows react when currently one of these values is 0633 * shown?). Does this make sense? Anyway do <em>not</em> allow this for 0634 * lightness, because the lightness is <em>by definition</em> bound 0635 * to <tt>[0, 100]</tt>. 0636 * 0637 * @todo Multi-threaded application of color transforms. It seems okay to 0638 * create the color transforms in one thread and use the same color 0639 * transform (once created) from various other threads at the same time 0640 * as long as the flag <tt>cmsFLAGS_NOCACHE</tt> is used to create the 0641 * transform. 0642 * 0643 * @todo Automatically scale the thickness of the wheel (and maybe even the 0644 * handle) with varying widget size? 0645 * 0646 * @todo Support more color spaces? https://pypi.org/project/colorio/ for 0647 * example supports a lot of (also perceptually uniform) color spaces… 0648 * 0649 * @todo Export less symbols? 0650 * 0651 * @todo Check in all classes that take a @ref PerceptualColor::RgbColorSpace 0652 * that the shared pointer is actually not a <tt>nullptr</tt>. If is 0653 * <em>is</em> a <tt>nullptr</tt> than throw an exception. Throwing the 0654 * exception early might make error detection easier for users of the library. 0655 * 0656 * * @todo Avoid default arguments like <tt>void test(int i = 0)</tt> in 0657 * public headers, as changes require re-compilation of the client application 0658 * to take effect, which might lead to a miss-match of behaviour between 0659 * application and library, if compile-time and run-time version of the 0660 * library are not the same. Is the problem for default constructors 0661 * like <tt>ClassName() = default</tt> similar? 0662 * 0663 * @todo mark all public non-slot functions with Q_INVOKABLE (except property 0664 * setters and getters) 0665 * 0666 * @todo A good widget library should also be touchscreen-ready. Find 0667 * an alternative to @ref PerceptualColor::MultiSpinBox? How, for up 0668 * to 360 values (degrees in step by 1)? Or should the steps simply be bigger? 0669 * 0670 * @todo KDE Frameworks / https://marketplace.qt.io/ ? 0671 * https://community.kde.org/Incubator 0672 * 0673 * @todo Provide property bindings as described in 0674 * https://www.qt.io/blog/property-bindings-in-qt-6 or not? It is worth 0675 * when we do not support QML? What are the pitfalls? Imagine a property 0676 * that holds a percent value from 0 to 100; the setter enforces this 0677 * range; the binding bypasses the setter and allows every value? And: 0678 * How can callbacks know about when a setter was called in C++? See 0679 * also: https://doc.qt.io/qt-5/qtqml-cppintegration-exposecppattributes.html 0680 * and https://doc.qt.io/qt-5/qtqml-tutorials-extending-qml-example.html and 0681 * http://blog.aeguana.com/2015/12/12/writing-a-gui-using-qml-for-a-c-project/ 0682 * for interaction between QML and C++. Pitfalls: Example of color() property 0683 * stored internally at m_color: Much implementation code of the class will 0684 * access directly m_color instead of color(), so when using bindings, 0685 * this code is broken? 0686 * 0687 * @todo Provide QML support so that for 0688 * https://doc.qt.io/qt-5/qml-qtquick-dialogs-colordialog.html (or its 0689 * Qt6 counterpart) we provide a source compatible alternative, like for 0690 * QColorWidget? Split the library in three parts (Common, Widgets, QML)? 0691 * Support <a href="https://mauikit.org/">MauiKit</a>? 0692 * 0693 * @todo Apparently QWidget cannot be used from QML. (Though there is 0694 * https://www.kdab.com/declarative-widgets/ – how does that work?) Is it 0695 * therefore worth to have complete support for signals in all our QWidget 0696 * code if this is not really necessary for QWidget (for example for 0697 * properties that can only be changed by the library user and not by the 0698 * end user)? 0699 * 0700 * @todo Comply with <a href="https://community.kde.org/Policies">KDE 0701 * policies</a>. 0702 * 0703 * @todo Remove all qDebug calls from the source 0704 * 0705 * @todo Qt Designer support for the widgets. Quote from a blog from Viking 0706 * about Qt Designer plugins: 0707 * The problem is that you have to build it with exactly the same compiler 0708 * tool chain as designer was built with, and you have to do it in release 0709 * mode. Unless your Qt is built in debug, then your plugin needs to be 0710 * built in debug mode as well. So you can’t just always use the same 0711 * compiler as you build the application with, if you use the system Qt or 0712 * a downloaded Qt version. 0713 * 0714 * @todo Use <a href="https://lvc.github.io/abi-compliance-checker/"> 0715 * abi-compliance-checker</a> to control ABI compatibility. 0716 * 0717 * @todo Follow KDE’s <a href="https://hig.kde.org/index.html">HIG</a> 0718 * 0719 * @todo Test linking against lcms.h in version 2.0.0 for compatibility 0720 * (or require more recent version?) 0721 * 0722 * @todo Require (by static cast additional to CMake conditions) a minimum 0723 * Qt version? 0724 * 0725 * @todo Would it be a good idea to implement Q_PROPERTY RESET overall? See 0726 * also https://phabricator.kde.org/T12359 0727 * 0728 * @todo Better design on small widget sizes for the whole library. 0729 * 0730 * @todo Anti-aliasing the gamut diagrams? Wouldn't this be bad for 0731 * performance? 0732 * 0733 * @todo Use a cross-hair cursor on @ref PerceptualColor::ChromaHueDiagram 0734 * and @ref PerceptualColor::ChromaLightnessDiagram when the mouse is 0735 * hovering over the gamut, to show that this surface can be clicked? 0736 * 0737 * @todo Touch-friendly interface: Would it be good to have buttons for 0738 * plus and minus on the various LCH axis which would be companions 0739 * for @ref PerceptualColor::ChromaHueDiagram and 0740 * @ref PerceptualColor::ChromaLightnessDiagram and would allow 0741 * more exactly choose colors also on touch devices? 0742 * 0743 * @todo Would it be a good idea to have plus and minus buttons that 0744 * manipulate the current color along the depth and vividness axis 0745 * as proposed in “Extending CIELAB - Vividness, V, depth, D, and clarity, T” 0746 * by Roy S. Berns? 0747 * 0748 * @todo Spell checking for the documentation, if possible also grammar 0749 * checking with LanguageTool */ 0750 0751 /** @page hidpisupport High DPI support 0752 * 0753 * This library supports High DPI out of the box. 0754 * 0755 * The only thing that requires special attention are icons. 0756 * 0757 * @section iconsupport Icon support 0758 * 0759 * This library uses by default a possibly existing icon theme 0760 * if available in Qt. Windows and Mac do not provide icon themes by 0761 * default, while Linux usually provides them. SVG is pretty much the standard 0762 * nowadays and the only reliably way to have crisp icons also on desktop 0763 * scales like 1.25 or 1.5. If high-DPI icons are available depends finally 0764 * on your operation system. Only if no icon at all is provided by the 0765 * operation system, the library falls back to built-in high-DPI SVG icons. 0766 * 0767 * Note that QSvgIconEnginePlugin is a mandatory run-time 0768 * dependency (see @ref build for details). 0769 * 0770 * @section qt5icons Qt5 legacy 0771 * 0772 * While <a href="https://bugreports.qt.io/browse/QTBUG-89279">Qt6 0773 * renders icons always with high-DPI</a> (if available), 0774 * Qt5 renders icons by default in low resolution. This applies even 0775 * for SVG icons on high-DPI displays! Application developers have to enable 0776 * high-DPI icon rendering manually with the following code (which should be 0777 * put by convention <em>before</em> creating the <tt>QCoreApplication</tt> 0778 * object): 0779 * <br/><tt>QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);</tt> */ 0780 0781 /** @page howtogetstarted How to get started 0782 * 0783 * How to get started? @ref PerceptualColor::ColorDialog provides a 0784 * perceptual replacement for QColorDialog: 0785 * @snippet testcolordialog.cpp ColorDialog Get color 0786 * 0787 * This is a minimal, but complete example project showing how to use 0788 * this library: 0789 * 0790 * CMakeLists.txt: 0791 * @include examples/CMakeLists.txt 0792 * 0793 * example.cpp: 0794 * @include examples/example.cpp */ 0795 0796 /** @page i18nl10n Internationalization and localization 0797 * 0798 * @section Internationalization 0799 * 0800 * This library is internationalized (i18n). This include also support 0801 * for right-to-left layouts in the widgets. 0802 * 0803 * @section Localization 0804 * 0805 * This library is also localized (l10n). The localization is divided 0806 * into two separate areas, which behave differently and independently 0807 * of each other. 0808 * 0809 * 1. Translation. 0810 * 2. Everything else. 0811 * 0812 * @subsection localizationtranslation Translation 0813 * 0814 * The translation of user-visible strings is a global setting for the whole 0815 * library. The language for the translation is auto-detected depending on 0816 * the settings of the current computer. You can specify the translation 0817 * explicitly with @ref PerceptualColor::setTranslation(), which can also 0818 * be used to change the translation dynamically (during program execution). 0819 * The various translations are build directly into the library binary; 0820 * no external files need to be available or loaded. 0821 * 0822 * @subsection localizationeverythingelse Everything else 0823 * 0824 * All other localization settings (like which decimal separator to use or 0825 * which date format to use) are individual per widget, depending on the 0826 * <tt><a href="https://doc.qt.io/qt-6/qwidget.html#locale-prop"> 0827 * QWidget::locale()</a></tt> property. Changing the localization dynamically 0828 * (during program execution) is currently not supported. 0829 * 0830 * @internal 0831 * 0832 * @todo Support changing the localization dynamically (during program 0833 * execution). This affects also @ref PerceptualColor::MultiSpinBox and 0834 * the <tt>QSpinBox</tt> in @ref PerceptualColor::ColorDialog that is 0835 * used for the opacity and maybe also the RGB-Hex-LineEdit. 0836 * 0837 * @todo Provide more localizations! */ 0838 0839 /** @page licenseinfo License 0840 * 0841 * @copyright 0842 * - We follow the <a href="https://reuse.software/">“Reuse” 0843 * specification</a>. 0844 * - The files from which the library (and this documentation as well) 0845 * are generated do not all have the same license; instead, each file 0846 * is subject to one of the following permissive licenses: 0847 * - BSD-2-Clause OR MIT (for example, some C++ source code files) 0848 * - MIT (for example, some icons) 0849 * - BSD-3-Clause (for example, some CMake files) 0850 * - CC0-1.0 (for example, some color profiles) 0851 * - Other parts of the codebase (which will 0852 * <em>not</em> be installed by CMake, examples include <em>autotests</em> 0853 * and <em>utils</em>) might have different licenses and/or include 0854 * compiled-in resources that have different licenses. */ 0855 0856 /** @internal 0857 * 0858 * @page measurementdetails Measurement details 0859 * 0860 * When this library deals with raster graphics, it simultaneously uses 0861 * concepts concerning measurement. This page describes the terminology 0862 * used within the documentation of this library. 0863 * 0864 * @section introduction Introduction 0865 * Today’s displays have a wide range of physical pixel density (pixels 0866 * per length). Displays with a high physical pixel density are called 0867 * <b>High-DPI displays</b> or <b>HiDPI displays</b> or <b>Retina displays</b>. 0868 * 0869 * @section unitsofmeasurement Units of measurement 0870 * As Qt documentation says: 0871 * “<em>Qt uses a model where the application coordinate system is 0872 * independent of the display device resolution. The application 0873 * operates in </em>device-independent pixels<em>, which are then 0874 * mapped to the physical pixels of the display via a scale 0875 * factor, known as the </em>device pixel ratio<em>.</em>” 0876 * 0877 * So when rendering widgets, there are two different units of measurement 0878 * to consider: 0879 * - <b>Device-independent pixels</b> are the unit of measurement for 0880 * widgets, windows, screens, mouse events and so on in Qt. 0881 * - <b>Physical pixels</b> are the unit that measures actual physical 0882 * display pixels. 0883 * 0884 * The conversion factor between these two units of measurement is 0885 * <tt>QPaintDevice::devicePixelRatioF()</tt>, a floating point number. 0886 * It is usually <tt>1.00</tt> on classic low-resolution screens. It could be 0887 * for example <tt>1.25</tt> or <tt>2.00</tt> on displays with a higher 0888 * pixel density. 0889 * 0890 * @section coordinatepointsversuspixelpositions Coordinate points versus pixel positions 0891 * 0892 * - <b>Coordinate points</b> are points in the mathematical sense, that 0893 * means they have zero surface. Coordinate points should be stored as 0894 * <em>floating point numbers</em>. 0895 * - <b>Pixel positions</b> describe the position of a particular pixel 0896 * within the pixel grid. Pixels are surfaces, not points. A pixel is a 0897 * square of the width and length <tt>1</tt>. The pixel at position 0898 * <tt>QPoint(x, y)</tt> is the square with the top-left edge at coordinate 0899 * point <tt>QPoint(x, y)</tt> and the bottom-right edge at coordinate 0900 * point <tt>QPoint(x+1, y+1)</tt>. Pixel positions should be stored 0901 * as <em>integer numbers</em>. 0902 * 0903 * Some functions (like mouse events) work with pixel positions, other 0904 * functions (like antialiased floating-point drawing operations) work 0905 * with coordinate points. It’s important to always distinguish correctly 0906 * these two different concepts. See https://doc.qt.io/qt-6/coordsys.html 0907 * for more details about integer precision vs floating point precision 0908 * on drawing operations. */ 0909 0910 /** @page namespacepollution Namespace pollution 0911 * 0912 * This library avoids namespace pollution and collisions: 0913 * 0914 * - Macros are prefixed with <tt>PERCEPTUALCOLOR_</tt>. 0915 * - Symbols that have external linkage are within the 0916 * namespace <tt>PerceptualColor</tt>. (Exception: The 0917 * <a href="https://doc.qt.io/qt-5/resources.html"> 0918 * Qt resource system</a> generates functions prefixed 0919 * with <tt>qInitResources_</tt> and <tt>qCleanupResources_</tt> 0920 * that are not within the previously mentioned namespace.) 0921 * - Resources within the <a href="https://doc.qt.io/qt-5/resources.html">Qt 0922 * resource system</a> are within the folder <tt>:/PerceptualColor/</tt>. */ 0923 0924 /** @internal 0925 * 0926 * @page pimpl Pointer to implementation idiom 0927 * 0928 * This library uses the <em>pointer to implementation</em> idiom 0929 * (also known as pimpl idiom, d-pointer idiom or opaque-pointer idiom) 0930 * in almost all classes that are part of the public API, and also in 0931 * some classes that are part of the private API. The idiom is described 0932 * in detail in the Internet. The following flavour of the idiom is used 0933 * in our library: 0934 * 0935 * - The pointer to the implementation is called <tt>d_pointer</tt>. It’s of 0936 * type @ref PerceptualColor::ConstPropagatingUniquePointer which provides 0937 * const-correctness. 0938 * - The back pointer is called <tt>q_pointer</tt>. (A “q” is just a “d” 0939 * pointing in a different direction, get it?). It’s 0940 * of type @ref PerceptualColor::ConstPropagatingRawPointer which provides 0941 * const-correctness. 0942 * - <a href="https://euroquis.nl//kde/2022/01/31/dptr.html"> The 0943 * <tt>q_pointer</tt> <em>must not</em> ever be used in the destructor 0944 * of the private implementation.</a> Rationale: All functions of the 0945 * public class could potentially use the d_pointer. However, at the moment 0946 * the destructor of the private class has started, the use of the d_pointer 0947 * is already undefined behaviour. With some compilers this leads to an 0948 * immediate crash, with other compilers it leads to 0949 * silent undefined behaviour. 0950 * 0951 * The private classes are <em>not</em> nested 0952 * classes of their public counterpart. This is also 0953 * <a href="https://community.kde.org/Policies/Binary_Compatibility_Issues_With_C%2B%2B#Using_a_d-Pointer"> 0954 * what the the KDE community recommends</a>: 0955 * > It is also possible (but not recommended) to declare the private 0956 * > class […] as a nested private class (e.g. Foo::Private). […] remember 0957 * > that the nested private class will inherit the public symbol visibility 0958 * > of the containing exported class. This will cause the functions 0959 * > of the private class to be named in the dynamic library's symbol 0960 * > table. […] Other downsides […] include […] the fact that it can't be 0961 * > forward-declared in unrelated headers anymore (which can be useful to 0962 * > declare it as a friend class). 0963 * 0964 * @note This idiom is also used by Qt itself, and Qt even provides some macros 0965 * and extension points (<tt>Q_DECLARE_PRIVATE</tt>, <tt>Q_D</tt>, a protected 0966 * member called <tt>d_ptr</tt> in almost all classes…), that help dealing 0967 * with the pimpl idiom. Though available, these Qt features are not 0968 * officially documented; and they would also interfere with private 0969 * implementations of Qt itself without documented behaviour, which seems 0970 * inappropriate. Furthermore, the Qt pimpl idiom is complicate because 0971 * it uses (for performance reasons) inheritance between the private 0972 * implementation classes. This breaks, however, the encapsulation, because 0973 * all formerly private elements of a class become protected now. Our class 0974 * hierarchy is not that deep, so the performance gain might not be worth 0975 * the additional code complexity. Therefore, this library uses a more simple 0976 * pimpl idiom without inheritance of the private implementation. It has 0977 * however all the other features of the Qt pimpl idiom, including 0978 * <tt>const</tt> propagating access to the private implementation 0979 * thanks to @ref PerceptualColor::ConstPropagatingUniquePointer and 0980 * @ref PerceptualColor::ConstPropagatingRawPointer. And, at difference 0981 * to Qt’s pimpl idiom, it keeps private code strictly private. 0982 * Note however, that switching later from our current pimpl idiom to 0983 * the polymorphic Qt pimpl idiom would break the binary 0984 * compatibility. See also the document <em> 0985 * <a href="https://accu.org/journals/overload/18/100/love_1718/">Interface 0986 * Versioning in C++</a></em> and KDE’s information document <em> 0987 * <a 0988 * href="https://community.kde.org/Policies/Binary_Compatibility_Issues_With_C%2B%2B"> 0989 * Binary Compatibility Issues With C++</a></em> and for details. 0990 * 0991 * @note It would be nice to have the d_pointer and q_pointer 0992 * be themselves be declared <tt>const</tt>, because this would 0993 * clearly communicate that those pointers are not expected to change 0994 * the address they point to. Unfortunately, apparently this does not 0995 * work with neither @ref PerceptualColor::ConstPropagatingUniquePointer nor 0996 * @ref PerceptualColor::ConstPropagatingRawPointer as it would change also 0997 * all the access rights to the pointed object to always <tt>const</tt>. */ 0998 0999 /** @page qtstylesheetssupport Qt Style Sheets support 1000 * 1001 * The widget of this library supports the Qt Style Sheet 1002 * <a href="https://doc.qt.io/qt-6/stylesheet-reference.html#list-of-stylable-widgets"> 1003 * properties of the Qt class they are derived from</a> only where it 1004 * makes sense. So you set the <tt>background-color</tt> of 1005 * a @ref PerceptualColor::MultiSpinBox. But you should not set 1006 * it for a @ref PerceptualColor::GradientSlider because the point 1007 * of this widget is to always use the gradient as the background; 1008 * the same applies for most widgets that showcase colors. 1009 * 1010 * When using class names of this library as 1011 * selectors in Qt Style Sheets, you have to 1012 * <a href="https://doc.qt.io/Qt-6/stylesheet-syntax.html#widgets-inside-c-namespaces"> 1013 * substitute the namespace separator <tt>::</tt> by <tt>\--</tt></a> 1014 * to get a working selector: To select the class 1015 * @ref PerceptualColor::ColorDialog, use the selector 1016 * <tt>PerceptualColor\--ColorDialog</tt>. */ 1017 1018 /** @page lchrange Range of LCH values 1019 * 1020 * 1021 * The LCH values in this library are implemented with the following range: 1022 * 1023 * | | l | a | b | c | h | 1024 * | :------------ | :------: | :------: | :------: |:-------: | :------: | 1025 * | CIELab/CIELCh | [0, 100] | [0, 255] | [0, 255] | [0, 255] | [0, 360[ | 1026 * | Oklab/Oklch | [0, 1] | [0, 2] | [0, 2] | [0, 2] | [0, 360[ | 1027 * 1028 * This range is enough to cover the hole range of human perception. (Note 1029 * that the actual range of human perception has an irregular shape and 1030 * covers only parts of all possible combinations of LCH values. And 1031 * the actual gamut of real-word output devices is smaller than the 1032 * human perception.) 1033 * 1034 * @internal 1035 * 1036 * @section lchrangerationale Rationale 1037 * 1038 * The gamut of actual human perception within the LAB color model (and 1039 * its alternative representation LCH) has an irregular shape. Its maximum 1040 * extensions: 1041 * 1042 * <b>Lightness (L)</b> 1043 * The maximum range for LAB/LCH lightness is limited by 1044 * definition: <tt>[0, 100]</tt> for CIELch and <tt>[0, 1]</tt> for Oklch. 1045 * 1046 * <b>Hue (H)</b> 1047 * The maximum range for LCH hue is limited by definition to 1048 * the full circle: <tt>[0°, 360°[</tt>. 1049 * 1050 * <b>a, b, Chroma (C)</b> 1051 * The maximum range for a, b and Chroma (C) is complex. It is <em>not</em> 1052 * limited by definition. A useful limit is the actual human perception. 1053 * 1054 * | CIELab/CIELCh | a | b | C | 1055 * | :---------------------------- |:----------------: | :---------------: | :---------: | 1056 * | Usual implementation¹ | [−128, 127] | [−128, 127] | | 1057 * | Human perception (Wikipedia)² | [−170, 100] | [−100, 150] | | 1058 * | Human perception (2° D50)³ | [−165.39, 129.05] | [−132.62, 146.69] | [0, 183.42] | 1059 * | Human perception (2° D65)³ | [−170.84, 147.84] | [−129.66, 146.78] | [0, 194.84] | 1060 * | Human perception (10° D65)³ | [−164.29, 115.14] | [−116.10, 145.53] | [0, 186.17] | 1061 * 1062 * 1. The range of <tt>[−128, 127]</tt> is in C++ a signed 8‑bit integer. But 1063 * this data type usually used in software implementations is (as the table 1064 * clearly shows) not enough to cover the hole range of actual human 1065 * color perception. 1066 * 2. Ranges of CIELAB coordinates according to the 1067 * <a href="https://de.wikipedia.org/w/index.php?title=Lab-Farbraum&oldid=197156292"> 1068 * German Wikipedia</a>. 1069 * 3. The German association <em>Freie Farbe e. V.</em> has 1070 * published a calculation of the 1071 * <a href="https://www.freiefarbe.de/artikel/grenzen-des-cielab-farbraums/"> 1072 * shape of actual human perception</a> for various observation angles 1073 * and illuminants. This data contains only the CIELAB coordinates 1074 * (L, a, b). From this data, the chroma (C) component can be calculated 1075 * easily as Pythagoras of the a axis and b axis value pairs: 1076 * √(a² + b²) = C. 1077 * 1078 * Logically, the chroma value can reach higher values than a and b, however, 1079 * for simplicity it seems appropriate to use the same range for chroma, a and 1080 * b. Following these tables, the maximum chroma in human perception in CIELCh 1081 * is <tt>194.84</tt>. As apparently this depends on viewing conditions, 1082 * it might be a good idea to use a slightly higher limit, to be sure that the 1083 * value will never be too small. Here, <tt>200</tt> might be a good candidate. 1084 * However, some gamuts are wider. The <em>LargeRGB-elle-V2-g22.icc</em> 1085 * profile goes up to a chroma value of 245. Finally, we have fixed the valid 1086 * range to 255, because this is for sure enough to cover the human 1087 * perception, and it will cover almost all existing profiles. 1088 * 1089 * For Oklch we have observed up to 1.52 as chroma values when using the 1090 * <em>LargeRGB-elle-V2-g22.icc</em> profile. As with CIELCh chroma, we have 1091 * added a safety margin, rounded up to the next integer, and finally 1092 * chosen 2 as maximum. 1093 * 1094 * @internal 1095 * 1096 * @sa @ref PerceptualColor::CielchD50Values::maximumChroma 1097 * @sa @ref PerceptualColor::OklchValues::maximumChroma 1098 * 1099 * @todo Why is the exact extend of non-imaginary colors unknown? Could it be 1100 * deduced from the <a href="https://en.m.wikipedia.org/wiki/CIE_1931_color_space#CIE_xy_chromaticity_diagram_and_the_CIE_xyY_color_space"> 1101 * CIE xy chromacity diagram</a>? And: Is 255 enough even for large color 1102 * spaces like <a href="https://en.m.wikipedia.org/wiki/Rec._2020"> 1103 * Rec. 2020</a> or <a href="https://en.m.wikipedia.org/wiki/DCI-P3"> 1104 * DCI-P3</a>? 1105 */ 1106 1107 /** @page versioninfo Version information at compiletime and runtime 1108 * 1109 * This library uses 1110 * <a href="https://semver.org/">Semantic Versioning 2.0.0</a>. 1111 * 1112 * Version information is provided by the header <tt>version.h</tt> 1113 * 1114 * To know against which version of this library you are <em>running</em>, use 1115 * - @ref PerceptualColor::perceptualColorRunTimeVersion 1116 * 1117 * To know against which version of this library you are <em>compiling</em>, 1118 * use 1119 * - @ref PERCEPTUALCOLOR_COMPILE_TIME_VERSION 1120 * - @ref PERCEPTUALCOLOR_COMPILE_TIME_VERSION_MAJOR 1121 * - @ref PERCEPTUALCOLOR_COMPILE_TIME_VERSION_MINOR 1122 * - @ref PERCEPTUALCOLOR_COMPILE_TIME_VERSION_PATCH */ 1123 1124 /** @brief The namespace of this library. 1125 * 1126 * All symbols that are provided in this library are encapsulated within this 1127 * namespace. */ 1128 namespace PerceptualColor 1129 { 1130 } // namespace PerceptualColor