├── doc_image
├── wasm_on_chrome.png
├── android_portrait_basic.png
├── linux_landscape_basic_normal.png
├── android_landscape_basic_test1.png
├── android_landscape_basic_test2.png
├── ios_iphone14pro_portrait_basic.png
├── win10_FHD_landscape_basic_normal.png
├── win10_FHD_landscape_fusion_normal.png
├── win10_FHD_portrait_imagine_test2.png
├── win10_FHD_portrait_material_test2.png
├── win10_FHD_landscape_basic_normal_test2.png
├── ios_iphone14pro_landscape_basic_small_dpm.png
├── win10_FHD_landscape_basic_norma_palette.png
├── win10_FHD_landscape_universal_normal_test2.png
└── ios_iphone14pro_landscape_basic_smalldpm_pallete.png
├── test
├── qml.qrc
├── main.cpp
├── qtquickcontrols2.conf
├── test.pro
├── CMakeLists.txt
└── main.qml
├── CMakeLists.txt
├── colorpicker
├── content
│ ├── Checkerboard.qml
│ ├── PanelBorder.qml
│ ├── SinglePalette.qml
│ ├── ColorSlider.qml
│ ├── NumberBox.qml
│ ├── SBPicker.qml
│ ├── SizeConfigrator.qml
│ └── Paletts.qml
├── Colorpicker.qrc
└── Colorpicker.qml
├── LICENSE
└── README.md
/doc_image/wasm_on_chrome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rshest/qml-colorpicker/HEAD/doc_image/wasm_on_chrome.png
--------------------------------------------------------------------------------
/doc_image/android_portrait_basic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rshest/qml-colorpicker/HEAD/doc_image/android_portrait_basic.png
--------------------------------------------------------------------------------
/doc_image/linux_landscape_basic_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rshest/qml-colorpicker/HEAD/doc_image/linux_landscape_basic_normal.png
--------------------------------------------------------------------------------
/doc_image/android_landscape_basic_test1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rshest/qml-colorpicker/HEAD/doc_image/android_landscape_basic_test1.png
--------------------------------------------------------------------------------
/doc_image/android_landscape_basic_test2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rshest/qml-colorpicker/HEAD/doc_image/android_landscape_basic_test2.png
--------------------------------------------------------------------------------
/doc_image/ios_iphone14pro_portrait_basic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rshest/qml-colorpicker/HEAD/doc_image/ios_iphone14pro_portrait_basic.png
--------------------------------------------------------------------------------
/doc_image/win10_FHD_landscape_basic_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rshest/qml-colorpicker/HEAD/doc_image/win10_FHD_landscape_basic_normal.png
--------------------------------------------------------------------------------
/doc_image/win10_FHD_landscape_fusion_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rshest/qml-colorpicker/HEAD/doc_image/win10_FHD_landscape_fusion_normal.png
--------------------------------------------------------------------------------
/doc_image/win10_FHD_portrait_imagine_test2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rshest/qml-colorpicker/HEAD/doc_image/win10_FHD_portrait_imagine_test2.png
--------------------------------------------------------------------------------
/doc_image/win10_FHD_portrait_material_test2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rshest/qml-colorpicker/HEAD/doc_image/win10_FHD_portrait_material_test2.png
--------------------------------------------------------------------------------
/doc_image/win10_FHD_landscape_basic_normal_test2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rshest/qml-colorpicker/HEAD/doc_image/win10_FHD_landscape_basic_normal_test2.png
--------------------------------------------------------------------------------
/doc_image/ios_iphone14pro_landscape_basic_small_dpm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rshest/qml-colorpicker/HEAD/doc_image/ios_iphone14pro_landscape_basic_small_dpm.png
--------------------------------------------------------------------------------
/doc_image/win10_FHD_landscape_basic_norma_palette.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rshest/qml-colorpicker/HEAD/doc_image/win10_FHD_landscape_basic_norma_palette.png
--------------------------------------------------------------------------------
/doc_image/win10_FHD_landscape_universal_normal_test2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rshest/qml-colorpicker/HEAD/doc_image/win10_FHD_landscape_universal_normal_test2.png
--------------------------------------------------------------------------------
/test/qml.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | main.qml
4 | qtquickcontrols2.conf
5 |
6 |
7 |
--------------------------------------------------------------------------------
/doc_image/ios_iphone14pro_landscape_basic_smalldpm_pallete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rshest/qml-colorpicker/HEAD/doc_image/ios_iphone14pro_landscape_basic_smalldpm_pallete.png
--------------------------------------------------------------------------------
/test/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | int main(int argc, char *argv[])
5 | {
6 | QGuiApplication app(argc, argv);
7 |
8 | QQmlApplicationEngine engine;
9 | engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
10 | if (engine.rootObjects().isEmpty())
11 | return -1;
12 |
13 | return app.exec();
14 | }
15 |
--------------------------------------------------------------------------------
/test/qtquickcontrols2.conf:
--------------------------------------------------------------------------------
1 | [Controls]
2 | Style=Basic
3 | # You can also override environment value or command line
4 | #Style=Universal
5 | #Style=Material
6 | #Style=Fusion
7 | #Style=Imagine
8 |
9 | [Basic]
10 | Theme=Light
11 |
12 | [Universal]
13 | Theme=Dark
14 |
15 | [Material]
16 | Theme=Light
17 | Accent=Olive
18 |
19 | [Fusion]
20 | Theme=Dark
21 |
22 | [Imagine]
23 | Theme=Light
24 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.16)
2 | project(qml-colorpicker)
3 |
4 | #
5 | # Set CMake Options
6 | #
7 | OPTION(BUILD_WITH_CPP_TEST "Build with C++ test" ON)
8 |
9 | if(WIN32 OR APPLE)
10 | set(CMAKE_CONFIGURATION_TYPES "Debug;Release;RelWithDebInfo")
11 | endif(WIN32 OR APPLE)
12 |
13 | #
14 | # Definitions
15 | #
16 |
17 | #
18 | # Sub Directories
19 | #
20 | if(${BUILD_WITH_CPP_TEST})
21 | add_subdirectory(test)
22 | endif(${BUILD_WITH_CPP_TEST})
23 |
--------------------------------------------------------------------------------
/colorpicker/content/Checkerboard.qml:
--------------------------------------------------------------------------------
1 | // Checkerboard-filled rectangle
2 | import QtQuick
3 | Grid {
4 | id: root
5 | property int cellSide: 5
6 | anchors.fill: parent
7 | rows: height/cellSide; columns: width/cellSide
8 | clip: true
9 | Repeater {
10 | model: root.columns*root.rows
11 | Rectangle {
12 | width: root.cellSide; height: root.cellSide
13 | color: (index%2 == 0) ? "gray" : "white"
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/colorpicker/Colorpicker.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | content/Checkerboard.qml
4 | content/ColorSlider.qml
5 | content/NumberBox.qml
6 | content/PanelBorder.qml
7 | content/SBPicker.qml
8 | Colorpicker.qml
9 | content/SinglePalette.qml
10 | content/Paletts.qml
11 | content/SizeConfigrator.qml
12 |
13 |
14 |
--------------------------------------------------------------------------------
/colorpicker/content/PanelBorder.qml:
--------------------------------------------------------------------------------
1 | // Fancy pseudo-3d control border
2 | import QtQuick
3 |
4 | Rectangle {
5 | width : 40; height : 15; radius: 2
6 | border.width: 1; border.color: _activePalette.light
7 | color: "transparent"
8 | anchors.leftMargin: 1; anchors.topMargin: 3
9 | clip: true
10 | Rectangle {
11 | anchors.fill: parent; radius: 2
12 | anchors.leftMargin: -1; anchors.topMargin: -1
13 | anchors.rightMargin: 0; anchors.bottomMargin: 0
14 | border.width: 1; border.color: _activePalette.mid
15 | color: "transparent"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/colorpicker/content/SinglePalette.qml:
--------------------------------------------------------------------------------
1 | import QtQuick
2 | import QtQuick.Controls
3 |
4 | RadioButton {
5 | id: control
6 | text: ""
7 | transformOrigin: Item.Center
8 | property color target_color : "#21be2b"
9 | property color border_color : palette.light
10 | property color selected_border_color : palette.dark
11 | padding: 0
12 |
13 | indicator: Rectangle {
14 | anchors.fill: control
15 | radius: 6
16 | color: checked ? selected_border_color : border_color
17 | Rectangle {
18 | anchors.fill: parent
19 | radius: parent.radius
20 | scale: 0.7
21 | color: target_color
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Ruslan Shestopalyuk
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/test/test.pro:
--------------------------------------------------------------------------------
1 | CONFIG += c++17
2 |
3 | QT += qml quick quickcontrols2
4 |
5 | target.path = $$PWD
6 | INSTALLS += target
7 |
8 | INCLUDEPATH += $$PWD $$PWD/../colorpicker
9 |
10 | # The following define makes your compiler emit warnings if you use
11 | # any feature of Qt which as been marked deprecated (the exact warnings
12 | # depend on your compiler). Please consult the documentation of the
13 | # deprecated API in order to know how to port your code away from it.
14 | DEFINES += QT_DEPRECATED_WARNINGS
15 |
16 | # You can also make your code fail to compile if you use deprecated APIs.
17 | # In order to do so, uncomment the following line.
18 | # You can also select to disable deprecated APIs only up to a certain version of Qt.
19 | DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
20 |
21 | SOURCES += \
22 | main.cpp
23 |
24 | RESOURCES += qml.qrc ../colorpicker/colorpicker.qrc
25 |
26 | # Additional import path used to resolve QML modules in Qt Creator's code model
27 | QML_IMPORT_PATH +=
28 |
29 | # Additional import path used to resolve QML modules just for Qt Quick Designer
30 | QML_DESIGNER_IMPORT_PATH +=
31 |
--------------------------------------------------------------------------------
/colorpicker/content/ColorSlider.qml:
--------------------------------------------------------------------------------
1 | // Vertical "slider" control used in colorpicker
2 | import QtQuick
3 | Item {
4 | property int cursorHeight: 7
5 | property real value: (1 - pickerCursor.y/height)
6 | width: 15; height: 300
7 | Item {
8 | id: pickerCursor
9 | width: parent.width
10 | Rectangle {
11 | x: -3; y: -height*0.5
12 | width: parent.width + 4; height: cursorHeight
13 | border.color: _activePalette.highlight; border.width: 1
14 | color: "transparent"
15 | Rectangle {
16 | anchors.fill: parent; anchors.margins: 2
17 | border.color: _activePalette.highlightedText; border.width: 1
18 | color: "transparent"
19 | }
20 | }
21 | }
22 | MouseArea {
23 | y: -Math.round(cursorHeight/2)
24 | height: parent.height+cursorHeight
25 | anchors.left: parent.left
26 | anchors.right: parent.right
27 | function handleMouse(mouse) {
28 | if (mouse.buttons & Qt.LeftButton) {
29 | pickerCursor.y = Math.max(0, Math.min(height, mouse.y)-cursorHeight)
30 | }
31 | }
32 | onPositionChanged: {
33 | handleMouse(mouse)
34 | }
35 | onPressed: handleMouse(mouse)
36 | }
37 |
38 | onVisibleChanged: {
39 | if(visible) {
40 | pickerCursor.y = 0
41 | }
42 | }
43 |
44 | function setValue(val) {
45 | pickerCursor.y = height * (1 - val)
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/colorpicker/content/NumberBox.qml:
--------------------------------------------------------------------------------
1 | // Edit box (with caption), editing a number value
2 | import QtQuick
3 | import QtQuick.Controls
4 |
5 | Row {
6 | property alias caption: captionBox.text
7 | property alias value: inputBox.text
8 | property alias min: numValidator.bottom
9 | property alias max: numValidator.top
10 | property alias decimals: numValidator.decimals
11 | property real fontPx: 11
12 | property real captionWidth: 15
13 |
14 | width: 80
15 | height: 15
16 | spacing: 4
17 | PanelBorder {
18 | id: captionBoarder
19 | height: parent.height
20 | width: captionWidth
21 | color: "transparent"
22 | TextInput {
23 | id: captionBox
24 | anchors.fill: parent
25 | font.pixelSize: fontPx; font.bold: true
26 | maximumLength: 3
27 | focus: false
28 | readOnly: true
29 | selectByMouse: true
30 | horizontalAlignment: TextInput.AlignLeft
31 | color: _activePalette.dark
32 | }
33 | }
34 | PanelBorder {
35 | id: textBorder
36 | height: parent.height
37 | width: parent.width - captionWidth - parent.spacing
38 | color: "transparent"
39 | TextInput {
40 | id: inputBox
41 | anchors.fill: parent
42 | font.pixelSize: fontPx
43 | maximumLength: 10
44 | focus: false
45 | readOnly: true
46 | selectByMouse: true
47 | validator: DoubleValidator {
48 | id: numValidator
49 | bottom: 0; top: 1; decimals: 2
50 | notation: DoubleValidator.StandardNotation
51 | }
52 | horizontalAlignment: TextInput.AlignHCenter
53 | color: _activePalette.dark
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/colorpicker/content/SBPicker.qml:
--------------------------------------------------------------------------------
1 | // Saturation/brightness picking box
2 | import QtQuick
3 |
4 | Item {
5 | id: root
6 | property color hueColor : "blue"
7 | property real saturation : pickerCursor.x/(width-2*r)
8 | property real brightness : 1 - pickerCursor.y/(height-2*r)
9 | property int r : colorHandleRadius
10 |
11 | Rectangle {
12 | x : r
13 | y : r + parent.height - 2 * r
14 | rotation: -90
15 | transformOrigin: Item.TopLeft
16 | width: parent.height - 2 * r
17 | height: parent.width - 2 * r
18 | gradient: Gradient {
19 | GradientStop { position: 0.0; color: "#FFFFFF" }
20 | GradientStop { position: 1.0; color: root.hueColor }
21 | }
22 | }
23 | Rectangle {
24 | x: r
25 | y: r
26 | width: parent.width - 2 * r
27 | height: parent.height - 2 * r
28 | gradient: Gradient {
29 | GradientStop { position: 1.0; color: "#FF000000" }
30 | GradientStop { position: 0.0; color: "#00000000" }
31 | }
32 | }
33 | Item {
34 | id: pickerCursor
35 | Rectangle {
36 | width: r*2; height: r*2
37 | radius: r
38 | border.color: _activePalette.highlight; border.width: 2
39 | color: "transparent"
40 | Rectangle {
41 | anchors.fill: parent; anchors.margins: 2;
42 | border.color: _activePalette.highlightedText; border.width: 2
43 | radius: width/2
44 | color: "transparent"
45 | }
46 | }
47 | }
48 | MouseArea {
49 | anchors.fill: parent
50 | x: r
51 | y: r
52 | function handleMouse(mouse: MouseEvent) {
53 | if (mouse.buttons & Qt.LeftButton) {
54 | pickerCursor.x = Math.max(0, Math.min(width, mouse.x) - 2 * r);
55 | pickerCursor.y = Math.max(0, Math.min(height, mouse.y) - 2 * r);
56 | mouse.accepted = true
57 | }
58 | }
59 | onPositionChanged: (mouse) => {
60 | handleMouse(mouse)
61 | }
62 | onPressed: (mouse) => {
63 | handleMouse(mouse)
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Colorpicker
2 | A basic colorpicker control made in Qt Quick/QML, as described in [the corresponding blog post](http://blog.ruslans.com/2010/12/cute-quick-colorpicker.html).
3 |
4 | # Prerequisite
5 | - Qt6(Qml, Quick and QuickControls2)
6 | - It's also needed c++ compiler env, Qt6 Core and Qt6 Gui to run test.
7 | - Note : If you want to use this on Qt5, refer to the other branch.
8 |
9 | # How to test
10 | see test directory and below gallery.
11 |
12 | # New features
13 | - Layout calculation using DPM(Pixel/Dot Per Millimeter) of primary screen.
14 | - Fontsize calculation using Qt Window info(optional).
15 | - Mostly follow [QML themes and styles](https://doc.qt.io/qt-6/qtquickcontrols2-styles.html).
16 | - Support changing almost every layout parameters at runtime.
17 |
18 | # Gallery
19 | ## Qt 6.4.3, WebAssembly (Chrome browser on Window10)
20 | ### Basic Style, dynamic layout change demo(set 'colorPicker.colorHandleRadius' to 22) and fake low DotPerMilimeter.
21 | 
22 |
23 | ## Qt 6.4.3, windows (windows10)
24 | ### Basic Style
25 | 
26 |
27 | ### Basic Style and fake low DotPerMilimeter
28 | 
29 |
30 | ### Basic Style and Palette mode
31 | 
32 |
33 | ### Universal Style and fake low DotPerMilimeter
34 | 
35 |
36 | ### Imagine Style, portrait and fake low DotPerMilimeter
37 | 
38 |
39 | ### Material Style and fake low DotPerMilimeter
40 | 
41 |
42 | ## Qt 6.4.3, android (Pixel 6 Pro API 33 on Simulator)
43 | ### Basic Style
44 | 
45 |
46 | ### Basic Style, palette mode and fake low DotPerMilimeter
47 | 
48 |
49 | ### Basic Style, palette mode and fake low DotPerMilimeter(alternative font size calculation)
50 | 
51 |
52 | ## Qt 6.4.3, linux (ubuntu 22.04.2 LTS on Hyper-V)
53 | ### Basic Style
54 | 
55 |
56 | ## Qt6.4.3, iPhone 14 pro (iOS16.2 on Simulator)
57 | ### Basic Style and fake low DotPerMilimeter
58 | 
59 |
60 | ### Basic Style and portrait
61 | 
62 |
63 | ### Basic Style, palette mode and fake low DotPerMilimeter
64 | 
65 |
66 |
--------------------------------------------------------------------------------
/test/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.16)
2 |
3 | project(test LANGUAGES CXX)
4 | set(CMAKE_CXX_STANDARD 17) # Qt6 requirement. If you want the latest, set "20"
5 | set(CMAKE_CXX_STANDARD_REQUIRED ON)
6 | set(CMAKE_CXX_EXTENSIONS ON)
7 |
8 | # specify build paths
9 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
10 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
11 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
12 |
13 | # definitions
14 | if (MSVC)
15 | set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fp:precise /EHa /MP")
16 | string (REGEX REPLACE "/EHsc" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
17 | add_definitions (-D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE -DUNICODE -D_UNICODE -D_USE_MATH_DEFINES)
18 | else()
19 | set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions -fPIC")
20 | endif()
21 |
22 | # Find dependencies
23 | find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick QuickControls2)
24 | set(CMAKE_AUTOMOC ON)
25 | set(CMAKE_AUTORCC ON)
26 |
27 | FILE(GLOB_RECURSE SOURCE_FILES LIST_DIRECTORIES false CONFIGURE_DEPENDS
28 | "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
29 | FILE(GLOB_RECURSE HEADER_FILES LIST_DIRECTORIES false CONFIGURE_DEPEND
30 | "${CMAKE_CURRENT_SOURCE_DIR}/*.h")
31 | #FILE(GLOB_RECURSE QML_FILES LIST_DIRECTORIES false CONFIGURE_DEPENDS
32 | # "${CMAKE_CURRENT_SOURCE_DIR}/*.qml")
33 | set (RESOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/qml.qrc ${CMAKE_CURRENT_SOURCE_DIR}/../colorpicker/Colorpicker.qrc)
34 | qt6_add_resources(RCC_SOURCES ${RESOURCE_FILES})
35 |
36 | if(WIN32)
37 | # qt6_add_executable(${PROJECT_NAME} ${SOURCE_FILES} ${HEADER_FILES}
38 | # ${QML_FILES} ${RESOURCE_FILE})
39 | qt6_add_executable(${PROJECT_NAME} ${SOURCE_FILES} ${HEADER_FILES}
40 | ${RCC_SOURCES})
41 |
42 | set_target_properties(${PROJECT_NAME} PROPERTIES
43 | WIN32_EXECUTABLE TRUE
44 | MACOSX_BUNDLE TRUE
45 |
46 | # Prevent name clash with build subdirectory on case-insensitive file systems
47 | OUTPUT_NAME ${PROJECT_NAME}
48 | )
49 | set_property(TARGET ${PROJECT_NAME} PROPERTY QT6_NO_LINK_QTMAIN ON)
50 | elseif(ANDROID)
51 | qt_add_library(${PROJECT_NAME} ${SOURCE_FILES} ${HEADER_FILES} SHARED)
52 | set_property(TARGET ${PROJECT_NAME} PROPERTY QT6_NO_LINK_QTMAIN ON)
53 | endif(WIN32)
54 |
55 | include_directories(
56 | ${CMAKE_CURRENT_SOURCE_DIR}
57 | )
58 |
59 | target_link_libraries(${PROJECT_NAME} PRIVATE
60 | Qt6::Core
61 | Qt6::Gui
62 | Qt6::Qml
63 | Qt6::Quick
64 | Qt6::QuickControls2
65 | # Qt6::QmlPrivate
66 | # Qt6::QuickPrivate
67 | )
68 |
69 | # auxiliary development environment
70 | if (MSVC)
71 | set (X_COMPILER_BITNESS x64)
72 | # get_target_property (QtCore_location Qt6::Core LOCATION)
73 | # get_filename_component (QT_BINARY_DIR ${QtCore_location} DIRECTORY)
74 | # set (QT_PLUGINS_DIR)
75 | # if(EXISTS "${QT_BINARY_DIR}/../plugins")
76 | # set (QT_PLUGINS_DIR "${QT_BINARY_DIR}/../plugins")
77 | # endif()
78 | #configure_file("${CMAKE_SOURCE_DIR}/adm/cmake/sample.vcxproj.user.in" "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/${PROJECT_NAME}.vcxproj.user" @ONLY)
79 | endif()
80 |
81 | add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
82 | COMMAND Qt6::windeployqt
83 | ARGS $
84 | )
85 |
--------------------------------------------------------------------------------
/colorpicker/content/SizeConfigrator.qml:
--------------------------------------------------------------------------------
1 | import QtQuick
2 |
3 | Item {
4 | visible: false
5 |
6 | property real ratio:1.0
7 | property real ratioFont:1.0
8 | property real currentDpm: 0.0
9 | property real currentFontPixelSize: 0.0
10 | property bool fontCalculationWithDPM: false
11 |
12 | QtObject {
13 | //
14 | // This item holds private variables
15 | //
16 | id: internal
17 |
18 | property real refDpm: 3.645956202882199
19 | property real refFontPixelSize: 14
20 |
21 | property string defaultSizes: '' +
22 | '{' +
23 | ' "colorPicker" : {' +
24 | // ' "width": 382,' +
25 | // ' "height": 194,' +
26 | ' "colorHandleRadius": 8' +
27 | ' },' +
28 | ' "paletteSwitch" : {' +
29 | ' "height": 16,' +
30 | ' "font" : {' +
31 | ' "pixelSize": 14' +
32 | ' }' +
33 | ' },' +
34 | ' "picker" : {' +
35 | ' "spacing": 8' +
36 | ' },' +
37 | ' "sbPicker" : {' +
38 | ' "width": 200' +
39 | ' },' +
40 | ' "huePicker" : {' +
41 | ' "width": 15' +
42 | ' },' +
43 | ' "alphaPicker" : {' +
44 | ' "width": 15' +
45 | ' },' +
46 | ' "detailColumn" : {' +
47 | ' "width": 73,' +
48 | ' "spacing": 3' +
49 | ' },' +
50 | ' "panelBorder" : {' +
51 | ' "height": 30' +
52 | ' },' +
53 | ' "colorEditBox" : {' +
54 | ' "height" : 15' +
55 | ' },' +
56 | ' "colorText" : {' +
57 | ' "font" : {' +
58 | ' "pixelSize": 11' +
59 | ' }' +
60 | ' },' +
61 | ' "NumberBox" : {' +
62 | ' "width" : 70,' +
63 | ' "height" : 15,' +
64 | ' "font" : {' +
65 | ' "pixelSize": 11' +
66 | ' },' +
67 | ' "captionBoarder" : {' +
68 | ' "width": 15' +
69 | ' }' +
70 | ' }' +
71 | '}'
72 |
73 | function load_default() {
74 | if(_debugLayout) {
75 | console.debug('load_default() is reading:'+defaultSizes)
76 | }
77 | sizes_json = JSON.parse(defaultSizes);
78 | }
79 |
80 | property var sizes_json: null
81 | }
82 |
83 | // utility method
84 | function _getValue(tag) {
85 | var str_list = tag.split('.')
86 | var tmp_json = internal.sizes_json
87 | for (var i = 0; i < str_list.length; i++) {
88 | if(i == str_list.length - 1) {
89 | return tmp_json[str_list[i]]
90 | } else {
91 | tmp_json = tmp_json[str_list[i]]
92 | }
93 | }
94 | console.log('error. unexpected tag:'+tag)
95 | return 0
96 | }
97 |
98 | function getSizeValue(tag) {
99 | if(_debugLayout) {
100 | console.debug('getSizeValue() is called. tag:'+tag)
101 | }
102 | var v = _getValue(tag)
103 | var vc = v * ratio
104 |
105 | if(_debugLayout) {
106 | console.debug('getSizeValue() returns : '+v+' * '+ratio+' = '+vc)
107 | }
108 | return vc
109 | }
110 |
111 | function getFontValue(tag) {
112 | if(_debugLayout) {
113 | console.debug('getFontValue() is called. tag:'+tag)
114 | }
115 | var v = _getValue(tag)
116 | var vc = v * ratioFont
117 | if(_debugLayout) {
118 | console.debug('getFontValue() returns : '+v+' * '+ratioFont+' = '+vc)
119 | }
120 | return vc
121 | }
122 |
123 | // utility method
124 | function setSizeValue(tag, value) {
125 | if(_debugLayout) {
126 | console.debug('setValue() is called. tag:'+tag)
127 | }
128 | var str_list = tag.split('.')
129 | var tmp_json = internal.sizes_json
130 | for (var i = 0; i < str_list.length; i++) {
131 | if(i == str_list.length - 1) {
132 | if(_debugLayout) {
133 | console.debug('setValue() overrides from '+tmp_json[str_list[i]]+' to '+ value)
134 | }
135 | tmp_json[str_list[i]] = value
136 | return
137 | } else {
138 | tmp_json = tmp_json[str_list[i]]
139 | }
140 | }
141 | console.log('error. unexpected tag:'+tag)
142 | return 0
143 | }
144 |
145 | function setDpm(_d) {
146 | currentDpm = _d
147 | _calculate()
148 | }
149 | function setRefFontPixelSize(_d) {
150 | currentFontPixelSize = _d
151 | _calculate()
152 | }
153 |
154 | function guess(_w, _h) {
155 | currentDpm = window.Screen.pixelDensity
156 | currentFontPixelSize = window.font.pixelSize
157 | _calculate()
158 | }
159 |
160 | function _calculate() {
161 | ratio = currentDpm / internal.refDpm
162 |
163 | if(fontCalculationWithDPM) {
164 | ratioFont = ratio
165 | } else {
166 | ratioFont = currentFontPixelSize / internal.refFontPixelSize
167 | }
168 |
169 | if(_debugLayout) {
170 | console.debug("primary screen:"+window.Screen.name)
171 | console.debug("dpm:" + currentDpm +" fontPixelSize:" + currentFontPixelSize +
172 | " ratio:" + ratio + " ratioFont:" + ratioFont)
173 | }
174 | }
175 |
176 | function initialize(_w, _h) {
177 | internal.load_default()
178 | guess(_w, _h)
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/test/main.qml:
--------------------------------------------------------------------------------
1 | import QtQuick
2 | import QtQuick.Controls
3 | import QtQuick.Layouts
4 |
5 | ApplicationWindow {
6 | id: window
7 | visible: true
8 | width: 400
9 | height: 350
10 | title: qsTr("Hello Colorpicker")
11 |
12 | property color captured_color: "transparent"
13 |
14 | property int fontPixelSize: 10
15 | property int itemHeight: 28
16 | property int buttonHeight: 26
17 |
18 | Flickable {
19 | id: flickable
20 | clip: true
21 | anchors.top: parent.top
22 | anchors.left: parent.left
23 | anchors.right:parent.right
24 | height: 150
25 | contentHeight: panel.implicitHeight
26 |
27 | ScrollBar.vertical: ScrollBar { }
28 |
29 | Flow {
30 | id: panel
31 | anchors.fill: parent
32 | padding: 5
33 | spacing: 5
34 |
35 | CheckBox {
36 | id: colorDialogAlpha
37 | text: "Show alpha channel"
38 | font.pixelSize: fontPixelSize
39 | checked: true
40 | height: itemHeight
41 | onClicked : {
42 | my_picker.enableAlphaChannel = checked
43 | }
44 | background: Rectangle {
45 | anchors.fill: parent
46 | border.width: 1
47 | border.color: "Gray"
48 | color: "transparent"
49 | }
50 | }
51 | CheckBox {
52 | id: colorDialogDetail
53 | text: "Show details"
54 | font.pixelSize: fontPixelSize
55 | checked: true
56 | height: itemHeight
57 | onClicked : {
58 | my_picker.enableDetails = checked
59 | }
60 | background: Rectangle {
61 | anchors.fill: parent
62 | border.width: 1
63 | border.color: "Gray"
64 | color: "transparent"
65 | }
66 | }
67 |
68 | CheckBox {
69 | id: paletteMode
70 | text: "Palette Mode"
71 | font.pixelSize: fontPixelSize
72 | checked: my_picker.paletteMode
73 | height: itemHeight
74 | onClicked : {
75 | my_picker.paletteMode = checked
76 | }
77 | background: Rectangle {
78 | anchors.fill: parent
79 | border.width: 1
80 | border.color: "Gray"
81 | }
82 | }
83 |
84 | CheckBox {
85 | id: paletteModeDefault
86 | text: "Enable Palette Mode"
87 | font.pixelSize: fontPixelSize
88 | checked: my_picker.enablePaletteMode
89 | height: itemHeight
90 | onClicked : {
91 | my_picker.enablePaletteMode = checked
92 | }
93 | background: Rectangle {
94 | anchors.fill: parent
95 | border.width: 1
96 | border.color: "Gray"
97 | color: "transparent"
98 | }
99 | }
100 |
101 | Rectangle {
102 | border.width: 1
103 | border.color: "Gray"
104 | color: "transparent"
105 | width: capture_color.implicitWidth
106 | height: capture_color.implicitHeight
107 | Row {
108 | id: capture_color
109 | height: itemHeight
110 | spacing: 5
111 | rightPadding: 5
112 | leftPadding: 5
113 | anchors.verticalCenter: parent.verticalCenter
114 | Rectangle {
115 | width: 40
116 | height: 15
117 | color: my_picker.colorValue
118 | border.color: activePalette.highlight
119 | border.width: 1
120 | anchors.verticalCenter: parent.verticalCenter
121 | }
122 | Button {
123 | height: buttonHeight
124 | text: "Get"
125 | font.pixelSize: fontPixelSize
126 | onClicked: {
127 | captured_color = my_picker.colorValue
128 | }
129 | }
130 | }
131 | }
132 |
133 | Rectangle {
134 | border.width: 1
135 | border.color: "Gray"
136 | color: "transparent"
137 | width: captured.implicitWidth
138 | height: captured.implicitHeight
139 | Row {
140 | id: captured
141 | height: itemHeight
142 | spacing: 5
143 | rightPadding: 5
144 | leftPadding: 5
145 | anchors.verticalCenter: parent.verticalCenter
146 | Rectangle {
147 | width: 40
148 | height: 15
149 | color: captured_color
150 | border.color: activePalette.highlight
151 | border.width: 1
152 | anchors.verticalCenter: parent.verticalCenter
153 | }
154 | Button {
155 | height: buttonHeight
156 | text: "Set"
157 | font.pixelSize: fontPixelSize
158 | onClicked: {
159 | my_picker.setColor(captured_color)
160 | }
161 | }
162 | }
163 | }
164 |
165 | Rectangle {
166 | border.width: 1
167 | border.color: "Gray"
168 | width: tests.implicitWidth
169 | height: tests.implicitHeight
170 | color: "transparent"
171 | Row {
172 | id: tests
173 | height: itemHeight
174 | spacing: 5
175 | rightPadding: 5
176 | leftPadding: 5
177 | Button {
178 | height: buttonHeight
179 | text: "Layout"
180 | font.pixelSize: fontPixelSize
181 | onClicked: {
182 | my_picker.setFontCalculationWithDPM(false)
183 | my_picker.layoutDefault()
184 | }
185 | }
186 | Button {
187 | height: buttonHeight
188 | text: "Test1"
189 | font.pixelSize: fontPixelSize
190 | onClicked: {
191 | my_picker.setDpm(0.7 * window.Screen.pixelDensity)
192 | my_picker.layout()
193 | }
194 | }
195 | Button {
196 | height: buttonHeight
197 | text: "Test2"
198 | font.pixelSize: fontPixelSize
199 | onClicked: {
200 | my_picker.setFontCalculationWithDPM(true)
201 | my_picker.setDpm(0.7 * window.Screen.pixelDensity)
202 |
203 | console.debug('colorPicker.colorHandleRadius: from ' + my_picker.getSizeValue("colorPicker.colorHandleRadius"))
204 | my_picker.setSizeValue("colorPicker.colorHandleRadius", 22)
205 | console.debug('colorPicker.colorHandleRadius: to ' + my_picker.getSizeValue("colorPicker.colorHandleRadius"))
206 |
207 | console.debug('colorPicker.colorHandleRadius: from ' + my_picker.getSizeValue("colorPicker.colorHandleRadius"))
208 | my_picker.setSizeValue("colorPicker.colorHandleRadius", 20)
209 | console.debug('colorPicker.colorHandleRadius: to ' + my_picker.getSizeValue("colorPicker.colorHandleRadius"))
210 |
211 | my_picker.layout()
212 | my_picker.setFontCalculationWithDPM(false)
213 | }
214 | }
215 | }
216 | }
217 | }
218 |
219 | SystemPalette {
220 | id: activePalette
221 | colorGroup: SystemPalette.Active
222 | }
223 | }
224 |
225 | Colorpicker {
226 | id: my_picker
227 | anchors.top: flickable.bottom
228 | anchors.bottom: parent.bottom
229 | anchors.right: parent.right
230 | anchors.left: parent.left
231 |
232 | onColorChanged: (changedColor) => {
233 | // test signal handler
234 | console.debug("handle signal:"+changedColor)
235 | }
236 | }
237 | }
238 |
--------------------------------------------------------------------------------
/colorpicker/content/Paletts.qml:
--------------------------------------------------------------------------------
1 | import QtQuick
2 | import QtQuick.Controls
3 |
4 | Grid {
5 | id: grid
6 |
7 | property color paletts_color : "transparent"
8 | property real button_width : 30
9 | property real button_height : 32
10 |
11 | rows: 5
12 | columns: 9
13 | spacing: 0
14 | padding: 0
15 |
16 | // row 0
17 | SinglePalette {
18 | target_color: "black"
19 | width: button_width
20 | height: button_height
21 | onCheckedChanged: () =>{
22 | if(checked) {
23 | paletts_color = target_color
24 | }
25 | }
26 | }
27 | SinglePalette {
28 | target_color: "#705958"
29 | width: button_width
30 | height: button_height
31 | onCheckedChanged: () => {
32 | if(checked) {
33 | paletts_color = target_color
34 | }
35 | }
36 | }
37 | SinglePalette {
38 | target_color: "red"
39 | implicitWidth: button_width
40 | height: button_height
41 | onCheckedChanged: () => {
42 | if(checked) {
43 | paletts_color = target_color
44 | }
45 | }
46 | }
47 | SinglePalette {
48 | target_color: "#c90002"
49 | implicitWidth: button_width
50 | height: button_height
51 | onCheckedChanged: () => {
52 | if(checked) {
53 | paletts_color = target_color
54 | }
55 | }
56 | }
57 | SinglePalette {
58 | target_color: "#9d0000"
59 | implicitWidth: button_width
60 | height: button_height
61 | onCheckedChanged: () => {
62 | if(checked) {
63 | paletts_color = target_color
64 | }
65 | }
66 | }
67 | SinglePalette {
68 | target_color: "#b20093" // red purple
69 | implicitWidth: button_width
70 | height: button_height
71 | onCheckedChanged: () => {
72 | if(checked) {
73 | paletts_color = target_color
74 | }
75 | }
76 | }
77 | SinglePalette {
78 | target_color: "#c978b8"
79 | implicitWidth: button_width
80 | height: button_height
81 | onCheckedChanged: () => {
82 | if(checked) {
83 | paletts_color = target_color
84 | }
85 | }
86 | }
87 | SinglePalette {
88 | target_color: "#8d0073"
89 | implicitWidth: button_width
90 | height: button_height
91 | onCheckedChanged: () => {
92 | if(checked) {
93 | paletts_color = target_color
94 | }
95 | }
96 | }
97 | SinglePalette {
98 | target_color: "#750161"
99 | implicitWidth: button_width
100 | height: button_height
101 | onCheckedChanged: () => {
102 | if(checked) {
103 | paletts_color = target_color
104 | }
105 | }
106 | }
107 |
108 | // row 1
109 | SinglePalette {
110 | target_color: "gray"
111 | implicitWidth: button_width
112 | height: button_height
113 | onCheckedChanged: () => {
114 | if(checked) {
115 | paletts_color = target_color
116 | }
117 | }
118 | }
119 | SinglePalette {
120 | target_color: "#8366b4"
121 | implicitWidth: button_width
122 | height: button_height
123 | onCheckedChanged: () => {
124 | if(checked) {
125 | paletts_color = target_color
126 | }
127 | }
128 | }
129 | SinglePalette {
130 | target_color: "purple"
131 | implicitWidth: button_width
132 | height: button_height
133 | onCheckedChanged: () => {
134 | if(checked) {
135 | paletts_color = target_color
136 | }
137 | }
138 | }
139 | SinglePalette {
140 | target_color: "#51127c"
141 | implicitWidth: button_width
142 | height: button_height
143 | onCheckedChanged: () => {
144 | if(checked) {
145 | paletts_color = target_color
146 | }
147 | }
148 | }
149 | SinglePalette {
150 | target_color: "#400061"
151 | implicitWidth: button_width
152 | height: button_height
153 | onCheckedChanged: () => {
154 | if(checked) {
155 | paletts_color = target_color
156 | }
157 | }
158 | }
159 | SinglePalette {
160 | target_color: "#5361b5"
161 | implicitWidth: button_width
162 | height: button_height
163 | onCheckedChanged: () => {
164 | if(checked) {
165 | paletts_color = target_color
166 | }
167 | }
168 | }
169 | SinglePalette {
170 | target_color: "#1b3d9f"
171 | implicitWidth: button_width
172 | height: button_height
173 | onCheckedChanged: () => {
174 | if(checked) {
175 | paletts_color = target_color
176 | }
177 | }
178 | }
179 | SinglePalette {
180 | target_color: "#152c81"
181 | implicitWidth: button_width
182 | height: button_height
183 | onCheckedChanged: () => {
184 | if(checked) {
185 | paletts_color = target_color
186 | }
187 | }
188 | }
189 | SinglePalette {
190 | target_color: "#061967"
191 | implicitWidth: button_width
192 | height: button_height
193 | onCheckedChanged: () => {
194 | if(checked) {
195 | paletts_color = target_color
196 | }
197 | }
198 | }
199 |
200 | // row 2
201 | SinglePalette {
202 | target_color: "darkgray"
203 | implicitWidth: button_width
204 | height: button_height
205 | onCheckedChanged: () => {
206 | if(checked) {
207 | paletts_color = target_color
208 | }
209 | }
210 | }
211 | SinglePalette {
212 | target_color: "#5188ca"
213 | implicitWidth: button_width
214 | height: button_height
215 | onCheckedChanged: () => {
216 | if(checked) {
217 | paletts_color = target_color
218 | }
219 | }
220 | }
221 | SinglePalette {
222 | target_color: "blue"
223 | implicitWidth: button_width
224 | height: button_height
225 | onCheckedChanged: () => {
226 | if(checked) {
227 | paletts_color = target_color
228 | }
229 | }
230 | }
231 | SinglePalette {
232 | target_color: "#004d90"
233 | implicitWidth: button_width
234 | height: button_height
235 | onCheckedChanged: () => {
236 | if(checked) {
237 | paletts_color = target_color
238 | }
239 | }
240 | }
241 | SinglePalette {
242 | target_color: "#003d75"
243 | implicitWidth: button_width
244 | height: button_height
245 | onCheckedChanged: () => {
246 | if(checked) {
247 | paletts_color = target_color
248 | }
249 | }
250 | }
251 | SinglePalette {
252 | target_color: "#02afae"
253 | implicitWidth: button_width
254 | height: button_height
255 | onCheckedChanged: () => {
256 | if(checked) {
257 | paletts_color = target_color
258 | }
259 | }
260 | }
261 | SinglePalette {
262 | target_color: "#008c8a"
263 | implicitWidth: button_width
264 | height: button_height
265 | onCheckedChanged: () => {
266 | if(checked) {
267 | paletts_color = target_color
268 | }
269 | }
270 | }
271 | SinglePalette {
272 | target_color: "#017071"
273 | implicitWidth: button_width
274 | height: button_height
275 | onCheckedChanged: () => {
276 | if(checked) {
277 | paletts_color = target_color
278 | }
279 | }
280 | }
281 | SinglePalette {
282 | target_color: "#36c590"
283 | implicitWidth: button_width
284 | height: button_height
285 | onCheckedChanged: () => {
286 | if(checked) {
287 | paletts_color = target_color
288 | }
289 | }
290 | }
291 |
292 | // row 3
293 | SinglePalette {
294 | target_color: "lightgray"
295 | implicitWidth: button_width
296 | height: button_height
297 | onCheckedChanged: () => {
298 | if(checked) {
299 | paletts_color = target_color
300 | }
301 | }
302 | }
303 | SinglePalette {
304 | target_color: "#56c222"
305 | implicitWidth: button_width
306 | height: button_height
307 | onCheckedChanged: () => {
308 | if(checked) {
309 | paletts_color = target_color
310 | }
311 | }
312 | }
313 | SinglePalette {
314 | target_color: "green"
315 | implicitWidth: button_width
316 | height: button_height
317 | onCheckedChanged: () => {
318 | if(checked) {
319 | paletts_color = target_color
320 | }
321 | }
322 | }
323 | SinglePalette {
324 | target_color: "#018944"
325 | implicitWidth: button_width
326 | height: button_height
327 | onCheckedChanged: () => {
328 | if(checked) {
329 | paletts_color = target_color
330 | }
331 | }
332 | }
333 | SinglePalette {
334 | target_color: "#006f35"
335 | implicitWidth: button_width
336 | height: button_height
337 | onCheckedChanged: () => {
338 | if(checked) {
339 | paletts_color = target_color
340 | }
341 | }
342 | }
343 | SinglePalette {
344 | target_color: "#fcf471"
345 | implicitWidth: button_width
346 | height: button_height
347 | onCheckedChanged: () => {
348 | if(checked) {
349 | paletts_color = target_color
350 | }
351 | }
352 | }
353 | SinglePalette {
354 | target_color: "yellow"
355 | implicitWidth: button_width
356 | height: button_height
357 | onCheckedChanged: () => {
358 | if(checked) {
359 | paletts_color = target_color
360 | }
361 | }
362 | }
363 | SinglePalette {
364 | target_color: "#cdc101"
365 | implicitWidth: button_width
366 | height: button_height
367 | onCheckedChanged: () => {
368 | if(checked) {
369 | paletts_color = target_color
370 | }
371 | }
372 | }
373 | SinglePalette {
374 | target_color: "#a39700"
375 | implicitWidth: button_width
376 | height: button_height
377 | onCheckedChanged: () => {
378 | if(checked) {
379 | paletts_color = target_color
380 | }
381 | }
382 | }
383 |
384 | // row 4
385 | SinglePalette {
386 | target_color: "white"
387 | implicitWidth: button_width
388 | height: button_height
389 | onCheckedChanged: () => {
390 | if(checked) {
391 | paletts_color = target_color
392 | }
393 | }
394 | }
395 | SinglePalette {
396 | target_color: "#fdc667"
397 | implicitWidth: button_width
398 | height: button_height
399 | onCheckedChanged: () => {
400 | if(checked) {
401 | paletts_color = target_color
402 | }
403 | }
404 | }
405 | SinglePalette {
406 | target_color: "#fea200"
407 | implicitWidth: button_width
408 | height: button_height
409 | onCheckedChanged: () => {
410 | if(checked) {
411 | paletts_color = target_color
412 | }
413 | }
414 | }
415 | SinglePalette {
416 | target_color: "#cb8001"
417 | implicitWidth: button_width
418 | height: button_height
419 | onCheckedChanged: () => {
420 | if(checked) {
421 | paletts_color = target_color
422 | }
423 | }
424 | }
425 | SinglePalette {
426 | target_color: "#a66400"
427 | implicitWidth: button_width
428 | height: button_height
429 | onCheckedChanged: () => {
430 | if(checked) {
431 | paletts_color = target_color
432 | }
433 | }
434 | }
435 | SinglePalette {
436 | target_color: "#ffa566"
437 | implicitWidth: button_width
438 | height: button_height
439 | onCheckedChanged: () => {
440 | if(checked) {
441 | paletts_color = target_color
442 | }
443 | }
444 | }
445 | SinglePalette {
446 | target_color: "#ff7c00"
447 | implicitWidth: button_width
448 | height: button_height
449 | onCheckedChanged: () => {
450 | if(checked) {
451 | paletts_color = target_color
452 | }
453 | }
454 | }
455 | SinglePalette {
456 | target_color: "#cf6402"
457 | implicitWidth: button_width
458 | height: button_height
459 | onCheckedChanged: () => {
460 | if(checked) {
461 | paletts_color = target_color
462 | }
463 | }
464 | }
465 | SinglePalette {
466 | target_color: "#a54b00"
467 | implicitWidth: button_width
468 | height: button_height
469 | onCheckedChanged: () => {
470 | if(checked) {
471 | paletts_color = target_color
472 | }
473 | }
474 | }
475 | }
476 |
--------------------------------------------------------------------------------
/colorpicker/Colorpicker.qml:
--------------------------------------------------------------------------------
1 | // A toy QML colorpicker control, by Ruslan Shestopalyuk
2 | import QtQuick
3 | import QtQuick.Controls
4 | import QtQuick.Layouts
5 | import "content"
6 |
7 | Rectangle {
8 | id: colorPicker
9 |
10 | property bool _debugLayout: false // if you want to debug layout, set to true
11 | property bool _layoutAcceptance: false // this will be set to true after loading automatically
12 |
13 | property color colorValue: "transparent"
14 | property bool enableAlphaChannel: true
15 | property bool enableDetails: true
16 | property real colorHandleRadius: 0
17 | property bool paletteMode: false
18 | property bool enablePaletteMode: false
19 | property string switchToColorPickerString: qsTr("Palette...")
20 | property string switchToPalleteString: qsTr("Color Picker...")
21 |
22 | property color _changingColorValue: paletteMode ?
23 | _rgb(paletts.paletts_color, alphaSlider.value) :
24 | _hsla(hueSlider.value, sbPicker.saturation,
25 | sbPicker.brightness, alphaSlider.value)
26 |
27 | on_ChangingColorValueChanged: {
28 | colorValue = _changingColorValue
29 | }
30 | onEnableDetailsChanged: {
31 | layout()
32 | }
33 | onEnablePaletteModeChanged: {
34 | layout()
35 | }
36 | onEnableAlphaChannelChanged: {
37 | layout()
38 | }
39 | onPaletteModeChanged: {
40 | layout()
41 | }
42 |
43 | Component.onCompleted: {
44 | _sizeConfig.initialize(width, height)
45 | _layoutAcceptance = true
46 | layout()
47 | }
48 |
49 | signal colorChanged(changedColor: color)
50 | color: "transparent"
51 |
52 | clip: true
53 |
54 | Text {
55 | id: paletteSwitch
56 | textFormat: Text.StyledText
57 | text: paletteMode ?
58 | "" + switchToColorPickerString + "" :
59 | "" + switchToPalleteString + ""
60 | visible: enablePaletteMode
61 | onLinkActivated: {
62 | paletteMode = !paletteMode
63 | }
64 | anchors.right: parent.right
65 | anchors.rightMargin: colorHandleRadius
66 | }
67 |
68 | RowLayout {
69 | id: picker
70 | anchors.top: enablePaletteMode ? paletteSwitch.bottom : parent.top
71 | anchors.left: parent.left
72 | anchors.right: parent.right
73 | anchors.bottom: parent.bottom
74 |
75 | SwipeView {
76 | id: swipe
77 | clip: true
78 | interactive: false
79 | currentIndex: paletteMode ? 1 : 0
80 | Layout.fillWidth: true
81 | Layout.fillHeight: true
82 | Layout.preferredWidth: width
83 | Layout.maximumWidth: width
84 | Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
85 |
86 | SBPicker {
87 | id: sbPicker
88 | anchors.top: parent.top
89 | anchors.bottom: parent.bottom
90 |
91 | hueColor: {
92 | var v = 1.0-hueSlider.value
93 | console.debug("v:"+v)
94 |
95 | if(0.0 <= v && v < 0.16) {
96 | return Qt.rgba(1.0, 0.0, v/0.16, 1.0)
97 | } else if(0.16 <= v && v < 0.33) {
98 | return Qt.rgba(1.0 - (v-0.16)/0.17, 0.0, 1.0, 1.0)
99 | } else if(0.33 <= v && v < 0.5) {
100 | return Qt.rgba(0.0, ((v-0.33)/0.17), 1.0, 1.0)
101 | } else if(0.5 <= v && v < 0.76) {
102 | return Qt.rgba(0.0, 1.0, 1.0 - (v-0.5)/0.26, 1.0)
103 | } else if(0.76 <= v && v < 0.85) {
104 | return Qt.rgba((v-0.76)/0.09, 1.0, 0.0, 1.0)
105 | } else if(0.85 <= v && v <= 1.0) {
106 | return Qt.rgba(1.0, 1.0 - (v-0.85)/0.15, 0.0, 1.0)
107 | } else {
108 | console.log("hue value is outside of expected boundaries of [0, 1]")
109 | return "red"
110 | }
111 | }
112 | }
113 |
114 | Item {
115 | id: palettsHolder
116 | anchors.top: parent.top
117 | anchors.bottom: parent.bottom
118 | // anchors.left: sbPicker.right
119 | Paletts {
120 | id: paletts
121 | anchors.leftMargin: 8
122 | anchors.topMargin: 8
123 | anchors.bottomMargin: 8
124 | anchors.fill:parent
125 | }
126 | }
127 | }
128 |
129 | // hue picking slider
130 | Item {
131 | id: huePicker
132 | visible: !paletteMode
133 | height: parent.height
134 | Layout.fillWidth: true
135 | Layout.fillHeight: true
136 | Layout.preferredWidth: width
137 | Layout.maximumWidth: width
138 | Layout.preferredHeight: parent.height
139 | Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
140 | Layout.topMargin: colorHandleRadius
141 | Layout.bottomMargin: colorHandleRadius
142 | Layout.rightMargin: enableAlphaChannel ? 0 : colorHandleRadius
143 |
144 | Rectangle {
145 | anchors.fill: parent
146 | id: colorBar
147 | gradient: Gradient {
148 | GradientStop { position: 1.0; color: "#FF0000" }
149 | GradientStop { position: 0.85; color: "#FFFF00" }
150 | GradientStop { position: 0.76; color: "#00FF00" }
151 | GradientStop { position: 0.5; color: "#00FFFF" }
152 | GradientStop { position: 0.33; color: "#0000FF" }
153 | GradientStop { position: 0.16; color: "#FF00FF" }
154 | GradientStop { position: 0.0; color: "#FF0000" }
155 | }
156 | }
157 | ColorSlider {
158 | id: hueSlider; anchors.fill: parent
159 | }
160 | }
161 |
162 | // alpha (transparency) picking slider
163 | Item {
164 | id: alphaPicker
165 | visible: enableAlphaChannel
166 | Layout.fillWidth: true
167 | Layout.fillHeight: true
168 | Layout.preferredWidth: width
169 | Layout.maximumWidth: width
170 | Layout.preferredHeight: parent.height
171 | Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
172 | Layout.topMargin: colorHandleRadius
173 | Layout.bottomMargin: colorHandleRadius
174 | Layout.rightMargin: enableDetails ? 0 : colorHandleRadius
175 |
176 | Checkerboard { cellSide: 4 }
177 | // alpha intensity gradient background
178 | Rectangle {
179 | anchors.fill: parent
180 | gradient: Gradient {
181 | GradientStop { position: 0.0; color: "#FF000000" }
182 | GradientStop { position: 1.0; color: "#00000000" }
183 | }
184 | }
185 | ColorSlider {
186 | id: alphaSlider; anchors.fill: parent
187 | }
188 | }
189 |
190 | // details column
191 | Column {
192 | id: detailColumn
193 | height: parent.height
194 | visible: enableDetails
195 | Layout.fillWidth: true
196 | Layout.fillHeight: true
197 | Layout.preferredWidth: width
198 | Layout.maximumWidth: width
199 | Layout.preferredHeight: parent.height
200 | Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
201 | Layout.topMargin: colorHandleRadius
202 | //Layout.bottomMargin: colorHandleRadius
203 | Layout.rightMargin: colorHandleRadius
204 |
205 | // current color/alpha display rectangle
206 | PanelBorder {
207 | id: panelBorder
208 | width: parent.width
209 | visible: enableAlphaChannel
210 | Checkerboard { cellSide: 5 }
211 | Rectangle {
212 | width: parent.width; height: parent.height
213 | border.width: 1; border.color: "black"
214 | color: colorPicker.colorValue
215 | }
216 | }
217 |
218 | // "#XXXXXXXX" color value box
219 | PanelBorder {
220 | id: colorEditBox
221 | width: parent.width
222 | height: 15
223 | color: "transparent"
224 | TextInput {
225 | id: colorText
226 | anchors.fill: parent
227 | font.pixelSize: 11
228 | maximumLength: 9
229 | focus: false
230 | readOnly: true
231 | text: _fullColorString(colorPicker.colorValue, alphaSlider.value)
232 | selectByMouse: true
233 | horizontalAlignment: TextInput.AlignHCenter
234 | color: _activePalette.dark
235 | }
236 | }
237 |
238 | // H, S, B color values boxes
239 | Column {
240 | visible: !paletteMode
241 | width: parent.width
242 | NumberBox { id: hsbH; caption: "H:"; value: hueSlider.value.toFixed(2) }
243 | NumberBox { id: hsbS; caption: "S:"; value: sbPicker.saturation.toFixed(2) }
244 | NumberBox { id: hsbB; caption: "B:"; value: sbPicker.brightness.toFixed(2) }
245 | }
246 |
247 | // R, G, B color values boxes
248 | Column {
249 | width: parent.width
250 | NumberBox {
251 | id: rgbR
252 | caption: "R:"
253 | value: _getChannelStr(colorPicker.colorValue, 0)
254 | min: 0; max: 255
255 | fontPx: numberBoxFontPixelSize
256 | }
257 | NumberBox {
258 | id: rgbG
259 | caption: "G:"
260 | value: _getChannelStr(colorPicker.colorValue, 1)
261 | min: 0; max: 255
262 | fontPx: numberBoxFontPixelSize
263 | }
264 | NumberBox {
265 | id: rgbB
266 | caption: "B:"
267 | value: _getChannelStr(colorPicker.colorValue, 2)
268 | min: 0; max: 255
269 | fontPx: numberBoxFontPixelSize
270 | }
271 | }
272 |
273 | // alpha value box
274 | NumberBox {
275 | id: alphaChannel
276 | visible: enableAlphaChannel
277 | caption: "A:"; value: Math.ceil(alphaSlider.value*255)
278 | min: 0; max: 255
279 | }
280 | }
281 | }
282 |
283 | // creates color value from hue, saturation, brightness, alpha
284 | function _hsla(h, s, b, a) {
285 | var lightness = (2 - s)*b
286 | var satHSL = s*b/((lightness <= 1) ? lightness : 2 - lightness)
287 | lightness /= 2
288 |
289 | var c = Qt.hsla(h, satHSL, lightness, a)
290 |
291 | colorChanged(c)
292 |
293 | return c
294 | }
295 |
296 | // create rgb value
297 | function _rgb(rgb, a) {
298 |
299 | var c = Qt.rgba(rgb.r, rgb.g, rgb.b, a)
300 |
301 | colorChanged(c)
302 |
303 | return c
304 | }
305 |
306 | // creates a full color string from color value and alpha[0..1], e.g. "#FF00FF00"
307 | function _fullColorString(clr, a) {
308 | return "#" + ((Math.ceil(a*255) + 256).toString(16).substr(1, 2) + clr.toString().substr(1, 6)).toUpperCase()
309 | }
310 |
311 | // extracts integer color channel value [0..255] from color value
312 | function _getChannelStr(clr, channelIdx) {
313 | return parseInt(clr.toString().substr(channelIdx*2 + 1, 2), 16)
314 | }
315 |
316 | // set color from outside
317 | function setColor(color) {
318 |
319 | // color object
320 | var c = Qt.tint(color, "transparent")
321 |
322 | console.debug('set_color is called with:'+c)
323 |
324 | // set alpha
325 | alphaSlider.setValue(c.a)
326 |
327 | // set rgb. Now it's insufficient to update hue related component.
328 | colorPicker.colorValue = c
329 | }
330 |
331 | SizeConfigrator {
332 | id: _sizeConfig
333 | }
334 |
335 | SystemPalette {
336 | id: _activePalette
337 | colorGroup: SystemPalette.Active
338 | }
339 |
340 | function layout() {
341 | if(!_layoutAcceptance) {
342 | return
343 | }
344 |
345 | colorHandleRadius = _sizeConfig.getSizeValue("colorPicker.colorHandleRadius")
346 | paletteSwitch.height = _sizeConfig.getSizeValue('paletteSwitch.height')
347 | picker.height = colorPicker.height - (enablePaletteMode ? paletteSwitch.height : 0)
348 | picker.spacing = _sizeConfig.getSizeValue('picker.spacing')
349 | huePicker.width = _sizeConfig.getSizeValue('huePicker.width')
350 | alphaPicker.width = _sizeConfig.getSizeValue('alphaPicker.width')
351 | detailColumn.width = _sizeConfig.getSizeValue('detailColumn.width')
352 | detailColumn.spacing = _sizeConfig.getSizeValue('detailColumn.spacing')
353 | panelBorder.height = _sizeConfig.getSizeValue('panelBorder.height')
354 | swipe.width = colorPicker.width - (!paletteMode ? huePicker.width + picker.spacing: 0) - (enableAlphaChannel ? alphaPicker.width + picker.spacing: 0) - (enableDetails ? detailColumn.width : 0)
355 | sbPicker.width = swipe.width
356 | paletts.button_width = (paletts.width - 2.0 * colorHandleRadius) / 9.0
357 | paletts.button_height = paletts.height / 5.0
358 | paletteSwitch.font.pixelSize = _sizeConfig.getFontValue('paletteSwitch.font.pixelSize')
359 | colorEditBox.height = _sizeConfig.getFontValue('colorEditBox.height')
360 | colorText.font.pixelSize = _sizeConfig.getFontValue('colorText.font.pixelSize')
361 |
362 | // NumberBox related
363 | {
364 | var px = _sizeConfig.getFontValue('NumberBox.font.pixelSize')
365 | var caption_width = _sizeConfig.getSizeValue('NumberBox.captionBoarder.width')
366 | var nbox_width = _sizeConfig.getSizeValue('NumberBox.width')
367 | var nbox_height = _sizeConfig.getSizeValue('NumberBox.height')
368 |
369 | hsbH.fontPx = px
370 | hsbH.width = nbox_width
371 | hsbH.height = nbox_height
372 | hsbH.captionWidth = caption_width
373 |
374 | hsbS.fontPx = px
375 | hsbS.width = nbox_width
376 | hsbS.height = nbox_height
377 | hsbS.captionWidth = caption_width
378 |
379 | hsbB.fontPx = px
380 | hsbB.width = nbox_width
381 | hsbB.height = nbox_height
382 | hsbB.captionWidth = caption_width
383 |
384 | rgbR.fontPx = px
385 | rgbR.width = nbox_width
386 | rgbR.height = nbox_height
387 | rgbR.captionWidth = caption_width
388 |
389 | rgbG.fontPx = px
390 | rgbG.width = nbox_width
391 | rgbG.height = nbox_height
392 | rgbG.captionWidth = caption_width
393 |
394 | rgbB.fontPx = px
395 | rgbB.width = nbox_width
396 | rgbB.height = nbox_height
397 | rgbB.captionWidth = caption_width
398 |
399 | alphaChannel.fontPx = px
400 | alphaChannel.width = nbox_width
401 | alphaChannel.height = nbox_height
402 | alphaChannel.captionWidth = caption_width
403 | }
404 |
405 | if(_debugLayout) {
406 | _dump_layout()
407 | }
408 | }
409 |
410 | function layoutWithGuess() {
411 | _sizeConfig.guess()
412 | layout()
413 | }
414 | function layoutDefault() {
415 | _sizeConfig.initialize()
416 | layout()
417 | }
418 |
419 | function setDpm(_d) {
420 | _sizeConfig.setDpm(_d)
421 | }
422 | function setRefFontPixelSize(_d) {
423 | _sizeConfig.setRefFontPixelSize(_d)
424 | }
425 | function setFontCalculationWithDPM(_b) {
426 | _sizeConfig.fontCalculationWithDPM = _b
427 | }
428 | function setSizeValue(tag, _v) {
429 | _sizeConfig.setSizeValue(tag, _v)
430 | }
431 | function getSizeValue(tag) {
432 | return _sizeConfig.getSizeValue(tag)
433 | }
434 |
435 | function _dump_layout() {
436 | console.debug('>>> layout information:')
437 | console.debug('colorHandleRadius:'+colorHandleRadius)
438 | console.debug('colorPicker.width/height/implicitWidth/implicitHeight='+colorPicker.width+','+colorPicker.height+','+colorPicker.implicitWidth+','+colorPicker.implicitHeight)
439 | console.debug('picker.width/height/implicitWidth/implicitHeight='+picker.width+','+picker.height+','+picker.implicitWidth+','+picker.implicitHeight)
440 | console.debug('huePicker.width/height/implicitWidth/implicitHeight='+huePicker.width+','+huePicker.height+','+huePicker.implicitWidth+','+huePicker.implicitHeight)
441 | console.debug('alphaPicker.width/height/implicitWidth/implicitHeight='+alphaPicker.width+','+alphaPicker.height+','+alphaPicker.implicitWidth+','+alphaPicker.implicitHeight)
442 | console.debug('detailColumn.width/height/implicitWidth/implicitHeight='+detailColumn.width+','+detailColumn.height+','+detailColumn.implicitWidth+','+detailColumn.implicitHeight)
443 | console.debug('swipe.width/height/implicitWidth/implicitHeight='+swipe.width+','+swipe.height+','+swipe.implicitWidth+','+swipe.implicitHeight)
444 | console.debug('sbPicker.width/height/implicitWidth/implicitHeight='+sbPicker.width+','+sbPicker.height+','+sbPicker.implicitWidth+','+sbPicker.implicitHeight)
445 | console.debug('paletts.width/height/implicitWidth/implicitHeight='+paletts.width+','+paletts.height+','+paletts.implicitWidth+','+paletts.implicitHeight)
446 | }
447 | }
448 |
--------------------------------------------------------------------------------