├── 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 | ![](doc_image/wasm_on_chrome.png) 22 | 23 | ## Qt 6.4.3, windows (windows10) 24 | ### Basic Style 25 | ![](doc_image/win10_FHD_landscape_basic_normal.png) 26 | 27 | ### Basic Style and fake low DotPerMilimeter 28 | ![](doc_image/win10_FHD_landscape_basic_normal_test2.png) 29 | 30 | ### Basic Style and Palette mode 31 | ![](doc_image/win10_FHD_landscape_basic_norma_palette.png) 32 | 33 | ### Universal Style and fake low DotPerMilimeter 34 | ![](doc_image/win10_FHD_landscape_universal_normal_test2.png) 35 | 36 | ### Imagine Style, portrait and fake low DotPerMilimeter 37 | ![](doc_image/win10_FHD_portrait_imagine_test2.png) 38 | 39 | ### Material Style and fake low DotPerMilimeter 40 | ![](doc_image/win10_FHD_portrait_material_test2.png) 41 | 42 | ## Qt 6.4.3, android (Pixel 6 Pro API 33 on Simulator) 43 | ### Basic Style 44 | ![](doc_image/android_portrait_basic.png) 45 | 46 | ### Basic Style, palette mode and fake low DotPerMilimeter 47 | ![](doc_image/android_landscape_basic_test1.png) 48 | 49 | ### Basic Style, palette mode and fake low DotPerMilimeter(alternative font size calculation) 50 | ![](doc_image/android_landscape_basic_test2.png) 51 | 52 | ## Qt 6.4.3, linux (ubuntu 22.04.2 LTS on Hyper-V) 53 | ### Basic Style 54 | ![](doc_image/linux_landscape_basic_normal.png) 55 | 56 | ## Qt6.4.3, iPhone 14 pro (iOS16.2 on Simulator) 57 | ### Basic Style and fake low DotPerMilimeter 58 | ![](doc_image/ios_iphone14pro_landscape_basic_small_dpm.png) 59 | 60 | ### Basic Style and portrait 61 | ![](doc_image/ios_iphone14pro_portrait_basic.png) 62 | 63 | ### Basic Style, palette mode and fake low DotPerMilimeter 64 | ![](doc_image/ios_iphone14pro_landscape_basic_smalldpm_pallete.png) 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 | --------------------------------------------------------------------------------