├── .gitignore ├── CMakeLists.txt ├── Gradient-16bit.png ├── README.md ├── StackStream.vpj ├── cmake_modules ├── FindFreeImage.cmake ├── FindFreeImagePlus.cmake ├── FindPyQt5.cmake ├── FindSIP.cmake ├── FindSIP.py └── SIPMacros.cmake ├── devtest └── PyQmlProof │ ├── ImagePane.qml │ ├── PointTablePane.qml │ ├── PyQmlProof.pro │ ├── PyQmlProof.py │ ├── PyQmlProof.qml │ ├── TiledBackground.qml │ └── list_role_model.py ├── source ├── Application │ ├── Application.qrc │ ├── CMakeLists.txt │ └── main.cpp ├── CMakeLists.txt ├── GilLocker.cpp ├── GilLocker.h ├── PythonModule │ └── CMakeLists.txt ├── QtQmlTricks │ ├── CMakeLists.txt │ ├── QtQmlTricks.qbs │ ├── README.md │ ├── doc │ │ ├── Doxyfile │ │ ├── doc_style.css │ │ └── symbolic_icons_guidelines.svg │ ├── examples │ │ ├── BitStream │ │ │ ├── QtBitStream.qbs │ │ │ └── main_bitstream.cpp │ │ ├── COBS │ │ │ ├── QtCOBS.qbs │ │ │ └── main_cobs.cpp │ │ ├── CustomPolygon │ │ │ ├── CustomPolygon.qbs │ │ │ ├── data_custompolygon.qrc │ │ │ ├── main_custompolygon.cpp │ │ │ └── ui_custompolygon.qml │ │ ├── IconCache │ │ │ ├── IconCache.qbs │ │ │ ├── data_iconcache.qrc │ │ │ ├── main_iconcache.cpp │ │ │ ├── mark.svg │ │ │ └── ui_iconcache.qml │ │ ├── JSONPath │ │ │ ├── QtJsonPath.qbs │ │ │ └── main_jsonpath.cpp │ │ └── NiceModels │ │ │ ├── NiceModels.qbs │ │ │ ├── data_nicemodels.qrc │ │ │ ├── defs_nicemodels.h │ │ │ ├── main_nicemodels.cpp │ │ │ └── ui_nicemodels.qml │ ├── import │ │ ├── QtQmlTricks │ │ │ ├── ComboList.qml │ │ │ ├── GridContainer.qml │ │ │ ├── IconTextButton.qml │ │ │ ├── QmlComponents.qbs │ │ │ ├── QtCoreApi.js │ │ │ ├── RowContainer.qml │ │ │ ├── ScrollContainer.qml │ │ │ ├── SingleLineEditBox.qml │ │ │ ├── Style.js │ │ │ ├── TextBox.qml │ │ │ ├── TextButton.qml │ │ │ ├── TextLabel.qml │ │ │ ├── WrapLeftRightContainer.qml │ │ │ ├── components.qrc │ │ │ └── qmldir │ │ └── import.qbs │ ├── include │ │ ├── QQmlGadgetListModel │ │ ├── QQmlHelpers │ │ ├── QQmlObjectListModel │ │ ├── QQmlSvgIconHelper │ │ ├── QQmlVariantListModel │ │ ├── QQuickPolygon │ │ ├── QtBitStream │ │ ├── QtCOBS │ │ ├── QtJsonPath │ │ └── QtQmlTricks │ ├── qtqmltricks.svg │ └── src │ │ ├── QtLibrary.qbs │ │ ├── qmlplugin.cpp │ │ ├── qmlplugin.h │ │ ├── qqmlgadgetlistmodel.cpp │ │ ├── qqmlgadgetlistmodel.h │ │ ├── qqmlhelpers.cpp │ │ ├── qqmlhelpers.h │ │ ├── qqmlmodels.h │ │ ├── qqmlobjectlistmodel.cpp │ │ ├── qqmlobjectlistmodel.h │ │ ├── qqmlsvgiconhelper.cpp │ │ ├── qqmlsvgiconhelper.h │ │ ├── qqmlvariantlistmodel.cpp │ │ ├── qqmlvariantlistmodel.h │ │ ├── qqmlvariantlistmodel_p.h │ │ ├── qquickpolygon.cpp │ │ ├── qquickpolygon.h │ │ ├── qtbitstream.h │ │ ├── qtcobs.h │ │ └── qtjsonpath.h ├── SSGContextPlugin │ ├── CMakeLists.txt │ ├── SSGContext.cpp │ ├── SSGContext.h │ ├── SSGContextPlugin.cpp │ ├── SSGContextPlugin.h │ ├── SSGContextPlugin.json │ ├── SSGQuickLayer.cpp │ └── SSGQuickLayer.h ├── SSGSimpleTextureNode.cpp ├── SSGSimpleTextureNode.h ├── SSGTexture.cpp ├── SSGTexture.h ├── SSGTextureMaterial.cpp ├── SSGTextureMaterial.h ├── SSImage.cpp ├── SSImage.h ├── SSImageItem.cpp ├── SSImageItem.h ├── SSQmlPlugin.cpp ├── SSQmlPlugin.h ├── SSView.cpp ├── SSView.h ├── StackStreamMainWindow.qml ├── StackStreamPlugin.qrc ├── TileBackground.qml ├── common.h └── qmldir └── todo_mindmap.vym /.gitignore: -------------------------------------------------------------------------------- 1 | # This file is used to ignore files which are generated 2 | # ---------------------------------------------------------------------------- 3 | 4 | *~ 5 | *.autosave 6 | *.a 7 | *.core 8 | *.moc 9 | *.o 10 | *.obj 11 | *.orig 12 | *.rej 13 | *.so 14 | *.so.* 15 | *_pch.h.cpp 16 | *_resource.rc 17 | *.qm 18 | .#* 19 | *.*# 20 | core 21 | !core/ 22 | tags 23 | .DS_Store 24 | *.debug 25 | Makefile* 26 | *.prl 27 | *.app 28 | moc_*.cpp 29 | ui_*.h 30 | qrc_*.cpp 31 | Thumbs.db 32 | *.res 33 | *.rc 34 | /.qmake.cache 35 | /.qmake.stash 36 | 37 | # qtcreator generated files 38 | *.pro.user* 39 | 40 | # xemacs temporary files 41 | *.flc 42 | 43 | # Vim temporary files 44 | .*.swp 45 | 46 | # Visual Studio generated files 47 | *.ib_pdb_index 48 | *.idb 49 | *.ilk 50 | *.pdb 51 | *.sln 52 | *.suo 53 | *.vcproj 54 | *vcproj.*.*.user 55 | *.ncb 56 | *.sdf 57 | *.opensdf 58 | *.vcxproj 59 | *vcxproj.* 60 | 61 | # MinGW generated files 62 | *.Debug 63 | *.Release 64 | 65 | # Python byte code 66 | *.pyc 67 | 68 | # Binaries 69 | # -------- 70 | *.dll 71 | *.exe 72 | 73 | 74 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 2016 Erik Hvatum 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 | # 23 | # Authors: Erik Hvatum 24 | 25 | cmake_minimum_required(VERSION 3.0) 26 | project(StackStream) 27 | 28 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake_modules") 29 | if(NOT MSVC) 30 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 31 | endif() 32 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 33 | set(CMAKE_AUTOMOC ON) 34 | set(CMAKE_AUTORCC ON) 35 | 36 | find_package(FreeImage REQUIRED) 37 | find_package(FreeImagePlus REQUIRED) 38 | find_package(OpenGL REQUIRED) 39 | find_package(Qt5 COMPONENTS Core Gui OpenGL Qml Quick Svg Widgets) 40 | find_package(Qt5Core REQUIRED Private) 41 | find_package(Qt5Gui REQUIRED Private) 42 | find_package(Qt5Qml REQUIRED Private) 43 | find_package(Qt5Quick REQUIRED Private) 44 | 45 | set(Python_ADDITIONAL_VERSIONS ${Python_ADDITIONAL_VERSIONS} "3.4") 46 | find_package(PythonInterp 3.4 REQUIRED) 47 | if(NOT APPLE) 48 | find_package(PythonLibs 3.4 REQUIRED) 49 | else() 50 | # FindPythonLibs.cmake is totally horked on OS X and will probably remain so until the end of time and beyond: http://www.itk.org/Bug/view.php?id=14809 51 | # Because Find*.cmake modules must support cross compilation, the obvious fix of just asking the interpreter where its stuff is can't go into the 52 | # official CMake distribution. Because it's better to have it not work at all under any circumstance, I guess? Okay, that would be fine, except 53 | # we need this to work. So, we resort to asking the interpreter. 54 | execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import distutils.sysconfig; vs = distutils.sysconfig.get_config_vars(); print('LIBPL:\"{}\"LIBRARY:\"{}\"get_python_lib:\"{}\"get_python_inc:\"{}\"'.format(vs['LIBPL'], vs['LIBRARY'], distutils.sysconfig.get_python_lib(), distutils.sysconfig.get_python_inc()))" 55 | RESULT_VARIABLE _PYC_RESULT 56 | ERROR_VARIABLE _PYC_ERROR 57 | OUTPUT_VARIABLE _PYC_OUT 58 | OUTPUT_STRIP_TRAILING_WHITESPACE) 59 | if(NOT _PYC_RESULT MATCHES 0) 60 | message(FATAL_ERROR "Failed to interrogate Python interpreter (which must be done in order to locate the CPython library and header directories):\n${_PYC_ERROR}") 61 | return() 62 | endif() 63 | string(REGEX REPLACE 64 | "LIBPL:\"(.+)\"LIBRARY:\"(.+)\"get_python_lib:\"(.+)\"get_python_inc:\"(.+)\"" 65 | "\\1;\\2;\\3;\\4" 66 | _PYC_OUTS 67 | ${_PYC_OUT}) 68 | set(PYTHONLIBS_FOUND true) 69 | list(GET _PYC_OUTS 0 _PYTHON_LIB_DIR) 70 | list(GET _PYC_OUTS 1 _PYTHON_LIB_NAME) 71 | set(PYTHON_LIBRARIES "${_PYTHON_LIB_DIR}/${_PYTHON_LIB_NAME}") 72 | set(PYTHON_LIBRARY ${PYTHON_LIBRARIES}) 73 | list(GET _PYC_OUTS 3 PYTHON_INCLUDE_PATH) 74 | list(GET _PYC_OUTS 3 PYTHON_INCLUDE_DIRS) 75 | unset(_PYC_RESULT) 76 | unset(_PYC_ERROR) 77 | unset(_PYC_OUT) 78 | unset(_PYC_OUTS) 79 | unset(_PYTHON_LIB_DIR) 80 | unset(_PYTHON_LIB_NAME) 81 | message(STATUS "Found PythonLibs: ${PYTHON_LIBRARY} (do not be alarmed if the filename ends in .a; dynamic linking will be used nonetheless, if possible)") 82 | include_directories(SYSTEM ${PYTHON_INCLUDE_DIRS}) 83 | endif() 84 | 85 | execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import numpy;print(numpy.get_include())" 86 | RESULT_VARIABLE _NUMPY_INCLUDE_DIR_FOUND 87 | ERROR_VARIABLE _NUMPY_INCLUDE_DIR_ERROR 88 | OUTPUT_VARIABLE NUMPY_INCLUDE_DIR 89 | OUTPUT_STRIP_TRAILING_WHITESPACE) 90 | if(NOT _NUMPY_INCLUDE_DIR_FOUND MATCHES 0) 91 | message(FATAL_ERROR "Failed to import numpy (which must be done in order to locate the numpy C API header directory):\n${_NUMPY_INCLUDE_DIR_ERROR}") 92 | return() 93 | endif() 94 | unset(_NUMPY_INCLUDE_DIR_FOUND) 95 | unset(_NUMPY_INCLUDE_DIR_ERROR) 96 | 97 | set(BUILD_STACKSTREAM_PYTHON_MODULE ON) 98 | 99 | include_directories(SYSTEM ${FREEIMAGE_INCLUDE_PATH}) 100 | include_directories(SYSTEM ${FREEIMAGEPLUS_INCLUDE_PATH}) 101 | include_directories(SYSTEM ${NUMPY_INCLUDE_DIR}) 102 | include_directories(SYSTEM ${PYTHON_INCLUDE_DIR}) 103 | include_directories(SYSTEM ${Qt5Core_PRIVATE_INCLUDE_DIRS}) 104 | include_directories(SYSTEM ${Qt5Gui_PRIVATE_INCLUDE_DIRS}) 105 | include_directories(SYSTEM ${Qt5Qml_PRIVATE_INCLUDE_DIRS}) 106 | include_directories(SYSTEM ${Qt5Quick_PRIVATE_INCLUDE_DIRS}) 107 | 108 | add_subdirectory(source) 109 | -------------------------------------------------------------------------------- /Gradient-16bit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erikhvatum/StackStream/b33cf282e83ad104818e70f5b0e8adf1d781a50b/Gradient-16bit.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # StackStream 2 | A small collection of Qt and QML widgets for viewing images and image stack collections of any size + a QML scene graph plugin providing 32 bit per channel floating point framebuffer and layer support for optimal compositing, manipulation, and display of HDR and high-depth images, including in 30-bit mode (10 bit per channel). 3 | 4 | At this time, StackStream includes: 5 | 6 | * The first open source QML scene graph plugin of any kind. Implemented in C++. 7 | * The first open source 30-bit display support for QML and QtQuick2. Implemented in C++. 8 | * The first open source float32-component framebuffer and texture map support for QML and QtQuick2. Implemented in C++. 9 | * The SSImage class, supporting higher bitdepths than QImage and floating point components (which QImage does not support at all). Implemented in C++, exposed to QML. 10 | * The SSLayer class, a QQuickItem for displaying SSImage objects with gamma transformation. Implemented in C++, exposed to QML. 11 | * An SSLayer viewer with a GUI interface for gamma transform parameters and associated classes and objects. Implemented QML. 12 | 13 | StackStream will soon include: 14 | 15 | * Support for blending any arbitrary number SSLayers with any combination of the blend modes specified by SVG. 16 | * An extensive Python API exposed via SIP. 17 | * An SSImage and SSLayer stack flipbook presented as a table, with a complete Python API and intuitive multi-image drag and drop support. 18 | * A QAbstractModel-derived model exposed to Python as a simple Python list in addition to its full PyQt API, eliminating the need to represent anything as a QQmlList ever again. 19 | -------------------------------------------------------------------------------- /cmake_modules/FindFreeImage.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Try to find the FreeImage library and include path. 3 | # Once done this will define 4 | # 5 | # FREEIMAGE_FOUND 6 | # FREEIMAGE_INCLUDE_PATH 7 | # FREEIMAGE_LIBRARY 8 | # 9 | 10 | IF (WIN32) 11 | FIND_PATH( FREEIMAGE_INCLUDE_PATH FreeImage.h 12 | C:/FreeImage/Dist/x64 13 | ${PROJECT_SOURCE_DIR}/extern/FreeImage 14 | DOC "The directory where FreeImage.h resides") 15 | FIND_LIBRARY( FREEIMAGE_LIBRARY 16 | NAMES FreeImage freeimage 17 | PATHS 18 | C:/FreeImage/Dist/x64 19 | ${PROJECT_SOURCE_DIR}/FreeImage 20 | DOC "The FreeImage library") 21 | ELSE (WIN32) 22 | FIND_PATH( FREEIMAGE_INCLUDE_PATH FreeImage.h 23 | /usr/include 24 | /usr/local/include 25 | /sw/include 26 | /opt/local/include 27 | DOC "The directory where FreeImage.h resides") 28 | FIND_LIBRARY( FREEIMAGE_LIBRARY 29 | NAMES FreeImage freeimage 30 | PATHS 31 | /usr/lib64 32 | /usr/lib 33 | /usr/local/lib64 34 | /usr/local/lib 35 | /sw/lib 36 | /opt/local/lib 37 | DOC "The FreeImage library") 38 | ENDIF (WIN32) 39 | 40 | SET(FREEIMAGE_LIBRARIES ${FREEIMAGE_LIBRARY}) 41 | 42 | IF (FREEIMAGE_INCLUDE_PATH AND FREEIMAGE_LIBRARY) 43 | SET( FREEIMAGE_FOUND TRUE CACHE BOOL "Set to TRUE if FreeImage is found, FALSE otherwise") 44 | ELSE (FREEIMAGE_INCLUDE_PATH AND FREEIMAGE_LIBRARY) 45 | SET( FREEIMAGE_FOUND FALSE CACHE BOOL "Set to TRUE if FreeImage is found, FALSE otherwise") 46 | ENDIF (FREEIMAGE_INCLUDE_PATH AND FREEIMAGE_LIBRARY) 47 | 48 | MARK_AS_ADVANCED( 49 | FREEIMAGE_FOUND 50 | FREEIMAGE_LIBRARY 51 | FREEIMAGE_LIBRARIES 52 | FREEIMAGE_INCLUDE_PATH) 53 | 54 | IF (FREEIMAGE_FOUND) 55 | MESSAGE(STATUS "FREEIMAGE_INCLUDE_PATH = ${FREEIMAGE_INCLUDE_PATH}") 56 | MESSAGE(STATUS "FREEIMAGE_LIBRARY = ${FREEIMAGE_LIBRARY}") 57 | ELSE (FREEIMAGE_FOUND) 58 | IF (FreeImage_FIND_REQUIRED) 59 | MESSAGE(FATAL_ERROR "Could not find FreeImage") 60 | ENDIF (FreeImage_FIND_REQUIRED) 61 | ENDIF (FREEIMAGE_FOUND) 62 | -------------------------------------------------------------------------------- /cmake_modules/FindFreeImagePlus.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Try to find the FreeImagePlus library and include path. 3 | # Once done this will define 4 | # 5 | # FREEIMAGEPLUS_FOUND 6 | # FREEIMAGEPLUS_INCLUDE_PATH 7 | # FREEIMAGEPLUS_LIBRARY 8 | # 9 | 10 | IF (WIN32) 11 | FIND_PATH( FREEIMAGEPLUS_INCLUDE_PATH FreeImagePlus.h 12 | ${PROJECT_SOURCE_DIR}/extern/FreeImage 13 | C:/FreeImage/Wrapper/FreeImagePlus/dist/x64 14 | DOC "The directory where FreeImagePlus.h resides") 15 | FIND_LIBRARY( FREEIMAGEPLUS_LIBRARY 16 | NAMES FreeImagePlus freeimageplus 17 | PATHS 18 | C:/FreeImage/Wrapper/FreeImagePlus/dist/x64 19 | ${PROJECT_SOURCE_DIR}/FreeImage 20 | DOC "The FreeImage library") 21 | ELSE (WIN32) 22 | FIND_PATH( FREEIMAGEPLUS_INCLUDE_PATH FreeImagePlus.h 23 | /usr/include 24 | /usr/local/include 25 | /sw/include 26 | /opt/local/include 27 | DOC "The directory where FreeImagePlus.h resides") 28 | FIND_LIBRARY( FREEIMAGEPLUS_LIBRARY 29 | NAMES FreeImagePlus freeimageplus 30 | PATHS 31 | /usr/lib64 32 | /usr/lib 33 | /usr/local/lib64 34 | /usr/local/lib 35 | /sw/lib 36 | /opt/local/lib 37 | DOC "The FreeImage library") 38 | ENDIF (WIN32) 39 | 40 | SET(FREEIMAGEPLUS_LIBRARIES ${FREEIMAGEPLUS_LIBRARY}) 41 | 42 | IF (FREEIMAGEPLUS_INCLUDE_PATH AND FREEIMAGEPLUS_LIBRARY) 43 | SET( FREEIMAGEPLUS_FOUND TRUE CACHE BOOL "Set to TRUE if FreeImagePlus is found, FALSE otherwise") 44 | ELSE (FREEIMAGEPLUS_INCLUDE_PATH AND FREEIMAGEPLUS_LIBRARY) 45 | SET( FREEIMAGEPLUS_FOUND FALSE CACHE BOOL "Set to TRUE if FreeImagePlus is found, FALSE otherwise") 46 | ENDIF (FREEIMAGEPLUS_INCLUDE_PATH AND FREEIMAGEPLUS_LIBRARY) 47 | 48 | MARK_AS_ADVANCED( 49 | FREEIMAGEPLUS_FOUND 50 | FREEIMAGEPLUS_LIBRARY 51 | FREEIMAGEPLUS_LIBRARIES 52 | FREEIMAGEPLUS_INCLUDE_PATH) 53 | 54 | IF (FREEIMAGEPLUS_FOUND) 55 | MESSAGE(STATUS "FREEIMAGEPLUS_INCLUDE_PATH = ${FREEIMAGEPLUS_INCLUDE_PATH}") 56 | MESSAGE(STATUS "FREEIMAGEPLUS_LIBRARY = ${FREEIMAGEPLUS_LIBRARY}") 57 | ELSE (FREEIMAGEPLUS_FOUND) 58 | IF (FreeImagePlus_FIND_REQUIRED) 59 | MESSAGE(FATAL_ERROR "Could not find FreeImagePlus") 60 | ENDIF (FreeImagePlus_FIND_REQUIRED) 61 | ENDIF (FREEIMAGEPLUS_FOUND) 62 | -------------------------------------------------------------------------------- /cmake_modules/FindPyQt5.cmake: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 2014 WUSTL ZPLAB 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 | # 23 | # Authors: Erik Hvatum 24 | 25 | # Do find_package(PythonInterp) or otherwise set PYTHON_EXECUTABLE before using this module. 26 | # Do find_package(SIP) or otherwise set SIP_DEFAULT_SIP_DIR before using this module. 27 | # 28 | # This module may do more in the future if I need it to, such as setting PYQT5_PYUIC5. However, right now, it just sets 29 | # the following variables: 30 | # 31 | # PYQT5_FOUND - System has PyQt5. 32 | # 33 | # PYQT5_SIP_FLAGS - Value of PyQt5.QtCore.PYQT_CONFIGURATION['sip_flags'], a string containing the -t and -x flags that 34 | # that were used by sip during the PyQt5 build process (ie, PyQt5's configure.py script called sip 35 | # with these -t and -x parameters while building PyQt5). C++ PyQt5 extensions are advised to use the 36 | # same -t and -x arguments when calling sip. 37 | # 38 | # PYQT5_SIP_DIR - Location of PyQt5 .sip files. Unlike PyQt4, which offers an API for determining this path, PyQt5 39 | # does... not........... So, we check the default sip includes directory, and if we don't find our 40 | # PyQt5 .sip files, we fail and the user must specify PYQT5_SIP_DIR. 41 | 42 | set(PYQT5_FOUND false) 43 | execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import PyQt5.QtCore;print(PyQt5.QtCore.PYQT_CONFIGURATION['sip_flags'])" 44 | RESULT_VARIABLE _PYQT5_SIP_FLAGS_RETRIEVED 45 | ERROR_VARIABLE _PYQT5_SIP_FLAGS_ERROR 46 | OUTPUT_VARIABLE PYQT5_SIP_FLAGS 47 | OUTPUT_STRIP_TRAILING_WHITESPACE) 48 | if(NOT _PYQT5_SIP_FLAGS_RETRIEVED MATCHES 0) 49 | if(PyQt5_FIND_REQUIRED) 50 | message(FATAL_ERROR "Failed to import PyQt5 (which must be done in order to determine the proper -x and -t sip arguments for this system):\n${_PYQT5_SIP_FLAGS_ERROR}") 51 | endif() 52 | else() 53 | unset(_PYQT5_SIP_FLAGS_RETRIEVED) 54 | unset(_PYQT5_SIP_FLAGS_ERROR) 55 | set(_PYQT5_SIP_FLAGS ${PYQT5_SIP_FLAGS}) 56 | separate_arguments(PYQT5_SIP_FLAGS) 57 | if(NOT PYQT5_SIP_DIR) # Only attempt to guess value if not specified by user 58 | if(NOT SIP_DEFAULT_SIP_DIR) 59 | if(PyQt5_FIND_REQUIRED}) 60 | message(FATAL_ERROR "Neither PYQT5_SIP_DIR nor SIP_DEFAULT_SIP_DIR are set. It is necessary to either, a) call find_package(SIP), or b) set(SIP_DEFAULT_SIP_DIR ...) or call cmake with -DSIP_DEFAULT_DIR=..., or c) set(PYQT5_SIP_DIR ...) or call cmake with -DPYQT5_SIP_DIR=... before attempting to find_package(PyQt5).") 61 | endif() 62 | else() 63 | set(PYQT5_SIP_DIR "${SIP_DEFAULT_SIP_DIR}/PyQt5") 64 | if(EXISTS "${PYQT5_SIP_DIR}/QtCore/QtCoremod.sip") # Any functional PyQt5 installation includes QtCoreMod.sip 65 | set(PYQT5_FOUND true) 66 | else() 67 | if(APPLE) 68 | execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "from distutils import sysconfig;print(sysconfig.PREFIX)" 69 | RESULT_VARIABLE _TRY_DIR_RETRIEVED 70 | ERROR_VARIABLE _TRY_DIR_ERROR 71 | OUTPUT_VARIABLE _TRY_DIR 72 | OUTPUT_STRIP_TRAILING_WHITESPACE) 73 | if(NOT _TRY_DIR_RETRIEVED MATCHES 0) 74 | messge(FATAL_ERROR "Failed to query python prefix:\n${_TRY_DIR_ERROR}") 75 | else() 76 | set(_TRY_DIR "${_TRY_DIR}/share/sip/PyQt5") 77 | message(WARNING "Guessed value for PYQT5_SIP_DIR, \"${PYQT5_SIP_DIR}\", does not seem to be correct. Trying \"${_TRY_DIR}\".") 78 | set(PYQT5_SIP_DIR ${_TRY_DIR}) 79 | if(EXISTS "${PYQT5_SIP_DIR}/QtCore/QtCoremod.sip") 80 | set(PYQT5_FOUND true) 81 | endif() 82 | unset(_TRY_DIR_RETRIEVED) 83 | unset(_TRY_DIR_ERROR) 84 | unset(_TRY_DIR) 85 | endif() 86 | endif() 87 | endif() 88 | if(NOT PYQT5_FOUND AND PyQt5_FIND_REQUIRED) 89 | if(APPLE) 90 | message(FATAL_ERROR "Could not determine correct value for PYQT5_SIP_DIR. Please specify a value for PYQT5_SIP_DIR (for example, by calling cmake with -DPYQT5_SIP_DIR=foo/bar).") 91 | else() 92 | message(FATAL_ERROR "Guessed value for PYQT5_SIP_DIR, \"${PYQT5_SIP_DIR}\", does not seem to be correct. Please specify a value for PYQT5_SIP_DIR (for example, by calling cmake with -DPYQT5_SIP_DIR=foo/bar).") 93 | endif() 94 | endif() 95 | endif() 96 | else() 97 | if(NOT EXISTS "${PYQT5_SIP_DIR}/QtCore/QtCoremod.sip") 98 | if(PyQt5_FIND_REQUIRED) 99 | message(FATAL_ERROR "Specified or cached value for PYQT5_SIP_DIR, \"${PYQT5_SIP_DIR}\", does not seem to be correct.") 100 | endif() 101 | else() 102 | set(PYQT5_FOUND true) 103 | endif() 104 | endif() 105 | endif() 106 | 107 | if(PYQT5_FOUND) 108 | message(STATUS "Found PyQt5:") 109 | message(STATUS " PyQt5 sip flags: ${_PYQT5_SIP_FLAGS}") 110 | message(STATUS " PyQt5 .sip file directory: ${PYQT5_SIP_DIR}") 111 | endif() 112 | 113 | mark_as_advanced(PYQT5_FOUND PYQT5_SIP_FLAGS PYQT5_SIP_DIR) 114 | unset(_PYQT5_SIP_FLAGS) -------------------------------------------------------------------------------- /cmake_modules/FindSIP.cmake: -------------------------------------------------------------------------------- 1 | # Find SIP 2 | # ~~~~~~~~ 3 | # 4 | # SIP website: http://www.riverbankcomputing.co.uk/sip/index.php 5 | # 6 | # Find the installed version of SIP. FindSIP should be called after Python 7 | # has been found. 8 | # 9 | # This file defines the following variables: 10 | # 11 | # SIP_VERSION - The version of SIP found expressed as a 6 digit hex number 12 | # suitable for comparison as a string. 13 | # 14 | # SIP_VERSION_STR - The version of SIP found as a human readable string. 15 | # 16 | # SIP_EXECUTABLE - Path and filename of the SIP command line executable. 17 | # 18 | # SIP_INCLUDE_DIR - Directory holding the SIP C++ header file. 19 | # 20 | # SIP_DEFAULT_SIP_DIR - Default directory where .sip files should be installed 21 | # into. 22 | 23 | # Copyright (c) 2007, Simon Edwards 24 | # Redistribution and use is allowed according to the terms of the BSD license. 25 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 26 | 27 | 28 | 29 | IF(SIP_VERSION) 30 | # Already in cache, be silent 31 | SET(SIP_FOUND TRUE) 32 | ELSE(SIP_VERSION) 33 | 34 | FIND_FILE(_find_sip_py FindSIP.py PATHS ${CMAKE_MODULE_PATH}) 35 | 36 | EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} ${_find_sip_py} OUTPUT_VARIABLE sip_config) 37 | IF(sip_config) 38 | STRING(REGEX REPLACE "^sip_version:([^\n]+).*$" "\\1" SIP_VERSION ${sip_config}) 39 | STRING(REGEX REPLACE ".*\nsip_version_str:([^\n]+).*$" "\\1" SIP_VERSION_STR ${sip_config}) 40 | STRING(REGEX REPLACE ".*\nsip_bin:([^\n]+).*$" "\\1" SIP_EXECUTABLE ${sip_config}) 41 | IF(NOT SIP_DEFAULT_SIP_DIR) 42 | STRING(REGEX REPLACE ".*\ndefault_sip_dir:([^\n]+).*$" "\\1" SIP_DEFAULT_SIP_DIR ${sip_config}) 43 | ENDIF(NOT SIP_DEFAULT_SIP_DIR) 44 | STRING(REGEX REPLACE ".*\nsip_inc_dir:([^\n]+).*$" "\\1" SIP_INCLUDE_DIR ${sip_config}) 45 | FILE(TO_CMAKE_PATH ${SIP_DEFAULT_SIP_DIR} SIP_DEFAULT_SIP_DIR) 46 | FILE(TO_CMAKE_PATH ${SIP_INCLUDE_DIR} SIP_INCLUDE_DIR) 47 | IF(EXISTS ${SIP_EXECUTABLE}) 48 | SET(SIP_FOUND TRUE) 49 | ELSE() 50 | MESSAGE(STATUS "Found SIP configuration but the sip executable could not be found.") 51 | ENDIF() 52 | ENDIF(sip_config) 53 | 54 | IF(SIP_FOUND) 55 | IF(NOT SIP_FIND_QUIETLY) 56 | MESSAGE(STATUS "Found SIP version: ${SIP_VERSION_STR}") 57 | ENDIF(NOT SIP_FIND_QUIETLY) 58 | ELSE(SIP_FOUND) 59 | IF(SIP_FIND_REQUIRED) 60 | MESSAGE(FATAL_ERROR "Could not find SIP") 61 | ENDIF(SIP_FIND_REQUIRED) 62 | ENDIF(SIP_FOUND) 63 | 64 | ENDIF(SIP_VERSION) 65 | -------------------------------------------------------------------------------- /cmake_modules/FindSIP.py: -------------------------------------------------------------------------------- 1 | # FindSIP.py 2 | # 3 | # Copyright (c) 2007, Simon Edwards 4 | # Redistribution and use is allowed according to the terms of the BSD license. 5 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 6 | 7 | import sys 8 | import sipconfig 9 | 10 | sipcfg = sipconfig.Configuration() 11 | print("sip_version:%06.0x" % sipcfg.sip_version) 12 | print("sip_version_str:%s" % sipcfg.sip_version_str) 13 | print("sip_bin:%s" % sipcfg.sip_bin) 14 | print("default_sip_dir:%s" % sipcfg.default_sip_dir) 15 | print("sip_inc_dir:%s" % sipcfg.sip_inc_dir) 16 | -------------------------------------------------------------------------------- /cmake_modules/SIPMacros.cmake: -------------------------------------------------------------------------------- 1 | # Macros for SIP 2 | # ~~~~~~~~~~~~~~ 3 | # Copyright (c) 2007, Simon Edwards 4 | # Redistribution and use is allowed according to the terms of the BSD license. 5 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 6 | # 7 | # SIP website: http://www.riverbankcomputing.co.uk/sip/index.php 8 | # 9 | # This file defines the following macros: 10 | # 11 | # ADD_SIP_PYTHON_MODULE (MODULE_NAME MODULE_SIP [library1, libaray2, ...]) 12 | # Specifies a SIP file to be built into a Python module and installed. 13 | # MODULE_NAME is the name of Python module including any path name. (e.g. 14 | # os.sys, Foo.bar etc). MODULE_SIP the path and filename of the .sip file 15 | # to process and compile. libraryN are libraries that the Python module, 16 | # which is typically a shared library, should be linked to. The built 17 | # module will also be install into Python's site-packages directory. 18 | # 19 | # The behaviour of the ADD_SIP_PYTHON_MODULE macro can be controlled by a 20 | # number of variables: 21 | # 22 | # SIP_INCLUDES - List of directories which SIP will scan through when looking 23 | # for included .sip files. (Corresponds to the -I option for SIP.) 24 | # 25 | # SIP_TAGS - List of tags to define when running SIP. (Corresponds to the -t 26 | # option for SIP.) 27 | # 28 | # SIP_CONCAT_PARTS - An integer which defines the number of parts the C++ code 29 | # of each module should be split into. Defaults to 8. (Corresponds to the 30 | # -j option for SIP.) 31 | # 32 | # SIP_DISABLE_FEATURES - List of feature names which should be disabled 33 | # running SIP. (Corresponds to the -x option for SIP.) 34 | # 35 | # SIP_EXTRA_OPTIONS - Extra command line options which should be passed on to 36 | # SIP. 37 | 38 | SET(SIP_INCLUDES) 39 | SET(SIP_TAGS) 40 | SET(SIP_CONCAT_PARTS 8) 41 | SET(SIP_DISABLE_FEATURES) 42 | SET(SIP_EXTRA_OPTIONS) 43 | 44 | MACRO(ADD_SIP_PYTHON_MODULE MODULE_NAME MODULE_SIP) 45 | 46 | SET(EXTRA_LINK_LIBRARIES ${ARGN}) 47 | 48 | STRING(REPLACE "." "/" _x ${MODULE_NAME}) 49 | GET_FILENAME_COMPONENT(_parent_module_path ${_x} PATH) 50 | GET_FILENAME_COMPONENT(_child_module_name ${_x} NAME) 51 | 52 | GET_FILENAME_COMPONENT(_module_path ${MODULE_SIP} PATH) 53 | 54 | if(_module_path STREQUAL "") 55 | set(CMAKE_CURRENT_SIP_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}") 56 | else(_module_path STREQUAL "") 57 | set(CMAKE_CURRENT_SIP_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/${_module_path}") 58 | endif(_module_path STREQUAL "") 59 | 60 | GET_FILENAME_COMPONENT(_abs_module_sip ${MODULE_SIP} ABSOLUTE) 61 | 62 | # We give this target a long logical target name. 63 | # (This is to avoid having the library name clash with any already 64 | # install library names. If that happens then cmake dependancy 65 | # tracking get confused.) 66 | STRING(REPLACE "." "_" _logical_name ${MODULE_NAME}) 67 | SET(_logical_name "python_module_${_logical_name}") 68 | 69 | FILE(MAKE_DIRECTORY ${CMAKE_CURRENT_SIP_OUTPUT_DIR}) # Output goes in this dir. 70 | 71 | SET(_sip_includes) 72 | FOREACH (_inc ${SIP_INCLUDES}) 73 | GET_FILENAME_COMPONENT(_abs_inc ${_inc} ABSOLUTE) 74 | LIST(APPEND _sip_includes -I ${_abs_inc}) 75 | ENDFOREACH (_inc ) 76 | 77 | SET(_sip_tags) 78 | FOREACH (_tag ${SIP_TAGS}) 79 | LIST(APPEND _sip_tags -t ${_tag}) 80 | ENDFOREACH (_tag) 81 | 82 | SET(_sip_x) 83 | FOREACH (_x ${SIP_DISABLE_FEATURES}) 84 | LIST(APPEND _sip_x -x ${_x}) 85 | ENDFOREACH (_x ${SIP_DISABLE_FEATURES}) 86 | 87 | SET(_message "-DMESSAGE=Generating CPP code for module ${MODULE_NAME}") 88 | SET(_sip_output_files) 89 | FOREACH(CONCAT_NUM RANGE 0 ${SIP_CONCAT_PARTS} ) 90 | IF( ${CONCAT_NUM} LESS ${SIP_CONCAT_PARTS} ) 91 | SET(_sip_output_files ${_sip_output_files} ${CMAKE_CURRENT_SIP_OUTPUT_DIR}/sip${_child_module_name}part${CONCAT_NUM}.cpp ) 92 | ENDIF( ${CONCAT_NUM} LESS ${SIP_CONCAT_PARTS} ) 93 | ENDFOREACH(CONCAT_NUM RANGE 0 ${SIP_CONCAT_PARTS} ) 94 | 95 | IF(NOT WIN32) 96 | SET(TOUCH_COMMAND touch) 97 | ELSE(NOT WIN32) 98 | SET(TOUCH_COMMAND echo) 99 | # instead of a touch command, give out the name and append to the files 100 | # this is basically what the touch command does. 101 | FOREACH(filename ${_sip_output_files}) 102 | FILE(APPEND filename "") 103 | ENDFOREACH(filename ${_sip_output_files}) 104 | ENDIF(NOT WIN32) 105 | ADD_CUSTOM_COMMAND( 106 | OUTPUT ${_sip_output_files} 107 | COMMAND ${CMAKE_COMMAND} -E echo ${message} 108 | COMMAND ${TOUCH_COMMAND} ${_sip_output_files} 109 | COMMAND ${SIP_EXECUTABLE} ${_sip_tags} ${_sip_x} ${SIP_EXTRA_OPTIONS} -j ${SIP_CONCAT_PARTS} -c ${CMAKE_CURRENT_SIP_OUTPUT_DIR} ${_sip_includes} ${_abs_module_sip} 110 | DEPENDS ${_abs_module_sip} ${SIP_EXTRA_FILES_DEPEND} 111 | ) 112 | # not sure if type MODULE could be uses anywhere, limit to cygwin for now 113 | IF (CYGWIN) 114 | ADD_LIBRARY(${_logical_name} MODULE ${_sip_output_files} ) 115 | ELSE (CYGWIN) 116 | ADD_LIBRARY(${_logical_name} SHARED ${_sip_output_files} ) 117 | ENDIF (CYGWIN) 118 | TARGET_LINK_LIBRARIES(${_logical_name} ${PYTHON_LIBRARY}) 119 | TARGET_LINK_LIBRARIES(${_logical_name} ${EXTRA_LINK_LIBRARIES}) 120 | SET_TARGET_PROPERTIES(${_logical_name} PROPERTIES PREFIX "" OUTPUT_NAME ${_child_module_name}) 121 | 122 | INSTALL(TARGETS ${_logical_name} DESTINATION "${PYTHON_SITE_PACKAGES_INSTALL_DIR}/${_parent_module_path}") 123 | 124 | ENDMACRO(ADD_SIP_PYTHON_MODULE) 125 | -------------------------------------------------------------------------------- /devtest/PyQmlProof/ImagePane.qml: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2016 Erik Hvatum 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 | // 23 | // Authors: Erik Hvatum 24 | 25 | import QtQuick 2.5 26 | import QtQuick.Controls 1.4 27 | import QtQuick.Layouts 1.2 28 | 29 | Item { 30 | id: imageContainer 31 | Layout.fillWidth: true 32 | clip: true 33 | 34 | DropArea { 35 | anchors.fill: parent 36 | onEntered: { 37 | // console.log('drop area entered'); 38 | drag.accept(Qt.CopyAction); 39 | } 40 | onDropped: { 41 | image.source = drop.urls[0] 42 | } 43 | // onExited: { 44 | // console.log('drop area exited'); 45 | // } 46 | } 47 | 48 | TiledBackground {} 49 | 50 | Image { 51 | id: image 52 | anchors.top: parent.top 53 | anchors.bottom: parent.bottom 54 | anchors.horizontalCenter: imageContainer.horizontalCenter 55 | property real scaleRel: sourceSize.height / height 56 | width: (sourceSize.width / sourceSize.height) * height 57 | 58 | Repeater { 59 | id: controlPointRepeater 60 | model: pointListModel 61 | delegate: Rectangle { 62 | id: rect 63 | x: x_ / image.scaleRel 64 | y: y_ / image.scaleRel 65 | z: 2 66 | width: 11 67 | height: 11 68 | color: activeFocus ? "red" : "yellow" 69 | Drag.active: dragArea.drag.active 70 | Keys.onDeletePressed: pointListModel.delAtIndex(index) 71 | onXChanged: x_ = x * image.scaleRel 72 | onYChanged: y_ = y * image.scaleRel 73 | 74 | MouseArea { 75 | id: dragArea 76 | anchors.fill: parent 77 | drag.target: parent 78 | onPressed: parent.focus = true 79 | drag.threshold: 0 80 | } 81 | 82 | transform: Translate { 83 | x: -5 84 | y: -5 85 | } 86 | } 87 | } 88 | 89 | Canvas { 90 | anchors.fill: parent 91 | // renderStrategy: Canvas.Threaded 92 | // renderTarget: Canvas.FramebufferObject 93 | antialiasing: true 94 | smooth: true 95 | Component.onCompleted: { 96 | pointListModel.dataChanged.connect(requestPaint) 97 | pointListModel.rowsInserted.connect(requestPaint) 98 | pointListModel.rowsRemoved.connect(requestPaint) 99 | pointListModel.modelReset.connect(requestPaint) 100 | pointListModel.rowsMoved.connect(requestPaint) 101 | } 102 | onPaint: { 103 | var rowCount = pointListModel.rowCount() 104 | if(rowCount >= 2) { 105 | var ctx = getContext("2d") 106 | ctx.reset() 107 | ctx.strokeStyle = Qt.rgba(0,1,0,1) 108 | ctx.lineWidth = 2 109 | ctx.beginPath() 110 | var p = pointListModel.data(pointListModel.index(0, 0), 0) 111 | ctx.moveTo(p.x_/image.scaleRel, p.y_/image.scaleRel) 112 | var idx_=1 113 | for(; idx_ < rowCount; idx_++) { 114 | p = pointListModel.data(pointListModel.index(idx_, 0), 0) 115 | ctx.lineTo(p.x_/image.scaleRel, p.y_/image.scaleRel) 116 | } 117 | ctx.stroke() 118 | } 119 | } 120 | } 121 | 122 | MouseArea { 123 | anchors.fill: parent 124 | onClicked: { 125 | pointListModel.append(mouseX * image.scaleRel, mouseY * image.scaleRel) 126 | } 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /devtest/PyQmlProof/PointTablePane.qml: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2016 Erik Hvatum 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 | // 23 | // Authors: Erik Hvatum 24 | 25 | import QtQuick 2.5 26 | import QtQuick.Controls 1.4 27 | import QtQuick.Layouts 1.2 28 | 29 | GroupBox { 30 | id: pointsGroupBox 31 | title: "Points" 32 | Layout.minimumWidth: 1 33 | Layout.margins: 5 34 | width: 400 35 | clip: true 36 | 37 | Column { 38 | id: "column" 39 | anchors.fill: parent 40 | z: 1 41 | 42 | TableView { 43 | id: tableView 44 | anchors.margins: 5 45 | anchors.left: parent.left 46 | anchors.right: parent.right 47 | model: pointListModel 48 | selectionMode: SelectionMode.ExtendedSelection 49 | activeFocusOnTab: true 50 | 51 | TableViewColumn { 52 | role: "x_" 53 | title: "x" 54 | width: column.width / 2 - 20 55 | movable: false 56 | } 57 | 58 | TableViewColumn { 59 | role: "y_" 60 | title: "y" 61 | width: column.width / 2 - 20 62 | movable: false 63 | } 64 | 65 | // Keys.onPressed: { 66 | // console.log("pressed") 67 | // tableView.selection.forEach(function(row){console.log(row)}) 68 | // } 69 | 70 | // onFocusChanged: { 71 | // console.log(focus) 72 | // } 73 | 74 | // onClicked: { 75 | // console.log("clicked") 76 | // parent.parent.forceActiveFocus() 77 | // parent.parent.focus = true 78 | // } 79 | } 80 | 81 | Repeater { 82 | id: spinBoxRepeater 83 | model: pointListModel 84 | delegate: Row { 85 | spacing: 5 86 | 87 | Label { 88 | text: index.toString() 89 | } 90 | 91 | SpinBox { 92 | id: xSpinBox 93 | minimumValue: -999999 94 | maximumValue: 999999 95 | decimals: 5 96 | value: x_ 97 | onValueChanged: { 98 | if(Math.abs(x_ - value) > 0.00001) x_ = value 99 | } 100 | } 101 | 102 | SpinBox { 103 | id: ySpinBox 104 | minimumValue: -999999 105 | maximumValue: 999999 106 | decimals: 5 107 | value: y_ 108 | onValueChanged: { 109 | if(Math.abs(y_ - value) > 0.00001) y_ = value 110 | } 111 | } 112 | 113 | Button { 114 | id: delButton 115 | text: 'X' 116 | onClicked: { 117 | pointListModel.delAtIndex(index) 118 | } 119 | } 120 | } 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /devtest/PyQmlProof/PyQmlProof.pro: -------------------------------------------------------------------------------- 1 | DISTFILES += \ 2 | list_role_model.py \ 3 | PyQmlProof.py \ 4 | PyQmlProof.qml \ 5 | SplinePoint.qml \ 6 | ImagePane.qml \ 7 | PointTablePane.qml \ 8 | TiledBackground.qml 9 | -------------------------------------------------------------------------------- /devtest/PyQmlProof/PyQmlProof.py: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 2016 Erik Hvatum 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 | # 23 | # Authors: Erik Hvatum 24 | 25 | from pathlib import Path 26 | from PyQt5 import Qt 27 | import sys 28 | from ris_widget import om 29 | from list_role_model import ListRoleModel 30 | 31 | class OutlinePoint(Qt.QObject): 32 | x_Changed = Qt.pyqtSignal(float) 33 | y_Changed = Qt.pyqtSignal(float) 34 | 35 | def __init__(self, x=0, y=0, parent=None): 36 | super().__init__(parent) 37 | self._x = float(x) 38 | self._y = float(y) 39 | 40 | def __repr__(self): 41 | return 'OutlinePoint({}, {})'.format(self._x, self._y) 42 | 43 | def getX_(self): 44 | return self._x 45 | 46 | def setX_(self, x): 47 | x = float(x) 48 | if abs(x - self._x) > 0.00001: 49 | self._x = x 50 | self.x_Changed.emit(x) 51 | 52 | x_ = Qt.pyqtProperty(float, fget=getX_, fset=setX_, notify=x_Changed) 53 | 54 | def getY_(self): 55 | return self._y 56 | 57 | def setY_(self, y): 58 | if abs(y - self._y) > 0.00001: 59 | self._y = y 60 | self.y_Changed.emit(y) 61 | 62 | y_ = Qt.pyqtProperty(float, fget=getY_, fset=setY_, notify=y_Changed) 63 | 64 | class OutlinePointList(om.UniformSignalingList): 65 | def take_input_element(self, obj): 66 | if isinstance(obj, OutlinePoint): 67 | return obj 68 | elif isinstance(obj, (Qt.QPointF, Qt.QPoint)): 69 | return OutlinePoint(obj.x(), obj.y()) 70 | else: 71 | i = iter(obj) 72 | return OutlinePoint(next(i), next(i)) 73 | 74 | class PointListModel(ListRoleModel): 75 | @Qt.pyqtSlot(float, float) 76 | def append(self, x, y): 77 | self.signaling_list.append(OutlinePoint(x, y)) 78 | 79 | @Qt.pyqtSlot(int) 80 | def delAtIndex(self, idx): 81 | del self.signaling_list[idx] 82 | 83 | _QML_TYPES_REGISTERED = False 84 | 85 | class PickerWidget(Qt.QQuickWidget): 86 | def __init__(self, parent=None): 87 | super().__init__(parent) 88 | global _QML_TYPES_REGISTERED 89 | if not _QML_TYPES_REGISTERED: 90 | Qt.qmlRegisterType(OutlinePoint) 91 | Qt.qmlRegisterType(ListRoleModel) 92 | _QML_TYPES_REGISTERED = True 93 | self.setResizeMode(Qt.QQuickWidget.SizeRootObjectToView) 94 | self.point_list = OutlinePointList() 95 | self.point_list_model = PointListModel(('x_', 'y_'), self.point_list) 96 | self.rootContext().setContextProperty("pointListModel", self.point_list_model) 97 | self.setSource(Qt.QUrl(str(Path(__file__).parent / 'PyQmlProof.qml'))) 98 | self.show() 99 | 100 | if __name__ == "__main__": 101 | app = Qt.QApplication(sys.argv) 102 | picker_widget = PickerWidget() 103 | app.exec_() 104 | -------------------------------------------------------------------------------- /devtest/PyQmlProof/PyQmlProof.qml: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2016 Erik Hvatum 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 | // 23 | // Authors: Erik Hvatum 24 | 25 | import QtQuick 2.5 26 | import QtQuick.Controls 1.4 27 | import QtQuick.Layouts 1.2 28 | 29 | Rectangle { 30 | id: containerRect 31 | implicitWidth: 1024 32 | implicitHeight: 768 33 | 34 | SplitView { 35 | id: splitView 36 | anchors.fill: parent 37 | orientation: Qt.Horizontal 38 | 39 | PointTablePane {} 40 | ImagePane {} 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /devtest/PyQmlProof/TiledBackground.qml: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2016 Erik Hvatum 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 | // 23 | // Authors: Erik Hvatum 24 | 25 | import QtQuick 2.5 26 | 27 | ShaderEffect { 28 | anchors.fill: parent 29 | // layer.enabled: true 30 | 31 | property real tileSize: 16 32 | property color color1: Qt.rgba(0.9, 0.9, 0.9, 1); 33 | property color color2: Qt.rgba(0.85, 0.85, 0.85, 1); 34 | 35 | property size pixelSize: Qt.size(width / tileSize, height / tileSize); 36 | 37 | fragmentShader: 38 | " 39 | uniform lowp vec4 color1; 40 | uniform lowp vec4 color2; 41 | uniform highp vec2 pixelSize; 42 | varying highp vec2 qt_TexCoord0; 43 | void main() { 44 | highp vec2 tc = sign(sin(3.14152 * qt_TexCoord0 * pixelSize)); 45 | if (tc.x != tc.y) 46 | gl_FragColor = color1; 47 | else 48 | gl_FragColor = color2; 49 | } 50 | " 51 | } 52 | -------------------------------------------------------------------------------- /source/Application/Application.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /source/Application/main.cpp: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2016 Erik Hvatum 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 | // 23 | // Authors: Erik Hvatum 24 | 25 | #include "../common.h" 26 | #include "../SSImageItem.h" 27 | #include 28 | #include 29 | 30 | static QSurfaceFormat fmt; 31 | 32 | static void onStackStreamWindowCreated(QObject* object, const QUrl&) 33 | { 34 | QQuickWindow* stackStreamMainWindow{qobject_cast(object)}; 35 | if(stackStreamMainWindow && stackStreamMainWindow->objectName() == "stackStreamMainWindow") 36 | { 37 | stackStreamMainWindow->setFormat(fmt); 38 | stackStreamMainWindow->show(); 39 | } 40 | } 41 | 42 | int main(int argc, char *argv[]) 43 | { 44 | setenv("QMLSCENE_DEVICE", "SSGContextPlugin", 1); 45 | QApplication app(argc, argv); 46 | { 47 | fmt.setRenderableType(QSurfaceFormat::OpenGL); 48 | fmt.setProfile(QSurfaceFormat::CompatibilityProfile); 49 | fmt.setSwapBehavior(QSurfaceFormat::DoubleBuffer); 50 | fmt.setSwapInterval(1); 51 | fmt.setVersion(4, 5); 52 | #ifdef ENABLE_GL_DEBUG_LOGGING 53 | fmt.setOptions(QSurfaceFormat::DebugContext | QSurfaceFormat::DeprecatedFunctions); 54 | #else 55 | fmt.setOptions(QSurfaceFormat::DeprecatedFunctions); 56 | #endif 57 | fmt.setStencilBufferSize(8); 58 | fmt.setSamples(8); 59 | // We request 30-bit color; if it's not available, Qt automatically falls back to 24-bit 60 | fmt.setRedBufferSize(10); 61 | fmt.setGreenBufferSize(10); 62 | fmt.setBlueBufferSize(10); 63 | // NB: Requesting 2-bit alpha and getting it on Linux leads to crashes 64 | // fmt.setAlphaBufferSize(2); 65 | QSurfaceFormat::setDefaultFormat(fmt); 66 | } 67 | 68 | QQmlApplicationEngine engine; 69 | QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, onStackStreamWindowCreated); 70 | engine.load(QUrl(QStringLiteral("qrc:/StackStreamMainWindow.qml"))); 71 | // MakeImage ssimageFactory; 72 | // engine.rootContext()->setContextProperty("ssimageFactory", &ssimageFactory); 73 | // engine.setObjectOwnership(&ssimageFactory, QQmlEngine::CppOwnership); 74 | 75 | int ret{app.exec()}; 76 | #ifdef ENABLE_GL_DEBUG_LOGGING 77 | if(g_glDebugLogger) 78 | { 79 | delete g_glDebugLogger; 80 | g_glDebugLogger = nullptr; 81 | } 82 | #endif 83 | return ret; 84 | } 85 | 86 | #include "main.moc" 87 | -------------------------------------------------------------------------------- /source/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 2016 Erik Hvatum 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 | # 23 | # Authors: Erik Hvatum 24 | 25 | set(SOURCE_FILES 26 | common.h 27 | GilLocker.cpp 28 | GilLocker.h 29 | qmldir 30 | SSGSimpleTextureNode.cpp 31 | SSGSimpleTextureNode.h 32 | SSGTexture.cpp 33 | SSGTexture.h 34 | SSGTextureMaterial.cpp 35 | SSGTextureMaterial.h 36 | SSImage.cpp 37 | SSImage.h 38 | SSImageItem.cpp 39 | SSImageItem.h 40 | SSQmlPlugin.cpp 41 | SSQmlPlugin.h 42 | SSView.cpp 43 | SSView.h) 44 | set(LIBRARIES 45 | ${OPENGL_LIBRARIES} 46 | ${FREEIMAGE_LIBRARY} 47 | ${FREEIMAGEPLUS_LIBRARY}) 48 | 49 | qt5_add_resources(RESOURCES StackStreamPlugin.qrc) 50 | add_library(StackStreamPlugin SHARED ${SOURCE_FILES} ${RESOURCES}) 51 | qt5_use_modules(StackStreamPlugin Core Gui Qml OpenGL Quick Widgets) 52 | target_link_libraries(StackStreamPlugin ${LIBRARIES}) 53 | set_target_properties(StackStreamPlugin PROPERTIES COMPILE_OPTIONS "-DSTACKSTREAM") 54 | #set_target_properties(StackStreamPlugin PROPERTIES COMPILE_OPTIONS "-DENABLE_GL_DEBUG_LOGGING") 55 | 56 | add_subdirectory(QtQmlTricks) 57 | add_subdirectory(SSGContextPlugin) 58 | add_subdirectory(Application) 59 | if(BUILD_STACKSTREAM_PYTHON_MODULE) 60 | add_subdirectory(PythonModule) 61 | endif() 62 | 63 | -------------------------------------------------------------------------------- /source/GilLocker.cpp: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2016 Erik Hvatum 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 | // 23 | // Authors: Erik Hvatum 24 | 25 | #ifdef WITH_PYTHON 26 | #include "GilLocker.h" 27 | 28 | GilLocker::GilLocker() 29 | : m_PyGILState_STATE(PyGILState_Ensure()) 30 | { 31 | } 32 | 33 | GilLocker::~GilLocker() 34 | { 35 | if(PyGILState_Check() == 0) 36 | qFatal("GilLocker::~GilLocker(): About to release the GIL, but the GIL is not " 37 | "currently held by this thread."); 38 | PyGILState_Release(m_PyGILState_STATE); 39 | } 40 | 41 | GilUnlocker::GilUnlocker() 42 | : m_pyThreadState(PyEval_SaveThread()) 43 | { 44 | if(m_pyThreadState == nullptr) 45 | qFatal("GilUnlocker::GilUnlocker(): PyEval_SaveThread() returned nullptr.") 46 | } 47 | 48 | GilUnlocker::~GilUnlocker() 49 | { 50 | PyEval_RestoreThread(m_pyThreadState); 51 | } 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /source/GilLocker.h: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2016 Erik Hvatum 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 | // 23 | // Authors: Erik Hvatum 24 | 25 | #pragma once 26 | #include "common.h" 27 | 28 | #ifdef WITH_PYTHON 29 | class STACKSTREAM_DLLSPEC GilLocker 30 | { 31 | public: 32 | GilLocker(); 33 | ~GilLocker(); 34 | GilLocker(const GilLocker&) = delete; 35 | GilLocker& operator = (const GilLocker&) = delete; 36 | 37 | private: 38 | PyGILState_STATE m_PyGILState_STATE; 39 | }; 40 | 41 | class STACKSTREAM_DLLSPEC GilUnlocker 42 | { 43 | public: 44 | GilUnlocker(); 45 | ~GilUnlocker(); 46 | GilUnlocker(const GilUnlocker&) = delete; 47 | GilUnlocker& operator = (const GilUnlocker&) = delete; 48 | 49 | private: 50 | PyThreadState* m_pyThreadState; 51 | }; 52 | #endif 53 | -------------------------------------------------------------------------------- /source/PythonModule/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 2016 Erik Hvatum 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 | # 23 | # Authors: Erik Hvatum 24 | -------------------------------------------------------------------------------- /source/QtQmlTricks/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 2016 Erik Hvatum 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 | # 23 | # Authors: Erik Hvatum 24 | 25 | project(QtQmlTricksPlugin) 26 | 27 | set(SOURCE_FILES 28 | # src/qqmlgadgetlistmodel.cpp 29 | # src/qqmlgadgetlistmodel.h 30 | src/qmlplugin.cpp 31 | src/qmlplugin.h 32 | src/qqmlhelpers.cpp 33 | src/qqmlhelpers.h 34 | src/qqmlmodels.h 35 | src/qqmlobjectlistmodel.cpp 36 | src/qqmlobjectlistmodel.h 37 | src/qqmlsvgiconhelper.cpp 38 | src/qqmlsvgiconhelper.h 39 | src/qqmlvariantlistmodel.cpp 40 | src/qqmlvariantlistmodel.h 41 | src/qqmlvariantlistmodel_p.h 42 | src/qquickpolygon.cpp 43 | src/qquickpolygon.h 44 | src/qtbitstream.h 45 | src/qtcobs.h 46 | src/qtjsonpath.h 47 | import/QtQmlTricks/qmldir 48 | include/QQmlGadgetListModel 49 | include/QQmlHelpers 50 | include/QQmlObjectListModel 51 | include/QQmlSvgIconHelper 52 | include/QQmlVariantListModel 53 | include/QQuickPolygon 54 | include/QtBitStream 55 | include/QtCOBS 56 | include/QtJsonPath 57 | include/QtQmlTricks 58 | ) 59 | 60 | unset(RESOURCES) 61 | qt5_add_resources(RESOURCES import/QtQmlTricks/components.qrc) 62 | add_library(QtQmlTricksPlugin SHARED ${SOURCE_FILES} ${RESOURCES}) 63 | qt5_use_modules(QtQmlTricksPlugin Core Gui Qml OpenGL Quick Svg Widgets) 64 | -------------------------------------------------------------------------------- /source/QtQmlTricks/QtQmlTricks.qbs: -------------------------------------------------------------------------------- 1 | import qbs; 2 | import qbs.Process; 3 | 4 | Project { 5 | name: "The Qt QML Tricks"; 6 | references: [ 7 | "src/QtLibrary.qbs", 8 | "import/QtQmlTricks/QmlComponents.qbs", 9 | "examples/IconCache/IconCache.qbs", 10 | "examples/NiceModels/NiceModels.qbs", 11 | "examples/CustomPolygon/CustomPolygon.qbs", 12 | "examples/COBS/QtCOBS.qbs", 13 | "examples/BitStream/QtBitStream.qbs", 14 | "examples/JSONPath/QtJsonPath.qbs", 15 | ]; 16 | 17 | Product { 18 | name: "sdk-utilities"; 19 | 20 | Export { 21 | cpp.includePaths: "./include"; 22 | 23 | Depends { name: "cpp"; } 24 | Depends { 25 | name: "Qt"; 26 | submodules: ["core", "gui", "qml", "quick", "svg"]; 27 | } 28 | Depends { name: "lib-qt-qml-tricks"; } 29 | Depends { name: "qml-js-imports"; } 30 | } 31 | Depends { 32 | name: "Qt"; 33 | submodules: ["qml", "quick"]; 34 | } 35 | Group { 36 | name: "Includes"; 37 | prefix: "include/"; 38 | files: ["Q*"]; 39 | excludeFiles: "*.qbs"; 40 | } 41 | } 42 | Product { 43 | name: "project-utils"; 44 | type: "docs"; 45 | 46 | Group { 47 | name: "Git files"; 48 | files: [ 49 | ".gitignore" 50 | ]; 51 | } 52 | Group { 53 | name: "Doyxgen config"; 54 | prefix: "doc/" 55 | files: ["Doxyfile"]; 56 | fileTags: "doxyconf"; 57 | } 58 | Group { 59 | name: "Schema"; 60 | prefix: "doc/" 61 | files: ["*.svg"]; 62 | } 63 | Group { 64 | name: "Doxygen CSS style"; 65 | prefix: "doc/" 66 | files: ["*.css"]; 67 | fileTags: "style"; 68 | } 69 | Group { 70 | name: "Doxygen C++ inputs"; 71 | prefix: "src/"; 72 | files: ["*.h", "*.cpp"]; 73 | fileTags: "source"; 74 | } 75 | Group { 76 | name: "Doxygen JavaScript & QML inputs"; 77 | prefix: "import/**/"; 78 | files: ["*.qml", "*.js"]; 79 | fileTags: "source"; 80 | } 81 | Group { 82 | name: "MarkDown documents"; 83 | files: ["*.md"]; 84 | fileTags: "markdown"; 85 | } 86 | Rule { 87 | inputs: ["doxyconf", "source", "style", "markdown"]; 88 | multiplex: "true"; 89 | prepare: { 90 | var cmd = new JavaScriptCommand (); 91 | cmd.description = "generating documentation from doxygen config"; 92 | cmd.highlight = "doxygen"; 93 | cmd.sourceCode = function () { 94 | for (var idx = 0; idx < inputs ["doxyconf"].length; idx++) { 95 | var file = inputs ["doxyconf"][idx].filePath; 96 | var proc = new Process (); 97 | proc.setWorkingDirectory (product.sourceDirectory + "/doc"); 98 | proc.exec ("doxygen", [file]); 99 | } 100 | } 101 | return cmd; 102 | } 103 | 104 | Artifact { 105 | fileTags: "docs"; 106 | filePath: "force.doc"; 107 | alwaysUpdated: true; 108 | } 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /source/QtQmlTricks/README.md: -------------------------------------------------------------------------------- 1 | About the project 2 | ================= 3 | 4 | _The **QtQmlTricks** library contains useful classes and macros. It also has some test cases and examples._ 5 | 6 | 7 | ### Why this project ? 8 | All the people out there who have done / are doing a mixed C++ / QML project, have surely been thinking that it needs too much code on C++ side, and that this code is often not that easy to do right. So here is the solution : 9 | 10 | **A nice library of classes and helpers that have been designed to simplify as much as possible the C++ side, so that it's finally not harder than QML side (which is already nice enough).** 11 | 12 | 13 | ### What does it bring at the moment ? 14 | 15 | We have done a very simple library, which brings mainly some C++ **classes** : 16 | 17 | * `QQmlObjectListModel` : a much nicer way to expose C++ list to QML than the quick & dirty `QList` property . Supports all the strong model features of `QAbstractListModel` while showing the simple and well know API of QList. 18 | * `QQmlVariantListModel` : a dead-simple way to create a dynamic C++ list of any type and expose it to QML, way better than using a `QVariantList` property. 19 | * `QQmlSvgIconHelper` : a class that takes a SVG file as input, plus size/ratio information, and makes a PNG file in persistant cache as output. If additional color information other than transparent is provided, the opaque pixels of the output will be colorized with the given tint. 20 | * `QQuickPolygon` : a simple QtQuick item that takes a list of points and draw them with a provided color. 21 | * `QtCOBS` : a codec to create COBS-encoded QByteArray from raw data, and vice-versa. 22 | * `QtBitStream` : a helper class to extract or inject custom amount of bits (between 1 and 64) in a `QByteArray` using a position cursor like `QDataStream` does for bytes... 23 | * `QtJsonPath` : a nice way to retreive specific sub-values from a QJson*** class as a QVariant, by simply asking it by path. 24 | 25 | It also strouts a pack of helper C++ **macros** : 26 | 27 | * `QML_WRITABLE_PROPERTY` : a macro that takes a type and a name, and creates automatically the member attribute, the public getter and setter, and the Qt signal for notifier, and allow use in QML by exposing a read/write `Q_PROPERTY`. 28 | * `QML_READONLY_PROPERTY` : another macro that does almost the same as `QML_WRITABLE_PROPERTY` except that the property is not modifiable from the QML side, only C++ can access the setter. 29 | * `QML_CONSTANT_PROPERTY` : a simplified version of the previous macros, that exposes a constant property with no getter and no setter, from C++ or QML side. 30 | * `QML_LIST_PROPERTY` : a really handy macro to create a QML list property that maps to an internal `QList` of objects, without having to declare and implement all static function pointers... 31 | * `QML_ENUM_CLASS` : a macro to declare a `QObject` class that only contains a `Q_ENUM` and can be exposed as is to QML. 32 | 33 | A nice set of JavaScript prototype modifications : 34 | 35 | * `String` and `Array` classes extended to have API closer to `QString`/`QByteArray` and `QList`/`QVector` : addition of `startsWith`, `contains`, `at`, `size`, `append`, `prepend`, `insert`, `isEmpty`, ... 36 | 37 | And a bunch of QML components : 38 | 39 | * `RowContainer` : an horizontal layout, that positions its childrens side-by-side, setting their size in consequence of their implicit size hints, and using remaining space in the layout to distribute it between all items that expose a negative implicit width. 40 | * `GridContainer` : a smart grid that dimensions itself according to the sum/max of its children's implicit size hints, and then distributes regularly the available space between all children, positioned against a col/row model. 41 | * `WrapLeftRightContainer` : a simplified layout for one of the most common positioning scheme in UI, on the same line, put some items at left, the others at right. But it has extra intelligency, to wrap itslef it left/right items do not fit in the provided space. 42 | * `ScrollContainer` : put a `Flickable` (or derived, e.g. `ListView`) in it to get vertical/horizontal scrollbars displayed around it (according to the flicking direction axis that are set). 43 | * `IconTextButton` : a simple and customizable push button that can have either an icon, a label, or both. Colors, sizes, fonts and rounding are customizable. 44 | 45 | **Note :** All these API are documented using _Doxygen_ so that one can easily generate HTML documentation or even Qt Help file (.qch). 46 | 47 | 48 | ### What are the plans for later ? 49 | 50 | First we want to add a lot of new classes and helpers for common use. 51 | 52 | Next, add more helpers and components for QML / JavaScript side too. 53 | 54 | And maybe then, propose this for integration into standard Qt module QtCore, if it's really useful to people ! 55 | 56 | ### How can I use it ? 57 | 58 | Well, license here is pretty "super-open", not even copy-left or copy-right, just use it as you want, as it's the most practical to you : 59 | 60 | * if you want to use it as GIT submodule and compile it in your app, do it ; 61 | * if you prefer separate project as a shared library, do it ; 62 | * if you need to modify the project to be able to integrate in you app (opensource or not), do it ; 63 | * if you want to share you work on the library, thanks a lot, but if you don't, no problem ; 64 | * if you think about some weird case I didn't talk about, well, do whatever you want, I don't need to know about it. 65 | 66 | **Enjoy !** -------------------------------------------------------------------------------- /source/QtQmlTricks/examples/BitStream/QtBitStream.qbs: -------------------------------------------------------------------------------- 1 | import qbs; 2 | 3 | Application { 4 | name: "example-bitstream"; 5 | targetName: "QtBitStream"; 6 | 7 | Depends { name: "Qt"; } 8 | Depends { name: "cpp"; } 9 | Depends { name: "sdk-utilities"; } 10 | Group { 11 | name: "C++ sources"; 12 | files: ["*.cpp"]; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /source/QtQmlTricks/examples/BitStream/main_bitstream.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | int main (int argc, char * argv []) { 8 | Q_UNUSED (argc) 9 | Q_UNUSED (argv) 10 | 11 | const unsigned char data [] = { 0x35, 0x02 , 0x26, 0x7F, 0x65, 0x4F, 0xAB, 0x03, 0x85, 0x7B }; 12 | const unsigned int size = (sizeof (data) / sizeof (data [0])); 13 | 14 | QtBitStream streamOut (QByteArray::fromRawData ((const char *) data, size)); 15 | 16 | qDebug () << "streamOut=" << streamOut.toBinary (); 17 | 18 | bool ok = false; 19 | 20 | for (int bit = 0; bit < 8; bit++) { 21 | qDebug () << "bit as bool :" << streamOut.getPosition () << streamOut.readBits (1, &ok); 22 | } 23 | qDebug () << "bits 8-24 in quint16 :" << streamOut.getPosition () << streamOut.readBits (16); 24 | 25 | QtBitStream streamIn (QByteArray (4, 0x00)); 26 | quint8 test1 = 0x7; 27 | streamIn.writeBits (test1, 3, &ok); 28 | qDebug () << "streamIn after test1=" << streamIn.toBinary () << ok; 29 | qreal test2 = 0x7; 30 | streamIn.writeBits (test2, 5, &ok); 31 | qDebug () << "streamIn after test2=" << streamIn.toBinary () << ok; 32 | QByteArray test3 = "toto"; 33 | streamIn.writeBits (test3, 23, &ok); 34 | qDebug () << "streamIn after test3=" << streamIn.toBinary () << ok; 35 | streamIn.writeBits (5651, 12, &ok); 36 | qDebug () << "streamIn after test3=" << streamIn.toBinary () << ok; 37 | 38 | return 0; 39 | } 40 | 41 | -------------------------------------------------------------------------------- /source/QtQmlTricks/examples/COBS/QtCOBS.qbs: -------------------------------------------------------------------------------- 1 | import qbs; 2 | 3 | Application { 4 | name: "example-cobs"; 5 | targetName: "QtCOBS"; 6 | 7 | Depends { name: "Qt"; } 8 | Depends { name: "cpp"; } 9 | Depends { name: "sdk-utilities"; } 10 | Group { 11 | name: "C++ sources"; 12 | files: ["*.cpp"]; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /source/QtQmlTricks/examples/COBS/main_cobs.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | int main (int argc, char * argv []) { 8 | QCoreApplication (argc, argv); 9 | 10 | const char _raw1 [1] = {0x00}; 11 | const QByteArray raw1 = QByteArray::fromRawData (_raw1, 1); 12 | const char _cob1 [2] = {0x01, 0x01}; 13 | const QByteArray cob1 = QByteArray::fromRawData (_cob1, 2); 14 | qDebug () << "TST1 :" 15 | << "RAW=" << raw1.toHex () 16 | << "COBS=" << cob1.toHex () 17 | << "ENCODE=" << (QtCOBS::encode (raw1) == cob1) 18 | << "DECODE=" << (QtCOBS::decode (cob1) == raw1); 19 | 20 | const char _raw2 [4] = {0x11, 0x22, 0x00, 0x33}; 21 | const QByteArray raw2 = QByteArray::fromRawData (_raw2, 4); 22 | const char _cob2 [5] = {0x03, 0x11, 0x22, 0x02, 0x33}; 23 | const QByteArray cob2 = QByteArray::fromRawData (_cob2, 5); 24 | qDebug () << "TST2 :" 25 | << "RAW=" << raw2.toHex () 26 | << "COBS=" << cob2.toHex () 27 | << "ENCODE=" << (QtCOBS::encode (raw2) == cob2) 28 | << "DECODE=" << (QtCOBS::decode (cob2) == raw2); 29 | 30 | const char _raw3 [4] = {0x11, 0x00, 0x00, 0x00}; 31 | const QByteArray raw3 = QByteArray::fromRawData (_raw3, 4); 32 | const char _cob3 [5] = {0x02, 0x11, 0x01, 0x01, 0x01}; 33 | const QByteArray cob3 = QByteArray::fromRawData (_cob3, 5); 34 | qDebug () << "TST3 :" 35 | << "RAW=" << raw3.toHex () 36 | << "COBS=" << cob3.toHex () 37 | << "ENCODE=" << (QtCOBS::encode (raw3) == cob3) 38 | << "DECODE=" << (QtCOBS::decode (cob3) == raw3); 39 | 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /source/QtQmlTricks/examples/CustomPolygon/CustomPolygon.qbs: -------------------------------------------------------------------------------- 1 | import qbs; 2 | 3 | Application { 4 | name: "example-custom-polygon"; 5 | targetName: "CustomPolygon"; 6 | 7 | Depends { name: "Qt"; } 8 | Depends { name: "cpp"; } 9 | Depends { name: "sdk-utilities"; } 10 | Group { 11 | name: "C++ sources & headers"; 12 | files: ["*.cpp", "*.h"]; 13 | } 14 | Group { 15 | name: "QML documents"; 16 | files: "*.qml"; 17 | } 18 | Group { 19 | name: "Qt resources"; 20 | files: "*.qrc"; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /source/QtQmlTricks/examples/CustomPolygon/data_custompolygon.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | ui_custompolygon.qml 4 | 5 | 6 | -------------------------------------------------------------------------------- /source/QtQmlTricks/examples/CustomPolygon/main_custompolygon.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | static QVector getPolygonForCircleArc (const QPointF & center, qreal radius, int startAngle = 0, int endAngle = 359, bool clockWise = true) { 14 | static const int degrees = 360; 15 | static QVector trigoVector; 16 | if (trigoVector.isEmpty ()) { 17 | trigoVector.resize (degrees); 18 | const qreal PI_RAD = (M_PI / 180.0); 19 | for (int angle = 0; angle < degrees; angle++) { 20 | const qreal radians = (angle * PI_RAD); 21 | trigoVector [angle].setX (qCos (radians)); 22 | trigoVector [angle].setY (qSin (radians)); 23 | } 24 | } 25 | QVector ret; 26 | const int firstAngle = ((startAngle + degrees) % degrees); 27 | const int lastAngle = ((endAngle + degrees) % degrees); 28 | const int stepAngle = (clockWise ? +1 : -1); 29 | for (int currAngle = firstAngle; 30 | currAngle != lastAngle; 31 | currAngle = ((currAngle + stepAngle + degrees) % degrees)) { 32 | ret.append (center + (trigoVector [currAngle] * radius)); 33 | } 34 | return ret; 35 | } 36 | 37 | int main (int argc, char * argv []) { 38 | QGuiApplication app (argc, argv); 39 | 40 | QVector tmp = getPolygonForCircleArc (QPointF (78.9, 45.6), 12.3); 41 | 42 | QVariantList circle; 43 | circle.reserve (tmp.size ()); 44 | foreach (const QPointF & val, tmp) { 45 | circle.append (QVariant::fromValue (val)); 46 | } 47 | 48 | QQuickView view; 49 | registerQtQmlTricksModule (view.engine ()); 50 | view.rootContext ()->setContextProperty ("Circle", QVariant::fromValue (circle)); 51 | view.setResizeMode (QQuickView::SizeRootObjectToView); 52 | view.setSource (QUrl ("qrc:/ui_custompolygon.qml")); 53 | view.show (); 54 | 55 | return app.exec (); 56 | } 57 | 58 | -------------------------------------------------------------------------------- /source/QtQmlTricks/examples/CustomPolygon/ui_custompolygon.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.1; 2 | import QtQmlTricks 1.0; 3 | 4 | Rectangle { 5 | id: window; 6 | width: 600; 7 | height: 400; 8 | 9 | readonly property real centerX : (width / 2); 10 | readonly property real centerY : (height / 2); 11 | 12 | readonly property real size : (Math.min (centerX, centerY) * 0.85); 13 | 14 | Timer { 15 | id: timer; 16 | repeat: true; 17 | running: true; 18 | interval: 1000; 19 | triggeredOnStart: true; 20 | onTriggered: { polygon.count++; } 21 | } 22 | FocusScope { 23 | focus: true; 24 | Keys.onPressed: { timer.running = !timer.running; } 25 | } 26 | Polygon { 27 | id: polygon; 28 | color: Qt.hsla (0.5, 0.5, 0.5, 0.5); 29 | points:{ 30 | var ret = []; 31 | for (var idx = 0; idx < count; idx++) { 32 | var rad = (Math.PI * 2) * (idx / count); 33 | ret.push (Qt.point (centerX + size * Math.cos (rad), 34 | centerY + size * Math.sin (rad))); 35 | } 36 | return ret; 37 | } 38 | 39 | property int count : 0; 40 | 41 | Repeater { 42 | model: parent.points; 43 | delegate: Text { 44 | text: ("P" + model.index); 45 | x: (modelData ["x"] - contentWidth / 2); 46 | y: (modelData ["y"] - contentHeight / 2); 47 | color: "white"; 48 | style: Text.Outline; 49 | styleColor: "black"; 50 | font { 51 | bold: true; 52 | pixelSize: 20; 53 | } 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /source/QtQmlTricks/examples/IconCache/IconCache.qbs: -------------------------------------------------------------------------------- 1 | import qbs; 2 | 3 | Application { 4 | name: "example-icon-cache"; 5 | targetName: "IconCache"; 6 | 7 | Depends { name: "Qt"; } 8 | Depends { name: "cpp"; } 9 | Depends { name: "sdk-utilities"; } 10 | Group { 11 | name: "C++ sources & headers"; 12 | files: ["*.cpp", "*.h"]; 13 | } 14 | Group { 15 | name: "QML documents"; 16 | files: "*.qml"; 17 | } 18 | Group { 19 | name: "Qt resources"; 20 | files: "*.qrc"; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /source/QtQmlTricks/examples/IconCache/data_iconcache.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | ui_iconcache.qml 4 | mark.svg 5 | 6 | 7 | -------------------------------------------------------------------------------- /source/QtQmlTricks/examples/IconCache/main_iconcache.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | int main (int argc, char * argv []) { 12 | QGuiApplication app (argc, argv); 13 | 14 | QQmlSvgIconHelper::setBasePath ("://"); 15 | 16 | QQuickView view; 17 | registerQtQmlTricksModule (view.engine ()); 18 | view.setResizeMode (QQuickView::SizeRootObjectToView); 19 | view.setSource (QUrl ("qrc:/ui_iconcache.qml")); 20 | view.show (); 21 | 22 | return app.exec (); 23 | } 24 | 25 | -------------------------------------------------------------------------------- /source/QtQmlTricks/examples/IconCache/ui_iconcache.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.1; 2 | import QtQmlTricks 1.0; 3 | 4 | Rectangle { 5 | id: window; 6 | width: 600; 7 | height: 400; 8 | 9 | Row { 10 | spacing: 20; 11 | anchors.centerIn: parent; 12 | 13 | Repeater { 14 | model: [ 15 | { "size" : 20, "color" : "gray" }, 16 | { "size" : 32, "color" : "orange" }, 17 | { "size" : 48, "color" : "steelblue" }, 18 | { "size" : 64, "color" : "transparent" }, 19 | ]; 20 | delegate: Image { 21 | cache: true; 22 | smooth: false; 23 | fillMode: Image.Pad; 24 | asynchronous: true; 25 | antialiasing: false; 26 | 27 | SvgIconHelper on source { 28 | icon: "mark"; 29 | size: modelData ["size"]; 30 | color: Qt.lighter (modelData ["color"], 1.0); 31 | } 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /source/QtQmlTricks/examples/JSONPath/QtJsonPath.qbs: -------------------------------------------------------------------------------- 1 | import qbs; 2 | 3 | Application { 4 | name: "example-jsonpath"; 5 | targetName: "QtJsonPath"; 6 | 7 | Depends { name: "Qt"; } 8 | Depends { name: "cpp"; } 9 | Depends { name: "sdk-utilities"; } 10 | Group { 11 | name: "C++ sources"; 12 | files: ["*.cpp"]; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /source/QtQmlTricks/examples/JSONPath/main_jsonpath.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | int main (int argc, char * argv []) { 8 | Q_UNUSED (argc) 9 | Q_UNUSED (argv) 10 | 11 | QByteArray json ("{ \"store\": {" 12 | " \"book\": [ " 13 | " { \"category\": \"reference\"," 14 | " \"author\": \"Nigel Rees\"," 15 | " \"title\": \"Sayings of the Century\"," 16 | " \"price\": 8.95" 17 | " }," 18 | " { \"category\": \"fiction\"," 19 | " \"author\": \"Evelyn Waugh\"," 20 | " \"title\": \"Sword of Honour\"," 21 | " \"price\": 12.99" 22 | " }," 23 | " { \"category\": \"fiction\"," 24 | " \"author\": \"Herman Melville\"," 25 | " \"title\": \"Moby Dick\"," 26 | " \"isbn\": \"0-553-21311-3\"," 27 | " \"price\": 8.99" 28 | " }," 29 | " { \"category\": \"fiction\"," 30 | " \"author\": \"J. R. R. Tolkien\"," 31 | " \"title\": \"The Lord of the Rings\"," 32 | " \"isbn\": \"0-395-19395-8\"," 33 | " \"price\": 22.99" 34 | " }" 35 | " ]," 36 | " \"bicycle\": {" 37 | " \"color\": \"red\"," 38 | " \"price\": 19.95" 39 | " }" 40 | " }" 41 | "}"); 42 | 43 | QJsonDocument jsonDoc = QJsonDocument::fromJson (json); 44 | 45 | QtJsonPath jsonPath (jsonDoc); 46 | 47 | qDebug () << "/store/book/1" << jsonPath.getValue ("/store/book/1"); 48 | qDebug () << "/store/book/2/author" << jsonPath.getValue ("/store/book/2/author"); 49 | qDebug () << "/store/bicycle" << jsonPath.getValue ("/store/bicycle"); 50 | qDebug () << "/store/toto" << jsonPath.getValue ("/store/toto", "N/A"); 51 | 52 | return 0; 53 | } 54 | 55 | -------------------------------------------------------------------------------- /source/QtQmlTricks/examples/NiceModels/NiceModels.qbs: -------------------------------------------------------------------------------- 1 | import qbs; 2 | 3 | Application { 4 | name: "example-nice-models"; 5 | targetName: "NiceModels"; 6 | 7 | Depends { name: "Qt"; } 8 | Depends { name: "cpp"; } 9 | Depends { name: "sdk-utilities"; } 10 | Group { 11 | name: "C++ sources & headers"; 12 | files: ["*.cpp", "*.h"]; 13 | } 14 | Group { 15 | name: "QML documents"; 16 | files: "*.qml"; 17 | } 18 | Group { 19 | name: "Qt resources"; 20 | files: "*.qrc"; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /source/QtQmlTricks/examples/NiceModels/data_nicemodels.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | ui_nicemodels.qml 4 | 5 | 6 | -------------------------------------------------------------------------------- /source/QtQmlTricks/examples/NiceModels/defs_nicemodels.h: -------------------------------------------------------------------------------- 1 | #ifndef DEFS_H 2 | #define DEFS_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | QML_ENUM_CLASS (MyEnum, Unknown = 0, First, Second, Third, Fourth, Fifth, Sixth, Seventh) 10 | 11 | class MyItem : public QObject { 12 | Q_OBJECT 13 | QML_WRITABLE_PROPERTY (int, foo) 14 | QML_WRITABLE_PROPERTY (QString, bar) 15 | QML_READONLY_PROPERTY (MyEnum::Type, test) 16 | QML_CONSTANT_PROPERTY (QString, type) 17 | QML_CONSTANT_PROPERTY (bool, model) 18 | 19 | public: 20 | explicit MyItem (QObject * parent = NULL) : QObject (parent) { 21 | m_foo = 0; 22 | m_bar = ""; 23 | m_test = MyEnum::Unknown; 24 | m_type = metaObject ()->className (); 25 | } 26 | }; 27 | 28 | #endif // DEFS_H 29 | -------------------------------------------------------------------------------- /source/QtQmlTricks/examples/NiceModels/main_nicemodels.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #include "defs_nicemodels.h" 12 | 13 | int main (int argc, char * argv []) { 14 | QGuiApplication app (argc, argv); 15 | 16 | QQmlObjectListModel * testModel = new QQmlObjectListModel (&app, "foo", "bar"); 17 | 18 | int year = QDateTime::currentDateTime ().date ().year (); 19 | QDate date (year, 1, 1); 20 | while (date.year () == year) { 21 | MyItem * item = new MyItem; 22 | item->set_foo (date.dayOfYear ()); 23 | item->set_bar (date.toString ("yyyy-MM-dd")); 24 | item->update_test (MyEnum::Type (date.dayOfWeek ())); 25 | testModel->append (item); 26 | date = date.addDays (1); 27 | } 28 | 29 | QQuickView view; 30 | registerQtQmlTricksModule (view.engine ()); 31 | view.rootContext ()->setContextProperty ("testModel", testModel); 32 | view.setResizeMode (QQuickView::SizeRootObjectToView); 33 | view.setSource (QUrl ("qrc:/ui_nicemodels.qml")); 34 | view.show (); 35 | 36 | return app.exec (); 37 | } 38 | 39 | -------------------------------------------------------------------------------- /source/QtQmlTricks/examples/NiceModels/ui_nicemodels.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.1; 2 | import QtQmlTricks 1.0; 3 | 4 | Rectangle { 5 | id: window; 6 | width: 600; 7 | height: 400; 8 | 9 | ScrollContainer { 10 | anchors.fill: parent; 11 | 12 | Flickable { 13 | id: flicker; 14 | contentWidth: width; 15 | contentHeight: layout.height; 16 | flickableDirection: Flickable.VerticalFlick; 17 | 18 | Column { 19 | id: layout; 20 | anchors { 21 | top: parent.top; 22 | left: parent.left; 23 | right: parent.right; 24 | } 25 | 26 | SingleLineEditBox { 27 | placeholderText: "Type here..."; 28 | anchors { 29 | left: parent.left; 30 | right: parent.right; 31 | } 32 | } 33 | 34 | Repeater { 35 | model: testModel; 36 | delegate: Text { 37 | text: "%1. %2 (%3) -> %4 = %5".arg (model.foo).arg (model.bar).arg (model.test).arg (model.type).arg (model.qtObject); 38 | } 39 | } 40 | } 41 | } 42 | } 43 | Timer { 44 | id: timer; 45 | repeat: true; 46 | running: true; 47 | interval: 1000; 48 | triggeredOnStart: true; 49 | onTriggered: { 50 | if (listOperations.length) { 51 | listOperations.shift () (); 52 | } 53 | } 54 | 55 | property var listOperations : [ 56 | function () { 57 | console.log ("model count=", testModel.count); 58 | }, 59 | function () { 60 | var uid = Qt.formatDate (new Date (), "yyyy-MM-dd"); 61 | var obj = testModel.get (uid); 62 | console.log ("uid=", uid, "obj=", obj, "val=", obj.bar); 63 | }, 64 | function () { 65 | console.log ("model remove idx 3=", (testModel.remove (3) || "DONE")); 66 | }, 67 | function () { 68 | console.log ("model move idx 100 to position 1=", (testModel.move (100, 1) || "DONE")); 69 | }, 70 | function () { 71 | console.log ("'foobar' at 2 :", "foobar".at (2)); 72 | }, 73 | function () { 74 | var arr = ["fo", "ob", "ar"]; 75 | console.log ("arr before=", JSON.stringify (arr)); 76 | console.log ("arr first=", arr.first ()); 77 | console.log ("arr last=", arr.last ()); 78 | arr.removeAt (1); 79 | console.log ("arr after remove at 1 =", JSON.stringify (arr)); 80 | }, 81 | function () { 82 | console.log ("remove all 'o' in 'foobar'=", "foobar".remove ('o')); 83 | }, 84 | ]; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /source/QtQmlTricks/import/QtQmlTricks/ComboList.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.1; 2 | import "Style.js" as Style; 3 | 4 | Item { 5 | id: base; 6 | width: implicitWidth; 7 | height: implicitHeight; 8 | implicitWidth: (lbl.contentWidth + padding * 2); 9 | implicitHeight: (lbl.contentHeight + padding * 2); 10 | 11 | property int padding : 6; 12 | property alias textColor : lbl.color; 13 | property alias backColor : rect.color; 14 | property alias rounding : rect.radius; 15 | 16 | property ListModel model : null; 17 | 18 | property int currentIdx : -1; 19 | readonly property var currentValue : (model && currentIdx >= 0 && currentIdx < model.count ? model.get (currentIdx) ["value"] : undefined); 20 | readonly property var currentKey : (model && currentIdx >= 0 && currentIdx < model.count ? model.get (currentIdx) ["key"] : undefined); 21 | 22 | Gradient { 23 | id: gradientIdle; 24 | 25 | GradientStop { color: Qt.lighter (Style.colorLightGray, 1.15); position: 0.0; } 26 | GradientStop { color: Qt.darker (Style.colorLightGray, 1.15); position: 1.0; } 27 | } 28 | Gradient { 29 | id: gradientPressed; 30 | 31 | GradientStop { color: Qt.darker (Style.colorDarkGray, 1.15); position: 0.0; } 32 | GradientStop { color: Qt.lighter (Style.colorDarkGray, 1.15); position: 1.0; } 33 | } 34 | Gradient { 35 | id: gradientDisabled; 36 | 37 | GradientStop { color: Style.colorLightGray; position: 0.0; } 38 | GradientStop { color: Style.colorLightGray; position: 1.0; } 39 | } 40 | MouseArea { 41 | id: clicker; 42 | anchors.fill: parent; 43 | onClicked: { 44 | if (dropdownItem) { 45 | destroyDropdown (); 46 | } 47 | else { 48 | createDropdown (); 49 | } 50 | } 51 | Component.onDestruction: { destroyDropdown (); } 52 | 53 | property Item dropdownItem : null; 54 | 55 | readonly property Item rootItem : { 56 | var tmp = base; 57 | while ("parent" in tmp && tmp ["parent"] !== null && "visible" in tmp ["parent"]) { 58 | tmp = tmp ["parent"]; 59 | } 60 | return tmp; 61 | } 62 | 63 | function createDropdown () { 64 | dropdownItem = compoDropdown.createObject (rootItem, { "referenceItem" : base }); 65 | } 66 | 67 | function destroyDropdown () { 68 | if (dropdownItem) { 69 | dropdownItem.destroy (); 70 | dropdownItem = null; 71 | } 72 | } 73 | } 74 | Rectangle { 75 | id: rect; 76 | radius: 3; 77 | antialiasing: true; 78 | gradient: (enabled 79 | ? (clicker.pressed || 80 | clicker.dropdownItem 81 | ? gradientPressed 82 | : gradientIdle) 83 | : gradientDisabled); 84 | border { 85 | width: 1; 86 | color: Style.colorGray; 87 | } 88 | anchors.fill: parent; 89 | } 90 | TextLabel { 91 | id: lbl; 92 | text: (currentValue || ""); 93 | color: (enabled ? Style.colorBlack : Style.colorGray); 94 | elide: Text.ElideRight; 95 | visible: (text !== ""); 96 | anchors { 97 | left: parent.left; 98 | right: arrow.left; 99 | margins: padding; 100 | verticalCenter: parent.verticalCenter; 101 | } 102 | } 103 | Item { 104 | id: arrow; 105 | clip: true; 106 | width: 12; 107 | height: (width / 2); 108 | anchors { 109 | right: parent.right; 110 | margins: padding; 111 | verticalCenter: parent.verticalCenter; 112 | } 113 | 114 | Rectangle { 115 | color: Style.colorBlack; 116 | width: (parent.height * Math.SQRT2); 117 | height: width; 118 | rotation: 45; 119 | antialiasing: true; 120 | anchors { 121 | verticalCenter: parent.top; 122 | horizontalCenter: parent.horizontalCenter; 123 | } 124 | } 125 | } 126 | Component { 127 | id: compoDropdown; 128 | 129 | MouseArea { 130 | id: dimmer; 131 | anchors.fill: parent; 132 | onWheel: { } 133 | onPressed: { clicker.destroyDropdown (); } 134 | 135 | property Item referenceItem : null; 136 | 137 | Rectangle { 138 | color: "lightgray"; 139 | height: Math.max (layout.height, 24); 140 | border { 141 | width: 1; 142 | color: Style.colorGray; 143 | } 144 | Component.onCompleted: { 145 | if (dimmer.referenceItem) { 146 | var pos = mapFromItem (dimmer.referenceItem.parent, 147 | dimmer.referenceItem.x, 148 | dimmer.referenceItem.y + 149 | dimmer.referenceItem.height); 150 | width = dimmer.referenceItem.width; 151 | x = pos ["x"]; 152 | y = pos ["y"]; 153 | } 154 | } 155 | 156 | Column { 157 | id: layout; 158 | anchors { 159 | top: parent.top; 160 | left: parent.left; 161 | right: parent.right; 162 | } 163 | 164 | Repeater { 165 | model: base.model; 166 | delegate: MouseArea { 167 | height: 24; 168 | anchors { 169 | left: layout.left; 170 | right: layout.right; 171 | } 172 | onClicked: { 173 | currentIdx = model.index; 174 | clicker.destroyDropdown (); 175 | } 176 | 177 | TextLabel { 178 | clip: true; 179 | text: (model ["value"] || ""); 180 | font.bold: (model.index === currentIdx); 181 | anchors { 182 | left: parent.left; 183 | right: parent.right; 184 | margins: padding; 185 | verticalCenter: parent.verticalCenter; 186 | } 187 | } 188 | } 189 | } 190 | } 191 | } 192 | } 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /source/QtQmlTricks/import/QtQmlTricks/GridContainer.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0; 2 | 3 | /** 4 | * @brief Item that layouts its children within a grid according to row/column count. 5 | * 6 | */ 7 | Item { 8 | id: layout; 9 | width: implicitWidth; 10 | height: implicitHeight; 11 | onColsChanged: { relayout (); } 12 | onWidthChanged: { relayout (); } 13 | onHeightChanged: { relayout (); } 14 | onCapacityChanged: { relayout (); } 15 | onFillEmptyChanged: { relayout (); } 16 | onVerticalFlowChanged: { relayout (); } 17 | onInvertDirectionChanged: { relayout (); } 18 | onChildrenChanged: { 19 | if (layout && layout.ready) { 20 | var tmp = []; 21 | var dirty = false; 22 | items.forEach (function (item) { 23 | if (item && item ["parent"] === layout) { 24 | tmp.push (item); 25 | } 26 | else { 27 | dirty = true; 28 | } 29 | }); 30 | for (var idx = 0; idx < children.length; idx++) { 31 | var child = children [idx]; 32 | if (items.indexOf (child) < 0 && !("delegate" in child)) { 33 | child.visibleChanged.connect (relayout); 34 | child.implicitWidthChanged.connect (relayout); 35 | child.implicitHeightChanged.connect (relayout); 36 | tmp.push (child); 37 | dirty = true; 38 | } 39 | } 40 | items = tmp; 41 | if (dirty) { 42 | relayout (); 43 | } 44 | } 45 | } 46 | Component.onCompleted: { 47 | ready = true; 48 | layout.childrenChanged (); 49 | } 50 | Component.onDestruction: { 51 | ready = false; 52 | } 53 | 54 | property int cols : 1; 55 | property int rows : 1; 56 | 57 | property int rowSpacing : 0; 58 | property int colSpacing : 0; 59 | 60 | property int capacity : -1; 61 | 62 | property bool ready : false; 63 | 64 | property bool fillEmpty : true; 65 | property bool verticalFlow : false; 66 | property bool invertDirection : false; 67 | 68 | property var items : []; 69 | 70 | function relayout () { 71 | if (layout && layout.ready) { 72 | var count = 0; 73 | var maxChildWidth = 0; 74 | var maxChildHeight = 0; 75 | items.forEach (function (child) { 76 | if (child && (child ["visible"] || !fillEmpty)) { 77 | if (child ["implicitWidth"] > maxChildWidth) { 78 | maxChildWidth = child ["implicitWidth"]; 79 | } 80 | if (child ["implicitHeight"] > maxChildHeight) { 81 | maxChildHeight = child ["implicitHeight"]; 82 | } 83 | count++; 84 | } 85 | }); 86 | if (cols > 0) { 87 | if (capacity > 0) { 88 | rows = Math.ceil (capacity / cols); 89 | } 90 | else if (count > 0) { 91 | rows = Math.ceil (count / cols); 92 | } 93 | else { 94 | rows = 1; 95 | } 96 | } 97 | else { 98 | rows = 1; 99 | } 100 | implicitWidth = (cols * maxChildWidth) + ((cols -1) * colSpacing); 101 | implicitHeight = (rows * maxChildHeight) + ((rows -1) * rowSpacing); 102 | var itemWidth = (((width + colSpacing) / cols) - colSpacing); 103 | var itemHeight = (((height + rowSpacing) / rows) - rowSpacing); 104 | var curX = (invertDirection ? width - itemWidth : 0); 105 | var curY = (invertDirection ? height - itemHeight : 0); 106 | var stepX = (itemWidth + colSpacing); 107 | var stepY = (itemHeight + rowSpacing); 108 | if (rows && cols) { 109 | var nb = 0; 110 | items.forEach (function (child) { 111 | if (child && (child ["visible"]|| !fillEmpty)) { 112 | child ["width"] = itemWidth; 113 | child ["height"] = itemHeight; 114 | child ["x"] = curX; 115 | child ["y"] = curY; 116 | if (!verticalFlow) { // horizontal 117 | if ((nb +1) % cols > 0) { // next column 118 | curX = (invertDirection ? curX - stepX : curX + stepX); 119 | } 120 | else { // next row 121 | curX = (invertDirection ? width - itemWidth : 0); 122 | curY = (invertDirection ? curY - stepY : curY + stepY); 123 | } 124 | } 125 | else { // vertical 126 | if ((nb +1) % rows > 0) { // next row 127 | curY = (invertDirection ? curY - stepY : curY + stepY); 128 | } 129 | else { // next column 130 | curY = (invertDirection ? height - itemHeight : 0); 131 | curX = (invertDirection ? curX - stepX : curX + stepX); 132 | } 133 | } 134 | nb++; 135 | } 136 | }); 137 | } 138 | } 139 | } 140 | 141 | /* CONTENT HERE */ 142 | } 143 | -------------------------------------------------------------------------------- /source/QtQmlTricks/import/QtQmlTricks/IconTextButton.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.1; 2 | import QtQmlTricks 1.0; 3 | 4 | MouseArea { 5 | id: clicker; 6 | width: implicitWidth; 7 | height: implicitHeight; 8 | states: [ 9 | State { 10 | name: "icon_and_text"; 11 | when: (img.visible && lbl.visible); 12 | 13 | PropertyChanges { 14 | target: clicker; 15 | implicitWidth: (img.width + lbl.contentWidth + padding * 3); 16 | implicitHeight: (img.height > lbl.contentHeight ? img.height + padding * 2: lbl.contentHeight + padding * 2); 17 | } 18 | AnchorChanges { 19 | target: img; 20 | anchors { 21 | left: parent.left; 22 | verticalCenter: parent.verticalCenter; 23 | } 24 | } 25 | AnchorChanges { 26 | target: lbl; 27 | anchors { 28 | left: img.right; 29 | right: parent.right; 30 | verticalCenter: parent.verticalCenter; 31 | } 32 | } 33 | }, 34 | State { 35 | name: "text_only"; 36 | when: (!img.visible && lbl.visible); 37 | 38 | PropertyChanges { 39 | target: clicker; 40 | implicitWidth: (lbl.contentWidth + padding * 2); 41 | implicitHeight: (lbl.contentHeight + padding * 2); 42 | } 43 | AnchorChanges { 44 | target: lbl; 45 | anchors { 46 | verticalCenter: parent.verticalCenter; 47 | horizontalCenter: parent.horizontalCenter; 48 | } 49 | } 50 | }, 51 | State { 52 | name: "icon_only"; 53 | when: (img.visible && !lbl.visible); 54 | 55 | PropertyChanges { 56 | target: clicker; 57 | implicitWidth: (img.width + padding * 2); 58 | implicitHeight: (img.height + padding * 2); 59 | } 60 | AnchorChanges { 61 | target: img; 62 | anchors { 63 | verticalCenter: parent.verticalCenter; 64 | horizontalCenter: parent.horizontalCenter; 65 | } 66 | } 67 | }, 68 | State { 69 | name: "empty"; 70 | when: (!img.visible && !lbl.visible); 71 | 72 | PropertyChanges { 73 | target: clicker; 74 | implicitWidth: 0; 75 | implicitHeight: 0; 76 | } 77 | } 78 | ] 79 | 80 | property int padding : 12; 81 | 82 | property alias label : lbl.text; 83 | property alias labelFont : lbl.font; 84 | property alias labelColor : lbl.color; 85 | property alias iconSize : helper.size; 86 | property alias iconName : helper.icon; 87 | property alias iconColor : helper.color; 88 | property alias backColor : rect.color; 89 | property alias rounding : rect.radius; 90 | 91 | Rectangle { 92 | id: shadow; 93 | color: Qt.darker (backColor, 1.35); 94 | radius: rounding; 95 | visible: !pressed; 96 | antialiasing: true; 97 | anchors { 98 | fill: parent; 99 | topMargin: +2; 100 | bottomMargin: -2; 101 | } 102 | } 103 | Rectangle { 104 | id: rect; 105 | color: (pressed ? "lightblue" : "lightgray"); 106 | radius: 6; 107 | antialiasing: true; 108 | border { 109 | color: "steelblue"; 110 | width: (pressed ? 1 : 0); 111 | } 112 | anchors.fill: parent; 113 | } 114 | Image { 115 | id: img; 116 | width: (helper.size * helper.horizontalRatio); 117 | height: (helper.size * helper.verticalRatio); 118 | visible: (status !== Image.Null); 119 | fillMode: Image.Pad 120 | anchors.margins: padding; 121 | 122 | SvgIconHelper on source { 123 | id: helper; 124 | size: 24; 125 | color: lbl.color; 126 | } 127 | } 128 | Text { 129 | id: lbl; 130 | color: (pressed ? "darkblue" : "black"); 131 | visible: (text !== ""); 132 | horizontalAlignment: (img.visible ? Text.AlignLeft : Text.AlignHCenter); 133 | font { 134 | weight: Font.Light; 135 | pixelSize: 18; 136 | } 137 | anchors.margins: padding; 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /source/QtQmlTricks/import/QtQmlTricks/QmlComponents.qbs: -------------------------------------------------------------------------------- 1 | import qbs 2 | 3 | StaticLibrary { 4 | name: "qml-js-imports"; 5 | targetName: "QmlJsTricks"; 6 | 7 | Depends { name: "Qt"; } 8 | Depends { name: "cpp"; } 9 | Group { 10 | name: "JavaScript modules"; 11 | files: "*.js"; 12 | } 13 | Group { 14 | name: "QML components"; 15 | files: "*.qml"; 16 | } 17 | Group { 18 | name: "QML directory"; 19 | files: "qmldir"; 20 | } 21 | Group { 22 | name: "Qt resources"; 23 | files: "*.qrc"; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /source/QtQmlTricks/import/QtQmlTricks/QtCoreApi.js: -------------------------------------------------------------------------------- 1 | .pragma library 2 | 3 | /************** Adds most of QString/QByteArray API to JS String *******************************/ 4 | 5 | function addMethod (object, method) { 6 | Object.defineProperty (object, method.name, { 7 | "value" : method, 8 | "enumerable" : false 9 | }); 10 | } 11 | 12 | 13 | function at (idx) { 14 | return (this [idx]); 15 | } 16 | addMethod (Array.prototype, at); 17 | addMethod (String.prototype, at); 18 | 19 | 20 | function first () { 21 | return this [0]; 22 | } 23 | addMethod (Array.prototype, first); 24 | addMethod (String.prototype, first); 25 | 26 | 27 | function last () { 28 | return (this.length ? this [this.length -1] : undefined); 29 | } 30 | addMethod (Array.prototype, last); 31 | addMethod (String.prototype, last); 32 | 33 | 34 | function contains (value) { 35 | return (this.indexOf (value) > -1); 36 | } 37 | addMethod (Array.prototype, contains); 38 | addMethod (String.prototype, contains); 39 | 40 | 41 | function size () { 42 | return (this.length); 43 | } 44 | addMethod (Array.prototype, size); 45 | addMethod (String.prototype, size); 46 | 47 | 48 | function isEmpty () { 49 | return (!this.length); 50 | } 51 | addMethod (Array.prototype, isEmpty); 52 | addMethod (String.prototype, isEmpty); 53 | 54 | 55 | function clear () { 56 | this.splice (0, this.length); 57 | } 58 | addMethod (Array.prototype, clear); 59 | 60 | 61 | function foreach (callback) { 62 | for (var i = 0; i < this.length; callback (i, this [i]), i++); 63 | } 64 | addMethod (Array.prototype, foreach); 65 | 66 | 67 | function append (value) { 68 | this.push (value); 69 | } 70 | addMethod (Array.prototype, append); 71 | 72 | 73 | function prepend (value) { 74 | this.unshift (value); 75 | } 76 | addMethod (Array.prototype, prepend); 77 | 78 | 79 | function removeAt (idx) { 80 | this.splice (idx, 1); 81 | } 82 | addMethod (Array.prototype, removeAt); 83 | 84 | 85 | function removeAll (value) { 86 | var ret = 0; 87 | var it = 0; 88 | while (it < this.length) { 89 | if (this [it] === (value)) { 90 | this.splice (it, 1); 91 | ret++; 92 | } 93 | else { it++; } 94 | } 95 | return ret; 96 | } 97 | addMethod (Array.prototype, removeAll); 98 | 99 | 100 | function takeAt (idx) { 101 | var ret = this [idx]; 102 | this.splice (idx, 1); 103 | return ret; 104 | } 105 | addMethod (Array.prototype, takeAt); 106 | 107 | 108 | function erase (idx) { 109 | this [idx] = undefined; 110 | } 111 | addMethod (Array.prototype, erase); 112 | 113 | 114 | function swap (idx1, idx2) { 115 | var tmp = this [idx1]; 116 | this [idx1] = this [idx2]; 117 | this [idx2] = tmp; 118 | } 119 | addMethod (Array.prototype, swap); 120 | 121 | 122 | function replace (idx, value) { 123 | this [idx] = value; 124 | } 125 | addMethod (Array.prototype, replace); 126 | 127 | 128 | function squeeze () { 129 | var it = 0; 130 | while (it < this.length) { 131 | if (this [it] !== null && this [it] !== undefined) { 132 | this.splice (it, 1); 133 | } 134 | else { it++; } 135 | } 136 | } 137 | addMethod (Array.prototype, squeeze); 138 | 139 | 140 | function append (str) { 141 | return String (this + (str || "")); 142 | } 143 | addMethod (String.prototype, append); 144 | 145 | 146 | function prepend (str) { 147 | return String ((str || "") + this); 148 | } 149 | addMethod (String.prototype, prepend); 150 | 151 | 152 | function trimmed () { 153 | return String (this.replace (/\s*$/, '').replace (/^\s*/, '')); 154 | } 155 | addMethod (String.prototype, trimmed); 156 | 157 | 158 | function remove (str) { 159 | var ret = String (this); 160 | while (ret.indexOf (str) > -1) { 161 | ret = ret.replace (str, ''); 162 | } 163 | return ret; 164 | } 165 | addMethod (String.prototype, remove); 166 | 167 | 168 | function repeat (str, count) { 169 | return (new Array (count +1).join (str)); 170 | } 171 | addMethod (String, repeat); 172 | 173 | 174 | function mid (pos, len) { 175 | return this.substr (pos, len); 176 | } 177 | addMethod (String.prototype, mid); 178 | 179 | 180 | function left (len) { 181 | return (len < this.length ? this.substr (0, len) : this); 182 | } 183 | addMethod (String.prototype, left); 184 | 185 | 186 | function right (len) { 187 | return (len < this.length ? this.substr (this.length - len, len) : this); 188 | } 189 | addMethod (String.prototype, right); 190 | 191 | 192 | function startsWith (str) { 193 | return (str && this.indexOf (str) === 0); 194 | } 195 | addMethod (String.prototype, startsWith); 196 | 197 | 198 | function endsWith (str) { 199 | return (str && this.lastIndexOf (str) > -1 && this.lastIndexOf (str) === (this.length - str.length)); 200 | } 201 | addMethod (String.prototype, endsWith); 202 | 203 | 204 | function toBase64 () { 205 | return Qt.atob (this); 206 | } 207 | addMethod (String.prototype, toBase64); 208 | 209 | 210 | function fromBase64 (str) { 211 | return Qt.btoa (str); 212 | } 213 | addMethod (String, fromBase64); 214 | 215 | -------------------------------------------------------------------------------- /source/QtQmlTricks/import/QtQmlTricks/RowContainer.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0; 2 | 3 | /** 4 | * @brief Item that layouts its children within a row, respecting size hints and spacers. 5 | * 6 | */ 7 | Item { 8 | id: layout; 9 | width: implicitWidth; 10 | height: implicitHeight; 11 | onWidthChanged: { relayout (); } 12 | onChildrenChanged: { 13 | if (layout && layout.ready) { 14 | var tmp = []; 15 | var dirty = false; 16 | items.forEach (function (item) { 17 | if (item && item ["parent"] === layout) { 18 | tmp.push (item); 19 | } 20 | else { 21 | dirty = true; 22 | } 23 | }); 24 | for (var idx = 0; idx < children.length; idx++) { 25 | var child = children [idx]; 26 | if (items.indexOf (child) < 0 && !("delegate" in child)) { 27 | child.visibleChanged.connect (relayout); 28 | child.implicitWidthChanged.connect (relayout); 29 | child.implicitHeightChanged.connect (relayout); 30 | tmp.push (child); 31 | dirty = true; 32 | } 33 | } 34 | if (dirty) { 35 | items = tmp; 36 | relayout (); 37 | } 38 | } 39 | } 40 | Component.onCompleted: { 41 | ready = true; 42 | layout.childrenChanged (); 43 | } 44 | Component.onDestruction: { 45 | ready = false; 46 | } 47 | 48 | property int spacing : 0; 49 | property var items : []; 50 | 51 | property bool ready : false; 52 | 53 | default property alias content : layout.data; 54 | 55 | function relayout () { 56 | if (layout && layout.ready) { 57 | var tmpW = 0; 58 | var tmpH = 0; 59 | var nbStretch = 0; 60 | var nb = 0; 61 | items.forEach (function (child) { 62 | if (child && child ["visible"]) { 63 | if (child ["implicitHeight"] > tmpH) { 64 | tmpH = child ["implicitHeight"]; 65 | } 66 | if (nb) { 67 | tmpW += spacing; 68 | } 69 | if (child ["implicitWidth"] >= 0) { 70 | tmpW += child ["implicitWidth"]; 71 | } 72 | else { 73 | nbStretch++; 74 | } 75 | nb++; 76 | } 77 | }); 78 | implicitWidth = tmpW; 79 | implicitHeight = tmpH; 80 | var autoSize = (nbStretch > 0 ? (width - implicitWidth) / nbStretch : 0); 81 | var currX = 0; 82 | items.forEach (function (child) { 83 | if (child && child ["visible"]) { 84 | if (currX) { 85 | currX += spacing; 86 | } 87 | child ["x"] = currX; 88 | child ["width"] = (child ["implicitWidth"] >= 0 ? child ["implicitWidth"] : autoSize); 89 | currX += child ["width"]; 90 | } 91 | }); 92 | } 93 | } 94 | 95 | /* CONTENT HERE */ 96 | } 97 | -------------------------------------------------------------------------------- /source/QtQmlTricks/import/QtQmlTricks/SingleLineEditBox.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.1; 2 | 3 | FocusScope { 4 | width: implicitWidth; 5 | height: implicitHeight; 6 | implicitWidth: (input.contentWidth + padding * 2); 7 | implicitHeight: (input.contentHeight + padding * 2); 8 | 9 | property int padding : 6; 10 | 11 | property color backgroundColor : "white"; 12 | property color foregroundColor : "black"; 13 | property color highlightColor : "steelblue"; 14 | property color secondaryColor : "lightgray"; 15 | property color borderColor : "gray"; 16 | 17 | property alias textFont : input.font; 18 | property alias rounding : rect.radius; 19 | property alias editableText : input.text; 20 | property alias isEditLocked : input.readOnly; 21 | property alias placeholderText : placeholder.text; 22 | 23 | Rectangle { 24 | id: rect; 25 | color: backgroundColor; 26 | radius: 4; 27 | antialiasing: true; 28 | anchors.fill: parent; 29 | } 30 | Item { 31 | clip: true; 32 | anchors.fill: parent; 33 | 34 | TextInput { 35 | id: input; 36 | focus: true; 37 | color: (enabled ? foregroundColor : secondaryColor); 38 | selectByMouse: true; 39 | selectionColor: highlightColor; 40 | selectedTextColor: backgroundColor; 41 | activeFocusOnPress: true; 42 | font { 43 | weight: Font.Light; 44 | pixelSize: 18; 45 | } 46 | anchors { 47 | left: parent.left; 48 | right: parent.right; 49 | margins: padding; 50 | verticalCenter: parent.verticalCenter; 51 | } 52 | } 53 | Text { 54 | id: placeholder; 55 | font: input.font; 56 | color: secondaryColor; 57 | visible: (!input.activeFocus && !input.length); 58 | anchors.fill: input; 59 | } 60 | } 61 | Rectangle { 62 | color: "transparent"; 63 | radius: rect.radius; 64 | antialiasing: true; 65 | border { 66 | width: (input.activeFocus ? 2 : 1); 67 | color: (input.activeFocus ? highlightColor : borderColor); 68 | } 69 | anchors.fill: parent; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /source/QtQmlTricks/import/QtQmlTricks/Style.js: -------------------------------------------------------------------------------- 1 | .pragma library; 2 | 3 | var fontSizeSmall = 11; 4 | var fontSizeNormal = 14; 5 | var fontSizeBig = 16; 6 | var fontSizeTitle = 18; 7 | 8 | var colorGray = "gray"; 9 | var colorBlack = "black"; 10 | var colorWhite = "white"; 11 | var colorDarkGray = "darkgray"; 12 | var colorLightGray = "lightgray"; 13 | var colorDarkRed = "darkred"; 14 | var colorOrange = "orange"; 15 | var colorSteelBlue = "steelblue"; 16 | var colorDarkBlue = "darkblue"; 17 | var colorLightBlue = "lightblue"; 18 | 19 | var fontName = selectFont ([ 20 | "Sail Sans Pro", 21 | "Source Sans Pro", 22 | "Ubuntu", 23 | "Roboto", 24 | "Droid Sans", 25 | "Liberation Sans", 26 | "Trebuchet MS", 27 | "Deja Vu Sans", 28 | "Tahoma", 29 | "Arial", 30 | ], 31 | "sans-serif"); 32 | 33 | var fontFixedName = selectFont ([ 34 | "Ubuntu Mono", 35 | "Deja Vu Mono", 36 | "Courier New", 37 | "Lucida Console", 38 | ], 39 | "monospace"); 40 | 41 | function gray (val) { 42 | var tmp = (val / 255); 43 | return Qt.rgba (tmp, tmp, tmp, 1.0); 44 | } 45 | function opacify (tint, alpha) { 46 | var tmp = Qt.darker (tint, 1.0); 47 | return Qt.rgba (tmp.r, tmp.g, tmp.b, alpha); 48 | } 49 | 50 | function selectFont (list, fallback) { 51 | var ret; 52 | var all = Qt.fontFamilies (); 53 | for (var idx = 0; idx < list.length; idx++) { 54 | var tmp = list [idx]; 55 | if (all.indexOf (tmp) >= 0) { 56 | ret = tmp; 57 | break; 58 | } 59 | } 60 | return (ret || fallback); 61 | } 62 | -------------------------------------------------------------------------------- /source/QtQmlTricks/import/QtQmlTricks/TextBox.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.1; 2 | import "Style.js" as Style; 3 | 4 | FocusScope { 5 | id: base; 6 | width: implicitWidth; 7 | height: implicitHeight; 8 | implicitWidth: (input.contentWidth + padding * 2); 9 | implicitHeight: (input.contentHeight + padding * 2); 10 | 11 | property int padding : 6; 12 | property alias text : input.text; 13 | property alias textFont : input.font; 14 | property alias textColor : input.color; 15 | property alias textAlign : input.horizontalAlignment; 16 | property alias textHolder : holder.text; 17 | property alias inputMask : input.inputMask; 18 | property alias validator : input.validator; 19 | property alias rounding : rect.radius; 20 | 21 | signal accepted (); 22 | 23 | function selectAll () { 24 | input.selectAll (); 25 | } 26 | function clear () { 27 | input.text = ""; 28 | } 29 | 30 | Gradient { 31 | id: gradientIdle; 32 | 33 | GradientStop { color: Style.colorWhite; position: 0.0; } 34 | GradientStop { color: Style.colorWhite; position: 1.0; } 35 | } 36 | Gradient { 37 | id: gradientDisabled; 38 | 39 | GradientStop { color: Style.colorLightGray; position: 0.0; } 40 | GradientStop { color: Style.colorLightGray; position: 1.0; } 41 | } 42 | Rectangle { 43 | id: rect; 44 | radius: 3; 45 | antialiasing: true; 46 | gradient: (base.enabled ? gradientIdle : gradientDisabled); 47 | border { 48 | width: 1; 49 | color: (input.activeFocus ? Style.colorSteelBlue : Style.colorGray); 50 | } 51 | anchors.fill: parent; 52 | } 53 | Item { 54 | clip: true; 55 | anchors { 56 | fill: rect; 57 | margins: rect.border.width; 58 | } 59 | 60 | TextInput { 61 | id: input; 62 | focus: true; 63 | color: (base.enabled ? Style.colorBlack : Style.colorGray); 64 | font { 65 | family: Style.fontName; 66 | weight: Font.Light; 67 | pixelSize: Style.fontSizeNormal; 68 | } 69 | anchors { 70 | left: parent.left; 71 | right: parent.right; 72 | margins: padding; 73 | verticalCenter: parent.verticalCenter; 74 | } 75 | onAccepted: { base.accepted (); } 76 | } 77 | } 78 | Text { 79 | id: holder; 80 | font: input.font; 81 | color: Style.colorGray; 82 | visible: (!input.activeFocus && input.text.trim ().length === 0); 83 | horizontalAlignment: input.horizontalAlignment; 84 | anchors { 85 | left: parent.left; 86 | right: parent.right; 87 | margins: padding; 88 | verticalCenter: parent.verticalCenter; 89 | } 90 | } 91 | } 92 | 93 | -------------------------------------------------------------------------------- /source/QtQmlTricks/import/QtQmlTricks/TextButton.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.1; 2 | import "Style.js" as Style; 3 | 4 | MouseArea { 5 | id: clicker; 6 | width: implicitWidth; 7 | height: implicitHeight; 8 | implicitWidth: (lbl.contentWidth + padding * 2); 9 | implicitHeight: (lbl.contentHeight + padding * 2); 10 | 11 | property int padding : 6; 12 | property bool checked : false; 13 | property alias text : lbl.text; 14 | property alias textFont : lbl.font; 15 | property alias textColor : lbl.color; 16 | property alias backColor : rect.color; 17 | property alias rounding : rect.radius; 18 | 19 | Gradient { 20 | id: gradientIdle; 21 | 22 | GradientStop { color: Qt.lighter (Style.colorLightGray, 1.15); position: 0.0; } 23 | GradientStop { color: Qt.darker (Style.colorLightGray, 1.15); position: 1.0; } 24 | } 25 | Gradient { 26 | id: gradientPressed; 27 | 28 | GradientStop { color: Qt.darker (Style.colorDarkGray, 1.15); position: 0.0; } 29 | GradientStop { color: Qt.lighter (Style.colorDarkGray, 1.15); position: 1.0; } 30 | } 31 | Gradient { 32 | id: gradientChecked; 33 | 34 | GradientStop { color: Qt.darker (Style.colorLightBlue, 1.15); position: 0.0; } 35 | GradientStop { color: Qt.lighter (Style.colorLightBlue, 1.15); position: 1.0; } 36 | } 37 | Gradient { 38 | id: gradientDisabled; 39 | 40 | GradientStop { color: Style.colorLightGray; position: 0.0; } 41 | GradientStop { color: Style.colorLightGray; position: 1.0; } 42 | } 43 | Rectangle { 44 | id: rect; 45 | radius: 3; 46 | antialiasing: true; 47 | gradient: (clicker.enabled 48 | ? (checked 49 | ? gradientChecked 50 | : (pressed 51 | ? gradientPressed 52 | : gradientIdle)) 53 | : gradientDisabled); 54 | border { 55 | width: 1; 56 | color: (checked ? Style.colorSteelBlue : Style.colorGray); 57 | } 58 | anchors.fill: parent; 59 | } 60 | Text { 61 | id: lbl; 62 | color: (clicker.enabled ? (checked ? Style.colorDarkBlue : Style.colorBlack) : Style.colorGray); 63 | visible: (text !== ""); 64 | font { 65 | family: Style.fontName; 66 | weight: Font.Light; 67 | pixelSize: Style.fontSizeNormal; 68 | } 69 | anchors.centerIn: parent; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /source/QtQmlTricks/import/QtQmlTricks/TextLabel.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.1; 2 | import "Style.js" as Style; 3 | 4 | Text { 5 | color: (enabled ? Style.colorBlack : Style.colorGray); 6 | font { 7 | weight: Font.Light; 8 | family: Style.fontName; 9 | pixelSize: Style.fontSizeNormal; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /source/QtQmlTricks/import/QtQmlTricks/components.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | GridContainer.qml 4 | QtCoreApi.js 5 | qmldir 6 | RowContainer.qml 7 | WrapLeftRightContainer.qml 8 | ScrollContainer.qml 9 | IconTextButton.qml 10 | SingleLineEditBox.qml 11 | 12 | 13 | -------------------------------------------------------------------------------- /source/QtQmlTricks/import/QtQmlTricks/qmldir: -------------------------------------------------------------------------------- 1 | module QtQmlTricks 2 | 3 | QtCoreApi 1.0 QtCoreApi.js 4 | RowContainer 1.0 RowContainer.qml 5 | GridContainer 1.0 GridContainer.qml 6 | ScrollContainer 1.0 ScrollContainer.qml 7 | WrapLeftRightContainer 1.0 WrapLeftRightContainer.qml 8 | IconTextButton 1.0 IconTextButton.qml 9 | SingleLineEditBox 1.0 SingleLineEditBox.qml 10 | 11 | plugin QtQmlTricksPlugin 12 | -------------------------------------------------------------------------------- /source/QtQmlTricks/import/import.qbs: -------------------------------------------------------------------------------- 1 | import qbs 1.0; 2 | 3 | Product { 4 | name: "qml-js-imports"; 5 | 6 | Group { 7 | name: "JavaScript modules"; 8 | files: "*.js"; 9 | } 10 | Group { 11 | name: "QML components"; 12 | files: "*.qml"; 13 | } 14 | Group { 15 | name: "QML directory"; 16 | files: "qmldir"; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /source/QtQmlTricks/include/QQmlGadgetListModel: -------------------------------------------------------------------------------- 1 | #include "../src/qqmlgadgetlistmodel.h" 2 | -------------------------------------------------------------------------------- /source/QtQmlTricks/include/QQmlHelpers: -------------------------------------------------------------------------------- 1 | #include "../src/qqmlhelpers.h" 2 | -------------------------------------------------------------------------------- /source/QtQmlTricks/include/QQmlObjectListModel: -------------------------------------------------------------------------------- 1 | #include "../src/qqmlobjectlistmodel.h" 2 | -------------------------------------------------------------------------------- /source/QtQmlTricks/include/QQmlSvgIconHelper: -------------------------------------------------------------------------------- 1 | #include "../src/qqmlsvgiconhelper.h" 2 | -------------------------------------------------------------------------------- /source/QtQmlTricks/include/QQmlVariantListModel: -------------------------------------------------------------------------------- 1 | #include "../src/qqmlvariantlistmodel.h" 2 | -------------------------------------------------------------------------------- /source/QtQmlTricks/include/QQuickPolygon: -------------------------------------------------------------------------------- 1 | #include "../src/qquickpolygon.h" 2 | -------------------------------------------------------------------------------- /source/QtQmlTricks/include/QtBitStream: -------------------------------------------------------------------------------- 1 | #include "../src/qtbitstream.h" 2 | -------------------------------------------------------------------------------- /source/QtQmlTricks/include/QtCOBS: -------------------------------------------------------------------------------- 1 | #include "../src/qtcobs.h" 2 | 3 | -------------------------------------------------------------------------------- /source/QtQmlTricks/include/QtJsonPath: -------------------------------------------------------------------------------- 1 | #include "../src/qtjsonpath.h" 2 | -------------------------------------------------------------------------------- /source/QtQmlTricks/include/QtQmlTricks: -------------------------------------------------------------------------------- 1 | #ifndef QTQMLTRICKS 2 | #define QTQMLTRICKS 3 | 4 | #include 5 | #include 6 | 7 | #include "QQuickPolygon" 8 | #include "QQmlSvgIconHelper" 9 | #include "QQmlObjectListModel" 10 | #include "QQmlVariantListModel" 11 | 12 | static void registerQtQmlTricksModule (QQmlEngine * engine) { 13 | Q_INIT_RESOURCE (components); 14 | 15 | const char * uri = "QtQmlTricks"; // @uri QtQmlTricks 16 | const int maj = 1; 17 | const int min = 0; 18 | 19 | qmlRegisterType (uri, maj, min, "Polygon"); 20 | qmlRegisterType (uri, maj, min, "SvgIconHelper"); 21 | 22 | qmlRegisterUncreatableType (uri, maj, min, "AbstractItemModel", "!!!"); 23 | qmlRegisterUncreatableType (uri, maj, min, "AbstractListModel", "!!!"); 24 | qmlRegisterUncreatableType (uri, maj, min, "VariantListModel", "!!!"); 25 | qmlRegisterUncreatableType (uri, maj, min, "ObjectListModelBase", "!!!"); 26 | 27 | if (engine) { 28 | engine->addImportPath ("qrc:/import"); 29 | } 30 | } 31 | 32 | #endif // QTQMLTRICKS 33 | 34 | -------------------------------------------------------------------------------- /source/QtQmlTricks/src/QtLibrary.qbs: -------------------------------------------------------------------------------- 1 | import qbs 1.0; 2 | 3 | StaticLibrary { 4 | name: "lib-qt-qml-tricks"; 5 | targetName: "QtQmlTricks"; 6 | 7 | Depends { name: "cpp"; } 8 | Depends { name: "Qt"; submodules: ["core", "qml", "gui", "quick", "svg"]; } 9 | Group { 10 | name: "C++ sources"; 11 | files: "*.cpp"; 12 | fileTags: "source"; 13 | overrideTags: false; 14 | } 15 | Group { 16 | name: "C++ headers"; 17 | files: "*.h"; 18 | fileTags: "source"; 19 | overrideTags: false; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /source/QtQmlTricks/src/qmlplugin.cpp: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2016 Erik Hvatum 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 | // 23 | // Authors: Erik Hvatum 24 | 25 | #include "qmlplugin.h" 26 | #include "include/QQuickPolygon" 27 | #include "include/QQmlSvgIconHelper" 28 | #include "include/QQmlObjectListModel" 29 | #include "include/QQmlVariantListModel" 30 | 31 | QtQmlTricksPlugin::QtQmlTricksPlugin(QObject* parent) 32 | : QQmlExtensionPlugin(parent) 33 | { 34 | qDebug() << "QtQmlTricksPlugin loaded"; 35 | } 36 | 37 | void QtQmlTricksPlugin::registerTypes(const char* uri) 38 | { 39 | Q_ASSERT(uri == QLatin1String("QtQmlTricks")); 40 | qDebug() << "QtQmlTricksPlugin::registerTypes(..)"; 41 | 42 | 43 | // Q_INIT_RESOURCE (components); 44 | 45 | // const char * uri = "QtQmlTricks"; // @uri QtQmlTricks 46 | const int maj = 1; 47 | const int min = 0; 48 | 49 | qmlRegisterType (uri, maj, min, "Polygon"); 50 | qmlRegisterType (uri, maj, min, "SvgIconHelper"); 51 | 52 | qmlRegisterUncreatableType (uri, maj, min, "AbstractItemModel", "!!!"); 53 | qmlRegisterUncreatableType (uri, maj, min, "AbstractListModel", "!!!"); 54 | qmlRegisterUncreatableType (uri, maj, min, "VariantListModel", "!!!"); 55 | qmlRegisterUncreatableType (uri, maj, min, "ObjectListModelBase", "!!!"); 56 | 57 | // if (engine) { 58 | // engine->addImportPath ("qrc:/import"); 59 | // } 60 | } 61 | -------------------------------------------------------------------------------- /source/QtQmlTricks/src/qmlplugin.h: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2016 Erik Hvatum 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 | // 23 | // Authors: Erik Hvatum 24 | 25 | #pragma once 26 | #include 27 | #include 28 | #include 29 | 30 | class QtQmlTricksPlugin 31 | : public QQmlExtensionPlugin 32 | { 33 | Q_OBJECT 34 | Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") 35 | public: 36 | explicit QtQmlTricksPlugin(QObject* parent=nullptr); 37 | 38 | void registerTypes(const char* uri) override; 39 | }; 40 | -------------------------------------------------------------------------------- /source/QtQmlTricks/src/qqmlhelpers.cpp: -------------------------------------------------------------------------------- 1 | #include "qqmlhelpers.h" 2 | 3 | /*! 4 | \defgroup QT_QML_HELPERS Qt helper macros 5 | 6 | Brings a couple of macros that can help saving development time, 7 | by avoiding manual code duplication, often leading to heavy copy-and-paste, 8 | which is largely error-prone and not productive at all. 9 | */ 10 | 11 | 12 | /*! 13 | \def QML_WRITABLE_PROPERTY(type, name) 14 | \ingroup QT_QML_HELPERS 15 | \hideinitializer 16 | \details Creates a \c Q_PROPERTY that will be readable / writable from QML. 17 | 18 | \param type The C++ type of the property 19 | \param name The name for the property 20 | 21 | It generates for this goal : 22 | \code 23 | {type} m_{name}; // private member variable 24 | {type} get_{name} () const; // public getter method 25 | void set_{name} ({type}); // public setter slot 26 | void {name}Changed ({type}); // notifier signal 27 | \endcode 28 | 29 | \b Note : Any change from either C++ or QML side will trigger the notification. 30 | */ 31 | 32 | 33 | /*! 34 | \def QML_READONLY_PROPERTY(type, name) 35 | \ingroup QT_QML_HELPERS 36 | \hideinitializer 37 | \details Creates a \c Q_PROPERTY that will be readable from QML and writable from C++. 38 | 39 | \param type The C++ type of the property 40 | \param name The name for the property 41 | 42 | It generates for this goal : 43 | \code 44 | {type} m_{name}; // private member variable 45 | {type} get_{name} () const; // public getter method 46 | void update_{name} ({type}); // public setter method 47 | void {name}Changed ({type}); // notifier signal 48 | \endcode 49 | 50 | \b Note : Any change from C++ side will trigger the notification to QML. 51 | */ 52 | 53 | 54 | /*! 55 | \def QML_CONSTANT_PROPERTY(type, name) 56 | \ingroup QT_QML_HELPERS 57 | \hideinitializer 58 | \details Creates a \c Q_PROPERTY for a constant value exposed from C++ to QML. 59 | 60 | \param type The C++ type of the property 61 | \param name The name for the property 62 | 63 | It generates for this goal : 64 | \code 65 | {type} m_{name}; // private member variable 66 | {type} get_{name} () const; // public getter method 67 | \endcode 68 | 69 | \b Note : There is no change notifier because value is constant. 70 | */ 71 | 72 | 73 | /*! 74 | \def QML_ENUM_CLASS(name, ...) 75 | \ingroup QT_QML_HELPERS 76 | \hideinitializer 77 | \details Creates a class that contains a C++ enum that can be exposed to QML. 78 | 79 | \param name The name for the class 80 | \param ... The variadic list of values for the enum (comma-separated) 81 | 82 | It generates for this goal : 83 | \li The \c {name} C++ QObject-derived class 84 | \li The \c {name}::Type enumeration containing the values list 85 | \li The \c Q_ENUMS macro call to allow QML usage 86 | 87 | Example in use : 88 | \code 89 | QML_ENUM_CLASS (DaysOfWeek, Monday = 1, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday) 90 | \endcode 91 | 92 | \b Note : The QML registration using \c qmlRegisterUncreatableType() will still be needed. 93 | */ 94 | -------------------------------------------------------------------------------- /source/QtQmlTricks/src/qqmlhelpers.h: -------------------------------------------------------------------------------- 1 | #ifndef QQMLHELPERS_H 2 | #define QQMLHELPERS_H 3 | 4 | #include 5 | 6 | #define QML_WRITABLE_PROPERTY(type, name) \ 7 | protected: \ 8 | Q_PROPERTY (type name READ get_##name WRITE set_##name NOTIFY name##Changed) \ 9 | private: \ 10 | type m_##name; \ 11 | public: \ 12 | type get_##name () const { \ 13 | return m_##name ; \ 14 | } \ 15 | public Q_SLOTS: \ 16 | bool set_##name (type name) { \ 17 | bool ret = false; \ 18 | if ((ret = m_##name != name)) { \ 19 | m_##name = name; \ 20 | emit name##Changed (m_##name); \ 21 | } \ 22 | return ret; \ 23 | } \ 24 | Q_SIGNALS: \ 25 | void name##Changed (type name); \ 26 | private: 27 | 28 | #define QML_READONLY_PROPERTY(type, name) \ 29 | protected: \ 30 | Q_PROPERTY (type name READ get_##name NOTIFY name##Changed) \ 31 | private: \ 32 | type m_##name; \ 33 | public: \ 34 | type get_##name () const { \ 35 | return m_##name ; \ 36 | } \ 37 | bool update_##name (type name) { \ 38 | bool ret = false; \ 39 | if ((ret = m_##name != name)) { \ 40 | m_##name = name; \ 41 | emit name##Changed (m_##name); \ 42 | } \ 43 | return ret; \ 44 | } \ 45 | Q_SIGNALS: \ 46 | void name##Changed (type name); \ 47 | private: 48 | 49 | #define QML_CONSTANT_PROPERTY(type, name) \ 50 | protected: \ 51 | Q_PROPERTY (type name READ get_##name CONSTANT) \ 52 | private: \ 53 | type m_##name; \ 54 | public: \ 55 | type get_##name () const { \ 56 | return m_##name ; \ 57 | } \ 58 | private: 59 | 60 | #define QML_LIST_PROPERTY(CLASS, NAME, TYPE) \ 61 | public: \ 62 | static int NAME##_count (QQmlListProperty * prop) { \ 63 | CLASS * instance = qobject_cast (prop->object); \ 64 | return (instance != NULL ? instance->m_##NAME.count () : 0); \ 65 | } \ 66 | static void NAME##_clear (QQmlListProperty * prop) { \ 67 | CLASS * instance = qobject_cast (prop->object); \ 68 | if (instance != NULL) { \ 69 | instance->m_##NAME.clear (); \ 70 | } \ 71 | } \ 72 | static void NAME##_append (QQmlListProperty * prop, TYPE * obj) { \ 73 | CLASS * instance = qobject_cast (prop->object); \ 74 | if (instance != NULL && obj != NULL) { \ 75 | instance->m_##NAME.append (obj); \ 76 | } \ 77 | } \ 78 | static TYPE * NAME##_at (QQmlListProperty * prop, int idx) { \ 79 | CLASS * instance = qobject_cast (prop->object); \ 80 | return (instance != NULL ? instance->m_##NAME.at (idx) : NULL); \ 81 | } \ 82 | QList get_##NAME##s (void) const { \ 83 | return m_##NAME; \ 84 | } \ 85 | private: \ 86 | QList m_##NAME; 87 | 88 | #define QML_ENUM_CLASS(name, ...) \ 89 | class name : public QObject { \ 90 | Q_GADGET \ 91 | public: \ 92 | enum Type { __VA_ARGS__ }; \ 93 | Q_ENUMS (Type) \ 94 | }; 95 | 96 | class QmlProperty : public QObject { Q_OBJECT }; // NOTE : to avoid "no suitable class found" MOC note 97 | 98 | #endif // QQMLHELPERS_H 99 | -------------------------------------------------------------------------------- /source/QtQmlTricks/src/qqmlmodels.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | #define NO_PARENT QModelIndex () 7 | #define BASE_ROLE Qt::UserRole 8 | #define EMPTY_STR QStringLiteral ("") 9 | #define EMPTY_BA QByteArrayLiteral ("") 10 | 11 | /*! 12 | \defgroup QT_QML_MODELS Qt models for QML 13 | 14 | Brings a bunch of nice, ready-to-use, C++ models for usual use-cases in C++/QML apps : 15 | \li Exposing a list of QObject-derived objects to QML while supporting dynamic changes 16 | \li Using a simple list of QVariant / QVariantMap just as easy as the plain QML ListModel item 17 | \li etc... 18 | */ 19 | -------------------------------------------------------------------------------- /source/QtQmlTricks/src/qqmlsvgiconhelper.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "qqmlsvgiconhelper.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | QString QQmlSvgIconHelper::s_basePath; 15 | QString QQmlSvgIconHelper::s_cachePath; 16 | QSvgRenderer QQmlSvgIconHelper::s_renderer; 17 | 18 | QQmlSvgIconHelper::QQmlSvgIconHelper (QObject * parent) 19 | : QObject (parent) 20 | , m_size (0) 21 | , m_ready (false) 22 | , m_verticalRatio (1.0) 23 | , m_horizontalRatio (1.0) 24 | , m_color (Qt::transparent) 25 | , m_icon (QString ()) 26 | { 27 | if (s_basePath.isEmpty ()) { 28 | QQmlSvgIconHelper::s_basePath = qApp->applicationDirPath (); 29 | } 30 | if (s_cachePath.isEmpty ()) { 31 | QQmlSvgIconHelper::s_cachePath = (QDir::homePath () % "/.CachedSvgIcon/" % qApp->applicationName ()); 32 | } 33 | } 34 | 35 | QQmlSvgIconHelper::~QQmlSvgIconHelper (void) { 36 | 37 | } 38 | 39 | void QQmlSvgIconHelper::classBegin (void) { 40 | m_ready = false; 41 | } 42 | 43 | void QQmlSvgIconHelper::componentComplete (void) { 44 | m_ready = true; 45 | refresh (); 46 | } 47 | 48 | void QQmlSvgIconHelper::setTarget (const QQmlProperty & target) { 49 | m_property = target; 50 | refresh (); 51 | } 52 | 53 | void QQmlSvgIconHelper::setBasePath (const QString & basePath) { 54 | QQmlSvgIconHelper::s_basePath = basePath; 55 | } 56 | 57 | void QQmlSvgIconHelper::setCachePath (const QString & cachePath) { 58 | QQmlSvgIconHelper::s_cachePath = cachePath; 59 | } 60 | 61 | int QQmlSvgIconHelper::getSize (void) const { 62 | return m_size; 63 | } 64 | 65 | qreal QQmlSvgIconHelper::getVerticalRatio (void) const { 66 | return m_verticalRatio; 67 | } 68 | 69 | qreal QQmlSvgIconHelper::getHorizontalRatio (void) const { 70 | return m_horizontalRatio; 71 | } 72 | 73 | QColor QQmlSvgIconHelper::getColor (void) const { 74 | return m_color; 75 | } 76 | 77 | QString QQmlSvgIconHelper::getIcon (void) const { 78 | return m_icon; 79 | } 80 | 81 | void QQmlSvgIconHelper::setSize (int size) { 82 | if (m_size != size) { 83 | m_size = size; 84 | refresh (); 85 | emit sizeChanged (); 86 | } 87 | } 88 | 89 | void QQmlSvgIconHelper::setVerticalRatio (qreal ratio) { 90 | if (m_verticalRatio != ratio) { 91 | m_verticalRatio = ratio; 92 | refresh (); 93 | emit verticalRatioChanged (); 94 | } 95 | } 96 | 97 | void QQmlSvgIconHelper::setHorizontalRatio (qreal ratio) { 98 | if (m_horizontalRatio != ratio) { 99 | m_horizontalRatio = ratio; 100 | refresh (); 101 | emit horizontalRatioChanged (); 102 | } 103 | } 104 | 105 | void QQmlSvgIconHelper::setColor (QColor color) { 106 | if (m_color != color) { 107 | m_color = color; 108 | refresh (); 109 | emit colorChanged (); 110 | } 111 | } 112 | 113 | void QQmlSvgIconHelper::setIcon (QString icon) { 114 | if (m_icon != icon) { 115 | m_icon = icon; 116 | refresh (); 117 | emit iconChanged (); 118 | } 119 | } 120 | 121 | void QQmlSvgIconHelper::refresh (void) { 122 | if (m_ready) { 123 | QUrl url; 124 | if (!m_icon.isEmpty () && m_size > 0 && m_horizontalRatio > 0.0 && m_verticalRatio > 0.0) { 125 | QImage image (m_size * m_horizontalRatio, m_size * m_verticalRatio, QImage::Format_ARGB32); 126 | QString uri (m_icon 127 | % "?color=" % (m_color.isValid () ? m_color.name () : "none") 128 | % "&width=" % QString::number (image.width ()) 129 | % "&height=" % QString::number (image.height ())); 130 | QString hash (QCryptographicHash::hash (uri.toLocal8Bit (), QCryptographicHash::Md5).toHex ()); 131 | QString sourcePath (s_basePath % "/" % m_icon % ".svg"); 132 | QString cachedPath (s_cachePath % "/" % hash % ".png"); 133 | if (!QFile::exists (cachedPath)) { 134 | QPainter painter (&image); 135 | image.fill (Qt::transparent); 136 | painter.setRenderHint (QPainter::Antialiasing, true); 137 | painter.setRenderHint (QPainter::SmoothPixmapTransform, true); 138 | painter.setRenderHint (QPainter::HighQualityAntialiasing, true); 139 | if (QFile::exists (sourcePath)) { 140 | s_renderer.load (sourcePath); 141 | if (s_renderer.isValid ()) { 142 | s_renderer.render (&painter); 143 | if (m_color.isValid () && m_color.alpha () > 0) { 144 | QColor tmp (m_color); 145 | for (int x (0); x < image.width (); x++) { 146 | for (int y (0); y < image.height (); y++) { 147 | tmp.setAlpha (qAlpha (image.pixel (x, y))); 148 | image.setPixel (x, y, tmp.rgba ()); 149 | } 150 | } 151 | } 152 | QDir ().mkpath (s_cachePath); 153 | image.save (cachedPath, "PNG", 0); 154 | url = QUrl::fromLocalFile (cachedPath); 155 | } 156 | } 157 | else { 158 | qWarning () << ">>> QmlSvgIconHelper : Can't render" << sourcePath << ", no such file !"; 159 | } 160 | } 161 | else { 162 | url = QUrl::fromLocalFile (cachedPath); 163 | } 164 | } 165 | if (m_property.isValid () && m_property.isWritable ()) { 166 | m_property.write (url); 167 | } 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /source/QtQmlTricks/src/qqmlsvgiconhelper.h: -------------------------------------------------------------------------------- 1 | #ifndef QQMLSVGICONHELPER_H 2 | #define QQMLSVGICONHELPER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | class QQmlSvgIconHelper : public QObject, public QQmlParserStatus, public QQmlPropertyValueSource { 13 | Q_OBJECT 14 | Q_INTERFACES (QQmlParserStatus) 15 | Q_INTERFACES (QQmlPropertyValueSource) 16 | Q_PROPERTY (int size READ getSize WRITE setSize NOTIFY sizeChanged) 17 | Q_PROPERTY (qreal verticalRatio READ getVerticalRatio WRITE setVerticalRatio NOTIFY verticalRatioChanged) 18 | Q_PROPERTY (qreal horizontalRatio READ getHorizontalRatio WRITE setHorizontalRatio NOTIFY horizontalRatioChanged) 19 | Q_PROPERTY (QColor color READ getColor WRITE setColor NOTIFY colorChanged) 20 | Q_PROPERTY (QString icon READ getIcon WRITE setIcon NOTIFY iconChanged) 21 | 22 | public: 23 | explicit QQmlSvgIconHelper (QObject * parent = NULL); 24 | virtual ~QQmlSvgIconHelper (void); 25 | 26 | virtual void setTarget (const QQmlProperty & target); 27 | virtual void classBegin (void); 28 | virtual void componentComplete (void); 29 | 30 | static void setBasePath (const QString & basePath); 31 | static void setCachePath (const QString & cachePath); 32 | 33 | int getSize (void) const; 34 | qreal getVerticalRatio (void) const; 35 | qreal getHorizontalRatio (void) const; 36 | QColor getColor (void) const; 37 | QString getIcon (void) const; 38 | 39 | public slots: 40 | void setSize (int size); 41 | void setVerticalRatio (qreal ratio); 42 | void setHorizontalRatio (qreal ratio); 43 | void setColor (QColor color); 44 | void setIcon (QString icon); 45 | 46 | signals: 47 | void sizeChanged (void); 48 | void verticalRatioChanged (void); 49 | void horizontalRatioChanged (void); 50 | void colorChanged (void); 51 | void iconChanged (void); 52 | 53 | protected: 54 | void refresh (void); 55 | 56 | private: 57 | int m_size; 58 | bool m_ready; 59 | qreal m_verticalRatio; 60 | qreal m_horizontalRatio; 61 | QColor m_color; 62 | QString m_icon; 63 | 64 | QQmlProperty m_property; 65 | 66 | static QString s_basePath; 67 | static QString s_cachePath; 68 | static QSvgRenderer s_renderer; 69 | }; 70 | 71 | #endif // QQMLSVGICONHELPER_H 72 | -------------------------------------------------------------------------------- /source/QtQmlTricks/src/qqmlvariantlistmodel.h: -------------------------------------------------------------------------------- 1 | #ifndef QQMLVARIANTLISTMODEL_H 2 | #define QQMLVARIANTLISTMODEL_H 3 | 4 | #include "qqmlmodels.h" 5 | 6 | class QQmlVariantListModelPrivate; 7 | 8 | class QQmlVariantListModel : public QAbstractListModel { 9 | Q_OBJECT 10 | Q_PROPERTY (int count READ count NOTIFY countChanged) 11 | 12 | public: 13 | explicit QQmlVariantListModel (QObject * parent); 14 | virtual ~QQmlVariantListModel (); 15 | 16 | public: // QAbstractItemModel interface reimplemented 17 | virtual int rowCount (const QModelIndex & parent = QModelIndex ()) const; 18 | virtual bool setData (const QModelIndex & index, const QVariant & value, int role); 19 | virtual QVariant data (const QModelIndex & index, int role) const; 20 | virtual QHash roleNames () const; 21 | 22 | public slots: // public API 23 | void clear (); 24 | int count () const; 25 | bool isEmpty () const; 26 | void append (QVariant item); 27 | void prepend (QVariant item); 28 | void insert (int idx, QVariant item); 29 | void appendList (QVariantList itemList); 30 | void prependList (QVariantList itemList); 31 | void replace (int pos, QVariant item); 32 | void insertList (int idx, QVariantList itemList); 33 | void move (int idx, int pos); 34 | void remove (int idx); 35 | QVariant get (int idx) const; 36 | QVariantList list () const; 37 | 38 | signals: // notifiers 39 | void countChanged (int count); 40 | 41 | private: 42 | QQmlVariantListModelPrivate * m_privateImpl; 43 | }; 44 | 45 | #endif // QQMLVARIANTLISTMODEL_H 46 | -------------------------------------------------------------------------------- /source/QtQmlTricks/src/qqmlvariantlistmodel_p.h: -------------------------------------------------------------------------------- 1 | #ifndef QQMLVARIANTLISTMODEL_P_H 2 | #define QQMLVARIANTLISTMODEL_P_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | class QQmlVariantListModel; 14 | 15 | class QQmlVariantListModelPrivate : public QObject { 16 | Q_OBJECT 17 | 18 | public: 19 | explicit QQmlVariantListModelPrivate (QQmlVariantListModel * parent); 20 | 21 | void updateCounter (); 22 | 23 | int m_count; 24 | QVariantList m_items; 25 | QHash m_roles; 26 | QQmlVariantListModel * m_publicObject; 27 | }; 28 | 29 | 30 | #endif // QQMLVARIANTLISTMODEL_P_H 31 | -------------------------------------------------------------------------------- /source/QtQmlTricks/src/qquickpolygon.h: -------------------------------------------------------------------------------- 1 | #ifndef QMLPOLYGON_H 2 | #define QMLPOLYGON_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | class QQuickPolygon : public QQuickItem { 16 | Q_OBJECT 17 | Q_PROPERTY (bool closed READ getClosed WRITE setClosed NOTIFY closedChanged) // whether last point should connect to first 18 | Q_PROPERTY (qreal border READ getBorder WRITE setBorder NOTIFY borderChanged) // border width 19 | Q_PROPERTY (QColor color READ getColor WRITE setColor NOTIFY colorChanged) // back color 20 | Q_PROPERTY (QColor stroke READ getStroke WRITE setStroke NOTIFY strokeChanged) // border color 21 | Q_PROPERTY (QVariantList points READ getPoints WRITE setPoints NOTIFY pointsChanged) // points list 22 | 23 | public: 24 | explicit QQuickPolygon (QQuickItem * parent = NULL); 25 | 26 | Q_INVOKABLE bool getClosed (void) const; 27 | Q_INVOKABLE qreal getBorder (void) const; 28 | Q_INVOKABLE QColor getColor (void) const; 29 | Q_INVOKABLE QColor getStroke (void) const; 30 | Q_INVOKABLE QVariantList getPoints (void) const; 31 | 32 | public slots: 33 | void setClosed (bool closed); 34 | void setBorder (qreal border); 35 | void setColor (const QColor & color); 36 | void setStroke (const QColor & stroke); 37 | void setPoints (const QVariantList & points); 38 | 39 | signals: 40 | void colorChanged (void); 41 | void pointsChanged (void); 42 | void borderChanged (void); 43 | void closedChanged (void); 44 | void strokeChanged (void); 45 | 46 | protected: 47 | virtual QSGNode * updatePaintNode (QSGNode * oldNode, UpdatePaintNodeData * updatePaintNodeData); 48 | 49 | protected slots: 50 | void processTriangulation (void); 51 | 52 | private: 53 | bool m_closed; 54 | qreal m_border; 55 | qreal m_minX; 56 | qreal m_maxX; 57 | qreal m_minY; 58 | qreal m_maxY; 59 | QColor m_color; 60 | QColor m_stroke; 61 | QPolygonF m_points; 62 | QVector m_triangles; 63 | QSGNode * m_node; 64 | QSGGeometryNode * m_foreNode; 65 | QSGGeometryNode * m_backNode; 66 | QSGGeometry * m_foreGeometry; 67 | QSGGeometry * m_backGeometry; 68 | QSGFlatColorMaterial * m_foreMaterial; 69 | QSGFlatColorMaterial * m_backMaterial; 70 | }; 71 | 72 | #endif // QMLPOLYGON_H 73 | -------------------------------------------------------------------------------- /source/QtQmlTricks/src/qtbitstream.h: -------------------------------------------------------------------------------- 1 | #ifndef QTBITSTREAM_H 2 | #define QTBITSTREAM_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | // TODO : handle little/big endian 9 | 10 | // TODO : handle sign bit moves 11 | 12 | // NOTE : using template partial specialization + SFINAE to ensure compile-time type checking and no build error 13 | 14 | typedef unsigned int UInt; 15 | typedef unsigned char Byte; 16 | 17 | template class CheckInt { 18 | public: 19 | static const bool isInt = false; 20 | static bool testBit (T, UInt) { return false; } 21 | }; 22 | 23 | #define CheckInt_SPECIALIZE(TYPE) \ 24 | template<> class CheckInt { \ 25 | public: static const bool isInt = true; \ 26 | public: static bool testBit (TYPE src, UInt bit) { return ((src >> bit) & 0x1); } } 27 | 28 | CheckInt_SPECIALIZE (bool); 29 | CheckInt_SPECIALIZE (qint8); 30 | CheckInt_SPECIALIZE (qint16); 31 | CheckInt_SPECIALIZE (qint32); 32 | CheckInt_SPECIALIZE (qint64); 33 | CheckInt_SPECIALIZE (quint8); 34 | CheckInt_SPECIALIZE (quint16); 35 | CheckInt_SPECIALIZE (quint32); 36 | CheckInt_SPECIALIZE (quint64); 37 | 38 | class QtBitStream { 39 | public: 40 | explicit QtBitStream (QByteArray data) 41 | : m_len (data.size () * 8) 42 | , m_pos (0) 43 | , m_data (data) { 44 | if (!m_len) { 45 | qWarning () << "QtBitStream with an empty data buffer is useless, nothing can be done on it !"; 46 | } 47 | } 48 | 49 | QByteArray getData (void) const { 50 | return m_data; 51 | } 52 | 53 | UInt getPosition (void) const { 54 | return m_pos; 55 | } 56 | 57 | QString toBinary (bool blocks = true) const { 58 | QString ret; 59 | for (UInt bit = 0; bit < m_len; bit++) { 60 | if (blocks && bit % 8 == 0) { 61 | ret.append (' '); 62 | } 63 | ret.append (testBit (bit) ? '1' : '0'); 64 | } 65 | return ret; 66 | } 67 | 68 | bool testBit (UInt bit) const { 69 | Byte byte (m_data [bit / 8]); 70 | return ((byte >> (bit % 8)) & 0x1); 71 | } 72 | 73 | void setPosition (UInt pos) { 74 | m_pos = pos; 75 | } 76 | 77 | void setBit (UInt bit, bool value) { 78 | Byte byte = m_data [bit / 8]; 79 | if (value) { 80 | byte |= (1 << (bit % 8)); 81 | } 82 | else { 83 | byte &= ~(1 << (bit % 8)); 84 | } 85 | m_data [bit / 8] = byte; 86 | } 87 | 88 | template IntegerType readBits (UInt count, bool * ok = NULL) { 89 | IntegerType ret = 0; 90 | bool result = false; 91 | if (CheckInt::isInt) { 92 | if (m_pos + count < m_len && count <= (sizeof (ret) * 8)) { 93 | for (UInt bit = 0; bit < count; bit++, m_pos++) { 94 | if (testBit (m_pos)) { 95 | ret |= (IntegerType)(1 << bit); 96 | } 97 | else { 98 | ret &= (IntegerType)~(1 << bit); 99 | } 100 | } 101 | result = true; 102 | } 103 | } 104 | else { 105 | qWarning () << "QtBitStream::readBits MUST be used with bool / int8 / int16 / int32 / int64 types only !"; 106 | } 107 | if (ok != NULL) { 108 | *ok = result; 109 | } 110 | return ret; 111 | } 112 | 113 | template void writeBits (IntegerType src, UInt count, bool * ok = NULL) { 114 | bool result = false; 115 | if (CheckInt::isInt) { 116 | if (m_pos + count < m_len && count <= (sizeof (src) * 8)) { 117 | for (UInt bit = 0; bit < count; bit++, m_pos++) { 118 | setBit (m_pos, CheckInt::testBit (src, bit)); 119 | } 120 | result = true; 121 | } 122 | } 123 | else { 124 | qWarning () << "QtBitStream::writeBits MUST be used with bool / int8 / int16 / int32 / int64 types only !"; 125 | } 126 | if (ok != NULL) { 127 | *ok = result; 128 | } 129 | } 130 | 131 | private: 132 | UInt m_len, m_pos; 133 | QByteArray m_data; 134 | }; 135 | 136 | #endif // QTBITSTREAM_H 137 | -------------------------------------------------------------------------------- /source/QtQmlTricks/src/qtcobs.h: -------------------------------------------------------------------------------- 1 | #ifndef QTCOBS_H 2 | #define QTCOBS_H 3 | 4 | #include 5 | 6 | class QtCOBS { 7 | public: 8 | static QByteArray encode (const QByteArray & rawData) { 9 | QByteArray encodedData; 10 | quint8 code = 0x01; 11 | int readIndex = 0; 12 | int writeIndex = 1; 13 | int codeIndex = 0; 14 | const int len = rawData.size (); 15 | while (readIndex < len) { 16 | if (rawData [readIndex] == 0x00) { 17 | encodedData [codeIndex] = code; 18 | code = 0x01; 19 | codeIndex = writeIndex++; 20 | readIndex++; 21 | } 22 | else { 23 | encodedData [writeIndex++] = rawData [readIndex++]; 24 | code++; 25 | if (code == 0xFF) { 26 | encodedData [codeIndex] = code; 27 | code = 0x01; 28 | codeIndex = writeIndex++; 29 | } 30 | } 31 | } 32 | encodedData [codeIndex] = code; 33 | return encodedData; 34 | } 35 | static QByteArray decode (const QByteArray & cobsData) { 36 | QByteArray decodedData; 37 | quint8 code; 38 | int readIndex = 0; 39 | int writeIndex = 0; 40 | const int len = cobsData.size (); 41 | while (readIndex < len) { 42 | code = cobsData [readIndex]; 43 | if (readIndex + code > len && code != 0x01) { 44 | decodedData.clear (); 45 | break; 46 | } 47 | readIndex++; 48 | for (quint8 pos = 1; pos < code; pos++) { 49 | decodedData [writeIndex++] = cobsData [readIndex++]; 50 | } 51 | if (code != 0xFF && readIndex != len) { 52 | decodedData [writeIndex++] = 0x00; 53 | } 54 | } 55 | return decodedData; 56 | } 57 | }; 58 | 59 | #endif // QTCOBS_H 60 | -------------------------------------------------------------------------------- /source/QtQmlTricks/src/qtjsonpath.h: -------------------------------------------------------------------------------- 1 | #ifndef QTJSONPATH 2 | #define QTJSONPATH 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | class QtJsonPath { 13 | public: 14 | explicit QtJsonPath (QJsonValue & jsonVal) { 15 | QJsonObject jsonObj = jsonVal.toObject (); 16 | if (!jsonObj.isEmpty ()) { 17 | initWithNode (jsonObj); 18 | } 19 | else { 20 | QJsonArray jsonArray = jsonVal.toArray (); 21 | if (!jsonArray.isEmpty ()) { 22 | initWithNode (jsonArray); 23 | } 24 | else { } 25 | } 26 | } 27 | 28 | explicit QtJsonPath (QJsonObject & jsonObj) { 29 | initWithNode (jsonObj); 30 | } 31 | 32 | explicit QtJsonPath (QJsonArray & jsonArray) { 33 | initWithNode (jsonArray); 34 | } 35 | 36 | explicit QtJsonPath (QJsonDocument & jsonDoc) { 37 | QJsonObject jsonObj = jsonDoc.object (); 38 | if (!jsonObj.isEmpty ()) { 39 | initWithNode (jsonObj); 40 | } 41 | else { 42 | QJsonArray jsonArray = jsonDoc.array (); 43 | if (!jsonArray.isEmpty ()) { 44 | initWithNode (jsonArray); 45 | } 46 | else { } 47 | } 48 | } 49 | 50 | QVariant getValue (QString path, QVariant fallback = QVariant ()) const { 51 | QVariant ret; 52 | QStringList list = path.split ('/', QString::SkipEmptyParts); 53 | if (!list.empty () && !m_rootNode.isUndefined () && !m_rootNode.isNull ()) { 54 | QJsonValue currNode = m_rootNode; 55 | bool error = false; 56 | const unsigned int len = list.size (); 57 | for (unsigned int depth = 0; (depth < len) && (!error); depth++) { 58 | QString part = list.at (depth); 59 | bool isNum = false; 60 | int index = part.toInt (&isNum, 10); 61 | if (isNum) { // NOTE : array subpath 62 | if (currNode.isArray ()) { 63 | QJsonArray arrayNode = currNode.toArray (); 64 | if (index < arrayNode.size ()) { 65 | currNode = arrayNode.at (index); 66 | } 67 | else { error = true; } 68 | } 69 | else { error = true; } 70 | } 71 | else { // NOTE : object subpath 72 | if (currNode.isObject ()) { 73 | QJsonObject objNode = currNode.toObject (); 74 | if (objNode.contains (part)) { 75 | currNode = objNode.value (part); 76 | } 77 | else { error = true; } 78 | } 79 | else { error = true; } 80 | } 81 | } 82 | ret = (!error ? currNode.toVariant () : fallback); 83 | } 84 | return ret; 85 | } 86 | 87 | protected: 88 | void initWithNode (QJsonValue jsonNode) { 89 | m_rootNode = jsonNode; 90 | } 91 | 92 | private: 93 | QJsonValue m_rootNode; 94 | }; 95 | 96 | #endif // QTJSONPATH 97 | 98 | -------------------------------------------------------------------------------- /source/SSGContextPlugin/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | # 3 | # Copyright (c) 2016 Erik Hvatum 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 | # 23 | # Authors: Erik Hvatum 24 | 25 | project(SSGContextPlugin) 26 | 27 | set(SOURCE_FILES 28 | ../common.h 29 | SSGContext.h 30 | SSGContext.cpp 31 | SSGContextPlugin.h 32 | SSGContextPlugin.cpp 33 | SSGQuickLayer.h 34 | SSGQuickLayer.cpp) 35 | set(LIBRARIES 36 | ${OPENGL_LIBRARIES} 37 | ${FREEIMAGE_LIBRARY} 38 | ${FREEIMAGEPLUS_LIBRARY}) 39 | 40 | add_library(SSGContextPlugin SHARED ${SOURCE_FILES}) 41 | qt5_use_modules(SSGContextPlugin Core Gui Qml OpenGL Quick Widgets) 42 | -------------------------------------------------------------------------------- /source/SSGContextPlugin/SSGContext.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** (C) 2016 Erik Hvatum 4 | ** 5 | ** $QT_BEGIN_LICENSE:LGPL21$ 6 | ** Commercial License Usage 7 | ** Licensees holding valid commercial Qt licenses may use this file in 8 | ** accordance with the commercial license agreement provided with the 9 | ** Software or, alternatively, in accordance with the terms contained in 10 | ** a written agreement between you and The Qt Company. For licensing terms 11 | ** and conditions see http://www.qt.io/terms-conditions. For further 12 | ** information use the contact form at http://www.qt.io/contact-us. 13 | ** 14 | ** GNU Lesser General Public License Usage 15 | ** Alternatively, this file may be used under the terms of the GNU Lesser 16 | ** General Public License version 2.1 or version 3 as published by the Free 17 | ** Software Foundation and appearing in the file LICENSE.LGPLv21 and 18 | ** LICENSE.LGPLv3 included in the packaging of this file. Please review the 19 | ** following information to ensure the GNU Lesser General Public License 20 | ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and 21 | ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 | ** 23 | ** As a special exception, The Qt Company gives you certain additional 24 | ** rights. These rights are described in The Qt Company LGPL Exception 25 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 26 | ** 27 | ** $QT_END_LICENSE$ 28 | ** 29 | ****************************************************************************/ 30 | 31 | #include 32 | #include 33 | #include "SSGContext.h" 34 | #include "SSGQuickLayer.h" 35 | 36 | SSGContext::SSGContext(QObject* parent) 37 | : QSGContext(parent) 38 | { 39 | } 40 | 41 | QSGImageNode* SSGContext::createImageNode() 42 | { 43 | qDebug() << "QSGImageNode* SSGContext::createImageNode()"; 44 | return QSGContext::createImageNode(); 45 | } 46 | 47 | QSGLayer* SSGContext::createLayer(QSGRenderContext* renderContext) 48 | { 49 | qDebug() << "QSGLayer* SSGContext::createLayer(QSGRenderContext* renderContext)"; 50 | return new SSGQuickLayer(renderContext); 51 | // return QSGContext::createLayer(renderContext); 52 | } 53 | -------------------------------------------------------------------------------- /source/SSGContextPlugin/SSGContext.h: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2016 Erik Hvatum 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 | // 23 | // Authors: Erik Hvatum 24 | 25 | #pragma once 26 | 27 | class QSGContext; 28 | class QSGLayer; 29 | 30 | class SSGContext 31 | : public QSGContext 32 | { 33 | public: 34 | explicit SSGContext(QObject* parent=nullptr); 35 | 36 | QSGImageNode* createImageNode() override; 37 | QSGLayer* createLayer(QSGRenderContext* renderContext) override; 38 | }; 39 | -------------------------------------------------------------------------------- /source/SSGContextPlugin/SSGContextPlugin.cpp: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2016 Erik Hvatum 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 | // 23 | // Authors: Erik Hvatum 24 | 25 | #include "SSGContextPlugin.h" 26 | #include "SSGContext.h" 27 | 28 | SSGContextPlugin::SSGContextPlugin(QObject* parent) 29 | : QObject(parent) 30 | { 31 | qDebug() << "SSGContextPlugin loaded"; 32 | } 33 | 34 | QStringList SSGContextPlugin::keys() const 35 | { 36 | // This never seems to be invoked. Perhaps it is vestigial? It does appear to be 37 | // redundant, given that the json metadata file contains a "Keys" entry. 38 | QStringList ret; 39 | ret << "SSGContextPlugin"; 40 | return ret; 41 | } 42 | 43 | QSGContext* SSGContextPlugin::create(const QString& key) const 44 | { 45 | return (key == "SSGContextPlugin") ? new SSGContext() : nullptr; 46 | } 47 | -------------------------------------------------------------------------------- /source/SSGContextPlugin/SSGContextPlugin.h: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2016 Erik Hvatum 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 | // 23 | // Authors: Erik Hvatum 24 | 25 | #pragma once 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | struct QSGContextFactoryInterface; 32 | 33 | class SSGContextPlugin 34 | : public QObject, 35 | public QSGContextFactoryInterface 36 | { 37 | Q_OBJECT 38 | Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QSGContextFactoryInterface" FILE "SSGContextPlugin.json") 39 | Q_INTERFACES(QSGContextFactoryInterface:QFactoryInterface) 40 | 41 | public: 42 | explicit SSGContextPlugin(QObject* parent=nullptr); 43 | 44 | QSGContext* create(const QString& key) const override; 45 | QStringList keys() const override; 46 | virtual QQuickTextureFactory *createTextureFactoryFromImage(const QImage &) override { return 0; } 47 | virtual QSGRenderLoop *createWindowManager() override { return 0; } 48 | }; 49 | -------------------------------------------------------------------------------- /source/SSGContextPlugin/SSGContextPlugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "Keys" : [ "SSGContextPlugin" ] 3 | } 4 | -------------------------------------------------------------------------------- /source/SSGContextPlugin/SSGQuickLayer.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Portions (C) 2015 The Qt Company Ltd. 4 | ** Portions (C) 2016 Erik Hvatum 5 | ** Contact: http://www.qt.io/licensing/ 6 | ** 7 | ** This file is part of the QtQuick module of the Qt Toolkit. 8 | ** 9 | ** $QT_BEGIN_LICENSE:LGPL21$ 10 | ** Commercial License Usage 11 | ** Licensees holding valid commercial Qt licenses may use this file in 12 | ** accordance with the commercial license agreement provided with the 13 | ** Software or, alternatively, in accordance with the terms contained in 14 | ** a written agreement between you and The Qt Company. For licensing terms 15 | ** and conditions see http://www.qt.io/terms-conditions. For further 16 | ** information use the contact form at http://www.qt.io/contact-us. 17 | ** 18 | ** GNU Lesser General Public License Usage 19 | ** Alternatively, this file may be used under the terms of the GNU Lesser 20 | ** General Public License version 2.1 or version 3 as published by the Free 21 | ** Software Foundation and appearing in the file LICENSE.LGPLv21 and 22 | ** LICENSE.LGPLv3 included in the packaging of this file. Please review the 23 | ** following information to ensure the GNU Lesser General Public License 24 | ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and 25 | ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 26 | ** 27 | ** As a special exception, The Qt Company gives you certain additional 28 | ** rights. These rights are described in The Qt Company LGPL Exception 29 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 30 | ** 31 | ** $QT_END_LICENSE$ 32 | ** 33 | ****************************************************************************/ 34 | 35 | // NB: SSGQuickLayer is *not* the scene graph personality of an SSLayer. SSGQuickLayer replaces QSGDefaultLayer, 36 | // the thing that is created when a QML Item's .layer property is set to true. 37 | 38 | #pragma once 39 | #include 40 | #include 41 | #include 42 | 43 | #define QSG_DEBUG_FBO_OVERLAY 44 | 45 | class SSGQuickLayer 46 | : public QSGLayer 47 | { 48 | Q_OBJECT 49 | public: 50 | SSGQuickLayer(QSGRenderContext *context); 51 | ~SSGQuickLayer(); 52 | 53 | bool updateTexture() override; 54 | 55 | // The item's "paint node", not effect node. 56 | QSGNode *item() const { return m_item; } 57 | void setItem(QSGNode *item) override; 58 | 59 | QRectF rect() const { return m_rect; } 60 | void setRect(const QRectF &rect) override; 61 | 62 | QSize size() const { return m_size; } 63 | void setSize(const QSize &size) override; 64 | 65 | void setHasMipmaps(bool mipmap) override; 66 | 67 | void bind() override; 68 | 69 | bool hasAlphaChannel() const override; 70 | bool hasMipmaps() const override; 71 | int textureId() const override; 72 | QSize textureSize() const override { return m_size; } 73 | 74 | GLenum format() const { return m_format; } 75 | void setFormat(GLenum format) override; 76 | 77 | bool live() const { return bool(m_live); } 78 | void setLive(bool live) override; 79 | 80 | bool recursive() const { return bool(m_recursive); } 81 | void setRecursive(bool recursive) override; 82 | 83 | void setDevicePixelRatio(qreal ratio) override { m_device_pixel_ratio = ratio; } 84 | 85 | bool mirrorHorizontal() const { return bool(m_mirrorHorizontal); } 86 | void setMirrorHorizontal(bool mirror) override; 87 | 88 | bool mirrorVertical() const { return bool(m_mirrorVertical); } 89 | void setMirrorVertical(bool mirror) override; 90 | 91 | void scheduleUpdate() override; 92 | 93 | QImage toImage() const override; 94 | 95 | QRectF normalizedTextureSubRect() const override; 96 | 97 | public Q_SLOTS: 98 | void markDirtyTexture() override; 99 | void invalidated() override; 100 | 101 | protected: 102 | void grab(); 103 | 104 | QSGNode *m_item; 105 | QRectF m_rect; 106 | QSize m_size; 107 | qreal m_device_pixel_ratio; 108 | GLenum m_format; 109 | 110 | QSGRenderer *m_renderer; 111 | QOpenGLFramebufferObject *m_fbo; 112 | QOpenGLFramebufferObject *m_secondaryFbo; 113 | QSharedPointer m_depthStencilBuffer; 114 | 115 | GLuint m_transparentTexture; 116 | 117 | #ifdef QSG_DEBUG_FBO_OVERLAY 118 | QSGSimpleRectNode *m_debugOverlay; 119 | #endif 120 | 121 | QSGRenderContext *m_context; 122 | 123 | uint m_mipmap : 1; 124 | uint m_live : 1; 125 | uint m_recursive : 1; 126 | uint m_dirtyTexture : 1; 127 | uint m_multisamplingChecked : 1; 128 | uint m_multisampling : 1; 129 | uint m_grab : 1; 130 | uint m_mirrorHorizontal : 1; 131 | uint m_mirrorVertical : 1; 132 | }; 133 | -------------------------------------------------------------------------------- /source/SSGSimpleTextureNode.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Portions (C) 2015 The Qt Company Ltd. 4 | ** Portions (C) 2016 Erik Hvatum 5 | ** Contact: http://www.qt.io/licensing/ 6 | ** 7 | ** This file is part of the QtQuick module of the Qt Toolkit. 8 | ** 9 | ** $QT_BEGIN_LICENSE:LGPL21$ 10 | ** Commercial License Usage 11 | ** Licensees holding valid commercial Qt licenses may use this file in 12 | ** accordance with the commercial license agreement provided with the 13 | ** Software or, alternatively, in accordance with the terms contained in 14 | ** a written agreement between you and The Qt Company. For licensing terms 15 | ** and conditions see http://www.qt.io/terms-conditions. For further 16 | ** information use the contact form at http://www.qt.io/contact-us. 17 | ** 18 | ** GNU Lesser General Public License Usage 19 | ** Alternatively, this file may be used under the terms of the GNU Lesser 20 | ** General Public License version 2.1 or version 3 as published by the Free 21 | ** Software Foundation and appearing in the file LICENSE.LGPLv21 and 22 | ** LICENSE.LGPLv3 included in the packaging of this file. Please review the 23 | ** following information to ensure the GNU Lesser General Public License 24 | ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and 25 | ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 26 | ** 27 | ** As a special exception, The Qt Company gives you certain additional 28 | ** rights. These rights are described in The Qt Company LGPL Exception 29 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 30 | ** 31 | ** $QT_END_LICENSE$ 32 | ** 33 | ****************************************************************************/ 34 | 35 | #pragma once 36 | #include "common.h" 37 | #include "SSGTexture.h" 38 | #include "SSGTextureMaterial.h" 39 | 40 | class SSGSimpleTextureNodePrivate; 41 | 42 | class Q_QUICK_EXPORT SSGSimpleTextureNode 43 | : public QSGGeometryNode 44 | { 45 | public: 46 | SSGSimpleTextureNode(); 47 | ~SSGSimpleTextureNode(); 48 | 49 | void setRect(const QRectF &rect); 50 | inline void setRect(qreal x, qreal y, qreal w, qreal h) { setRect(QRectF(x, y, w, h)); } 51 | QRectF rect() const; 52 | 53 | void setSourceRect(const QRectF &r); 54 | inline void setSourceRect(qreal x, qreal y, qreal w, qreal h) { setSourceRect(QRectF(x, y, w, h)); } 55 | QRectF sourceRect() const; 56 | 57 | void setTexture(SSGTexture *texture); 58 | SSGTexture *texture() const; 59 | 60 | void setMinFiltering(SSGTexture::Filtering filtering); 61 | SSGTexture::Filtering minFiltering() const; 62 | 63 | void setMagFiltering(SSGTexture::Filtering filtering); 64 | SSGTexture::Filtering magFiltering() const; 65 | 66 | enum TextureCoordinatesTransformFlag { 67 | NoTransform = 0x00, 68 | MirrorHorizontally = 0x01, 69 | MirrorVertically = 0x02 70 | }; 71 | Q_DECLARE_FLAGS(TextureCoordinatesTransformMode, TextureCoordinatesTransformFlag) 72 | 73 | void setTextureCoordinatesTransform(TextureCoordinatesTransformMode mode); 74 | TextureCoordinatesTransformMode textureCoordinatesTransform() const; 75 | 76 | void setOwnsTexture(bool owns); 77 | bool ownsTexture() const; 78 | 79 | protected: 80 | QSGGeometry m_geometry; 81 | SSGTextureMaterial m_material; 82 | bool m_ownsTexture; 83 | TextureCoordinatesTransformMode m_texCoordMode; 84 | QRectF m_rect; 85 | QRectF m_sourceRect; 86 | 87 | private: 88 | Q_DECLARE_PRIVATE(SSGSimpleTextureNode) 89 | }; 90 | 91 | Q_DECLARE_OPERATORS_FOR_FLAGS(SSGSimpleTextureNode::TextureCoordinatesTransformMode) 92 | -------------------------------------------------------------------------------- /source/SSGTexture.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Portions (C) 2015 The Qt Company Ltd. 4 | ** Portions (C) 2016 Erik Hvatum 5 | ** Contact: http://www.qt.io/licensing/ 6 | ** 7 | ** This file is part of the QtQuick module of the Qt Toolkit. 8 | ** 9 | ** $QT_BEGIN_LICENSE:LGPL21$ 10 | ** Commercial License Usage 11 | ** Licensees holding valid commercial Qt licenses may use this file in 12 | ** accordance with the commercial license agreement provided with the 13 | ** Software or, alternatively, in accordance with the terms contained in 14 | ** a written agreement between you and The Qt Company. For licensing terms 15 | ** and conditions see http://www.qt.io/terms-conditions. For further 16 | ** information use the contact form at http://www.qt.io/contact-us. 17 | ** 18 | ** GNU Lesser General Public License Usage 19 | ** Alternatively, this file may be used under the terms of the GNU Lesser 20 | ** General Public License version 2.1 or version 3 as published by the Free 21 | ** Software Foundation and appearing in the file LICENSE.LGPLv21 and 22 | ** LICENSE.LGPLv3 included in the packaging of this file. Please review the 23 | ** following information to ensure the GNU Lesser General Public License 24 | ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and 25 | ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 26 | ** 27 | ** As a special exception, The Qt Company gives you certain additional 28 | ** rights. These rights are described in The Qt Company LGPL Exception 29 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 30 | ** 31 | ** $QT_END_LICENSE$ 32 | ** 33 | ****************************************************************************/ 34 | 35 | #pragma once 36 | #include "common.h" 37 | #include "SSImage.h" 38 | 39 | class SSGTexture 40 | : public QObject 41 | { 42 | Q_OBJECT 43 | public: 44 | struct ComponentCountFormats { 45 | QOpenGLTexture::TextureFormat texFormat; 46 | QOpenGLTexture::PixelFormat srcPixelFormat; 47 | }; 48 | static const ComponentCountFormats sm_componentCountFormats[]; 49 | static const QOpenGLTexture::PixelType sm_componentPixelTypes[]; 50 | 51 | enum WrapMode { 52 | Repeat, 53 | ClampToEdge 54 | }; 55 | 56 | enum Filtering { 57 | None, 58 | Nearest, 59 | Linear 60 | }; 61 | 62 | SSGTexture(); 63 | virtual ~SSGTexture(); 64 | 65 | void setOwnsTexture(bool owns) { m_owns_texture = owns; } 66 | bool ownsTexture() const { return m_owns_texture; } 67 | 68 | void setTextureId(int id); 69 | int textureId() const; 70 | inline void setTextureSize(const QSize &size) { m_texture_size = size; } 71 | inline QSize textureSize() const { return m_texture_size; } 72 | inline bool hasAlphaChannel() const { return m_has_alpha; } 73 | inline bool hasMipmaps() const { return minMipmapFiltering() != SSGTexture::None || magMipmapFiltering() != SSGTexture::None; } 74 | inline QRectF normalizedTextureSubRect() const { return QRectF(0, 0, 1, 1); } 75 | QRectF convertToNormalizedSourceRect(const QRectF &rect) const; 76 | 77 | void setImage(SSImage* image); 78 | SSImage* image() { return m_image.data(); } 79 | 80 | virtual void bind(); 81 | virtual void updateBindOptions(bool force=false); 82 | 83 | void setMinMipmapFiltering(Filtering filter); 84 | SSGTexture::Filtering minMipmapFiltering() const; 85 | 86 | void setMagMipmapFiltering(Filtering filter); 87 | SSGTexture::Filtering magMipmapFiltering() const; 88 | 89 | void setMinFiltering(Filtering filter); 90 | SSGTexture::Filtering minFiltering() const; 91 | 92 | void setMagFiltering(Filtering filter); 93 | SSGTexture::Filtering magFiltering() const; 94 | 95 | void setHorizontalWrapMode(WrapMode hwrap); 96 | SSGTexture::WrapMode horizontalWrapMode() const; 97 | 98 | void setVerticalWrapMode(WrapMode vwrap); 99 | SSGTexture::WrapMode verticalWrapMode() const; 100 | 101 | static SSGTexture *fromImage(SSImage* image); 102 | 103 | protected: 104 | QSharedPointer m_image; 105 | 106 | uint m_wrapChanged : 1; 107 | uint m_filteringChanged : 1; 108 | 109 | uint m_horizontalWrap : 1; 110 | uint m_verticalWrap : 1; 111 | uint m_minMipmapMode : 2; 112 | uint m_magMipmapMode : 2; 113 | uint m_minFilterMode : 2; 114 | uint m_magFilterMode : 2; 115 | 116 | GLuint m_texture_id; 117 | QSize m_texture_size; 118 | QRectF m_texture_rect; 119 | 120 | uint m_has_alpha : 1; 121 | uint m_dirty_texture : 1; 122 | uint m_dirty_bind_options : 1; 123 | uint m_owns_texture : 1; 124 | uint m_mipmaps_generated : 1; 125 | uint m_retain_image: 1; 126 | }; 127 | 128 | bool ssg_safeguard_texture(SSGTexture *); 129 | -------------------------------------------------------------------------------- /source/SSGTextureMaterial.cpp: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Portions (C) 2015 The Qt Company Ltd. 4 | ** Portions (C) 2016 Erik Hvatum 5 | ** Contact: http://www.qt.io/licensing/ 6 | ** 7 | ** This file is part of the QtQuick module of the Qt Toolkit. 8 | ** 9 | ** $QT_BEGIN_LICENSE:LGPL21$ 10 | ** Commercial License Usage 11 | ** Licensees holding valid commercial Qt licenses may use this file in 12 | ** accordance with the commercial license agreement provided with the 13 | ** Software or, alternatively, in accordance with the terms contained in 14 | ** a written agreement between you and The Qt Company. For licensing terms 15 | ** and conditions see http://www.qt.io/terms-conditions. For further 16 | ** information use the contact form at http://www.qt.io/contact-us. 17 | ** 18 | ** GNU Lesser General Public License Usage 19 | ** Alternatively, this file may be used under the terms of the GNU Lesser 20 | ** General Public License version 2.1 or version 3 as published by the Free 21 | ** Software Foundation and appearing in the file LICENSE.LGPLv21 and 22 | ** LICENSE.LGPLv3 included in the packaging of this file. Please review the 23 | ** following information to ensure the GNU Lesser General Public License 24 | ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and 25 | ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 26 | ** 27 | ** As a special exception, The Qt Company gives you certain additional 28 | ** rights. These rights are described in The Qt Company LGPL Exception 29 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 30 | ** 31 | ** $QT_END_LICENSE$ 32 | ** 33 | ****************************************************************************/ 34 | 35 | #include "SSGTextureMaterial.h" 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | class SSGTextureMaterialShader : public QSGMaterialShader 43 | { 44 | public: 45 | SSGTextureMaterialShader(); 46 | 47 | virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect); 48 | virtual char const *const *attributeNames() const; 49 | 50 | static QSGMaterialType type; 51 | 52 | protected: 53 | virtual void initialize(); 54 | 55 | int m_matrix_id; 56 | int m_opacity_id; 57 | }; 58 | 59 | inline static bool isPowerOfTwo(int x) 60 | { 61 | // Assumption: x >= 1 62 | return x == (x & -x); 63 | } 64 | 65 | QSGMaterialType SSGTextureMaterialShader::type; 66 | 67 | SSGTextureMaterialShader::SSGTextureMaterialShader() 68 | : QSGMaterialShader() 69 | { 70 | setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qt-project.org/scenegraph/shaders/opaquetexture.vert")); 71 | setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/scenegraph/shaders/texture.frag")); 72 | } 73 | 74 | char const *const *SSGTextureMaterialShader::attributeNames() const 75 | { 76 | static char const *const attr[] = { "qt_VertexPosition", "qt_VertexTexCoord", 0 }; 77 | return attr; 78 | } 79 | 80 | void SSGTextureMaterialShader::initialize() 81 | { 82 | m_matrix_id = program()->uniformLocation("qt_Matrix"); 83 | m_opacity_id = program()->uniformLocation("opacity"); 84 | } 85 | 86 | void SSGTextureMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) 87 | { 88 | Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type()); 89 | SSGTextureMaterial *tx = static_cast(newEffect); 90 | SSGTextureMaterial *oldTx = static_cast(oldEffect); 91 | 92 | if (state.isOpacityDirty()) 93 | program()->setUniformValue(m_opacity_id, state.opacity()); 94 | 95 | SSGTexture *t = tx->texture(); 96 | 97 | #ifndef QT_NO_DEBUG 98 | if (!ssg_safeguard_texture(t)) 99 | return; 100 | #endif 101 | 102 | t->setMinFiltering(tx->minFiltering()); 103 | t->setMagFiltering(tx->magFiltering()); 104 | 105 | t->setHorizontalWrapMode(tx->horizontalWrapMode()); 106 | t->setVerticalWrapMode(tx->verticalWrapMode()); 107 | bool npotSupported = const_cast(state.context()) 108 | ->functions()->hasOpenGLFeature(QOpenGLFunctions::NPOTTextureRepeat); 109 | if (!npotSupported) { 110 | QSize size = t->textureSize(); 111 | const bool isNpot = !isPowerOfTwo(size.width()) || !isPowerOfTwo(size.height()); 112 | if (isNpot) { 113 | t->setHorizontalWrapMode(SSGTexture::ClampToEdge); 114 | t->setVerticalWrapMode(SSGTexture::ClampToEdge); 115 | } 116 | } 117 | 118 | t->setMinMipmapFiltering(tx->minMipmapFiltering()); 119 | t->setMagMipmapFiltering(tx->magMipmapFiltering()); 120 | 121 | if (oldTx == 0 || oldTx->texture()->textureId() != t->textureId()) 122 | t->bind(); 123 | else 124 | t->updateBindOptions(); 125 | 126 | if (state.isMatrixDirty()) 127 | program()->setUniformValue(m_matrix_id, state.combinedMatrix()); 128 | } 129 | 130 | SSGTextureMaterial::SSGTextureMaterial() 131 | : m_texture(0), 132 | m_min_filtering(SSGTexture::Nearest), 133 | m_mag_filtering(SSGTexture::Nearest), 134 | m_min_mipmap_filtering(SSGTexture::None), 135 | m_mag_mipmap_filtering(SSGTexture::None), 136 | m_horizontal_wrap(SSGTexture::ClampToEdge), 137 | m_vertical_wrap(SSGTexture::ClampToEdge) 138 | { 139 | } 140 | 141 | QSGMaterialType *SSGTextureMaterial::type() const 142 | { 143 | return &SSGTextureMaterialShader::type; 144 | } 145 | 146 | QSGMaterialShader *SSGTextureMaterial::createShader() const 147 | { 148 | return new SSGTextureMaterialShader(); 149 | } 150 | 151 | void SSGTextureMaterial::setTexture(SSGTexture *texture) 152 | { 153 | m_texture = texture; 154 | setFlag(Blending, m_texture ? m_texture->hasAlphaChannel() : false); 155 | } 156 | 157 | int SSGTextureMaterial::compare(const QSGMaterial *o) const 158 | { 159 | Q_ASSERT(o && type() == o->type()); 160 | qDebug() << "int SSGTextureMaterial::compare(const QSGMaterial *o) const"; 161 | const SSGTextureMaterial *other = static_cast(o); 162 | int diff = m_texture->textureId() - other->texture()->textureId(); 163 | if (diff) 164 | return diff; 165 | diff = int(m_min_filtering) - int(other->m_min_filtering); 166 | if (diff) 167 | return diff; 168 | return int(m_mag_filtering) - int(other->m_mag_filtering); 169 | } 170 | 171 | -------------------------------------------------------------------------------- /source/SSGTextureMaterial.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Portions (C) 2015 The Qt Company Ltd. 4 | ** Portions (C) 2016 Erik Hvatum 5 | ** Contact: http://www.qt.io/licensing/ 6 | ** 7 | ** This file is part of the QtQuick module of the Qt Toolkit. 8 | ** 9 | ** $QT_BEGIN_LICENSE:LGPL21$ 10 | ** Commercial License Usage 11 | ** Licensees holding valid commercial Qt licenses may use this file in 12 | ** accordance with the commercial license agreement provided with the 13 | ** Software or, alternatively, in accordance with the terms contained in 14 | ** a written agreement between you and The Qt Company. For licensing terms 15 | ** and conditions see http://www.qt.io/terms-conditions. For further 16 | ** information use the contact form at http://www.qt.io/contact-us. 17 | ** 18 | ** GNU Lesser General Public License Usage 19 | ** Alternatively, this file may be used under the terms of the GNU Lesser 20 | ** General Public License version 2.1 or version 3 as published by the Free 21 | ** Software Foundation and appearing in the file LICENSE.LGPLv21 and 22 | ** LICENSE.LGPLv3 included in the packaging of this file. Please review the 23 | ** following information to ensure the GNU Lesser General Public License 24 | ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and 25 | ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 26 | ** 27 | ** As a special exception, The Qt Company gives you certain additional 28 | ** rights. These rights are described in The Qt Company LGPL Exception 29 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 30 | ** 31 | ** $QT_END_LICENSE$ 32 | ** 33 | ****************************************************************************/ 34 | 35 | #pragma once 36 | #include "common.h" 37 | #include "SSGTexture.h" 38 | 39 | class SSGTextureMaterial 40 | : public QSGMaterial 41 | { 42 | public: 43 | SSGTextureMaterial(); 44 | 45 | virtual QSGMaterialType *type() const; 46 | virtual QSGMaterialShader *createShader() const; 47 | virtual int compare(const QSGMaterial *other) const; 48 | 49 | void setTexture(SSGTexture *texture); 50 | SSGTexture *texture() const { return m_texture; } 51 | 52 | void setMinFiltering(SSGTexture::Filtering filteringType) { m_min_filtering = filteringType; } 53 | SSGTexture::Filtering minFiltering() const { return SSGTexture::Filtering(m_min_filtering); } 54 | 55 | void setMagFiltering(SSGTexture::Filtering filteringType) { m_mag_filtering = filteringType; } 56 | SSGTexture::Filtering magFiltering() const { return SSGTexture::Filtering(m_mag_filtering); } 57 | 58 | void setMinMipmapFiltering(SSGTexture::Filtering filteringType) { m_min_mipmap_filtering = filteringType; } 59 | SSGTexture::Filtering minMipmapFiltering() const { return SSGTexture::Filtering(m_min_mipmap_filtering); } 60 | 61 | void setMagMipmapFiltering(SSGTexture::Filtering filteringType) { m_mag_mipmap_filtering = filteringType; } 62 | SSGTexture::Filtering magMipmapFiltering() const { return SSGTexture::Filtering(m_mag_mipmap_filtering); } 63 | 64 | void setHorizontalWrapMode(SSGTexture::WrapMode mode) { m_horizontal_wrap = mode; } 65 | SSGTexture::WrapMode horizontalWrapMode() const { return SSGTexture::WrapMode(m_horizontal_wrap); } 66 | 67 | void setVerticalWrapMode(SSGTexture::WrapMode mode) { m_vertical_wrap = mode; } 68 | SSGTexture::WrapMode verticalWrapMode() const { return SSGTexture::WrapMode(m_vertical_wrap); } 69 | 70 | protected: 71 | SSGTexture *m_texture; 72 | 73 | uint m_min_filtering: 2; 74 | uint m_mag_filtering: 2; 75 | uint m_min_mipmap_filtering: 2; 76 | uint m_mag_mipmap_filtering: 2; 77 | uint m_horizontal_wrap : 1; 78 | uint m_vertical_wrap: 1; 79 | 80 | uint m_reserved : 26; 81 | }; 82 | 83 | -------------------------------------------------------------------------------- /source/SSImageItem.cpp: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2016 Erik Hvatum 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 | // 23 | // Authors: Erik Hvatum 24 | 25 | #include "SSImageItem.h" 26 | #include "SSGSimpleTextureNode.h" 27 | 28 | SSImageItem::SSImageItem(QQuickItem* parent) 29 | : QQuickItem(parent), 30 | m_imageSerialSet(false) 31 | { 32 | setFlag(ItemHasContents); 33 | } 34 | 35 | SSImage* SSImageItem::image() 36 | { 37 | return m_image.data(); 38 | } 39 | 40 | const SSImage* SSImageItem::image() const 41 | { 42 | return m_image.data(); 43 | } 44 | 45 | static void noopDeleter(SSImage*) {} 46 | 47 | void SSImageItem::setImage(SSImage* image) 48 | { 49 | if(image != m_image.data()) 50 | { 51 | if(image) 52 | { 53 | m_image = image->sharedFromThis(); 54 | if(!m_image) m_image = QSharedPointer(image, noopDeleter); 55 | setImplicitSize(m_image->size().width(), m_image->size().height()); 56 | } 57 | else 58 | { 59 | m_image.reset(); 60 | setImplicitSize(0,0); 61 | } 62 | imageChanged(); 63 | update(); 64 | } 65 | } 66 | 67 | QSGNode* SSImageItem::updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData* updatePaintNodeData) 68 | { 69 | SSGSimpleTextureNode* n{static_cast(oldNode)}; 70 | if(m_image) 71 | { 72 | if(!n) 73 | { 74 | n = new SSGSimpleTextureNode(); 75 | n->setTextureCoordinatesTransform(SSGSimpleTextureNode::MirrorVertically); 76 | } 77 | if(!m_imageSerialSet || m_imageSerial != m_image->serial()) 78 | { 79 | m_imageSerialSet = true; 80 | m_imageSerial = m_image->serial(); 81 | SSGTexture* t = SSGTexture::fromImage(m_image.data()); 82 | n->setTexture(t); 83 | } 84 | n->setRect(x(), y(), width(), height()); 85 | } 86 | else 87 | { 88 | if(n) 89 | { 90 | delete n; 91 | n = nullptr; 92 | } 93 | m_imageSerialSet = false; 94 | } 95 | return n; 96 | } 97 | -------------------------------------------------------------------------------- /source/SSImageItem.h: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2016 Erik Hvatum 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 | // 23 | // Authors: Erik Hvatum 24 | 25 | #pragma once 26 | #include "common.h" 27 | #include "SSImage.h" 28 | 29 | class SSImageItem 30 | : public QQuickItem 31 | { 32 | Q_OBJECT 33 | Q_PROPERTY(SSImage* image READ image WRITE setImage STORED false NOTIFY imageChanged FINAL) 34 | public: 35 | explicit SSImageItem(QQuickItem* parent=nullptr); 36 | 37 | SSImage* image(); 38 | const SSImage* image() const; 39 | void setImage(SSImage* image); 40 | 41 | signals: 42 | void imageChanged(); 43 | 44 | protected: 45 | QSharedPointer m_image; 46 | bool m_imageSerialSet; 47 | std::size_t m_imageSerial; 48 | 49 | QSGNode* updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData* updatePaintNodeData) override; 50 | }; 51 | -------------------------------------------------------------------------------- /source/SSQmlPlugin.cpp: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2016 Erik Hvatum 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 | // 23 | // Authors: Erik Hvatum 24 | 25 | #include "SSQmlPlugin.h" 26 | #include "SSImage.h" 27 | #include "SSImageItem.h" 28 | #include "SSView.h" 29 | 30 | SSQmlPlugin::SSQmlPlugin(QObject* parent) 31 | : QQmlExtensionPlugin(parent) 32 | { 33 | qDebug() << "SSQmlPlugin loaded"; 34 | } 35 | 36 | void SSQmlPlugin::registerTypes(const char* uri) 37 | { 38 | Q_ASSERT(uri == QLatin1String("StackStream")); 39 | qDebug() << "SSQmlPlugin::registerTypes(..)"; 40 | 41 | const char ss[] = "StackStream"; 42 | const int ver[] = {1, 0}; 43 | qmlRegisterType(ss, ver[0], ver[1], "SSImage"); 44 | qRegisterMetaType("DType"); 45 | qRegisterMetaType("Components"); 46 | qRegisterMetaType("std::size_t"); 47 | qmlRegisterType(ss, ver[0], ver[1], "SSImageItem"); 48 | qmlRegisterType(ss, ver[0], ver[1], "SSView"); 49 | } 50 | -------------------------------------------------------------------------------- /source/SSQmlPlugin.h: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2016 Erik Hvatum 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 | // 23 | // Authors: Erik Hvatum 24 | 25 | #pragma once 26 | #include "common.h" 27 | #include 28 | 29 | class SSQmlPlugin 30 | : public QQmlExtensionPlugin 31 | { 32 | Q_OBJECT 33 | Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") 34 | public: 35 | explicit SSQmlPlugin(QObject* parent=nullptr); 36 | 37 | void registerTypes(const char* uri) override; 38 | }; 39 | -------------------------------------------------------------------------------- /source/SSView.cpp: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2016 Erik Hvatum 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 | // 23 | // Authors: Erik Hvatum 24 | 25 | #include "SSView.h" 26 | 27 | SSView::SSView() 28 | { 29 | setFlag(QQuickItem::ItemClipsChildrenToShape); 30 | } 31 | 32 | -------------------------------------------------------------------------------- /source/SSView.h: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2016 Erik Hvatum 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 | // 23 | // Authors: Erik Hvatum 24 | 25 | #pragma once 26 | #include "common.h" 27 | 28 | class SSView 29 | : public QQuickItem 30 | { 31 | Q_OBJECT 32 | public: 33 | SSView(); 34 | // TODO: custom transform node 35 | 36 | signals: 37 | 38 | public slots: 39 | }; 40 | -------------------------------------------------------------------------------- /source/StackStreamMainWindow.qml: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2016 Erik Hvatum 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 | // 23 | // Authors: Erik Hvatum 24 | 25 | import QtQuick 2.5 26 | import QtQuick.Controls 1.3 27 | import QtQuick.Dialogs 1.2 28 | import QtQuick.Extras 1.4 29 | import QtQuick.Layouts 1.2 30 | import QtQuick.Window 2.2 31 | 32 | import StackStream 1.0 33 | import QtQmlTricks 1.0 34 | 35 | ApplicationWindow { 36 | visible: false 37 | width: 1024 38 | height: 768 39 | title: qsTr("StackStream") 40 | objectName: "stackStreamMainWindow" 41 | property SSImage image: SSImage{} 42 | 43 | SSView { 44 | id: mainView 45 | // anchors.left: parent.left 46 | // anchors.top: parent.top 47 | // anchors.bottom: parent.bottom 48 | // width: parent.width - layerPropertiesGroupBox.width - 20 49 | anchors.fill: parent 50 | z: -1 51 | 52 | TileBackground { 53 | anchors.fill: parent 54 | } 55 | 56 | SSImageItem { 57 | id: imageItem 58 | y: 0 59 | x: 0 60 | layer.enabled: true 61 | Drag.active: mouseArea.drag.active 62 | Drag.hotSpot.x: 10 63 | Drag.hotSpot.y: 10 64 | 65 | transform: Scale { 66 | id: scale 67 | property real factor: 1.0 68 | xScale: factor 69 | yScale: factor 70 | } 71 | 72 | MouseArea { 73 | id: mouseArea 74 | anchors.fill: parent 75 | drag.target: parent 76 | property var factors: [ 4.0 , 3.8 , 3.6 , 3.4 , 3.2 , 77 | 3.0 , 2.8 , 2.6 , 2.4 , 2.2 , 78 | 2.0 , 1.8 , 1.6 , 1.4 , 1.2 , 79 | 1.0 , 0.91700404, 0.84089642, 0.77110541, 0.70710678, 80 | 0.64841978, 0.59460356, 0.54525387, 0.5 , 0.45850202, 81 | 0.42044821, 0.38555271, 0.35355339, 0.32420989, 0.29730178, 82 | 0.27262693, 0.25 ] 83 | property int factorIdx: 15 84 | onWheel: { 85 | factorIdx = (factorIdx + (wheel.angleDelta.y / 120)) | 0 86 | if(factorIdx < 0) factorIdx = 0 87 | else if (factorIdx >= factors.length) factorIdx = factors.length - 1 88 | scale.factor = factors[factorIdx] 89 | } 90 | } 91 | 92 | Text { 93 | smooth: true 94 | text: 'hello world' 95 | color: 'red' 96 | x: 400 97 | y: 300 98 | width: 100 99 | height: 20 100 | } 101 | } 102 | 103 | // Rectangle { 104 | // x: 0 105 | // y: 0 106 | // width: 100 107 | // height: 200 108 | // anchors.fill: imageItem 109 | // anchors.margins: 5 110 | // color: 'blue' 111 | // opacity: 0.5 112 | // layer.enabled: true 113 | // } 114 | 115 | DropArea { 116 | anchors.fill: parent 117 | onEntered: { 118 | // console.log('drop area entered'); 119 | drag.accept(Qt.CopyAction); 120 | } 121 | onDropped: { 122 | image.read(drop.urls[0]) 123 | imageItem.image = image 124 | } 125 | // onExited: { 126 | // console.log('drop area exited'); 127 | // } 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /source/StackStreamPlugin.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | StackStreamMainWindow.qml 4 | TileBackground.qml 5 | 6 | 7 | -------------------------------------------------------------------------------- /source/TileBackground.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.5 2 | 3 | ShaderEffect { 4 | property real tileSize: 16 5 | property color color1: Qt.rgba(0.9, 0.9, 0.9, 1); 6 | property color color2: Qt.rgba(0.85, 0.85, 0.85, 1); 7 | 8 | property size pixelSize: Qt.size(width / tileSize, height / tileSize); 9 | 10 | fragmentShader: 11 | " 12 | uniform lowp vec4 color1; 13 | uniform lowp vec4 color2; 14 | uniform highp vec2 pixelSize; 15 | varying highp vec2 qt_TexCoord0; 16 | void main() { 17 | highp vec2 tc = sign(sin(3.14152 * qt_TexCoord0 * pixelSize)); 18 | if (tc.x != tc.y) 19 | gl_FragColor = color1; 20 | else 21 | gl_FragColor = color2; 22 | } 23 | " 24 | } 25 | -------------------------------------------------------------------------------- /source/common.h: -------------------------------------------------------------------------------- 1 | // The MIT License (MIT) 2 | // 3 | // Copyright (c) 2016 Erik Hvatum 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 | // 23 | // Authors: Erik Hvatum 24 | 25 | #pragma once 26 | 27 | #ifndef QT_NO_DEBUG 28 | #define QT_QML_DEBUG 29 | #endif 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | 53 | #ifdef WITH_PYTHON 54 | #include 55 | #endif 56 | 57 | #ifdef STACKSTREAM 58 | #define STACKSTREAM_DLLSPEC Q_DECL_EXPORT 59 | #ifdef ENABLE_GL_DEBUG_LOGGING 60 | extern QOpenGLDebugLogger* g_glDebugLogger; 61 | #endif 62 | #else 63 | #define STACKSTREAM_DLLSPEC Q_DECL_IMPORT 64 | #endif 65 | 66 | #ifdef min 67 | #undef min 68 | #endif 69 | 70 | #ifdef max 71 | #undef max 72 | #endif 73 | 74 | #ifdef read 75 | #undef read 76 | #endif 77 | 78 | #ifdef write 79 | #undef write 80 | #endif 81 | 82 | #include 83 | #include 84 | #include 85 | 86 | class TimeThisBlock 87 | { 88 | public: 89 | TimeThisBlock() : t0(std::chrono::high_resolution_clock::now()) {} 90 | ~TimeThisBlock() 91 | { 92 | std::chrono::high_resolution_clock::time_point t1{std::chrono::high_resolution_clock::now()}; 93 | double nanoseconds_elapsed = static_cast(std::chrono::duration_cast(t1 - t0).count()); 94 | if(nanoseconds_elapsed < 1000) 95 | std::cout << nanoseconds_elapsed << "ns"; 96 | else if(nanoseconds_elapsed < 1e6) 97 | std::cout << nanoseconds_elapsed * static_cast(1e-3) << "µs"; 98 | else if(nanoseconds_elapsed < 1e9) 99 | std::cout << nanoseconds_elapsed * static_cast(1e-6) << "ms"; 100 | else 101 | std::cout << nanoseconds_elapsed * static_cast(1e-9) << "s"; 102 | std::cout << std::endl; 103 | } 104 | protected: 105 | std::chrono::high_resolution_clock::time_point t0; 106 | }; 107 | -------------------------------------------------------------------------------- /source/qmldir: -------------------------------------------------------------------------------- 1 | module StackStream 2 | StackStreamMainWindow 1.0 StackStreamMainWindow.qml 3 | plugin StackStreamPlugin 4 | -------------------------------------------------------------------------------- /todo_mindmap.vym: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erikhvatum/StackStream/b33cf282e83ad104818e70f5b0e8adf1d781a50b/todo_mindmap.vym --------------------------------------------------------------------------------