@@ -0,0 +1,42 @@ | |||
vstgui/ide/xcode4/build | |||
vstgui/ide/xcode4/DerivedData | |||
vstgui/ide/xcode4/vstgui.xcodeproj/xcuserdata | |||
vstgui/tests/uidescription vst3/mac/build | |||
vstgui/tests/uidescription vst3/mac/DerivedData | |||
vstgui/tests/uidescription vst3/mac/uidescription test.xcodeproj/xcuserdata | |||
vstgui/tests/unittest/lcov/out | |||
vstgui-coverage.info | |||
vstgui/tests/uidescription vst3/mac/uidescription test.xcodeproj/project.xcworkspace | |||
vstgui/tests/ios standalone/build | |||
vstgui/tests/ios standalone/DerivedData | |||
vstgui/tests/ios standalone/iOS Standalone.xcodeproj/project.xcworkspace | |||
vstgui/tests/ios standalone/iOS Standalone.xcodeproj/xcuserdata | |||
vstgui/ide/visualstudio/vs2015/build | |||
*.VC.opendb | |||
vstgui/tests/uidescription vst3/win/x64 | |||
vstgui/tests/uidescription vst3/win/Win32 | |||
vstgui/ide/xcode4/vstgui.xcodeproj/project.xcworkspace | |||
vstgui/ide/visualstudio/vs2013/build | |||
vstgui.opensdf | |||
vstgui/tests/standalone/mac/build | |||
vstgui/tests/standalone/mac/DerivedData | |||
vstgui/tests/standalone/mac/VSTGUIStandalone.xcodeproj/project.xcworkspace | |||
vstgui/tests/standalone/mac/VSTGUIStandalone.xcodeproj/xcuserdata | |||
vstgui/tests/standalone/win/vs2015/x64 | |||
*.vcxproj.user | |||
vstgui/tests/standalone/win/vs2015/.vs | |||
vstgui/CMakeFiles | |||
CMakeCache.txt | |||
compile_commands.json | |||
vstgui.sdf | |||
vstgui.v12.suo | |||
vstgui/ide/visualstudio/vs2015/.vs | |||
vstgui/build | |||
vstgui/tests/uidescription vst3/win/.vs | |||
vstgui/Documentation/html | |||
/vstgui/uidescription/editing/editoruidesc.h | |||
CMakeLists.txt.user | |||
build | |||
vstgui/gdk | |||
vstgui/gdkmm | |||
vstgui/gtk |
@@ -0,0 +1,49 @@ | |||
language: cpp | |||
matrix: | |||
include: | |||
# macOS | |||
- os: osx | |||
osx_image: xcode7.3 | |||
compiler: clang | |||
env: CPPCOMPILER='clang++' CCOMPILER='clang' BUILD_TYPE='Debug' | |||
- os: osx | |||
osx_image: xcode9.4 | |||
compiler: clang | |||
env: CPPCOMPILER='clang++' CCOMPILER='clang' BUILD_TYPE='Debug' | |||
# linux | |||
- os: linux | |||
compiler: gcc | |||
addons: &gcc7 | |||
apt: | |||
sources: ['ubuntu-toolchain-r-test'] | |||
packages: [ | |||
'g++-7', | |||
'libxcb-util0-dev', | |||
'libxcb-xkb-dev', | |||
'libgtkmm-3.0-dev', | |||
'libxcb-cursor-dev', | |||
'libxkbcommon-dev', | |||
'libxkbcommon-x11-dev', | |||
'libxcb-keysyms1-dev' | |||
] | |||
env: CPPCOMPILER='g++-7' CCOMPILER='gcc-7' BUILD_TYPE='Debug' | |||
install: | |||
true | |||
script: | |||
- export CXX=${CPPCOMPILER} | |||
- export CC=${CCOMPILER} | |||
- mkdir -p build | |||
- cd build | |||
- | | |||
if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then | |||
cmake -GXcode -DCMAKE_BUILD_TYPE=${BUILD_TYPE} ../vstgui/ | |||
elif [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then | |||
cmake -DVSTGUI_STANDALONE=OFF -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_BUILD_TYPE=${BUILD_TYPE} ../vstgui/ | |||
fi | |||
- cmake --build . | |||
@@ -0,0 +1,27 @@ | |||
//----------------------------------------------------------------------------- | |||
// VSTGUI LICENSE | |||
// (c) 2018, Steinberg Media Technologies, All Rights Reserved | |||
//----------------------------------------------------------------------------- | |||
// Redistribution and use in source and binary forms, with or without modification, | |||
// are permitted provided that the following conditions are met: | |||
// | |||
// * Redistributions of source code must retain the above copyright notice, | |||
// this list of conditions and the following disclaimer. | |||
// * Redistributions in binary form must reproduce the above copyright notice, | |||
// this list of conditions and the following disclaimer in the documentation | |||
// and/or other materials provided with the distribution. | |||
// * Neither the name of the Steinberg Media Technologies nor the names of its | |||
// contributors may be used to endorse or promote products derived from this | |||
// software without specific prior written permission. | |||
// | |||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |||
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | |||
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | |||
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |||
// OF THE POSSIBILITY OF SUCH DAMAGE. | |||
//----------------------------------------------------------------------------- |
@@ -0,0 +1,52 @@ | |||
# VSTGUI | |||
[](https://travis-ci.com/scheffle/vstgui) | |||
VSTGUI is a user interface toolkit mainly for audio plug-ins (VST, AAX, AudioUnit, etc...) | |||
and it is designed for working well with VST3 plug-ins. | |||
## History | |||
- First developed inhouse of Steinberg Media Technologies (around 1998) for their first VST plug-ins. | |||
- Later added as binary libraries to the official VST SDK. | |||
- Since May 2003 VSTGUI is open source. | |||
## System requirements | |||
Supported OS: | |||
- Microsoft Windows 7-10 | |||
- Apple OSX 10.9-10.13 | |||
- Apple iOS 8-11 | |||
- Linux (Preview) | |||
Supported IDE: | |||
- Visual Studio 2015/2017 | |||
- minimum Xcode 8 | |||
- Qt Creator | |||
## License | |||
BSD style | |||
VSTGUI LICENSE | |||
(c) Steinberg Media Technologies, All Rights Reserved | |||
Redistribution and use in source and binary forms, with or without modification, | |||
are permitted provided that the following conditions are met: | |||
* Redistributions of source code must retain the above copyright notice, | |||
this list of conditions and the following disclaimer. | |||
* Redistributions in binary form must reproduce the above copyright notice, | |||
this list of conditions and the following disclaimer in the documentation | |||
and/or other materials provided with the distribution. | |||
* Neither the name of the Steinberg Media Technologies nor the names of its | |||
contributors may be used to endorse or promote products derived from this | |||
software without specific prior written permission. | |||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |||
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | |||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | |||
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |||
OF THE POSSIBILITY OF SUCH DAMAGE. |
@@ -0,0 +1,24 @@ | |||
{ | |||
"configurations": [ | |||
{ | |||
"name": "Linux", | |||
"browse": { | |||
"path": [ | |||
"${workspaceFolder}" | |||
], | |||
"limitSymbolsToIncludedHeaders": true | |||
}, | |||
"includePath": [ | |||
"${workspaceFolder}" | |||
], | |||
"defines": [], | |||
"compilerPath": "/usr/bin/clang", | |||
"cStandard": "c11", | |||
"cppStandard": "c++17", | |||
"compileCommands": "build/compile_commands.json", | |||
"intelliSenseMode": "clang-x64", | |||
"configurationProvider": "vector-of-bool.cmake-tools" | |||
} | |||
], | |||
"version": 4 | |||
} |
@@ -0,0 +1,36 @@ | |||
{ | |||
// Use IntelliSense to learn about possible attributes. | |||
// Hover to view descriptions of existing attributes. | |||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 | |||
"version": "0.2.0", | |||
"configurations": [ | |||
{ | |||
"name": "(gdb) standalone", | |||
"type": "cppdbg", | |||
"request": "launch", | |||
"program": "${workspaceFolder}/build/Debug/standalone/standalone", | |||
"args": [], | |||
"stopAtEntry": false, | |||
"cwd": "${workspaceFolder}/build/Debug/", | |||
"environment": [ | |||
{ | |||
"name": "LD_LIBRARY_PATH", | |||
"value": "/home/scheffle/tmp/gtk+3.0-3.22.11/debian/build/shared/gdk/.libs;/home/scheffle/tmp/gtkmm3.0-3.22.0/gdk/gdkmm/.libs;/home/scheffle/tmp/cairomm-1.12.0/debian/libcairomm-1.0-1v5/usr/lib/x86_64-linux-gnu" | |||
}, | |||
// { | |||
// "name": "DISPLAY", | |||
// "value": ":9" | |||
// } | |||
], | |||
"externalConsole": true, | |||
"MIMode": "gdb", | |||
"setupCommands": [ | |||
{ | |||
"description": "Enable pretty-printing for gdb", | |||
"text": "-enable-pretty-printing", | |||
"ignoreFailures": true | |||
} | |||
] | |||
} | |||
] | |||
} |
@@ -0,0 +1,51 @@ | |||
{ | |||
"files.associations": { | |||
"deque": "cpp", | |||
"vector": "cpp", | |||
"*.tcc": "cpp", | |||
"fstream": "cpp", | |||
"valarray": "cpp", | |||
"array": "cpp", | |||
"chrono": "cpp", | |||
"functional": "cpp", | |||
"ratio": "cpp", | |||
"type_traits": "cpp", | |||
"tuple": "cpp", | |||
"utility": "cpp", | |||
"atomic": "cpp", | |||
"bitset": "cpp", | |||
"cctype": "cpp", | |||
"clocale": "cpp", | |||
"cmath": "cpp", | |||
"complex": "cpp", | |||
"condition_variable": "cpp", | |||
"cstdarg": "cpp", | |||
"cstddef": "cpp", | |||
"cstdint": "cpp", | |||
"cstdio": "cpp", | |||
"cstdlib": "cpp", | |||
"cstring": "cpp", | |||
"ctime": "cpp", | |||
"cwchar": "cpp", | |||
"cwctype": "cpp", | |||
"list": "cpp", | |||
"unordered_map": "cpp", | |||
"exception": "cpp", | |||
"initializer_list": "cpp", | |||
"iosfwd": "cpp", | |||
"iostream": "cpp", | |||
"istream": "cpp", | |||
"limits": "cpp", | |||
"memory": "cpp", | |||
"mutex": "cpp", | |||
"new": "cpp", | |||
"ostream": "cpp", | |||
"sstream": "cpp", | |||
"stdexcept": "cpp", | |||
"streambuf": "cpp", | |||
"system_error": "cpp", | |||
"thread": "cpp", | |||
"typeinfo": "cpp" | |||
}, | |||
"cmake.configureOnOpen": true, | |||
} |
@@ -0,0 +1,188 @@ | |||
########################################################################################## | |||
cmake_minimum_required(VERSION 3.5) | |||
if(NOT PROJECT_NAME) | |||
project(vstgui) | |||
set(VSTGUI_MAIN_PROJECT_BUILD 1) | |||
endif() | |||
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.9) | |||
if (UNIX AND NOT CMAKE_HOST_APPLE) | |||
set(LINUX TRUE) | |||
endif() | |||
########################################################################################## | |||
function(vstgui_set_cxx_version target version) | |||
set_property(TARGET ${target} PROPERTY CXX_STANDARD ${version}) | |||
set_property(TARGET ${target} PROPERTY CXX_STANDARD_REQUIRED ON) | |||
set_property(TARGET ${target} PROPERTY CMAKE_CXX_STANDARD_REQUIRED ON) | |||
if(APPLE) | |||
target_compile_options(${target} PUBLIC "-stdlib=libc++") | |||
endif() | |||
endfunction(vstgui_set_cxx_version target version) | |||
########################################################################################## | |||
function(vstgui_source_group_by_folder target) | |||
if(CMAKE_CONFIGURATION_TYPES) | |||
set(SOURCE_GROUP_DELIMITER "/") | |||
set(last_dir "") | |||
set(files "") | |||
foreach(file ${${target}_sources}) | |||
get_filename_component(dir "${file}" DIRECTORY) | |||
string(FIND "${dir}" ${target} isTargetFolder) | |||
if (${isTargetFolder} EQUAL 0) | |||
string(LENGTH ${target} offset) | |||
string(SUBSTRING "${dir}" ${offset} -1 dir) | |||
endif(${isTargetFolder} EQUAL 0) | |||
if (NOT "${dir}" STREQUAL "${last_dir}") | |||
if (files) | |||
source_group("${last_dir}" FILES ${files}) | |||
endif (files) | |||
set(files "") | |||
endif (NOT "${dir}" STREQUAL "${last_dir}") | |||
set(files ${files} ${file}) | |||
set(last_dir "${dir}") | |||
endforeach(file) | |||
if (files) | |||
source_group("${last_dir}" FILES ${files}) | |||
endif (files) | |||
endif(CMAKE_CONFIGURATION_TYPES) | |||
endfunction(vstgui_source_group_by_folder) | |||
########################################################################################## | |||
if(CMAKE_CONFIGURATION_TYPES) | |||
set(CMAKE_CONFIGURATION_TYPES Debug Release ReleaseLTO) | |||
set_property(GLOBAL PROPERTY USE_FOLDERS ON) | |||
endif() | |||
########################################################################################## | |||
set(VSTGUI_COMPILE_DEFINITIONS_DEBUG "VSTGUI_LIVE_EDITING;DEBUG") | |||
set(VSTGUI_COMPILE_DEFINITIONS_RELEASE "NDEBUG;RELEASE") | |||
if(CMAKE_HOST_APPLE) | |||
if(CMAKE_C_COMPILER_VERSION VERSION_GREATER 7) | |||
set(VSTGUI_LTO_COMPILER_FLAGS "-O3 -flto=thin") | |||
else() | |||
set(VSTGUI_LTO_COMPILER_FLAGS "-O3 -flto") | |||
endif() | |||
set(VSTGUI_LTO_LINKER_FLAGS "") | |||
endif() | |||
if(LINUX) | |||
set(VSTGUI_LTO_COMPILER_FLAGS "-O3 -flto") | |||
set(VSTGUI_LTO_LINKER_FLAGS "") | |||
find_package(X11 REQUIRED) | |||
find_package(Freetype REQUIRED) | |||
find_package(PkgConfig REQUIRED) | |||
pkg_check_modules(LIBXCB REQUIRED xcb) | |||
pkg_check_modules(LIBXCB_UTIL REQUIRED xcb-util) | |||
pkg_check_modules(LIBXCB_CURSOR REQUIRED xcb-cursor) | |||
pkg_check_modules(LIBXCB_KEYSYMS REQUIRED xcb-keysyms) | |||
pkg_check_modules(LIBXCB_XKB REQUIRED xcb-xkb) | |||
pkg_check_modules(LIBXKB_COMMON REQUIRED xkbcommon) | |||
pkg_check_modules(LIBXKB_COMMON_X11 REQUIRED xkbcommon-x11) | |||
set(LINUX_LIBRARIES | |||
${X11_LIBRARIES} | |||
${FREETYPE_LIBRARIES} | |||
${LIBXCB_LIBRARIES} | |||
${LIBXCB_UTIL_LIBRARIES} | |||
${LIBXCB_CURSOR_LIBRARIES} | |||
${LIBXCB_KEYSYMS_LIBRARIES} | |||
${LIBXCB_XKB_LIBRARIES} | |||
${LIBXKB_COMMON_LIBRARIES} | |||
${LIBXKB_COMMON_X11_LIBRARIES} | |||
cairo | |||
fontconfig | |||
dl | |||
) | |||
if(VSTGUI_WARN_EVERYTHING) | |||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") | |||
endif() | |||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-multichar") | |||
endif() | |||
if(MSVC) | |||
set(VSTGUI_COMPILE_DEFINITIONS_DEBUG "${VSTGUI_COMPILE_DEFINITIONS_DEBUG};_CRT_SECURE_NO_WARNINGS") | |||
set(VSTGUI_COMPILE_DEFINITIONS_RELEASE "${VSTGUI_COMPILE_DEFINITIONS_RELEASE};_CRT_SECURE_NO_WARNINGS") | |||
set(VSTGUI_LTO_COMPILER_FLAGS "/GL /MP") | |||
set(VSTGUI_LTO_LINKER_FLAGS "/LTCG") | |||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") | |||
set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /IGNORE:4221") | |||
endif() | |||
set(VSTGUI_COMPILE_DEFINITIONS PRIVATE | |||
$<$<CONFIG:Debug>:${VSTGUI_COMPILE_DEFINITIONS_DEBUG}> | |||
$<$<CONFIG:Release>:${VSTGUI_COMPILE_DEFINITIONS_RELEASE}> | |||
$<$<CONFIG:ReleaseLTO>:${VSTGUI_COMPILE_DEFINITIONS_RELEASE}> | |||
) | |||
set(CMAKE_CXX_FLAGS_RELEASELTO | |||
"${CMAKE_CXX_FLAGS_RELEASE} ${VSTGUI_LTO_COMPILER_FLAGS}" | |||
) | |||
set(CMAKE_EXE_LINKER_FLAGS_RELEASELTO | |||
"${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${VSTGUI_LTO_LINKER_FLAGS}" | |||
) | |||
set(CMAKE_STATIC_LINKER_FLAGS_RELEASELTO | |||
"${CMAKE_STATIC_LINKER_FLAGS_RELEASE} ${VSTGUI_LTO_LINKER_FLAGS}" | |||
) | |||
########################################################################################## | |||
if(NOT CMAKE_CONFIGURATION_TYPES) | |||
if(NOT CMAKE_BUILD_TYPE) | |||
set(CMAKE_BUILD_TYPE Debug) | |||
endif() | |||
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") | |||
endif() | |||
if(VSTGUI_MAIN_PROJECT_BUILD) | |||
message("Building only vstgui") | |||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY | |||
$<$<CONFIG:Debug>:${CMAKE_BINARY_DIR}/Debug/>$<$<CONFIG:Release>:${CMAKE_BINARY_DIR}/Release/>$<$<CONFIG:ReleaseLTO>:${CMAKE_BINARY_DIR}/ReleaseLTO/> | |||
) | |||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY | |||
$<$<CONFIG:Debug>:${CMAKE_BINARY_DIR}/Debug/libs/>$<$<CONFIG:Release>:${CMAKE_BINARY_DIR}/Release/libs/>$<$<CONFIG:ReleaseLTO>:${CMAKE_BINARY_DIR}/ReleaseLTO/libs/> | |||
) | |||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY | |||
$<$<CONFIG:Debug>:${CMAKE_BINARY_DIR}/Debug/libs>$<$<CONFIG:Release>:${CMAKE_BINARY_DIR}/Release/libs>$<$<CONFIG:ReleaseLTO>:${CMAKE_BINARY_DIR}/ReleaseLTO/libs> | |||
) | |||
endif() | |||
########################################################################################## | |||
add_subdirectory(lib) | |||
add_subdirectory(uidescription) | |||
if(LINUX) | |||
set(VSTGUI_DISABLE_UNITTESTS 1) | |||
endif() | |||
if(NOT DEFINED VSTGUI_STANDALONE) | |||
option(VSTGUI_STANDALONE "VSTGUI Standalone library" ON) | |||
if(NOT DEFINED VSTGUI_STANDALONE_EXAMPLES) | |||
option(VSTGUI_STANDALONE_EXAMPLES "VSTGUI Standalone examples" ON) | |||
endif() | |||
endif() | |||
if(NOT VSTGUI_STANDALONE AND VSTGUI_STANDALONE_EXAMPLES) | |||
set(VSTGUI_STANDALONE_EXAMPLES OFF) | |||
endif() | |||
option(VSTGUI_TOOLS "VSTGUI Tools" ON) | |||
if(VSTGUI_STANDALONE) | |||
add_subdirectory(standalone) | |||
if(NOT VSTGUI_DISABLE_UNITTESTS) | |||
add_subdirectory(tests/gfxtest) | |||
add_subdirectory(tests/base64codecspeed) | |||
endif() | |||
endif() | |||
if(NOT VSTGUI_DISABLE_UNITTESTS) | |||
add_subdirectory(tests) | |||
endif() | |||
if(VSTGUI_TOOLS) | |||
add_subdirectory(tools) | |||
endif() | |||
get_directory_property(hasParent PARENT_DIRECTORY) | |||
if(hasParent) | |||
set(VSTGUI_COMPILE_DEFINITIONS ${VSTGUI_COMPILE_DEFINITIONS} PARENT_SCOPE) | |||
set(VSTGUI_LTO_COMPILER_FLAGS ${VSTGUI_LTO_COMPILER_FLAGS} PARENT_SCOPE) | |||
endif() |
@@ -0,0 +1,73 @@ | |||
{\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf100 | |||
{\fonttbl\f0\fswiss\fcharset77 Helvetica-Bold;\f1\fswiss\fcharset77 Helvetica;} | |||
{\colortbl;\red255\green255\blue255;\red255\green0\blue24;} | |||
\paperw11900\paperh16840\margl1440\margr1440\vieww21420\viewh15340\viewkind0 | |||
\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\ql\qnatural | |||
\f0\b\fs38 \cf0 \ul \ulc0 Migrating from VSTGUI 2.3 to VSTGUI 3.0\ | |||
\f1\b0\fs22 \ulnone \ | |||
\f0\b\fs26 \ul Things you need to change in your code:\ | |||
\f1\b0\fs22 \ulnone \ | |||
\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\li560\fi-560\ql\qnatural | |||
\fs24 \cf0 - CFrame::removeView (CView *pView, const bool &withForget = true) The second parameter (withForget) has changed its default parameter.\ | |||
\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\ql\qnatural | |||
\cf0 \ | |||
- CDrawContext::getMouseLocation (CPoint &point)\ | |||
\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\li560\fi-560\ql\qnatural | |||
\cf0 This call will always report the global frame coordinate of the mouse. If you need the mouse coordinates relative to a view, use view->getMouseLocation (context, point)\ | |||
\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\ql\qnatural | |||
\cf0 \ | |||
- The following CView methods are deprecated :\ | |||
\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\li560\fi-560\ql\qnatural | |||
\cf0 virtual void setParentView (CView *pParentView);\ | |||
virtual void setFrame (CFrame *pParent);\ | |||
virtual void getFrameTopLeftPos (CPoint& topLeft) const;\ | |||
\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\ql\qnatural | |||
\cf0 \ | |||
\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\li140\fi-140\ql\qnatural | |||
\cf0 - Don't call frame->beginEdit(..) and frame->endEdit(..) in your subclassed controls. Use the CControl methods beginEdit, endEdit.\ | |||
\ | |||
- Nearly all getter methods have changed to be const. Check all your subclasses, so that your methods don't hide the inherited virtual functions.\ | |||
\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\li140\fi20\ql\qnatural | |||
\cf0 This may be the most important methods from CView and CControl\ | |||
- CView::checkUpdate ()\ | |||
- CView::isDirty ()\ | |||
- CControl::getValue ()\ | |||
- CControl::getMin ()\ | |||
- CControl::getMax ()\ | |||
- CControl::getOldValue ()\ | |||
- CControl::getDefaultValue ()\ | |||
- CControl::getTag ()\ | |||
- CControl::getWheelInc ()\ | |||
- CControl::getListener ()\ | |||
\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\li140\fi-140\ql\qnatural | |||
\cf0 \ | |||
- Don't call CControl::update (..) anymore to force an control to redraw. Just call CControl::setDirty (true);\ | |||
\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\ql\qnatural | |||
\cf0 \ | |||
\pard\tx565\tx1133\tx1700\tx2266\tx2833\tx3401\tx3967\tx4535\tx5102\tx5669\tx6235\tx6802\ql\qnatural | |||
\f0\b\fs26 \cf0 \ul How to use PNG Images on Windows:\ | |||
\ | |||
\pard\tx565\tx1133\tx1700\tx2266\tx2833\tx3401\tx3967\tx4535\tx5102\tx5669\tx6235\tx6802\ql\qnatural | |||
\f1\b0\fs24 \cf0 \ulnone - Download libpng and zlib ({\field{\*\fldinst{HYPERLINK "http://libpng.sourceforge.net/"}}{\fldrslt \cf2 http://libpng.sourceforge.net/}}\cf2 , {\field{\*\fldinst{HYPERLINK "http://www.zlib.net/"}}{\fldrslt http://www.zlib.net/}}\cf0 )\ | |||
- Add their sources to your project\ | |||
- Define the preprocessor macro: USE_LIBPNG=1\ | |||
- add your png images to your rc file like this: \ | |||
128 PNG bmp00128.png\ | |||
- rebuild ;-)\ | |||
\ | |||
\pard\tx565\tx1133\tx1700\tx2266\tx2832\tx3401\tx3967\tx4535\tx5102\tx5669\tx6235\tx6802\ql\qnatural | |||
\f0\b\fs26 \cf0 \ul Transparent Bitmaps with QUARTZ on Mac OS X:\ | |||
\ | |||
\pard\tx565\tx1133\tx1700\tx2266\tx2832\tx3401\tx3967\tx4535\tx5102\tx5669\tx6235\tx6802\ql\qnatural | |||
\f1\b0\fs24 \cf0 \ulnone Per default on Mac OS X if you need transparent bitmaps, you should use the alpha channel of a PNG Image. If you need the old behaviour and want to set bitmap->setTransparentColor (someColor) you need to call bitmap->setNoAlpha (true); (This actually is only necessary for PNG images, all other images will get the noAlpha state per default)\ | |||
\ | |||
} |
@@ -0,0 +1,11 @@ | |||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" | |||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |||
<html xmlns="http://www.w3.org/1999/xhtml"> | |||
<head> | |||
<title>VSTGUI</title> | |||
<meta http-equiv="refresh" content="0; URL=html/index.html" /> | |||
</head> | |||
<body> | |||
</body> | |||
</html> |
@@ -0,0 +1,106 @@ | |||
Language: Cpp | |||
AccessModifierOffset: -4 | |||
AlignAfterOpenBracket: Align | |||
AlignConsecutiveAssignments: false | |||
AlignConsecutiveDeclarations: false | |||
AlignEscapedNewlines: Right | |||
AlignOperands: true | |||
AlignTrailingComments: true | |||
AllowAllParametersOfDeclarationOnNextLine: true | |||
AllowShortBlocksOnASingleLine: false | |||
AllowShortCaseLabelsOnASingleLine: false | |||
AllowShortFunctionsOnASingleLine: Inline | |||
AllowShortIfStatementsOnASingleLine: false | |||
AllowShortLoopsOnASingleLine: false | |||
# AlwaysBreakAfterDefinitionReturnType: None | |||
AlwaysBreakAfterReturnType: None | |||
AlwaysBreakBeforeMultilineStrings: false | |||
AlwaysBreakTemplateDeclarations: true | |||
BinPackArguments: true | |||
BinPackParameters: false | |||
BreakBeforeBraces: Custom | |||
BraceWrapping: | |||
AfterClass: true | |||
AfterControlStatement: true | |||
AfterEnum: true | |||
AfterFunction: true | |||
AfterNamespace: false | |||
AfterObjCDeclaration: true | |||
AfterStruct: true | |||
AfterUnion: true | |||
AfterExternBlock: true | |||
BeforeCatch: true | |||
BeforeElse: true | |||
IndentBraces: false | |||
SplitEmptyFunction: true | |||
SplitEmptyRecord: true | |||
SplitEmptyNamespace: true | |||
BreakBeforeBinaryOperators: None | |||
BreakBeforeInheritanceComma: true | |||
BreakBeforeTernaryOperators: true | |||
BreakConstructorInitializers: BeforeComma | |||
BreakAfterJavaFieldAnnotations: false | |||
BreakStringLiterals: true | |||
ColumnLimit: 100 | |||
# CommentPragmas: '^ IWYU pragma:' | |||
CompactNamespaces: false | |||
ConstructorInitializerAllOnOneLineOrOnePerLine: true | |||
ConstructorInitializerIndentWidth: 4 | |||
ContinuationIndentWidth: 4 | |||
Cpp11BracedListStyle: true | |||
DerivePointerAlignment: false | |||
DisableFormat: false | |||
ExperimentalAutoDetectBinPacking: false | |||
FixNamespaceComments: false | |||
# ForEachMacros: | |||
# - foreach | |||
# - Q_FOREACH | |||
# - BOOST_FOREACH | |||
IncludeBlocks: Preserve | |||
# IncludeCategories: | |||
# - Regex: '^"(llvm|llvm-c|clang|clang-c)/' | |||
# Priority: 2 | |||
# - Regex: '^(<|"(gtest|gmock|isl|json)/)' | |||
# Priority: 3 | |||
# - Regex: '.*' | |||
# Priority: 1 | |||
# IncludeIsMainRegex: '(Test)?$' | |||
IndentCaseLabels: true | |||
IndentPPDirectives: AfterHash | |||
IndentWidth: 4 | |||
IndentWrappedFunctionNames: false | |||
JavaScriptQuotes: Leave | |||
JavaScriptWrapImports: true | |||
KeepEmptyLinesAtTheStartOfBlocks: true | |||
MacroBlockBegin: '' | |||
MacroBlockEnd: '' | |||
MaxEmptyLinesToKeep: 1 | |||
NamespaceIndentation: None | |||
ObjCBlockIndentWidth: 4 | |||
ObjCSpaceAfterProperty: false | |||
ObjCSpaceBeforeProtocolList: false | |||
PenaltyBreakAssignment: 2 | |||
PenaltyBreakBeforeFirstCallParameter: 19 | |||
PenaltyBreakComment: 300 | |||
PenaltyBreakFirstLessLess: 120 | |||
PenaltyBreakString: 1000 | |||
PenaltyExcessCharacter: 1000000 | |||
PenaltyReturnTypeOnItsOwnLine: 80 | |||
PointerAlignment: Left | |||
ReflowComments: true | |||
SortIncludes: false | |||
SortUsingDeclarations: false | |||
SpaceAfterCStyleCast: false | |||
SpaceAfterTemplateKeyword: false | |||
SpaceBeforeAssignmentOperators: true | |||
SpaceBeforeParens: Always | |||
SpaceInEmptyParentheses: false | |||
SpacesBeforeTrailingComments: 1 | |||
SpacesInAngles: false | |||
SpacesInContainerLiterals: false | |||
SpacesInCStyleCastParentheses: false | |||
SpacesInParentheses: false | |||
SpacesInSquareBrackets: false | |||
Standard: Cpp11 | |||
TabWidth: 4 | |||
UseTab: Always |
@@ -0,0 +1,26 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "../lib/cbitmapfilter.h" | |||
//------------------------------------------------------------------------ | |||
namespace VSTGUI { | |||
namespace BitmapFilter { | |||
//------------------------------------------------------------------------ | |||
class CIBoxBlurFilter : public BitmapFilter::FilterBase | |||
{ | |||
public: | |||
CIBoxBlurFilter (); | |||
bool run (bool replace) override; | |||
static IFilter* CreateFunction (IdStringPtr _name) { return new CIBoxBlurFilter (); } | |||
}; | |||
//------------------------------------------------------------------------ | |||
} // BitmapFilter | |||
} // VSTGUI |
@@ -0,0 +1,81 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#import "ciboxblurfilter.h" | |||
#import "../lib/platform/mac/cgbitmap.h" | |||
#import "../lib/cbitmap.h" | |||
#import <QuartzCore/QuartzCore.h> | |||
namespace VSTGUI { | |||
namespace BitmapFilter { | |||
//------------------------------------------------------------------------ | |||
__attribute__((__constructor__)) static void registerFilter () | |||
{ | |||
Factory::getInstance ().registerFilter (Standard::kBoxBlur, CIBoxBlurFilter::CreateFunction); | |||
} | |||
//------------------------------------------------------------------------ | |||
CIBoxBlurFilter::CIBoxBlurFilter () : FilterBase ("A Box Blur Filter using CoreImage") | |||
{ | |||
registerProperty (Standard::Property::kInputBitmap, | |||
BitmapFilter::Property (BitmapFilter::Property::kObject)); | |||
registerProperty (Standard::Property::kRadius, | |||
BitmapFilter::Property (static_cast<int32_t> (2))); | |||
} | |||
//------------------------------------------------------------------------ | |||
bool CIBoxBlurFilter::run (bool replace) | |||
{ | |||
CBitmap* inputBitmap = getInputBitmap (); | |||
int32_t radius = static_cast<int32_t> ( | |||
static_cast<double> (getProperty (Standard::Property::kRadius).getInteger ()) * | |||
inputBitmap->getPlatformBitmap ()->getScaleFactor ()); | |||
if (inputBitmap == nullptr) | |||
return false; | |||
CGBitmap* cgBitmap = dynamic_cast<CGBitmap*> (inputBitmap->getPlatformBitmap ()); | |||
if (cgBitmap == nullptr) | |||
return false; | |||
CIImage* inputImage = [[[CIImage alloc] initWithCGImage:cgBitmap->getCGImage ()] autorelease]; | |||
if (inputImage == nil) | |||
return false; | |||
CIFilter* filter = [CIFilter filterWithName:@"CIBoxBlur"]; | |||
NSMutableDictionary* values = [[NSMutableDictionary new] autorelease]; | |||
[values setObject:@(radius) forKey:@"inputRadius"]; | |||
[values setObject:inputImage forKey:@"inputImage"]; | |||
[filter setValuesForKeysWithDictionary:values]; | |||
CIImage* outputImage = [filter valueForKey:@"outputImage"]; | |||
if (outputImage == nil) | |||
return false; | |||
SharedPointer<CGBitmap> outputBitmap = owned (new CGBitmap (cgBitmap->getSize ())); | |||
CGContextRef cgContext = outputBitmap->createCGContext (); | |||
if (cgContext == nullptr) | |||
return false; | |||
CGContextScaleCTM (cgContext, 1, -1); | |||
CIContext* context = [CIContext contextWithCGContext:cgContext options:nil]; | |||
if (context == nil) | |||
return false; | |||
[context drawImage:outputImage | |||
atPoint:CGPointMake (0, -cgBitmap->getSize ().y) | |||
fromRect:CGRectMake (0, 0, cgBitmap->getSize ().x, cgBitmap->getSize ().y)]; | |||
CFRelease (cgContext); | |||
outputBitmap->setScaleFactor (cgBitmap->getScaleFactor ()); | |||
if (replace) | |||
{ | |||
inputBitmap->setPlatformBitmap (outputBitmap); | |||
return true; | |||
} | |||
return registerProperty (Standard::Property::kOutputBitmap, | |||
BitmapFilter::Property (owned (new CBitmap (outputBitmap)))); | |||
} | |||
//------------------------------------------------------------------------ | |||
} // BitmapFilter | |||
} // VSTGUI |
@@ -0,0 +1,269 @@ | |||
//------------------------------------------------------------------------ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
// Flags : clang-format SMTGSequencer | |||
#pragma once | |||
#include "vstgui/lib/vstguifwd.h" | |||
#include "vstgui/lib/ccolor.h" | |||
#include "vstgui/lib/cview.h" | |||
#include "vstgui/lib/dispatchlist.h" | |||
#include "vstgui/lib/itouchevent.h" | |||
#include <array> | |||
#include <bitset> | |||
#include <map> | |||
namespace VSTGUI { | |||
//------------------------------------------------------------------------ | |||
class KeyboardViewBase : public CView | |||
{ | |||
public: | |||
using NoteIndex = int16_t; | |||
using NumNotes = uint8_t; | |||
static constexpr NumNotes MaxNotes = 128; | |||
enum class BitmapID | |||
{ | |||
WhiteKeyPressed = 0, | |||
WhiteKeyUnpressed, | |||
BlackKeyPressed, | |||
BlackKeyUnpressed, | |||
WhiteKeyShadowLeft, | |||
WhiteKeyShadowRight, | |||
NumBitmaps | |||
}; | |||
KeyboardViewBase (); | |||
void setKeyPressed (NoteIndex note, bool state); | |||
virtual void setKeyRange (NoteIndex startNote, NumNotes numKeys); | |||
NoteIndex getKeyRangeStart () const { return startNote; } | |||
NumNotes getNumKeys () const { return numKeys; } | |||
NumNotes getNumWhiteKeys () const; | |||
void setWhiteKeyWidth (CCoord width); | |||
void setBlackKeyWidth (CCoord width); | |||
void setBlackKeyHeight (CCoord height); | |||
void setLineWidth (CCoord width); | |||
CCoord getWhiteKeyWidth () const { return whiteKeyWidth; } | |||
CCoord getBlackKeyWidth () const { return blackKeyWidth; } | |||
CCoord getBlackKeyHeight () const { return blackKeyHeight; } | |||
CCoord getLineWidth () const { return lineWidth; } | |||
void setFrameColor (CColor color); | |||
void setFontColor (CColor color); | |||
void setWhiteKeyColor (CColor color); | |||
void setWhiteKeyPressedColor (CColor color); | |||
void setBlackKeyColor (CColor color); | |||
void setBlackKeyPressedColor (CColor color); | |||
CColor getFrameColor () const { return frameColor; } | |||
CColor getFontColor () const { return fontColor; } | |||
CColor getWhiteKeyColor () const { return whiteKeyColor; } | |||
CColor getWhiteKeyPressedColor () const { return whiteKeyPressedColor; } | |||
CColor getBlackKeyColor () const { return blackKeyColor; } | |||
CColor getBlackKeyPressedColor () const { return blackKeyPressedColor; } | |||
void setNoteNameFont (CFontDesc* font); | |||
CFontDesc* getNoteNameFont () const { return noteNameFont; } | |||
void setDrawNoteText (bool state); | |||
bool getDrawNoteText () const { return drawNoteText; } | |||
void setBitmap (BitmapID bID, CBitmap* bitmap); | |||
CBitmap* getBitmap (BitmapID bID) const; | |||
void setWhiteKeyBitmapInset (const CRect& inset); // TODO: uidesc | |||
void setBlackKeyBitmapInset (const CRect& inset); // TODO: uidesc | |||
const CRect& getNoteRect (NoteIndex note) const { return noteRectCache[note]; } | |||
bool isWhiteKey (NoteIndex note) const; | |||
void drawRect (CDrawContext* context, const CRect& dirtyRect) override; | |||
void setViewSize (const CRect& rect, bool invalid = true) override; | |||
bool sizeToFit () override; | |||
//------------------------------------------------------------------------ | |||
protected: | |||
using NoteRectCache = std::array<CRect, MaxNotes>; | |||
void invalidNote (NoteIndex note); | |||
NoteIndex pointToNote (const CPoint& p, bool ignoreY) const; | |||
const NoteRectCache& getNoteRectCache () const { return noteRectCache; } | |||
private: | |||
void drawNote (CDrawContext* context, CRect& rect, NoteIndex note, bool isWhite) const; | |||
CRect calcNoteRect (NoteIndex note) const; | |||
void updateNoteRectCache () const; | |||
void createBitmapCache (); | |||
using BitmapArray = | |||
std::array<SharedPointer<CBitmap>, static_cast<size_t> (BitmapID::NumBitmaps)>; | |||
BitmapArray bitmaps; | |||
SharedPointer<CBitmap> whiteKeyBitmapCache; | |||
SharedPointer<CBitmap> blackKeyBitmapCache; | |||
SharedPointer<CFontDesc> noteNameFont; | |||
CRect whiteKeyBitmapInset; | |||
CRect blackKeyBitmapInset; | |||
CCoord whiteKeyWidth {30}; | |||
CCoord blackKeyWidth {20}; | |||
CCoord blackKeyHeight {20}; | |||
CCoord lineWidth {1.}; | |||
CColor frameColor {kBlackCColor}; | |||
CColor fontColor {kBlackCColor}; | |||
CColor whiteKeyColor {kWhiteCColor}; | |||
CColor whiteKeyPressedColor {kGreyCColor}; | |||
CColor blackKeyColor {kBlackCColor}; | |||
CColor blackKeyPressedColor {kGreyCColor}; | |||
NumNotes numKeys {88}; | |||
NoteIndex startNote {21}; | |||
bool drawNoteText {false}; | |||
mutable bool noteRectCacheInvalid {true}; | |||
mutable NoteRectCache noteRectCache; | |||
std::bitset<MaxNotes> keyPressed {}; | |||
}; | |||
class KeyboardViewRangeSelector; | |||
//------------------------------------------------------------------------ | |||
struct IKeyboardViewKeyRangeChangedListener | |||
{ | |||
virtual void onKeyRangeChanged (KeyboardViewRangeSelector*) = 0; | |||
virtual ~IKeyboardViewKeyRangeChangedListener () noexcept = default; | |||
}; | |||
//------------------------------------------------------------------------ | |||
class KeyboardViewRangeSelector : public KeyboardViewBase | |||
{ | |||
public: | |||
struct Range | |||
{ | |||
NoteIndex position; | |||
NumNotes length; | |||
Range (NoteIndex position = 0, NumNotes length = 0) : position (position), length (length) | |||
{ | |||
} | |||
bool operator!= (const Range& r) const | |||
{ | |||
return position != r.position || length != r.length; | |||
} | |||
}; | |||
KeyboardViewRangeSelector () = default; | |||
void drawRect (CDrawContext* context, const CRect& dirtyRect) override; | |||
void setKeyRange (NoteIndex startNote, NumNotes numKeys) override; | |||
void setSelectionRange (const Range& range); | |||
void setSelectionMinMax (NumNotes minRange, NumNotes maxRange); | |||
const Range& getSelectionRange () const { return selectionRange; } | |||
NumNotes getSelectionMin () const { return rangeMin; } | |||
NumNotes getSelectionMax () const { return rangeMax; } | |||
NumNotes getNumWhiteKeysSelected () const; | |||
void registerKeyRangeChangedListener (IKeyboardViewKeyRangeChangedListener* listener); | |||
void unregisterKeyRangeChangedListener (IKeyboardViewKeyRangeChangedListener* listener); | |||
//------------------------------------------------------------------------ | |||
private: | |||
DispatchList<IKeyboardViewKeyRangeChangedListener*> listeners; | |||
Range selectionRange {0, 12}; | |||
NumNotes rangeMin {12}; | |||
NumNotes rangeMax {24}; | |||
#if VSTGUI_TOUCH_EVENT_HANDLING | |||
void onTouchEvent (ITouchEvent& event) override; | |||
bool wantsMultiTouchEvents () const override; | |||
void onTouchBegin (const ITouchEvent::TouchPair& touch, ITouchEvent& event); | |||
void onTouchMove (const ITouchEvent::TouchPair& touch, ITouchEvent& event); | |||
enum TouchMode {kUnknown, kMoveRange, kChangeRangeFront, kChangeRangeBack}; | |||
Range selectionRangeOnTouchStart; | |||
int32_t touchIds[2] {-1}; | |||
TouchMode touchMode {kUnknown}; | |||
NoteIndex touchStartNote[2]; | |||
#else | |||
CMouseEventResult onMouseDown (CPoint& where, const CButtonState& buttons) override; | |||
CMouseEventResult onMouseMoved (CPoint& where, const CButtonState& buttons) override; | |||
CMouseEventResult onMouseUp (CPoint& where, const CButtonState& buttons) override; | |||
CMouseEventResult onMouseCancel () override; | |||
Range moveStartRange; | |||
NoteIndex moveStartNote {-1}; | |||
#endif | |||
}; | |||
//------------------------------------------------------------------------ | |||
struct IKeyboardViewPlayerDelegate | |||
{ | |||
using NoteIndex = KeyboardViewBase::NoteIndex; | |||
virtual int32_t onNoteOn (NoteIndex note, double xPos, double yPos) = 0; | |||
virtual void onNoteOff (NoteIndex note, int32_t noteID) = 0; | |||
virtual void onNoteModulation (int32_t noteID, double xPos, double yPos) = 0; | |||
virtual ~IKeyboardViewPlayerDelegate () noexcept = default; | |||
}; | |||
//------------------------------------------------------------------------ | |||
struct KeyboardViewPlayerDelegate : public IKeyboardViewPlayerDelegate | |||
{ | |||
int32_t onNoteOn (NoteIndex note, double xPos, double yPos) override { return -1; } | |||
void onNoteOff (NoteIndex note, int32_t noteID) override {} | |||
void onNoteModulation (int32_t noteID, double xPos, double yPos) override {} | |||
}; | |||
//------------------------------------------------------------------------ | |||
class KeyboardView : public KeyboardViewBase | |||
{ | |||
public: | |||
KeyboardView (); | |||
void setDelegate (IKeyboardViewPlayerDelegate* delegate) { this->delegate = delegate; } | |||
private: | |||
double calcYParameter (NoteIndex note, CCoord y) const; | |||
double calcXParameter (NoteIndex note, CCoord x) const; | |||
#if VSTGUI_TOUCH_EVENT_HANDLING | |||
bool wantsMultiTouchEvents () const override { return true; } | |||
void onTouchEvent (ITouchEvent& event) override; | |||
void onTouchBegin (const ITouchEvent::TouchPair& touch, ITouchEvent& event); | |||
void onTouchMove (const ITouchEvent::TouchPair& touch, ITouchEvent& event); | |||
void onTouchEnd (const ITouchEvent::TouchPair& touch, ITouchEvent& event); | |||
struct NoteTouch | |||
{ | |||
NoteIndex note; | |||
int32_t noteID; | |||
NoteTouch (NoteIndex note) : note (note), noteID (-1) {} | |||
}; | |||
std::map<int32_t, NoteTouch> noteTouches; | |||
#else | |||
void doNoteOff (); | |||
void doNoteOn (NoteIndex note, double yPos, double xPos); | |||
CMouseEventResult onMouseDown (CPoint& where, const CButtonState& buttons) override; | |||
CMouseEventResult onMouseMoved (CPoint& where, const CButtonState& buttons) override; | |||
CMouseEventResult onMouseUp (CPoint& where, const CButtonState& buttons) override; | |||
CMouseEventResult onMouseCancel () override; | |||
NoteIndex pressedNote {-1}; | |||
int32_t noteID {-1}; | |||
#endif | |||
IKeyboardViewPlayerDelegate* delegate {nullptr}; | |||
}; | |||
//------------------------------------------------------------------------ | |||
} // VSTGUI |
@@ -0,0 +1,85 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
/** | |||
@mainpage | |||
Welcome to VSTGUI | |||
- @ref intro @n | |||
- @ref page_news_and_changes @n | |||
- @ref page_vst3_inline_editing @n | |||
- @ref page_vst2_tutorial @n | |||
- @ref page_changelog @n | |||
- @ref page_license @n | |||
@section intro Introduction | |||
\par VSTGUI | |||
VSTGUI is a User Interface Toolkit mainly for Audio Plug-Ins (VST, AudioUnit, etc). | |||
\par History | |||
First developed inhouse of Steinberg Media Technologies (around 1998) for their first VST Plug-Ins. | |||
Later added as binary libraries to the official VST SDK. | |||
Since May 2003 VSTGUI is open source, was hosted at sourceforge and now at GitHub https://github.com/steinbergmedia/vstgui. | |||
Currently VSTGUI compiles on | |||
\par Microsoft Windows (with Visual Studio and Windows 7 Platform SDK) | |||
- 7 (32 and 64 bit) | |||
- 8 (32 and 64 bit) | |||
- 10 (32 and 64 bit) | |||
\par Apple Mac OS X (with gcc 4.0/4.2 or Clang 2.0) | |||
- 10.8 - 10.14 (32 and 64 bit) | |||
\par Apple iOS | |||
- 7.0 - 12.0 (32 and 64 bit) | |||
\par Linux (with gcc >= 5.4 or clang >= 3.8) | |||
- Ubuntu 2016.04 or newer | |||
\sa | |||
<a href="https://github.com/steinbergmedia/vstgui target=_blank> VSTGUI @ GitHub </a> | |||
@page page_setup Setup | |||
\par To include VSTGUI in your projects you only have to add | |||
- vstgui_win32.cpp (for Windows) | |||
- vstgui_linux.cpp (for Linux) | |||
- vstgui_mac.mm (for macOS) | |||
- vstgui_ios.mm (for iOS) | |||
to your IDE project and add a search path to the parent of the root folder of vstgui. | |||
\par On macOS, you need to link to the following Frameworks: | |||
- Accelerate | |||
- Carbon | |||
- Cocoa | |||
- OpenGL | |||
- QuartzCore | |||
\par On iOS, you need to link to the following Frameworks: | |||
- UIKit | |||
- CoreGraphics | |||
- ImageIO | |||
- CoreText | |||
- GLKit | |||
- Accelerate | |||
- QuartzCore | |||
\par On Linux you have to install xcb, freetype, fontconfig and cairo | |||
Debian/Ubuntu based distribution: | |||
- libx11-xcb-dev | |||
- libxcb-util-dev | |||
- libxcb-cursor-dev | |||
- libxcb-keysyms1-dev | |||
- libxcb-xkb-dev | |||
- libxkbcommon-dev | |||
- libxkbcommon-x11-dev | |||
- libfontconfig1-dev | |||
- libcairo2-dev | |||
*/ |
@@ -0,0 +1,836 @@ | |||
/* The standard CSS for doxygen */ | |||
body, table, div, p, dl { | |||
font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif; | |||
font-size: 12px; | |||
} | |||
/* @group Heading Levels */ | |||
h1 { | |||
font-size: 150%; | |||
} | |||
.title { | |||
font-size: 150%; | |||
font-weight: bold; | |||
margin: 10px 2px; | |||
} | |||
h2 { | |||
font-size: 120%; | |||
} | |||
h3 { | |||
font-size: 100%; | |||
} | |||
dt { | |||
font-weight: bold; | |||
} | |||
div.multicol { | |||
-moz-column-gap: 1em; | |||
-webkit-column-gap: 1em; | |||
-moz-column-count: 3; | |||
-webkit-column-count: 3; | |||
} | |||
p.startli, p.startdd, p.starttd { | |||
margin-top: 2px; | |||
} | |||
p.endli { | |||
margin-bottom: 0px; | |||
} | |||
p.enddd { | |||
margin-bottom: 4px; | |||
} | |||
p.endtd { | |||
margin-bottom: 2px; | |||
} | |||
/* @end */ | |||
caption { | |||
font-weight: bold; | |||
} | |||
span.legend { | |||
font-size: 70%; | |||
text-align: center; | |||
} | |||
h3.version { | |||
font-size: 90%; | |||
text-align: center; | |||
} | |||
div.qindex, div.navtab{ | |||
background-color: #E7EEF4; | |||
border: 1px solid #91B0CE; | |||
text-align: center; | |||
margin: 2px; | |||
padding: 2px; | |||
} | |||
div.qindex, div.navpath { | |||
width: 100%; | |||
line-height: 140%; | |||
} | |||
div.navtab { | |||
margin-right: 15px; | |||
} | |||
/* @group Link Styling */ | |||
a { | |||
color: #30506F; | |||
font-weight: normal; | |||
text-decoration: none; | |||
} | |||
.contents a:visited { | |||
color: #3A6085; | |||
} | |||
a:hover { | |||
text-decoration: underline; | |||
} | |||
a.qindex { | |||
font-weight: bold; | |||
} | |||
a.qindexHL { | |||
font-weight: bold; | |||
background-color: #88AACB; | |||
color: #ffffff; | |||
border: 1px double #6F98C0; | |||
} | |||
.contents a.qindexHL:visited { | |||
color: #ffffff; | |||
} | |||
a.el { | |||
font-weight: bold; | |||
} | |||
a.elRef { | |||
} | |||
a.code { | |||
color: #3A6085; | |||
} | |||
a.codeRef { | |||
color: #3A6085; | |||
} | |||
/* @end */ | |||
dl.el { | |||
margin-left: -1cm; | |||
} | |||
.fragment { | |||
font-family: monospace, fixed; | |||
font-size: 105%; | |||
} | |||
pre.fragment { | |||
border: 1px solid #B8CCE0; | |||
background-color: #FAFCFD; | |||
padding: 4px 6px; | |||
margin: 4px 8px 4px 2px; | |||
overflow: auto; | |||
word-wrap: break-word; | |||
font-size: 9pt; | |||
line-height: 125%; | |||
} | |||
div.ah { | |||
background-color: black; | |||
font-weight: bold; | |||
color: #ffffff; | |||
margin-bottom: 3px; | |||
margin-top: 3px; | |||
padding: 0.2em; | |||
border: solid thin #333; | |||
border-radius: 0.5em; | |||
-webkit-border-radius: .5em; | |||
-moz-border-radius: .5em; | |||
box-shadow: 2px 2px 3px #999; | |||
-webkit-box-shadow: 2px 2px 3px #999; | |||
-moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; | |||
background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444)); | |||
background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000); | |||
} | |||
div.groupHeader { | |||
margin-left: 16px; | |||
margin-top: 12px; | |||
font-weight: bold; | |||
} | |||
div.groupText { | |||
margin-left: 16px; | |||
font-style: italic; | |||
} | |||
body { | |||
background: white; | |||
color: black; | |||
margin: 0; | |||
} | |||
div.contents { | |||
margin-top: 10px; | |||
margin-left: 10px; | |||
margin-right: 5px; | |||
} | |||
td.indexkey { | |||
background-color: #E7EEF4; | |||
font-weight: bold; | |||
border: 1px solid #B8CCE0; | |||
margin: 2px 0px 2px 0; | |||
padding: 2px 10px; | |||
} | |||
td.indexvalue { | |||
background-color: #E7EEF4; | |||
border: 1px solid #B8CCE0; | |||
padding: 2px 10px; | |||
margin: 2px 0px; | |||
} | |||
tr.memlist { | |||
background-color: #EAF0F5; | |||
} | |||
p.formulaDsp { | |||
text-align: center; | |||
} | |||
img.formulaDsp { | |||
} | |||
img.formulaInl { | |||
vertical-align: middle; | |||
} | |||
div.center { | |||
text-align: center; | |||
margin-top: 0px; | |||
margin-bottom: 0px; | |||
padding: 0px; | |||
} | |||
div.center img { | |||
border: 0px; | |||
} | |||
address.footer { | |||
text-align: right; | |||
padding-right: 12px; | |||
} | |||
img.footer { | |||
border: 0px; | |||
vertical-align: middle; | |||
} | |||
/* @group Code Colorization */ | |||
span.keyword { | |||
color: #008000 | |||
} | |||
span.keywordtype { | |||
color: #604020 | |||
} | |||
span.keywordflow { | |||
color: #e08000 | |||
} | |||
span.comment { | |||
color: #800000 | |||
} | |||
span.preprocessor { | |||
color: #806020 | |||
} | |||
span.stringliteral { | |||
color: #002080 | |||
} | |||
span.charliteral { | |||
color: #008080 | |||
} | |||
span.vhdldigit { | |||
color: #ff00ff | |||
} | |||
span.vhdlchar { | |||
color: #000000 | |||
} | |||
span.vhdlkeyword { | |||
color: #700070 | |||
} | |||
span.vhdllogic { | |||
color: #ff0000 | |||
} | |||
/* @end */ | |||
/* | |||
.search { | |||
color: #003399; | |||
font-weight: bold; | |||
} | |||
form.search { | |||
margin-bottom: 0px; | |||
margin-top: 0px; | |||
} | |||
input.search { | |||
font-size: 75%; | |||
color: #000080; | |||
font-weight: normal; | |||
background-color: #e8eef2; | |||
} | |||
*/ | |||
td.tiny { | |||
font-size: 75%; | |||
} | |||
.dirtab { | |||
padding: 4px; | |||
border-collapse: collapse; | |||
border: 1px solid #91B0CE; | |||
} | |||
th.dirtab { | |||
background: #E7EEF4; | |||
font-weight: bold; | |||
} | |||
hr { | |||
height: 0px; | |||
border: none; | |||
border-top: 1px solid #3E668E; | |||
} | |||
hr.footer { | |||
height: 1px; | |||
} | |||
/* @group Member Descriptions */ | |||
table.memberdecls { | |||
border-spacing: 0px; | |||
padding: 0px; | |||
} | |||
.mdescLeft, .mdescRight, | |||
.memItemLeft, .memItemRight, | |||
.memTemplItemLeft, .memTemplItemRight, .memTemplParams { | |||
background-color: #F8FAFB; | |||
border: none; | |||
margin: 4px; | |||
padding: 1px 0 0 8px; | |||
} | |||
.mdescLeft, .mdescRight { | |||
padding: 0px 8px 4px 8px; | |||
color: #555; | |||
} | |||
.memItemLeft, .memItemRight, .memTemplParams { | |||
border-top: 1px solid #B8CCE0; | |||
} | |||
.memItemLeft, .memTemplItemLeft { | |||
white-space: nowrap; | |||
} | |||
.memItemRight { | |||
width: 100%; | |||
} | |||
.memTemplParams { | |||
color: #3A6085; | |||
white-space: nowrap; | |||
} | |||
/* @end */ | |||
/* @group Member Details */ | |||
/* Styles for detailed member documentation */ | |||
.memtemplate { | |||
font-size: 80%; | |||
color: #3A6085; | |||
font-weight: normal; | |||
margin-left: 9px; | |||
} | |||
.memnav { | |||
background-color: #E7EEF4; | |||
border: 1px solid #91B0CE; | |||
text-align: center; | |||
margin: 2px; | |||
margin-right: 15px; | |||
padding: 2px; | |||
} | |||
.mempage { | |||
width: 100%; | |||
} | |||
.memitem { | |||
padding: 0; | |||
margin-bottom: 10px; | |||
margin-right: 5px; | |||
} | |||
.memname { | |||
white-space: nowrap; | |||
font-weight: bold; | |||
margin-left: 6px; | |||
} | |||
.memproto { | |||
border-top: 1px solid #96B4D1; | |||
border-left: 1px solid #96B4D1; | |||
border-right: 1px solid #96B4D1; | |||
padding: 6px 0px 6px 0px; | |||
color: #1A2B3B; | |||
font-weight: bold; | |||
text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); | |||
/* opera specific markup */ | |||
box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); | |||
border-top-right-radius: 8px; | |||
border-top-left-radius: 8px; | |||
/* firefox specific markup */ | |||
-moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; | |||
-moz-border-radius-topright: 8px; | |||
-moz-border-radius-topleft: 8px; | |||
/* webkit specific markup */ | |||
-webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); | |||
-webkit-border-top-right-radius: 8px; | |||
-webkit-border-top-left-radius: 8px; | |||
background-image:url('nav_f.png'); | |||
background-repeat:repeat-x; | |||
background-color: #DCE6EF; | |||
} | |||
.memdoc { | |||
border-bottom: 1px solid #96B4D1; | |||
border-left: 1px solid #96B4D1; | |||
border-right: 1px solid #96B4D1; | |||
padding: 2px 5px; | |||
background-color: #FAFCFD; | |||
border-top-width: 0; | |||
/* opera specific markup */ | |||
border-bottom-left-radius: 8px; | |||
border-bottom-right-radius: 8px; | |||
box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); | |||
/* firefox specific markup */ | |||
-moz-border-radius-bottomleft: 8px; | |||
-moz-border-radius-bottomright: 8px; | |||
-moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; | |||
background-image: -moz-linear-gradient(center top, #FFFFFF 0%, #FFFFFF 60%, #F5F8FA 95%, #EAF0F5); | |||
/* webkit specific markup */ | |||
-webkit-border-bottom-left-radius: 8px; | |||
-webkit-border-bottom-right-radius: 8px; | |||
-webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); | |||
background-image: -webkit-gradient(linear,center top,center bottom,from(#FFFFFF), color-stop(0.6,#FFFFFF), color-stop(0.60,#FFFFFF), color-stop(0.95,#F5F8FA), to(#EAF0F5)); | |||
} | |||
.paramkey { | |||
text-align: right; | |||
} | |||
.paramtype { | |||
white-space: nowrap; | |||
} | |||
.paramname { | |||
color: #602020; | |||
white-space: nowrap; | |||
} | |||
.paramname em { | |||
font-style: normal; | |||
} | |||
.params, .retval, .exception, .tparams { | |||
border-spacing: 6px 2px; | |||
} | |||
.params .paramname, .retval .paramname { | |||
font-weight: bold; | |||
vertical-align: top; | |||
} | |||
.params .paramtype { | |||
font-style: italic; | |||
vertical-align: top; | |||
} | |||
.params .paramdir { | |||
font-family: "courier new",courier,monospace; | |||
vertical-align: top; | |||
} | |||
/* @end */ | |||
/* @group Directory (tree) */ | |||
/* for the tree view */ | |||
.ftvtree { | |||
font-family: sans-serif; | |||
margin: 0px; | |||
} | |||
/* these are for tree view when used as main index */ | |||
.directory { | |||
font-size: 9pt; | |||
font-weight: bold; | |||
margin: 5px; | |||
} | |||
.directory h3 { | |||
margin: 0px; | |||
margin-top: 1em; | |||
font-size: 11pt; | |||
} | |||
/* | |||
The following two styles can be used to replace the root node title | |||
with an image of your choice. Simply uncomment the next two styles, | |||
specify the name of your image and be sure to set 'height' to the | |||
proper pixel height of your image. | |||
*/ | |||
/* | |||
.directory h3.swap { | |||
height: 61px; | |||
background-repeat: no-repeat; | |||
background-image: url("yourimage.gif"); | |||
} | |||
.directory h3.swap span { | |||
display: none; | |||
} | |||
*/ | |||
.directory > h3 { | |||
margin-top: 0; | |||
} | |||
.directory p { | |||
margin: 0px; | |||
white-space: nowrap; | |||
} | |||
.directory div { | |||
display: none; | |||
margin: 0px; | |||
} | |||
.directory img { | |||
vertical-align: -30%; | |||
} | |||
/* these are for tree view when not used as main index */ | |||
.directory-alt { | |||
font-size: 100%; | |||
font-weight: bold; | |||
} | |||
.directory-alt h3 { | |||
margin: 0px; | |||
margin-top: 1em; | |||
font-size: 11pt; | |||
} | |||
.directory-alt > h3 { | |||
margin-top: 0; | |||
} | |||
.directory-alt p { | |||
margin: 0px; | |||
white-space: nowrap; | |||
} | |||
.directory-alt div { | |||
display: none; | |||
margin: 0px; | |||
} | |||
.directory-alt img { | |||
vertical-align: -30%; | |||
} | |||
/* @end */ | |||
div.dynheader { | |||
margin-top: 8px; | |||
} | |||
address { | |||
font-style: normal; | |||
color: #1F3347; | |||
} | |||
table.doxtable { | |||
border-collapse:collapse; | |||
} | |||
table.doxtable td, table.doxtable th { | |||
border: 1px solid #21374C; | |||
padding: 3px 7px 2px; | |||
} | |||
table.doxtable th { | |||
background-color: #2B4762; | |||
color: #FFFFFF; | |||
font-size: 110%; | |||
padding-bottom: 4px; | |||
padding-top: 5px; | |||
text-align:left; | |||
} | |||
.tabsearch { | |||
top: 0px; | |||
left: 10px; | |||
height: 36px; | |||
background-image: url('tab_b.png'); | |||
z-index: 101; | |||
overflow: hidden; | |||
font-size: 13px; | |||
} | |||
.navpath ul | |||
{ | |||
font-size: 11px; | |||
background-image:url('tab_b.png'); | |||
background-repeat:repeat-x; | |||
height:30px; | |||
line-height:30px; | |||
color:#739BC2; | |||
border:solid 1px #B5CADE; | |||
overflow:hidden; | |||
margin:0px; | |||
padding:0px; | |||
} | |||
.navpath li | |||
{ | |||
list-style-type:none; | |||
float:left; | |||
padding-left:10px; | |||
padding-right:15px; | |||
background-image:url('bc_s.png'); | |||
background-repeat:no-repeat; | |||
background-position:right; | |||
color:#294560; | |||
} | |||
.navpath li.navelem a | |||
{ | |||
height:32px; | |||
display:block; | |||
text-decoration: none; | |||
outline: none; | |||
} | |||
.navpath li.navelem a:hover | |||
{ | |||
color:#4E80B1; | |||
} | |||
.navpath li.footer | |||
{ | |||
list-style-type:none; | |||
float:right; | |||
padding-left:10px; | |||
padding-right:15px; | |||
background-image:none; | |||
background-repeat:no-repeat; | |||
background-position:right; | |||
color:#294560; | |||
font-size: 8pt; | |||
} | |||
div.summary | |||
{ | |||
float: right; | |||
font-size: 8pt; | |||
padding-right: 5px; | |||
width: 50%; | |||
text-align: right; | |||
} | |||
div.summary a | |||
{ | |||
white-space: nowrap; | |||
} | |||
div.ingroups | |||
{ | |||
font-size: 8pt; | |||
padding-left: 5px; | |||
width: 50%; | |||
text-align: left; | |||
} | |||
div.ingroups a | |||
{ | |||
white-space: nowrap; | |||
} | |||
div.header | |||
{ | |||
background-image:url('nav_h.png'); | |||
background-repeat:repeat-x; | |||
background-color: #F8FAFB; | |||
margin: 0px; | |||
border-bottom: 1px solid #B8CCE0; | |||
} | |||
div.headertitle | |||
{ | |||
padding: 5px 5px 5px 10px; | |||
} | |||
dl | |||
{ | |||
padding: 0 0 0 10px; | |||
} | |||
dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug | |||
{ | |||
border-left:4px solid; | |||
padding: 0 0 0 6px; | |||
} | |||
dl.note | |||
{ | |||
border-color: #D0C000; | |||
} | |||
dl.warning, dl.attention | |||
{ | |||
border-color: #FF0000; | |||
} | |||
dl.pre, dl.post, dl.invariant | |||
{ | |||
border-color: #00D000; | |||
} | |||
dl.deprecated | |||
{ | |||
border-color: #505050; | |||
} | |||
dl.todo | |||
{ | |||
border-color: #00C0E0; | |||
} | |||
dl.test | |||
{ | |||
border-color: #3030E0; | |||
} | |||
dl.bug | |||
{ | |||
border-color: #C08050; | |||
} | |||
#projectlogo | |||
{ | |||
text-align: center; | |||
vertical-align: bottom; | |||
border-collapse: separate; | |||
} | |||
#projectlogo img | |||
{ | |||
border: 0px none; | |||
} | |||
#projectname | |||
{ | |||
font: 250% Tahoma, Arial,sans-serif; | |||
margin: 0px; | |||
padding: 0px; | |||
} | |||
#projectbrief | |||
{ | |||
font: 80% Tahoma, Arial,sans-serif; | |||
margin: 0px; | |||
margin-bottom: 3px; | |||
padding: 0px; | |||
} | |||
#projectnumber | |||
{ | |||
font: 50% Tahoma, Arial,sans-serif; | |||
margin: 0px; | |||
padding: 0px; | |||
} | |||
#titlearea | |||
{ | |||
padding: 0px; | |||
margin: 0px; | |||
width: 100%; | |||
border-bottom: 1px solid #44709B; | |||
} | |||
.image | |||
{ | |||
text-align: center; | |||
} | |||
.dotgraph | |||
{ | |||
text-align: center; | |||
} | |||
.mscgraph | |||
{ | |||
text-align: center; | |||
} | |||
.caption | |||
{ | |||
font-weight: bold; | |||
} | |||
@@ -0,0 +1,12 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
/** | |||
@page page_changelog Changelog | |||
For newer changes please see the git log. | |||
@include Changelog | |||
*/ |
@@ -0,0 +1,298 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
/** | |||
@page page_news_and_changes New stuff in VSTGUI 4 | |||
- @ref version4_introduction @n | |||
- @ref new_stuff @n | |||
- @ref code_changes @n | |||
- @ref hidpi_support @n | |||
- @ref cocoa_support @n | |||
- @ref ios_support @n | |||
- @subpage page_previous_new_stuff | |||
@section version4_introduction Introduction | |||
Version 4 of VSTGUI is a new milestone release with a restructured code base with the focus of code conformity and easier future enhancements. | |||
The result is that code written for any earlier version of VSTGUI is not always compatible. | |||
It's recommended to start new projects with version 4 while old projects should stay with version 3.6. | |||
@section new_stuff New Stuff | |||
@subsection version4_7 Version 4.7 | |||
- redesigned drag'n drop | |||
- drags with bitmaps are now supported on Windows | |||
- standalone library support for Windows 7 | |||
- new ImageStitcher tool | |||
- the GDI+ draw backend was removed, the Direct2D backend is the replacement | |||
@subsection version4_6 Version 4.6 | |||
- new Control: keyboardView | |||
- cmake cleanup | |||
- fix static object initialization order | |||
- fix build warnings/errors depending on macOS SDK use | |||
- remove warnings | |||
@subsection version4_5 Version 4.5 | |||
- cmake build system | |||
- preview of @ref standalone_library @n | |||
- new Controls: VSTGUI::CMultiLineTextLabel, VSTGUI::CSearchTextEdit | |||
- adopt many c++11 language features | |||
@subsection version4_4 Version 4.4 | |||
- preview Linux version | |||
- support for Windows XP, Mac OS X 10.6 and non c++11 mode will be removed with version 4.5 | |||
@subsection version4_3 Version 4.3 | |||
- last version to support Windows XP, Mac OS X 10.6 and non c++11 mode | |||
- HiDPI support (aka Retina support) for Quartz2D and Direct2D backends | |||
- support for creating a graphics path from a string | |||
- new Control : VSTGUI::CSegmentButton | |||
- add support for adding a custom view to the split view separator | |||
- transformation matrix support in VSTGUI::CDrawContext | |||
- alternative c++11 callback functions for VSTGUI::CFileSelector::run(), VSTGUI::CVSTGUITimer, VSTGUI::CParamDisplay::setValueToStringFunction, VSTGUI::CTextEdit::setStringToValueFunction and VSTGUI::CCommandMenuItem::setActions | |||
Note: All current deprecated methods will be removed in the next version. So make sure that your code compiles with VSTGUI_ENABLE_DEPRECATED_METHODS=0 | |||
@subsection version4_2 Version 4.2 | |||
- iOS Support with Multi Touch handling. See @ref ios_support | |||
- support drawing an icon on a VSTGUI::CTextButton | |||
- VSTGUI::CGradientView | |||
- VSTGUI::CDataBrowser now supports multi row selections | |||
- support compiling in c++11 mode with clang and visual studio | |||
- VSTGUI_OVERRIDE_VMETHOD is now used throughout the vstgui sources to indicate methods which are expecting to override a virtual method of its base classes. (c++11 only) | |||
@subsection version4_1 Version 4.1 | |||
- @ref page_uidescription_editor @n | |||
- VSTGUI::COpenGLView (only Windows & Mac Cocoa) | |||
- VSTGUI::CRowColumnView | |||
- VSTGUI::CShadowViewContainer | |||
- VSTGUI::BitmapFilter | |||
- More @link VSTGUI::CScrollView::CScrollViewStyle VSTGUI::CScrollView styles @endlink | |||
@subsection version4_0 Version 4.0 | |||
- VST3 Support : Complete inline VST3 Editor support. See @ref page_vst3_inline_editing @n | |||
- UIDescription : Building user interfaces via XML description files. See @ref uidescription @n | |||
- Animation Support : Simple to use animations. See @ref page_animation | |||
- Amalgamation : Easy integration in your projects via one or two source files | |||
- Cleaned Code : Removed all deprecated methods and classes, splittet individual classes into different files | |||
- Platform Abstraction : Platform dependent code was refactored and moved into its own files | |||
- New notable classes : VSTGUI::CCheckBox, VSTGUI::CGraphicsPath, VSTGUI::CNinePartTiledBitmap, VSTGUI::IFocusDrawing | |||
- Direct2D drawing on Windows (Windows Vista or Windows 7) | |||
@section code_changes Changes for existing VSTGUI code | |||
@subsection code_changes_4_6_to_4_7 VSTGUI 4.6 -> VSTGUI 4.7 | |||
- CView::doDrag is deprecated, instead use the asynchronous variant of it : CView::doDrag ;-) | |||
- CView don't has drop target methods (onDragEnter, onDragLeave, onDragMove and onDrop) anymore. Instead it has a method to return a drop target. See the documentation for IDropTarget on how to use it. | |||
- the CControlEnum is gone and is moved into the classes where they are used: CParamDisplay/COptionMenu/CTextEdit/CSlider | |||
- CControl::kMessageTagWillChange and CControl::kMessageTagDidChange is gone, use IControlListener instead | |||
- COptionMenu::popup has changed behaviour and got a callback function that will be called when the popup is closed. The return of COptionMenu::popup now only indicates if the popup was shown. | |||
- IDataBrowserDelegate is now a real virtual interface class, use DataBrowserDelegateAdapter instead if you get compile/linker errors. | |||
- renamed the following interface adapter classes : | |||
- IViewListenerAdapter -> ViewListenerAdapter | |||
- IViewContainerListenerAdapter -> ViewContainerListenerAdapter | |||
- IViewMouseListenerAdapter -> ViewMouseListenerAdapter | |||
- IGenericStringListDataBrowserSourceSelectionChanged -> GenericStringListDataBrowserSourceSelectionChanged | |||
@subsection code_changes_4_3_to_4_5 VSTGUI 4.3 -> VSTGUI 4.5 | |||
- COffscreenContext::create returns a SharedPointer<COffscreenContext> now, not a naked pointer. | |||
@subsection code_changes_4_2_to_4_3 VSTGUI 4.2 -> VSTGUI 4.3 | |||
- CControlListener was renamed to IControlListener and moved into the VSTGUI namespace and its own header file. A typedef for CControlListener is available but marked as deprecated. | |||
- the VSTGUI::CDrawContext::drawString methods don't set the clip to rect by itself anymore. If you call this method in your code, you need to set the clip yourself now. | |||
- the interfaces for VSTGUI::IController and VSTGUI::IViewCreator have changed and if you have inherited from them you need to change your implementations accordingly. | |||
- the enum DragResult was moved out of CView into VSTGUI namespace | |||
- VSTGUI::CGradient can now be created without a VSTGUI::CDrawContext object | |||
- VSTGUI::CGradientView takes now a VSTGUI::CGradient. Setting the gradient colors and start offsets are removed. | |||
- VSTGUI::CTextButton takes now VSTGUI::CGradient objects instead of colors and start offsets. | |||
- method signature change for: VSTGUI::CViewContainer::getViewAt, VSTGUI::CViewContainer::getViewsAt, VSTGUI::CViewContainer::getContainerAt | |||
- Some methods changed its arguments or return types from a signed type to an unsigned type, check your overrides ! | |||
@subsection code_changes_4_1_to_4_2 VSTGUI 4.1 -> VSTGUI 4.2 | |||
- the class CDragContainer is replaced by IDataPackage. The class CDragContainerHelper is a helper class you can use to quickly get your code up and running again. | |||
- the class IDataBrowser is renamed to IDataBrowserDelegate and the drag and drop methods have changed | |||
- CView::getVisibleSize () was renamed to CView::getVisibleViewSize () | |||
@subsection code_changes_4_0_to_4_1 VSTGUI 4.0 -> VSTGUI 4.1 | |||
- the pBackground member of CView is now private. You must replace all read access with getDrawBackground () or getBackground () and all write access with setBackground () | |||
@subsection code_changes_3_6_to_4_0 VSTGUI 3.6 -> VSTGUI 4.0 | |||
- the variable types were changed to use C99 style types (int32_t, etc), you must do this for all your derivated VSTGUI classes too | |||
- the buttons parameter has changed from long to CButtonState | |||
- your custom views need to use the new mouse methods | |||
- COptionMenuScheme is not available anymore | |||
- VSTGUI::CFileSelector is gone, you have to use VSTGUI::CNewFileSelector | |||
- VST extensions previously enabled via ENABLE_VST_EXTENSION_IN_VSTGUI is gone without replacement | |||
- VSTGUI::CBitmap was completely changed and does not use a transparency color anymore, you need to use the alpha channel of a bitmap to get the same results | |||
- VSTGUI::COffscreenContext is handled completely different. But in most cases you can simply remove all offscreens where you needed them to reduce flicker. | |||
- On Windows graphics are entirely drawn with GDI+ or Direct2D (when available), GDI is not used anymore | |||
- The internal string encoding is now always UTF-8 | |||
- The VSTGUI::CCoord type is now always a double | |||
- on Mac OS X, embedding a CFrame into a non composited carbon window is not supported anymore | |||
- on Mac OS X, when targeting Mac OS X 10.4 some of the graphics path methods are not implemented. | |||
- Method signature changes which don't lead to compile errors: | |||
- CView::setViewSize (CRect& rect, bool invalid = true) | |||
- CView::hitTest (const CPoint& where, CButtonState& buttons = -1) | |||
- CView::invalidRect (CRect& rect) | |||
- CViewContainer::drawBackgroundRect (CDrawContext* pContext, CRect& _updateRect) | |||
- CViewContainer::addView (CView* pView, CRect& mouseableArea, bool mouseEnabled = true) | |||
@section hidpi_support HiDPI notes | |||
- HiDPI is supported on OSX, iOS and Windows (with Direct2D backend) | |||
- Due to platform differences one need to call frame->setZoom (scaleFactor) on Windows, while on OSX and iOS this is not needed. | |||
@section cocoa_support Cocoa notes | |||
- To get cocoa support your minimum required Mac OS X version is 10.6. | |||
- In 32 bit Cocoa and Carbon are available. You can switch between them with CFrame::setCocoaMode(bool state). You must do this before creating the CFrame. | |||
- In 64 bit only Cocoa is available. | |||
- The pSystemWindow pointer in the CFrame constructor must be a NSView not a NSWindow. | |||
@section ios_support iOS support notes | |||
- VSTGUI supports iOS 7 and later | |||
- Currently COptionMenu, CScrollView and COpenGLView are not supported | |||
- Support for a single MultiTouch View is not yet tested and the API may change in the future | |||
@page page_previous_new_stuff New Stuff in VSTGUI 3.6 and earlier | |||
@section new_mouse_methods New mouse methods | |||
In earlier versions there were only one method in CView for handling mouse events (VSTGUI::CView::mouse). | |||
In this version there are five new methods : | |||
- VSTGUI::CView::onMouseDown (new in 3.5) | |||
- VSTGUI::CView::onMouseUp (new in 3.5) | |||
- VSTGUI::CView::onMouseMoved (new in 3.5) | |||
- VSTGUI::CView::onMouseEntered (new in 3.5) | |||
- VSTGUI::CView::onMouseExited (new in 3.5) | |||
For convenience the old method is still working, but should be replaced with the ones above. | |||
@section other_new_things Other new things | |||
- VSTGUI::CDataBrowser (new in 3.5) | |||
- VSTGUI::CScrollView (new in 3.0) | |||
- VSTGUI::CTabView (new in 3.0) | |||
- Mac OS X 64 bit support via Cocoa. (new in 3.6) | |||
- New Fileselector class : VSTGUI::CNewFileSelector (new in 3.6) | |||
- VSTGUI::COptionMenu refactored. Supports icons for menu items. (new in 3.6) | |||
- View autoresizing support. (new in 3.6) | |||
- Bitmaps can be loaded either by number or by name (see VSTGUI::CBitmap) (new in 3.5) | |||
- VSTGUI::CTooltipSupport (new in 3.5) | |||
- VSTGUI::CVSTGUITimer (new in 3.5) | |||
- System event driven drawing (new in 3.5) | |||
- Unicode support via UTF-8 (new in 3.5) | |||
- New font implementation (new in 3.5) | |||
- Windows GDI+ support (new in 3.5) | |||
- Mac OS X Composited Window support (new in 3.0) | |||
@section about_deprecation About deprecation in version 3.6 | |||
With VSTGUI 3.6 the VSTGUI_ENABLE_DEPRECATED_METHODS macro has changed to be zero per default. You should change your code so that | |||
it compiles without changing the macro. All methods marked this way will be unavailable in the next version. | |||
@section code_changes_for_3_5 Code changes for existing VSTGUI 3.5 code | |||
- COptionMenu was refactored and uses the CMenuItem class for menu items. Item flags are not encoded in the item title anymore. | |||
- CParamDisplay::setTxtFace () and CParamDisplay::getTxtFace () is gone. The text face is already in CFontRef. | |||
- You need to use the new CNewFileSelector class instead of CFileSelector if you want to use it on Mac 64 bit. | |||
@section code_changes_for_3_0 Code changes for existing VSTGUI 3.0 code | |||
- Per default CBitmaps don't get a transparent color on creation. You must call bitmap->setTransparency (color) explicitly. And this may only works once depending on the internal implementation. | |||
- CViewContainer addView and removeView returns a bool value now. | |||
- Mouse methods moved from CDrawContext to CFrame. | |||
- Custom views which override attached and removed must propagate the call to the parent. | |||
- VST specific code is enclosed with the macro ENABLE_VST_EXTENSION_IN_VSTGUI, which per default is set to zero. If you need them you must enable it (best practice is to set it in the prefix header or the preprocessor panel in your compiler). | |||
- Removed all CDrawContext parameters from CView methods except for draw and drawRect. You need to change this in your custom views and controls. | |||
- Every usage of CFont must be changed to CFontRef. | |||
- When using GDI+ or libpng on Windows there is no need in using any offscreen context for flicker reduction as VSTGUI uses a backbuffer for drawing. | |||
- Custom controls must implement the CLASS_METHODS macro if it directly inherits from CControl. Otherwise you will get a compile error. | |||
- Custom controls which don't implement the new mouse methods must override onMouseDown and return kMouseEventNotHandled so that the old mouse method is called. | |||
@subsection cviewchanges CView method changes | |||
For custom views you need to change the following methods because their parameters changed: | |||
- onWheel | |||
- onDrop | |||
- onDragEnter | |||
- onDragLeave | |||
- onDragMove | |||
- takeFocus | |||
- looseFocus | |||
- setViewSize | |||
@subsection aeffguieditorchanges AEffGUIEditor method changes | |||
- valueChanged | |||
@section code_changes_for_2_3 Code changes for existing VSTGUI 2.3 code | |||
please see the "Migrating from 2.3.rtf" file in the Documentation folder. | |||
*/ | |||
//------------------------------------------------------------------------ | |||
// Doxygen Group Definitions | |||
//------------------------------------------------------------------------ | |||
/*! @defgroup new_in New classes | |||
*/ | |||
//------------------------------------------------------------------------ | |||
/*! @defgroup new_in_4_0 Version 4.0 | |||
* @ingroup new_in | |||
*/ | |||
//------------------------------------------------------------------------ | |||
/*! @defgroup new_in_4_1 Version 4.1 | |||
* @ingroup new_in | |||
*/ | |||
//------------------------------------------------------------------------ | |||
/*! @defgroup new_in_4_2 Version 4.2 | |||
* @ingroup new_in | |||
*/ | |||
//------------------------------------------------------------------------ | |||
/*! @defgroup new_in_4_3 Version 4.3 | |||
* @ingroup new_in | |||
*/ | |||
//------------------------------------------------------------------------ | |||
/*! @defgroup new_in_4_5 Version 4.5 | |||
* @ingroup new_in | |||
*/ | |||
//------------------------------------------------------------------------ | |||
/*! @defgroup new_in_4_7 Version 4.7 | |||
* @ingroup new_in | |||
*/ | |||
//------------------------------------------------------------------------ | |||
/*! @defgroup views Views | |||
* @ingroup viewsandcontrols | |||
*/ | |||
//------------------------------------------------------------------------ | |||
/*! @defgroup controls Controls | |||
* @ingroup views | |||
* @brief Controls are views the user can interact with | |||
*/ | |||
//------------------------------------------------------------------------ | |||
/*! @defgroup containerviews Container Views | |||
* @ingroup views | |||
*/ | |||
//------------------------------------------------------------------------ | |||
@@ -0,0 +1,25 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
/** | |||
@page key_event_flow Keyboard Event Flow | |||
@section short_story Short Story | |||
Keyboard events are dispatched from CFrame in this order : | |||
- IKeyboardHook | |||
- focus view | |||
- parents of focus view | |||
- modal view | |||
@section long_story Long Story | |||
If a keyboard event is coming to CFrame::onKeyDown or CFrame::onKeyUp, CFrame will first sent the event to the keyboard hook if | |||
it is set. If the keyboard hook has not handled the event, the next candidate is the focus view. If there is a focus view and | |||
the focus view does not handle the event, the event is dispatched to the parent of the focus view. If the parent also does not | |||
handle the event the event is propagated to the parent of the parent and so on until the parent is the frame. | |||
If the event is still not handled the event will be passed on to the modal view if it exists. | |||
*/ |
@@ -0,0 +1,38 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
/** | |||
@page page_license License | |||
\code | |||
//----------------------------------------------------------------------------- | |||
// VSTGUI LICENSE | |||
// Copyright 2010, Steinberg Media Technologies, All Rights Reserved | |||
//----------------------------------------------------------------------------- | |||
// Redistribution and use in source and binary forms, with or without modification, | |||
// are permitted provided that the following conditions are met: | |||
// | |||
// * Redistributions of source code must retain the above copyright notice, | |||
// this list of conditions and the following disclaimer. | |||
// * Redistributions in binary form must reproduce the above copyright notice, | |||
// this list of conditions and the following disclaimer in the documentation | |||
// and/or other materials provided with the distribution. | |||
// * Neither the name of the Steinberg Media Technologies nor the names of its | |||
// contributors may be used to endorse or promote products derived from this | |||
// software without specific prior written permission. | |||
// | |||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |||
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | |||
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | |||
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |||
// OF THE POSSIBILITY OF SUCH DAMAGE. | |||
//----------------------------------------------------------------------------- | |||
\endcode | |||
*/ |
@@ -0,0 +1,197 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
/** | |||
@page page_vst2_tutorial Getting Started Tutorial (VST 2.x) | |||
This tutorial should give you a brief overview on how to get started using VSTGUI. | |||
- @ref vstintegration @n | |||
- @ref addingviewsandcontrols @n | |||
- @ref controllistener @n | |||
Note: If you are new to VST in general, consider using the VST3 SDK so that you can use @ref page_vst3_inline_editing. | |||
The VST3 SDK includes a wrapper so that the VST3 plug-in can be used in hosts which only supports VST2. | |||
@section vstintegration VST Integration | |||
To add a user interface to a VST Plug-In with VSTGUI is quite simple. | |||
Create a new class which inherits from AEffGUIEditor. Overwrite AEffGUIEditor::open and AEffGUIEditor::close. | |||
@code | |||
class MyEditor : public AEffGUIEditor | |||
{ | |||
public: | |||
MyEditor (void* ptr) : AEffGUIEditor (ptr) {} | |||
bool open (void* ptr); | |||
void close (); | |||
}; | |||
@endcode | |||
In MyEditor::open you create the CFrame. | |||
@code | |||
bool MyEditor::open (void* ptr) | |||
{ | |||
CRect frameSize (0, 0, 300, 300); | |||
frame = new CFrame (frameSize, ptr, this); | |||
return true; | |||
} | |||
@endcode | |||
In MyEditor::close you need to delete the CFrame | |||
@code | |||
void MyEditor::close () | |||
{ | |||
delete frame; | |||
frame = 0; | |||
} | |||
@endcode | |||
Now you just need to set the editor of your VST Plug-In to a new instance of MyEditor. | |||
@code | |||
// somewhere in the constructor of your VST Plug-In | |||
setEditor (new MyEditor (this)); | |||
@endcode | |||
So you have your own editor for a VST Plug-In. Now you need to add controls to it. | |||
@section addingviewsandcontrols Adding views and controls | |||
- @ref loading_bitmaps @n | |||
- @ref adding_views @n | |||
- @ref adding_knob @n | |||
@subsection loading_bitmaps Loading images | |||
Most controls provided with VSTGUI use images. So you need to know how to load and use images in VSTGUI. | |||
To load an image, you just need to use the CBitmap class. | |||
@code | |||
CBitmap* bitmap = new CBitmap ("MyBitmap.png"); | |||
@endcode | |||
The image "MyBitmap.png" must be defined in the .rc file on Windows like this : | |||
@code | |||
MyBitmap.png DATA DISCARDABLE "MyBitmap.png" | |||
@endcode | |||
On Mac OS X the image must be inside the Resources folder of the vst bundle. | |||
@subsection adding_views Creating views and adding them to the frame | |||
Now that we have loaded an image, we want this image to be shown in our editor. | |||
The simplest way is to use the CView class, which is the base of all view and control classes. | |||
@code | |||
CView* myView = new CView (CRect (0, 0, bitmap->getWidth (), bitmap->getHeight ())); | |||
myView->setBackground (bitmap); | |||
@endcode | |||
To actually get this shown, we need to add this view to the CFrame object created earlier. | |||
@code | |||
frame->addView (myView); | |||
@endcode | |||
So after we have setup all views we can get rid of our image as all views will remember the image by its own. | |||
@code | |||
bitmap->forget (); | |||
@endcode | |||
Now lets see how this looks as a complete example : | |||
@code | |||
bool MyEditor::open (void* ptr) | |||
{ | |||
CRect frameSize (0, 0, 300, 300); | |||
frame = new CFrame (frameSize, ptr, this); | |||
CBitmap* bitmap = new CBitmap ("MyBitmap.png"); | |||
CView* myView = new CView (CRect (0, 0, bitmap->getWidth (), bitmap->getHeight ())); | |||
myView->setBackground (bitmap); | |||
frame->addView (myView); | |||
bitmap->forget (); | |||
return true; | |||
} | |||
@endcode | |||
To only have an image shown in our editor is a little bit lame. We want to have some controls the user can interact with. | |||
@subsection adding_knob Creating a knob control | |||
VSTGUI provides some basic controls you can use. As an example we use the CKnob control. The CKnob control takes two images, the background and the handle. The background as its name suggest is always drawn as the background of this control, while the handle is drawn at the position of the value of this control. See VSTGUI::CKnob for more info. | |||
Now lets see how to create such a knob: | |||
@code | |||
CKnob* knob = new CKnob (r, 0, 0, background, handle, CPoint (0, 0)); | |||
@endcode | |||
As you can see there are some parameters set to zero. Ignore them for a moment. I will talk about it later. | |||
If you add this knob to the frame and test the interface you will see that if you press the mouse button over this control and move the mouse, the handle of the knob is also moving. Great, we have something to play with in the editor. | |||
The complete example : | |||
@code | |||
bool MyEditor::open (void* ptr) | |||
{ | |||
CRect frameSize (0, 0, 300, 300); | |||
frame = new CFrame (frameSize, ptr, this); | |||
CBitmap* background = new CBitmap ("KnobBackground.png"); | |||
CBitmap* handle = new CBitmap ("KnobHandle.png"); | |||
CRect r (0, 0, background->getWidth (), background->getHeight ()); | |||
CKnob* knob = new CKnob (r, 0, 0, background, handle, CPoint (0, 0)); | |||
background->forget (); | |||
handle->forget (); | |||
frame->addView (knob); | |||
return true; | |||
} | |||
@endcode | |||
@section controllistener Getting notification of control changes | |||
So now we have a knob in our editor. We'd like to know when the user uses this control. | |||
@subsection TheCControlListener The CControlListener | |||
This is done with the CControlListener interface. Every control in VSTGUI can have one listener. When the value of the control has changed the listener is notified. | |||
First we need a CControlListener. The easiest way is to inherit our editor not only from AEffGUIEditor but also from CControlListener : | |||
@code | |||
class MyEditor : public AEffGUIEditor, public CControlListener | |||
{ | |||
public: | |||
MyEditor (void* ptr) : AEffGUIEditor (ptr) {} | |||
// from AEffGUIEditor | |||
bool open (void* ptr); | |||
void close (); | |||
// from CControlListener | |||
void valueChanged (CControl* pControl); | |||
}; | |||
@endcode | |||
Now we can use our editor as the listener parameter in the CKnob constructor. | |||
@code | |||
CKnob* knob = new CKnob (r, this, 0, background, handle, CPoint (0, 0)); | |||
@endcode | |||
We only need to implement the valueChanged method and we know when the user twiddles our knob. | |||
@code | |||
void MyEditor::valueChanged (CControl* pControl) | |||
{ | |||
// pControl is our knob in this example | |||
} | |||
@endcode | |||
@subsection ControlIdentification Control identification | |||
With one control it's fairly easy to know which control was used by the user. If there are more controls in our editor, to know which control was used is done by the tag of the control. So if we add two knobs to the frame we gave them different tags : | |||
@code | |||
CKnob* knob1 = new CKnob (r, this, 0, background, handle, CPoint (0, 0)); | |||
CKnob* knob2 = new CKnob (r, this, 1, background, handle, CPoint (0, 0)); | |||
@endcode | |||
Now in our valueChanged method we can differentiate between the controls : | |||
@code | |||
void MyEditor::valueChanged (CControl* pControl) | |||
{ | |||
int32_t tag = pControl->getTag (); | |||
if (tag == 0) | |||
{ | |||
// the first knob | |||
} | |||
else if (tag == 1) | |||
{ | |||
// the second knob | |||
} | |||
} | |||
@endcode | |||
For a complete example have a look at the tutorial project included with VSTGUI. | |||
*/ |
@@ -0,0 +1,55 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
/** | |||
@page tutorial Tutorial | |||
This tutorial should give you a brief overview on how to get started using VSTGUI. | |||
- @ref vstintegration @n | |||
- @ref addingviewsandcontrols @n | |||
- @ref Getting notification of control changes @n | |||
- @ref Creating custom controls and views @n | |||
@section vstintegration VST Integration | |||
To add a user interface to a VST Plug-In with VSTGUI is quite simple. | |||
Create a new class which inherite from AEffGUIEditor. Overwrite AEffGUIEditor::open and AEffGUIEditor::close. | |||
@code | |||
class MyEditor : public AEffGUIEditor | |||
{ | |||
public: | |||
bool open (void* ptr); | |||
void close (); | |||
}; | |||
@endcode | |||
In MyEditor::open you create the CFrame. | |||
@code | |||
bool MyEditor::open (void* ptr) | |||
{ | |||
CRect frameSize (0, 0, 300, 300); | |||
frame = new CFrame (frameSize, ptr, this); | |||
return true; | |||
} | |||
@endcode | |||
In MyEditor::close you need to delete the CFrame | |||
@code | |||
void MyEditor::close () | |||
{ | |||
delete frame; | |||
frame = 0; | |||
} | |||
@endcode | |||
Now you have your own editor for a VST Plug-In. Now you need to add controls to it. | |||
@section addingviewsandcontrols Adding views and controls | |||
Most controls provided with VSTGUI use bitmaps. So you need to know how to load and use bitmaps in VSTGUI. | |||
To load a bitmap, you just need to use the CBitmap class. | |||
*/ |
@@ -0,0 +1,303 @@ | |||
########################################################################################## | |||
# VSTGUI Library | |||
########################################################################################## | |||
set(target vstgui) | |||
set(${target}_common_sources | |||
animation/animations.cpp | |||
animation/animations.h | |||
animation/animator.cpp | |||
animation/animator.h | |||
animation/ianimationtarget.h | |||
animation/itimingfunction.h | |||
animation/timingfunctions.cpp | |||
animation/timingfunctions.h | |||
cbitmap.cpp | |||
cbitmap.h | |||
cbitmapfilter.cpp | |||
cbitmapfilter.h | |||
cbuttonstate.h | |||
ccolor.cpp | |||
ccolor.h | |||
cdatabrowser.cpp | |||
cdatabrowser.h | |||
cdrawcontext.cpp | |||
cdrawcontext.h | |||
cdrawdefs.h | |||
cdrawmethods.cpp | |||
cdrawmethods.h | |||
cdropsource.cpp | |||
cdropsource.h | |||
cfileselector.cpp | |||
cfileselector.h | |||
cfont.cpp | |||
cfont.h | |||
cframe.cpp | |||
cframe.h | |||
cgradient.h | |||
cgradientview.cpp | |||
cgradientview.h | |||
cgraphicspath.cpp | |||
cgraphicspath.h | |||
cgraphicstransform.h | |||
clayeredviewcontainer.cpp | |||
clayeredviewcontainer.h | |||
clinestyle.cpp | |||
clinestyle.h | |||
coffscreencontext.cpp | |||
coffscreencontext.h | |||
controls/cautoanimation.cpp | |||
controls/cautoanimation.h | |||
controls/cbuttons.cpp | |||
controls/cbuttons.h | |||
controls/ccolorchooser.cpp | |||
controls/ccolorchooser.h | |||
controls/ccontrol.cpp | |||
controls/ccontrol.h | |||
controls/cfontchooser.cpp | |||
controls/cfontchooser.h | |||
controls/cknob.cpp | |||
controls/cknob.h | |||
controls/cmoviebitmap.cpp | |||
controls/cmoviebitmap.h | |||
controls/cmoviebutton.cpp | |||
controls/cmoviebutton.h | |||
controls/coptionmenu.cpp | |||
controls/coptionmenu.h | |||
controls/cparamdisplay.cpp | |||
controls/cparamdisplay.h | |||
controls/cscrollbar.cpp | |||
controls/cscrollbar.h | |||
controls/csearchtextedit.cpp | |||
controls/csearchtextedit.h | |||
controls/csegmentbutton.cpp | |||
controls/csegmentbutton.h | |||
controls/cslider.cpp | |||
controls/cslider.h | |||
controls/cspecialdigit.cpp | |||
controls/cspecialdigit.h | |||
controls/csplashscreen.cpp | |||
controls/csplashscreen.h | |||
controls/cswitch.cpp | |||
controls/cswitch.h | |||
controls/ctextedit.cpp | |||
controls/ctextedit.h | |||
controls/ctextlabel.cpp | |||
controls/ctextlabel.h | |||
controls/cvumeter.cpp | |||
controls/cvumeter.h | |||
controls/cxypad.cpp | |||
controls/cxypad.h | |||
controls/icommandmenuitemtarget.h | |||
controls/icontrollistener.h | |||
controls/ioptionmenulistener.h | |||
controls/itextlabellistener.h | |||
copenglview.cpp | |||
copenglview.h | |||
cpoint.cpp | |||
cpoint.h | |||
crect.cpp | |||
crect.h | |||
cresourcedescription.h | |||
crowcolumnview.cpp | |||
crowcolumnview.h | |||
cscrollview.cpp | |||
cscrollview.h | |||
cshadowviewcontainer.cpp | |||
cshadowviewcontainer.h | |||
csplitview.cpp | |||
csplitview.h | |||
cstring.cpp | |||
cstring.h | |||
ctabview.cpp | |||
ctabview.h | |||
ctooltipsupport.cpp | |||
ctooltipsupport.h | |||
cview.cpp | |||
cview.h | |||
cviewcontainer.cpp | |||
cviewcontainer.h | |||
cvstguitimer.cpp | |||
cvstguitimer.h | |||
dragging.h | |||
dispatchlist.h | |||
genericstringlistdatabrowsersource.cpp | |||
genericstringlistdatabrowsersource.h | |||
idatabrowserdelegate.h | |||
idatapackage.h | |||
idependency.h | |||
ifocusdrawing.h | |||
iscalefactorchangedlistener.h | |||
itouchevent.h | |||
iviewlistener.h | |||
malloc.h | |||
optional.h | |||
platform/iplatformbitmap.h | |||
platform/iplatformfont.h | |||
platform/iplatformframe.h | |||
platform/iplatformframecallback.h | |||
platform/iplatformopenglview.h | |||
platform/iplatformoptionmenu.h | |||
platform/iplatformresourceinputstream.h | |||
platform/iplatformstring.h | |||
platform/iplatformtextedit.h | |||
platform/iplatformtimer.h | |||
platform/iplatformviewlayer.h | |||
platform/platform_macos.h | |||
platform/platform_win32.h | |||
platform/platform_x11.h | |||
platform/std_unorderedmap.h | |||
vstguibase.h | |||
vstguidebug.cpp | |||
vstguidebug.h | |||
vstguifwd.h | |||
vstkeycode.h | |||
) | |||
########################################################################################## | |||
set(${target}_mac_sources | |||
platform/common/fileresourceinputstream.cpp | |||
platform/common/fileresourceinputstream.h | |||
platform/common/genericoptionmenu.cpp | |||
platform/common/genericoptionmenu.h | |||
platform/common/generictextedit.cpp | |||
platform/common/generictextedit.h | |||
platform/mac/carbon/hiviewframe.cpp | |||
platform/mac/carbon/hiviewframe.h | |||
platform/mac/carbon/hiviewoptionmenu.cpp | |||
platform/mac/carbon/hiviewoptionmenu.h | |||
platform/mac/carbon/hiviewtextedit.cpp | |||
platform/mac/carbon/hiviewtextedit.h | |||
platform/mac/caviewlayer.h | |||
platform/mac/caviewlayer.mm | |||
platform/mac/cfontmac.h | |||
platform/mac/cfontmac.mm | |||
platform/mac/cgbitmap.cpp | |||
platform/mac/cgbitmap.h | |||
platform/mac/cgdrawcontext.cpp | |||
platform/mac/cgdrawcontext.h | |||
platform/mac/cocoa/autoreleasepool.h | |||
platform/mac/cocoa/autoreleasepool.mm | |||
platform/mac/cocoa/cocoahelpers.h | |||
platform/mac/cocoa/cocoahelpers.mm | |||
platform/mac/cocoa/cocoaopenglview.h | |||
platform/mac/cocoa/cocoaopenglview.mm | |||
platform/mac/cocoa/cocoatextedit.h | |||
platform/mac/cocoa/cocoatextedit.mm | |||
platform/mac/cocoa/nsviewdraggingsession.h | |||
platform/mac/cocoa/nsviewdraggingsession.mm | |||
platform/mac/cocoa/nsviewframe.h | |||
platform/mac/cocoa/nsviewframe.mm | |||
platform/mac/cocoa/nsviewoptionmenu.h | |||
platform/mac/cocoa/nsviewoptionmenu.mm | |||
platform/mac/macclipboard.h | |||
platform/mac/macclipboard.mm | |||
platform/mac/macfileselector.mm | |||
platform/mac/macglobals.cpp | |||
platform/mac/macglobals.h | |||
platform/mac/macstring.h | |||
platform/mac/macstring.mm | |||
platform/mac/mactimer.cpp | |||
platform/mac/quartzgraphicspath.cpp | |||
platform/mac/quartzgraphicspath.h | |||
platform/win32 | |||
platform/linux | |||
platform/mac/ios | |||
../doxygen | |||
) | |||
########################################################################################## | |||
set(${target}_win32_sources | |||
platform/common/fileresourceinputstream.cpp | |||
platform/common/fileresourceinputstream.h | |||
platform/win32/direct2d/d2dbitmap.cpp | |||
platform/win32/direct2d/d2dbitmap.h | |||
platform/win32/direct2d/d2ddrawcontext.cpp | |||
platform/win32/direct2d/d2ddrawcontext.h | |||
platform/win32/direct2d/d2dfont.cpp | |||
platform/win32/direct2d/d2dfont.h | |||
platform/win32/direct2d/d2dgraphicspath.cpp | |||
platform/win32/direct2d/d2dgraphicspath.h | |||
platform/win32/win32bitmapbase.h | |||
platform/win32/win32dll.h | |||
platform/win32/win32datapackage.cpp | |||
platform/win32/win32datapackage.h | |||
platform/win32/win32dragging.cpp | |||
platform/win32/win32dragging.h | |||
platform/win32/win32frame.cpp | |||
platform/win32/win32frame.h | |||
platform/win32/win32openglview.cpp | |||
platform/win32/win32openglview.h | |||
platform/win32/win32optionmenu.cpp | |||
platform/win32/win32optionmenu.h | |||
platform/win32/win32support.cpp | |||
platform/win32/win32support.h | |||
platform/win32/win32textedit.cpp | |||
platform/win32/win32textedit.h | |||
platform/win32/winfileselector.cpp | |||
platform/win32/winstring.cpp | |||
platform/win32/winstring.h | |||
platform/win32/wintimer.cpp | |||
) | |||
########################################################################################## | |||
set(${target}_linux_sources | |||
platform/common/fileresourceinputstream.cpp | |||
platform/common/fileresourceinputstream.h | |||
platform/common/genericoptionmenu.cpp | |||
platform/common/genericoptionmenu.h | |||
platform/common/generictextedit.cpp | |||
platform/common/generictextedit.h | |||
platform/common/stb_textedit.h | |||
platform/linux/cairobitmap.cpp | |||
platform/linux/cairobitmap.h | |||
platform/linux/cairocontext.cpp | |||
platform/linux/cairocontext.h | |||
platform/linux/cairofont.cpp | |||
platform/linux/cairofont.h | |||
platform/linux/cairogradient.cpp | |||
platform/linux/cairogradient.h | |||
platform/linux/cairopath.cpp | |||
platform/linux/cairopath.h | |||
platform/linux/cairoutils.h | |||
platform/linux/linuxstring.cpp | |||
platform/linux/linuxstring.h | |||
platform/linux/x11fileselector.cpp | |||
platform/linux/x11frame.cpp | |||
platform/linux/x11frame.h | |||
platform/linux/x11platform.cpp | |||
platform/linux/x11platform.h | |||
platform/linux/x11timer.cpp | |||
platform/linux/x11timer.h | |||
platform/linux/x11utils.cpp | |||
platform/linux/x11utils.h | |||
) | |||
########################################################################################## | |||
if(CMAKE_HOST_APPLE) | |||
set(${target}_sources ${${target}_common_sources} ${${target}_mac_sources}) | |||
endif() | |||
########################################################################################## | |||
if(MSVC) | |||
set(${target}_sources ${${target}_common_sources} ${${target}_win32_sources}) | |||
endif() | |||
########################################################################################## | |||
# Linux | |||
if(LINUX) | |||
set(${target}_sources ${${target}_common_sources} ${${target}_linux_sources}) | |||
endif() | |||
########################################################################################## | |||
add_library(${target} STATIC ${${target}_sources}) | |||
target_compile_definitions(${target} ${VSTGUI_COMPILE_DEFINITIONS}) | |||
vstgui_set_cxx_version(${target} 11) | |||
vstgui_source_group_by_folder(${target}) | |||
if(LINUX) | |||
target_include_directories(${target} PRIVATE ${X11_INCLUDE_DIR}) | |||
target_include_directories(${target} PRIVATE ${FREETYPE_INCLUDE_DIRS}) | |||
target_link_libraries(${target} PRIVATE ${LINUX_LIBRARIES}) | |||
endif() |
@@ -0,0 +1,367 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#include "animations.h" | |||
#include "../cview.h" | |||
#include "../cframe.h" | |||
#include "../controls/ccontrol.h" | |||
#include <cassert> | |||
#include <cmath> | |||
namespace VSTGUI { | |||
namespace Animation { | |||
//------------------------------------------------------------------------ | |||
/*! @defgroup AnimationTargets Animation Targets | |||
* @ingroup animation | |||
*/ | |||
//------------------------------------------------------------------------ | |||
/** @class AlphaValueAnimation | |||
see @ref page_animation Support */ | |||
//----------------------------------------------------------------------------- | |||
AlphaValueAnimation::AlphaValueAnimation (float endValue, bool forceEndValueOnFinish) | |||
: startValue (0.f) | |||
, endValue (endValue) | |||
, forceEndValueOnFinish (forceEndValueOnFinish) | |||
{ | |||
} | |||
//----------------------------------------------------------------------------- | |||
void AlphaValueAnimation::animationStart (CView* view, IdStringPtr name) | |||
{ | |||
startValue = view->getAlphaValue (); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void AlphaValueAnimation::animationTick (CView* view, IdStringPtr name, float pos) | |||
{ | |||
float alpha = startValue + (endValue - startValue) * pos; | |||
view->setAlphaValue (alpha); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void AlphaValueAnimation::animationFinished (CView* view, IdStringPtr name, bool wasCanceled) | |||
{ | |||
if (!wasCanceled || forceEndValueOnFinish) | |||
view->setAlphaValue (endValue); | |||
} | |||
//----------------------------------------------------------------------------- | |||
/** @class ViewSizeAnimation | |||
see @ref page_animation Support */ | |||
//----------------------------------------------------------------------------- | |||
ViewSizeAnimation::ViewSizeAnimation (const CRect& inNewRect, bool forceEndValueOnFinish) | |||
: newRect (inNewRect) | |||
, forceEndValueOnFinish (forceEndValueOnFinish) | |||
{ | |||
} | |||
//----------------------------------------------------------------------------- | |||
void ViewSizeAnimation::animationStart (CView* view, IdStringPtr name) | |||
{ | |||
startRect = view->getViewSize (); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void ViewSizeAnimation::animationFinished (CView* view, IdStringPtr name, bool wasCanceled) | |||
{ | |||
if (!wasCanceled || forceEndValueOnFinish) | |||
{ | |||
if (view->getViewSize () != newRect) | |||
{ | |||
view->invalid (); | |||
view->setViewSize (newRect); | |||
view->setMouseableArea (newRect); | |||
view->invalid (); | |||
} | |||
} | |||
} | |||
//----------------------------------------------------------------------------- | |||
void ViewSizeAnimation::animationTick (CView* view, IdStringPtr name, float pos) | |||
{ | |||
CRect r; | |||
r.left = (int32_t)(startRect.left + ((newRect.left - startRect.left) * pos)); | |||
r.right = (int32_t)(startRect.right + ((newRect.right - startRect.right) * pos)); | |||
r.top = (int32_t)(startRect.top + ((newRect.top - startRect.top) * pos)); | |||
r.bottom = (int32_t)(startRect.bottom + ((newRect.bottom - startRect.bottom) * pos)); | |||
if (view->getViewSize () != r) | |||
{ | |||
view->invalid (); | |||
view->setViewSize (r); | |||
view->setMouseableArea (r); | |||
view->invalid (); | |||
} | |||
} | |||
//----------------------------------------------------------------------------- | |||
/** @class ExchangeViewAnimation | |||
see @ref page_animation Support */ | |||
//----------------------------------------------------------------------------- | |||
ExchangeViewAnimation::ExchangeViewAnimation (CView* oldView, CView* newView, AnimationStyle style) | |||
: newView (newView) | |||
, viewToRemove (oldView) | |||
, style (style) | |||
{ | |||
vstgui_assert (newView->isAttached () == false); | |||
vstgui_assert (viewToRemove->isAttached ()); | |||
if (auto parent = viewToRemove->getParentView ()->asViewContainer ()) | |||
parent->addView (newView); | |||
init (); | |||
} | |||
//----------------------------------------------------------------------------- | |||
ExchangeViewAnimation::~ExchangeViewAnimation () noexcept | |||
{ | |||
} | |||
//----------------------------------------------------------------------------- | |||
void ExchangeViewAnimation::updateViewSize (CView* view, const CRect& rect) | |||
{ | |||
view->invalid (); | |||
view->setViewSize (rect); | |||
view->setMouseableArea (rect); | |||
view->invalid (); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void ExchangeViewAnimation::init () | |||
{ | |||
if (style == kAlphaValueFade) | |||
{ | |||
oldViewAlphaValueStart = viewToRemove->getAlphaValue (); | |||
newViewAlphaValueEnd = newView->getAlphaValue (); | |||
newView->setAlphaValue (0.f); | |||
} | |||
else | |||
{ | |||
destinationRect = viewToRemove->getViewSize (); | |||
switch (style) | |||
{ | |||
case kAlphaValueFade: break; | |||
case kPushInFromLeft: | |||
{ | |||
doPushInFromLeft (0.f); | |||
break; | |||
} | |||
case kPushInFromRight: | |||
{ | |||
doPushInFromRight (0.f); | |||
break; | |||
} | |||
case kPushInFromTop: | |||
{ | |||
doPushInFromTop (0.f); | |||
break; | |||
} | |||
case kPushInFromBottom: | |||
{ | |||
doPushInFromBottom (0.f); | |||
break; | |||
} | |||
case kPushInOutFromLeft: | |||
{ | |||
doPushInOutFromLeft (0.f); | |||
break; | |||
} | |||
case kPushInOutFromRight: | |||
{ | |||
doPushInOutFromRight (0.f); | |||
break; | |||
} | |||
} | |||
} | |||
} | |||
//----------------------------------------------------------------------------- | |||
void ExchangeViewAnimation::doAlphaFade (float pos) | |||
{ | |||
float alpha = oldViewAlphaValueStart - (oldViewAlphaValueStart * pos); | |||
viewToRemove->setAlphaValue (alpha); | |||
alpha = newViewAlphaValueEnd * pos; | |||
newView->setAlphaValue (alpha); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void ExchangeViewAnimation::doPushInFromLeft (float pos) | |||
{ | |||
CRect viewSize (newView->getViewSize ()); | |||
CCoord leftOrigin = destinationRect.left; | |||
CCoord offset = viewSize.getWidth () * (1.f - pos); | |||
viewSize.offset (-viewSize.left, 0); | |||
viewSize.offset (leftOrigin - offset, 0); | |||
updateViewSize (newView, viewSize); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void ExchangeViewAnimation::doPushInFromRight (float pos) | |||
{ | |||
CRect viewSize (newView->getViewSize ()); | |||
CCoord rightOrigin = destinationRect.left + destinationRect.getWidth (); | |||
CCoord offset = viewSize.getWidth () * pos; | |||
viewSize.offset (-viewSize.left, 0); | |||
viewSize.offset (rightOrigin - offset, 0); | |||
updateViewSize (newView, viewSize); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void ExchangeViewAnimation::doPushInFromTop (float pos) | |||
{ | |||
CRect viewSize (newView->getViewSize ()); | |||
CCoord topOrigin = destinationRect.top; | |||
CCoord offset = viewSize.getHeight () * (1.f - pos); | |||
viewSize.offset (0, -viewSize.top); | |||
viewSize.offset (0, topOrigin - offset); | |||
updateViewSize (newView, viewSize); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void ExchangeViewAnimation::doPushInFromBottom (float pos) | |||
{ | |||
CRect viewSize (newView->getViewSize ()); | |||
CCoord bottomOrigin = destinationRect.top + destinationRect.getHeight (); | |||
CCoord offset = viewSize.getHeight () * pos; | |||
viewSize.offset (0, -viewSize.top); | |||
viewSize.offset (0, bottomOrigin - offset); | |||
updateViewSize (newView, viewSize); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void ExchangeViewAnimation::doPushInOutFromLeft (float pos) | |||
{ | |||
CRect viewSize (newView->getViewSize ()); | |||
CCoord offset = viewSize.getWidth () * (1.f - pos); | |||
viewSize.offset (-viewSize.left, 0); | |||
viewSize.offset (destinationRect.left - offset, 0); | |||
updateViewSize (newView, viewSize); | |||
offset = viewToRemove->getWidth () * pos; | |||
viewSize = destinationRect; | |||
viewSize.offset (offset, 0); | |||
updateViewSize (viewToRemove, viewSize); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void ExchangeViewAnimation::doPushInOutFromRight (float pos) | |||
{ | |||
CRect viewSize (newView->getViewSize ()); | |||
CCoord offset = viewSize.getWidth () * pos; | |||
viewSize.offset (-viewSize.left, 0); | |||
viewSize.offset ((destinationRect.left + destinationRect.getWidth ()) - offset, 0); | |||
updateViewSize (newView, viewSize); | |||
offset = viewToRemove->getWidth () * pos; | |||
viewSize = destinationRect; | |||
viewSize.offset (-offset, 0); | |||
updateViewSize (viewToRemove, viewSize); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void ExchangeViewAnimation::animationStart (CView* view, IdStringPtr name) | |||
{ | |||
#if DEBUG | |||
CViewContainer* parent = viewToRemove->getParentView ()->asViewContainer (); | |||
vstgui_assert (view == parent); | |||
#endif | |||
} | |||
//----------------------------------------------------------------------------- | |||
void ExchangeViewAnimation::animationTick (CView* view, IdStringPtr name, float pos) | |||
{ | |||
switch (style) | |||
{ | |||
case kAlphaValueFade: | |||
{ | |||
doAlphaFade (pos); | |||
break; | |||
} | |||
case kPushInFromLeft: | |||
{ | |||
doPushInFromLeft (pos); | |||
break; | |||
} | |||
case kPushInFromRight: | |||
{ | |||
doPushInFromRight (pos); | |||
break; | |||
} | |||
case kPushInFromTop: | |||
{ | |||
doPushInFromTop (pos); | |||
break; | |||
} | |||
case kPushInFromBottom: | |||
{ | |||
doPushInFromBottom (pos); | |||
break; | |||
} | |||
case kPushInOutFromLeft: | |||
{ | |||
doPushInOutFromLeft (pos); | |||
break; | |||
} | |||
case kPushInOutFromRight: | |||
{ | |||
doPushInOutFromRight (pos); | |||
break; | |||
} | |||
} | |||
} | |||
//----------------------------------------------------------------------------- | |||
void ExchangeViewAnimation::animationFinished (CView* view, IdStringPtr name, bool wasCanceled) | |||
{ | |||
animationTick (nullptr, nullptr, 1.f); | |||
if (auto viewContainer = viewToRemove->getParentView ()->asViewContainer ()) | |||
{ | |||
viewContainer->removeView (viewToRemove); | |||
} | |||
} | |||
//----------------------------------------------------------------------------- | |||
/** @class ControlValueAnimation | |||
see @ref page_animation Support */ | |||
//----------------------------------------------------------------------------- | |||
ControlValueAnimation::ControlValueAnimation (float endValue, bool forceEndValueOnFinish) | |||
: startValue (0.f) | |||
, endValue (endValue) | |||
, forceEndValueOnFinish (forceEndValueOnFinish) | |||
{ | |||
} | |||
//----------------------------------------------------------------------------- | |||
void ControlValueAnimation::animationStart (CView* view, IdStringPtr name) | |||
{ | |||
CControl* control = dynamic_cast<CControl*> (view); | |||
if (control) | |||
startValue = control->getValue (); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void ControlValueAnimation::animationTick (CView* view, IdStringPtr name, float pos) | |||
{ | |||
CControl* control = dynamic_cast<CControl*> (view); | |||
if (control) | |||
{ | |||
float value = startValue + (endValue - startValue) * pos; | |||
control->setValue (value); | |||
if (control->isDirty ()) | |||
control->invalid (); | |||
} | |||
} | |||
//----------------------------------------------------------------------------- | |||
void ControlValueAnimation::animationFinished (CView* view, IdStringPtr name, bool wasCanceled) | |||
{ | |||
CControl* control = dynamic_cast<CControl*> (view); | |||
if (control) | |||
{ | |||
if (!wasCanceled || forceEndValueOnFinish) | |||
control->setValue (endValue); | |||
} | |||
} | |||
}} // namespaces |
@@ -0,0 +1,119 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "../vstguifwd.h" | |||
#include "ianimationtarget.h" | |||
#include "../crect.h" | |||
namespace VSTGUI { | |||
namespace Animation { | |||
//----------------------------------------------------------------------------- | |||
/// @brief animates the alpha value of the view | |||
/// @ingroup AnimationTargets | |||
/// @ingroup new_in_4_0 | |||
//----------------------------------------------------------------------------- | |||
class AlphaValueAnimation : public IAnimationTarget, public NonAtomicReferenceCounted | |||
{ | |||
public: | |||
AlphaValueAnimation (float endValue, bool forceEndValueOnFinish = false); | |||
void animationStart (CView* view, IdStringPtr name) override; | |||
void animationTick (CView* view, IdStringPtr name, float pos) override; | |||
void animationFinished (CView* view, IdStringPtr name, bool wasCanceled) override; | |||
protected: | |||
float startValue; | |||
float endValue; | |||
bool forceEndValueOnFinish; | |||
}; | |||
//----------------------------------------------------------------------------- | |||
/// @brief animates the view size of the view | |||
/// @ingroup AnimationTargets | |||
/// @ingroup new_in_4_0 | |||
//----------------------------------------------------------------------------- | |||
class ViewSizeAnimation : public IAnimationTarget, public NonAtomicReferenceCounted | |||
{ | |||
public: | |||
ViewSizeAnimation (const CRect& newRect, bool forceEndValueOnFinish = false); | |||
void animationStart (CView* view, IdStringPtr name) override; | |||
void animationTick (CView* view, IdStringPtr name, float pos) override; | |||
void animationFinished (CView* view, IdStringPtr name, bool wasCanceled) override; | |||
protected: | |||
CRect startRect; | |||
CRect newRect; | |||
bool forceEndValueOnFinish; | |||
}; | |||
//----------------------------------------------------------------------------- | |||
/// @brief exchange a view by another view with an animation | |||
/// @ingroup AnimationTargets | |||
/// @ingroup new_in_4_0 | |||
//----------------------------------------------------------------------------- | |||
class ExchangeViewAnimation : public IAnimationTarget, public NonAtomicReferenceCounted | |||
{ | |||
public: | |||
enum AnimationStyle { | |||
kAlphaValueFade = 0, | |||
kPushInFromLeft, | |||
kPushInFromRight, | |||
kPushInFromTop, | |||
kPushInFromBottom, | |||
kPushInOutFromLeft, | |||
kPushInOutFromRight | |||
}; | |||
/** oldView must be a subview of the animation view */ | |||
ExchangeViewAnimation (CView* oldView, CView* newView, AnimationStyle style = kAlphaValueFade); | |||
~ExchangeViewAnimation () noexcept override; | |||
void animationStart (CView* view, IdStringPtr name) override; | |||
void animationTick (CView* view, IdStringPtr name, float pos) override; | |||
void animationFinished (CView* view, IdStringPtr name, bool wasCanceled) override; | |||
protected: | |||
void init (); | |||
void doAlphaFade (float pos); | |||
void doPushInFromLeft (float pos); | |||
void doPushInFromRight (float pos); | |||
void doPushInFromTop (float pos); | |||
void doPushInFromBottom (float pos); | |||
void doPushInOutFromLeft (float pos); | |||
void doPushInOutFromRight (float pos); | |||
void updateViewSize (CView* view, const CRect& rect); | |||
SharedPointer<CView> newView; | |||
SharedPointer<CView> viewToRemove; | |||
AnimationStyle style; | |||
float newViewAlphaValueEnd; | |||
float oldViewAlphaValueStart; | |||
CRect destinationRect; | |||
}; | |||
//----------------------------------------------------------------------------- | |||
/// @brief animates the value of a CControl | |||
/// @ingroup AnimationTargets | |||
/// @ingroup new_in_4_0 | |||
//----------------------------------------------------------------------------- | |||
class ControlValueAnimation : public IAnimationTarget, public NonAtomicReferenceCounted | |||
{ | |||
public: | |||
ControlValueAnimation (float endValue, bool forceEndValueOnFinish = false); | |||
void animationStart (CView* view, IdStringPtr name) override; | |||
void animationTick (CView* view, IdStringPtr name, float pos) override; | |||
void animationFinished (CView* view, IdStringPtr name, bool wasCanceled) override; | |||
protected: | |||
float startValue; | |||
float endValue; | |||
bool forceEndValueOnFinish; | |||
}; | |||
} // Animation | |||
} // VSTGUI | |||
@@ -0,0 +1,368 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
/** | |||
@page page_animation Animations | |||
VSTGUI version 4 adds simple to use view animation support. | |||
The source can be found under /lib/animation/ | |||
@section the_animator The Animator | |||
Every @link VSTGUI::CFrame::getAnimator CFrame @endlink object can have one @link VSTGUI::Animation::Animator Animator @endlink object which runs animations at 60 Hz. | |||
The animator is responsible for running animations. | |||
You can add and remove animations. | |||
Animations are identified by a view and a name. | |||
To add an animation you just call @link VSTGUI::CView::addAnimation CView::addAnimation (name, target, timing)@endlink. | |||
The animation will start immediately and will automatically be removed if it has finished. | |||
If you want to stop it before it has finished you can use @link VSTGUI::CView::removeAnimation CView::removeAnimation (name)@endlink. | |||
You can also stop all animations for a view with @link VSTGUI::CView::removeAllAnimations CView::removeAllAnimations ()@endlink. | |||
The animator is the owner of the target and timing function objects and will destroy these objects when the animation has finished. | |||
This means that the animator will call delete on these objects or if they are inherited from CBaseObject it will call forget() on them. | |||
@section the_animation The Animation | |||
An animation is made up by an @link VSTGUI::Animation::IAnimationTarget IAnimationTarget @endlink and an @link VSTGUI::Animation::ITimingFunction ITimingFunction @endlink object. | |||
@subsection animation_target The Animation Target | |||
The animation target is responsible for changing the view from one state to another state. | |||
The animation target interface consists of 3 methods: | |||
- @link VSTGUI::Animation::IAnimationTarget::animationStart animationStart (view, name) @endlink | |||
- @link VSTGUI::Animation::IAnimationTarget::animationTick animationTick (view, name, pos) @endlink | |||
- @link VSTGUI::Animation::IAnimationTarget::animationFinished animationFinished (view, name, wasCanceled) @endlink | |||
All these methods have the view and the animation name as arguments to identify the animation within the target. | |||
The animationTick method in addition has the normalized animation position as argument and the animationFinished method has a bool argument indicating if the animation was canceled. | |||
see @link AnimationTargets included animation target classes @endlink | |||
@subsection animation_timing The Animation Timing Function | |||
the animation timing function maps elapsed time to a normalized position. | |||
see @link AnimationTimingFunctions included animation timing function classes @endlink | |||
@section simple_example Simple Usage Example | |||
In this example the custom view animates it's alpha value when the mouse moves inside or outside the view. | |||
@code | |||
using namespace VSTGUI::Animation; | |||
class MyView : public CView | |||
{ | |||
public: | |||
MyView (const CRect& r) : CView (r) { setAlphaValue (0.5f); } | |||
CMouseEventResult onMouseEntered (CPoint &where, const CButtonState& buttons) | |||
{ | |||
// this adds an animation which takes 200 ms to make a linear alpha fade from the current value to 1 | |||
addAnimation ("AlphaValueAnimation", new AlphaValueAnimation (1.f), new LinearTimingFunction (200)); | |||
return kMouseEventHandled; | |||
} | |||
CMouseEventResult onMouseExited (CPoint &where, const CButtonState& buttons) | |||
{ | |||
// this adds an animation which takes 200 ms to make a linear alpha fade from the current value to 0.5 | |||
addAnimation ("AlphaValueAnimation", new AlphaValueAnimation (0.5f), new LinearTimingFunction (200)); | |||
return kMouseEventHandled; | |||
} | |||
void draw (CDrawContext* context) | |||
{ | |||
// ... any drawing code here | |||
} | |||
}; | |||
@endcode | |||
*/ | |||
//------------------------------------------------------------------------ | |||
/*! @defgroup animation Animation | |||
see @ref page_animation | |||
*/ | |||
//----------------------------------------------------------------------------- | |||
#include "animator.h" | |||
#include "ianimationtarget.h" | |||
#include "itimingfunction.h" | |||
#include "../cvstguitimer.h" | |||
#include "../cview.h" | |||
#include "../dispatchlist.h" | |||
#include "../platform/iplatformframe.h" | |||
#include <list> | |||
#define DEBUG_LOG 0 // DEBUG | |||
namespace VSTGUI { | |||
namespace Animation { | |||
///@cond ignore | |||
namespace Detail { | |||
//----------------------------------------------------------------------------- | |||
class Timer : public NonAtomicReferenceCounted | |||
{ | |||
public: | |||
static void addAnimator (Animator* animator) | |||
{ | |||
getInstance ()->animators.emplace_back (animator); | |||
#if DEBUG_LOG | |||
DebugPrint ("Animator added: %p\n", animator); | |||
#endif | |||
} | |||
static void removeAnimator (Animator* animator) | |||
{ | |||
if (gInstance) | |||
{ | |||
if (getInstance ()->inTimer) | |||
{ | |||
gInstance->toRemove.emplace_back (animator); | |||
} | |||
else | |||
{ | |||
#if DEBUG_LOG | |||
DebugPrint ("Animator removed: %p\n", animator); | |||
#endif | |||
gInstance->animators.remove (animator); | |||
if (gInstance->animators.empty ()) | |||
{ | |||
gInstance->forget (); | |||
gInstance = nullptr; | |||
} | |||
} | |||
} | |||
} | |||
protected: | |||
static Timer* getInstance () | |||
{ | |||
if (gInstance == nullptr) | |||
gInstance = new Timer; | |||
return gInstance; | |||
} | |||
Timer () | |||
: inTimer (false) | |||
{ | |||
#if DEBUG_LOG | |||
DebugPrint ("Animation timer started\n"); | |||
#endif | |||
timer = new CVSTGUITimer ([this] (CVSTGUITimer*) { | |||
onTimer (); | |||
}, 1000/60); // 60 Hz | |||
} | |||
~Timer () noexcept override | |||
{ | |||
#if DEBUG_LOG | |||
DebugPrint ("Animation timer stopped\n"); | |||
#endif | |||
timer->forget (); | |||
gInstance = nullptr; | |||
} | |||
void onTimer () | |||
{ | |||
inTimer = true; | |||
auto guard = shared (this); | |||
#if DEBUG_LOG | |||
DebugPrint ("Current Animators : %d\n", animators.size ()); | |||
#endif | |||
for (auto& animator : animators) | |||
animator->onTimer (); | |||
inTimer = false; | |||
for (auto& animator : toRemove) | |||
removeAnimator (animator); | |||
toRemove.clear (); | |||
} | |||
CVSTGUITimer* timer; | |||
using Animators = std::list<Animator*>; | |||
Animators animators; | |||
Animators toRemove; | |||
bool inTimer; | |||
static Timer* gInstance; | |||
}; | |||
Timer* Timer::gInstance = nullptr; | |||
//----------------------------------------------------------------------------- | |||
class Animation : public NonAtomicReferenceCounted | |||
{ | |||
public: | |||
Animation (CView* view, const std::string& name, IAnimationTarget* at, ITimingFunction* t, DoneFunction&& notification); | |||
~Animation () noexcept override; | |||
std::string name; | |||
SharedPointer<CView> view; | |||
IAnimationTarget* animationTarget; | |||
ITimingFunction* timingFunction; | |||
DoneFunction notification; | |||
uint32_t startTime; | |||
float lastPos; | |||
bool done; | |||
}; | |||
//----------------------------------------------------------------------------- | |||
Animation::Animation (CView* view, const std::string& name, IAnimationTarget* at, ITimingFunction* t, DoneFunction&& notification) | |||
: name (name) | |||
, view (view) | |||
, animationTarget (at) | |||
, timingFunction (t) | |||
, notification (std::move (notification)) | |||
, startTime (0) | |||
, lastPos (-1) | |||
, done (false) | |||
{ | |||
} | |||
//----------------------------------------------------------------------------- | |||
Animation::~Animation () noexcept | |||
{ | |||
if (notification) | |||
notification (view, name.c_str (), animationTarget); | |||
if (auto obj = dynamic_cast<IReference*> (animationTarget)) | |||
obj->forget (); | |||
else | |||
delete animationTarget; | |||
if (auto obj = dynamic_cast<IReference*> (timingFunction)) | |||
obj->forget (); | |||
else | |||
delete timingFunction; | |||
} | |||
} // Detail | |||
//----------------------------------------------------------------------------- | |||
struct Animator::Impl | |||
{ | |||
DispatchList<SharedPointer<Detail::Animation>> animations; | |||
}; | |||
///@endcond | |||
//----------------------------------------------------------------------------- | |||
Animator::Animator () | |||
{ | |||
pImpl = std::unique_ptr<Impl> (new Impl ()); | |||
} | |||
//----------------------------------------------------------------------------- | |||
Animator::~Animator () noexcept | |||
{ | |||
Detail::Timer::removeAnimator (this); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void Animator::addAnimation (CView* view, IdStringPtr name, IAnimationTarget* target, ITimingFunction* timingFunction, DoneFunction notification) | |||
{ | |||
if (pImpl->animations.empty ()) | |||
Detail::Timer::addAnimator (this); | |||
removeAnimation (view, name); | |||
pImpl->animations.add (makeOwned<Detail::Animation> (view, name, target, timingFunction, std::move (notification))); | |||
#if DEBUG_LOG | |||
DebugPrint ("new animation added: %p - %s\n", view, name); | |||
#endif | |||
} | |||
#if VSTGUI_ENABLE_DEPRECATED_METHODS | |||
//----------------------------------------------------------------------------- | |||
void Animator::addAnimation (CView* view, IdStringPtr name, IAnimationTarget* target, ITimingFunction* timingFunction, CBaseObject* notificationObject) | |||
{ | |||
DoneFunction notification; | |||
if (notificationObject) | |||
{ | |||
SharedPointer<CBaseObject> nObj (notificationObject); | |||
notification = [nObj] (CView* view, const IdStringPtr name, IAnimationTarget* target) { | |||
FinishedMessage fmsg (view, name, target); | |||
nObj->notify (&fmsg, kMsgAnimationFinished); | |||
}; | |||
} | |||
addAnimation (view, name, target, timingFunction, std::move (notification)); | |||
} | |||
#endif | |||
//----------------------------------------------------------------------------- | |||
void Animator::removeAnimation (CView* view, IdStringPtr name) | |||
{ | |||
pImpl->animations.forEach ([&] (const SharedPointer<Detail::Animation>& animation) { | |||
if (animation->view == view && animation->name == name) | |||
{ | |||
#if DEBUG_LOG | |||
DebugPrint ("animation removed: %p - %s\n", view, name); | |||
#endif | |||
if (animation->done == false) | |||
{ | |||
animation->done = true; | |||
animation->animationTarget->animationFinished (view, name, true); | |||
} | |||
pImpl->animations.remove (animation); | |||
} | |||
}); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void Animator::removeAnimations (CView* view) | |||
{ | |||
pImpl->animations.forEach ([&] (const SharedPointer<Detail::Animation>& animation) { | |||
if (animation->view == view) | |||
{ | |||
#if DEBUG_LOG | |||
DebugPrint ("animation removed: %p - %s\n", view, animation->name.data ()); | |||
#endif | |||
if (animation->done == false) | |||
{ | |||
animation->done = true; | |||
animation->animationTarget->animationFinished (view, animation->name.data (), true); | |||
} | |||
pImpl->animations.remove (animation); | |||
} | |||
}); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void Animator::onTimer () | |||
{ | |||
auto selfGuard = shared (this); | |||
uint32_t currentTicks = IPlatformFrame::getTicks (); | |||
pImpl->animations.forEach ([&] (SharedPointer<Detail::Animation>& animation) { | |||
if (animation->startTime == 0) | |||
{ | |||
#if DEBUG_LOG | |||
DebugPrint ("animation start: %p - %s\n", animation->view.cast<CView>(), animation->name.data ()); | |||
#endif | |||
animation->animationTarget->animationStart (animation->view, animation->name.data ()); | |||
animation->startTime = currentTicks; | |||
} | |||
uint32_t time = currentTicks - animation->startTime; | |||
float pos = animation->timingFunction->getPosition (time); | |||
if (pos != animation->lastPos) | |||
{ | |||
animation->animationTarget->animationTick (animation->view, animation->name.data (), pos); | |||
animation->lastPos = pos; | |||
} | |||
if (animation->timingFunction->isDone (time)) | |||
{ | |||
animation->done = true; | |||
animation->animationTarget->animationFinished (animation->view, animation->name.data (), false); | |||
#if DEBUG_LOG | |||
DebugPrint ("animation finished: %p - %s\n", animation->view.cast<CView>(), animation->name.data ()); | |||
#endif | |||
pImpl->animations.remove (animation); | |||
} | |||
}); | |||
if (pImpl->animations.empty ()) | |||
Detail::Timer::removeAnimator (this); | |||
} | |||
#if VSTGUI_ENABLE_DEPRECATED_METHODS | |||
IdStringPtr kMsgAnimationFinished = "kMsgAnimationFinished"; | |||
#endif | |||
}} // namespaces |
@@ -0,0 +1,93 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "../vstguifwd.h" | |||
#include <string> | |||
#include <functional> | |||
#include <memory> | |||
namespace VSTGUI { | |||
namespace Animation { | |||
//----------------------------------------------------------------------------- | |||
/// @brief Animation runner | |||
/// @ingroup new_in_4_0 | |||
//----------------------------------------------------------------------------- | |||
class Animator : public NonAtomicReferenceCounted | |||
{ | |||
public: | |||
//----------------------------------------------------------------------------- | |||
/// @name Adding and removing Animations | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
VSTGUI_DEPRECATED( | |||
/** adds an animation. | |||
Animation and timingFunction is now owned by the animator. | |||
An already running animation for view with name will be canceled. | |||
If a notificationObject is supplied, it will be notified when the animation has finished @see FinishedMessage. | |||
*/ | |||
void addAnimation (CView* view, IdStringPtr name, IAnimationTarget* target, ITimingFunction* timingFunction, CBaseObject* notificationObject);) | |||
/** adds an animation. | |||
Animation and timingFunction is now owned by the animator. | |||
An already running animation for view with name will be canceled. | |||
The notification function will be called when the animation has finished. | |||
*/ | |||
void addAnimation (CView* view, IdStringPtr name, IAnimationTarget* target, | |||
ITimingFunction* timingFunction, DoneFunction notification = nullptr); | |||
/** removes an animation. | |||
If animation has the IReference interface forget() will be called otherwise it is deleted. | |||
The same will be done with the timingFunction. | |||
*/ | |||
void removeAnimation (CView* view, IdStringPtr name); | |||
/** removes all animations for view */ | |||
void removeAnimations (CView* view); | |||
//@} | |||
/// @cond ignore | |||
Animator (); // do not use this, instead use CFrame::getAnimator() | |||
void onTimer (); | |||
protected: | |||
~Animator () noexcept override; | |||
struct Impl; | |||
std::unique_ptr<Impl> pImpl; | |||
/// @endcond | |||
}; | |||
#if VSTGUI_ENABLE_DEPRECATED_METHODS | |||
/** message sent to the notificationObject when the animation has finished, the sender parameter will be a FinishedMessage object. */ | |||
extern IdStringPtr kMsgAnimationFinished; | |||
//----------------------------------------------------------------------------- | |||
/// @brief Animation Finished Message Object | |||
/// | |||
/// The FinishedMessage will be sent to the notificationObject when the animation has finished | |||
/// @ingroup new_in_4_0 | |||
//----------------------------------------------------------------------------- | |||
class FinishedMessage : public CBaseObject | |||
{ | |||
public: | |||
FinishedMessage (CView* view, const std::string& name, IAnimationTarget* target) : view (view), name (name), target (target) {} | |||
CView* getView () const { return view; } | |||
const IdStringPtr getName () const { return name.c_str (); } | |||
IAnimationTarget* getTarget () const { return target; } | |||
CLASS_METHODS_NOCOPY(FinishedMessage, CBaseObject) | |||
protected: | |||
CView* view; | |||
const std::string& name; | |||
IAnimationTarget* target; | |||
}; | |||
#endif | |||
} // Animation | |||
} // VSTGUI |
@@ -0,0 +1,30 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "../vstguifwd.h" | |||
namespace VSTGUI { | |||
namespace Animation { | |||
//----------------------------------------------------------------------------- | |||
/// @brief Animation target interface | |||
/// @ingroup new_in_4_0 | |||
//----------------------------------------------------------------------------- | |||
class IAnimationTarget | |||
{ | |||
public: | |||
virtual ~IAnimationTarget () noexcept = default; | |||
/** animation starts */ | |||
virtual void animationStart (CView* view, IdStringPtr name) = 0; | |||
/** pos is a normalized value between zero and one */ | |||
virtual void animationTick (CView* view, IdStringPtr name, float pos) = 0; | |||
/** animation ended */ | |||
virtual void animationFinished (CView* view, IdStringPtr name, bool wasCanceled) = 0; | |||
}; | |||
} // Animation | |||
} // VSTGUI |
@@ -0,0 +1,26 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "../vstguibase.h" | |||
namespace VSTGUI { | |||
namespace Animation { | |||
//----------------------------------------------------------------------------- | |||
/// @brief Animation timing function interface | |||
/// @ingroup new_in_4_0 | |||
//----------------------------------------------------------------------------- | |||
class ITimingFunction | |||
{ | |||
public: | |||
virtual ~ITimingFunction () noexcept = default; | |||
virtual float getPosition (uint32_t milliseconds) = 0; | |||
virtual bool isDone (uint32_t milliseconds) = 0; | |||
}; | |||
} // Animation | |||
} // VSTGUI |
@@ -0,0 +1,201 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#include "timingfunctions.h" | |||
#include "../vstguibase.h" | |||
#include <cmath> | |||
namespace VSTGUI { | |||
namespace Animation { | |||
//------------------------------------------------------------------------ | |||
/*! @defgroup AnimationTimingFunctions Animation Timing Functions | |||
* @ingroup animation | |||
*/ | |||
//------------------------------------------------------------------------ | |||
//----------------------------------------------------------------------------- | |||
//----------------------------------------------------------------------------- | |||
//----------------------------------------------------------------------------- | |||
LinearTimingFunction::LinearTimingFunction (uint32_t length) | |||
: TimingFunctionBase (length) | |||
{ | |||
} | |||
//----------------------------------------------------------------------------- | |||
float LinearTimingFunction::getPosition (uint32_t milliseconds) | |||
{ | |||
float pos = ((float)milliseconds) / ((float)length); | |||
if (pos > 1.f) | |||
pos = 1.f; | |||
else if (pos < 0.f) | |||
pos = 0.f; | |||
return pos; | |||
} | |||
//----------------------------------------------------------------------------- | |||
//----------------------------------------------------------------------------- | |||
//----------------------------------------------------------------------------- | |||
PowerTimingFunction::PowerTimingFunction (uint32_t length, float factor) | |||
: TimingFunctionBase (length) | |||
, factor (factor) | |||
{ | |||
} | |||
//----------------------------------------------------------------------------- | |||
float PowerTimingFunction::getPosition (uint32_t milliseconds) | |||
{ | |||
float pos = ((float)milliseconds) / ((float)length); | |||
pos = std::pow (pos, factor); | |||
if (pos > 1.f) | |||
pos = 1.f; | |||
else if (pos < 0.f) | |||
pos = 0.f; | |||
return pos; | |||
} | |||
//----------------------------------------------------------------------------- | |||
//----------------------------------------------------------------------------- | |||
//----------------------------------------------------------------------------- | |||
InterpolationTimingFunction::InterpolationTimingFunction (uint32_t length, float startPos, float endPos) | |||
: TimingFunctionBase (length) | |||
{ | |||
addPoint (0.f, startPos); | |||
addPoint (1.f, endPos); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void InterpolationTimingFunction::addPoint (float time, float pos) | |||
{ | |||
points.emplace ((uint32_t)((float)getLength () * time), pos); | |||
} | |||
//----------------------------------------------------------------------------- | |||
float InterpolationTimingFunction::getPosition (uint32_t milliseconds) | |||
{ | |||
uint32_t prevTime = getLength (); | |||
float prevPos = points[prevTime]; | |||
PointMap::reverse_iterator it = points.rbegin (); | |||
while (it != points.rend ()) | |||
{ | |||
uint32_t time = it->first; | |||
float pos = it->second; | |||
if (time == milliseconds) | |||
return pos; | |||
else if (time <= milliseconds && prevTime > milliseconds) | |||
{ | |||
double timePos = (double)(milliseconds - time) / (double)(prevTime - time); | |||
return static_cast<float> (static_cast<double> (pos) + ((static_cast<double> (prevPos) - static_cast<double> (pos)) * timePos)); | |||
} | |||
prevTime = time; | |||
prevPos = pos; | |||
++it; | |||
} | |||
return 1.f; | |||
} | |||
//----------------------------------------------------------------------------- | |||
//----------------------------------------------------------------------------- | |||
//----------------------------------------------------------------------------- | |||
CubicBezierTimingFunction::CubicBezierTimingFunction (uint32_t milliseconds, CPoint p1, CPoint p2) | |||
: TimingFunctionBase (milliseconds), p1 (p1), p2 (p2) | |||
{ | |||
} | |||
//----------------------------------------------------------------------------- | |||
CPoint CubicBezierTimingFunction::lerp (CPoint p1, CPoint p2, float pos) const | |||
{ | |||
return p1 * (1.f - pos) + p2 * pos; | |||
} | |||
//----------------------------------------------------------------------------- | |||
float CubicBezierTimingFunction::getPosition (uint32_t milliseconds) | |||
{ | |||
constexpr CPoint p0 (0, 0); | |||
constexpr CPoint p3 (1, 1); | |||
auto t = static_cast<float> (milliseconds) / static_cast<float> (length); | |||
auto a = lerp (p0, p1, t); | |||
auto b = lerp (p1, p2, t); | |||
auto c = lerp (p2, p3, t); | |||
auto d = lerp (a, b, t); | |||
auto e = lerp (b, c, t); | |||
auto result = lerp (d, e, t).y; | |||
return static_cast<float> (result); | |||
} | |||
//----------------------------------------------------------------------------- | |||
CubicBezierTimingFunction CubicBezierTimingFunction::easy (uint32_t time) | |||
{ | |||
return CubicBezierTimingFunction (time, CPoint (0.25, 0.1), CPoint (0.25, 1.)); | |||
} | |||
//----------------------------------------------------------------------------- | |||
CubicBezierTimingFunction CubicBezierTimingFunction::easyIn (uint32_t time) | |||
{ | |||
return CubicBezierTimingFunction (time, CPoint (0.42, 0.), CPoint (1., 1.)); | |||
} | |||
//----------------------------------------------------------------------------- | |||
CubicBezierTimingFunction CubicBezierTimingFunction::easyOut (uint32_t time) | |||
{ | |||
return CubicBezierTimingFunction (time, CPoint (0., 0.), CPoint (0.58, 1.)); | |||
} | |||
//----------------------------------------------------------------------------- | |||
CubicBezierTimingFunction CubicBezierTimingFunction::easyInOut (uint32_t time) | |||
{ | |||
return CubicBezierTimingFunction (time, CPoint (0.42, 0.), CPoint (0.58, 1.)); | |||
} | |||
//----------------------------------------------------------------------------- | |||
//----------------------------------------------------------------------------- | |||
//----------------------------------------------------------------------------- | |||
RepeatTimingFunction::RepeatTimingFunction (TimingFunctionBase* tf, int32_t repeatCount, bool autoReverse) | |||
: tf (tf) | |||
, repeatCount (repeatCount) | |||
, runCounter (0) | |||
, autoReverse (autoReverse) | |||
, isReverse (false) | |||
{ | |||
} | |||
//----------------------------------------------------------------------------- | |||
RepeatTimingFunction::~RepeatTimingFunction () noexcept | |||
{ | |||
auto obj = dynamic_cast<IReference*> (tf); | |||
if (obj) | |||
obj->forget (); | |||
else | |||
delete tf; | |||
} | |||
//----------------------------------------------------------------------------- | |||
float RepeatTimingFunction::getPosition (uint32_t milliseconds) | |||
{ | |||
if (runCounter > 0) | |||
milliseconds -= tf->getLength () * runCounter; | |||
float pos = tf->getPosition (milliseconds); | |||
return isReverse ? 1.f - pos : pos; | |||
} | |||
//----------------------------------------------------------------------------- | |||
bool RepeatTimingFunction::isDone (uint32_t milliseconds) | |||
{ | |||
if (runCounter > 0) | |||
milliseconds -= tf->getLength () * runCounter; | |||
if (tf->isDone (milliseconds)) | |||
{ | |||
runCounter++; | |||
if (autoReverse) | |||
isReverse = !isReverse; | |||
if ((uint64_t)runCounter >= (uint64_t)repeatCount) | |||
return true; | |||
} | |||
return false; | |||
} | |||
}} // namespaces | |||
@@ -0,0 +1,133 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "animator.h" | |||
#include "itimingfunction.h" | |||
#include "../cpoint.h" | |||
#include <map> | |||
namespace VSTGUI { | |||
namespace Animation { | |||
//----------------------------------------------------------------------------- | |||
/// @ingroup AnimationTimingFunctions | |||
/// @ingroup new_in_4_0 | |||
//----------------------------------------------------------------------------- | |||
class TimingFunctionBase : public ITimingFunction | |||
{ | |||
public: | |||
explicit TimingFunctionBase (uint32_t length) : length (length) {} | |||
TimingFunctionBase (const TimingFunctionBase&) = default; | |||
TimingFunctionBase& operator= (const TimingFunctionBase&) = default; | |||
uint32_t getLength () const { return length; } | |||
bool isDone (uint32_t milliseconds) override { return milliseconds >= length; } | |||
protected: | |||
uint32_t length; // in milliseconds | |||
}; | |||
//----------------------------------------------------------------------------- | |||
/// @ingroup AnimationTimingFunctions | |||
/// @ingroup new_in_4_0 | |||
//----------------------------------------------------------------------------- | |||
class LinearTimingFunction : public TimingFunctionBase | |||
{ | |||
public: | |||
explicit LinearTimingFunction (uint32_t length); | |||
LinearTimingFunction (const LinearTimingFunction&) = default; | |||
LinearTimingFunction& operator= (const LinearTimingFunction&) = default; | |||
float getPosition (uint32_t milliseconds) override; | |||
}; | |||
//----------------------------------------------------------------------------- | |||
/// @ingroup AnimationTimingFunctions | |||
/// @ingroup new_in_4_0 | |||
//----------------------------------------------------------------------------- | |||
class PowerTimingFunction : public TimingFunctionBase | |||
{ | |||
public: | |||
PowerTimingFunction (uint32_t length, float factor); | |||
PowerTimingFunction (const PowerTimingFunction&) = default; | |||
PowerTimingFunction& operator= (const PowerTimingFunction&) = default; | |||
float getPosition (uint32_t milliseconds) override; | |||
protected: | |||
float factor; | |||
}; | |||
//----------------------------------------------------------------------------- | |||
/// @ingroup AnimationTimingFunctions | |||
/// @ingroup new_in_4_0 | |||
//----------------------------------------------------------------------------- | |||
class InterpolationTimingFunction : public TimingFunctionBase | |||
{ | |||
public: | |||
InterpolationTimingFunction (uint32_t length, float startPos = 0.f, float endPos = 1.f); | |||
InterpolationTimingFunction (const InterpolationTimingFunction&) = default; | |||
InterpolationTimingFunction& operator= (const InterpolationTimingFunction&) = default; | |||
/** both values are normalized ones */ | |||
void addPoint (float time, float pos); | |||
float getPosition (uint32_t milliseconds) override; | |||
protected: | |||
using PointMap = std::map<uint32_t, float>; | |||
PointMap points; | |||
}; | |||
//----------------------------------------------------------------------------- | |||
/// @ingroup AnimationTimingFunctions | |||
/// @ingroup new_in_4_7 | |||
//----------------------------------------------------------------------------- | |||
class CubicBezierTimingFunction : public TimingFunctionBase | |||
{ | |||
public: | |||
CubicBezierTimingFunction (uint32_t milliseconds, CPoint p1, CPoint p2); | |||
CubicBezierTimingFunction (const CubicBezierTimingFunction&) = default; | |||
CubicBezierTimingFunction& operator= (const CubicBezierTimingFunction&) = default; | |||
float getPosition (uint32_t milliseconds) override; | |||
// some common timings | |||
static CubicBezierTimingFunction easy (uint32_t time); | |||
static CubicBezierTimingFunction easyIn (uint32_t time); | |||
static CubicBezierTimingFunction easyOut (uint32_t time); | |||
static CubicBezierTimingFunction easyInOut (uint32_t time); | |||
private: | |||
CPoint lerp (CPoint p1, CPoint p2, float pos) const; | |||
CPoint p1; | |||
CPoint p2; | |||
}; | |||
//----------------------------------------------------------------------------- | |||
/// @ingroup AnimationTimingFunctions | |||
/// @ingroup new_in_4_0 | |||
//----------------------------------------------------------------------------- | |||
class RepeatTimingFunction : public ITimingFunction | |||
{ | |||
public: | |||
RepeatTimingFunction (TimingFunctionBase* tf, int32_t repeatCount, bool autoReverse = true); | |||
~RepeatTimingFunction () noexcept override; | |||
float getPosition (uint32_t milliseconds) override; | |||
bool isDone (uint32_t milliseconds) override; | |||
protected: | |||
TimingFunctionBase* tf; | |||
int32_t repeatCount; | |||
uint32_t runCounter; | |||
bool autoReverse; | |||
bool isReverse; | |||
}; | |||
} // Animation | |||
} // VSTGUI |
@@ -0,0 +1,306 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#include "cbitmap.h" | |||
#include "cdrawcontext.h" | |||
#include "ccolor.h" | |||
#include "platform/iplatformbitmap.h" | |||
#include <cassert> | |||
namespace VSTGUI { | |||
//----------------------------------------------------------------------------- | |||
// CBitmap Implementation | |||
//----------------------------------------------------------------------------- | |||
/*! @class CBitmap | |||
@section changes_version_4 Changes in 4.0 | |||
In Version 4.0 CBitmap was simplified. Previous versions supported drawing a color transparent of the bitmap. Since CBitmap supports | |||
alpha drawing of bitmaps since some time, it's now the only way of drawing a bitmap with some parts transparent. | |||
@section supported_file_formats Supported file formats | |||
File format support is handled in a platform dependent way. On Windows GDI+ is used to import images. On Mac OS X CoreGraphics is used to import them. | |||
For cross platform compatibility it is recommended to use PNG files. | |||
@section loading Loading Bitmaps | |||
You load a bitmap via a CResourceDescription which can hold a string or a number. | |||
If you use names, you need to use the real filename with extension. Then it gets automaticly | |||
loaded on Mac OS X out of the Resources folder of the vst bundle. On Windows you also specify the resource in the .rc file with the real filename. | |||
@code | |||
// using a number | |||
1001 PNG DISCARDABLE "bmp01001.png" | |||
// using a string | |||
RealFileName.png PNG DISCARDABLE "RealFileName.png" | |||
@endcode | |||
@code | |||
CBitmap* bitmap1 = new CBitmap (1001); // number | |||
CBitmap* bitmap2 = new CBitmap ("RealFileName.png"); // string | |||
@endcode | |||
*/ | |||
//----------------------------------------------------------------------------- | |||
CBitmap::CBitmap () | |||
{ | |||
} | |||
//----------------------------------------------------------------------------- | |||
CBitmap::CBitmap (const CResourceDescription& desc) | |||
: resourceDesc (desc) | |||
{ | |||
if (auto platformBitmap = IPlatformBitmap::create ()) | |||
{ | |||
if (platformBitmap->load (desc)) | |||
{ | |||
bitmaps.emplace_back (platformBitmap); | |||
} | |||
} | |||
} | |||
//----------------------------------------------------------------------------- | |||
CBitmap::CBitmap (CCoord width, CCoord height) | |||
{ | |||
CPoint p (width, height); | |||
bitmaps.emplace_back (IPlatformBitmap::create (&p)); | |||
} | |||
//------------------------------------------------------------------------ | |||
CBitmap::CBitmap (CPoint size, double scaleFactor) | |||
{ | |||
size.x *= scaleFactor; | |||
size.y *= scaleFactor; | |||
size.makeIntegral (); | |||
auto bitmap = IPlatformBitmap::create (&size); | |||
bitmap->setScaleFactor (scaleFactor); | |||
bitmaps.emplace_back (bitmap); | |||
} | |||
//----------------------------------------------------------------------------- | |||
CBitmap::CBitmap (const PlatformBitmapPtr& platformBitmap) | |||
{ | |||
bitmaps.emplace_back (platformBitmap); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CBitmap::draw (CDrawContext* context, const CRect& rect, const CPoint& offset, float alpha) | |||
{ | |||
CRect clipRect; | |||
context->getClipRect (clipRect); | |||
clipRect.bound (rect); | |||
if (!clipRect.isEmpty ()) | |||
context->drawBitmap (this, rect, offset, alpha); | |||
} | |||
//----------------------------------------------------------------------------- | |||
CCoord CBitmap::getWidth () const | |||
{ | |||
if (auto pb = getPlatformBitmap ()) | |||
return pb->getSize ().x / pb->getScaleFactor (); | |||
return 0; | |||
} | |||
//----------------------------------------------------------------------------- | |||
CCoord CBitmap::getHeight () const | |||
{ | |||
if (auto pb = getPlatformBitmap ()) | |||
return pb->getSize ().y / pb->getScaleFactor (); | |||
return 0; | |||
} | |||
//------------------------------------------------------------------------ | |||
CPoint CBitmap::getSize () const | |||
{ | |||
CPoint p; | |||
if (auto pb = getPlatformBitmap ()) | |||
{ | |||
auto scaleFactor = pb->getScaleFactor (); | |||
p = pb->getSize (); | |||
p.x /= scaleFactor; | |||
p.y /= scaleFactor; | |||
} | |||
return p; | |||
} | |||
//----------------------------------------------------------------------------- | |||
auto CBitmap::getPlatformBitmap () const -> PlatformBitmapPtr | |||
{ | |||
return bitmaps.empty () ? nullptr : bitmaps[0]; | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CBitmap::setPlatformBitmap (const PlatformBitmapPtr& bitmap) | |||
{ | |||
if (bitmaps.empty ()) | |||
bitmaps.emplace_back (bitmap); | |||
else | |||
bitmaps[0] = bitmap; | |||
} | |||
//----------------------------------------------------------------------------- | |||
bool CBitmap::addBitmap (const PlatformBitmapPtr& platformBitmap) | |||
{ | |||
double scaleFactor = platformBitmap->getScaleFactor (); | |||
CPoint size = getSize (); | |||
CPoint bitmapSize = platformBitmap->getSize (); | |||
bitmapSize.x /= scaleFactor; | |||
bitmapSize.y /= scaleFactor; | |||
if (size != bitmapSize) | |||
{ | |||
vstgui_assert (size == bitmapSize, "wrong bitmap size"); | |||
return false; | |||
} | |||
for (const auto& bitmap : bitmaps) | |||
{ | |||
if (bitmap->getScaleFactor () == scaleFactor || bitmap == platformBitmap) | |||
{ | |||
vstgui_assert (bitmap->getScaleFactor () != scaleFactor && bitmap != platformBitmap); | |||
return false; | |||
} | |||
} | |||
bitmaps.emplace_back (platformBitmap); | |||
return true; | |||
} | |||
//----------------------------------------------------------------------------- | |||
auto CBitmap::getBestPlatformBitmapForScaleFactor (double scaleFactor) const -> PlatformBitmapPtr | |||
{ | |||
if (bitmaps.empty ()) | |||
return nullptr; | |||
auto bestBitmap = bitmaps[0]; | |||
double bestDiff = std::abs (scaleFactor - bestBitmap->getScaleFactor ()); | |||
for (const auto& bitmap : bitmaps) | |||
{ | |||
if (bitmap->getScaleFactor () == scaleFactor) | |||
return bitmap; | |||
else if (std::abs (scaleFactor - bitmap->getScaleFactor ()) <= bestDiff && bitmap->getScaleFactor () > bestBitmap->getScaleFactor ()) | |||
{ | |||
bestBitmap = bitmap; | |||
bestDiff = std::abs (scaleFactor - bitmap->getScaleFactor ()); | |||
} | |||
} | |||
return bestBitmap; | |||
} | |||
//----------------------------------------------------------------------------- | |||
// CNinePartTiledBitmap Implementation | |||
//----------------------------------------------------------------------------- | |||
/*! @class CNinePartTiledBitmap | |||
A nine-part tiled bitmap is tiled in nine parts which are drawing according to its part offsets: | |||
- top left corner | |||
- top right corner | |||
- bottom left corner | |||
- bottom right corner | |||
- top edge, repeated as often as necessary and clipped appropriately | |||
- left edge, dto. | |||
- right edge, dto. | |||
- bottom edge, dto. | |||
- center, repeated horizontally and vertically as often as necessary | |||
@verbatim | |||
|------------------------------------------------------------------------------------------------| | |||
| Top-Left Corner | <---- Top Edge ----> | Top-Right Corner | | |||
|--------------------|-----------------------------------------------------|---------------------| | |||
| ^ | ^ | ^ | | |||
| | | | | | | | |||
| Left Edge | <---- Center ----> | Right Edge | | |||
| | | | | | | | |||
| v | v | v | | |||
|--------------------|-----------------------------------------------------|---------------------| | |||
| Bottom-Left Corner | <---- Bottom Edge ----> | Bottom-Right Corner | | |||
|------------------------------------------------------------------------------------------------| | |||
@endverbatim | |||
*/ | |||
//----------------------------------------------------------------------------- | |||
CNinePartTiledBitmap::CNinePartTiledBitmap (const CResourceDescription& desc, const CNinePartTiledDescription& offsets) | |||
: CBitmap (desc) | |||
, offsets (offsets) | |||
{ | |||
} | |||
//----------------------------------------------------------------------------- | |||
CNinePartTiledBitmap::CNinePartTiledBitmap (const PlatformBitmapPtr& platformBitmap, const CNinePartTiledDescription& offsets) | |||
: CBitmap (platformBitmap) | |||
, offsets (offsets) | |||
{ | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CNinePartTiledBitmap::draw (CDrawContext* inContext, const CRect& inDestRect, const CPoint& offset, float inAlpha) | |||
{ | |||
inContext->drawBitmapNinePartTiled (this, inDestRect, offsets, inAlpha); | |||
} | |||
//------------------------------------------------------------------------ | |||
//------------------------------------------------------------------------ | |||
//------------------------------------------------------------------------ | |||
CBitmapPixelAccess::CBitmapPixelAccess () | |||
: bitmap (nullptr) | |||
, pixelAccess (nullptr) | |||
, currentPos (nullptr) | |||
, address (nullptr) | |||
, bytesPerRow (0) | |||
, maxX (0) | |||
, maxY (0) | |||
, x (0) | |||
, y (0) | |||
{ | |||
} | |||
//------------------------------------------------------------------------ | |||
void CBitmapPixelAccess::init (CBitmap* _bitmap, IPlatformBitmapPixelAccess* _pixelAccess) | |||
{ | |||
bitmap = _bitmap; | |||
pixelAccess = _pixelAccess; | |||
address = currentPos = pixelAccess->getAddress (); | |||
bytesPerRow = pixelAccess->getBytesPerRow (); | |||
auto size = bitmap->getPlatformBitmap ()->getSize (); | |||
maxX = static_cast<uint32_t> (size.x) - 1; | |||
maxY = static_cast<uint32_t> (size.y) - 1; | |||
} | |||
/// @cond ignore | |||
//------------------------------------------------------------------------ | |||
//------------------------------------------------------------------------ | |||
//------------------------------------------------------------------------ | |||
template <int32_t redPosition, int32_t greenPosition, int32_t bluePosition, int32_t alphaPosition> | |||
class CBitmapPixelAccessOrder : public CBitmapPixelAccess | |||
{ | |||
public: | |||
void getColor (CColor& c) const override | |||
{ | |||
c.red = currentPos[redPosition]; | |||
c.green = currentPos[greenPosition]; | |||
c.blue = currentPos[bluePosition]; | |||
c.alpha = currentPos[alphaPosition]; | |||
} | |||
void setColor (const CColor& c) override | |||
{ | |||
currentPos[redPosition] = c.red; | |||
currentPos[greenPosition] = c.green; | |||
currentPos[bluePosition] = c.blue; | |||
currentPos[alphaPosition] = c.alpha; | |||
} | |||
}; | |||
/// @endcond | |||
//------------------------------------------------------------------------ | |||
CBitmapPixelAccess* CBitmapPixelAccess::create (CBitmap* bitmap, bool alphaPremultiplied) | |||
{ | |||
if (bitmap == nullptr || bitmap->getPlatformBitmap () == nullptr) | |||
return nullptr; | |||
auto pixelAccess = bitmap->getPlatformBitmap ()->lockPixels (alphaPremultiplied); | |||
if (pixelAccess == nullptr) | |||
return nullptr; | |||
CBitmapPixelAccess* result = nullptr; | |||
switch (pixelAccess->getPixelFormat ()) | |||
{ | |||
case IPlatformBitmapPixelAccess::kARGB: result = new CBitmapPixelAccessOrder<1,2,3,0> (); break; | |||
case IPlatformBitmapPixelAccess::kRGBA: result = new CBitmapPixelAccessOrder<0,1,2,3> (); break; | |||
case IPlatformBitmapPixelAccess::kABGR: result = new CBitmapPixelAccessOrder<3,2,1,0> (); break; | |||
case IPlatformBitmapPixelAccess::kBGRA: result = new CBitmapPixelAccessOrder<2,1,0,3> (); break; | |||
} | |||
if (result) | |||
result->init (bitmap, pixelAccess); | |||
return result; | |||
} | |||
} // VSTGUI | |||
@@ -0,0 +1,238 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "vstguifwd.h" | |||
#include "cpoint.h" | |||
#include "crect.h" | |||
#include "cresourcedescription.h" | |||
#include "platform/iplatformbitmap.h" | |||
#include <vector> | |||
namespace VSTGUI { | |||
//----------------------------------------------------------------------------- | |||
// CBitmap Declaration | |||
//! @brief Encapsulates various platform depended kinds of bitmaps | |||
//----------------------------------------------------------------------------- | |||
class CBitmap : public AtomicReferenceCounted | |||
{ | |||
public: | |||
using PlatformBitmapPtr = SharedPointer<IPlatformBitmap>; | |||
/** Create an image from a resource identifier */ | |||
explicit CBitmap (const CResourceDescription& desc); | |||
/** Create an image with a given size */ | |||
CBitmap (CCoord width, CCoord height); | |||
/** Create an image with a given size and scale factor */ | |||
CBitmap (CPoint size, double scaleFactor = 1.); | |||
explicit CBitmap (const PlatformBitmapPtr& platformBitmap); | |||
~CBitmap () noexcept override = default; | |||
//----------------------------------------------------------------------------- | |||
/// @name CBitmap Methods | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
virtual void draw (CDrawContext* context, const CRect& rect, const CPoint& offset = CPoint (0, 0), float alpha = 1.f); | |||
/** get the width of the image */ | |||
CCoord getWidth () const; | |||
/** get the height of the image */ | |||
CCoord getHeight () const; | |||
/** get size of image */ | |||
CPoint getSize () const; | |||
/** check if image is loaded */ | |||
bool isLoaded () const { return getPlatformBitmap () ? true : false; } | |||
const CResourceDescription& getResourceDescription () const { return resourceDesc; } | |||
PlatformBitmapPtr getPlatformBitmap () const; | |||
void setPlatformBitmap (const PlatformBitmapPtr& bitmap); | |||
bool addBitmap (const PlatformBitmapPtr& platformBitmap); | |||
PlatformBitmapPtr getBestPlatformBitmapForScaleFactor (double scaleFactor) const; | |||
//@} | |||
//----------------------------------------------------------------------------- | |||
protected: | |||
CBitmap (); | |||
CResourceDescription resourceDesc; | |||
using BitmapVector = std::vector<PlatformBitmapPtr>; | |||
BitmapVector bitmaps; | |||
}; | |||
//----------------------------------------------------------------------------- | |||
struct CNinePartTiledDescription | |||
{ | |||
enum | |||
{ | |||
kPartTopLeft, | |||
kPartTop, | |||
kPartTopRight, | |||
kPartLeft, | |||
kPartCenter, | |||
kPartRight, | |||
kPartBottomLeft, | |||
kPartBottom, | |||
kPartBottomRight, | |||
kPartCount | |||
}; | |||
CCoord left {0.}; | |||
CCoord top {0.}; | |||
CCoord right {0.}; | |||
CCoord bottom {0.}; | |||
CNinePartTiledDescription () = default; | |||
CNinePartTiledDescription (CCoord left, CCoord top, CCoord right, CCoord bottom) | |||
: left (left), top (top), right (right), bottom (bottom) {} | |||
//----------------------------------------------------------------------------- | |||
inline void calcRects (const CRect& inBitmapRect, CRect outRect[kPartCount]) const | |||
{ | |||
// Center | |||
CRect myCenter = outRect[kPartCenter] (inBitmapRect.left + left, | |||
inBitmapRect.top + top, | |||
inBitmapRect.right - right, | |||
inBitmapRect.bottom - bottom); | |||
// Edges | |||
outRect[kPartTop] (myCenter.left, inBitmapRect.top, myCenter.right, myCenter.top); | |||
outRect[kPartLeft] (inBitmapRect.left, myCenter.top, myCenter.left, myCenter.bottom); | |||
outRect[kPartRight] (myCenter.right, myCenter.top, inBitmapRect.right, myCenter.bottom); | |||
outRect[kPartBottom] (myCenter.left, myCenter.bottom, myCenter.right, inBitmapRect.bottom); | |||
// Corners | |||
outRect[kPartTopLeft] (inBitmapRect.left, inBitmapRect.top, myCenter.left, myCenter.top); | |||
outRect[kPartTopRight] (myCenter.right, inBitmapRect.top, inBitmapRect.right, myCenter.top); | |||
outRect[kPartBottomLeft] (inBitmapRect.left, myCenter.bottom, myCenter.left, inBitmapRect.bottom); | |||
outRect[kPartBottomRight] (myCenter.right, myCenter.bottom, inBitmapRect.right, inBitmapRect.bottom); | |||
} | |||
}; | |||
//----------------------------------------------------------------------------- | |||
// CNinePartTiledBitmap Declaration | |||
/// @brief a nine-part tiled bitmap | |||
/// @ingroup new_in_4_0 | |||
//----------------------------------------------------------------------------- | |||
class CNinePartTiledBitmap : public CBitmap | |||
{ | |||
public: | |||
CNinePartTiledBitmap (const CResourceDescription& desc, const CNinePartTiledDescription& offsets); | |||
CNinePartTiledBitmap (const PlatformBitmapPtr& platformBitmap, const CNinePartTiledDescription& offsets); | |||
~CNinePartTiledBitmap () noexcept override = default; | |||
//----------------------------------------------------------------------------- | |||
/// @name Part Offsets | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
void setPartOffsets (const CNinePartTiledDescription& partOffsets) { offsets = partOffsets; } | |||
const CNinePartTiledDescription& getPartOffsets () const { return offsets; } | |||
//@} | |||
void draw (CDrawContext* context, const CRect& rect, const CPoint& offset = CPoint (0, 0), float alpha = 1.f) override; | |||
//----------------------------------------------------------------------------- | |||
protected: | |||
CNinePartTiledDescription offsets; | |||
}; | |||
//------------------------------------------------------------------------ | |||
// CBitmapPixelAccess | |||
/// @brief direct pixel access to a CBitmap | |||
/// @ingroup new_in_4_0 | |||
//------------------------------------------------------------------------ | |||
class CBitmapPixelAccess : public AtomicReferenceCounted | |||
{ | |||
public: | |||
/** advance position */ | |||
inline bool operator++ (); | |||
/** set current position */ | |||
inline bool setPosition (uint32_t x, uint32_t y); | |||
/** return current x position */ | |||
inline uint32_t getX () const { return x; } | |||
/** return current y position */ | |||
inline uint32_t getY () const { return y; } | |||
/** get color of current pixel */ | |||
virtual void getColor (CColor& c) const = 0; | |||
/** set color of current pixel */ | |||
virtual void setColor (const CColor& c) = 0; | |||
/** get native color value */ | |||
inline void getValue (uint32_t& value); | |||
/** set native color value */ | |||
inline void setValue (uint32_t value); | |||
inline uint32_t getBitmapWidth () const { return maxX+1; } | |||
inline uint32_t getBitmapHeight () const { return maxY+1; } | |||
inline IPlatformBitmapPixelAccess* getPlatformBitmapPixelAccess () const { return pixelAccess; } | |||
/** create an accessor. | |||
can return 0 if platform implementation does not support this. | |||
result needs to be forgotten before the CBitmap reflects the change to the pixels */ | |||
static CBitmapPixelAccess* create (CBitmap* bitmap, bool alphaPremultiplied = true); | |||
//----------------------------------------------------------------------------- | |||
protected: | |||
CBitmapPixelAccess (); | |||
~CBitmapPixelAccess () noexcept override = default; | |||
void init (CBitmap* bitmap, IPlatformBitmapPixelAccess* pixelAccess); | |||
CBitmap* bitmap; | |||
SharedPointer<IPlatformBitmapPixelAccess> pixelAccess; | |||
uint8_t* currentPos; | |||
uint8_t* address; | |||
uint32_t bytesPerRow; | |||
uint32_t maxX; | |||
uint32_t maxY; | |||
uint32_t x; | |||
uint32_t y; | |||
}; | |||
//------------------------------------------------------------------------ | |||
inline bool CBitmapPixelAccess::operator++ () | |||
{ | |||
if (x < maxX) | |||
{ | |||
x++; | |||
currentPos += 4; | |||
return true; | |||
} | |||
else if (y < maxY) | |||
{ | |||
y++; | |||
x = 0; | |||
currentPos = address + y * bytesPerRow; | |||
return true; | |||
} | |||
return false; | |||
} | |||
//------------------------------------------------------------------------ | |||
inline bool CBitmapPixelAccess::setPosition (uint32_t _x, uint32_t _y) | |||
{ | |||
if (_x > maxX || _y > maxY) | |||
return false; | |||
x = _x; | |||
y = _y; | |||
currentPos = address + y * bytesPerRow + x * 4; | |||
return true; | |||
} | |||
//------------------------------------------------------------------------ | |||
inline void CBitmapPixelAccess::getValue (uint32_t& value) | |||
{ | |||
value = *(uint32_t*) (currentPos); | |||
} | |||
//------------------------------------------------------------------------ | |||
inline void CBitmapPixelAccess::setValue (uint32_t value) | |||
{ | |||
*(uint32_t*) (currentPos) = value; | |||
} | |||
} // VSTGUI |
@@ -0,0 +1,930 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#include "cbitmapfilter.h" | |||
#include "cbitmap.h" | |||
#include "platform/iplatformbitmap.h" | |||
#include "ccolor.h" | |||
#include "cgraphicspath.h" | |||
#include "cgraphicstransform.h" | |||
#include <cassert> | |||
#include <algorithm> | |||
#include <memory> | |||
namespace VSTGUI { | |||
namespace BitmapFilter { | |||
//---------------------------------------------------------------------------------------------------- | |||
template<typename T> void Property::assign (T toAssign) | |||
{ | |||
value = std::malloc (sizeof (toAssign)); | |||
memcpy (value, &toAssign, sizeof (toAssign)); | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
Property::Property (Type type) | |||
: type (type) | |||
, value (nullptr) | |||
{ | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
Property::Property (int32_t intValue) | |||
: type (kInteger) | |||
{ | |||
assign (intValue); | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
Property::Property (double floatValue) | |||
: type (kFloat) | |||
{ | |||
assign (floatValue); | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
Property::Property (IReference* objectValue) | |||
: type (kObject) | |||
{ | |||
value = static_cast<void*> (objectValue); | |||
objectValue->remember (); | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
Property::Property (const CRect& rectValue) | |||
: type (kRect) | |||
{ | |||
assign (rectValue); | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
Property::Property (const CPoint& pointValue) | |||
: type (kPoint) | |||
{ | |||
assign (pointValue); | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
Property::Property (const CColor& colorValue) | |||
: type (kColor) | |||
{ | |||
assign (colorValue); | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
Property::Property (const CGraphicsTransform& transformValue) | |||
: type (kTransformMatrix) | |||
{ | |||
assign (transformValue); | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
Property::Property (const Property& p) | |||
: type (p.type) | |||
, value (nullptr) | |||
{ | |||
*this = p; | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
Property::~Property () noexcept | |||
{ | |||
if (value) | |||
{ | |||
if (type == kObject) | |||
getObject ()->forget (); | |||
else | |||
std::free (value); | |||
} | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
Property::Property (Property&& p) noexcept | |||
: value (nullptr) | |||
{ | |||
*this = std::move (p); | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
Property& Property::operator=(Property&& p) noexcept | |||
{ | |||
if (value) | |||
{ | |||
if (type == kObject) | |||
getObject ()->forget (); | |||
else | |||
std::free (value); | |||
} | |||
type = p.type; | |||
value = p.value; | |||
p.value = nullptr; | |||
p.type = kUnknown; | |||
return *this; | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
Property& Property::operator=(const Property& p) | |||
{ | |||
if (value) | |||
{ | |||
if (type == kObject) | |||
getObject ()->forget (); | |||
else | |||
std::free (value); | |||
value = nullptr; | |||
} | |||
type = p.type; | |||
if (p.value) | |||
{ | |||
uint32_t valueSize = 0u; | |||
switch (type) | |||
{ | |||
case kInteger: valueSize = sizeof (int32_t); break; | |||
case kFloat: valueSize = sizeof (double); break; | |||
case kObject: value = p.value; p.getObject ()->remember (); break; | |||
case kRect: valueSize = sizeof (CRect); break; | |||
case kPoint: valueSize = sizeof (CPoint); break; | |||
case kColor: valueSize = sizeof (CColor); break; | |||
case kTransformMatrix: valueSize = sizeof (CGraphicsTransform); break; | |||
case kUnknown: valueSize = 0u; break; | |||
} | |||
if (valueSize) | |||
{ | |||
value = std::malloc (valueSize); | |||
memcpy (value, p.value, valueSize); | |||
} | |||
} | |||
return *this; | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
int32_t Property::getInteger () const | |||
{ | |||
vstgui_assert (type == kInteger); | |||
return *static_cast<int32_t*> (value); | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
double Property::getFloat () const | |||
{ | |||
vstgui_assert (type == kFloat); | |||
return *static_cast<double*> (value); | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
IReference* Property::getObject () const | |||
{ | |||
vstgui_assert (type == kObject); | |||
return static_cast<IReference*> (value); | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
const CRect& Property::getRect () const | |||
{ | |||
vstgui_assert (type == kRect); | |||
return *static_cast<CRect*> (value); | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
const CPoint& Property::getPoint () const | |||
{ | |||
vstgui_assert (type == kPoint); | |||
return *static_cast<CPoint*> (value); | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
const CColor& Property::getColor () const | |||
{ | |||
vstgui_assert (type == kColor); | |||
return *static_cast<CColor*> (value); | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
const CGraphicsTransform& Property::getTransform () const | |||
{ | |||
vstgui_assert (type == kTransformMatrix); | |||
return *static_cast<CGraphicsTransform*> (value); | |||
} | |||
namespace Standard { | |||
static void registerStandardFilters (Factory& factory); | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
//---------------------------------------------------------------------------------------------------- | |||
//---------------------------------------------------------------------------------------------------- | |||
Factory& Factory::getInstance () | |||
{ | |||
static Factory gInstance; | |||
static bool initialized = false; | |||
if (initialized == false) | |||
{ | |||
Standard::registerStandardFilters (gInstance); | |||
initialized = true; | |||
} | |||
return gInstance; | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
uint32_t Factory::getNumFilters () const | |||
{ | |||
return (uint32_t)filters.size (); | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
IdStringPtr Factory::getFilterName (uint32_t index) const | |||
{ | |||
for (const auto& filter : filters) | |||
{ | |||
if (index == 0) | |||
return filter.first.c_str (); | |||
--index; | |||
} | |||
return nullptr; | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
IFilter* Factory::createFilter (IdStringPtr name) const | |||
{ | |||
FilterMap::const_iterator it = filters.find (name); | |||
if (it != filters.end ()) | |||
return (*it).second (name); | |||
return nullptr; | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
bool Factory::registerFilter (IdStringPtr name, IFilter::CreateFunction createFunction) | |||
{ | |||
FilterMap::iterator it = filters.find (name); | |||
if (it != filters.end ()) | |||
it->second = createFunction; | |||
else | |||
filters.emplace (name, createFunction); | |||
return true; | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
bool Factory::unregisterFilter (IdStringPtr name, IFilter::CreateFunction createFunction) | |||
{ | |||
FilterMap::iterator it = filters.find (name); | |||
if (it == filters.end ()) | |||
return false; | |||
filters.erase (it); | |||
return true; | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
//---------------------------------------------------------------------------------------------------- | |||
//---------------------------------------------------------------------------------------------------- | |||
FilterBase::FilterBase (UTF8StringPtr description) | |||
: description (description ? description : "") | |||
{ | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
UTF8StringPtr FilterBase::getDescription () const | |||
{ | |||
return description.c_str (); | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
bool FilterBase::setProperty (IdStringPtr name, const Property& property) | |||
{ | |||
auto it = properties.find (name); | |||
if (it != properties.end () && it->second.getType () == property.getType ()) | |||
{ | |||
properties[name] = property; | |||
return true; | |||
} | |||
return false; | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
bool FilterBase::setProperty (IdStringPtr name, Property&& property) | |||
{ | |||
auto it = properties.find (name); | |||
if (it != properties.end () && it->second.getType () == property.getType ()) | |||
{ | |||
properties[name] = std::move (property); | |||
return true; | |||
} | |||
return false; | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
const Property& FilterBase::getProperty (IdStringPtr name) const | |||
{ | |||
auto it = properties.find (name); | |||
if (it != properties.end ()) | |||
return it->second; | |||
static Property notFound (Property::kUnknown); | |||
return notFound; | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
uint32_t FilterBase::getNumProperties () const | |||
{ | |||
return static_cast<uint32_t> (properties.size ()); | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
IdStringPtr FilterBase::getPropertyName (uint32_t index) const | |||
{ | |||
for (const auto & it : properties) | |||
{ | |||
if (index == 0) | |||
return it.first.c_str (); | |||
index--; | |||
} | |||
return nullptr; | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
Property::Type FilterBase::getPropertyType (uint32_t index) const | |||
{ | |||
for (const auto & it : properties) | |||
{ | |||
if (index == 0) | |||
return it.second.getType (); | |||
index--; | |||
} | |||
return Property::kUnknown; | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
Property::Type FilterBase::getPropertyType (IdStringPtr name) const | |||
{ | |||
auto it = properties.find (name); | |||
if (it != properties.end ()) | |||
{ | |||
return (*it).second.getType (); | |||
} | |||
return Property::kUnknown; | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
bool FilterBase::registerProperty (IdStringPtr name, const Property& defaultProperty) | |||
{ | |||
return properties.emplace (name, defaultProperty).second; | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
CBitmap* FilterBase::getInputBitmap () const | |||
{ | |||
auto it = properties.find (Standard::Property::kInputBitmap); | |||
if (it != properties.end ()) | |||
{ | |||
auto obj = (*it).second.getObject (); | |||
return obj ? dynamic_cast<CBitmap*>(obj) : nullptr; | |||
} | |||
return nullptr; | |||
} | |||
///@cond ignore | |||
namespace Standard { | |||
//---------------------------------------------------------------------------------------------------- | |||
//---------------------------------------------------------------------------------------------------- | |||
//---------------------------------------------------------------------------------------------------- | |||
class BoxBlur : public FilterBase | |||
{ | |||
public: | |||
static IFilter* CreateFunction (IdStringPtr _name) | |||
{ | |||
return new BoxBlur (); | |||
} | |||
private: | |||
BoxBlur () | |||
: FilterBase ("A Box Blur Filter") | |||
{ | |||
registerProperty (Property::kInputBitmap, BitmapFilter::Property (BitmapFilter::Property::kObject)); | |||
registerProperty (Property::kRadius, BitmapFilter::Property ((int32_t)2)); | |||
} | |||
bool run (bool replace) override | |||
{ | |||
CBitmap* inputBitmap = getInputBitmap (); | |||
uint32_t radius = static_cast<uint32_t>(static_cast<double>(getProperty (Property::kRadius).getInteger ()) * inputBitmap->getPlatformBitmap ()->getScaleFactor ()); | |||
if (inputBitmap == nullptr || radius == UINT_MAX) | |||
return false; | |||
if (radius < 2) | |||
{ | |||
if (replace) | |||
return true; | |||
return false; // TODO: We should just copy the input bitmap to the output bitmap | |||
} | |||
if (replace) | |||
{ | |||
SharedPointer<CBitmapPixelAccess> inputAccessor = owned (CBitmapPixelAccess::create (inputBitmap)); | |||
if (inputAccessor == nullptr) | |||
return false; | |||
run (*inputAccessor, *inputAccessor, radius); | |||
return registerProperty (Property::kOutputBitmap, BitmapFilter::Property (inputBitmap)); | |||
} | |||
SharedPointer<CBitmap> outputBitmap = owned (new CBitmap (inputBitmap->getWidth (), inputBitmap->getHeight ())); | |||
if (outputBitmap) | |||
{ | |||
SharedPointer<CBitmapPixelAccess> inputAccessor = owned (CBitmapPixelAccess::create (inputBitmap)); | |||
SharedPointer<CBitmapPixelAccess> outputAccessor = owned (CBitmapPixelAccess::create (outputBitmap)); | |||
if (inputAccessor == nullptr || outputAccessor == nullptr) | |||
return false; | |||
run (*inputAccessor, *outputAccessor, radius); | |||
return registerProperty (Property::kOutputBitmap, BitmapFilter::Property (outputBitmap)); | |||
} | |||
return false; | |||
} | |||
void run (CBitmapPixelAccess& inputAccessor, CBitmapPixelAccess& outputAccessor, uint32_t radius) | |||
{ | |||
auto inputPbpa = inputAccessor.getPlatformBitmapPixelAccess (); | |||
auto outputPbpa = outputAccessor.getPlatformBitmapPixelAccess (); | |||
auto inputAddressPtr = inputPbpa->getAddress (); | |||
auto outputAddressPtr = outputPbpa->getAddress (); | |||
auto width = inputPbpa->getBytesPerRow () / 4; | |||
auto height = inputAccessor.getBitmapHeight (); | |||
switch (inputPbpa->getPixelFormat ()) | |||
{ | |||
case IPlatformBitmapPixelAccess::kARGB: | |||
case IPlatformBitmapPixelAccess::kABGR: | |||
{ | |||
algo<0, 1, 2, 3> (inputAddressPtr, outputAddressPtr, width, height, | |||
static_cast<int32_t> (radius / 2)); | |||
break; | |||
} | |||
case IPlatformBitmapPixelAccess::kRGBA: | |||
case IPlatformBitmapPixelAccess::kBGRA: | |||
{ | |||
algo<1, 2, 3, 0> (inputAddressPtr, outputAddressPtr, width, height, | |||
static_cast<int32_t> (radius / 2)); | |||
break; | |||
} | |||
} | |||
} | |||
template <int32_t redPos, int32_t greenPos, int32_t bluePos, int32_t alphaPos> | |||
void algo (uint8_t* inputPixel, uint8_t* outputPixel, int32_t width, int32_t height, | |||
int32_t radius) | |||
{ | |||
vstgui_assert (radius > 0); | |||
constexpr int32_t numComponents = 4; | |||
int32_t wm = width - 1; | |||
int32_t hm = height - 1; | |||
int32_t areaSize = width * height; | |||
int32_t div = radius + radius + 1; | |||
auto red = std::unique_ptr<uint8_t[]> (new uint8_t[areaSize]); | |||
auto green = std::unique_ptr<uint8_t[]> (new uint8_t[areaSize]); | |||
auto blue = std::unique_ptr<uint8_t[]> (new uint8_t[areaSize]); | |||
auto vMin = std::unique_ptr<int32_t[]> (new int32_t[std::max (width, height)]); | |||
auto vMax = std::unique_ptr<int32_t[]> (new int32_t[std::max (width, height)]); | |||
auto dv = std::unique_ptr<uint8_t[]> (new uint8_t[256 * div]); | |||
for (auto i = 0; i < 256 * div; ++i) | |||
dv[i] = (i / div); | |||
int32_t rsum, gsum, bsum; | |||
for (auto y = 0, yw = 0, yi = 0; y < height; ++y, yw += width) | |||
{ | |||
rsum = gsum = bsum = 0; | |||
for (auto i = -radius; i <= radius; i++) | |||
{ | |||
auto p = (yi + std::min (wm, std::max (i, 0))) * numComponents; | |||
rsum += inputPixel[p + redPos]; | |||
gsum += inputPixel[p + greenPos]; | |||
bsum += inputPixel[p + bluePos]; | |||
} | |||
if (y == 0) | |||
{ | |||
for (auto x = 0; x < width; ++x, ++yi) | |||
{ | |||
red[yi] = dv[rsum]; | |||
green[yi] = dv[gsum]; | |||
blue[yi] = dv[bsum]; | |||
vMin[x] = std::min (x + radius + 1, wm); | |||
vMax[x] = std::max (x - radius, 0); | |||
auto p1 = (yw + vMin[x]) * numComponents; | |||
auto p2 = (yw + vMax[x]) * numComponents; | |||
rsum += inputPixel[p1 + redPos] - inputPixel[p2 + redPos]; | |||
gsum += inputPixel[p1 + greenPos] - inputPixel[p2 + greenPos]; | |||
bsum += inputPixel[p1 + bluePos] - inputPixel[p2 + bluePos]; | |||
} | |||
} | |||
else | |||
{ | |||
for (auto x = 0; x < width; ++x, ++yi) | |||
{ | |||
red[yi] = dv[rsum]; | |||
green[yi] = dv[gsum]; | |||
blue[yi] = dv[bsum]; | |||
auto p1 = (yw + vMin[x]) * numComponents; | |||
auto p2 = (yw + vMax[x]) * numComponents; | |||
rsum += inputPixel[p1 + redPos] - inputPixel[p2 + redPos]; | |||
gsum += inputPixel[p1 + greenPos] - inputPixel[p2 + greenPos]; | |||
bsum += inputPixel[p1 + bluePos] - inputPixel[p2 + bluePos]; | |||
} | |||
} | |||
} | |||
rsum = gsum = bsum = 0; | |||
for (auto i = -radius, yp = -radius * width; i <= radius; ++i, yp += width) | |||
{ | |||
auto yi = std::max (0, yp); | |||
rsum += red[yi]; | |||
gsum += green[yi]; | |||
bsum += blue[yi]; | |||
} | |||
for (auto y = 0, yi = 0; y < height; ++y, yi += width) | |||
{ | |||
auto pos = yi * numComponents; | |||
outputPixel[pos + redPos] = dv[rsum]; | |||
outputPixel[pos + greenPos] = dv[gsum]; | |||
outputPixel[pos + bluePos] = dv[bsum]; | |||
outputPixel[pos + alphaPos] = inputPixel[pos + alphaPos]; | |||
vMin[y] = std::min (y + radius + 1, hm) * width; | |||
vMax[y] = std::max (y - radius, 0) * width; | |||
auto p1 = vMin[y]; | |||
auto p2 = vMax[y]; | |||
rsum += red[p1] - red[p2]; | |||
gsum += green[p1] - green[p2]; | |||
bsum += blue[p1] - blue[p2]; | |||
} | |||
for (auto x = 1; x < width; ++x) | |||
{ | |||
rsum = gsum = bsum = 0; | |||
for (auto i = -radius, yp = -radius * width; i <= radius; ++i, yp += width) | |||
{ | |||
auto yi = std::max (0, yp) + x; | |||
rsum += red[yi]; | |||
gsum += green[yi]; | |||
bsum += blue[yi]; | |||
} | |||
for (auto y = 0, yi = x; y < height; ++y, yi += width) | |||
{ | |||
auto pos = yi * numComponents; | |||
outputPixel[pos + redPos] = dv[rsum]; | |||
outputPixel[pos + greenPos] = dv[gsum]; | |||
outputPixel[pos + bluePos] = dv[bsum]; | |||
outputPixel[pos + alphaPos] = inputPixel[pos + alphaPos]; | |||
auto p1 = x + vMin[y]; | |||
auto p2 = x + vMax[y]; | |||
rsum += red[p1] - red[p2]; | |||
gsum += green[p1] - green[p2]; | |||
bsum += blue[p1] - blue[p2]; | |||
} | |||
} | |||
} | |||
}; | |||
//---------------------------------------------------------------------------------------------------- | |||
class ScaleBase : public FilterBase | |||
{ | |||
protected: | |||
ScaleBase (UTF8StringPtr description = "") | |||
: FilterBase (description) | |||
{ | |||
registerProperty (Property::kInputBitmap, BitmapFilter::Property (BitmapFilter::Property::kObject)); | |||
registerProperty (Property::kOutputRect, CRect (0, 0, 10, 10)); | |||
} | |||
bool run (bool replace) override | |||
{ | |||
if (replace) | |||
return false; | |||
CRect outSize = getProperty (Property::kOutputRect).getRect (); | |||
outSize.makeIntegral (); | |||
if (outSize.getWidth () <= 0 || outSize.getHeight () <= 0) | |||
return false; | |||
CBitmap* inputBitmap = getInputBitmap (); | |||
if (inputBitmap == nullptr) | |||
return false; | |||
SharedPointer<CBitmap> outputBitmap = owned (new CBitmap (outSize.getWidth (), outSize.getHeight ())); | |||
if (outputBitmap == nullptr) | |||
return false; | |||
SharedPointer<CBitmapPixelAccess> inputAccessor = owned (CBitmapPixelAccess::create (inputBitmap)); | |||
SharedPointer<CBitmapPixelAccess> outputAccessor = owned (CBitmapPixelAccess::create (outputBitmap)); | |||
if (inputAccessor == nullptr || outputAccessor == nullptr) | |||
return false; | |||
process (*inputAccessor, *outputAccessor); | |||
return registerProperty (Property::kOutputBitmap, BitmapFilter::Property (outputBitmap)); | |||
} | |||
virtual void process (CBitmapPixelAccess& originalBitmap, CBitmapPixelAccess& copyBitmap) = 0; | |||
}; | |||
//---------------------------------------------------------------------------------------------------- | |||
class ScaleLinear : public ScaleBase | |||
{ | |||
public: | |||
static IFilter* CreateFunction (IdStringPtr _name) | |||
{ | |||
return new ScaleLinear (); | |||
} | |||
private: | |||
ScaleLinear () : ScaleBase ("A Linear Scale Filter") {} | |||
void process (CBitmapPixelAccess& originalBitmap, CBitmapPixelAccess& copyBitmap) override | |||
{ | |||
originalBitmap.setPosition (0, 0); | |||
copyBitmap.setPosition (0, 0); | |||
uint32_t origWidth = (uint32_t)originalBitmap.getBitmapWidth (); | |||
uint32_t origHeight = (uint32_t)originalBitmap.getBitmapHeight (); | |||
uint32_t newWidth = (uint32_t)copyBitmap.getBitmapWidth (); | |||
uint32_t newHeight = (uint32_t)copyBitmap.getBitmapHeight (); | |||
float xRatio = (float)origWidth / (float)newWidth; | |||
float yRatio = (float)origHeight / (float)newHeight; | |||
uint8_t* origAddress = originalBitmap.getPlatformBitmapPixelAccess ()->getAddress (); | |||
uint8_t* copyAddress = copyBitmap.getPlatformBitmapPixelAccess ()->getAddress (); | |||
uint32_t origBytesPerRow = originalBitmap.getPlatformBitmapPixelAccess ()->getBytesPerRow (); | |||
uint32_t copyBytesPerRow = copyBitmap.getPlatformBitmapPixelAccess ()->getBytesPerRow (); | |||
int32_t ix; | |||
int32_t iy = -1; | |||
int32_t* origPixel = nullptr; | |||
float origY = 0; | |||
float origX = 0; | |||
for (uint32_t y = 0; y < newHeight; y++, origY += yRatio) | |||
{ | |||
int32_t* copyPixel = (int32_t*)(copyAddress + y * copyBytesPerRow); | |||
if (iy != (int32_t)origY) | |||
iy = (int32_t)origY; | |||
ix = -1; | |||
origX = 0; | |||
for (uint32_t x = 0; x < newWidth; x++, origX += xRatio, copyPixel++) | |||
{ | |||
if (ix != (int32_t)origX || origPixel == nullptr) | |||
{ | |||
ix = (int32_t)origX; | |||
vstgui_assert (iy >= 0); | |||
origPixel = (int32_t*)(origAddress + static_cast<uint32_t> (iy) * origBytesPerRow + ix * 4); | |||
} | |||
*copyPixel = *origPixel; | |||
} | |||
} | |||
} | |||
}; | |||
//---------------------------------------------------------------------------------------------------- | |||
class ScaleBiliniear : public ScaleBase | |||
{ | |||
public: | |||
static IFilter* CreateFunction (IdStringPtr _name) | |||
{ | |||
return new ScaleBiliniear (); | |||
} | |||
private: | |||
ScaleBiliniear () : ScaleBase ("A Biliniear Scale Filter") {} | |||
void process (CBitmapPixelAccess& originalBitmap, CBitmapPixelAccess& copyBitmap) override | |||
{ | |||
originalBitmap.setPosition (0, 0); | |||
copyBitmap.setPosition (0, 0); | |||
uint32_t origWidth = (uint32_t)originalBitmap.getBitmapWidth (); | |||
uint32_t origHeight = (uint32_t)originalBitmap.getBitmapHeight (); | |||
uint32_t newWidth = (uint32_t)copyBitmap.getBitmapWidth (); | |||
uint32_t newHeight = (uint32_t)copyBitmap.getBitmapHeight (); | |||
float xRatio = ((float)(origWidth-1)) / (float)newWidth; | |||
float yRatio = ((float)(origHeight-1)) / (float)newHeight; | |||
float xDiff, yDiff, r, g, b, a; | |||
uint32_t x, y; | |||
CColor color[4]; | |||
CColor result; | |||
for (uint32_t i = 0; i < newHeight; i++) | |||
{ | |||
y = static_cast<uint32_t> (yRatio * i); | |||
yDiff = (yRatio * i) - y; | |||
for (uint32_t j = 0; j < newWidth; j++, ++copyBitmap) | |||
{ | |||
x = static_cast<uint32_t> (xRatio * j); | |||
xDiff = (xRatio * j) - x; | |||
originalBitmap.setPosition (x, y); | |||
originalBitmap.getColor (color[0]); | |||
originalBitmap.setPosition (x+1, y); | |||
originalBitmap.getColor (color[1]); | |||
originalBitmap.setPosition (x, y+1); | |||
originalBitmap.getColor (color[2]); | |||
originalBitmap.setPosition (x+1, y+1); | |||
originalBitmap.getColor (color[3]); | |||
r = color[0].red * (1.f - xDiff) * (1.f - yDiff) + color[1].red * xDiff * (1.f - yDiff) | |||
+ color[2].red * yDiff * (1.f - xDiff) + color[3].red * xDiff * yDiff; | |||
g = color[0].green * (1.f - xDiff) * (1.f - yDiff) + color[1].green * xDiff * (1.f - yDiff) | |||
+ color[2].green * yDiff * (1.f - xDiff) + color[3].green * xDiff * yDiff; | |||
b = color[0].blue * (1.f - xDiff) * (1.f - yDiff) + color[1].blue * xDiff * (1.f - yDiff) | |||
+ color[2].blue * yDiff * (1.f - xDiff) + color[3].blue * xDiff * yDiff; | |||
a = color[0].alpha * (1.f - xDiff) * (1.f - yDiff) + color[1].alpha * xDiff * (1.f - yDiff) | |||
+ color[2].alpha * yDiff * (1.f - xDiff) + color[3].alpha * xDiff * yDiff; | |||
result = CColor ((uint8_t)r, (uint8_t)g, (uint8_t)b, (uint8_t)a); | |||
copyBitmap.setColor (result); | |||
} | |||
} | |||
} | |||
}; | |||
//---------------------------------------------------------------------------------------------------- | |||
//---------------------------------------------------------------------------------------------------- | |||
//---------------------------------------------------------------------------------------------------- | |||
using SimpleFilterProcessFunction = void (*) (CColor& color, FilterBase* self); | |||
template<typename SimpleFilterProcessFunction> | |||
class SimpleFilter : public FilterBase | |||
{ | |||
protected: | |||
SimpleFilter (UTF8StringPtr description, SimpleFilterProcessFunction function) | |||
: FilterBase (description) | |||
, processFunction (function) | |||
{ | |||
registerProperty (Property::kInputBitmap, BitmapFilter::Property (BitmapFilter::Property::kObject)); | |||
} | |||
bool run (bool replace) override | |||
{ | |||
SharedPointer<CBitmap> inputBitmap = getInputBitmap (); | |||
if (inputBitmap == nullptr) | |||
return false; | |||
SharedPointer<CBitmapPixelAccess> inputAccessor = owned (CBitmapPixelAccess::create (inputBitmap)); | |||
if (inputAccessor == nullptr) | |||
return false; | |||
SharedPointer<CBitmap> outputBitmap; | |||
SharedPointer<CBitmapPixelAccess> outputAccessor; | |||
if (replace == false) | |||
{ | |||
outputBitmap = owned (new CBitmap (inputBitmap->getWidth (), inputBitmap->getHeight ())); | |||
if (outputBitmap == nullptr) | |||
return false; | |||
outputAccessor = owned (CBitmapPixelAccess::create (outputBitmap)); | |||
if (outputAccessor == nullptr) | |||
return false; | |||
} | |||
else | |||
{ | |||
outputBitmap = inputBitmap; | |||
outputAccessor = inputAccessor; | |||
} | |||
run (*inputAccessor, *outputAccessor); | |||
return registerProperty (Property::kOutputBitmap, BitmapFilter::Property (outputBitmap)); | |||
} | |||
void run (CBitmapPixelAccess& inputAccessor, CBitmapPixelAccess& outputAccessor) | |||
{ | |||
inputAccessor.setPosition (0, 0); | |||
outputAccessor.setPosition (0, 0); | |||
CColor color; | |||
if (&inputAccessor == &outputAccessor) | |||
{ | |||
do | |||
{ | |||
inputAccessor.getColor (color); | |||
processFunction (color, this); | |||
outputAccessor.setColor (color); | |||
} | |||
while (++inputAccessor); | |||
} | |||
else | |||
{ | |||
do | |||
{ | |||
inputAccessor.getColor (color); | |||
processFunction (color, this); | |||
outputAccessor.setColor (color); | |||
++outputAccessor; | |||
} | |||
while (++inputAccessor); | |||
} | |||
} | |||
SimpleFilterProcessFunction processFunction; | |||
}; | |||
//---------------------------------------------------------------------------------------------------- | |||
//---------------------------------------------------------------------------------------------------- | |||
//---------------------------------------------------------------------------------------------------- | |||
class SetColor : public SimpleFilter<SimpleFilterProcessFunction> | |||
{ | |||
public: | |||
static IFilter* CreateFunction (IdStringPtr _name) | |||
{ | |||
return new SetColor (); | |||
} | |||
private: | |||
SetColor () | |||
: SimpleFilter<SimpleFilterProcessFunction> ("A Set Color Filter", processSetColor) | |||
{ | |||
registerProperty (Property::kIgnoreAlphaColorValue, BitmapFilter::Property ((int32_t)1)); | |||
registerProperty (Property::kInputColor, BitmapFilter::Property (kWhiteCColor)); | |||
} | |||
static void processSetColor (CColor& color, FilterBase* obj) | |||
{ | |||
SetColor* filter = static_cast<SetColor*> (obj); | |||
if (filter->ignoreAlpha) | |||
filter->inputColor.alpha = color.alpha; | |||
color = filter->inputColor; | |||
} | |||
bool ignoreAlpha; | |||
CColor inputColor; | |||
bool run (bool replace) override | |||
{ | |||
inputColor = getProperty (Property::kInputColor).getColor (); | |||
ignoreAlpha = getProperty (Property::kIgnoreAlphaColorValue).getInteger () > 0; | |||
return SimpleFilter<SimpleFilterProcessFunction>::run (replace); | |||
} | |||
}; | |||
//---------------------------------------------------------------------------------------------------- | |||
//---------------------------------------------------------------------------------------------------- | |||
//---------------------------------------------------------------------------------------------------- | |||
class Grayscale : public SimpleFilter<SimpleFilterProcessFunction> | |||
{ | |||
public: | |||
static IFilter* CreateFunction (IdStringPtr name) | |||
{ | |||
return new Grayscale (); | |||
} | |||
private: | |||
Grayscale () | |||
: SimpleFilter<SimpleFilterProcessFunction> ("A Grayscale Filter", processGrayscale) | |||
{ | |||
} | |||
static void processGrayscale (CColor& color, FilterBase* obj) | |||
{ | |||
color.red = color.green = color.blue = color.getLuma (); | |||
} | |||
}; | |||
//---------------------------------------------------------------------------------------------------- | |||
//---------------------------------------------------------------------------------------------------- | |||
//---------------------------------------------------------------------------------------------------- | |||
class ReplaceColor : public SimpleFilter<SimpleFilterProcessFunction> | |||
{ | |||
public: | |||
static IFilter* CreateFunction (IdStringPtr name) | |||
{ | |||
return new ReplaceColor (); | |||
} | |||
private: | |||
ReplaceColor () | |||
: SimpleFilter<SimpleFilterProcessFunction> ("A Replace Color Filter", processReplace) | |||
{ | |||
registerProperty (Property::kInputColor, BitmapFilter::Property (kWhiteCColor)); | |||
registerProperty (Property::kOutputColor, BitmapFilter::Property (kTransparentCColor)); | |||
} | |||
static void processReplace (CColor& color, FilterBase* obj) | |||
{ | |||
ReplaceColor* filter = static_cast<ReplaceColor*> (obj); | |||
if (color == filter->inputColor) | |||
color = filter->outputColor; | |||
} | |||
CColor inputColor; | |||
CColor outputColor; | |||
bool run (bool replace) override | |||
{ | |||
inputColor = getProperty (Property::kInputColor).getColor (); | |||
outputColor = getProperty (Property::kOutputColor).getColor (); | |||
return SimpleFilter<SimpleFilterProcessFunction>::run (replace); | |||
} | |||
}; | |||
//---------------------------------------------------------------------------------------------------- | |||
//---------------------------------------------------------------------------------------------------- | |||
//---------------------------------------------------------------------------------------------------- | |||
void registerStandardFilters (Factory& factory) | |||
{ | |||
factory.registerFilter (kBoxBlur, BoxBlur::CreateFunction); | |||
factory.registerFilter (kSetColor, SetColor::CreateFunction); | |||
factory.registerFilter (kGrayscale, Grayscale::CreateFunction); | |||
factory.registerFilter (kReplaceColor, ReplaceColor::CreateFunction); | |||
factory.registerFilter (kScaleBilinear, ScaleBiliniear::CreateFunction); | |||
factory.registerFilter (kScaleLinear, ScaleLinear::CreateFunction); | |||
} | |||
} // Standard | |||
///@end cond | |||
}} // namespaces |
@@ -0,0 +1,233 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "vstguifwd.h" | |||
#include <vector> | |||
#include <string> | |||
#include <map> | |||
namespace VSTGUI { | |||
namespace BitmapFilter { | |||
//---------------------------------------------------------------------------------------------------- | |||
/// @brief Filter Property | |||
/// @ingroup new_in_4_1 | |||
//---------------------------------------------------------------------------------------------------- | |||
class Property | |||
{ | |||
public: | |||
enum Type { | |||
kUnknown = 0, | |||
kInteger, | |||
kFloat, | |||
kObject, | |||
kRect, | |||
kPoint, | |||
kColor, | |||
kTransformMatrix | |||
}; | |||
Property (Type type = kUnknown); | |||
Property (int32_t intValue); | |||
Property (double floatValue); | |||
Property (IReference* objectValue); | |||
Property (const CRect& rectValue); | |||
Property (const CPoint& pointValue); | |||
Property (const CColor& colorValue); | |||
Property (const CGraphicsTransform& transformValue); | |||
Property (const Property& p); | |||
Property (Property&& p) noexcept; | |||
~Property () noexcept; | |||
Type getType () const { return type; } | |||
int32_t getInteger () const; | |||
double getFloat () const; | |||
IReference* getObject () const; | |||
const CRect& getRect () const; | |||
const CPoint& getPoint () const; | |||
const CColor& getColor () const; | |||
const CGraphicsTransform& getTransform () const; | |||
Property& operator=(const Property& p); | |||
Property& operator=(Property&& p) noexcept; | |||
//---------------------------------------------------------------------------------------------------- | |||
private: | |||
template<typename T> void assign (T value); | |||
Type type; | |||
void* value; | |||
}; | |||
//---------------------------------------------------------------------------------------------------- | |||
/// @brief Filter Interface | |||
/// @ingroup new_in_4_1 | |||
//---------------------------------------------------------------------------------------------------- | |||
class IFilter : public NonAtomicReferenceCounted | |||
{ | |||
public: | |||
virtual bool run (bool replaceInputBitmap = false) = 0; | |||
virtual UTF8StringPtr getDescription () const = 0; | |||
virtual bool setProperty (IdStringPtr name, const Property& property) = 0; | |||
virtual bool setProperty (IdStringPtr name, Property&& property) = 0; | |||
virtual const Property& getProperty (IdStringPtr name) const = 0; | |||
virtual uint32_t getNumProperties () const = 0; | |||
virtual IdStringPtr getPropertyName (uint32_t index) const = 0; | |||
virtual Property::Type getPropertyType (uint32_t index) const = 0; | |||
virtual Property::Type getPropertyType (IdStringPtr name) const = 0; | |||
using CreateFunction = IFilter* (*) (IdStringPtr name); | |||
}; | |||
//---------------------------------------------------------------------------------------------------- | |||
/// @brief Bitmap Filter Factory. | |||
/// @ingroup new_in_4_1 | |||
/// @details See @ref VSTGUI::BitmapFilter::Standard for a description of included Filters | |||
//---------------------------------------------------------------------------------------------------- | |||
class Factory | |||
{ | |||
public: | |||
static Factory& getInstance (); | |||
uint32_t getNumFilters () const; | |||
IdStringPtr getFilterName (uint32_t index) const; | |||
IFilter* createFilter (IdStringPtr name) const; | |||
bool registerFilter (IdStringPtr name, IFilter::CreateFunction createFunction); | |||
bool unregisterFilter (IdStringPtr name, IFilter::CreateFunction createFunction); | |||
protected: | |||
using FilterMap = std::map<std::string, IFilter::CreateFunction>; | |||
FilterMap filters; | |||
}; | |||
/** @brief Standard Bitmap Filter Names */ | |||
namespace Standard { | |||
/** Box Blur Filter Name. | |||
Applies a box blur on the input bitmap. | |||
Properties: | |||
- Property::kInputBitmap | |||
- Property::kRadius | |||
- Property::kOutputBitmap | |||
*/ | |||
static const IdStringPtr kBoxBlur = "Box Blur"; | |||
/** Grayscale Filter Name. | |||
Produces a grayscale version of the input bitmap. | |||
Properties: | |||
- Property::kInputBitmap | |||
- Property::kOutputBitmap | |||
*/ | |||
static const IdStringPtr kGrayscale = "Grayscale"; | |||
/** Replace Color Filter Name. | |||
Replaces the colors which match the input color to the output color. | |||
Properties: | |||
- Property::kInputBitmap | |||
- Property::kInputColor | |||
- Property::kOutputColor | |||
- Property::kOutputBitmap | |||
*/ | |||
static const IdStringPtr kReplaceColor = "Replace Color"; | |||
/** Set Color Filter Name. | |||
Sets all colors of the input bitmap the color of the input color. If Property::kIgnoreAlphaColorValue is set, the | |||
alpha value of the input bitmap is not changed. | |||
Properties: | |||
- Property::kInputBitmap | |||
- Property::kInputColor | |||
- Property::kIgnoreAlphaColorValue | |||
- Property::kOutputBitmap | |||
*/ | |||
static const IdStringPtr kSetColor = "Set Color"; | |||
/** Scale Bilinear Filter Name. | |||
Creates a bilinear scaled bitmap of the input bitmap. | |||
Does not work inplace. | |||
Properties: | |||
- Property::kInputBitmap | |||
- Property::kOutputRect | |||
- Property::kOutputBitmap | |||
*/ | |||
static const IdStringPtr kScaleBilinear = "Scale Biliniear"; | |||
/** Scale Linear Filter Name. | |||
Creates a linear scaled bitmap of the input bitmap. | |||
Does not work inplace. | |||
Properties: | |||
- Property::kInputBitmap | |||
- Property::kOutputRect | |||
- Property::kOutputBitmap | |||
*/ | |||
static const IdStringPtr kScaleLinear = "Scale Linear"; | |||
/** @brief Standard Bitmap Property Names */ | |||
namespace Property | |||
{ | |||
/** [Property::kObject - CBitmap] */ | |||
static const IdStringPtr kInputBitmap = "InputBitmap"; | |||
/** [Property::kObject - CBitmap] */ | |||
static const IdStringPtr kOutputBitmap = "OutputBitmap"; | |||
/** [Property::kInteger] */ | |||
static const IdStringPtr kRadius = "Radius"; | |||
/** [Property::kColor] */ | |||
static const IdStringPtr kInputColor = "InputColor"; | |||
/** [Property::kColor] */ | |||
static const IdStringPtr kOutputColor = "OutputColor"; | |||
/** [Property::kRect] */ | |||
static const IdStringPtr kOutputRect = "OutputRect"; | |||
/** [Property::kInteger] */ | |||
static const IdStringPtr kIgnoreAlphaColorValue = "IgnoreAlphaColorValue"; | |||
} // Property | |||
} // Standard | |||
//---------------------------------------------------------------------------------------------------- | |||
/// @brief A Base Class for Implementing Bitmap Filters | |||
/// @ingroup new_in_4_1 | |||
//---------------------------------------------------------------------------------------------------- | |||
class FilterBase : public IFilter | |||
{ | |||
protected: | |||
FilterBase (UTF8StringPtr description); | |||
bool registerProperty (IdStringPtr name, const Property& defaultProperty); | |||
CBitmap* getInputBitmap () const; | |||
UTF8StringPtr getDescription () const override; | |||
bool setProperty (IdStringPtr name, const Property& property) override; | |||
bool setProperty (IdStringPtr name, Property&& property) override; | |||
const Property& getProperty (IdStringPtr name) const override; | |||
uint32_t getNumProperties () const override; | |||
IdStringPtr getPropertyName (uint32_t index) const override; | |||
Property::Type getPropertyType (uint32_t index) const override; | |||
Property::Type getPropertyType (IdStringPtr name) const override; | |||
private: | |||
using PropertyMap = std::map<std::string, Property>; | |||
std::string description; | |||
PropertyMap properties; | |||
}; | |||
} // BitmapFilter | |||
} // VSTGUI |
@@ -0,0 +1,95 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "vstguibase.h" | |||
namespace VSTGUI { | |||
//---------------------------- | |||
// @brief Button Types (+modifiers) | |||
//---------------------------- | |||
enum CButton | |||
{ | |||
/** left mouse button */ | |||
kLButton = 1 << 1, | |||
/** middle mouse button */ | |||
kMButton = 1 << 2, | |||
/** right mouse button */ | |||
kRButton = 1 << 3, | |||
/** shift modifier */ | |||
kShift = 1 << 4, | |||
/** control modifier (Command Key on Mac OS X and Control Key on Windows) */ | |||
kControl = 1 << 5, | |||
/** alt modifier */ | |||
kAlt = 1 << 6, | |||
/** apple modifier (Mac OS X only. Is the Control key) */ | |||
kApple = 1 << 7, | |||
/** 4th mouse button */ | |||
kButton4 = 1 << 8, | |||
/** 5th mouse button */ | |||
kButton5 = 1 << 9, | |||
/** mouse button is double click */ | |||
kDoubleClick = 1 << 10, | |||
/** system mouse wheel setting is inverted (Only valid for onMouseWheel methods). The distance | |||
value is already transformed back to non inverted. But for scroll views we need to know if we | |||
need to invert it back. */ | |||
kMouseWheelInverted = 1 << 11 | |||
}; | |||
//----------------------------------------------------------------------------- | |||
// CButtonState Declaration | |||
//! @brief Button and Modifier state | |||
//----------------------------------------------------------------------------- | |||
struct CButtonState | |||
{ | |||
public: | |||
CButtonState (int32_t state = 0) : state (state) {} | |||
CButtonState (const CButtonState& bs) : state (bs.state) {} | |||
int32_t getButtonState () const { return state & (kLButton | kRButton | kMButton | kButton4 | kButton5); } | |||
int32_t getModifierState () const { return state & (kShift | kAlt | kControl | kApple); } | |||
/** returns true if only the left button is set. Ignores modifier state */ | |||
bool isLeftButton () const { return getButtonState () == kLButton; } | |||
/** returns true if only the middle button is set. Ignores modifier state */ | |||
bool isMiddleButton () const { return getButtonState () == kMButton; } | |||
/** returns true if only the right button is set. Ignores modifier state */ | |||
bool isRightButton () const { return getButtonState () == kRButton; } | |||
/** returns true if only the 4th button is set. Ignores modifier state */ | |||
bool isButton4 () const { return getButtonState () == kButton4; } | |||
/** returns true if only the 5th button is set. Ignores modifier state */ | |||
bool isButton5 () const { return getButtonState () == kButton5; } | |||
/** returns true if the double click flag is set. */ | |||
bool isDoubleClick () const { return hasBit<int32_t> (state, kDoubleClick); } | |||
/** returns true if the shift modifier is set. */ | |||
bool isShiftSet () const { return hasBit<int32_t> (state, kShift); } | |||
/** returns true if the alt modifier is set. */ | |||
bool isAltSet () const { return hasBit<int32_t> (state, kAlt); } | |||
/** returns true if the control modifier is set. */ | |||
bool isControlSet () const { return hasBit<int32_t> (state, kControl); } | |||
/** returns true if the apple modifier is set. */ | |||
bool isAppleSet () const { return hasBit<int32_t> (state, kApple); } | |||
bool isMouseWheelInverted () const { return hasBit<int32_t> (state, kMouseWheelInverted); } | |||
int32_t operator() () const { return state; } | |||
CButtonState& operator= (int32_t s) { state = s; return *this; } | |||
CButtonState& operator&= (int32_t s) { state &= s; return *this; } | |||
CButtonState& operator|= (int32_t s) { state |= s; return *this; } | |||
int32_t operator& (const CButtonState& s) const { return state & s.state; } | |||
int32_t operator| (const CButtonState& s) const { return state | s.state; } | |||
int32_t operator~ () const { return ~state; } | |||
bool operator== (const CButtonState& s) const { return state == s.state; } | |||
bool operator!= (const CButtonState& s) const { return state != s.state; } | |||
protected: | |||
int32_t state; | |||
}; | |||
} // VSTGUI |
@@ -0,0 +1,319 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#include "ccolor.h" | |||
#include "cstring.h" | |||
#include <cmath> | |||
#include <sstream> | |||
#include <iomanip> | |||
namespace VSTGUI { | |||
/// @cond ignore | |||
//----------------------------------------------------------------------------- | |||
template<typename _Tp> | |||
inline const _Tp& min3 (const _Tp& v1, const _Tp& v2, const _Tp& v3) | |||
{ | |||
if (v1 <= v2) | |||
return (v1 <= v3) ? v1 : v3; | |||
return (v2 <= v3) ? v2 : v3; | |||
} | |||
//----------------------------------------------------------------------------- | |||
template<typename _Tp> | |||
inline const _Tp& max3 (const _Tp& v1, const _Tp& v2, const _Tp& v3) | |||
{ | |||
if (v1 >= v2) | |||
return (v1 >= v3) ? v1 : v3; | |||
return (v2 >= v3) ? v2 : v3; | |||
} | |||
/// @endcond | |||
//----------------------------------------------------------------------------- | |||
uint8_t CColor::getLightness () const | |||
{ | |||
return (max3<uint8_t> (red, green, blue) / 2) + (min3<uint8_t>(red, green, blue) / 2); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CColor::toHSL (double& hue, double& saturation, double& lightness) const | |||
{ | |||
double r = red / 255.; | |||
double g = green / 255.; | |||
double b = blue / 255.; | |||
double M = max3<double> (r, g ,b); | |||
double m = min3<double> (r, g ,b); | |||
double C = M - m; | |||
lightness = (M + m) / 2.; | |||
if (C == 0.) | |||
{ | |||
hue = saturation = 0.; | |||
return; | |||
} | |||
if (M == r) | |||
{ | |||
hue = fmod (((g-b) / C), 6.); | |||
} | |||
else if (M == g) | |||
{ | |||
hue = ((b - r) / C) + 2.; | |||
} | |||
else if (M == b) | |||
{ | |||
hue = ((r - g) / C) + 4.; | |||
} | |||
hue *= 60.; | |||
if (hue < 0.0) | |||
hue += 360.0; | |||
if (lightness <= 0.5) | |||
saturation = C / (2. * lightness); | |||
else | |||
saturation = C / (2. - 2. * lightness); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CColor::fromHSL (double hue, double saturation, double lightness) | |||
{ | |||
while (hue > 360.) | |||
hue -= 360.; | |||
while (hue < 0.) | |||
hue += 360.; | |||
double C = (1. - fabs (2 * lightness - 1)) * saturation; | |||
double H = hue / 60.; | |||
double X = C * (1. - fabs (fmod (H, 2) - 1.)); | |||
double r,g,b; | |||
if (H >= 0 && H < 1.) | |||
{ | |||
r = C; | |||
g = X; | |||
b = 0.; | |||
} | |||
else if (H >= 1. && H < 2.) | |||
{ | |||
r = X; | |||
g = C; | |||
b = 0.; | |||
} | |||
else if (H >= 2. && H < 3.) | |||
{ | |||
r = 0.; | |||
g = C; | |||
b = X; | |||
} | |||
else if (H >= 3. && H < 4.) | |||
{ | |||
r = 0.; | |||
g = X; | |||
b = C; | |||
} | |||
else if (H >= 4. && H < 5.) | |||
{ | |||
r = X; | |||
g = 0.; | |||
b = C; | |||
} | |||
else // if (H >= 5. && H <= 6.) | |||
{ | |||
r = C; | |||
g = 0.; | |||
b = X; | |||
} | |||
double m = lightness - (C / 2.); | |||
r = (r + m) * 255; | |||
g = (g + m ) * 255.; | |||
b = (b + m ) * 255.; | |||
red = static_cast<uint8_t> (floor (r + 0.5)); | |||
green = static_cast<uint8_t> (floor (g + 0.5)); | |||
blue = static_cast<uint8_t> (floor (b + 0.5)); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CColor::toHSV (double& hue, double& saturation, double& value) const | |||
{ | |||
double rgbMax = (max3<uint8_t> (red, green, blue)) / 255.; | |||
value = rgbMax; | |||
if (value == 0) | |||
{ | |||
hue = saturation = 0; | |||
return; | |||
} | |||
/* Normalize value to 1 */ | |||
double r = (red / 255.) / value; | |||
double g = (green / 255.) / value; | |||
double b = (blue / 255.) / value; | |||
double rgbMin = min3<double> (r, g, b); | |||
rgbMax = max3<double> (r, g, b); | |||
saturation = rgbMax - rgbMin; | |||
if (saturation == 0) | |||
{ | |||
hue = 0.; | |||
return; | |||
} | |||
/* Normalize saturation to 1 */ | |||
r = (r - rgbMin)/(rgbMax - rgbMin); | |||
g = (g - rgbMin)/(rgbMax - rgbMin); | |||
b = (b - rgbMin)/(rgbMax - rgbMin); | |||
rgbMax = max3<double> (r, g, b); | |||
/* Compute hue */ | |||
if (rgbMax == r) | |||
{ | |||
hue = 0.0 + 60.0 * (g - b); | |||
} | |||
else if (rgbMax == g) | |||
{ | |||
hue = 120.0 + 60.0 * (b - r); | |||
} | |||
else /* rgbMax == b */ | |||
{ | |||
hue = 240.0 + 60.0 * (r - g); | |||
} | |||
if (hue < 0.0) | |||
{ | |||
hue += 360.0; | |||
} | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CColor::fromHSV (double hue, double saturation, double value) | |||
{ | |||
if (value <= 0.) | |||
{ | |||
red = green = blue = 0; | |||
return; | |||
} | |||
else if (value > 1.) | |||
value = 1.; | |||
if (saturation <= 0.) | |||
{ | |||
red = green = blue = static_cast<uint8_t> (value * 255.); | |||
return; | |||
} | |||
else if (saturation > 1.) | |||
saturation = 1.; | |||
while (hue > 360.) | |||
hue -= 360.; | |||
while (hue < 0.) | |||
hue += 360.; | |||
const double hf = hue / 60.0; | |||
const int32_t i = static_cast<int32_t> (floor (hf)); | |||
const double f = hf - i; | |||
const double pv = value * ( 1 - saturation ); | |||
const double qv = value * ( 1 - saturation * f ); | |||
const double tv = value * ( 1 - saturation * ( 1 - f ) ); | |||
double r = 0.; | |||
double g = 0.; | |||
double b = 0.; | |||
switch (i) | |||
{ | |||
// red is dominant | |||
case 0: | |||
{ | |||
r = value; | |||
g = tv; | |||
b = pv; | |||
break; | |||
} | |||
case 5: | |||
{ | |||
r = value; | |||
g = pv; | |||
b = qv; | |||
break; | |||
} | |||
case 6: | |||
{ | |||
r = value; | |||
g = tv; | |||
b = pv; | |||
break; | |||
} | |||
case -1: | |||
{ | |||
r = value; | |||
g = pv; | |||
b = qv; | |||
break; | |||
} | |||
// green is dominant | |||
case 1: | |||
{ | |||
r = qv; | |||
g = value; | |||
b = pv; | |||
break; | |||
} | |||
case 2: | |||
{ | |||
r = pv; | |||
g = value; | |||
b = tv; | |||
break; | |||
} | |||
// blue is dominant | |||
case 3: | |||
{ | |||
r = pv; | |||
g = qv; | |||
b = value; | |||
break; | |||
} | |||
case 4: | |||
{ | |||
r = tv; | |||
g = pv; | |||
b = value; | |||
break; | |||
} | |||
} | |||
red = static_cast<uint8_t> (floor (r * 255. + 0.5)); | |||
green = static_cast<uint8_t> (floor (g * 255. + 0.5)); | |||
blue = static_cast<uint8_t> (floor (b * 255. + 0.5)); | |||
} | |||
//----------------------------------------------------------------------------- | |||
bool CColor::isColorRepresentation (UTF8StringPtr str) | |||
{ | |||
if (str && str[0] == '#' && strlen (str) == 9) | |||
return true; | |||
return false; | |||
} | |||
//----------------------------------------------------------------------------- | |||
bool CColor::fromString (UTF8StringPtr str) | |||
{ | |||
if (!str) | |||
return false; | |||
if (!isColorRepresentation (str)) | |||
return false; | |||
std::string rv (str + 1, 2); | |||
std::string gv (str + 3, 2); | |||
std::string bv (str + 5, 2); | |||
std::string av (str + 7, 2); | |||
red = (uint8_t)strtol (rv.data (), nullptr, 16); | |||
green = (uint8_t)strtol (gv.data (), nullptr, 16); | |||
blue = (uint8_t)strtol (bv.data (), nullptr, 16); | |||
alpha = (uint8_t)strtol (av.data (), nullptr, 16); | |||
return true; | |||
} | |||
//----------------------------------------------------------------------------- | |||
UTF8String CColor::toString () const | |||
{ | |||
std::stringstream str; | |||
str << "#"; | |||
str << std::hex << std::setw (2) << std::setfill ('0') << static_cast<int32_t> (red); | |||
str << std::hex << std::setw (2) << std::setfill ('0') << static_cast<int32_t> (green); | |||
str << std::hex << std::setw (2) << std::setfill ('0') << static_cast<int32_t> (blue); | |||
str << std::hex << std::setw (2) << std::setfill ('0') << static_cast<int32_t> (alpha); | |||
return UTF8String (str.str ()); | |||
} | |||
} // VSTGUI |
@@ -0,0 +1,126 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "vstguibase.h" | |||
#include "vstguifwd.h" | |||
namespace VSTGUI { | |||
//----------------------------------------------------------------------------- | |||
//! @brief RGBA Color structure | |||
//----------------------------------------------------------------------------- | |||
struct CColor | |||
{ | |||
constexpr CColor () = default; | |||
constexpr CColor (uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha = 255) | |||
: red (red), green (green), blue (blue), alpha (alpha) | |||
{} | |||
constexpr CColor (const CColor& inColor) | |||
: red (inColor.red), green (inColor.green), blue (inColor.blue), alpha (inColor.alpha) | |||
{} | |||
//----------------------------------------------------------------------------- | |||
/// @name Operator Methods | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
CColor& operator() (uint8_t _red, uint8_t _green, uint8_t _blue, uint8_t _alpha) | |||
{ | |||
red = _red; | |||
green = _green; | |||
blue = _blue; | |||
alpha = _alpha; | |||
return *this; | |||
} | |||
CColor& operator= (const CColor& newColor) | |||
{ | |||
red = newColor.red; | |||
green = newColor.green; | |||
blue = newColor.blue; | |||
alpha = newColor.alpha; | |||
return *this; | |||
} | |||
bool operator!= (const CColor &other) const | |||
{ return (red != other.red || green != other.green || blue != other.blue || alpha != other.alpha); } | |||
bool operator== (const CColor &other) const | |||
{ return (red == other.red && green == other.green && blue == other.blue && alpha == other.alpha); } | |||
//@} | |||
//----------------------------------------------------------------------------- | |||
/// @name Convert Methods | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
/** | |||
* @brief convert to hue, saturation and value | |||
* @param hue in degree [0..360] | |||
* @param saturation normalized [0..1] | |||
* @param value normalized [0..1] | |||
*/ | |||
void toHSV (double& hue, double& saturation, double& value) const; | |||
/** | |||
* @brief convert from hue, saturation and value | |||
* @param hue in degree [0..360] | |||
* @param saturation normalized [0..1] | |||
* @param value normalized [0..1] | |||
*/ | |||
void fromHSV (double hue, double saturation, double value); | |||
/** | |||
* @brief convert to hue, saturation and lightness | |||
* @param hue in degree [0..360] | |||
* @param saturation normalized [0..1] | |||
* @param lightness normalized [0..1] | |||
*/ | |||
void toHSL (double& hue, double& saturation, double& lightness) const; | |||
/** | |||
* @brief convert from hue, saturation and lightness | |||
* @param hue in degree [0..360] | |||
* @param saturation normalized [0..1] | |||
* @param lightness normalized [0..1] | |||
*/ | |||
void fromHSL (double hue, double saturation, double lightness); | |||
/** get the luma of the color */ | |||
constexpr uint8_t getLuma () const { return (uint8_t)((float)red * 0.3f + (float)green * 0.59f + (float)blue * 0.11f); } | |||
/** get the lightness of the color */ | |||
uint8_t getLightness () const; | |||
//@} | |||
bool fromString (UTF8StringPtr str); | |||
UTF8String toString () const; | |||
static bool isColorRepresentation (UTF8StringPtr str); | |||
/** red component [0..255] */ | |||
uint8_t red {255}; | |||
/** green component [0..255] */ | |||
uint8_t green {255}; | |||
/** blue component [0..255] */ | |||
uint8_t blue {255}; | |||
/** alpha component [0..255] */ | |||
uint8_t alpha {255}; | |||
}; | |||
inline constexpr CColor MakeCColor (uint8_t red = 0, uint8_t green = 0, uint8_t blue = 0, uint8_t alpha = 255) | |||
{ | |||
return CColor (red, green, blue, alpha); | |||
} | |||
// define some basic colors | |||
constexpr const CColor kTransparentCColor = CColor (255, 255, 255, 0); | |||
constexpr const CColor kBlackCColor = CColor ( 0, 0, 0, 255); | |||
constexpr const CColor kWhiteCColor = CColor (255, 255, 255, 255); | |||
constexpr const CColor kGreyCColor = CColor (127, 127, 127, 255); | |||
constexpr const CColor kRedCColor = CColor (255, 0, 0, 255); | |||
constexpr const CColor kGreenCColor = CColor ( 0, 255, 0, 255); | |||
constexpr const CColor kBlueCColor = CColor ( 0, 0, 255, 255); | |||
constexpr const CColor kYellowCColor = CColor (255, 255, 0, 255); | |||
constexpr const CColor kMagentaCColor = CColor (255, 0, 255, 255); | |||
constexpr const CColor kCyanCColor = CColor ( 0, 255, 255, 255); | |||
} // VSTGUI |
@@ -0,0 +1,129 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "vstguifwd.h" | |||
#include "cscrollview.h" | |||
#include "cfont.h" | |||
#include "ccolor.h" | |||
#include "cstring.h" | |||
#include <vector> | |||
namespace VSTGUI { | |||
// forward private internal views | |||
class CDataBrowserView; | |||
class CDataBrowserHeader; | |||
//----------------------------------------------------------------------------- | |||
// CDataBrowser Declaration | |||
//! @brief DataBrowser view | |||
/// @ingroup controls | |||
//----------------------------------------------------------------------------------------------- | |||
class CDataBrowser : public CScrollView | |||
{ | |||
protected: | |||
enum | |||
{ | |||
kDrawRowLinesFlag = kLastScrollViewStyleFlag, | |||
kDrawColumnLinesFlag, | |||
kDrawHeaderFlag, | |||
kMultiSelectionStyleFlag | |||
}; | |||
public: | |||
CDataBrowser (const CRect& size, IDataBrowserDelegate* db, int32_t style = 0, CCoord scrollbarWidth = 16, CBitmap* pBackground = nullptr); | |||
enum CDataBrowserStyle | |||
{ | |||
// see CScrollView for more styles | |||
kDrawRowLines = 1 << kDrawRowLinesFlag, | |||
kDrawColumnLines = 1 << kDrawColumnLinesFlag, | |||
kDrawHeader = 1 << kDrawHeaderFlag, | |||
kMultiSelectionStyle = 1 << kMultiSelectionStyleFlag | |||
}; | |||
enum | |||
{ | |||
kNoSelection = -1 | |||
}; | |||
/// @brief CDataBrowser Cell position description | |||
struct Cell { | |||
int32_t row {-1}; | |||
int32_t column {-1}; | |||
Cell () = default; | |||
Cell (int32_t row, int32_t column) : row (row), column (column) {} | |||
bool isValid () const { return row > -1 && column > -1; } | |||
}; | |||
using Selection = std::vector<int32_t>; | |||
//----------------------------------------------------------------------------- | |||
/// @name CDataBrowser Methods | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
/** trigger recalculation, call if numRows or numColumns changed */ | |||
virtual void recalculateLayout (bool rememberSelection = false); | |||
/** invalidates an individual cell */ | |||
virtual void invalidate (const Cell& cell); | |||
/** invalidates a complete row */ | |||
virtual void invalidateRow (int32_t row); | |||
/** scrolls the scrollview so that row is visible */ | |||
virtual void makeRowVisible (int32_t row); | |||
/** get bounds of a cell */ | |||
virtual CRect getCellBounds (const Cell& cell); | |||
/** get the cell at position where */ | |||
virtual Cell getCellAt (const CPoint& where) const; | |||
/** get first selected row */ | |||
virtual int32_t getSelectedRow () const; | |||
/** set the exclusive selected row */ | |||
virtual void setSelectedRow (int32_t row, bool makeVisible = false); | |||
/** get all selected rows */ | |||
const Selection& getSelection () const { return selection; } | |||
/** add row to selection */ | |||
virtual void selectRow (int32_t row); | |||
/** remove row from selection */ | |||
virtual void unselectRow (int32_t row); | |||
/** empty selection */ | |||
virtual void unselectAll (); | |||
/** starts a text edit for a cell */ | |||
virtual void beginTextEdit (const Cell& cell, UTF8StringPtr initialText); | |||
/** get delegate object */ | |||
IDataBrowserDelegate* getDelegate () const { return db; } | |||
//@} | |||
void setAutosizeFlags (int32_t flags) override; | |||
void setViewSize (const CRect& size, bool invalid) override; | |||
void setWantsFocus (bool state) override; | |||
int32_t onKeyDown (VstKeyCode& keyCode) override; | |||
CMouseEventResult onMouseDown (CPoint& where, const CButtonState& buttons) override; | |||
protected: | |||
~CDataBrowser () noexcept override; | |||
void valueChanged (CControl *pControl) override; | |||
CMessageResult notify (CBaseObject* sender, IdStringPtr message) override; | |||
bool attached (CView *parent) override; | |||
bool removed (CView* parent) override; | |||
bool wantsFocus () const override; | |||
void recalculateSubViews () override; | |||
void validateSelection (); | |||
IDataBrowserDelegate* db; | |||
CDataBrowserView* dbView; | |||
CDataBrowserHeader* dbHeader; | |||
CViewContainer* dbHeaderContainer; | |||
Selection selection; | |||
}; | |||
//----------------------------------------------------------------------------- | |||
} // VSTGUI |
@@ -0,0 +1,381 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#include "cdrawcontext.h" | |||
#include "cgraphicspath.h" | |||
#include "cbitmap.h" | |||
#include "cstring.h" | |||
#include "platform/iplatformfont.h" | |||
#include <cassert> | |||
namespace VSTGUI { | |||
//----------------------------------------------------------------------------- | |||
CDrawContext::CDrawContextState::CDrawContextState (const CDrawContextState& state) | |||
{ | |||
*this = state; | |||
} | |||
//----------------------------------------------------------------------------- | |||
CDrawContext::CDrawContextState::CDrawContextState (CDrawContextState&& state) noexcept | |||
{ | |||
*this = std::move (state); | |||
} | |||
//----------------------------------------------------------------------------- | |||
CDrawContext::CDrawContextState& CDrawContext::CDrawContextState::operator= (CDrawContextState&& state) noexcept | |||
{ | |||
font = std::move (state.font); | |||
frameColor = std::move (state.frameColor); | |||
fillColor = std::move (state.fillColor); | |||
fontColor = std::move (state.fontColor); | |||
frameWidth = std::move (state.frameWidth); | |||
penLoc = std::move (state.penLoc); | |||
clipRect = std::move (state.clipRect); | |||
lineStyle = std::move (state.lineStyle); | |||
drawMode = std::move (state.drawMode); | |||
globalAlpha = std::move (state.globalAlpha); | |||
return *this; | |||
} | |||
//----------------------------------------------------------------------------- | |||
CDrawContext::Transform::Transform (CDrawContext& context, const CGraphicsTransform& transformation) | |||
: context (context) | |||
, transformation (transformation) | |||
{ | |||
if (transformation.isInvariant () == false) | |||
context.pushTransform (transformation); | |||
} | |||
//----------------------------------------------------------------------------- | |||
CDrawContext::Transform::~Transform () noexcept | |||
{ | |||
if (transformation.isInvariant () == false) | |||
context.popTransform (); | |||
} | |||
//----------------------------------------------------------------------------- | |||
CDrawContext::CDrawContext (const CRect& surfaceRect) | |||
: surfaceRect (surfaceRect) | |||
{ | |||
transformStack.push (CGraphicsTransform ()); | |||
} | |||
//----------------------------------------------------------------------------- | |||
CDrawContext::~CDrawContext () noexcept | |||
{ | |||
#if DEBUG | |||
if (!globalStatesStack.empty ()) | |||
DebugPrint ("Global state stack not empty. Save and restore global state must be called in sequence !\n"); | |||
#endif | |||
if (drawStringHelper) | |||
delete drawStringHelper; | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CDrawContext::init () | |||
{ | |||
// set the default values | |||
setFrameColor (kWhiteCColor); | |||
setLineStyle (kLineSolid); | |||
setLineWidth (1); | |||
setFillColor (kBlackCColor); | |||
setFontColor (kWhiteCColor); | |||
setFont (kSystemFont); | |||
setDrawMode (kAliasing); | |||
setClipRect (surfaceRect); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CDrawContext::saveGlobalState () | |||
{ | |||
globalStatesStack.push (currentState); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CDrawContext::restoreGlobalState () | |||
{ | |||
if (!globalStatesStack.empty ()) | |||
{ | |||
currentState = std::move (globalStatesStack.top ()); | |||
globalStatesStack.pop (); | |||
} | |||
else | |||
{ | |||
#if DEBUG | |||
DebugPrint ("No saved global state in draw context !!!\n"); | |||
#endif | |||
} | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CDrawContext::setBitmapInterpolationQuality(BitmapInterpolationQuality quality) | |||
{ | |||
currentState.bitmapQuality = quality; | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CDrawContext::setLineStyle (const CLineStyle& style) | |||
{ | |||
currentState.lineStyle = style; | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CDrawContext::setLineWidth (CCoord width) | |||
{ | |||
currentState.frameWidth = width; | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CDrawContext::setDrawMode (CDrawMode mode) | |||
{ | |||
currentState.drawMode = mode; | |||
} | |||
//----------------------------------------------------------------------------- | |||
CRect& CDrawContext::getClipRect (CRect &clip) const | |||
{ | |||
clip = currentState.clipRect; | |||
getCurrentTransform ().inverse ().transform (clip); | |||
clip.normalize (); | |||
return clip; | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CDrawContext::setClipRect (const CRect &clip) | |||
{ | |||
currentState.clipRect = clip; | |||
getCurrentTransform ().transform (currentState.clipRect); | |||
currentState.clipRect.normalize (); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CDrawContext::resetClipRect () | |||
{ | |||
currentState.clipRect = surfaceRect; | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CDrawContext::setFillColor (const CColor& color) | |||
{ | |||
currentState.fillColor = color; | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CDrawContext::setFrameColor (const CColor& color) | |||
{ | |||
currentState.frameColor = color; | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CDrawContext::setFontColor (const CColor& color) | |||
{ | |||
currentState.fontColor = color; | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CDrawContext::setFont (const CFontRef newFont, const CCoord& size, const int32_t& style) | |||
{ | |||
if (newFont == nullptr) | |||
return; | |||
if ((size > 0 && newFont->getSize () != size) || (style != -1 && newFont->getStyle () != style)) | |||
{ | |||
currentState.font = makeOwned<CFontDesc> (*newFont); | |||
if (size > 0) | |||
currentState.font->setSize (size); | |||
if (style != -1) | |||
currentState.font->setStyle (style); | |||
} | |||
else | |||
{ | |||
currentState.font = newFont; | |||
} | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CDrawContext::setGlobalAlpha (float newAlpha) | |||
{ | |||
currentState.globalAlpha = newAlpha; | |||
} | |||
//----------------------------------------------------------------------------- | |||
const UTF8String& CDrawContext::getDrawString (UTF8StringPtr string) | |||
{ | |||
if (drawStringHelper == nullptr) | |||
drawStringHelper = new UTF8String (string); | |||
else | |||
drawStringHelper->assign (string); | |||
return *drawStringHelper; | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CDrawContext::clearDrawString () | |||
{ | |||
if (drawStringHelper) | |||
drawStringHelper->clear (); | |||
} | |||
//------------------------------------------------------------------------ | |||
CCoord CDrawContext::getStringWidth (IPlatformString* string) | |||
{ | |||
CCoord result = -1; | |||
if (currentState.font == nullptr || string == nullptr) | |||
return result; | |||
if (auto painter = currentState.font->getFontPainter ()) | |||
result = painter->getStringWidth (this, string, true); | |||
return result; | |||
} | |||
//------------------------------------------------------------------------ | |||
void CDrawContext::drawString (IPlatformString* string, const CRect& _rect, const CHoriTxtAlign hAlign, bool antialias) | |||
{ | |||
if (!string || currentState.font == nullptr) | |||
return; | |||
auto painter = currentState.font->getFontPainter (); | |||
if (painter == nullptr) | |||
return; | |||
CRect rect (_rect); | |||
double capHeight = -1; | |||
auto platformFont = currentState.font->getPlatformFont (); | |||
if (platformFont) | |||
capHeight = platformFont->getCapHeight (); | |||
if (capHeight > 0.) | |||
rect.bottom -= (rect.getHeight () / 2. - capHeight / 2.); | |||
else | |||
rect.bottom -= (rect.getHeight () / 2. - currentState.font->getSize () / 2.) + 1.; | |||
if (hAlign != kLeftText) | |||
{ | |||
CCoord stringWidth = painter->getStringWidth (this, string, antialias); | |||
if (hAlign == kRightText) | |||
rect.left = rect.right - stringWidth; | |||
else | |||
rect.left = rect.left + (rect.getWidth () / 2.) - (stringWidth / 2.); | |||
} | |||
painter->drawString (this, string, CPoint (rect.left, rect.bottom), antialias); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CDrawContext::drawString (IPlatformString* string, const CPoint& point, bool antialias) | |||
{ | |||
if (string == nullptr || currentState.font == nullptr) | |||
return; | |||
if (auto painter = currentState.font->getFontPainter ()) | |||
painter->drawString (this, string, point, antialias); | |||
} | |||
//----------------------------------------------------------------------------- | |||
CCoord CDrawContext::getStringWidth (UTF8StringPtr string) | |||
{ | |||
return getStringWidth (getDrawString (string).getPlatformString ()); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CDrawContext::drawString (UTF8StringPtr string, const CPoint& point, bool antialias) | |||
{ | |||
drawString (getDrawString (string).getPlatformString (), point, antialias); | |||
clearDrawString (); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CDrawContext::drawString (UTF8StringPtr string, const CRect& rect, const CHoriTxtAlign hAlign, bool antialias) | |||
{ | |||
drawString (getDrawString (string).getPlatformString (), rect, hAlign, antialias); | |||
clearDrawString (); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CDrawContext::fillRectWithBitmap (CBitmap* bitmap, const CRect& srcRect, const CRect& dstRect, float alpha) | |||
{ | |||
if (srcRect.isEmpty () || dstRect.isEmpty ()) | |||
return; | |||
CRect bitmapPartRect; | |||
CPoint sourceOffset (srcRect.left, srcRect.top); | |||
for (auto top = dstRect.top; top < dstRect.bottom; top += srcRect.getHeight ()) | |||
{ | |||
bitmapPartRect.top = top; | |||
bitmapPartRect.bottom = top + srcRect.getHeight (); | |||
if (bitmapPartRect.bottom > dstRect.bottom) | |||
bitmapPartRect.bottom = dstRect.bottom; | |||
// The following should never be true, I guess | |||
if (bitmapPartRect.getHeight () > srcRect.getHeight ()) | |||
bitmapPartRect.setHeight (srcRect.getHeight ()); | |||
for (auto left = dstRect.left; left < dstRect.right; left += srcRect.getWidth ()) | |||
{ | |||
bitmapPartRect.left = left; | |||
bitmapPartRect.right = left + srcRect.getWidth (); | |||
if (bitmapPartRect.right > dstRect.right) | |||
bitmapPartRect.right = dstRect.right; | |||
// The following should never be true, I guess | |||
if (bitmapPartRect.getWidth () > srcRect.getWidth ()) | |||
bitmapPartRect.setWidth (srcRect.getWidth ()); | |||
drawBitmap (bitmap, bitmapPartRect, sourceOffset, alpha); | |||
} | |||
} | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CDrawContext::drawBitmapNinePartTiled (CBitmap* bitmap, const CRect& dest, const CNinePartTiledDescription& desc, float alpha) | |||
{ | |||
CRect myBitmapBounds (0, 0, bitmap->getWidth (), bitmap->getHeight ()); | |||
CRect mySourceRect [CNinePartTiledDescription::kPartCount]; | |||
CRect myDestRect [CNinePartTiledDescription::kPartCount]; | |||
desc.calcRects (myBitmapBounds, mySourceRect); | |||
desc.calcRects (dest, myDestRect); | |||
for (size_t i = 0; i < CNinePartTiledDescription::kPartCount; i++) | |||
fillRectWithBitmap (bitmap, mySourceRect[i], myDestRect[i], alpha); | |||
} | |||
//----------------------------------------------------------------------------- | |||
CGraphicsPath* CDrawContext::createRoundRectGraphicsPath (const CRect& size, CCoord radius) | |||
{ | |||
CGraphicsPath* path = createGraphicsPath (); | |||
if (path) | |||
{ | |||
path->addRoundRect (size, radius); | |||
} | |||
return path; | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CDrawContext::pushTransform (const CGraphicsTransform& transformation) | |||
{ | |||
vstgui_assert (transformStack.size () > 0); | |||
const CGraphicsTransform& currentTransform = transformStack.top (); | |||
CGraphicsTransform newTransform = currentTransform * transformation; | |||
transformStack.push (newTransform); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CDrawContext::popTransform () | |||
{ | |||
vstgui_assert (transformStack.size () > 1); | |||
transformStack.pop (); | |||
} | |||
//----------------------------------------------------------------------------- | |||
const CGraphicsTransform& CDrawContext::getCurrentTransform () const | |||
{ | |||
return transformStack.top (); | |||
} | |||
//------------------------------------------------------------------------ | |||
CCoord CDrawContext::getHairlineSize () const | |||
{ | |||
return 1. / (getScaleFactor () * getCurrentTransform ().m11); | |||
} | |||
} // VSTGUI |
@@ -0,0 +1,302 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "vstguifwd.h" | |||
#include "cpoint.h" | |||
#include "crect.h" | |||
#include "cfont.h" | |||
#include "ccolor.h" | |||
#include "cgraphicstransform.h" | |||
#include "clinestyle.h" | |||
#include "cdrawdefs.h" | |||
#include <cmath> | |||
#include <stack> | |||
#include <vector> | |||
namespace VSTGUI { | |||
struct CNinePartTiledDescription; | |||
//----------------------------------------------------------------------------- | |||
// CDrawContext Declaration | |||
//! @brief A drawing context encapsulates the drawing context of the underlying OS | |||
//----------------------------------------------------------------------------- | |||
class CDrawContext : public AtomicReferenceCounted | |||
{ | |||
public: | |||
//----------------------------------------------------------------------------- | |||
/** Add a transform to all draw routines. Must be used as stack object. */ | |||
//----------------------------------------------------------------------------- | |||
struct Transform | |||
{ | |||
Transform (CDrawContext& context, const CGraphicsTransform& transformation); | |||
~Transform () noexcept; | |||
private: | |||
CDrawContext& context; | |||
const CGraphicsTransform transformation; | |||
}; | |||
//----------------------------------------------------------------------------- | |||
/// @name Draw primitives | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
using LinePair = std::pair<CPoint, CPoint>; | |||
using LineList = std::vector<LinePair>; | |||
using PointList = std::vector<CPoint>; | |||
inline void drawLine (const CPoint& start, const CPoint& end) { drawLine (std::make_pair (start, end)); } | |||
/** draw a line */ | |||
virtual void drawLine (const LinePair& line) = 0; | |||
/** draw multiple lines at once */ | |||
virtual void drawLines (const LineList& lines) = 0; | |||
/** draw a polygon */ | |||
virtual void drawPolygon (const PointList& polygonPointList, const CDrawStyle drawStyle = kDrawStroked) = 0; | |||
/** draw a rect */ | |||
virtual void drawRect (const CRect &rect, const CDrawStyle drawStyle = kDrawStroked) = 0; | |||
/** draw an arc, angles are in degree */ | |||
virtual void drawArc (const CRect &rect, const float startAngle1, const float endAngle2, const CDrawStyle drawStyle = kDrawStroked) = 0; | |||
/** draw an ellipse */ | |||
virtual void drawEllipse (const CRect &rect, const CDrawStyle drawStyle = kDrawStroked) = 0; | |||
/** draw a point */ | |||
virtual void drawPoint (const CPoint &point, const CColor& color) = 0; | |||
/** don't call directly, please use CBitmap::draw instead */ | |||
virtual void drawBitmap (CBitmap* bitmap, const CRect& dest, const CPoint& offset = CPoint (0, 0), float alpha = 1.f) = 0; | |||
virtual void drawBitmapNinePartTiled (CBitmap* bitmap, const CRect& dest, const CNinePartTiledDescription& desc, float alpha = 1.f); | |||
virtual void fillRectWithBitmap (CBitmap* bitmap, const CRect& srcRect, const CRect& dstRect, float alpha); | |||
/** clears the rect (makes r = 0, g = 0, b = 0, a = 0) */ | |||
virtual void clearRect (const CRect& rect) = 0; | |||
//@} | |||
//----------------------------------------------------------------------------- | |||
// @name Bitmap Interpolation Quality | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
virtual void setBitmapInterpolationQuality (BitmapInterpolationQuality quality); ///< set the current bitmap interpolation quality | |||
const BitmapInterpolationQuality& getBitmapInterpolationQuality () const { return currentState.bitmapQuality; } ///< get the current bitmap interpolation quality | |||
//@} | |||
//----------------------------------------------------------------------------- | |||
/// @name Line Mode | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
/** set the current line style */ | |||
virtual void setLineStyle (const CLineStyle& style); | |||
/** get the current line style */ | |||
const CLineStyle& getLineStyle () const { return currentState.lineStyle; } | |||
/** set the current line width */ | |||
virtual void setLineWidth (CCoord width); | |||
/** get the current line width */ | |||
CCoord getLineWidth () const { return currentState.frameWidth; } | |||
//@} | |||
//----------------------------------------------------------------------------- | |||
/// @name Draw Mode | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
/** set the current draw mode, see CDrawMode */ | |||
virtual void setDrawMode (CDrawMode mode); | |||
/** get the current draw mode, see CDrawMode */ | |||
CDrawMode getDrawMode () const { return currentState.drawMode; } | |||
//@} | |||
//----------------------------------------------------------------------------- | |||
/// @name Clipping | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
/** set the current clip */ | |||
virtual void setClipRect (const CRect &clip); | |||
/** get the current clip */ | |||
CRect& getClipRect (CRect &clip) const; | |||
/** reset the clip to the default state */ | |||
virtual void resetClipRect (); | |||
//@} | |||
//----------------------------------------------------------------------------- | |||
/// @name Color | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
/** set current fill color */ | |||
virtual void setFillColor (const CColor& color); | |||
/** get current fill color */ | |||
CColor getFillColor () const { return currentState.fillColor; } | |||
/** set current stroke color */ | |||
virtual void setFrameColor (const CColor& color); | |||
/** get current stroke color */ | |||
CColor getFrameColor () const { return currentState.frameColor; } | |||
//@} | |||
//----------------------------------------------------------------------------- | |||
/// @name Font | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
/** set current font color */ | |||
virtual void setFontColor (const CColor& color); | |||
/** get current font color */ | |||
CColor getFontColor () const { return currentState.fontColor; } | |||
/** set current font */ | |||
virtual void setFont (const CFontRef font, const CCoord& size = 0, const int32_t& style = -1); | |||
/** get current font */ | |||
const CFontRef getFont () const { return currentState.font; } | |||
//@} | |||
//----------------------------------------------------------------------------- | |||
/// @name Text | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
/** get the width of an UTF-8 encoded string */ | |||
CCoord getStringWidth (UTF8StringPtr pStr); | |||
/** draw an UTF-8 encoded string */ | |||
void drawString (UTF8StringPtr string, const CRect& _rect, const CHoriTxtAlign hAlign = kCenterText, bool antialias = true); | |||
/** draw an UTF-8 encoded string */ | |||
void drawString (UTF8StringPtr string, const CPoint& _point, bool antialias = true); | |||
/** get the width of a platform string */ | |||
CCoord getStringWidth (IPlatformString* pStr); | |||
/** draw a platform string */ | |||
void drawString (IPlatformString* string, const CRect& _rect, const CHoriTxtAlign hAlign = kCenterText, bool antialias = true); | |||
/** draw a platform string */ | |||
void drawString (IPlatformString* string, const CPoint& _point, bool antialias = true); | |||
//@} | |||
//----------------------------------------------------------------------------- | |||
/// @name Global Alpha State | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
/** sets the global alpha value[0..1] */ | |||
virtual void setGlobalAlpha (float newAlpha); | |||
/** get current global alpha value */ | |||
float getGlobalAlpha () const { return currentState.globalAlpha; } | |||
//@} | |||
//----------------------------------------------------------------------------- | |||
/// @name Global State Stack | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
virtual void saveGlobalState (); | |||
virtual void restoreGlobalState (); | |||
//@} | |||
//----------------------------------------------------------------------------- | |||
/// @name Transformation | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
const CGraphicsTransform& getCurrentTransform () const; | |||
const CRect& getAbsoluteClipRect () const { return currentState.clipRect; } | |||
/** returns the backend scale factor. */ | |||
virtual double getScaleFactor () const { return 1.; } | |||
/** returns the current line size which corresponds to one pixel on screen. | |||
* | |||
* do not cache this value, instead ask for it every time you need it. | |||
*/ | |||
CCoord getHairlineSize () const; | |||
//@} | |||
//----------------------------------------------------------------------------- | |||
/// @name Graphics Paths | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
/** create a graphics path object, you need to forget it after usage */ | |||
virtual CGraphicsPath* createGraphicsPath () = 0; | |||
/** create a graphics path from a text */ | |||
virtual CGraphicsPath* createTextPath (const CFontRef font, UTF8StringPtr text) = 0; | |||
/** create a rect with round corners as graphics path, you need to forget it after usage */ | |||
CGraphicsPath* createRoundRectGraphicsPath (const CRect& size, CCoord radius); | |||
enum PathDrawMode | |||
{ | |||
kPathFilled, | |||
kPathFilledEvenOdd, | |||
kPathStroked | |||
}; | |||
virtual void drawGraphicsPath (CGraphicsPath* path, PathDrawMode mode = kPathFilled, CGraphicsTransform* transformation = nullptr) = 0; | |||
virtual void fillLinearGradient (CGraphicsPath* path, const CGradient& gradient, const CPoint& startPoint, const CPoint& endPoint, bool evenOdd = false, CGraphicsTransform* transformation = nullptr) = 0; | |||
virtual void fillRadialGradient (CGraphicsPath* path, const CGradient& gradient, const CPoint& center, CCoord radius, const CPoint& originOffset = CPoint (0,0), bool evenOdd = false, CGraphicsTransform* transformation = nullptr) = 0; | |||
//@} | |||
virtual void beginDraw () {} | |||
virtual void endDraw () {} | |||
const CRect& getSurfaceRect () const { return surfaceRect; } | |||
protected: | |||
CDrawContext () = delete; | |||
explicit CDrawContext (const CRect& surfaceRect); | |||
~CDrawContext () noexcept override; | |||
virtual void init (); | |||
void pushTransform (const CGraphicsTransform& transformation); | |||
void popTransform (); | |||
const UTF8String& getDrawString (UTF8StringPtr string); | |||
void clearDrawString (); | |||
/// @cond ignore | |||
struct CDrawContextState | |||
{ | |||
SharedPointer<CFontDesc> font; | |||
CColor frameColor {kTransparentCColor}; | |||
CColor fillColor {kTransparentCColor}; | |||
CColor fontColor {kTransparentCColor}; | |||
CCoord frameWidth {0.}; | |||
CPoint penLoc {}; | |||
CRect clipRect {}; | |||
CLineStyle lineStyle {kLineOnOffDash}; | |||
CDrawMode drawMode {kAntiAliasing}; | |||
float globalAlpha {1.f}; | |||
BitmapInterpolationQuality bitmapQuality {BitmapInterpolationQuality::kDefault}; | |||
CDrawContextState () = default; | |||
CDrawContextState (const CDrawContextState& state); | |||
CDrawContextState& operator= (const CDrawContextState& state) = default; | |||
CDrawContextState (CDrawContextState&& state) noexcept; | |||
CDrawContextState& operator= (CDrawContextState&& state) noexcept; | |||
}; | |||
/// @endcond | |||
const CDrawContextState& getCurrentState () const { return currentState; } | |||
CDrawContextState& getCurrentState () { return currentState; } | |||
private: | |||
UTF8String* drawStringHelper {nullptr}; | |||
CRect surfaceRect; | |||
CDrawContextState currentState; | |||
std::stack<CDrawContextState> globalStatesStack; | |||
std::stack<CGraphicsTransform> transformStack; | |||
}; | |||
//----------------------------------------------------------------------------- | |||
struct ConcatClip | |||
{ | |||
ConcatClip (CDrawContext& context, CRect rect) | |||
: context (context) | |||
{ | |||
context.getClipRect (origClip); | |||
rect.normalize (); | |||
rect.bound (origClip); | |||
context.setClipRect (rect); | |||
} | |||
~ConcatClip () noexcept | |||
{ | |||
context.setClipRect (origClip); | |||
} | |||
private: | |||
CDrawContext& context; | |||
CRect origClip; | |||
}; | |||
} // VSTGUI |
@@ -0,0 +1,68 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "vstguifwd.h" | |||
namespace VSTGUI { | |||
//----------- | |||
// @brief Draw Mode Flags | |||
//----------- | |||
enum CDrawModeFlags : uint32_t | |||
{ | |||
/** aliased drawing */ | |||
kAliasing = 0, | |||
/** antialised drawing */ | |||
kAntiAliasing = 1, | |||
/** do not round coordinates to pixel aligned values */ | |||
kNonIntegralMode = 0xF0000000 | |||
}; | |||
//----------- | |||
// @brief Draw Mode | |||
//----------- | |||
struct CDrawMode | |||
{ | |||
public: | |||
constexpr CDrawMode (uint32_t mode = kAliasing) : mode (mode) {} | |||
constexpr CDrawMode (const CDrawMode& m) : mode (m.mode) {} | |||
constexpr uint32_t modeIgnoringIntegralMode () const { return (mode & ~kNonIntegralMode); } | |||
constexpr bool integralMode () const { return !hasBit (mode, kNonIntegralMode); } | |||
constexpr bool aliasing () const { return modeIgnoringIntegralMode () == kAliasing; } | |||
constexpr bool antiAliasing () const { return modeIgnoringIntegralMode () == kAntiAliasing; } | |||
CDrawMode& operator= (uint32_t m) { mode = m; return *this; } | |||
constexpr uint32_t operator() () const { return mode; } | |||
constexpr bool operator== (const CDrawMode& m) const { return modeIgnoringIntegralMode () == m.modeIgnoringIntegralMode (); } | |||
constexpr bool operator!= (const CDrawMode& m) const { return modeIgnoringIntegralMode () != m.modeIgnoringIntegralMode (); } | |||
private: | |||
uint32_t mode; | |||
}; | |||
//---------------------------- | |||
// @brief Text Alignment (Horizontal) | |||
//---------------------------- | |||
enum CHoriTxtAlign | |||
{ | |||
kLeftText = 0, | |||
kCenterText, | |||
kRightText | |||
}; | |||
//---------------------------- | |||
// @brief Draw Style | |||
//---------------------------- | |||
enum CDrawStyle | |||
{ | |||
kDrawStroked = 0, | |||
kDrawFilled, | |||
kDrawFilledAndStroked | |||
}; | |||
} // VSTGUI |
@@ -0,0 +1,144 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#include "cdrawmethods.h" | |||
#include "cbitmap.h" | |||
#include "cstring.h" | |||
#include "cdrawcontext.h" | |||
#include "platform/iplatformfont.h" | |||
namespace VSTGUI { | |||
namespace CDrawMethods { | |||
//------------------------------------------------------------------------ | |||
UTF8String createTruncatedText (TextTruncateMode mode, const UTF8String& text, CFontRef font, CCoord maxWidth, const CPoint& textInset, uint32_t flags) | |||
{ | |||
if (mode == kTextTruncateNone) | |||
return text; | |||
auto painter = font->getPlatformFont () ? font->getPlatformFont ()->getPainter () : nullptr; | |||
if (!painter) | |||
return text; | |||
CCoord width = painter->getStringWidth (nullptr, text.getPlatformString (), true); | |||
width += textInset.x * 2; | |||
if (width > maxWidth) | |||
{ | |||
std::string truncatedText; | |||
UTF8String result; | |||
auto left = text.begin (); | |||
auto right = text.end (); | |||
while (width > maxWidth && left != right) | |||
{ | |||
if (mode == kTextTruncateHead) | |||
{ | |||
++left; | |||
truncatedText = ".."; | |||
} | |||
else if (mode == kTextTruncateTail) | |||
{ | |||
--right; | |||
truncatedText = ""; | |||
} | |||
truncatedText += {left.base (), right.base ()}; | |||
if (mode == kTextTruncateTail) | |||
truncatedText += ".."; | |||
result = truncatedText; | |||
width = painter->getStringWidth (nullptr, result.getPlatformString (), true); | |||
width += textInset.x * 2; | |||
} | |||
if (left == right && flags & kReturnEmptyIfTruncationIsPlaceholderOnly) | |||
result = ""; | |||
return result; | |||
} | |||
return text; | |||
} | |||
//------------------------------------------------------------------------ | |||
void drawIconAndText (CDrawContext* context, CBitmap* iconToDraw, IconPosition iconPosition, CHoriTxtAlign textAlignment, CCoord textIconMargin, CRect drawRect, const UTF8String& title, CFontRef font, CColor textColor, TextTruncateMode textTruncateMode) | |||
{ | |||
if (iconToDraw) | |||
{ | |||
CRect iconRect (0, 0, iconToDraw->getWidth (), iconToDraw->getHeight ()); | |||
iconRect.offset (drawRect.left, drawRect.top); | |||
switch (iconPosition) | |||
{ | |||
case kIconLeft: | |||
{ | |||
iconRect.offset (textIconMargin, drawRect.getHeight () / 2. - iconRect.getHeight () / 2.); | |||
drawRect.left = iconRect.right; | |||
drawRect.right -= textIconMargin; | |||
if (textAlignment == kLeftText) | |||
drawRect.left += textIconMargin; | |||
break; | |||
} | |||
case kIconRight: | |||
{ | |||
iconRect.offset (drawRect.getWidth () - (textIconMargin + iconRect.getWidth ()), drawRect.getHeight () / 2. - iconRect.getHeight () / 2.); | |||
drawRect.right = iconRect.left; | |||
drawRect.left += textIconMargin; | |||
if (textAlignment == kRightText) | |||
drawRect.right -= textIconMargin; | |||
break; | |||
} | |||
case kIconCenterAbove: | |||
{ | |||
iconRect.offset (drawRect.getWidth () / 2. - iconRect.getWidth () / 2., 0); | |||
if (title.empty ()) | |||
iconRect.offset (0, drawRect.getHeight () / 2. - iconRect.getHeight () / 2.); | |||
else | |||
{ | |||
iconRect.offset (0, drawRect.getHeight () / 2. - (iconRect.getHeight () / 2. + (textIconMargin + font->getSize ()) / 2.)); | |||
drawRect.top = iconRect.bottom + textIconMargin; | |||
drawRect.setHeight (font->getSize ()); | |||
if (textAlignment == kLeftText) | |||
drawRect.left += textIconMargin; | |||
else if (textAlignment == kRightText) | |||
drawRect.right -= textIconMargin; | |||
} | |||
break; | |||
} | |||
case kIconCenterBelow: | |||
{ | |||
iconRect.offset (drawRect.getWidth () / 2. - iconRect.getWidth () / 2., 0); | |||
if (title.empty ()) | |||
iconRect.offset (0, drawRect.getHeight () / 2. - iconRect.getHeight () / 2.); | |||
else | |||
{ | |||
iconRect.offset (0, drawRect.getHeight () / 2. - (iconRect.getHeight () / 2.) + (textIconMargin + font->getSize ()) / 2.); | |||
drawRect.top = iconRect.top - (textIconMargin + font->getSize ()); | |||
drawRect.setHeight (font->getSize ()); | |||
if (textAlignment == kLeftText) | |||
drawRect.left += textIconMargin; | |||
else if (textAlignment == kRightText) | |||
drawRect.right -= textIconMargin; | |||
} | |||
break; | |||
} | |||
} | |||
context->drawBitmap (iconToDraw, iconRect); | |||
} | |||
else | |||
{ | |||
if (textAlignment == kLeftText) | |||
drawRect.left += textIconMargin; | |||
else if (textAlignment == kRightText) | |||
drawRect.right -= textIconMargin; | |||
} | |||
if (!title.empty ()) | |||
{ | |||
context->setFont (font); | |||
context->setFontColor (textColor); | |||
if (textTruncateMode != kTextTruncateNone) | |||
{ | |||
UTF8String truncatedText = createTruncatedText (textTruncateMode, title, font, drawRect.getWidth (), CPoint (0, 0), kReturnEmptyIfTruncationIsPlaceholderOnly); | |||
context->drawString (truncatedText.getPlatformString (), drawRect, textAlignment); | |||
} | |||
else | |||
context->drawString (title.getPlatformString (), drawRect, textAlignment); | |||
} | |||
} | |||
}} // namespaces |
@@ -0,0 +1,70 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "vstguifwd.h" | |||
#include "cdrawdefs.h" | |||
#include "cfont.h" | |||
#include "cpoint.h" | |||
namespace VSTGUI { | |||
namespace CDrawMethods { | |||
//----------------------------------------------------------------------------- | |||
enum IconPosition { | |||
/** icon left, text centered in the area next to the icon*/ | |||
kIconLeft, | |||
/** icon centered above the text, text centered */ | |||
kIconCenterAbove, | |||
/** icon centered below the text, text centered */ | |||
kIconCenterBelow, | |||
/** icon right, text centered in the area next to the icon */ | |||
kIconRight | |||
}; | |||
//----------------------------------------------------------------------------- | |||
enum TextTruncateMode { | |||
kTextTruncateNone, | |||
kTextTruncateHead, | |||
kTextTruncateTail | |||
}; | |||
//----------------------------------------------------------------------------- | |||
enum CreateTextTruncateFlags { | |||
/** return an empty string if the truncated text is only the placeholder string */ | |||
kReturnEmptyIfTruncationIsPlaceholderOnly = 1 << 0, | |||
}; | |||
//----------------------------------------------------------------------------- | |||
/** create a truncated string | |||
* | |||
* @param mode truncation mode | |||
* @param text text string | |||
* @param font font | |||
* @param maxWidth maximum width | |||
* @param textInset text inset | |||
* @param flags flags see CreateTextTruncateFlags | |||
* @return truncated text or original text if no truncation needed | |||
*/ | |||
UTF8String createTruncatedText (TextTruncateMode mode, const UTF8String& text, CFontRef font, CCoord maxWidth, const CPoint& textInset = CPoint (0, 0), uint32_t flags = 0); | |||
//----------------------------------------------------------------------------- | |||
/** draws an icon and a string into a rectangle | |||
* | |||
* @param context draw context | |||
* @param iconToDraw icon to draw | |||
* @param iconPosition position of the icon | |||
* @param textAlignment alignment of the string | |||
* @param textIconMargin margin of the string | |||
* @param drawRect draw rectangle | |||
* @param title string | |||
* @param font font | |||
* @param textColor font color | |||
* @param truncateMode trunaction mode | |||
*/ | |||
void drawIconAndText (CDrawContext* context, CBitmap* iconToDraw, IconPosition iconPosition, CHoriTxtAlign textAlignment, CCoord textIconMargin, CRect drawRect, const UTF8String& title, CFontRef font, CColor textColor, TextTruncateMode truncateMode = kTextTruncateNone); | |||
} // CDrawMethods | |||
} // VSTGUI |
@@ -0,0 +1,89 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#include "cdropsource.h" | |||
namespace VSTGUI { | |||
//----------------------------------------------------------------------------- | |||
CDropSource::CDropEntry::CDropEntry (const void* inBuffer, uint32_t inBufferSize, Type inType) | |||
: type (inType) | |||
{ | |||
buffer.allocate (inBufferSize); | |||
if (buffer.get ()) | |||
memcpy (buffer.get (), inBuffer, buffer.size ()); | |||
} | |||
//----------------------------------------------------------------------------- | |||
CDropSource::CDropEntry::CDropEntry (const CDropEntry& entry) | |||
: type (entry.type) | |||
{ | |||
buffer.allocate (entry.buffer.size ()); | |||
if (buffer.get ()) | |||
memcpy (buffer.get (), entry.buffer.get (), buffer.size ()); | |||
} | |||
//----------------------------------------------------------------------------- | |||
CDropSource::CDropEntry::CDropEntry (CDropEntry&& entry) noexcept | |||
{ | |||
buffer = std::move (entry.buffer); | |||
type = entry.type; | |||
entry.type = kError; | |||
} | |||
//----------------------------------------------------------------------------- | |||
CDropSource::CDropSource () | |||
{ | |||
} | |||
//----------------------------------------------------------------------------- | |||
CDropSource::CDropSource (const void* buffer, uint32_t bufferSize, Type type) | |||
{ | |||
add (buffer, bufferSize, type); | |||
} | |||
//----------------------------------------------------------------------------- | |||
bool CDropSource::add (const void* buffer, uint32_t bufferSize, Type type) | |||
{ | |||
if (entries.size () == entries.max_size ()) | |||
return false; | |||
entries.emplace_back (buffer, bufferSize, type); | |||
return true; | |||
} | |||
//----------------------------------------------------------------------------- | |||
uint32_t CDropSource::getCount () const | |||
{ | |||
return static_cast<uint32_t> (entries.size ()); | |||
} | |||
//----------------------------------------------------------------------------- | |||
uint32_t CDropSource::getDataSize (uint32_t index) const | |||
{ | |||
return index < getCount () ? static_cast<uint32_t> (entries[index].buffer.size ()) : 0; | |||
} | |||
//----------------------------------------------------------------------------- | |||
CDropSource::Type CDropSource::getDataType (uint32_t index) const | |||
{ | |||
return index < getCount () ? entries[index].type : kError; | |||
} | |||
//----------------------------------------------------------------------------- | |||
uint32_t CDropSource::getData (uint32_t index, const void*& buffer, Type& type) const | |||
{ | |||
if (index >= getCount ()) | |||
return 0; | |||
buffer = entries[index].buffer.get (); | |||
type = entries[index].type; | |||
return static_cast<uint32_t> (entries[index].buffer.size ()); | |||
} | |||
//----------------------------------------------------------------------------- | |||
SharedPointer<IDataPackage> CDropSource::create (const void* buffer, uint32_t bufferSize, Type type) | |||
{ | |||
return makeOwned<CDropSource> (buffer, bufferSize, type); | |||
} | |||
} // VSTGUI |
@@ -0,0 +1,50 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "vstguibase.h" | |||
#include "idatapackage.h" | |||
#include "malloc.h" | |||
#include <vector> | |||
namespace VSTGUI { | |||
//----------------------------------------------------------------------------- | |||
// CDropSource Declaration | |||
//! @brief drop source | |||
//! | |||
//! @ingroup new_in_4_0 | |||
//----------------------------------------------------------------------------- | |||
class CDropSource : public IDataPackage | |||
{ | |||
public: | |||
static SharedPointer<IDataPackage> create (const void* buffer, uint32_t bufferSize, Type type); | |||
CDropSource (); | |||
CDropSource (const void* buffer, uint32_t bufferSize, Type type); | |||
bool add (const void* buffer, uint32_t bufferSize, Type type); | |||
// IDataPackage | |||
uint32_t getCount () const final; | |||
uint32_t getDataSize (uint32_t index) const final; | |||
Type getDataType (uint32_t index) const final; | |||
uint32_t getData (uint32_t index, const void*& buffer, Type& type) const final; | |||
protected: | |||
/// @cond ignore | |||
struct CDropEntry { | |||
Buffer<int8_t> buffer; | |||
Type type; | |||
CDropEntry (const void* buffer, uint32_t bufferSize, Type type); | |||
CDropEntry (const CDropEntry& entry); | |||
CDropEntry (CDropEntry&& entry) noexcept; | |||
}; | |||
/// @endcond | |||
using DropEntryVector = std::vector<CDropEntry>; | |||
DropEntryVector entries; | |||
}; | |||
} // VSTGUI |
@@ -0,0 +1,242 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#include "cfileselector.h" | |||
#include "cframe.h" | |||
#include "cstring.h" | |||
#include <algorithm> | |||
namespace VSTGUI { | |||
//----------------------------------------------------------------------------- | |||
CFileExtension::CFileExtension (const UTF8String& inDescription, const UTF8String& inExtension, const UTF8String& inMimeType, int32_t inMacType, const UTF8String& inUti) | |||
: macType (inMacType) | |||
{ | |||
init (inDescription, inExtension, inMimeType, inUti); | |||
} | |||
//----------------------------------------------------------------------------- | |||
CFileExtension::CFileExtension (const CFileExtension& ext) | |||
: macType (ext.macType) | |||
{ | |||
init (ext.description, ext.extension, ext.mimeType, ext.uti); | |||
} | |||
//----------------------------------------------------------------------------- | |||
CFileExtension::~CFileExtension () noexcept = default; | |||
//----------------------------------------------------------------------------- | |||
CFileExtension::CFileExtension (CFileExtension&& ext) noexcept | |||
{ | |||
*this = std::move (ext); | |||
} | |||
//----------------------------------------------------------------------------- | |||
CFileExtension& CFileExtension::operator=(CFileExtension&& ext) noexcept | |||
{ | |||
description = std::move (ext.description); | |||
extension = std::move (ext.extension); | |||
mimeType = std::move (ext.mimeType); | |||
uti = std::move (ext.uti); | |||
macType = ext.macType; | |||
ext.macType = 0; | |||
return *this; | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CFileExtension::init (const UTF8String& inDescription, const UTF8String& inExtension, const UTF8String& inMimeType, const UTF8String& inUti) | |||
{ | |||
description = inDescription; | |||
extension = inExtension; | |||
mimeType = inMimeType; | |||
uti = inUti; | |||
if (description == nullptr && !extension.empty ()) | |||
{ | |||
// TODO: query system for file type description | |||
// Win32: AssocGetPerceivedType | |||
// Mac: Uniform Type Identifier | |||
} | |||
} | |||
//----------------------------------------------------------------------------- | |||
bool CFileExtension::operator== (const CFileExtension& ext) const | |||
{ | |||
bool result = false; | |||
result = extension == ext.extension; | |||
if (!result) | |||
result = mimeType == ext.mimeType; | |||
if (!result) | |||
result = uti == ext.uti; | |||
if (!result && macType != 0 && ext.macType != 0) | |||
result = (macType == ext.macType); | |||
return result; | |||
} | |||
//----------------------------------------------------------------------------- | |||
const CFileExtension& CNewFileSelector::getAllFilesExtension () | |||
{ | |||
static CFileExtension allFilesExtension ("All Files", ""); | |||
return allFilesExtension; | |||
} | |||
//----------------------------------------------------------------------------- | |||
IdStringPtr CNewFileSelector::kSelectEndMessage = "CNewFileSelector Select End Message"; | |||
//----------------------------------------------------------------------------- | |||
// CNewFileSelector Implementation | |||
//----------------------------------------------------------------------------- | |||
CNewFileSelector::CNewFileSelector (CFrame* frame) | |||
: frame (frame) | |||
, title (nullptr) | |||
, initialPath (nullptr) | |||
, defaultSaveName (nullptr) | |||
, defaultExtension (nullptr) | |||
, allowMultiFileSelection (false) | |||
{ | |||
} | |||
//----------------------------------------------------------------------------- | |||
CNewFileSelector::~CNewFileSelector () noexcept = default; | |||
//----------------------------------------------------------------------------- | |||
bool CNewFileSelector::run (CBaseObject* delegate) | |||
{ | |||
if (delegate == nullptr) | |||
{ | |||
#if DEBUG | |||
DebugPrint ("You need to specify a delegate in CNewFileSelector::run (CBaseObject* delegate, void* parentWindow)\n"); | |||
#endif | |||
return false; | |||
} | |||
if (frame) | |||
frame->onStartLocalEventLoop (); | |||
return runInternal (delegate); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CNewFileSelector::cancel () | |||
{ | |||
cancelInternal (); | |||
} | |||
//----------------------------------------------------------------------------- | |||
bool CNewFileSelector::runModal () | |||
{ | |||
if (frame) | |||
frame->onStartLocalEventLoop (); | |||
return runModalInternal (); | |||
} | |||
//----------------------------------------------------------------------------- | |||
class CNewFileSelectorCallback : public CBaseObject | |||
{ | |||
public: | |||
CNewFileSelectorCallback (CNewFileSelector::CallbackFunc&& callback) : callbackFunc (std::move (callback)) {} | |||
~CNewFileSelectorCallback () noexcept override = default; | |||
private: | |||
CMessageResult notify (CBaseObject* sender, IdStringPtr message) override | |||
{ | |||
if (message == CNewFileSelector::kSelectEndMessage) | |||
{ | |||
callbackFunc (dynamic_cast<CNewFileSelector*> (sender)); | |||
return kMessageNotified; | |||
} | |||
return kMessageUnknown; | |||
} | |||
CNewFileSelector::CallbackFunc callbackFunc; | |||
}; | |||
//----------------------------------------------------------------------------- | |||
bool CNewFileSelector::run (CallbackFunc&& callback) | |||
{ | |||
if (frame) | |||
frame->onStartLocalEventLoop (); | |||
auto fsCallback = makeOwned<CNewFileSelectorCallback> (std::move (callback)); | |||
return runInternal (fsCallback); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CNewFileSelector::setTitle (const UTF8String& inTitle) | |||
{ | |||
title = inTitle; | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CNewFileSelector::setInitialDirectory (const UTF8String& path) | |||
{ | |||
initialPath = path; | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CNewFileSelector::setDefaultSaveName (const UTF8String& name) | |||
{ | |||
defaultSaveName = name; | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CNewFileSelector::setAllowMultiFileSelection (bool state) | |||
{ | |||
allowMultiFileSelection = state; | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CNewFileSelector::setDefaultExtension (const CFileExtension& extension) | |||
{ | |||
if (defaultExtension) | |||
{ | |||
#if DEBUG | |||
DebugPrint ("VSTGUI Warning: It's not allowed to set a default extension twice on a CFileSelector instance\n"); | |||
#endif | |||
return; | |||
} | |||
bool found = false; | |||
FileExtensionList::const_iterator it = extensions.begin (); | |||
while (it != extensions.end ()) | |||
{ | |||
if ((*it) == extension) | |||
{ | |||
defaultExtension = &(*it); | |||
found = true; | |||
break; | |||
} | |||
++it; | |||
} | |||
if (!found) | |||
{ | |||
addFileExtension (extension); | |||
setDefaultExtension (extension); | |||
} | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CNewFileSelector::addFileExtension (const CFileExtension& extension) | |||
{ | |||
extensions.emplace_back (extension); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CNewFileSelector::addFileExtension (CFileExtension&& extension) | |||
{ | |||
extensions.emplace_back (std::move (extension)); | |||
} | |||
//----------------------------------------------------------------------------- | |||
uint32_t CNewFileSelector::getNumSelectedFiles () const | |||
{ | |||
return static_cast<uint32_t> (result.size ()); | |||
} | |||
//----------------------------------------------------------------------------- | |||
UTF8StringPtr CNewFileSelector::getSelectedFile (uint32_t index) const | |||
{ | |||
if (index < result.size ()) | |||
return result[index]; | |||
return nullptr; | |||
} | |||
} // VSTGUI | |||
@@ -0,0 +1,169 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "vstguifwd.h" | |||
#include "cstring.h" | |||
#include <list> | |||
#include <vector> | |||
#include <functional> | |||
namespace VSTGUI { | |||
//----------------------------------------------------------------------------- | |||
// CFileExtension Declaration | |||
//! @brief file extension description | |||
//----------------------------------------------------------------------------- | |||
class CFileExtension | |||
{ | |||
public: | |||
CFileExtension (const UTF8String& description, const UTF8String& extension, const UTF8String& mimeType = "", int32_t macType = 0, const UTF8String& uti = ""); | |||
CFileExtension (const CFileExtension& ext); | |||
~CFileExtension () noexcept; | |||
const UTF8String& getDescription () const { return description; } | |||
const UTF8String& getExtension () const { return extension; } | |||
const UTF8String& getMimeType () const { return mimeType; } | |||
const UTF8String& getUTI () const { return uti; } | |||
int32_t getMacType () const { return macType; } | |||
bool operator== (const CFileExtension& ext) const; | |||
//----------------------------------------------------------------------------- | |||
CFileExtension (CFileExtension&& ext) noexcept; | |||
CFileExtension& operator=(CFileExtension&& ext) noexcept; | |||
protected: | |||
void init (const UTF8String& description, const UTF8String& extension, const UTF8String& mimeType, const UTF8String& uti); | |||
UTF8String description; | |||
UTF8String extension; | |||
UTF8String mimeType; | |||
UTF8String uti; | |||
int32_t macType; | |||
}; | |||
//----------------------------------------------------------------------------- | |||
// CNewFileSelector Declaration | |||
//! @brief New file selector class | |||
/*! @class CNewFileSelector | |||
@section usage Usage | |||
Running the file selector | |||
@code | |||
void MyClass::runFileSelector () | |||
{ | |||
CNewFileSelector* selector = CNewFileSelector::create (getFrame (), CNewFileSelector::kSelectFile); | |||
if (selector) | |||
{ | |||
selector->addFileExtension (CFileExtension ("AIFF", "aif", "audio/aiff")); | |||
selector->setDefaultExtension (CFileExtension ("WAVE", "wav")); | |||
selector->setTitle("Choose An Audio File"); | |||
selector->run (this); | |||
selector->forget (); | |||
} | |||
} | |||
@endcode | |||
Getting results | |||
@code | |||
CMessageResult MyClass::notify (CBaseObject* sender, IdStringPtr message) | |||
{ | |||
if (message == CNewFileSelector::kSelectEndMessage) | |||
{ | |||
CNewFileSelector* sel = dynamic_cast<CNewFileSelector*>(sender); | |||
if (sel) | |||
{ | |||
// do anything with the selected files here | |||
return kMessageNotified; | |||
} | |||
} | |||
return parent::notify (sender, message); | |||
} | |||
@endcode | |||
*/ | |||
//----------------------------------------------------------------------------- | |||
class CNewFileSelector : public CBaseObject | |||
{ | |||
public: | |||
enum Style { | |||
/** select file(s) selector style */ | |||
kSelectFile, | |||
/** select save file selector style */ | |||
kSelectSaveFile, | |||
/** select directory style */ | |||
kSelectDirectory | |||
}; | |||
//----------------------------------------------------------------------------- | |||
/// @name CFileSelector running | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
/** create a new instance */ | |||
static CNewFileSelector* create (CFrame* parent = nullptr, Style style = kSelectFile); | |||
using CallbackFunc = std::function<void(CNewFileSelector*)>; | |||
bool run (CallbackFunc&& callback); | |||
/** the delegate will get a kSelectEndMessage throu the notify method where the sender is this CNewFileSelector object */ | |||
bool run (CBaseObject* delegate); | |||
/** cancel running the file selector */ | |||
void cancel (); | |||
/** run as modal dialog */ | |||
bool runModal (); | |||
//@} | |||
//----------------------------------------------------------------------------- | |||
/// @name CFileSelector setup | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
/** set title of file selector */ | |||
void setTitle (const UTF8String& title); | |||
/** set initial directory (UTF8 string) */ | |||
void setInitialDirectory (const UTF8String& path); | |||
/** set initial save name (UTF8 string) */ | |||
void setDefaultSaveName (const UTF8String& name); | |||
/** set default file extension */ | |||
void setDefaultExtension (const CFileExtension& extension); | |||
/** set allow multi file selection (only valid for kSelectFile selector style) */ | |||
void setAllowMultiFileSelection (bool state); | |||
/** add a file extension */ | |||
void addFileExtension (const CFileExtension& extension); | |||
/** add a file extension */ | |||
void addFileExtension (CFileExtension&& extension); | |||
//@} | |||
//----------------------------------------------------------------------------- | |||
/// @name CFileSelector result | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
/** get number of selected files */ | |||
uint32_t getNumSelectedFiles () const; | |||
/** get selected file. Result is only valid as long as the instance of CNewFileSelector is valid. */ | |||
UTF8StringPtr getSelectedFile (uint32_t index) const; | |||
//@} | |||
/** get the all files extension */ | |||
static const CFileExtension& getAllFilesExtension (); | |||
static IdStringPtr kSelectEndMessage; | |||
//----------------------------------------------------------------------------- | |||
CLASS_METHODS_NOCOPY(CNewFileSelector, CBaseObject) | |||
protected: | |||
explicit CNewFileSelector (CFrame* frame = nullptr); | |||
~CNewFileSelector () noexcept override; | |||
virtual bool runInternal (CBaseObject* delegate) = 0; | |||
virtual void cancelInternal () = 0; | |||
virtual bool runModalInternal () = 0; | |||
CFrame* frame; | |||
UTF8String title; | |||
UTF8String initialPath; | |||
UTF8String defaultSaveName; | |||
const CFileExtension* defaultExtension; | |||
bool allowMultiFileSelection; | |||
using FileExtensionList = std::list<CFileExtension>; | |||
FileExtensionList extensions; | |||
std::vector<UTF8String> result; | |||
}; | |||
} // VSTGUI |
@@ -0,0 +1,177 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#include "cfont.h" | |||
#include "cstring.h" | |||
#include "platform/iplatformfont.h" | |||
namespace VSTGUI { | |||
//----------------------------------------------------------------------------- | |||
// Global Fonts | |||
//----------------------------------------------------------------------------- | |||
#if MAC | |||
#if TARGET_OS_IPHONE | |||
static CFontDesc gSystemFont ("Helvetica", 12); | |||
static CFontDesc gNormalFontVeryBig ("ArialMT", 18); | |||
static CFontDesc gNormalFontBig ("ArialMT", 14); | |||
static CFontDesc gNormalFont ("ArialMT", 12); | |||
static CFontDesc gNormalFontSmall ("ArialMT", 11); | |||
static CFontDesc gNormalFontSmaller ("ArialMT", 10); | |||
static CFontDesc gNormalFontVerySmall ("ArialMT", 9); | |||
static CFontDesc gSymbolFont ("Symbol", 12); | |||
#else | |||
static CFontDesc gSystemFont ("Lucida Grande", 12); | |||
static CFontDesc gNormalFontVeryBig ("Arial", 18); | |||
static CFontDesc gNormalFontBig ("Arial", 14); | |||
static CFontDesc gNormalFont ("Arial", 12); | |||
static CFontDesc gNormalFontSmall ("Arial", 11); | |||
static CFontDesc gNormalFontSmaller ("Arial", 10); | |||
static CFontDesc gNormalFontVerySmall ("Arial", 9); | |||
static CFontDesc gSymbolFont ("Symbol", 12); | |||
#endif | |||
#elif WINDOWS | |||
static CFontDesc gSystemFont ("Arial", 12); | |||
static CFontDesc gNormalFontVeryBig ("Arial", 18); | |||
static CFontDesc gNormalFontBig ("Arial", 14); | |||
static CFontDesc gNormalFont ("Arial", 12); | |||
static CFontDesc gNormalFontSmall ("Arial", 11); | |||
static CFontDesc gNormalFontSmaller ("Arial", 10); | |||
static CFontDesc gNormalFontVerySmall ("Arial", 9); | |||
static CFontDesc gSymbolFont ("Symbol", 13); | |||
#else | |||
static CFontDesc gSystemFont ("Arial", 12); | |||
static CFontDesc gNormalFontVeryBig ("Arial", 18); | |||
static CFontDesc gNormalFontBig ("Arial", 14); | |||
static CFontDesc gNormalFont ("Arial", 12); | |||
static CFontDesc gNormalFontSmall ("Arial", 11); | |||
static CFontDesc gNormalFontSmaller ("Arial", 10); | |||
static CFontDesc gNormalFontVerySmall ("Arial", 9); | |||
static CFontDesc gSymbolFont ("Symbol", 13); | |||
#endif | |||
const CFontRef kSystemFont = &gSystemFont; | |||
const CFontRef kNormalFontVeryBig = &gNormalFontVeryBig; | |||
const CFontRef kNormalFontBig = &gNormalFontBig; | |||
const CFontRef kNormalFont = &gNormalFont; | |||
const CFontRef kNormalFontSmall = &gNormalFontSmall; | |||
const CFontRef kNormalFontSmaller = &gNormalFontSmaller; | |||
const CFontRef kNormalFontVerySmall = &gNormalFontVerySmall; | |||
const CFontRef kSymbolFont = &gSymbolFont; | |||
//----------------------------------------------------------------------------- | |||
// CFontDesc Implementation | |||
/*! @class CFontDesc | |||
The CFontDesc class replaces the old font handling. You have now the possibilty to use whatever font you like | |||
as long as it is available on the system. You should cache your own CFontDesc as this speeds up drawing on some systems. | |||
*/ | |||
//----------------------------------------------------------------------------- | |||
CFontDesc::CFontDesc (const UTF8String& inName, const CCoord& inSize, const int32_t inStyle) | |||
: size (inSize) | |||
, style (inStyle) | |||
, platformFont (nullptr) | |||
{ | |||
setName (inName); | |||
} | |||
//----------------------------------------------------------------------------- | |||
CFontDesc::CFontDesc (const CFontDesc& font) | |||
: size (0) | |||
, style (0) | |||
, platformFont (nullptr) | |||
{ | |||
*this = font; | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CFontDesc::beforeDelete () | |||
{ | |||
freePlatformFont (); | |||
} | |||
//----------------------------------------------------------------------------- | |||
auto CFontDesc::getPlatformFont () const -> const PlatformFontPtr | |||
{ | |||
if (platformFont == nullptr) | |||
platformFont = IPlatformFont::create (name, size, style); | |||
return platformFont; | |||
} | |||
//----------------------------------------------------------------------------- | |||
const IFontPainter* CFontDesc::getFontPainter () const | |||
{ | |||
IPlatformFont* pf = getPlatformFont (); | |||
if (pf) | |||
return pf->getPainter (); | |||
return nullptr; | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CFontDesc::freePlatformFont () | |||
{ | |||
platformFont = nullptr; | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CFontDesc::setName (const UTF8String& newName) | |||
{ | |||
if (name == newName) | |||
return; | |||
name = newName; | |||
freePlatformFont (); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CFontDesc::setSize (CCoord newSize) | |||
{ | |||
size = newSize; | |||
freePlatformFont (); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CFontDesc::setStyle (int32_t newStyle) | |||
{ | |||
style = newStyle; | |||
freePlatformFont (); | |||
} | |||
//----------------------------------------------------------------------------- | |||
CFontDesc& CFontDesc::operator = (const CFontDesc& f) | |||
{ | |||
setName (f.getName ()); | |||
setSize (f.getSize ()); | |||
setStyle (f.getStyle ()); | |||
return *this; | |||
} | |||
//----------------------------------------------------------------------------- | |||
bool CFontDesc::operator == (const CFontDesc& f) const | |||
{ | |||
if (size != f.getSize ()) | |||
return false; | |||
if (style != f.getStyle ()) | |||
return false; | |||
if (name != f.getName ()) | |||
return false; | |||
return true; | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CFontDesc::cleanup () | |||
{ | |||
gSystemFont.freePlatformFont (); | |||
gNormalFontVeryBig.freePlatformFont (); | |||
gNormalFontBig.freePlatformFont (); | |||
gNormalFont.freePlatformFont (); | |||
gNormalFontSmall.freePlatformFont (); | |||
gNormalFontSmaller.freePlatformFont (); | |||
gNormalFontVerySmall.freePlatformFont (); | |||
gSymbolFont.freePlatformFont (); | |||
} | |||
} // VSTGUI |
@@ -0,0 +1,91 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "vstguifwd.h" | |||
#include "cstring.h" | |||
#include <string> | |||
#include <list> | |||
namespace VSTGUI { | |||
//----------- | |||
// @brief Text Face | |||
//----------- | |||
enum CTxtFace | |||
{ | |||
kNormalFace = 0, | |||
kBoldFace = 1 << 1, | |||
kItalicFace = 1 << 2, | |||
kUnderlineFace = 1 << 3, | |||
kStrikethroughFace = 1 << 4 | |||
}; | |||
//----------------------------------------------------------------------------- | |||
// CFontDesc Declaration | |||
//! @brief font class | |||
//----------------------------------------------------------------------------- | |||
class CFontDesc : public AtomicReferenceCounted | |||
{ | |||
public: | |||
using PlatformFontPtr = SharedPointer<IPlatformFont>; | |||
CFontDesc (const UTF8String& name = "", const CCoord& size = 0, const int32_t style = 0); | |||
CFontDesc (const CFontDesc& font); | |||
~CFontDesc () noexcept override = default; | |||
//----------------------------------------------------------------------------- | |||
/// @name Size, Name and Style Methods | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
/** get the name of the font */ | |||
const UTF8String& getName () const { return name; } | |||
/** get the height of the font */ | |||
const CCoord& getSize () const { return size; } | |||
/** get the style of the font */ | |||
const int32_t& getStyle () const { return style; } | |||
/** set the name of the font */ | |||
virtual void setName (const UTF8String& newName); | |||
/** set the height of the font */ | |||
virtual void setSize (CCoord newSize); | |||
/** set the style of the font @sa CTxtFace */ | |||
virtual void setStyle (int32_t newStyle); | |||
//@} | |||
virtual const PlatformFontPtr getPlatformFont () const; | |||
virtual const IFontPainter* getFontPainter () const; | |||
virtual CFontDesc& operator= (const CFontDesc&); | |||
virtual bool operator== (const CFontDesc&) const; | |||
virtual bool operator!= (const CFontDesc& other) const { return !(*this == other);} | |||
static void cleanup (); | |||
protected: | |||
void beforeDelete () override; | |||
virtual void freePlatformFont (); | |||
UTF8String name; | |||
CCoord size; | |||
int32_t style; | |||
mutable PlatformFontPtr platformFont; | |||
}; | |||
using CFontRef = CFontDesc*; | |||
//----------------------------------------------------------------------------- | |||
// Global fonts | |||
//----------------------------------------------------------------------------- | |||
extern const CFontRef kSystemFont; | |||
extern const CFontRef kNormalFontVeryBig; | |||
extern const CFontRef kNormalFontBig; | |||
extern const CFontRef kNormalFont; | |||
extern const CFontRef kNormalFontSmall; | |||
extern const CFontRef kNormalFontSmaller; | |||
extern const CFontRef kNormalFontVerySmall; | |||
extern const CFontRef kSymbolFont; | |||
} // VSTGUI |
@@ -0,0 +1,345 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "vstguifwd.h" | |||
#include "cviewcontainer.h" | |||
#include "platform/iplatformframecallback.h" | |||
namespace VSTGUI { | |||
//---------------------------- | |||
// @brief Knob Mode | |||
//---------------------------- | |||
enum CKnobMode | |||
{ | |||
kCircularMode = 0, | |||
kRelativCircularMode, | |||
kLinearMode | |||
}; | |||
/** Message send to all parents of the new focus view */ | |||
extern IdStringPtr kMsgNewFocusView; | |||
/** Message send to all parents of the old focus view */ | |||
extern IdStringPtr kMsgOldFocusView; | |||
//----------------------------------------------------------------------------- | |||
// CFrame Declaration | |||
//! @brief The CFrame is the parent container of all views | |||
/// @ingroup containerviews | |||
//----------------------------------------------------------------------------- | |||
class CFrame final : public CViewContainer, public IPlatformFrameCallback | |||
{ | |||
public: | |||
CFrame (const CRect& size, VSTGUIEditorInterface* pEditor); | |||
//----------------------------------------------------------------------------- | |||
/// @name CFrame Methods | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
bool open (void* pSystemWindow, PlatformType systemWindowType = kDefaultNative, IPlatformFrameConfig* = nullptr); | |||
/** closes the frame and calls forget */ | |||
void close (); | |||
/** set zoom factor */ | |||
bool setZoom (double zoomFactor); | |||
/** get zoom factor */ | |||
double getZoom () const; | |||
void setBitmapInterpolationQuality (BitmapInterpolationQuality quality); ///< set interpolation quality for bitmaps | |||
BitmapInterpolationQuality getBitmapInterpolationQuality () const; ///< get interpolation quality for bitmaps | |||
double getScaleFactor () const; | |||
void idle (); | |||
/** get the current time (in ms) */ | |||
uint32_t getTicks () const; | |||
/** default knob mode if host does not provide one */ | |||
static int32_t kDefaultKnobMode; | |||
/** get hosts knob mode */ | |||
int32_t getKnobMode () const; | |||
bool setPosition (CCoord x, CCoord y); | |||
bool getPosition (CCoord& x, CCoord& y) const; | |||
bool setSize (CCoord width, CCoord height); | |||
bool getSize (CRect* pSize) const; | |||
bool getSize (CRect& pSize) const; | |||
VSTGUI_DEPRECATED (bool setModalView (CView* pView);) | |||
CView* getModalView () const; | |||
ModalViewSession* beginModalViewSession (CView* view); | |||
bool endModalViewSession (ModalViewSession* session); | |||
void beginEdit (int32_t index); | |||
void endEdit (int32_t index); | |||
/** get current mouse location */ | |||
bool getCurrentMouseLocation (CPoint& where) const; | |||
/** get current mouse buttons and key modifiers */ | |||
CButtonState getCurrentMouseButtons () const; | |||
/** set mouse cursor */ | |||
void setCursor (CCursorType type); | |||
void setFocusView (CView* pView); | |||
CView* getFocusView () const; | |||
bool advanceNextFocusView (CView* oldFocus, bool reverse = false) override; | |||
void onViewAdded (CView* pView); | |||
void onViewRemoved (CView* pView); | |||
/** called when the platform view/window is activated/deactivated */ | |||
void onActivate (bool state); | |||
void invalidate (const CRect& rect); | |||
/** scroll src rect by distance */ | |||
void scrollRect (const CRect& src, const CPoint& distance); | |||
/** enable or disable tooltips */ | |||
void enableTooltips (bool state, uint32_t delayTimeInMs = 1000); | |||
/** get animator for this frame */ | |||
Animation::Animator* getAnimator (); | |||
/** get the clipboard data. data is owned by the caller */ | |||
SharedPointer<IDataPackage> getClipboard (); | |||
/** set the clipboard data. */ | |||
void setClipboard (const SharedPointer<IDataPackage>& data); | |||
IViewAddedRemovedObserver* getViewAddedRemovedObserver () const; | |||
void setViewAddedRemovedObserver (IViewAddedRemovedObserver* observer); | |||
/** register a keyboard hook */ | |||
void registerKeyboardHook (IKeyboardHook* hook); | |||
/** unregister a keyboard hook */ | |||
void unregisterKeyboardHook (IKeyboardHook* hook); | |||
/** register a mouse observer */ | |||
void registerMouseObserver (IMouseObserver* observer); | |||
/** unregister a mouse observer */ | |||
void unregisterMouseObserver (IMouseObserver* observer); | |||
void registerScaleFactorChangedListeneer (IScaleFactorChangedListener* listener); | |||
void unregisterScaleFactorChangedListeneer (IScaleFactorChangedListener* listener); | |||
void registerFocusViewObserver (IFocusViewObserver* observer); | |||
void unregisterFocusViewObserver (IFocusViewObserver* observer); | |||
//@} | |||
//----------------------------------------------------------------------------- | |||
/// @name Focus Drawing Methods [new in 4.0] | |||
//! If focus drawing is enabled, the focus view will get a focus ring around it defined with the focus width and the focus color. | |||
//! Views can define their own shape with the IFocusDrawing interface. | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
/** enable focus drawing */ | |||
void setFocusDrawingEnabled (bool state); | |||
/** is focus drawing enabled */ | |||
bool focusDrawingEnabled () const; | |||
/** set focus draw color */ | |||
void setFocusColor (const CColor& color); | |||
/** get focus draw color */ | |||
CColor getFocusColor () const; | |||
/** set focus draw width */ | |||
void setFocusWidth (CCoord width); | |||
/** get focus draw width */ | |||
CCoord getFocusWidth () const; | |||
//@} | |||
using Function = std::function<void ()>; | |||
/** Queue a function which will be executed after the current event was handled. | |||
* Only allowed when inEventProcessing () is true | |||
* | |||
* @param func Function to execute | |||
* @return true if the function was added to the execution queue | |||
*/ | |||
bool doAfterEventProcessing (Function&& func); | |||
/** Queue a function which will be executed after the current event was handled. | |||
* Only allowed when inEventProcessing () is true | |||
* | |||
* @param func Function to execute | |||
* @return true if the function was added to the execution queue | |||
*/ | |||
bool doAfterEventProcessing (const Function& func); | |||
/** Returns true if an event is currently being processed. */ | |||
bool inEventProcessing () const; | |||
void onStartLocalEventLoop (); | |||
void invalid () override { invalidRect (getViewSize ()); setDirty (false); } | |||
void invalidRect (const CRect& rect) override; | |||
bool removeView (CView* pView, bool withForget = true) override; | |||
bool removeAll (bool withForget = true) override; | |||
CView* getViewAt (const CPoint& where, const GetViewOptions& options = GetViewOptions ()) const override; | |||
CViewContainer* getContainerAt (const CPoint& where, const GetViewOptions& options = GetViewOptions ().deep ()) const override; | |||
bool hitTestSubViews (const CPoint& where, const CButtonState& buttons = -1) override; | |||
// CView | |||
bool attached (CView* parent) override; | |||
void draw (CDrawContext* pContext) override; | |||
void drawRect (CDrawContext* pContext, const CRect& updateRect) override; | |||
CMouseEventResult onMouseDown (CPoint& where, const CButtonState& buttons) override; | |||
CMouseEventResult onMouseUp (CPoint& where, const CButtonState& buttons) override; | |||
CMouseEventResult onMouseMoved (CPoint& where, const CButtonState& buttons) override; | |||
CMouseEventResult onMouseExited (CPoint& where, const CButtonState& buttons) override; | |||
bool onWheel (const CPoint& where, const float& distance, const CButtonState& buttons) override; | |||
bool onWheel (const CPoint& where, const CMouseWheelAxis& axis, const float& distance, const CButtonState& buttons) override; | |||
int32_t onKeyDown (VstKeyCode& keyCode) override; | |||
int32_t onKeyUp (VstKeyCode& keyCode) override; | |||
void setViewSize (const CRect& rect, bool invalid = true) override; | |||
VSTGUIEditorInterface* getEditor () const override; | |||
IPlatformFrame* getPlatformFrame () const; | |||
#if DEBUG | |||
void dumpHierarchy () override; | |||
#endif | |||
CLASS_METHODS(CFrame, CViewContainer) | |||
//------------------------------------------- | |||
protected: | |||
struct CollectInvalidRects; | |||
~CFrame () noexcept override = default; | |||
void beforeDelete () override; | |||
void checkMouseViews (const CPoint& where, const CButtonState& buttons); | |||
void clearMouseViews (const CPoint& where, const CButtonState& buttons, bool callMouseExit = true); | |||
void removeFromMouseViews (CView* view); | |||
void setCollectInvalidRects (CollectInvalidRects* collectInvalidRects); | |||
// keyboard hooks | |||
int32_t keyboardHooksOnKeyDown (const VstKeyCode& key); | |||
int32_t keyboardHooksOnKeyUp (const VstKeyCode& key); | |||
// mouse observers | |||
void callMouseObserverMouseEntered (CView* view); | |||
void callMouseObserverMouseExited (CView* view); | |||
CMouseEventResult callMouseObserverMouseDown (const CPoint& where, const CButtonState& buttons); | |||
CMouseEventResult callMouseObserverMouseMoved (const CPoint& where, const CButtonState& buttons); | |||
void dispatchNewScaleFactor (double newScaleFactor); | |||
// platform frame | |||
bool platformDrawRect (CDrawContext* context, const CRect& rect) override; | |||
CMouseEventResult platformOnMouseDown (CPoint& where, const CButtonState& buttons) override; | |||
CMouseEventResult platformOnMouseMoved (CPoint& where, const CButtonState& buttons) override; | |||
CMouseEventResult platformOnMouseUp (CPoint& where, const CButtonState& buttons) override; | |||
CMouseEventResult platformOnMouseExited (CPoint& where, const CButtonState& buttons) override; | |||
bool platformOnMouseWheel (const CPoint& where, const CMouseWheelAxis& axis, const float& distance, const CButtonState& buttons) override; | |||
DragOperation platformOnDragEnter (DragEventData data) override; | |||
DragOperation platformOnDragMove (DragEventData data) override; | |||
void platformOnDragLeave (DragEventData data) override; | |||
bool platformOnDrop (DragEventData data) override; | |||
bool platformOnKeyDown (VstKeyCode& keyCode) override; | |||
bool platformOnKeyUp (VstKeyCode& keyCode) override; | |||
void platformOnActivate (bool state) override; | |||
void platformOnWindowActivate (bool state) override; | |||
void platformScaleFactorChanged (double newScaleFactor) override; | |||
#if VSTGUI_TOUCH_EVENT_HANDLING | |||
void platformOnTouchEvent (ITouchEvent& event) override; | |||
#endif | |||
private: | |||
#if VSTGUI_ENABLE_DEPRECATED_METHODS | |||
void endLegacyModalViewSession (); | |||
#endif | |||
void initModalViewSession (ModalViewSession* session); | |||
void clearModalViewSessions (); | |||
struct Impl; | |||
Impl* pImpl {nullptr}; | |||
}; | |||
//---------------------------------------------------- | |||
class VSTGUIEditorInterface | |||
{ | |||
public: | |||
virtual void doIdleStuff () {} | |||
virtual int32_t getKnobMode () const { return -1; } | |||
virtual void beginEdit (int32_t index) {} | |||
virtual void endEdit (int32_t index) {} | |||
/** frame will change size, if this returns false the upstream implementation does not allow it and thus the size of the frame will not change */ | |||
virtual bool beforeSizeChange (const CRect& newSize, const CRect& oldSize) { return true; } | |||
virtual CFrame* getFrame () const { return frame; } | |||
protected: | |||
VSTGUIEditorInterface () = default; | |||
virtual ~VSTGUIEditorInterface () noexcept = default; | |||
CFrame* frame {nullptr}; | |||
}; | |||
//----------------------------------------------------------------------------- | |||
// IMouseObserver Declaration | |||
//! @brief generic mouse observer interface for CFrame | |||
//----------------------------------------------------------------------------- | |||
class IMouseObserver | |||
{ | |||
public: | |||
virtual ~IMouseObserver() noexcept = default; | |||
virtual void onMouseEntered (CView* view, CFrame* frame) = 0; | |||
virtual void onMouseExited (CView* view, CFrame* frame) = 0; | |||
/** a mouse move event happend on the frame at position where. If the observer handles this, the event won't be propagated further */ | |||
virtual CMouseEventResult onMouseMoved (CFrame* frame, const CPoint& where, const CButtonState& buttons) { return kMouseEventNotHandled; } | |||
/** a mouse down event happend on the frame at position where. If the observer handles this, the event won't be propagated further */ | |||
virtual CMouseEventResult onMouseDown (CFrame* frame, const CPoint& where, const CButtonState& buttons) { return kMouseEventNotHandled; } | |||
}; | |||
//----------------------------------------------------------------------------- | |||
// IKeyboardHook Declaration | |||
//! @brief generic keyboard hook interface for CFrame | |||
//! @ingroup new_in_4_0 | |||
//----------------------------------------------------------------------------- | |||
class IKeyboardHook | |||
{ | |||
public: | |||
virtual ~IKeyboardHook () noexcept = default; | |||
/** should return 1 if no further key down processing should apply, otherwise -1 */ | |||
virtual int32_t onKeyDown (const VstKeyCode& code, CFrame* frame) = 0; | |||
/** should return 1 if no further key up processing should apply, otherwise -1 */ | |||
virtual int32_t onKeyUp (const VstKeyCode& code, CFrame* frame) = 0; | |||
}; | |||
//----------------------------------------------------------------------------- | |||
// IViewAddedRemovedObserver Declaration | |||
//! @brief view added removed observer interface for CFrame | |||
//! @ingroup new_in_4_0 | |||
//----------------------------------------------------------------------------- | |||
class IViewAddedRemovedObserver | |||
{ | |||
public: | |||
virtual ~IViewAddedRemovedObserver () noexcept = default; | |||
virtual void onViewAdded (CFrame* frame, CView* view) = 0; | |||
virtual void onViewRemoved (CFrame* frame, CView* view) = 0; | |||
}; | |||
//----------------------------------------------------------------------------- | |||
// IFocusViewObserver Declaration | |||
//! @brief focus view observer interface for CFrame | |||
//! @ingroup new_in_4_5 | |||
//----------------------------------------------------------------------------- | |||
class IFocusViewObserver | |||
{ | |||
public: | |||
virtual ~IFocusViewObserver () noexcept = default; | |||
virtual void onFocusViewChanged (CFrame* frame, CView* newFocusView, CView* oldFocusView) = 0; | |||
}; | |||
} // VSTGUI |
@@ -0,0 +1,65 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "vstguifwd.h" | |||
#include "ccolor.h" | |||
#include <map> | |||
#include <algorithm> | |||
namespace VSTGUI { | |||
//----------------------------------------------------------------------------- | |||
/// @brief Gradient Object [new in 4.0] | |||
/// @ingroup new_in_4_0 | |||
//----------------------------------------------------------------------------- | |||
class CGradient : public AtomicReferenceCounted | |||
{ | |||
public: | |||
using ColorStopMap = std::multimap<double, CColor>; | |||
static CGradient* create (const ColorStopMap& colorStopMap); | |||
static CGradient* create (double color1Start, double color2Start, const CColor& color1, const CColor& color2) | |||
{ | |||
ColorStopMap map; | |||
map.emplace (color1Start, color1); | |||
map.emplace (color2Start, color2); | |||
return create (map); | |||
} | |||
//----------------------------------------------------------------------------- | |||
/// @name Member Access | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
void addColorStop (double start, const CColor& color) | |||
{ | |||
addColorStop (std::make_pair (start, color)); | |||
} | |||
virtual void addColorStop (const std::pair<double, CColor>& colorStop) | |||
{ | |||
colorStops.emplace (colorStop); | |||
} | |||
virtual void addColorStop (std::pair<double, CColor>&& colorStop) | |||
{ | |||
colorStops.emplace (std::move (colorStop)); | |||
} | |||
const ColorStopMap& getColorStops () const { return colorStops; } | |||
//@} | |||
protected: | |||
CGradient (double color1Start, double color2Start, const CColor& color1, const CColor& color2) | |||
{ | |||
addColorStop (color1Start, color1); | |||
addColorStop (color2Start, color2); | |||
} | |||
explicit CGradient (const ColorStopMap& colorStopMap) : colorStops (colorStopMap) {} | |||
ColorStopMap colorStops; | |||
}; | |||
} // VSTGUI |
@@ -0,0 +1,171 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#include "cgradientview.h" | |||
#include "cdrawcontext.h" | |||
#include "cgraphicspath.h" | |||
namespace VSTGUI { | |||
//----------------------------------------------------------------------------- | |||
CGradientView::CGradientView (const CRect& size) | |||
: CView (size) | |||
{ | |||
} | |||
//------------------------------------------------------------------------ | |||
void CGradientView::attributeChanged () | |||
{ | |||
invalid (); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CGradientView::setGradientStyle (GradientStyle style) | |||
{ | |||
if (gradientStyle != style) | |||
{ | |||
gradientStyle = style; | |||
attributeChanged (); | |||
} | |||
} | |||
//------------------------------------------------------------------------ | |||
void CGradientView::setGradient (CGradient* newGradient) | |||
{ | |||
if (gradient != newGradient) | |||
{ | |||
gradient = newGradient; | |||
attributeChanged (); | |||
} | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CGradientView::setFrameColor (const CColor& newColor) | |||
{ | |||
if (newColor != frameColor) | |||
{ | |||
frameColor = newColor; | |||
attributeChanged (); | |||
} | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CGradientView::setGradientAngle (double angle) | |||
{ | |||
if (angle != gradientAngle) | |||
{ | |||
gradientAngle = angle; | |||
attributeChanged (); | |||
} | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CGradientView::setRoundRectRadius (CCoord radius) | |||
{ | |||
if (radius != roundRectRadius) | |||
{ | |||
roundRectRadius = radius; | |||
path = nullptr; | |||
attributeChanged (); | |||
} | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CGradientView::setFrameWidth (CCoord width) | |||
{ | |||
if (width != frameWidth) | |||
{ | |||
frameWidth = width; | |||
path = nullptr; | |||
attributeChanged (); | |||
} | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CGradientView::setDrawAntialiased (bool state) | |||
{ | |||
if (state != drawAntialiased) | |||
{ | |||
drawAntialiased = state; | |||
attributeChanged (); | |||
} | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CGradientView::setRadialCenter (const CPoint& center) | |||
{ | |||
if (radialCenter != center) | |||
{ | |||
radialCenter = center; | |||
attributeChanged (); | |||
} | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CGradientView::setRadialRadius (CCoord radius) | |||
{ | |||
if (radialRadius != radius) | |||
{ | |||
radialRadius = radius; | |||
attributeChanged (); | |||
} | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CGradientView::setViewSize (const CRect& rect, bool invalid) | |||
{ | |||
if (rect != getViewSize ()) | |||
{ | |||
CView::setViewSize (rect, invalid); | |||
path = nullptr; | |||
} | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CGradientView::draw (CDrawContext* context) | |||
{ | |||
auto lineWidth = getFrameWidth (); | |||
if (lineWidth < 0.) | |||
lineWidth = context->getHairlineSize (); | |||
if (path == nullptr) | |||
{ | |||
CRect r = getViewSize (); | |||
r.inset (lineWidth / 2., lineWidth / 2.); | |||
path = owned (context->createRoundRectGraphicsPath (r, roundRectRadius)); | |||
} | |||
if (path && gradient) | |||
{ | |||
context->setDrawMode (drawAntialiased ? kAntiAliasing : kAliasing); | |||
if (gradientStyle == kLinearGradient) | |||
{ | |||
CPoint colorStartPoint (0, 0); | |||
colorStartPoint.x = getViewSize ().left + getViewSize ().getWidth () / 2 + cos (radians (gradientAngle-90)) * getViewSize ().getWidth () / 2; | |||
colorStartPoint.y = getViewSize ().top + getViewSize ().getHeight () / 2 + sin (radians (gradientAngle-90)) * getViewSize ().getHeight () / 2; | |||
CPoint colorEndPoint (0, getViewSize ().getHeight ()); | |||
colorEndPoint.x = getViewSize ().left + getViewSize ().getWidth () / 2 + cos (radians (gradientAngle+90)) * getViewSize ().getWidth () / 2; | |||
colorEndPoint.y = getViewSize ().top + getViewSize ().getHeight () / 2 + sin (radians (gradientAngle+90)) * getViewSize ().getHeight () / 2; | |||
context->fillLinearGradient (path, *gradient, colorStartPoint, colorEndPoint, false); | |||
} | |||
else | |||
{ | |||
CPoint center (radialCenter); | |||
center.x *= getViewSize ().getWidth (); | |||
center.y *= getViewSize ().getHeight (); | |||
center.offset (getViewSize ().left, getViewSize ().top); | |||
context->fillRadialGradient (path, *gradient, center, radialRadius * std::max (getViewSize ().getWidth (), getViewSize ().getHeight ())); | |||
} | |||
if (frameColor.alpha != 0 && lineWidth > 0.) | |||
{ | |||
context->setDrawMode (drawAntialiased ? kAntiAliasing : kAliasing); | |||
context->setFrameColor (frameColor); | |||
context->setLineWidth (lineWidth); | |||
context->setLineStyle (kLineSolid); | |||
context->drawGraphicsPath (path, CDrawContext::kPathStroked); | |||
} | |||
} | |||
} | |||
} // VSTGUI |
@@ -0,0 +1,73 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "vstguifwd.h" | |||
#include "cview.h" | |||
#include "ccolor.h" | |||
#include "cgradient.h" | |||
namespace VSTGUI { | |||
//----------------------------------------------------------------------------- | |||
/// @brief View which draws a gradient | |||
/// @ingroup new_in_4_2 | |||
//----------------------------------------------------------------------------- | |||
class CGradientView : public CView | |||
{ | |||
public: | |||
explicit CGradientView (const CRect& size); | |||
~CGradientView () noexcept override = default; | |||
//----------------------------------------------------------------------------- | |||
/// @name Gradient Style Methods | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
enum GradientStyle { | |||
kLinearGradient, | |||
kRadialGradient | |||
}; | |||
void setGradientStyle (GradientStyle style); | |||
void setGradient (CGradient* gradient); | |||
void setFrameColor (const CColor& newColor); | |||
void setGradientAngle (double angle); | |||
void setRoundRectRadius (CCoord radius); | |||
void setFrameWidth (CCoord width); | |||
void setDrawAntialiased (bool state); | |||
void setRadialCenter (const CPoint& center); | |||
void setRadialRadius (CCoord radius); | |||
GradientStyle getGradientStyle () const { return gradientStyle; } | |||
CGradient* getGradient () const { return gradient; } | |||
const CColor& getFrameColor () const { return frameColor; } | |||
double getGradientAngle () const { return gradientAngle; } | |||
CCoord getRoundRectRadius () const { return roundRectRadius; } | |||
CCoord getFrameWidth () const { return frameWidth; } | |||
bool getDrawAntialised () const { return drawAntialiased; } | |||
const CPoint& getRadialCenter () const { return radialCenter; } | |||
CCoord getRadialRadius () const { return radialRadius; } | |||
//@} | |||
// override | |||
void setViewSize (const CRect& rect, bool invalid = true) override; | |||
void draw (CDrawContext* context) override; | |||
protected: | |||
virtual void attributeChanged (); | |||
GradientStyle gradientStyle {kLinearGradient}; | |||
CColor frameColor {kBlackCColor}; | |||
double gradientAngle {0.}; | |||
CCoord roundRectRadius {5.}; | |||
CCoord frameWidth {1.}; | |||
CCoord radialRadius {1.}; | |||
CPoint radialCenter {0.5, 0.5}; | |||
bool drawAntialiased {true}; | |||
SharedPointer<CGraphicsPath> path; | |||
SharedPointer<CGradient> gradient; | |||
}; | |||
} // VSTGUI |
@@ -0,0 +1,152 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#include "cgraphicspath.h" | |||
#include "cdrawcontext.h" | |||
#include "cgraphicstransform.h" | |||
namespace VSTGUI { | |||
//----------------------------------------------------------------------------- | |||
void CGraphicsPath::addRoundRect (const CRect& size, CCoord radius) | |||
{ | |||
if (radius == 0.) | |||
{ | |||
addRect (size); | |||
return; | |||
} | |||
CRect rect2 (size); | |||
rect2.normalize (); | |||
const CCoord left = rect2.left; | |||
const CCoord right = rect2.right; | |||
const CCoord top = rect2.top; | |||
const CCoord bottom = rect2.bottom; | |||
beginSubpath (CPoint (right-radius, top)); | |||
addArc (CRect (right - 2.0 * radius, top, right, top + 2.0 * radius), 270., 360., true); | |||
addArc (CRect (right - 2.0 * radius, bottom - 2.0 *radius, right, bottom), 0., 90., true); | |||
addArc (CRect (left, bottom - 2.0 * radius, left + 2.0 * radius, bottom), 90., 180., true); | |||
addArc (CRect (left, top, left + 2.0 * radius, top + 2.0 * radius), 180., 270., true); | |||
closeSubpath (); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CGraphicsPath::addPath (const CGraphicsPath& path, CGraphicsTransform* transformation) | |||
{ | |||
for (auto e : path.elements) | |||
{ | |||
if (transformation) | |||
{ | |||
switch (e.type) | |||
{ | |||
case Element::kArc: | |||
{ | |||
transformation->transform (e.instruction.arc.rect.left, e.instruction.arc.rect.right, e.instruction.arc.rect.top, e.instruction.arc.rect.bottom); | |||
break; | |||
} | |||
case Element::kEllipse: | |||
case Element::kRect: | |||
{ | |||
transformation->transform (e.instruction.rect.left, e.instruction.rect.right, e.instruction.rect.top, e.instruction.rect.bottom); | |||
break; | |||
} | |||
case Element::kBeginSubpath: | |||
case Element::kLine: | |||
{ | |||
transformation->transform (e.instruction.point.x, e.instruction.point.y); | |||
break; | |||
} | |||
case Element::kBezierCurve: | |||
{ | |||
transformation->transform (e.instruction.curve.control1.x, e.instruction.curve.control1.y); | |||
transformation->transform (e.instruction.curve.control2.x, e.instruction.curve.control2.y); | |||
transformation->transform (e.instruction.curve.end.x, e.instruction.curve.end.y); | |||
break; | |||
} | |||
case Element::kCloseSubpath: | |||
{ | |||
break; | |||
} | |||
} | |||
} | |||
elements.emplace_back (e); | |||
} | |||
dirty (); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CGraphicsPath::addArc (const CRect& rect, double startAngle, double endAngle, bool clockwise) | |||
{ | |||
Element e; | |||
e.type = Element::kArc; | |||
CRect2Rect (rect, e.instruction.arc.rect); | |||
e.instruction.arc.startAngle = startAngle; | |||
e.instruction.arc.endAngle = endAngle; | |||
e.instruction.arc.clockwise = clockwise; | |||
elements.emplace_back (e); | |||
dirty (); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CGraphicsPath::addEllipse (const CRect& rect) | |||
{ | |||
Element e; | |||
e.type = Element::kEllipse; | |||
CRect2Rect (rect, e.instruction.rect); | |||
elements.emplace_back (e); | |||
dirty (); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CGraphicsPath::addRect (const CRect& rect) | |||
{ | |||
Element e; | |||
e.type = Element::kRect; | |||
CRect2Rect (rect, e.instruction.rect); | |||
elements.emplace_back (e); | |||
dirty (); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CGraphicsPath::addLine (const CPoint& to) | |||
{ | |||
Element e; | |||
e.type = Element::kLine; | |||
CPoint2Point (to, e.instruction.point); | |||
elements.emplace_back (e); | |||
dirty (); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CGraphicsPath::addBezierCurve (const CPoint& control1, const CPoint& control2, const CPoint& end) | |||
{ | |||
Element e; | |||
e.type = Element::kBezierCurve; | |||
CPoint2Point (control1, e.instruction.curve.control1); | |||
CPoint2Point (control2, e.instruction.curve.control2); | |||
CPoint2Point (end, e.instruction.curve.end); | |||
elements.emplace_back (e); | |||
dirty (); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CGraphicsPath::beginSubpath (const CPoint& start) | |||
{ | |||
Element e; | |||
e.type = Element::kBeginSubpath; | |||
CPoint2Point (start, e.instruction.point); | |||
elements.emplace_back (e); | |||
dirty (); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CGraphicsPath::closeSubpath () | |||
{ | |||
Element e; | |||
e.type = Element::kCloseSubpath; | |||
elements.emplace_back (e); | |||
dirty (); | |||
} | |||
} // VSTGUI |
@@ -0,0 +1,153 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "vstguifwd.h" | |||
#include "ccolor.h" | |||
#include "crect.h" | |||
#include <vector> | |||
namespace VSTGUI { | |||
//----------------------------------------------------------------------------- | |||
/// @brief Graphics Path Object | |||
/// @ingroup new_in_4_0 | |||
//----------------------------------------------------------------------------- | |||
class CGraphicsPath : public AtomicReferenceCounted | |||
{ | |||
public: | |||
//----------------------------------------------------------------------------- | |||
/// @name Creating gradients | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
/** | |||
* @brief creates a new gradient object, you must release it with forget() when you're done with it | |||
* @param color1Start value between zero and one which defines the normalized start offset for color1 | |||
* @param color2Start value between zero and one which defines the normalized start offset for color2 | |||
* @param color1 the first color of the gradient | |||
* @param color2 the second color of the gradient | |||
* @return a new gradient object | |||
*/ | |||
virtual CGradient* createGradient (double color1Start, double color2Start, const CColor& color1, const CColor& color2) = 0; | |||
//@} | |||
//----------------------------------------------------------------------------- | |||
/// @name Adding Elements | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
/** add an arc to the path. Begins a new subpath if no elements were added before. */ | |||
virtual void addArc (const CRect& rect, double startAngle, double endAngle, bool clockwise); | |||
/** add an ellipse to the path. Begins a new subpath if no elements were added before. */ | |||
virtual void addEllipse (const CRect& rect); | |||
/** add a rectangle to the path. Begins a new subpath if no elements were added before. */ | |||
virtual void addRect (const CRect& rect); | |||
/** add another path to the path. Begins a new subpath if no elements were added before. */ | |||
virtual void addPath (const CGraphicsPath& path, CGraphicsTransform* transformation = nullptr); | |||
/** add a line to the path. A subpath must begin before */ | |||
virtual void addLine (const CPoint& to); | |||
/** add a bezier curve to the path. A subpath must begin before */ | |||
virtual void addBezierCurve (const CPoint& control1, const CPoint& control2, const CPoint& end); | |||
/** begin a new subpath. */ | |||
virtual void beginSubpath (const CPoint& start); | |||
/** close a subpath. A straight line will be added from the current point to the start point. */ | |||
virtual void closeSubpath (); | |||
inline void beginSubpath (CCoord x, CCoord y) | |||
{ | |||
beginSubpath (CPoint (x, y)); | |||
} | |||
inline void addLine (CCoord x, CCoord y) | |||
{ | |||
addLine (CPoint(x, y)); | |||
} | |||
inline void addBezierCurve (CCoord cp1x, CCoord cp1y, CCoord cp2x, CCoord cp2y, CCoord x, CCoord y) | |||
{ | |||
addBezierCurve (CPoint (cp1x, cp1y), CPoint (cp2x, cp2y), CPoint (x, y)); | |||
} | |||
//@} | |||
//----------------------------------------------------------------------------- | |||
/// @name Helpers | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
void addRoundRect (const CRect& size, CCoord radius); | |||
//@} | |||
//----------------------------------------------------------------------------- | |||
/// @name Hit Testing | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
virtual bool hitTest (const CPoint& p, bool evenOddFilled = false, CGraphicsTransform* transform = nullptr) = 0; | |||
//@} | |||
//----------------------------------------------------------------------------- | |||
/// @name States | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
virtual CPoint getCurrentPosition () = 0; | |||
virtual CRect getBoundingBox () = 0; | |||
//@} | |||
protected: | |||
CGraphicsPath () {} | |||
virtual void dirty () = 0; // platform object should be released | |||
/// @cond ignore | |||
struct Rect { | |||
CCoord left; | |||
CCoord top; | |||
CCoord right; | |||
CCoord bottom; | |||
}; | |||
struct Point { | |||
CCoord x; | |||
CCoord y; | |||
}; | |||
struct Arc { | |||
Rect rect; | |||
double startAngle; | |||
double endAngle; | |||
bool clockwise; | |||
}; | |||
struct BezierCurve { | |||
Point control1; | |||
Point control2; | |||
Point end; | |||
}; | |||
struct Element { | |||
enum Type { | |||
kArc = 0, | |||
kEllipse, | |||
kRect, | |||
kLine, | |||
kBezierCurve, | |||
kBeginSubpath, | |||
kCloseSubpath | |||
}; | |||
Type type; | |||
union Instruction { | |||
Arc arc; | |||
Rect rect; | |||
BezierCurve curve; | |||
Point point; | |||
} instruction; | |||
}; | |||
inline void CRect2Rect (const CRect& rect, CGraphicsPath::Rect& r) const {r.left = rect.left;r.right = rect.right;r.top = rect.top;r.bottom = rect.bottom;} | |||
inline void CPoint2Point (const CPoint& point, CGraphicsPath::Point& p) const {p.x = point.x;p.y = point.y;} | |||
/// @endcond | |||
using ElementList = std::vector<Element>; | |||
ElementList elements; | |||
}; | |||
} // VSTGUI |
@@ -0,0 +1,154 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "cpoint.h" | |||
#include "crect.h" | |||
#ifndef M_PI | |||
#define M_PI 3.14159265358979323846264338327950288 | |||
#endif | |||
namespace VSTGUI { | |||
static inline double radians (double degrees) { return degrees * M_PI / 180; } | |||
//----------------------------------------------------------------------------- | |||
/// @brief Graphics Transform Matrix | |||
/// @ingroup new_in_4_0 | |||
//----------------------------------------------------------------------------- | |||
struct CGraphicsTransform | |||
{ | |||
double m11 {1.}; | |||
double m12 {0.}; | |||
double m21 {0.}; | |||
double m22 {1.}; | |||
double dx {0.}; | |||
double dy {0.}; | |||
CGraphicsTransform () = default; | |||
CGraphicsTransform (double _m11, double _m12, double _m21, double _m22, double _dx, double _dy) | |||
: m11 (_m11), m12 (_m12), m21 (_m21), m22 (_m22), dx (_dx), dy (_dy) | |||
{} | |||
CGraphicsTransform& translate (double x, double y) | |||
{ | |||
*this = CGraphicsTransform (1, 0, 0, 1, x, y) * this; | |||
return *this; | |||
} | |||
CGraphicsTransform& translate (const CPoint& p) | |||
{ | |||
return translate (p.x, p.y); | |||
} | |||
CGraphicsTransform& scale (double x, double y) | |||
{ | |||
*this = CGraphicsTransform (x, 0., 0., y, 0., 0.) * this; | |||
return *this; | |||
} | |||
CGraphicsTransform& scale (const CPoint& p) | |||
{ | |||
return scale (p.x, p.y); | |||
} | |||
CGraphicsTransform& rotate (double angle) | |||
{ | |||
angle = radians (angle); | |||
*this = CGraphicsTransform (cos (angle), -sin (angle), sin (angle), cos (angle), 0, 0) * this; | |||
return *this; | |||
} | |||
CGraphicsTransform& rotate (double angle, const CPoint& center) | |||
{ | |||
return translate (-center.x, -center.y).rotate (angle).translate (center.x, center.y); | |||
} | |||
CGraphicsTransform& skewX (double angle) | |||
{ | |||
*this = CGraphicsTransform (1, std::tan (radians (angle)), 0, 1, 0, 0) * *this; | |||
return *this; | |||
} | |||
CGraphicsTransform& skewY (double angle) | |||
{ | |||
*this = CGraphicsTransform (1, 0, std::tan (radians (angle)), 1, 0, 0) * *this; | |||
return *this; | |||
} | |||
bool isInvariant () const | |||
{ | |||
return *this == CGraphicsTransform (); | |||
} | |||
void transform (CCoord& x, CCoord& y) const | |||
{ | |||
CCoord x2 = m11*x + m12*y + dx; | |||
CCoord y2 = m21*x + m22*y + dy; | |||
x = x2; | |||
y = y2; | |||
} | |||
void transform (CCoord& left, CCoord& right, CCoord& top, CCoord& bottom) const | |||
{ | |||
transform (left, top); | |||
transform (right, bottom); | |||
} | |||
CPoint& transform (CPoint& p) const | |||
{ | |||
transform (p.x, p.y); | |||
return p; | |||
} | |||
CRect& transform (CRect& r) const | |||
{ | |||
transform (r.left, r.right, r.top, r.bottom); | |||
return r; | |||
} | |||
CGraphicsTransform inverse () const | |||
{ | |||
CGraphicsTransform result; | |||
const double denominator = m11 * m22 - m12 * m21; | |||
if (denominator != 0) | |||
{ | |||
result.m11 = m22 / denominator; | |||
result.m12 = -m12 / denominator; | |||
result.m21 = -m21 / denominator; | |||
result.m22 = m11 / denominator; | |||
result.dx = ((m12 * dy) - (m22 * dx)) / denominator; | |||
result.dy = ((m21 * dx) - (m11 * dy)) / denominator; | |||
} | |||
return result; | |||
} | |||
CGraphicsTransform operator* (const CGraphicsTransform& t) const | |||
{ | |||
CGraphicsTransform result; | |||
result.m11 = (m11 * t.m11) + (m12 * t.m21); | |||
result.m21 = (m21 * t.m11) + (m22 * t.m21); | |||
result.dx = (m11 * t.dx) + (m12 * t.dy) + dx; | |||
result.m12 = (m11 * t.m12) + (m12 * t.m22); | |||
result.m22 = (m21 * t.m12) + (m22 * t.m22); | |||
result.dy = (m21 * t.dx) + (m22 * t.dy) + dy; | |||
return result; | |||
} | |||
CGraphicsTransform operator* (const CGraphicsTransform* t) const { return *this * *t; } | |||
bool operator== (const CGraphicsTransform& t) const | |||
{ | |||
return m11 == t.m11 && m12 == t.m12 && m21 == t.m21 && m22 == t.m22 && dx == t.dx && dy == t.dy; | |||
} | |||
bool operator!= (const CGraphicsTransform& t) const | |||
{ | |||
return m11 != t.m11 || m12 != t.m12 || m21 != t.m21 || m22 != t.m22 || dx != t.dx || dy != t.dy; | |||
} | |||
}; | |||
} // VSTGUI |
@@ -0,0 +1,239 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#include "clayeredviewcontainer.h" | |||
#include "cframe.h" | |||
#include "cdrawcontext.h" | |||
#include "platform/iplatformframe.h" | |||
namespace VSTGUI { | |||
//----------------------------------------------------------------------------- | |||
CLayeredViewContainer::CLayeredViewContainer (const CRect& r) | |||
: CViewContainer (r) | |||
{ | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CLayeredViewContainer::setZIndex (uint32_t _zIndex) | |||
{ | |||
if (_zIndex != zIndex) | |||
{ | |||
zIndex = _zIndex; | |||
if (layer) | |||
layer->setZIndex (zIndex); | |||
} | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CLayeredViewContainer::updateLayerSize () | |||
{ | |||
CRect newSize = getViewSize (); | |||
getTransform ().transform (newSize); | |||
CViewContainer* parent = static_cast<CViewContainer*> (getParentView ()); | |||
while (parent) | |||
{ | |||
CRect parentSize = parent->getViewSize (); | |||
parent->getTransform ().transform (newSize); | |||
newSize.offset (parentSize.left, parentSize.top); | |||
newSize.bound (parentSize); | |||
parent = static_cast<CViewContainer*> (parent->getParentView ()); | |||
} | |||
if (parentLayerView) | |||
{ | |||
CPoint p (parentLayerView->getVisibleViewSize ().getTopLeft ()); | |||
parentLayerView->translateToGlobal (p); | |||
newSize.offsetInverse (p); | |||
} | |||
if (layer) | |||
layer->setSize (newSize); | |||
} | |||
//----------------------------------------------------------------------------- | |||
bool CLayeredViewContainer::removed (CView* parent) | |||
{ | |||
if (!isAttached ()) | |||
return false; | |||
registerListeners (false); | |||
if (layer) | |||
{ | |||
layer = nullptr; | |||
parentLayerView = nullptr; | |||
getFrame ()->unregisterScaleFactorChangedListeneer (this); | |||
} | |||
return CViewContainer::removed (parent); | |||
} | |||
//----------------------------------------------------------------------------- | |||
bool CLayeredViewContainer::attached (CView* parent) | |||
{ | |||
if (isAttached ()) | |||
return false; | |||
setParentView (parent); | |||
setParentFrame (parent->getFrame ()); | |||
if (getFrame ()) | |||
{ | |||
while (parent && dynamic_cast<CFrame*>(parent) == nullptr) | |||
{ | |||
parentLayerView = dynamic_cast<CLayeredViewContainer*>(parent); | |||
if (parentLayerView) | |||
{ | |||
break; | |||
} | |||
parent = parent->getParentView (); | |||
} | |||
layer = getFrame ()->getPlatformFrame ()->createPlatformViewLayer (this, parentLayerView ? parentLayerView->layer : nullptr); | |||
if (layer) | |||
{ | |||
layer->setZIndex (zIndex); | |||
layer->setAlpha (getAlphaValue ()); | |||
updateLayerSize (); | |||
getFrame ()->registerScaleFactorChangedListeneer (this); | |||
} | |||
} | |||
parent = getParentView (); | |||
registerListeners (true); | |||
setParentView (nullptr); | |||
setParentFrame (nullptr); | |||
return CViewContainer::attached (parent); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CLayeredViewContainer::registerListeners (bool state) | |||
{ | |||
CViewContainer* parent = static_cast<CViewContainer*> (getParentView ()); | |||
while (parent) | |||
{ | |||
if (state) | |||
parent->registerViewContainerListener (this); | |||
else | |||
parent->unregisterViewContainerListener (this); | |||
parent = static_cast<CViewContainer*> (parent->getParentView ()); | |||
} | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CLayeredViewContainer::viewContainerTransformChanged (CViewContainer* container) | |||
{ | |||
if (layer) | |||
updateLayerSize (); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CLayeredViewContainer::invalid () | |||
{ | |||
CRect r = getViewSize (); | |||
r.originize (); | |||
invalidRect (r); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CLayeredViewContainer::invalidRect (const CRect& rect) | |||
{ | |||
if (layer) | |||
{ | |||
CRect r (rect); | |||
getDrawTransform ().transform (r); | |||
layer->invalidRect (r); | |||
} | |||
else | |||
{ | |||
CViewContainer::invalidRect (rect); | |||
} | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CLayeredViewContainer::parentSizeChanged () | |||
{ | |||
CViewContainer::parentSizeChanged (); | |||
if (layer) | |||
{ | |||
updateLayerSize (); | |||
invalid (); | |||
} | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CLayeredViewContainer::setViewSize (const CRect& rect, bool invalid) | |||
{ | |||
CViewContainer::setViewSize (rect, invalid); | |||
if (layer) | |||
{ | |||
updateLayerSize (); | |||
} | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CLayeredViewContainer::setAlphaValue (float alpha) | |||
{ | |||
if (layer) | |||
{ | |||
setAlphaValueNoInvalidate (alpha); | |||
layer->setAlpha (alpha); | |||
} | |||
else | |||
CViewContainer::setAlphaValue (alpha); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CLayeredViewContainer::drawRect (CDrawContext* pContext, const CRect& updateRect) | |||
{ | |||
if (layer) | |||
layer->draw (pContext, updateRect); | |||
else | |||
CViewContainer::drawRect (pContext, updateRect); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CLayeredViewContainer::drawViewLayer (CDrawContext* context, const CRect& _dirtyRect) | |||
{ | |||
CRect dirtyRect (_dirtyRect); | |||
CGraphicsTransform drawTransform = getDrawTransform (); | |||
drawTransform.inverse ().transform (dirtyRect); | |||
CRect visibleSize = getVisibleViewSize (); | |||
CPoint p (visibleSize.left, visibleSize.top); | |||
dirtyRect.offset (p.x, p.y); | |||
CDrawContext::Transform transform (*context, drawTransform * CGraphicsTransform ().translate (-p.x, -p.y)); | |||
CViewContainer::drawRect (context, dirtyRect); | |||
} | |||
//----------------------------------------------------------------------------- | |||
CGraphicsTransform CLayeredViewContainer::getDrawTransform () const | |||
{ | |||
using ParentViews = std::list<CViewContainer*>; | |||
CGraphicsTransform transform; | |||
ParentViews parents; | |||
CViewContainer* parent = static_cast<CViewContainer*> (getParentView ()); | |||
while (parent) | |||
{ | |||
parents.push_front (parent); | |||
parent = static_cast<CViewContainer*> (parent->getParentView ()); | |||
} | |||
for (const auto& parent : parents) | |||
transform = parent->getTransform () * transform; | |||
const CViewContainer* This = static_cast<const CViewContainer*> (this); | |||
if (This) | |||
transform = This->getTransform () * transform; | |||
return transform; | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CLayeredViewContainer::onScaleFactorChanged (CFrame* frame, double newScaleFactor) | |||
{ | |||
if (layer) | |||
layer->onScaleFactorChanged (newScaleFactor); | |||
} | |||
} |
@@ -0,0 +1,58 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "cviewcontainer.h" | |||
#include "iviewlistener.h" | |||
#include "iscalefactorchangedlistener.h" | |||
#include "platform/iplatformviewlayer.h" | |||
namespace VSTGUI { | |||
//----------------------------------------------------------------------------- | |||
// CLayeredViewContainer Declaration | |||
//! @brief a view container which draws into a platform layer on top of a parent layer or the platform view | |||
//! @ingroup containerviews | |||
//! @ingroup new_in_4_2 | |||
//! A CLayeredViewContainer creates a platform layer on top of a parent layer or the platform view of CFrame | |||
//! if available on that platform and draws into it, otherwise it acts exactly like a CViewContainer | |||
//----------------------------------------------------------------------------- | |||
class CLayeredViewContainer : public CViewContainer, | |||
public IPlatformViewLayerDelegate, | |||
public ViewContainerListenerAdapter, | |||
public IScaleFactorChangedListener | |||
{ | |||
public: | |||
explicit CLayeredViewContainer (const CRect& r = CRect (0, 0, 0, 0)); | |||
~CLayeredViewContainer () noexcept override = default; | |||
IPlatformViewLayer* getPlatformLayer () const { return layer; } | |||
void setZIndex (uint32_t zIndex); | |||
uint32_t getZIndex () const { return zIndex; } | |||
bool removed (CView* parent) override; | |||
bool attached (CView* parent) override; | |||
void invalid () override; | |||
void invalidRect (const CRect& rect) override; | |||
void parentSizeChanged () override; | |||
void setViewSize (const CRect& rect, bool invalid = true) override; | |||
void setAlphaValue (float alpha) override; | |||
//----------------------------------------------------------------------------- | |||
protected: | |||
void drawRect (CDrawContext* pContext, const CRect& updateRect) override; | |||
void drawViewLayer (CDrawContext* context, const CRect& dirtyRect) override; | |||
void viewContainerTransformChanged (CViewContainer* container) override; | |||
void onScaleFactorChanged (CFrame* frame, double newScaleFactor) override; | |||
void updateLayerSize (); | |||
CGraphicsTransform getDrawTransform () const; | |||
void registerListeners (bool state); | |||
SharedPointer<IPlatformViewLayer> layer; | |||
CLayeredViewContainer* parentLayerView {nullptr}; | |||
uint32_t zIndex {0}; | |||
}; | |||
} // VSTGUI |
@@ -0,0 +1,91 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#include "clinestyle.h" | |||
namespace VSTGUI { | |||
//----------------------------------------------------------------------------- | |||
//----------------------------------------------------------------------------- | |||
//----------------------------------------------------------------------------- | |||
CLineStyle::CLineStyle (LineCap _cap, LineJoin _join, CCoord _dashPhase, uint32_t _dashCount, const CCoord* _dashLengths) | |||
: cap (_cap) | |||
, join (_join) | |||
, dashPhase (_dashPhase) | |||
{ | |||
if (_dashCount && _dashLengths) | |||
{ | |||
for (uint32_t i = 0; i < _dashCount; i++) | |||
dashLengths.emplace_back (_dashLengths[i]); | |||
} | |||
} | |||
//----------------------------------------------------------------------------- | |||
CLineStyle::CLineStyle (LineCap _cap, LineJoin _join, CCoord _dashPhase, const CoordVector& _dashLengths) | |||
: cap (_cap) | |||
, join (_join) | |||
, dashPhase (_dashPhase) | |||
, dashLengths (_dashLengths) | |||
{ | |||
} | |||
//----------------------------------------------------------------------------- | |||
CLineStyle::CLineStyle (const CLineStyle& lineStyle) | |||
{ | |||
*this = lineStyle; | |||
} | |||
//----------------------------------------------------------------------------- | |||
CLineStyle::CLineStyle (LineCap _cap, LineJoin _join, CCoord _dashPhase, CoordVector&& _dashLengths) noexcept | |||
: cap (_cap) | |||
, join (_join) | |||
, dashPhase (_dashPhase) | |||
, dashLengths (std::move (_dashLengths)) | |||
{ | |||
} | |||
//----------------------------------------------------------------------------- | |||
CLineStyle::CLineStyle (CLineStyle&& cls) noexcept | |||
{ | |||
*this = std::move (cls); | |||
} | |||
//----------------------------------------------------------------------------- | |||
CLineStyle& CLineStyle::operator= (CLineStyle&& cls) noexcept | |||
{ | |||
dashLengths.clear (); | |||
cap = cls.cap; | |||
join = cls.join; | |||
dashPhase = cls.dashPhase; | |||
dashLengths = std::move (cls.dashLengths); | |||
return *this; | |||
} | |||
//----------------------------------------------------------------------------- | |||
bool CLineStyle::operator== (const CLineStyle& cls) const | |||
{ | |||
if (cap == cls.cap && join == cls.join && dashPhase == cls.dashPhase && dashLengths == cls.dashLengths) | |||
{ | |||
return true; | |||
} | |||
return false; | |||
} | |||
//----------------------------------------------------------------------------- | |||
CLineStyle& CLineStyle::operator= (const CLineStyle& cls) | |||
{ | |||
dashLengths.clear (); | |||
cap = cls.cap; | |||
join = cls.join; | |||
dashPhase = cls.dashPhase; | |||
dashLengths = cls.dashLengths; | |||
return *this; | |||
} | |||
//----------------------------------------------------------------------------- | |||
static const CCoord kDefaultOnOffDashLength[] = {1, 1}; | |||
const CLineStyle kLineSolid {}; | |||
const CLineStyle kLineOnOffDash (CLineStyle::kLineCapButt, CLineStyle::kLineJoinMiter, 0, 2, kDefaultOnOffDashLength); | |||
} |
@@ -0,0 +1,69 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "vstguifwd.h" | |||
#include <vector> | |||
namespace VSTGUI { | |||
//----------- | |||
// @brief Line Style | |||
//----------- | |||
class CLineStyle | |||
{ | |||
public: | |||
using CoordVector = std::vector<CCoord>; | |||
enum LineCap | |||
{ | |||
kLineCapButt = 0, | |||
kLineCapRound, | |||
kLineCapSquare | |||
}; | |||
enum LineJoin | |||
{ | |||
kLineJoinMiter = 0, | |||
kLineJoinRound, | |||
kLineJoinBevel | |||
}; | |||
CLineStyle () = default; | |||
explicit CLineStyle (LineCap cap, LineJoin join = kLineJoinMiter, CCoord dashPhase = 0., uint32_t dashCount = 0, const CCoord* dashLengths = nullptr); | |||
CLineStyle (LineCap cap, LineJoin join, CCoord dashPhase, const CoordVector& dashLengths); | |||
CLineStyle (const CLineStyle& lineStyle); | |||
~CLineStyle () noexcept = default; | |||
CLineStyle (LineCap cap, LineJoin join, CCoord dashPhase, CoordVector&& dashLengths) noexcept; | |||
CLineStyle (CLineStyle&& cls) noexcept; | |||
CLineStyle& operator= (CLineStyle&& cls) noexcept; | |||
LineCap getLineCap () const { return cap; } | |||
LineJoin getLineJoin () const { return join; } | |||
CCoord getDashPhase () const { return dashPhase; } | |||
uint32_t getDashCount () const { return static_cast<uint32_t> (dashLengths.size ()); } | |||
CoordVector& getDashLengths () { return dashLengths; } | |||
const CoordVector& getDashLengths() const { return dashLengths; } | |||
void setLineCap (LineCap newCap) { cap = newCap; } | |||
void setLineJoin (LineJoin newJoin) { join = newJoin; } | |||
void setDashPhase (CCoord phase) { dashPhase = phase; } | |||
bool operator== (const CLineStyle& cls) const; | |||
bool operator!= (const CLineStyle& cls) const { return !(*this == cls); } | |||
CLineStyle& operator= (const CLineStyle& cls); | |||
protected: | |||
LineCap cap {kLineCapButt}; | |||
LineJoin join {kLineJoinMiter}; | |||
CCoord dashPhase {0.}; | |||
CoordVector dashLengths; | |||
}; | |||
extern const CLineStyle kLineSolid; | |||
extern const CLineStyle kLineOnOffDash; | |||
} // VSTGUI |
@@ -0,0 +1,56 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#include "coffscreencontext.h" | |||
#include "cframe.h" | |||
#include "cbitmap.h" | |||
#include "platform/iplatformframe.h" | |||
namespace VSTGUI { | |||
//----------------------------------------------------------------------------- | |||
COffscreenContext::COffscreenContext (CBitmap* bitmap) | |||
: CDrawContext (CRect (0, 0, bitmap->getWidth (), bitmap->getHeight ())) | |||
, bitmap (bitmap) | |||
{ | |||
} | |||
//----------------------------------------------------------------------------- | |||
COffscreenContext::COffscreenContext (const CRect& surfaceRect) | |||
: CDrawContext (surfaceRect) | |||
{ | |||
} | |||
//----------------------------------------------------------------------------- | |||
void COffscreenContext::copyFrom (CDrawContext *pContext, CRect destRect, CPoint srcOffset) | |||
{ | |||
if (bitmap) | |||
bitmap->draw (pContext, destRect, srcOffset); | |||
} | |||
//----------------------------------------------------------------------------- | |||
SharedPointer<COffscreenContext> COffscreenContext::create (CFrame* frame, CCoord width, CCoord height, double scaleFactor) | |||
{ | |||
if (width >= 1. && height >= 1.) | |||
{ | |||
IPlatformFrame* pf = frame ? frame->getPlatformFrame () : nullptr; | |||
if (pf) | |||
return pf->createOffscreenContext (width, height, scaleFactor); | |||
} | |||
return nullptr; | |||
} | |||
//----------------------------------------------------------------------------- | |||
CCoord COffscreenContext::getWidth () const | |||
{ | |||
return bitmap ? bitmap->getWidth () : 0.; | |||
} | |||
//----------------------------------------------------------------------------- | |||
CCoord COffscreenContext::getHeight () const | |||
{ | |||
return bitmap ? bitmap->getHeight () : 0.; | |||
} | |||
} // VSTGUI |
@@ -0,0 +1,82 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "vstguifwd.h" | |||
#include "cdrawcontext.h" | |||
namespace VSTGUI { | |||
//----------------------------------------------------------------------------- | |||
// COffscreenContext Declaration | |||
//! @brief A draw context using a bitmap as it's back buffer | |||
/*! @class COffscreenContext | |||
There are two usage scenarios : | |||
@section offscreen_usage1 Drawing into a bitmap and then push the contents into another draw context | |||
@code | |||
if (auto offscreen = COffscreenContext::create (frame, 100, 100)) | |||
{ | |||
offscreen->beginDraw (); | |||
// ... | |||
// draw into offscreen | |||
// ... | |||
offscreen->endDraw (); | |||
offscreen->copyFrom (otherContext, destRect); | |||
} | |||
@endcode | |||
@section offscreen_usage2 Drawing static content into a bitmap and reuse the bitmap for drawing | |||
@code | |||
if (cachedBitmap == 0) | |||
{ | |||
if (auto offscreen = COffscreenContext::create (frame, 100, 100)) | |||
{ | |||
offscreen->beginDraw (); | |||
// ... | |||
// draw into offscreen | |||
// ... | |||
offscreen->endDraw (); | |||
cachedBitmap = offscreen->getBitmap (); | |||
if (cachedBitmap) | |||
cachedBitmap->remember (); | |||
} | |||
} | |||
if (cachedBitmap) | |||
{ | |||
// ... | |||
} | |||
@endcode | |||
*/ | |||
//----------------------------------------------------------------------------- | |||
class COffscreenContext : public CDrawContext | |||
{ | |||
public: | |||
static SharedPointer<COffscreenContext> create (CFrame* frame, CCoord width, CCoord height, double scaleFactor = 1.); | |||
//----------------------------------------------------------------------------- | |||
/// @name COffscreenContext Methods | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
/** copy from offscreen to pContext */ | |||
void copyFrom (CDrawContext *pContext, CRect destRect, CPoint srcOffset = CPoint (0, 0)); | |||
CCoord getWidth () const; | |||
CCoord getHeight () const; | |||
//@} | |||
CBitmap* getBitmap () const { return bitmap; } | |||
protected: | |||
explicit COffscreenContext (CBitmap* bitmap); | |||
explicit COffscreenContext (const CRect& surfaceRect); | |||
SharedPointer<CBitmap> bitmap; | |||
}; | |||
} // VSTGUI |
@@ -0,0 +1,145 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#include "cautoanimation.h" | |||
#include "../cdrawcontext.h" | |||
#include "../cbitmap.h" | |||
namespace VSTGUI { | |||
//------------------------------------------------------------------------ | |||
// CAutoAnimation | |||
//------------------------------------------------------------------------ | |||
/*! @class CAutoAnimation | |||
An auto-animation control contains a given number of subbitmaps which can be displayed in loop. | |||
Two functions allows to get the previous or the next subbitmap (these functions increase or decrease the current value of this control). | |||
*/ | |||
// displays bitmaps within a (child-) window | |||
//------------------------------------------------------------------------ | |||
/** | |||
* CAutoAnimation constructor. | |||
* @param size the size of this view | |||
* @param listener the listener | |||
* @param tag the control tag | |||
* @param background the bitmap | |||
* @param offset unused | |||
*/ | |||
//------------------------------------------------------------------------ | |||
CAutoAnimation::CAutoAnimation (const CRect& size, IControlListener* listener, int32_t tag, CBitmap* background, const CPoint& offset) | |||
: CControl (size, listener, tag, background) | |||
, offset (offset) | |||
, bWindowOpened (false) | |||
{ | |||
heightOfOneImage = size.getHeight (); | |||
setNumSubPixmaps (background ? (int32_t)(background->getHeight () / heightOfOneImage) : 0); | |||
totalHeightOfBitmap = heightOfOneImage * getNumSubPixmaps (); | |||
} | |||
//------------------------------------------------------------------------ | |||
/** | |||
* CAutoAnimation constructor. | |||
* @param size the size of this view | |||
* @param listener the listener | |||
* @param tag the control tag | |||
* @param subPixmaps number of sub bitmaps in background | |||
* @param heightOfOneImage height of one sub bitmap | |||
* @param background the bitmap | |||
* @param offset unused | |||
*/ | |||
//------------------------------------------------------------------------ | |||
CAutoAnimation::CAutoAnimation (const CRect& size, IControlListener* listener, int32_t tag, int32_t subPixmaps, CCoord heightOfOneImage, CBitmap* background, const CPoint& offset) | |||
: CControl (size, listener, tag, background) | |||
, offset (offset) | |||
, bWindowOpened (false) | |||
{ | |||
setNumSubPixmaps (subPixmaps); | |||
setHeightOfOneImage (heightOfOneImage); | |||
totalHeightOfBitmap = heightOfOneImage * getNumSubPixmaps (); | |||
setMin (0.f); | |||
setMax ((float)(totalHeightOfBitmap - (heightOfOneImage + 1.))); | |||
} | |||
//------------------------------------------------------------------------ | |||
CAutoAnimation::CAutoAnimation (const CAutoAnimation& v) | |||
: CControl (v) | |||
, offset (v.offset) | |||
, totalHeightOfBitmap (v.totalHeightOfBitmap) | |||
, bWindowOpened (v.bWindowOpened) | |||
{ | |||
setNumSubPixmaps (v.subPixmaps); | |||
setHeightOfOneImage (v.heightOfOneImage); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CAutoAnimation::draw (CDrawContext *pContext) | |||
{ | |||
if (isWindowOpened ()) | |||
{ | |||
CPoint where; | |||
where.y = (int32_t)value + offset.y; | |||
where.x = offset.x; | |||
if (getDrawBackground ()) | |||
{ | |||
getDrawBackground ()->draw (pContext, getViewSize (), where); | |||
} | |||
} | |||
setDirty (false); | |||
} | |||
//------------------------------------------------------------------------ | |||
CMouseEventResult CAutoAnimation::onMouseDown (CPoint& where, const CButtonState& buttons) | |||
{ | |||
if (buttons & kLButton) | |||
{ | |||
if (!isWindowOpened ()) | |||
{ | |||
value = 0; | |||
openWindow (); | |||
invalid (); | |||
valueChanged (); | |||
} | |||
else | |||
{ | |||
// stop info animation | |||
value = 0; // draw first pic of bitmap | |||
invalid (); | |||
closeWindow (); | |||
valueChanged (); | |||
} | |||
return kMouseDownEventHandledButDontNeedMovedOrUpEvents; | |||
} | |||
return kMouseEventNotHandled; | |||
} | |||
//------------------------------------------------------------------------ | |||
void CAutoAnimation::openWindow () | |||
{ | |||
bWindowOpened = true; | |||
} | |||
//------------------------------------------------------------------------ | |||
void CAutoAnimation::closeWindow () | |||
{ | |||
bWindowOpened = false; | |||
} | |||
//------------------------------------------------------------------------ | |||
void CAutoAnimation::nextPixmap () | |||
{ | |||
value += (float)heightOfOneImage; | |||
if (value >= (totalHeightOfBitmap - heightOfOneImage)) | |||
value = 0; | |||
} | |||
//------------------------------------------------------------------------ | |||
void CAutoAnimation::previousPixmap () | |||
{ | |||
value -= (float)heightOfOneImage; | |||
if (value < 0.f) | |||
value = (float)(totalHeightOfBitmap - heightOfOneImage - 1); | |||
} | |||
} // VSTGUI |
@@ -0,0 +1,56 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "ccontrol.h" | |||
namespace VSTGUI { | |||
//----------------------------------------------------------------------------- | |||
// CAutoAnimation Declaration | |||
//! | |||
/// @ingroup controls | |||
//----------------------------------------------------------------------------- | |||
class CAutoAnimation : public CControl, public IMultiBitmapControl | |||
{ | |||
public: | |||
CAutoAnimation (const CRect& size, IControlListener* listener, int32_t tag, CBitmap* background, const CPoint& offset = CPoint (0, 0)); | |||
CAutoAnimation (const CRect& size, IControlListener* listener, int32_t tag, int32_t subPixmaps, CCoord heightOfOneImage, CBitmap* background, const CPoint& offset = CPoint (0, 0)); | |||
CAutoAnimation (const CAutoAnimation& autoAnimation); | |||
void draw (CDrawContext*) override; | |||
CMouseEventResult onMouseDown (CPoint& where, const CButtonState& buttons) override; | |||
//----------------------------------------------------------------------------- | |||
/// @name CAutoAnimation Methods | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
/** enabled drawing */ | |||
virtual void openWindow (void); | |||
/** disable drawing */ | |||
virtual void closeWindow (void); | |||
/** the next sub bitmap should be displayed */ | |||
virtual void nextPixmap (void); | |||
/** the previous sub bitmap should be displayed */ | |||
virtual void previousPixmap (void); | |||
bool isWindowOpened () const { return bWindowOpened; } | |||
//@} | |||
void setNumSubPixmaps (int32_t numSubPixmaps) override { IMultiBitmapControl::setNumSubPixmaps (numSubPixmaps); invalid (); } | |||
CLASS_METHODS(CAutoAnimation, CControl) | |||
protected: | |||
~CAutoAnimation () noexcept override = default; | |||
CPoint offset; | |||
CCoord totalHeightOfBitmap; | |||
bool bWindowOpened; | |||
}; | |||
} // VSTGUI |
@@ -0,0 +1,276 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "ccontrol.h" | |||
#include "../cfont.h" | |||
#include "../ccolor.h" | |||
#include "../cbitmap.h" | |||
#include "../cgradient.h" | |||
#include "../cgraphicspath.h" | |||
#include "../cstring.h" | |||
#include "../cdrawmethods.h" | |||
namespace VSTGUI { | |||
//----------------------------------------------------------------------------- | |||
// COnOffButton Declaration | |||
//! @brief a button control with 2 states | |||
/// @ingroup controls | |||
//----------------------------------------------------------------------------- | |||
class COnOffButton : public CControl | |||
{ | |||
public: | |||
COnOffButton (const CRect& size, IControlListener* listener = nullptr, int32_t tag = -1, CBitmap* background = nullptr, int32_t style = 0); | |||
COnOffButton (const COnOffButton& onOffButton); | |||
//----------------------------------------------------------------------------- | |||
/// @name COnOffButton Methods | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
virtual int32_t getStyle () const { return style; } | |||
virtual void setStyle (int32_t newStyle) { style = newStyle; } | |||
//@} | |||
// overrides | |||
void draw (CDrawContext*) override; | |||
CMouseEventResult onMouseDown (CPoint& where, const CButtonState& buttons) override; | |||
CMouseEventResult onMouseMoved (CPoint& where, const CButtonState& buttons) override; | |||
CMouseEventResult onMouseUp (CPoint& where, const CButtonState& buttons) override; | |||
CMouseEventResult onMouseCancel () override; | |||
int32_t onKeyDown (VstKeyCode& keyCode) override; | |||
bool sizeToFit () override; | |||
CLASS_METHODS(COnOffButton, CControl) | |||
protected: | |||
~COnOffButton () noexcept override = default; | |||
int32_t style; | |||
}; | |||
//----------------------------------------------------------------------------- | |||
// CCheckBox Declaration | |||
/// @brief a check box control with a title and 3 states | |||
/// @ingroup controls | |||
/// @ingroup new_in_4_0 | |||
//----------------------------------------------------------------------------- | |||
class CCheckBox : public CControl | |||
{ | |||
public: | |||
CCheckBox (const CRect& size, IControlListener* listener = nullptr, int32_t tag = -1, UTF8StringPtr title = nullptr, CBitmap* bitmap = nullptr, int32_t style = 0); | |||
CCheckBox (const CCheckBox& checkbox); | |||
enum Styles { | |||
/** automatically adjusts the width so that the label is completely visible */ | |||
kAutoSizeToFit = 1 << 0, | |||
/** draws a crossbox instead of a checkmark if no bitmap is provided */ | |||
kDrawCrossBox = 1 << 1 | |||
}; | |||
//----------------------------------------------------------------------------- | |||
/// @name CCheckBox Methods | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
virtual void setTitle (const UTF8String& newTitle); | |||
const UTF8String& getTitle () const { return title; } | |||
virtual void setFont (CFontRef newFont); | |||
const CFontRef getFont () const { return font; } | |||
virtual void setFontColor (const CColor& newColor) { fontColor = newColor; invalid (); } | |||
const CColor& getFontColor () const { return fontColor; } | |||
virtual void setBoxFrameColor (const CColor& newColor) { boxFrameColor = newColor; invalid (); } | |||
const CColor& getBoxFrameColor () const { return boxFrameColor; } | |||
virtual void setBoxFillColor (const CColor& newColor) { boxFillColor = newColor; invalid (); } | |||
const CColor& getBoxFillColor () const { return boxFillColor; } | |||
virtual void setCheckMarkColor (const CColor& newColor) { checkMarkColor = newColor; invalid (); } | |||
const CColor& getCheckMarkColor () const { return checkMarkColor; } | |||
virtual int32_t getStyle () const { return style; } | |||
virtual void setStyle (int32_t newStyle); | |||
CCoord getFrameWidth () const { return frameWidth; } | |||
virtual void setFrameWidth (CCoord width); | |||
CCoord getRoundRectRadius () const { return roundRectRadius; } | |||
virtual void setRoundRectRadius (CCoord radius); | |||
//@} | |||
// overrides | |||
void draw (CDrawContext* context) override; | |||
CMouseEventResult onMouseDown (CPoint& where, const CButtonState& buttons) override; | |||
CMouseEventResult onMouseMoved (CPoint& where, const CButtonState& buttons) override; | |||
CMouseEventResult onMouseUp (CPoint& where, const CButtonState& buttons) override; | |||
CMouseEventResult onMouseCancel () override; | |||
int32_t onKeyDown (VstKeyCode& keyCode) override; | |||
bool sizeToFit () override; | |||
void setBackground (CBitmap *background) override; | |||
bool getFocusPath (CGraphicsPath& outPath) override; | |||
CLASS_METHODS(CCheckBox, CControl) | |||
protected: | |||
~CCheckBox () noexcept override = default; | |||
UTF8String title; | |||
int32_t style; | |||
CColor fontColor; | |||
CColor boxFrameColor; | |||
CColor boxFillColor; | |||
CColor checkMarkColor; | |||
CCoord frameWidth {1}; | |||
CCoord roundRectRadius {0}; | |||
SharedPointer<CFontDesc> font; | |||
private: | |||
float previousValue {0.f}; | |||
bool hilight {false}; | |||
}; | |||
//----------------------------------------------------------------------------- | |||
// CKickButton Declaration | |||
//! | |||
/// @ingroup controls | |||
//----------------------------------------------------------------------------- | |||
class CKickButton : public CControl, public IMultiBitmapControl | |||
{ | |||
public: | |||
CKickButton (const CRect& size, IControlListener* listener, int32_t tag, CBitmap* background, const CPoint& offset = CPoint (0, 0)); | |||
CKickButton (const CRect& size, IControlListener* listener, int32_t tag, CCoord heightOfOneImage, CBitmap* background, const CPoint& offset = CPoint (0, 0)); | |||
CKickButton (const CKickButton& kickButton); | |||
void draw (CDrawContext*) override; | |||
CMouseEventResult onMouseDown (CPoint& where, const CButtonState& buttons) override; | |||
CMouseEventResult onMouseUp (CPoint& where, const CButtonState& buttons) override; | |||
CMouseEventResult onMouseMoved (CPoint& where, const CButtonState& buttons) override; | |||
CMouseEventResult onMouseCancel () override; | |||
int32_t onKeyDown (VstKeyCode& keyCode) override; | |||
int32_t onKeyUp (VstKeyCode& keyCode) override; | |||
bool sizeToFit () override; | |||
void setNumSubPixmaps (int32_t numSubPixmaps) override { IMultiBitmapControl::setNumSubPixmaps (numSubPixmaps); invalid (); } | |||
CLASS_METHODS(CKickButton, CControl) | |||
protected: | |||
~CKickButton () noexcept override = default; | |||
CPoint offset; | |||
}; | |||
//----------------------------------------------------------------------------- | |||
// CTextButton Declaration | |||
/// @brief a button which renders without bitmaps | |||
/// @ingroup controls | |||
/// @ingroup new_in_4_0 | |||
//----------------------------------------------------------------------------- | |||
class CTextButton : public CControl | |||
{ | |||
public: | |||
/** CTextButton style */ | |||
enum Style | |||
{ | |||
kKickStyle = 0, | |||
kOnOffStyle | |||
}; | |||
CTextButton (const CRect& size, IControlListener* listener = nullptr, int32_t tag = -1, UTF8StringPtr title = nullptr, Style = kKickStyle); | |||
//----------------------------------------------------------------------------- | |||
/// @name CTextButton Methods | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
virtual void setTitle (const UTF8String& newTitle); | |||
const UTF8String& getTitle () const { return title; } | |||
virtual void setFont (CFontRef newFont); | |||
CFontRef getFont () const { return font; } | |||
virtual void setTextColor (const CColor& color); | |||
const CColor& getTextColor () const { return textColor; } | |||
virtual void setTextColorHighlighted (const CColor& color); | |||
const CColor& getTextColorHighlighted () const { return textColorHighlighted; } | |||
virtual void setGradient (CGradient* gradient); | |||
CGradient* getGradient () const; | |||
virtual void setGradientHighlighted (CGradient* gradient); | |||
CGradient* getGradientHighlighted () const; | |||
virtual void setFrameColor (const CColor& color); | |||
const CColor& getFrameColor () const { return frameColor; } | |||
virtual void setFrameColorHighlighted (const CColor& color); | |||
const CColor& getFrameColorHighlighted () const { return frameColorHighlighted; } | |||
virtual void setFrameWidth (CCoord width); | |||
CCoord getFrameWidth () const { return frameWidth; } | |||
virtual void setRoundRadius (CCoord radius); | |||
CCoord getRoundRadius () const { return roundRadius; } | |||
virtual void setStyle (Style style); | |||
Style getStyle () const { return style; } | |||
virtual void setIcon (CBitmap* bitmap); | |||
CBitmap* getIcon () const; | |||
virtual void setIconHighlighted (CBitmap* bitmap); | |||
CBitmap* getIconHighlighted () const; | |||
virtual void setIconPosition (CDrawMethods::IconPosition pos); | |||
CDrawMethods::IconPosition getIconPosition () const { return iconPosition; } | |||
virtual void setTextMargin (CCoord margin); | |||
CCoord getTextMargin () const { return textMargin; } | |||
virtual void setTextAlignment (CHoriTxtAlign hAlign); | |||
CHoriTxtAlign getTextAlignment () const { return horiTxtAlign; } | |||
//@} | |||
// overrides | |||
void draw (CDrawContext* context) override; | |||
bool getFocusPath (CGraphicsPath& outPath) override; | |||
bool drawFocusOnTop () override; | |||
void setViewSize (const CRect& rect, bool invalid = true) override; | |||
bool removed (CView* parent) override; | |||
bool sizeToFit () override; | |||
CMouseEventResult onMouseDown (CPoint& where, const CButtonState& buttons) override; | |||
CMouseEventResult onMouseUp (CPoint& where, const CButtonState& buttons) override; | |||
CMouseEventResult onMouseMoved (CPoint& where, const CButtonState& buttons) override; | |||
CMouseEventResult onMouseCancel () override; | |||
int32_t onKeyDown (VstKeyCode& keyCode) override; | |||
int32_t onKeyUp (VstKeyCode& keyCode) override; | |||
CLASS_METHODS(CTextButton, CControl) | |||
protected: | |||
~CTextButton () noexcept override = default; | |||
void invalidPath (); | |||
CGraphicsPath* getPath (CDrawContext* context, CCoord lineWidth); | |||
SharedPointer<CFontDesc> font; | |||
SharedPointer<CGraphicsPath> _path; | |||
SharedPointer<CBitmap> icon; | |||
SharedPointer<CBitmap> iconHighlighted; | |||
SharedPointer<CGradient> gradient; | |||
SharedPointer<CGradient> gradientHighlighted; | |||
CColor textColor; | |||
CColor frameColor; | |||
CColor textColorHighlighted; | |||
CColor frameColorHighlighted; | |||
CCoord frameWidth; | |||
CCoord roundRadius; | |||
CCoord textMargin; | |||
CHoriTxtAlign horiTxtAlign; | |||
CDrawMethods::IconPosition iconPosition; | |||
Style style; | |||
UTF8String title; | |||
private: | |||
float fEntryState; | |||
}; | |||
} // VSTGUI |
@@ -0,0 +1,594 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#include "ccolorchooser.h" | |||
#include "cslider.h" | |||
#include "ctextlabel.h" | |||
#include "ccontrol.h" | |||
#include "../cdrawcontext.h" | |||
#include "../cframe.h" | |||
#include "../idatapackage.h" | |||
#include "../dragging.h" | |||
#include <string> | |||
namespace VSTGUI { | |||
/// @cond ignore | |||
namespace CColorChooserInternal { | |||
//----------------------------------------------------------------------------- | |||
class Slider : public CSlider | |||
{ | |||
public: | |||
Slider (const CRect& size, IControlListener* listener = nullptr, int32_t tag = -1) | |||
: CSlider (size, listener, tag, 0, 0, nullptr, nullptr) | |||
{ | |||
if (size.getWidth () > size.getHeight ()) | |||
setSliderSize (size.getHeight (), size.getHeight ()); | |||
else | |||
setSliderSize (size.getWidth (), size.getWidth ()); | |||
CRect r (size); | |||
setViewSize (r, false); | |||
setWheelInc (10.f/255.f); | |||
} | |||
void draw (CDrawContext* context) override | |||
{ | |||
CColor handleFillColor (kWhiteCColor); | |||
CColor handleFrameColor (kBlackCColor); | |||
CColor backgroundFillColor (kGreyCColor); | |||
CColor backgroundFrameColor (kBlackCColor); | |||
CColor bandColor (kTransparentCColor); | |||
CCoord backgroundFrameWidth = 1; | |||
CCoord handleFrameWidth = 1; | |||
auto controlSize = getControlSize (); | |||
auto sliderSize = getSliderSize (); | |||
CRect backgroundRect; | |||
backgroundRect.setSize (controlSize); | |||
backgroundRect.offset (getViewSize ().left, getViewSize ().top); | |||
context->setDrawMode (kAntiAliasing); | |||
context->setFillColor (backgroundFillColor); | |||
context->setFrameColor (backgroundFrameColor); | |||
context->setLineWidth (backgroundFrameWidth); | |||
context->setLineStyle (kLineSolid); | |||
context->drawRect (backgroundRect, kDrawFilledAndStroked); | |||
if (getStyle () & kHorizontal) | |||
{ | |||
backgroundRect.left += getOffsetHandle ().x + sliderSize.x / 2; | |||
backgroundRect.right -= getOffsetHandle ().x + sliderSize.x / 2; | |||
backgroundRect.top += controlSize.y / 2 - 2; | |||
backgroundRect.bottom -= controlSize.y / 2 - 2; | |||
} | |||
else | |||
{ | |||
backgroundRect.left += controlSize.x / 2 - 2; | |||
backgroundRect.right -= controlSize.x / 2 - 2; | |||
backgroundRect.top += getOffsetHandle ().y + sliderSize.y / 2; | |||
backgroundRect.bottom -= getOffsetHandle ().y + sliderSize.y / 2; | |||
} | |||
context->setFillColor (bandColor); | |||
context->drawRect (backgroundRect, kDrawFilled); | |||
// calc new coords of slider | |||
CRect rectNew = calculateHandleRect (getValueNormalized ()); | |||
context->setFillColor (handleFillColor); | |||
context->setFrameColor (handleFrameColor); | |||
context->setLineWidth (handleFrameWidth); | |||
context->drawRect (rectNew, kDrawFilledAndStroked); | |||
setDirty (false); | |||
} | |||
}; | |||
//----------------------------------------------------------------------------- | |||
class ColorView : public CControl, public IDropTarget | |||
{ | |||
public: | |||
ColorView (const CRect& r, const CColor& initialColor, IControlListener* listener = nullptr, int32_t tag = -1, bool checkerBoardBack = true, const CColor& checkerBoardColor1 = kWhiteCColor, const CColor& checkerBoardColor2 = kBlackCColor) | |||
: CControl (r, listener, tag) | |||
, color (initialColor) | |||
, checkerBoardColor1 (checkerBoardColor1) | |||
, checkerBoardColor2 (checkerBoardColor2) | |||
, checkerBoardBack (checkerBoardBack) | |||
{ | |||
} | |||
void draw (CDrawContext* context) override | |||
{ | |||
context->setDrawMode (kAliasing); | |||
if (checkerBoardBack && color.alpha != 255) | |||
{ | |||
context->setFillColor (checkerBoardColor1); | |||
context->drawRect (getViewSize (), kDrawFilled); | |||
context->setFillColor (checkerBoardColor2); | |||
CRect r (getViewSize ().left, getViewSize ().top, getViewSize ().left + 5, getViewSize ().top + 5); | |||
for (int32_t x = 0; x < getViewSize ().getWidth (); x+=5) | |||
{ | |||
r.left = getViewSize ().left + x; | |||
r.top = (x % 2) ? getViewSize ().top : getViewSize ().top + 5; | |||
r.right = r.left + 5; | |||
r.bottom = r.top + 5; | |||
for (int32_t y = 0; y < getViewSize ().getHeight (); y+=10) | |||
{ | |||
context->drawRect (r, kDrawFilled); | |||
r.offset (0, 10); | |||
} | |||
} | |||
} | |||
context->setLineWidth (1); | |||
context->setFillColor (color); | |||
context->setFrameColor (kBlackCColor); | |||
context->drawRect (getViewSize (), kDrawFilledAndStroked); | |||
setDirty (false); | |||
} | |||
const CColor& getColor () const { return color; } | |||
void setColor (const CColor& newColor) | |||
{ | |||
color = newColor; | |||
} | |||
// we accept strings which look like : '#ff3355' (rgb) and '#ff3355bb' (rgba) | |||
static bool dragContainerHasColor (IDataPackage* drag, CColor* color) | |||
{ | |||
IDataPackage::Type type; | |||
const void* item; | |||
if (drag->getData (0, item, type) > 0 && type == IDataPackage::kText) | |||
{ | |||
UTF8StringPtr text = static_cast<UTF8StringPtr> (item); | |||
std::string colorString (text); | |||
if (colorString.length () == 7) | |||
{ | |||
if (colorString[0] == '#') | |||
{ | |||
if (color) | |||
{ | |||
std::string rv (colorString.substr (1, 2)); | |||
std::string gv (colorString.substr (3, 2)); | |||
std::string bv (colorString.substr (5, 2)); | |||
color->red = (uint8_t)strtol (rv.c_str (), nullptr, 16); | |||
color->green = (uint8_t)strtol (gv.c_str (), nullptr, 16); | |||
color->blue = (uint8_t)strtol (bv.c_str (), nullptr, 16); | |||
color->alpha = 255; | |||
} | |||
return true; | |||
} | |||
} | |||
if (colorString.length () == 9) | |||
{ | |||
if (colorString[0] == '#') | |||
{ | |||
if (color) | |||
{ | |||
std::string rv (colorString.substr (1, 2)); | |||
std::string gv (colorString.substr (3, 2)); | |||
std::string bv (colorString.substr (5, 2)); | |||
std::string av (colorString.substr (7, 2)); | |||
color->red = (uint8_t)strtol (rv.c_str (), nullptr, 16); | |||
color->green = (uint8_t)strtol (gv.c_str (), nullptr, 16); | |||
color->blue = (uint8_t)strtol (bv.c_str (), nullptr, 16); | |||
color->alpha = (uint8_t)strtol (av.c_str (), nullptr, 16); | |||
} | |||
return true; | |||
} | |||
} | |||
} | |||
return false; | |||
} | |||
SharedPointer<IDropTarget> getDropTarget () override { return this; } | |||
bool onDrop (DragEventData data) override | |||
{ | |||
CColor color; | |||
if (dragContainerHasColor (data.drag, &color)) | |||
{ | |||
setColor (color); | |||
valueChanged (); | |||
return true; | |||
} | |||
return false; | |||
} | |||
DragOperation onDragEnter (DragEventData data) override | |||
{ | |||
dragOperation = | |||
dragContainerHasColor (data.drag, nullptr) ? DragOperation::Copy : DragOperation::None; | |||
return dragOperation; | |||
} | |||
DragOperation onDragMove (DragEventData data) override | |||
{ | |||
return dragOperation; | |||
} | |||
void onDragLeave (DragEventData data) override | |||
{ | |||
dragOperation = DragOperation::None; | |||
} | |||
CLASS_METHODS(ColorView, CControl) | |||
protected: | |||
DragOperation dragOperation {DragOperation::None}; | |||
CColor color; | |||
CColor checkerBoardColor1; | |||
CColor checkerBoardColor2; | |||
bool checkerBoardBack; | |||
}; | |||
//----------------------------------------------------------------------------- | |||
static void setupParamDisplay (CParamDisplay* display, const CColorChooserUISettings& settings) | |||
{ | |||
display->setFont (settings.font); | |||
display->setFontColor (settings.fontColor); | |||
display->setTransparency (true); | |||
} | |||
} // CColorChooserInternal | |||
/// @endcond | |||
//----------------------------------------------------------------------------- | |||
bool CColorChooser::convertNormalizedToString (float value, char string[256], CParamDisplay::ValueToStringUserData* userData) | |||
{ | |||
sprintf (string, "%.3f", value); | |||
return true; | |||
} | |||
//----------------------------------------------------------------------------- | |||
bool CColorChooser::convertColorValueToString (float value, char string[256], CParamDisplay::ValueToStringUserData* userData) | |||
{ | |||
sprintf (string, "%d", (int32_t)(value*255.f)); | |||
return true; | |||
} | |||
//----------------------------------------------------------------------------- | |||
bool CColorChooser::convertAngleToString (float value, char string[256], CParamDisplay::ValueToStringUserData* userData) | |||
{ | |||
sprintf (string, "%d%s", (int32_t)(value*359.f), kDegreeSymbol); | |||
return true; | |||
} | |||
//----------------------------------------------------------------------------- | |||
bool CColorChooser::convertNormalized (UTF8StringPtr string, float& output, CTextEdit::StringToValueUserData* userData) | |||
{ | |||
output = UTF8StringView (string).toFloat (); | |||
if (output < 0.f) | |||
output = 0.f; | |||
else if (output > 1.f) | |||
output = 1.f; | |||
return true; | |||
} | |||
//----------------------------------------------------------------------------- | |||
bool CColorChooser::convertColorValue (UTF8StringPtr string, float& output, CTextEdit::StringToValueUserData* userData) | |||
{ | |||
output = UTF8StringView (string).toFloat (); | |||
if (output < 0.f) | |||
output = 0.f; | |||
else if (output > 255.f) | |||
output = 255.f; | |||
output /= 255.f; | |||
return true; | |||
} | |||
//----------------------------------------------------------------------------- | |||
bool CColorChooser::convertAngle (UTF8StringPtr string, float& output, CTextEdit::StringToValueUserData* userData) | |||
{ | |||
output = UTF8StringView (string).toFloat (); | |||
if (output < 0.f) | |||
output = 0.f; | |||
else if (output > 359.f) | |||
output = 359.f; | |||
output /= 359.f; | |||
return true; | |||
} | |||
//----------------------------------------------------------------------------- | |||
CColorChooser::CColorChooser (IColorChooserDelegate* delegate, const CColor& initialColor, const CColorChooserUISettings& settings) | |||
: CViewContainer (CRect (0, 0, 0, 0)) | |||
, delegate (delegate) | |||
, color (initialColor) | |||
, redSlider (nullptr) | |||
, greenSlider (nullptr) | |||
, blueSlider (nullptr) | |||
, hueSlider (nullptr) | |||
, saturationSlider (nullptr) | |||
, brightnessSlider (nullptr) | |||
, alphaSlider (nullptr) | |||
, colorView (nullptr) | |||
{ | |||
setTransparency (true); | |||
setAutosizeFlags (kAutosizeAll); | |||
const CCoord controlHeight = settings.font->getSize () + 2; | |||
const CCoord controlWidth = 150; | |||
const CCoord editWidth = 40; | |||
const CCoord labelWidth = 40; | |||
const CCoord xMargin = settings.margin.x; | |||
const CCoord yMargin = settings.margin.y; | |||
colorView = new CColorChooserInternal::ColorView (CRect (1, 1, labelWidth + xMargin + controlWidth + xMargin + editWidth, 100), initialColor, this, kColorTag, settings.checkerBoardBack, settings.checkerBoardColor1, settings.checkerBoardColor2); | |||
colorView->setAutosizeFlags (kAutosizeAll); | |||
addView (colorView); | |||
CRect r (colorView->getViewSize ()); | |||
r.offset (labelWidth + xMargin, r.bottom + yMargin); | |||
r.setWidth (controlWidth); | |||
r.setHeight (controlHeight); | |||
redSlider = new CColorChooserInternal::Slider (r, this, kRedTag); | |||
redSlider->setAutosizeFlags (kAutosizeLeft|kAutosizeRight|kAutosizeBottom); | |||
addView (redSlider); | |||
r.offset (0, yMargin + controlHeight); | |||
greenSlider = new CColorChooserInternal::Slider (r, this, kGreenTag); | |||
greenSlider->setAutosizeFlags (kAutosizeLeft|kAutosizeRight|kAutosizeBottom); | |||
addView (greenSlider); | |||
r.offset (0, yMargin + controlHeight); | |||
blueSlider = new CColorChooserInternal::Slider (r, this, kBlueTag); | |||
blueSlider->setAutosizeFlags (kAutosizeLeft|kAutosizeRight|kAutosizeBottom); | |||
addView (blueSlider); | |||
r.offset (0, yMargin + yMargin + controlHeight); | |||
hueSlider = new CColorChooserInternal::Slider (r, this, kHueTag); | |||
hueSlider->setAutosizeFlags (kAutosizeLeft|kAutosizeRight|kAutosizeBottom); | |||
addView (hueSlider); | |||
r.offset (0, yMargin + controlHeight); | |||
saturationSlider = new CColorChooserInternal::Slider (r, this, kSaturationTag); | |||
saturationSlider->setAutosizeFlags (kAutosizeLeft|kAutosizeRight|kAutosizeBottom); | |||
addView (saturationSlider); | |||
r.offset (0, yMargin + controlHeight); | |||
brightnessSlider = new CColorChooserInternal::Slider (r, this, kBrightnessTag); | |||
brightnessSlider->setAutosizeFlags (kAutosizeLeft|kAutosizeRight|kAutosizeBottom); | |||
addView (brightnessSlider); | |||
r.offset (0, yMargin + yMargin + controlHeight); | |||
alphaSlider = new CColorChooserInternal::Slider (r, this, kAlphaTag); | |||
alphaSlider->setAutosizeFlags (kAutosizeLeft|kAutosizeRight|kAutosizeBottom); | |||
addView (alphaSlider); | |||
CRect newSize (getViewSize ()); | |||
newSize.bottom = r.bottom+1; | |||
newSize.right = colorView->getViewSize ().right+2; | |||
setAutosizingEnabled (false); | |||
setViewSize (newSize); | |||
setMouseableArea (newSize); | |||
setAutosizingEnabled (true); | |||
r = colorView->getViewSize (); | |||
r.offset (0, r.bottom + yMargin); | |||
r.setWidth (labelWidth); | |||
r.setHeight (controlHeight); | |||
CTextLabel* label = new CTextLabel (r, "Red"); | |||
CColorChooserInternal::setupParamDisplay (label, settings); | |||
label->setAutosizeFlags (kAutosizeLeft|kAutosizeBottom); | |||
addView (label); | |||
r.offset (0, yMargin + controlHeight); | |||
label = new CTextLabel (r, "Green"); | |||
CColorChooserInternal::setupParamDisplay (label, settings); | |||
label->setAutosizeFlags (kAutosizeLeft|kAutosizeBottom); | |||
addView (label); | |||
r.offset (0, yMargin + controlHeight); | |||
label = new CTextLabel (r, "Blue"); | |||
CColorChooserInternal::setupParamDisplay (label, settings); | |||
label->setAutosizeFlags (kAutosizeLeft|kAutosizeBottom); | |||
addView (label); | |||
r.offset (0, yMargin + yMargin + controlHeight); | |||
label = new CTextLabel (r, "Hue"); | |||
CColorChooserInternal::setupParamDisplay (label, settings); | |||
label->setAutosizeFlags (kAutosizeLeft|kAutosizeBottom); | |||
addView (label); | |||
r.offset (0, yMargin + controlHeight); | |||
label = new CTextLabel (r, "Sat"); | |||
CColorChooserInternal::setupParamDisplay (label, settings); | |||
label->setAutosizeFlags (kAutosizeLeft|kAutosizeBottom); | |||
addView (label); | |||
r.offset (0, yMargin + controlHeight); | |||
label = new CTextLabel (r, "Value"); | |||
CColorChooserInternal::setupParamDisplay (label, settings); | |||
label->setAutosizeFlags (kAutosizeLeft|kAutosizeBottom); | |||
addView (label); | |||
r.offset (0, yMargin + yMargin + controlHeight); | |||
label = new CTextLabel (r, "Alpha"); | |||
CColorChooserInternal::setupParamDisplay (label, settings); | |||
label->setAutosizeFlags (kAutosizeLeft|kAutosizeBottom); | |||
addView (label); | |||
r = colorView->getViewSize (); | |||
r.offset (labelWidth + xMargin + controlWidth + xMargin, r.bottom + yMargin); | |||
r.setWidth (editWidth); | |||
r.setHeight (controlHeight); | |||
editFields[0] = new CTextEdit (r, this, kRedTag, nullptr); | |||
CColorChooserInternal::setupParamDisplay (editFields[0], settings); | |||
editFields[0]->setAutosizeFlags (kAutosizeRight|kAutosizeBottom); | |||
editFields[0]->setStringToValueFunction (convertColorValue); | |||
editFields[0]->setValueToStringFunction (convertColorValueToString); | |||
addView (editFields[0]); | |||
r.offset (0, yMargin + controlHeight); | |||
editFields[1] = new CTextEdit (r, this, kGreenTag, nullptr); | |||
CColorChooserInternal::setupParamDisplay (editFields[1], settings); | |||
editFields[1]->setAutosizeFlags (kAutosizeRight|kAutosizeBottom); | |||
editFields[1]->setStringToValueFunction (convertColorValue); | |||
editFields[1]->setValueToStringFunction (convertColorValueToString); | |||
addView (editFields[1]); | |||
r.offset (0, yMargin + controlHeight); | |||
editFields[2] = new CTextEdit (r, this, kBlueTag, nullptr); | |||
CColorChooserInternal::setupParamDisplay (editFields[2], settings); | |||
editFields[2]->setAutosizeFlags (kAutosizeRight|kAutosizeBottom); | |||
editFields[2]->setStringToValueFunction (convertColorValue); | |||
editFields[2]->setValueToStringFunction (convertColorValueToString); | |||
addView (editFields[2]); | |||
r.offset (0, yMargin + yMargin + controlHeight); | |||
editFields[3] = new CTextEdit (r, this, kHueTag, nullptr); | |||
CColorChooserInternal::setupParamDisplay (editFields[3], settings); | |||
editFields[3]->setAutosizeFlags (kAutosizeRight|kAutosizeBottom); | |||
editFields[3]->setStringToValueFunction (convertColorValue); | |||
editFields[3]->setValueToStringFunction (convertColorValueToString); | |||
addView (editFields[3]); | |||
r.offset (0, yMargin + controlHeight); | |||
editFields[4] = new CTextEdit (r, this, kSaturationTag, nullptr); | |||
CColorChooserInternal::setupParamDisplay (editFields[4], settings); | |||
editFields[4]->setAutosizeFlags (kAutosizeRight|kAutosizeBottom); | |||
editFields[4]->setStringToValueFunction (convertColorValue); | |||
editFields[4]->setValueToStringFunction (convertColorValueToString); | |||
addView (editFields[4]); | |||
r.offset (0, yMargin + controlHeight); | |||
editFields[5] = new CTextEdit (r, this, kBrightnessTag, nullptr); | |||
CColorChooserInternal::setupParamDisplay (editFields[5], settings); | |||
editFields[5]->setAutosizeFlags (kAutosizeRight|kAutosizeBottom); | |||
editFields[5]->setStringToValueFunction (convertColorValue); | |||
editFields[5]->setValueToStringFunction (convertColorValueToString); | |||
addView (editFields[5]); | |||
r.offset (0, yMargin + yMargin + controlHeight); | |||
editFields[6] = new CTextEdit (r, this, kAlphaTag, nullptr); | |||
CColorChooserInternal::setupParamDisplay (editFields[6], settings); | |||
editFields[6]->setAutosizeFlags (kAutosizeRight|kAutosizeBottom); | |||
editFields[6]->setStringToValueFunction (convertColorValue); | |||
editFields[6]->setValueToStringFunction (convertColorValueToString); | |||
addView (editFields[6]); | |||
updateState (); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CColorChooser::valueChanged (CControl* control) | |||
{ | |||
switch (control->getTag ()) | |||
{ | |||
case kRedTag: | |||
{ | |||
color.red = (uint8_t) (control->getValue () * 255.f); | |||
break; | |||
} | |||
case kGreenTag: | |||
{ | |||
color.green = (uint8_t) (control->getValue () * 255.f); | |||
break; | |||
} | |||
case kBlueTag: | |||
{ | |||
color.blue = (uint8_t) (control->getValue () * 255.f); | |||
break; | |||
} | |||
case kAlphaTag: | |||
{ | |||
color.alpha = (uint8_t) (control->getValue () * 255.f); | |||
break; | |||
} | |||
case kHueTag: | |||
{ | |||
double hue, saturation, value; | |||
color.toHSV (hue, saturation, value); | |||
hue = control->getValue () * 359.; | |||
color.fromHSV (hue, saturation, value); | |||
break; | |||
} | |||
case kSaturationTag: | |||
{ | |||
double hue, saturation, value; | |||
color.toHSV (hue, saturation, value); | |||
saturation = control->getValue (); | |||
color.fromHSV (hue, saturation, value); | |||
break; | |||
} | |||
case kBrightnessTag: | |||
{ | |||
double hue, saturation, value; | |||
color.toHSV (hue, saturation, value); | |||
value = control->getValue (); | |||
color.fromHSV (hue, saturation, value); | |||
break; | |||
} | |||
case kColorTag: | |||
{ | |||
color = colorView->getColor (); | |||
} | |||
} | |||
updateState (); | |||
if (delegate) | |||
delegate->colorChanged (this, color); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CColorChooser::controlBeginEdit (CControl* pControl) | |||
{ | |||
if (delegate) | |||
delegate->onBeginColorChange (this); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CColorChooser::controlEndEdit (CControl* pControl) | |||
{ | |||
if (delegate) | |||
delegate->onEndColorChange (this); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CColorChooser::setColor (const CColor& newColor) | |||
{ | |||
color = newColor; | |||
updateState (); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CColorChooser::updateState () | |||
{ | |||
double hue, saturation, value; | |||
color.toHSV (hue, saturation, value); | |||
redSlider->setValue (color.red / 255.f); | |||
greenSlider->setValue (color.green / 255.f); | |||
blueSlider->setValue (color.blue / 255.f); | |||
alphaSlider->setValue (color.alpha / 255.f); | |||
hueSlider->setValue ((float)(hue / 359.)); | |||
saturationSlider->setValue ((float)saturation); | |||
brightnessSlider->setValue ((float)value); | |||
colorView->setColor (color); | |||
editFields[0]->setValue (redSlider->getValue ()); | |||
editFields[1]->setValue (greenSlider->getValue ()); | |||
editFields[2]->setValue (blueSlider->getValue ()); | |||
editFields[3]->setValue (hueSlider->getValue ()); | |||
editFields[4]->setValue (saturationSlider->getValue ()); | |||
editFields[5]->setValue (brightnessSlider->getValue ()); | |||
editFields[6]->setValue (alphaSlider->getValue ()); | |||
for (int32_t i = 0; i < 7; i++) | |||
editFields[i]->invalid (); | |||
redSlider->invalid (); | |||
greenSlider->invalid (); | |||
blueSlider->invalid (); | |||
alphaSlider->invalid (); | |||
hueSlider->invalid (); | |||
saturationSlider->invalid (); | |||
brightnessSlider->invalid (); | |||
colorView->invalid (); | |||
} | |||
} // VSTGUI |
@@ -0,0 +1,95 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "../vstguifwd.h" | |||
#include "../cviewcontainer.h" | |||
#include "icontrollistener.h" | |||
#include "ctextedit.h" | |||
namespace VSTGUI { | |||
/// @cond ignore | |||
namespace CColorChooserInternal { | |||
class ColorView; | |||
} | |||
/// @endcond | |||
/// @ingroup new_in_4_0 | |||
//----------------------------------------------------------------------------- | |||
class IColorChooserDelegate | |||
{ | |||
public: | |||
virtual void colorChanged (CColorChooser* chooser, const CColor& color) = 0; | |||
virtual void onBeginColorChange (CColorChooser* chooser) = 0; | |||
virtual void onEndColorChange (CColorChooser* chooser) = 0; | |||
}; | |||
//----------------------------------------------------------------------------- | |||
struct CColorChooserUISettings | |||
{ | |||
CFontRef font {kNormalFont}; | |||
CColor fontColor {kWhiteCColor}; | |||
CColor checkerBoardColor1 {kWhiteCColor}; | |||
CColor checkerBoardColor2 {kBlackCColor}; | |||
CPoint margin {5, 5}; | |||
bool checkerBoardBack {true}; | |||
}; | |||
/// @ingroup new_in_4_0 | |||
//----------------------------------------------------------------------------- | |||
class CColorChooser : public CViewContainer, public IControlListener | |||
{ | |||
public: | |||
CColorChooser (IColorChooserDelegate* delegate = 0, const CColor& initialColor = kTransparentCColor, const CColorChooserUISettings& settings = CColorChooserUISettings ()); | |||
~CColorChooser () noexcept override = default; | |||
void setColor (const CColor& newColor); | |||
//----------------------------------------------------------------------------- | |||
protected: | |||
void valueChanged (CControl* pControl) override; | |||
void controlBeginEdit (CControl* pControl) override; | |||
void controlEndEdit (CControl* pControl) override; | |||
void updateState (); | |||
/// @cond ignore | |||
IColorChooserDelegate* delegate; | |||
CColor color; | |||
CSlider* redSlider; | |||
CSlider* greenSlider; | |||
CSlider* blueSlider; | |||
CSlider* hueSlider; | |||
CSlider* saturationSlider; | |||
CSlider* brightnessSlider; | |||
CSlider* alphaSlider; | |||
CTextEdit* editFields[8]; | |||
CColorChooserInternal::ColorView* colorView; | |||
//----------------------------------------------------------------------------- | |||
enum { | |||
kRedTag = 10000, | |||
kGreenTag, | |||
kBlueTag, | |||
kHueTag, | |||
kSaturationTag, | |||
kBrightnessTag, | |||
kAlphaTag, | |||
kColorTag | |||
}; | |||
//----------------------------------------------------------------------------- | |||
static bool convertNormalized (UTF8StringPtr string, float& output, CTextEdit::StringToValueUserData* userData); | |||
static bool convertColorValue (UTF8StringPtr string, float& output, CTextEdit::StringToValueUserData* userData); | |||
static bool convertAngle (UTF8StringPtr string, float& output, CTextEdit::StringToValueUserData* userData); | |||
static bool convertNormalizedToString (float value, char string[256], CParamDisplay::ValueToStringUserData* userData); | |||
static bool convertColorValueToString (float value, char string[256], CParamDisplay::ValueToStringUserData* userData); | |||
static bool convertAngleToString (float value, char string[256], CParamDisplay::ValueToStringUserData* userData); | |||
/// @endcond | |||
}; | |||
} // VSTGUI |
@@ -0,0 +1,264 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#include "ccontrol.h" | |||
#include "icontrollistener.h" | |||
#include "../cframe.h" | |||
#include "../cgraphicspath.h" | |||
#include <cassert> | |||
#define VSTGUI_CCONTROL_LOG_EDITING 0 //DEBUG | |||
namespace VSTGUI { | |||
//------------------------------------------------------------------------ | |||
// CControl | |||
//------------------------------------------------------------------------ | |||
/*! @class CControl | |||
This object manages the tag identification and the value of a control object. | |||
*/ | |||
CControl::CControl (const CRect& size, IControlListener* listener, int32_t tag, CBitmap *pBackground) | |||
: CView (size) | |||
, listener (listener) | |||
, tag (tag) | |||
, oldValue (1) | |||
, defaultValue (0.5f) | |||
, value (0) | |||
, vmin (0) | |||
, vmax (1.f) | |||
, wheelInc (0.1f) | |||
, editing (0) | |||
{ | |||
setTransparency (false); | |||
setMouseEnabled (true); | |||
setBackground (pBackground); | |||
} | |||
//------------------------------------------------------------------------ | |||
CControl::CControl (const CControl& c) | |||
: CView (c) | |||
, listener (c.listener) | |||
, tag (c.tag) | |||
, oldValue (c.oldValue) | |||
, defaultValue (c.defaultValue) | |||
, value (c.value) | |||
, vmin (c.vmin) | |||
, vmax (c.vmax) | |||
, wheelInc (c.wheelInc) | |||
, editing (0) | |||
{ | |||
} | |||
//------------------------------------------------------------------------ | |||
void CControl::registerControlListener (IControlListener* subListener) | |||
{ | |||
vstgui_assert (listener != subListener, "the subListener is already the main listener"); | |||
subListeners.add (subListener); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CControl::unregisterControlListener (IControlListener* subListener) | |||
{ | |||
subListeners.remove (subListener); | |||
} | |||
//------------------------------------------------------------------------ | |||
int32_t CControl::kZoomModifier = kShift; | |||
int32_t CControl::kDefaultValueModifier = kControl; | |||
//------------------------------------------------------------------------ | |||
void CControl::setTag (int32_t val) | |||
{ | |||
if (listener) | |||
listener->controlTagWillChange (this); | |||
tag = val; | |||
if (listener) | |||
listener->controlTagDidChange (this); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CControl::beginEdit () | |||
{ | |||
// begin of edit parameter | |||
editing++; | |||
if (editing == 1) | |||
{ | |||
if (listener) | |||
listener->controlBeginEdit (this); | |||
subListeners.forEach ([this] (IControlListener* l) { l->controlBeginEdit (this); }); | |||
if (getFrame ()) | |||
getFrame ()->beginEdit (tag); | |||
} | |||
#if VSTGUI_CCONTROL_LOG_EDITING | |||
DebugPrint("beginEdit [%d] - %d\n", tag, editing); | |||
#endif | |||
} | |||
//------------------------------------------------------------------------ | |||
void CControl::endEdit () | |||
{ | |||
editing--; | |||
vstgui_assert(editing >= 0); | |||
if (editing == 0) | |||
{ | |||
if (getFrame ()) | |||
getFrame ()->endEdit (tag); | |||
if (listener) | |||
listener->controlEndEdit (this); | |||
subListeners.forEach ([this] (IControlListener* l) { l->controlEndEdit (this); }); | |||
} | |||
#if VSTGUI_CCONTROL_LOG_EDITING | |||
DebugPrint("endEdit [%d] - %d\n", tag, editing); | |||
#endif | |||
} | |||
//------------------------------------------------------------------------ | |||
void CControl::setValue (float val) | |||
{ | |||
if (val < getMin ()) | |||
val = getMin (); | |||
else if (val > getMax ()) | |||
val = getMax (); | |||
if (val != value) | |||
{ | |||
value = val; | |||
} | |||
} | |||
//------------------------------------------------------------------------ | |||
void CControl::setValueNormalized (float val) | |||
{ | |||
if (val > 1.f) | |||
val = 1.f; | |||
else if (val < 0.f) | |||
val = 0.f; | |||
setValue (getRange () * val + getMin ()); | |||
} | |||
//------------------------------------------------------------------------ | |||
float CControl::getValueNormalized () const | |||
{ | |||
return (value - getMin ()) / getRange (); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CControl::valueChanged () | |||
{ | |||
if (listener) | |||
listener->valueChanged (this); | |||
subListeners.forEach ([this] (IControlListener* l) { l->valueChanged (this); }); | |||
} | |||
//------------------------------------------------------------------------ | |||
bool CControl::isDirty () const | |||
{ | |||
if (getOldValue () != value || CView::isDirty ()) | |||
return true; | |||
return false; | |||
} | |||
//------------------------------------------------------------------------ | |||
void CControl::setDirty (bool val) | |||
{ | |||
CView::setDirty (val); | |||
if (val) | |||
{ | |||
if (value != -1.f) | |||
setOldValue (-1.f); | |||
else | |||
setOldValue (0.f); | |||
} | |||
else | |||
setOldValue (value); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CControl::bounceValue () | |||
{ | |||
if (value > getMax ()) | |||
value = getMax (); | |||
else if (value < getMin ()) | |||
value = getMin (); | |||
} | |||
//----------------------------------------------------------------------------- | |||
bool CControl::checkDefaultValue (CButtonState button) | |||
{ | |||
#if TARGET_OS_IPHONE | |||
if (button.isDoubleClick ()) | |||
#else | |||
if (button.isLeftButton () && button.getModifierState () == kDefaultValueModifier) | |||
#endif | |||
{ | |||
float defValue = getDefaultValue (); | |||
if (defValue != getValue ()) | |||
{ | |||
// begin of edit parameter | |||
beginEdit (); | |||
setValue (defValue); | |||
valueChanged (); | |||
// end of edit parameter | |||
endEdit (); | |||
setDirty (); | |||
} | |||
return true; | |||
} | |||
return false; | |||
} | |||
//------------------------------------------------------------------------ | |||
bool CControl::drawFocusOnTop () | |||
{ | |||
return false; | |||
} | |||
//------------------------------------------------------------------------ | |||
bool CControl::getFocusPath (CGraphicsPath& outPath) | |||
{ | |||
if (wantsFocus ()) | |||
{ | |||
CCoord focusWidth = getFrame ()->getFocusWidth (); | |||
CRect r (getVisibleViewSize ()); | |||
if (!r.isEmpty ()) | |||
{ | |||
outPath.addRect (r); | |||
r.extend (focusWidth, focusWidth); | |||
outPath.addRect (r); | |||
} | |||
} | |||
return true; | |||
} | |||
//----------------------------------------------------------------------------- | |||
int32_t CControl::mapVstKeyModifier (int32_t vstModifier) | |||
{ | |||
int32_t modifiers = 0; | |||
if (vstModifier & MODIFIER_SHIFT) | |||
modifiers |= kShift; | |||
if (vstModifier & MODIFIER_ALTERNATE) | |||
modifiers |= kAlt; | |||
if (vstModifier & MODIFIER_COMMAND) | |||
modifiers |= kApple; | |||
if (vstModifier & MODIFIER_CONTROL) | |||
modifiers |= kControl; | |||
return modifiers; | |||
} | |||
//------------------------------------------------------------------------ | |||
//------------------------------------------------------------------------ | |||
//------------------------------------------------------------------------ | |||
void IMultiBitmapControl::autoComputeHeightOfOneImage () | |||
{ | |||
CView* view = dynamic_cast<CView*>(this); | |||
if (view) | |||
{ | |||
CRect viewSize = view->getViewSize (); | |||
heightOfOneImage = viewSize.getHeight (); | |||
} | |||
} | |||
} // VSTGUI |
@@ -0,0 +1,148 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "../cview.h" | |||
#include "../ifocusdrawing.h" | |||
#include "../idependency.h" | |||
#include "../dispatchlist.h" | |||
#include "icontrollistener.h" | |||
#include <list> | |||
namespace VSTGUI { | |||
namespace Constants { | |||
static constexpr auto pi = 3.14159265358979323846; | |||
static constexpr auto double_pi = 6.28318530717958647692; | |||
static constexpr auto half_pi = 1.57079632679489661923f; | |||
static constexpr auto quarter_pi = 0.78539816339744830962; | |||
static constexpr auto e = 2.7182818284590452354; | |||
static constexpr auto ln2 = 0.69314718055994530942; | |||
static constexpr auto sqrt2 = 1.41421356237309504880; | |||
} // Constants | |||
//----------------------------------------------------------------------------- | |||
// CControl Declaration | |||
//! @brief base class of all VSTGUI controls | |||
//----------------------------------------------------------------------------- | |||
class CControl : public CView, public IFocusDrawing | |||
{ | |||
public: | |||
CControl (const CRect& size, IControlListener* listener = nullptr, int32_t tag = 0, CBitmap* pBackground = nullptr); | |||
CControl (const CControl& c); | |||
//----------------------------------------------------------------------------- | |||
/// @name Value Methods | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
virtual void setValue (float val); | |||
virtual float getValue () const { return value; } | |||
virtual void setValueNormalized (float val); | |||
virtual float getValueNormalized () const; | |||
virtual void setMin (float val) { vmin = val; bounceValue (); } | |||
virtual float getMin () const { return vmin; } | |||
virtual void setMax (float val) { vmax = val; bounceValue (); } | |||
virtual float getMax () const { return vmax; } | |||
float getRange () const { return getMax () - getMin (); } | |||
virtual void setOldValue (float val) { oldValue = val; } | |||
virtual float getOldValue (void) const { return oldValue; } | |||
virtual void setDefaultValue (float val) { defaultValue = val; } | |||
virtual float getDefaultValue (void) const { return defaultValue; } | |||
virtual void bounceValue (); | |||
virtual bool checkDefaultValue (CButtonState button); | |||
/** notifies listener and dependent objects */ | |||
virtual void valueChanged (); | |||
//@} | |||
//----------------------------------------------------------------------------- | |||
/// @name Editing Methods | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
virtual void setTag (int32_t val); | |||
virtual int32_t getTag () const { return tag; } | |||
virtual void beginEdit (); | |||
virtual void endEdit (); | |||
bool isEditing () const { return editing > 0; } | |||
/** get main listener */ | |||
virtual IControlListener* getListener () const { return listener; } | |||
/** set main listener */ | |||
virtual void setListener (IControlListener* l) { listener = l; } | |||
/** register a sub listener */ | |||
void registerControlListener (IControlListener* listener); | |||
/** unregister a sub listener */ | |||
void unregisterControlListener (IControlListener* listener); | |||
//@} | |||
//----------------------------------------------------------------------------- | |||
/// @name Misc | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
virtual void setWheelInc (float val) { wheelInc = val; } | |||
virtual float getWheelInc () const { return wheelInc; } | |||
//@} | |||
// overrides | |||
void draw (CDrawContext* pContext) override = 0; | |||
bool isDirty () const override; | |||
void setDirty (bool val = true) override; | |||
bool drawFocusOnTop () override; | |||
bool getFocusPath (CGraphicsPath& outPath) override; | |||
/** zoom modifier key, per default is the shift key */ | |||
static int32_t kZoomModifier; | |||
/** default value modifier key, per default is the control key */ | |||
static int32_t kDefaultValueModifier; | |||
CLASS_METHODS_VIRTUAL(CControl, CView) | |||
protected: | |||
~CControl () noexcept override = default; | |||
static int32_t mapVstKeyModifier (int32_t vstModifier); | |||
using SubListenerDispatcher = DispatchList<IControlListener*>; | |||
IControlListener* listener; | |||
SubListenerDispatcher subListeners; | |||
int32_t tag; | |||
float oldValue; | |||
float defaultValue; | |||
float value; | |||
float vmin; | |||
float vmax; | |||
float wheelInc; | |||
int32_t editing; | |||
}; | |||
//----------------------------------------------------------------------------- | |||
// IMultiBitmapControl Declaration | |||
//! @brief interface for controls with sub images | |||
//----------------------------------------------------------------------------- | |||
class IMultiBitmapControl | |||
{ | |||
public: | |||
virtual ~IMultiBitmapControl() {} | |||
virtual void setHeightOfOneImage (const CCoord& height) { heightOfOneImage = height; } | |||
virtual CCoord getHeightOfOneImage () const { return heightOfOneImage; } | |||
virtual void setNumSubPixmaps (int32_t numSubPixmaps) { subPixmaps = numSubPixmaps; } | |||
virtual int32_t getNumSubPixmaps () const { return subPixmaps; } | |||
virtual void autoComputeHeightOfOneImage (); | |||
protected: | |||
IMultiBitmapControl () : heightOfOneImage (0), subPixmaps (0) {} | |||
CCoord heightOfOneImage; | |||
int32_t subPixmaps; | |||
}; | |||
} // VSTGUI |
@@ -0,0 +1,297 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#include "cfontchooser.h" | |||
#include "../cdatabrowser.h" | |||
#include "cbuttons.h" | |||
#include "ctextedit.h" | |||
#include "cscrollbar.h" | |||
#include "../cstring.h" | |||
#include "../platform/iplatformfont.h" | |||
#include <list> | |||
#include <cmath> | |||
namespace VSTGUI { | |||
/// @cond ignore | |||
namespace CFontChooserInternal { | |||
class FontPreviewView : public CView | |||
{ | |||
public: | |||
FontPreviewView (const CRect& size, const CColor& color = kWhiteCColor) : CView (size), font (nullptr), fontColor (color) {} | |||
~FontPreviewView () noexcept override { if (font) font->forget (); } | |||
void setFont (CFontRef newFont) | |||
{ | |||
if (font) | |||
font->forget (); | |||
font = newFont; | |||
if (font) | |||
font->remember (); | |||
invalid (); | |||
} | |||
void draw (CDrawContext *context) override | |||
{ | |||
context->setFontColor (fontColor); | |||
context->setFont (font); | |||
std::string text; | |||
char string[2]; | |||
CRect glyphRect (getViewSize ().left, getViewSize ().top, getViewSize ().left, getViewSize ().top); | |||
CCoord height = ceil (font->getPlatformFont ()->getAscent () + font->getPlatformFont ()->getDescent () + font->getPlatformFont ()->getLeading () + 2.); | |||
glyphRect.setHeight (height); | |||
for (int8_t i = 33; i < 126;) | |||
{ | |||
while (glyphRect.right < getViewSize ().right && i < 126) | |||
{ | |||
sprintf (string, "%c", i++); | |||
text += string; | |||
glyphRect.setWidth (context->getStringWidth (text.c_str ())); | |||
} | |||
context->drawString (text.c_str (), glyphRect, kLeftText); | |||
glyphRect.left = glyphRect.right = getViewSize ().left; | |||
glyphRect.offset (0, height); | |||
text = ""; | |||
} | |||
setDirty (false); | |||
} | |||
protected: | |||
CFontRef font; | |||
CColor fontColor; | |||
}; | |||
enum { | |||
kFontChooserSizeTag, | |||
kFontChooserBoldTag, | |||
kFontChooserItalicTag, | |||
kFontChooserUnderlineTag, | |||
kFontChooserStrikeoutTag | |||
}; | |||
} // CFontChooserInternal | |||
/// @endcond | |||
//----------------------------------------------------------------------------- | |||
//----------------------------------------------------------------------------- | |||
//----------------------------------------------------------------------------- | |||
CFontChooser::CFontChooser (IFontChooserDelegate* delegate, CFontRef initialFont, const CFontChooserUIDefinition& uiDef) | |||
: CViewContainer (CRect (0, 0, 300, 500)) | |||
, delegate (nullptr) | |||
, fontBrowser (nullptr) | |||
, selFont (nullptr) | |||
{ | |||
std::list<std::string> fnList; | |||
IPlatformFont::getAllPlatformFontFamilies (fnList); | |||
fnList.sort (); | |||
std::list<std::string>::const_iterator it = fnList.begin (); | |||
while (it != fnList.end ()) | |||
{ | |||
fontNames.emplace_back (*it); | |||
++it; | |||
} | |||
GenericStringListDataBrowserSource* dbSource = new GenericStringListDataBrowserSource (&fontNames, this); | |||
dbSource->setupUI (uiDef.selectionColor, uiDef.fontColor, uiDef.rowlineColor, uiDef.rowBackColor, uiDef.rowAlternateBackColor, uiDef.font, uiDef.rowHeight); | |||
int32_t dbStyle = CDataBrowser::kDrawRowLines | CScrollView::kVerticalScrollbar | CScrollView::kDontDrawFrame | CScrollView::kOverlayScrollbars; | |||
fontBrowser = new CDataBrowser (CRect (0, 0, 200, 500), dbSource, dbStyle, uiDef.scrollbarWidth); | |||
dbSource->forget (); | |||
fontBrowser->setAutosizeFlags (kAutosizeLeft | kAutosizeTop | kAutosizeBottom); | |||
fontBrowser->setTransparency (true); | |||
CScrollbar* scrollbar = fontBrowser->getVerticalScrollbar (); | |||
if (scrollbar) | |||
{ | |||
scrollbar->setBackgroundColor (uiDef.scrollbarBackgroundColor); | |||
scrollbar->setFrameColor (uiDef.scrollbarFrameColor); | |||
scrollbar->setScrollerColor (uiDef.scrollbarScrollerColor); | |||
} | |||
addView (fontBrowser); | |||
CRect controlRect (210, 0, 300, 20); | |||
CTextLabel* label = new CTextLabel (controlRect, "Size:"); | |||
label->setFont (uiDef.font); | |||
label->setFontColor (uiDef.fontColor); | |||
label->sizeToFit (); | |||
label->setHoriAlign (kLeftText); | |||
label->setTransparency (true); | |||
label->setAutosizeFlags (kAutosizeLeft | kAutosizeTop); | |||
addView (label); | |||
CRect teRect = label->getViewSize (); | |||
teRect.left = teRect.right + 5.; | |||
teRect.right = controlRect.right; | |||
sizeEdit = new CTextEdit (teRect, this, CFontChooserInternal::kFontChooserSizeTag); | |||
sizeEdit->setFont (uiDef.font); | |||
sizeEdit->setFontColor (uiDef.fontColor); | |||
sizeEdit->setHoriAlign (kLeftText); | |||
sizeEdit->setTransparency (true); | |||
sizeEdit->setAutosizeFlags (kAutosizeLeft | kAutosizeTop); | |||
sizeEdit->setMax (2000); | |||
sizeEdit->setMin (6); | |||
sizeEdit->setValue (2000); | |||
sizeEdit->sizeToFit (); | |||
sizeEdit->setStringToValueFunction ([] (UTF8StringPtr txt, float& result, CTextEdit* textEdit) { result = UTF8StringView (txt).toFloat (); return true; }); | |||
addView (sizeEdit); | |||
controlRect.offset (0, 20); | |||
boldBox = new CCheckBox (controlRect, this, CFontChooserInternal::kFontChooserBoldTag, "Bold"); | |||
boldBox->setFont (uiDef.font); | |||
boldBox->setFontColor (uiDef.fontColor); | |||
boldBox->setAutosizeFlags (kAutosizeLeft | kAutosizeTop); | |||
boldBox->sizeToFit (); | |||
addView (boldBox); | |||
controlRect.offset (0, 20); | |||
italicBox = new CCheckBox (controlRect, this, CFontChooserInternal::kFontChooserItalicTag, "Italic"); | |||
italicBox->setFont (uiDef.font); | |||
italicBox->setFontColor (uiDef.fontColor); | |||
italicBox->setAutosizeFlags (kAutosizeLeft | kAutosizeTop); | |||
italicBox->sizeToFit (); | |||
addView (italicBox); | |||
controlRect.offset (0, 20); | |||
underlineBox = new CCheckBox (controlRect, this, CFontChooserInternal::kFontChooserUnderlineTag, "Underline"); | |||
underlineBox->setFont (uiDef.font); | |||
underlineBox->setFontColor (uiDef.fontColor); | |||
underlineBox->setAutosizeFlags (kAutosizeLeft | kAutosizeTop); | |||
underlineBox->sizeToFit (); | |||
addView (underlineBox); | |||
controlRect.offset (0, 20); | |||
strikeoutBox = new CCheckBox (controlRect, this, CFontChooserInternal::kFontChooserStrikeoutTag, "Strikeout"); | |||
strikeoutBox->setFont (uiDef.font); | |||
strikeoutBox->setFontColor (uiDef.fontColor); | |||
strikeoutBox->setAutosizeFlags (kAutosizeLeft | kAutosizeTop); | |||
strikeoutBox->sizeToFit (); | |||
addView (strikeoutBox); | |||
CViewContainer* container = new CViewContainer (CRect (controlRect.left, controlRect.bottom+10, 300, 500)); | |||
container->setBackgroundColor (uiDef.previewBackgroundColor); | |||
container->setAutosizeFlags (kAutosizeTop | kAutosizeBottom | kAutosizeLeft | kAutosizeRight); | |||
fontPreviewView = new CFontChooserInternal::FontPreviewView (CRect (10, 10, container->getWidth () - 10, container->getHeight () - 10), uiDef.previewTextColor); | |||
fontPreviewView->setAutosizeFlags (kAutosizeAll); | |||
container->addView (fontPreviewView); | |||
addView (container); | |||
setFont (initialFont ? initialFont : kSystemFont); | |||
sizeToFit (); | |||
this->delegate = delegate; | |||
} | |||
//----------------------------------------------------------------------------- | |||
CFontChooser::~CFontChooser () noexcept | |||
{ | |||
if (selFont) | |||
selFont->forget (); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CFontChooser::setFont (CFontRef font) | |||
{ | |||
if (font) | |||
{ | |||
if (selFont) | |||
selFont->forget (); | |||
selFont = new CFontDesc (*font); | |||
sizeEdit->setValue ((float)font->getSize ()); | |||
boldBox->setValue ((font->getStyle () & kBoldFace) ? 1.f : 0.f); | |||
italicBox->setValue ((font->getStyle () & kItalicFace) ? 1.f : 0.f); | |||
underlineBox->setValue ((font->getStyle () & kUnderlineFace) ? 1.f : 0.f); | |||
strikeoutBox->setValue ((font->getStyle () & kStrikethroughFace) ? 1.f : 0.f); | |||
auto it = fontNames.begin (); | |||
int32_t row = 0; | |||
while (it != fontNames.end ()) | |||
{ | |||
if (*it == font->getName ()) | |||
{ | |||
fontBrowser->setSelectedRow (row, true); | |||
break; | |||
} | |||
++it; | |||
row++; | |||
} | |||
static_cast<CFontChooserInternal::FontPreviewView*> (fontPreviewView)->setFont (selFont); | |||
} | |||
invalid (); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CFontChooser::valueChanged (CControl* pControl) | |||
{ | |||
if (selFont == nullptr) | |||
return; | |||
switch (pControl->getTag ()) | |||
{ | |||
case CFontChooserInternal::kFontChooserSizeTag: | |||
{ | |||
pControl->setValue (pControl->getValue ()); | |||
selFont->setSize (pControl->getValue ()); | |||
break; | |||
} | |||
case CFontChooserInternal::kFontChooserBoldTag: | |||
{ | |||
if (pControl->getValue () == 1) | |||
selFont->setStyle (selFont->getStyle () | kBoldFace); | |||
else | |||
selFont->setStyle (selFont->getStyle () & ~kBoldFace); | |||
break; | |||
} | |||
case CFontChooserInternal::kFontChooserItalicTag: | |||
{ | |||
if (pControl->getValue () == 1) | |||
selFont->setStyle (selFont->getStyle () | kItalicFace); | |||
else | |||
selFont->setStyle (selFont->getStyle () & ~kItalicFace); | |||
break; | |||
} | |||
case CFontChooserInternal::kFontChooserUnderlineTag: | |||
{ | |||
if (pControl->getValue () == 1) | |||
selFont->setStyle (selFont->getStyle () | kUnderlineFace); | |||
else | |||
selFont->setStyle (selFont->getStyle () & ~kUnderlineFace); | |||
break; | |||
} | |||
case CFontChooserInternal::kFontChooserStrikeoutTag: | |||
{ | |||
if (pControl->getValue () == 1) | |||
selFont->setStyle (selFont->getStyle () | kStrikethroughFace); | |||
else | |||
selFont->setStyle (selFont->getStyle () & ~kStrikethroughFace); | |||
break; | |||
} | |||
} | |||
if (delegate) | |||
delegate->fontChanged (this, selFont); | |||
static_cast<CFontChooserInternal::FontPreviewView*> (fontPreviewView)->setFont (selFont); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CFontChooser::dbSelectionChanged (int32_t selectedRow, GenericStringListDataBrowserSource* source) | |||
{ | |||
if (selectedRow >= 0 && static_cast<size_t> (selectedRow) <= fontNames.size ()) | |||
selFont->setName (fontNames[static_cast<size_t> (selectedRow)].data ()); | |||
static_cast<CFontChooserInternal::FontPreviewView*> (fontPreviewView)->setFont (selFont); | |||
if (delegate) | |||
delegate->fontChanged (this, selFont); | |||
} | |||
//----------------------------------------------------------------------------- | |||
bool CFontChooser::attached (CView* parent) | |||
{ | |||
if (CViewContainer::attached (parent)) | |||
{ | |||
fontBrowser->makeRowVisible (fontBrowser->getSelectedRow ()); | |||
return true; | |||
} | |||
return false; | |||
} | |||
//----------------------------------------------------------------------------- | |||
int32_t CFontChooser::onKeyDown (VstKeyCode& keyCode) | |||
{ | |||
return fontBrowser->onKeyDown (keyCode); | |||
} | |||
} // VSTGUI |
@@ -0,0 +1,92 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "../vstguifwd.h" | |||
#include "../cviewcontainer.h" | |||
#include "../cfont.h" | |||
#include "../cdatabrowser.h" | |||
#include "../genericstringlistdatabrowsersource.h" | |||
#include "icontrollistener.h" | |||
namespace VSTGUI { | |||
/// @ingroup new_in_4_0 | |||
//----------------------------------------------------------------------------- | |||
class IFontChooserDelegate | |||
{ | |||
public: | |||
virtual void fontChanged (CFontChooser* chooser, CFontRef newFont) = 0; | |||
}; | |||
/// @ingroup new_in_4_0 | |||
//----------------------------------------------------------------------------- | |||
struct CFontChooserUIDefinition | |||
{ | |||
CFontRef font; | |||
int32_t rowHeight; | |||
CColor fontColor; | |||
CColor selectionColor; | |||
CColor rowlineColor; | |||
CColor rowBackColor; | |||
CColor rowAlternateBackColor; | |||
CColor previewTextColor; | |||
CColor previewBackgroundColor; | |||
CColor scrollbarScrollerColor; | |||
CColor scrollbarFrameColor; | |||
CColor scrollbarBackgroundColor; | |||
CCoord scrollbarWidth; | |||
CFontChooserUIDefinition (CFontRef font = kSystemFont, | |||
const CColor& fontColor = kWhiteCColor, | |||
const CColor& selectionColor = kBlueCColor, | |||
const CColor& rowlineColor = kGreyCColor, | |||
const CColor& rowBackColor = kTransparentCColor, | |||
const CColor& rowAlternateBackColor = kTransparentCColor, | |||
const CColor& previewTextColor = kBlackCColor, | |||
const CColor& previewBackgroundColor = kWhiteCColor, | |||
const CColor& scrollbarScrollerColor = kBlueCColor, | |||
const CColor& scrollbarFrameColor = kBlackCColor, | |||
const CColor& scrollbarBackgroundColor = kGreyCColor, | |||
int32_t rowHeight = -1, | |||
CCoord scrollbarWidth = 16) | |||
: font (font), rowHeight (rowHeight), fontColor (fontColor), selectionColor (selectionColor), rowlineColor (rowlineColor) | |||
, rowBackColor (rowBackColor), rowAlternateBackColor (rowAlternateBackColor), previewTextColor (previewTextColor), previewBackgroundColor (previewBackgroundColor) | |||
, scrollbarScrollerColor (scrollbarScrollerColor), scrollbarFrameColor (scrollbarFrameColor) | |||
, scrollbarBackgroundColor (scrollbarBackgroundColor), scrollbarWidth (scrollbarWidth) | |||
{} | |||
}; | |||
/// @ingroup new_in_4_0 | |||
//----------------------------------------------------------------------------- | |||
class CFontChooser : public CViewContainer, public IControlListener, public GenericStringListDataBrowserSourceSelectionChanged | |||
{ | |||
public: | |||
CFontChooser (IFontChooserDelegate* delegate, CFontRef initialFont = nullptr, const CFontChooserUIDefinition& uiDef = CFontChooserUIDefinition ()); | |||
~CFontChooser () noexcept override; | |||
void setFont (CFontRef font); | |||
protected: | |||
void dbSelectionChanged (int32_t selectedRow, GenericStringListDataBrowserSource* source) override; | |||
void valueChanged (CControl* pControl) override; | |||
bool attached (CView* parent) override; | |||
int32_t onKeyDown (VstKeyCode& keyCode) override; | |||
IFontChooserDelegate* delegate; | |||
CDataBrowser* fontBrowser; | |||
CTextEdit* sizeEdit; | |||
CCheckBox* boldBox; | |||
CCheckBox* italicBox; | |||
CCheckBox* underlineBox; | |||
CCheckBox* strikeoutBox; | |||
CView* fontPreviewView; | |||
GenericStringListDataBrowserSource::StringVector fontNames; | |||
CFontRef selFont; | |||
}; | |||
} // VSTGUI | |||
@@ -0,0 +1,816 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#include "cknob.h" | |||
#include "../cbitmap.h" | |||
#include "../cdrawcontext.h" | |||
#include "../cframe.h" | |||
#include "../cgraphicspath.h" | |||
#include <cmath> | |||
namespace VSTGUI { | |||
#if TARGET_OS_IPHONE | |||
static const float kCKnobRange = 300.f; | |||
#else | |||
static const float kCKnobRange = 200.f; | |||
#endif | |||
static constexpr CViewAttributeID kCKnobMouseStateAttribute = 'knms'; | |||
//------------------------------------------------------------------------ | |||
struct CKnob::MouseEditingState | |||
{ | |||
CPoint firstPoint; | |||
CPoint lastPoint; | |||
float startValue; | |||
float entryState; | |||
float range; | |||
float coef; | |||
CButtonState oldButton; | |||
bool modeLinear; | |||
}; | |||
//------------------------------------------------------------------------ | |||
// CKnob | |||
//------------------------------------------------------------------------ | |||
/*! @class CKnob | |||
Define a knob with a given background and foreground handle. | |||
The handle describes a circle over the background (between -45deg and +225deg). | |||
By clicking alt modifier and left mouse button the default value is used. | |||
By clicking alt modifier and left mouse button the value changes with a vertical move (version 2.1) | |||
*/ | |||
//------------------------------------------------------------------------ | |||
/** | |||
* CKnob constructor. | |||
* @param size the size of this view | |||
* @param listener the listener | |||
* @param tag the control tag | |||
* @param background background bitmap | |||
* @param handle handle bitmap | |||
* @param offset offset of background bitmap | |||
* @param drawStyle draw style | |||
*/ | |||
//------------------------------------------------------------------------ | |||
CKnob::CKnob (const CRect& size, IControlListener* listener, int32_t tag, CBitmap* background, CBitmap* handle, const CPoint& offset, int32_t drawStyle) | |||
: CControl (size, listener, tag, background) | |||
, offset (offset) | |||
, drawStyle (drawStyle) | |||
, handleLineWidth (1.) | |||
, coronaInset (0) | |||
, coronaOutlineWidthAdd (2.) | |||
, pHandle (handle) | |||
{ | |||
if (pHandle) | |||
{ | |||
pHandle->remember (); | |||
inset = (CCoord)((float)pHandle->getWidth () / 2.f + 2.5f); | |||
} | |||
else | |||
{ | |||
inset = 3; | |||
} | |||
colorShadowHandle = kGreyCColor; | |||
colorHandle = kWhiteCColor; | |||
rangeAngle = 1.f; | |||
setStartAngle ((float)(3.f * Constants::quarter_pi)); | |||
setRangeAngle ((float)(3.f * Constants::half_pi)); | |||
zoomFactor = 1.5f; | |||
setWantsFocus (true); | |||
} | |||
//------------------------------------------------------------------------ | |||
CKnob::CKnob (const CKnob& v) | |||
: CControl (v) | |||
, offset (v.offset) | |||
, drawStyle (v.drawStyle) | |||
, colorHandle (v.colorHandle) | |||
, colorShadowHandle (v.colorShadowHandle) | |||
, handleLineWidth (v.handleLineWidth) | |||
, inset (v.inset) | |||
, coronaInset (v.coronaInset) | |||
, coronaOutlineWidthAdd (v.coronaInset) | |||
, pHandle (v.pHandle) | |||
, startAngle (v.startAngle) | |||
, rangeAngle (v.rangeAngle) | |||
, zoomFactor (v.zoomFactor) | |||
{ | |||
if (pHandle) | |||
pHandle->remember (); | |||
} | |||
//------------------------------------------------------------------------ | |||
CKnob::~CKnob () noexcept | |||
{ | |||
if (pHandle) | |||
pHandle->forget (); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CKnob::setViewSize (const CRect &rect, bool invalid) | |||
{ | |||
CControl::setViewSize (rect, invalid); | |||
compute (); | |||
} | |||
//------------------------------------------------------------------------ | |||
bool CKnob::sizeToFit () | |||
{ | |||
if (getDrawBackground ()) | |||
{ | |||
CRect vs (getViewSize ()); | |||
vs.setWidth (getDrawBackground ()->getWidth ()); | |||
vs.setHeight (getDrawBackground ()->getHeight ()); | |||
setViewSize (vs); | |||
setMouseableArea (vs); | |||
return true; | |||
} | |||
return false; | |||
} | |||
//------------------------------------------------------------------------ | |||
bool CKnob::drawFocusOnTop () | |||
{ | |||
if (drawStyle & kCoronaDrawing && wantsFocus ()) | |||
{ | |||
return false; | |||
} | |||
return CControl::drawFocusOnTop (); | |||
} | |||
//------------------------------------------------------------------------ | |||
bool CKnob::getFocusPath (CGraphicsPath &outPath) | |||
{ | |||
if (drawStyle & kCoronaDrawing && wantsFocus ()) | |||
{ | |||
CRect corona (getViewSize ()); | |||
corona.inset (coronaInset, coronaInset); | |||
corona.inset (handleLineWidth/2., handleLineWidth/2.); | |||
outPath.addEllipse (corona); | |||
return true; | |||
} | |||
return CControl::getFocusPath (outPath); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CKnob::draw (CDrawContext *pContext) | |||
{ | |||
if (getDrawBackground ()) | |||
{ | |||
getDrawBackground ()->draw (pContext, getViewSize (), offset); | |||
} | |||
if (pHandle) | |||
drawHandle (pContext); | |||
else | |||
{ | |||
if (drawStyle & kCoronaOutline) | |||
drawCoronaOutline (pContext); | |||
if (drawStyle & kCoronaDrawing) | |||
drawCorona (pContext); | |||
if (!(drawStyle & kSkipHandleDrawing)) | |||
{ | |||
if (drawStyle & kHandleCircleDrawing) | |||
drawHandleAsCircle (pContext); | |||
else | |||
drawHandleAsLine (pContext); | |||
} | |||
} | |||
setDirty (false); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CKnob::addArc (CGraphicsPath* path, const CRect& r, double startAngle, double sweepAngle) const | |||
{ | |||
CCoord w = r.getWidth (); | |||
CCoord h = r.getHeight (); | |||
double endAngle = startAngle + sweepAngle; | |||
if (w != h) | |||
{ | |||
startAngle = atan2 (sin (startAngle) * h, cos (startAngle) * w); | |||
endAngle = atan2 (sin (endAngle) * h, cos (endAngle) * w); | |||
} | |||
path->addArc (r, startAngle / Constants::pi * 180, endAngle / Constants::pi * 180, sweepAngle >= 0); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CKnob::drawCoronaOutline (CDrawContext* pContext) const | |||
{ | |||
auto path = owned (pContext->createGraphicsPath ()); | |||
if (path == nullptr) | |||
return; | |||
CRect corona (getViewSize ()); | |||
corona.inset (coronaInset, coronaInset); | |||
addArc (path, corona, startAngle, rangeAngle); | |||
pContext->setFrameColor (colorShadowHandle); | |||
CLineStyle lineStyle (kLineSolid); | |||
if (!(drawStyle & kCoronaLineCapButt)) | |||
lineStyle.setLineCap (CLineStyle::kLineCapRound); | |||
pContext->setLineStyle (lineStyle); | |||
pContext->setLineWidth (handleLineWidth+coronaOutlineWidthAdd); | |||
pContext->setDrawMode (kAntiAliasing | kNonIntegralMode); | |||
pContext->drawGraphicsPath (path, CDrawContext::kPathStroked); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CKnob::drawCorona (CDrawContext* pContext) const | |||
{ | |||
auto path = owned (pContext->createGraphicsPath ()); | |||
if (path == nullptr) | |||
return; | |||
float coronaValue = getValueNormalized (); | |||
if (drawStyle & kCoronaInverted) | |||
coronaValue = 1.f - coronaValue; | |||
CRect corona (getViewSize ()); | |||
corona.inset (coronaInset, coronaInset); | |||
if (drawStyle & kCoronaFromCenter) | |||
addArc (path, corona, 1.5 * Constants::pi, rangeAngle * (coronaValue - 0.5)); | |||
else | |||
{ | |||
if (drawStyle & kCoronaInverted) | |||
addArc (path, corona, startAngle + rangeAngle, -rangeAngle * coronaValue); | |||
else | |||
addArc (path, corona, startAngle, rangeAngle * coronaValue); | |||
} | |||
pContext->setFrameColor (coronaColor); | |||
CLineStyle lineStyle ((drawStyle & kCoronaLineDashDot) ? kLineOnOffDash : kLineSolid); | |||
if (!(drawStyle & kCoronaLineCapButt)) | |||
lineStyle.setLineCap (CLineStyle::kLineCapRound); | |||
if (drawStyle & kCoronaLineDashDot) | |||
lineStyle.getDashLengths ()[1] = 2; | |||
pContext->setLineStyle (lineStyle); | |||
pContext->setLineWidth (handleLineWidth); | |||
pContext->setDrawMode (kAntiAliasing | kNonIntegralMode); | |||
pContext->drawGraphicsPath (path, CDrawContext::kPathStroked); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CKnob::drawHandleAsCircle (CDrawContext* pContext) const | |||
{ | |||
CPoint where; | |||
valueToPoint (where); | |||
where.offset (getViewSize ().left, getViewSize ().top); | |||
CRect r (where.x - 0.5, where.y - 0.5, where.x + 0.5, where.y + 0.5); | |||
r.extend (handleLineWidth, handleLineWidth); | |||
pContext->setDrawMode (kAntiAliasing); | |||
pContext->setFrameColor (colorShadowHandle); | |||
pContext->setFillColor (colorHandle); | |||
pContext->setLineWidth (0.5); | |||
pContext->setLineStyle (kLineSolid); | |||
pContext->setDrawMode (kAntiAliasing | kNonIntegralMode); | |||
pContext->drawEllipse (r, kDrawFilledAndStroked); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CKnob::drawHandleAsLine (CDrawContext* pContext) const | |||
{ | |||
CPoint where; | |||
valueToPoint (where); | |||
CPoint origin (getViewSize ().getWidth () / 2, getViewSize ().getHeight () / 2); | |||
where.offset (getViewSize ().left - 1, getViewSize ().top); | |||
origin.offset (getViewSize ().left - 1, getViewSize ().top); | |||
pContext->setFrameColor (colorShadowHandle); | |||
pContext->setLineWidth (handleLineWidth); | |||
pContext->setLineStyle (CLineStyle (CLineStyle::kLineCapRound)); | |||
pContext->setDrawMode (kAntiAliasing | kNonIntegralMode); | |||
pContext->drawLine (where, origin); | |||
where.offset (1, -1); | |||
origin.offset (1, -1); | |||
pContext->setFrameColor (colorHandle); | |||
pContext->drawLine (where, origin); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CKnob::drawHandle (CDrawContext *pContext) | |||
{ | |||
CPoint where; | |||
valueToPoint (where); | |||
CCoord width = pHandle->getWidth (); | |||
CCoord height = pHandle->getHeight (); | |||
where.offset (getViewSize ().left - width / 2, getViewSize ().top - height / 2); | |||
where.x = floor (where.x); | |||
where.y = floor (where.y); | |||
CRect handleSize (0, 0, width, height); | |||
handleSize.offset (where.x, where.y); | |||
pHandle->draw (pContext, handleSize); | |||
} | |||
//------------------------------------------------------------------------ | |||
auto CKnob::getMouseEditingState () -> MouseEditingState& | |||
{ | |||
MouseEditingState* state = nullptr; | |||
uint32_t size; | |||
if (!getAttribute (kCKnobMouseStateAttribute, sizeof (MouseEditingState*), &state, size)) | |||
{ | |||
state = new MouseEditingState; | |||
setAttribute (kCKnobMouseStateAttribute, sizeof (MouseEditingState*), &state); | |||
} | |||
return *state; | |||
} | |||
//------------------------------------------------------------------------ | |||
void CKnob::clearMouseEditingState () | |||
{ | |||
MouseEditingState* state = nullptr; | |||
uint32_t size; | |||
if (!getAttribute (kCKnobMouseStateAttribute, sizeof (MouseEditingState*), &state, size)) | |||
return; | |||
delete state; | |||
removeAttribute (kCKnobMouseStateAttribute); | |||
} | |||
//------------------------------------------------------------------------ | |||
CMouseEventResult CKnob::onMouseDown (CPoint& where, const CButtonState& buttons) | |||
{ | |||
if (!buttons.isLeftButton ()) | |||
return kMouseEventNotHandled; | |||
beginEdit (); | |||
if (checkDefaultValue (buttons)) | |||
{ | |||
endEdit (); | |||
return kMouseDownEventHandledButDontNeedMovedOrUpEvents; | |||
} | |||
auto& mouseState = getMouseEditingState (); | |||
mouseState.firstPoint = where; | |||
mouseState.lastPoint (-1, -1); | |||
mouseState.startValue = getOldValue (); | |||
mouseState.modeLinear = false; | |||
mouseState.entryState = value; | |||
mouseState.range = kCKnobRange; | |||
mouseState.coef = (getMax () - getMin ()) / mouseState.range; | |||
mouseState.oldButton = buttons; | |||
int32_t mode = kCircularMode; | |||
int32_t newMode = getFrame ()->getKnobMode (); | |||
if (kLinearMode == newMode) | |||
{ | |||
if (!(buttons & kAlt)) | |||
mode = newMode; | |||
} | |||
else if (buttons & kAlt) | |||
{ | |||
mode = kLinearMode; | |||
} | |||
if (mode == kLinearMode) | |||
{ | |||
if (buttons & kZoomModifier) | |||
mouseState.range *= zoomFactor; | |||
mouseState.lastPoint = where; | |||
mouseState.modeLinear = true; | |||
mouseState.coef = (getMax () - getMin ()) / mouseState.range; | |||
} | |||
else | |||
{ | |||
CPoint where2 (where); | |||
where2.offset (-getViewSize ().left, -getViewSize ().top); | |||
mouseState.startValue = valueFromPoint (where2); | |||
mouseState.lastPoint = where; | |||
} | |||
return onMouseMoved (where, buttons); | |||
} | |||
//------------------------------------------------------------------------ | |||
CMouseEventResult CKnob::onMouseUp (CPoint& where, const CButtonState& buttons) | |||
{ | |||
if (isEditing ()) | |||
{ | |||
endEdit (); | |||
clearMouseEditingState (); | |||
} | |||
return kMouseEventHandled; | |||
} | |||
//------------------------------------------------------------------------ | |||
CMouseEventResult CKnob::onMouseCancel () | |||
{ | |||
if (isEditing ()) | |||
{ | |||
auto& mouseState = getMouseEditingState (); | |||
value = mouseState.startValue; | |||
if (isDirty ()) | |||
{ | |||
valueChanged (); | |||
invalid (); | |||
} | |||
endEdit (); | |||
clearMouseEditingState (); | |||
} | |||
return kMouseEventHandled; | |||
} | |||
//------------------------------------------------------------------------ | |||
CMouseEventResult CKnob::onMouseMoved (CPoint& where, const CButtonState& buttons) | |||
{ | |||
if (isEditing ()) | |||
{ | |||
auto& mouseState = getMouseEditingState (); | |||
float middle = (getMax () - getMin ()) * 0.5f; | |||
if (where != mouseState.lastPoint) | |||
{ | |||
mouseState.lastPoint = where; | |||
if (mouseState.modeLinear) | |||
{ | |||
CCoord diff = (mouseState.firstPoint.y - where.y) + (where.x - mouseState.firstPoint.x); | |||
if (buttons != mouseState.oldButton) | |||
{ | |||
mouseState.range = kCKnobRange; | |||
if (buttons & kZoomModifier) | |||
mouseState.range *= zoomFactor; | |||
float coef2 = (getMax () - getMin ()) / mouseState.range; | |||
mouseState.entryState += (float)(diff * (mouseState.coef - coef2)); | |||
mouseState.coef = coef2; | |||
mouseState.oldButton = buttons; | |||
} | |||
value = (float)(mouseState.entryState + diff * mouseState.coef); | |||
bounceValue (); | |||
} | |||
else | |||
{ | |||
where.offset (-getViewSize ().left, -getViewSize ().top); | |||
value = valueFromPoint (where); | |||
if (mouseState.startValue - value > middle) | |||
value = getMax (); | |||
else if (value - mouseState.startValue > middle) | |||
value = getMin (); | |||
else | |||
mouseState.startValue = value; | |||
} | |||
if (value != getOldValue ()) | |||
valueChanged (); | |||
if (isDirty ()) | |||
invalid (); | |||
} | |||
return kMouseEventHandled; | |||
} | |||
return kMouseEventNotHandled; | |||
} | |||
//------------------------------------------------------------------------ | |||
bool CKnob::onWheel (const CPoint& where, const float &distance, const CButtonState &buttons) | |||
{ | |||
if (!getMouseEnabled ()) | |||
return false; | |||
float v = getValueNormalized (); | |||
if (buttons & kZoomModifier) | |||
v += 0.1f * distance * wheelInc; | |||
else | |||
v += distance * wheelInc; | |||
setValueNormalized (v); | |||
if (isDirty ()) | |||
{ | |||
invalid (); | |||
// begin of edit parameter | |||
beginEdit (); | |||
valueChanged (); | |||
// end of edit parameter | |||
endEdit (); | |||
} | |||
return true; | |||
} | |||
//------------------------------------------------------------------------ | |||
int32_t CKnob::onKeyDown (VstKeyCode& keyCode) | |||
{ | |||
switch (keyCode.virt) | |||
{ | |||
case VKEY_UP : | |||
case VKEY_RIGHT : | |||
case VKEY_DOWN : | |||
case VKEY_LEFT : | |||
{ | |||
float distance = 1.f; | |||
if (keyCode.virt == VKEY_DOWN || keyCode.virt == VKEY_LEFT) | |||
distance = -distance; | |||
float v = getValueNormalized (); | |||
if (mapVstKeyModifier (keyCode.modifier) & kZoomModifier) | |||
v += 0.1f * distance * wheelInc; | |||
else | |||
v += distance * wheelInc; | |||
setValueNormalized (v); | |||
if (isDirty ()) | |||
{ | |||
invalid (); | |||
// begin of edit parameter | |||
beginEdit (); | |||
valueChanged (); | |||
// end of edit parameter | |||
endEdit (); | |||
} | |||
} return 1; | |||
} | |||
return -1; | |||
} | |||
//------------------------------------------------------------------------ | |||
void CKnob::setStartAngle (float val) | |||
{ | |||
startAngle = val; | |||
compute (); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CKnob::setRangeAngle (float val) | |||
{ | |||
rangeAngle = val; | |||
compute (); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CKnob::compute () | |||
{ | |||
setDirty (); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CKnob::valueToPoint (CPoint &point) const | |||
{ | |||
float alpha = (value - getMin()) / (getMax() - getMin()); | |||
alpha = startAngle + alpha*rangeAngle; | |||
CPoint c (getViewSize ().getWidth () / 2., getViewSize ().getHeight () / 2.); | |||
double xradius = c.x - inset; | |||
double yradius = c.y - inset; | |||
point.x = (CCoord)(c.x + cosf (alpha) * xradius + 0.5f); | |||
point.y = (CCoord)(c.y + sinf (alpha) * yradius + 0.5f); | |||
} | |||
//------------------------------------------------------------------------ | |||
float CKnob::valueFromPoint (CPoint &point) const | |||
{ | |||
float v; | |||
double d = rangeAngle * 0.5; | |||
double a = startAngle + d; | |||
CPoint c (getViewSize ().getWidth () / 2., getViewSize ().getHeight () / 2.); | |||
double xradius = c.x - inset; | |||
double yradius = c.y - inset; | |||
double dx = (point.x - c.x) / xradius; | |||
double dy = (point.y - c.y) / yradius; | |||
double alpha = atan2 (dy, dx) - a; | |||
while (alpha >= Constants::pi) | |||
alpha -= Constants::double_pi; | |||
while (alpha < -Constants::pi) | |||
alpha += Constants::double_pi; | |||
if (d < 0.0) | |||
alpha = -alpha; | |||
if (alpha > d) | |||
v = getMax (); | |||
else if (alpha < -d) | |||
v = getMin (); | |||
else | |||
v = float (0.5 + alpha / rangeAngle); | |||
v *= (getMax () - getMin ()); | |||
return v; | |||
} | |||
//------------------------------------------------------------------------ | |||
void CKnob::setCoronaInset (CCoord inset) | |||
{ | |||
if (inset != coronaInset) | |||
{ | |||
coronaInset = inset; | |||
setDirty (); | |||
} | |||
} | |||
//------------------------------------------------------------------------ | |||
void CKnob::setCoronaColor (CColor color) | |||
{ | |||
if (color != coronaColor) | |||
{ | |||
coronaColor = color; | |||
setDirty (); | |||
} | |||
} | |||
//------------------------------------------------------------------------ | |||
void CKnob::setColorShadowHandle (CColor color) | |||
{ | |||
if (color != colorShadowHandle) | |||
{ | |||
colorShadowHandle = color; | |||
setDirty (); | |||
} | |||
} | |||
//------------------------------------------------------------------------ | |||
void CKnob::setColorHandle (CColor color) | |||
{ | |||
if (color != colorHandle) | |||
{ | |||
colorHandle = color; | |||
setDirty (); | |||
} | |||
} | |||
//------------------------------------------------------------------------ | |||
void CKnob::setHandleLineWidth (CCoord width) | |||
{ | |||
if (width != handleLineWidth) | |||
{ | |||
handleLineWidth = width; | |||
setDirty (); | |||
} | |||
} | |||
//------------------------------------------------------------------------ | |||
void CKnob::setCoronaOutlineWidthAdd (CCoord width) | |||
{ | |||
if (width != coronaOutlineWidthAdd) | |||
{ | |||
coronaOutlineWidthAdd = width; | |||
setDirty (); | |||
} | |||
} | |||
//------------------------------------------------------------------------ | |||
void CKnob::setDrawStyle (int32_t style) | |||
{ | |||
if (style != drawStyle) | |||
{ | |||
drawStyle = style; | |||
setDirty (); | |||
} | |||
} | |||
//------------------------------------------------------------------------ | |||
void CKnob::setHandleBitmap (CBitmap* bitmap) | |||
{ | |||
if (pHandle) | |||
{ | |||
pHandle->forget (); | |||
pHandle = nullptr; | |||
} | |||
if (bitmap) | |||
{ | |||
pHandle = bitmap; | |||
pHandle->remember (); | |||
inset = (CCoord)((float)pHandle->getWidth () / 2.f + 2.5f); | |||
} | |||
setDirty (); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CKnob::setMin (float val) | |||
{ | |||
CControl::setMin (val); | |||
if (getValue () < val) | |||
setValue (val); | |||
compute (); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CKnob::setMax (float val) | |||
{ | |||
CControl::setMax (val); | |||
if (getValue () > val) | |||
setValue (val); | |||
compute (); | |||
} | |||
//------------------------------------------------------------------------ | |||
// CAnimKnob | |||
//------------------------------------------------------------------------ | |||
/*! @class CAnimKnob | |||
Such as a CKnob control object, but there is a unique bitmap which contains different views (subbitmaps) of this knob. | |||
According to the value, a specific subbitmap is displayed. The different subbitmaps are stacked in the bitmap object. | |||
*/ | |||
//------------------------------------------------------------------------ | |||
/** | |||
* CAnimKnob constructor. | |||
* @param size the size of this view | |||
* @param listener the listener | |||
* @param tag the control tag | |||
* @param background the background bitmap | |||
* @param offset unused | |||
*/ | |||
//------------------------------------------------------------------------ | |||
CAnimKnob::CAnimKnob (const CRect& size, IControlListener* listener, int32_t tag, CBitmap* background, const CPoint &offset) | |||
: CKnob (size, listener, tag, background, nullptr, offset) | |||
, bInverseBitmap (false) | |||
{ | |||
heightOfOneImage = size.getHeight (); | |||
setNumSubPixmaps (background ? (int32_t)(background->getHeight () / heightOfOneImage) : 0); | |||
inset = 0; | |||
} | |||
//------------------------------------------------------------------------ | |||
/** | |||
* CAnimKnob constructor. | |||
* @param size the size of this view | |||
* @param listener the listener | |||
* @param tag the control tag | |||
* @param subPixmaps number of sub bitmaps in background | |||
* @param heightOfOneImage the height of one sub bitmap | |||
* @param background the background bitmap | |||
* @param offset unused | |||
*/ | |||
//------------------------------------------------------------------------ | |||
CAnimKnob::CAnimKnob (const CRect& size, IControlListener* listener, int32_t tag, int32_t subPixmaps, CCoord heightOfOneImage, CBitmap* background, const CPoint &offset) | |||
: CKnob (size, listener, tag, background, nullptr, offset) | |||
, bInverseBitmap (false) | |||
{ | |||
setNumSubPixmaps (subPixmaps); | |||
setHeightOfOneImage (heightOfOneImage); | |||
inset = 0; | |||
} | |||
//------------------------------------------------------------------------ | |||
CAnimKnob::CAnimKnob (const CAnimKnob& v) | |||
: CKnob (v) | |||
, bInverseBitmap (v.bInverseBitmap) | |||
{ | |||
setNumSubPixmaps (v.subPixmaps); | |||
setHeightOfOneImage (v.heightOfOneImage); | |||
} | |||
//----------------------------------------------------------------------------------------------- | |||
bool CAnimKnob::sizeToFit () | |||
{ | |||
if (getDrawBackground ()) | |||
{ | |||
CRect vs (getViewSize ()); | |||
vs.setWidth (getDrawBackground ()->getWidth ()); | |||
vs.setHeight (getHeightOfOneImage ()); | |||
setViewSize (vs); | |||
setMouseableArea (vs); | |||
return true; | |||
} | |||
return false; | |||
} | |||
//----------------------------------------------------------------------------------------------- | |||
void CAnimKnob::setHeightOfOneImage (const CCoord& height) | |||
{ | |||
IMultiBitmapControl::setHeightOfOneImage (height); | |||
if (getDrawBackground () && heightOfOneImage > 0) | |||
setNumSubPixmaps ((int32_t)(getDrawBackground ()->getHeight () / heightOfOneImage)); | |||
} | |||
//----------------------------------------------------------------------------------------------- | |||
void CAnimKnob::setBackground (CBitmap *background) | |||
{ | |||
CKnob::setBackground (background); | |||
if (heightOfOneImage == 0) | |||
heightOfOneImage = getViewSize ().getHeight (); | |||
if (background && heightOfOneImage > 0) | |||
setNumSubPixmaps ((int32_t)(background->getHeight () / heightOfOneImage)); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CAnimKnob::draw (CDrawContext *pContext) | |||
{ | |||
if (getDrawBackground ()) | |||
{ | |||
CPoint where (0, 0); | |||
float val = getValueNormalized (); | |||
if (val >= 0.f && heightOfOneImage > 0.) | |||
{ | |||
CCoord tmp = heightOfOneImage * (getNumSubPixmaps () - 1); | |||
if (bInverseBitmap) | |||
where.y = floor ((1. - val) * tmp); | |||
else | |||
where.y = floor (val * tmp); | |||
where.y -= (int32_t)where.y % (int32_t)heightOfOneImage; | |||
} | |||
getDrawBackground ()->draw (pContext, getViewSize (), where); | |||
} | |||
setDirty (false); | |||
} | |||
} // VSTGUI |
@@ -0,0 +1,159 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "ccontrol.h" | |||
#include "../ccolor.h" | |||
namespace VSTGUI { | |||
//----------------------------------------------------------------------------- | |||
// CKnob Declaration | |||
//! @brief a knob control | |||
/// @ingroup controls | |||
//----------------------------------------------------------------------------- | |||
class CKnob : public CControl | |||
{ | |||
public: | |||
enum DrawStyle { | |||
kLegacyHandleLineDrawing = 0, | |||
kHandleCircleDrawing = 1 << 0, | |||
kCoronaDrawing = 1 << 1, | |||
kCoronaFromCenter = 1 << 2, | |||
kCoronaInverted = 1 << 3, | |||
kCoronaLineDashDot = 1 << 4, | |||
kCoronaOutline = 1 << 5, | |||
kCoronaLineCapButt = 1 << 6, | |||
kSkipHandleDrawing = 1 << 7, | |||
}; | |||
CKnob (const CRect& size, IControlListener* listener, int32_t tag, CBitmap* background, CBitmap* handle, const CPoint& offset = CPoint (0, 0), int32_t drawStyle = kLegacyHandleLineDrawing); | |||
CKnob (const CKnob& knob); | |||
//----------------------------------------------------------------------------- | |||
/// @name CKnob Methods | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
virtual void setStartAngle (float val); | |||
virtual float getStartAngle () const { return startAngle; } | |||
virtual void setRangeAngle (float val); | |||
virtual float getRangeAngle () const { return rangeAngle; } | |||
virtual void valueToPoint (CPoint& point) const; | |||
virtual float valueFromPoint (CPoint& point) const; | |||
virtual CCoord getInsetValue () const { return inset; } | |||
virtual void setInsetValue (CCoord val) { inset = val; } | |||
virtual int32_t getDrawStyle () const { return drawStyle; } | |||
virtual void setDrawStyle (int32_t style); | |||
virtual CColor getCoronaColor () const { return coronaColor; } | |||
virtual void setCoronaColor (CColor color); | |||
virtual CCoord getCoronaInset () const { return coronaInset; } | |||
virtual void setCoronaInset (CCoord inset); | |||
virtual CColor getColorShadowHandle () const { return colorShadowHandle; } | |||
virtual void setColorShadowHandle (CColor color); | |||
virtual CColor getColorHandle () const { return colorHandle; } | |||
virtual void setColorHandle (CColor color); | |||
virtual CCoord getHandleLineWidth () const { return handleLineWidth; } | |||
virtual void setHandleLineWidth (CCoord width); | |||
virtual CCoord getCoronaOutlineWidthAdd () const { return coronaOutlineWidthAdd; } | |||
virtual void setCoronaOutlineWidthAdd (CCoord width); | |||
virtual CBitmap* getHandleBitmap () const { return pHandle; } | |||
virtual void setHandleBitmap (CBitmap* bitmap); | |||
virtual void setZoomFactor (float val) { zoomFactor = val; } | |||
virtual float getZoomFactor () const { return zoomFactor; } | |||
//@} | |||
// overrides | |||
void draw (CDrawContext* pContext) override; | |||
bool onWheel (const CPoint& where, const float& distance, const CButtonState& buttons) override; | |||
int32_t onKeyDown (VstKeyCode& keyCode) override; | |||
void setViewSize (const CRect &rect, bool invalid = true) override; | |||
bool sizeToFit () override; | |||
void setMin (float val) override; | |||
void setMax (float val) override; | |||
bool getFocusPath (CGraphicsPath& outPath) override; | |||
bool drawFocusOnTop () override; | |||
CMouseEventResult onMouseDown (CPoint& where, const CButtonState& buttons) override; | |||
CMouseEventResult onMouseUp (CPoint& where, const CButtonState& buttons) override; | |||
CMouseEventResult onMouseMoved (CPoint& where, const CButtonState& buttons) override; | |||
CMouseEventResult onMouseCancel () override; | |||
CLASS_METHODS(CKnob, CControl) | |||
protected: | |||
~CKnob () noexcept override; | |||
virtual void drawHandle (CDrawContext* pContext); | |||
virtual void drawCoronaOutline (CDrawContext* pContext) const; | |||
virtual void drawCorona (CDrawContext* pContext) const; | |||
virtual void drawHandleAsCircle (CDrawContext* pContext) const; | |||
virtual void drawHandleAsLine (CDrawContext* pContext) const; | |||
void compute (); | |||
void addArc (CGraphicsPath* path, const CRect& r, double startAngle, double sweepAngle) const; | |||
CPoint offset; | |||
int32_t drawStyle; | |||
CColor colorHandle, colorShadowHandle, coronaColor; | |||
CCoord handleLineWidth; | |||
CCoord inset; | |||
CCoord coronaInset; | |||
CCoord coronaOutlineWidthAdd; | |||
CBitmap* pHandle; | |||
float startAngle, rangeAngle; | |||
float zoomFactor; | |||
private: | |||
struct MouseEditingState; | |||
MouseEditingState& getMouseEditingState (); | |||
void clearMouseEditingState (); | |||
}; | |||
//----------------------------------------------------------------------------- | |||
// CAnimKnob Declaration | |||
//! @brief a bitmap knob control | |||
/// @ingroup controls | |||
//----------------------------------------------------------------------------- | |||
class CAnimKnob : public CKnob, public IMultiBitmapControl | |||
{ | |||
public: | |||
CAnimKnob (const CRect& size, IControlListener* listener, int32_t tag, CBitmap* background, const CPoint& offset = CPoint (0, 0)); | |||
CAnimKnob (const CRect& size, IControlListener* listener, int32_t tag, int32_t subPixmaps, CCoord heightOfOneImage, CBitmap* background, const CPoint& offset = CPoint (0, 0)); | |||
CAnimKnob (const CAnimKnob& knob); | |||
//----------------------------------------------------------------------------- | |||
/// @name CAnimKnob Methods | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
void setInverseBitmap (bool val) { bInverseBitmap = val; } | |||
bool getInverseBitmap () const { return bInverseBitmap; } | |||
//@} | |||
// overrides | |||
void draw (CDrawContext* pContext) override; | |||
bool sizeToFit () override; | |||
void setHeightOfOneImage (const CCoord& height) override; | |||
void setBackground (CBitmap *background) override; | |||
void setNumSubPixmaps (int32_t numSubPixmaps) override { IMultiBitmapControl::setNumSubPixmaps (numSubPixmaps); invalid (); } | |||
CLASS_METHODS(CAnimKnob, CKnob) | |||
protected: | |||
~CAnimKnob () noexcept override = default; | |||
bool bInverseBitmap; | |||
}; | |||
} // VSTGUI |
@@ -0,0 +1,102 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#include "cmoviebitmap.h" | |||
#include "../cdrawcontext.h" | |||
#include "../cbitmap.h" | |||
namespace VSTGUI { | |||
//------------------------------------------------------------------------ | |||
bool CMovieBitmap::useLegacyFrameCalculation = false; | |||
//------------------------------------------------------------------------ | |||
// CMovieBitmap | |||
//------------------------------------------------------------------------ | |||
/** | |||
* CMovieBitmap constructor. | |||
* @param size the size of this view | |||
* @param listener the listener | |||
* @param tag the control tag | |||
* @param background bitmap | |||
* @param offset | |||
*/ | |||
//------------------------------------------------------------------------ | |||
CMovieBitmap::CMovieBitmap (const CRect& size, IControlListener* listener, int32_t tag, CBitmap* background, const CPoint &offset) | |||
: CControl (size, listener, tag, background) | |||
, offset (offset) | |||
{ | |||
setHeightOfOneImage (size.getHeight ()); | |||
setNumSubPixmaps (background ? (int32_t)(background->getHeight () / heightOfOneImage) : 0); | |||
} | |||
//------------------------------------------------------------------------ | |||
/** | |||
* CMovieBitmap constructor. | |||
* @param size the size of this view | |||
* @param listener the listener | |||
* @param tag the control tag | |||
* @param subPixmaps number of subPixmaps | |||
* @param heightOfOneImage height of one image in pixel | |||
* @param background bitmap | |||
* @param offset | |||
*/ | |||
//------------------------------------------------------------------------ | |||
CMovieBitmap::CMovieBitmap (const CRect& size, IControlListener* listener, int32_t tag, int32_t subPixmaps, CCoord heightOfOneImage, CBitmap* background, const CPoint &offset) | |||
: CControl (size, listener, tag, background) | |||
, offset (offset) | |||
{ | |||
setNumSubPixmaps (subPixmaps); | |||
setHeightOfOneImage (heightOfOneImage); | |||
} | |||
//------------------------------------------------------------------------ | |||
CMovieBitmap::CMovieBitmap (const CMovieBitmap& v) | |||
: CControl (v) | |||
, offset (v.offset) | |||
{ | |||
setNumSubPixmaps (v.subPixmaps); | |||
setHeightOfOneImage (v.heightOfOneImage); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CMovieBitmap::draw (CDrawContext *pContext) | |||
{ | |||
if (auto bitmap = getDrawBackground ()) | |||
{ | |||
CPoint where (offset.x, offset.y); | |||
if (useLegacyFrameCalculation) | |||
{ | |||
where.y += heightOfOneImage * | |||
(int32_t) (getValueNormalized () * (getNumSubPixmaps () - 1) + 0.5); | |||
} | |||
else | |||
{ | |||
auto step = static_cast<int32_t> ( | |||
std::min (getNumSubPixmaps () - 1.f, getValueNormalized () * getNumSubPixmaps ())); | |||
where.y += heightOfOneImage * step; | |||
} | |||
bitmap->draw (pContext, getViewSize (), where); | |||
} | |||
setDirty (false); | |||
} | |||
//----------------------------------------------------------------------------------------------- | |||
bool CMovieBitmap::sizeToFit () | |||
{ | |||
if (getDrawBackground ()) | |||
{ | |||
CRect vs (getViewSize ()); | |||
vs.setWidth (getDrawBackground ()->getWidth ()); | |||
vs.setHeight (getHeightOfOneImage ()); | |||
setViewSize (vs); | |||
setMouseableArea (vs); | |||
return true; | |||
} | |||
return false; | |||
} | |||
} // VSTGUI |
@@ -0,0 +1,35 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "ccontrol.h" | |||
namespace VSTGUI { | |||
//----------------------------------------------------------------------------- | |||
// CMovieBitmap Declaration | |||
//! @brief a bitmap view that displays different bitmaps according to its current value | |||
/// @ingroup views | |||
//----------------------------------------------------------------------------- | |||
class CMovieBitmap : public CControl, public IMultiBitmapControl | |||
{ | |||
public: | |||
CMovieBitmap (const CRect& size, IControlListener* listener, int32_t tag, CBitmap* background, const CPoint& offset = CPoint (0, 0)); | |||
CMovieBitmap (const CRect& size, IControlListener* listener, int32_t tag, int32_t subPixmaps, CCoord heightOfOneImage, CBitmap* background, const CPoint& offset = CPoint (0, 0)); | |||
CMovieBitmap (const CMovieBitmap& movieBitmap); | |||
void draw (CDrawContext*) override; | |||
bool sizeToFit () override; | |||
void setNumSubPixmaps (int32_t numSubPixmaps) override { IMultiBitmapControl::setNumSubPixmaps (numSubPixmaps); invalid (); } | |||
static bool useLegacyFrameCalculation; | |||
CLASS_METHODS(CMovieBitmap, CControl) | |||
protected: | |||
~CMovieBitmap () noexcept override = default; | |||
CPoint offset; | |||
}; | |||
} // VSTGUI |
@@ -0,0 +1,168 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#include "cmoviebutton.h" | |||
#include "../cdrawcontext.h" | |||
#include "../cbitmap.h" | |||
namespace VSTGUI { | |||
//------------------------------------------------------------------------ | |||
// CMovieButton | |||
//------------------------------------------------------------------------ | |||
/** | |||
* CMovieButton constructor. | |||
* @param size the size of this view | |||
* @param listener the listener | |||
* @param tag the control tag | |||
* @param background bitmap | |||
* @param offset | |||
*/ | |||
//------------------------------------------------------------------------ | |||
CMovieButton::CMovieButton (const CRect& size, IControlListener* listener, int32_t tag, CBitmap* background, const CPoint &offset) | |||
: CControl (size, listener, tag, background), offset (offset), buttonState (value) | |||
{ | |||
heightOfOneImage = size.getHeight (); | |||
setWantsFocus (true); | |||
} | |||
//------------------------------------------------------------------------ | |||
/** | |||
* CMovieButton constructor. | |||
* @param size the size of this view | |||
* @param listener the listener | |||
* @param tag the control tag | |||
* @param heightOfOneImage height of one image in pixel | |||
* @param background bitmap | |||
* @param offset | |||
*/ | |||
//------------------------------------------------------------------------ | |||
CMovieButton::CMovieButton (const CRect& size, IControlListener* listener, int32_t tag, CCoord heightOfOneImage, CBitmap* background, const CPoint &offset) | |||
: CControl (size, listener, tag, background) | |||
, offset (offset) | |||
, buttonState (value) | |||
{ | |||
setHeightOfOneImage (heightOfOneImage); | |||
setWantsFocus (true); | |||
} | |||
//------------------------------------------------------------------------ | |||
CMovieButton::CMovieButton (const CMovieButton& v) | |||
: CControl (v) | |||
, offset (v.offset) | |||
, buttonState (v.buttonState) | |||
{ | |||
setHeightOfOneImage (v.heightOfOneImage); | |||
setWantsFocus (true); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CMovieButton::draw (CDrawContext *pContext) | |||
{ | |||
CPoint where; | |||
where.x = 0; | |||
if (value == getMax ()) | |||
where.y = heightOfOneImage; | |||
else | |||
where.y = 0; | |||
if (getDrawBackground ()) | |||
{ | |||
getDrawBackground ()->draw (pContext, getViewSize (), where); | |||
} | |||
buttonState = value; | |||
setDirty (false); | |||
} | |||
//------------------------------------------------------------------------ | |||
CMouseEventResult CMovieButton::onMouseDown (CPoint& where, const CButtonState& buttons) | |||
{ | |||
if (!(buttons & kLButton)) | |||
return kMouseEventNotHandled; | |||
fEntryState = value; | |||
beginEdit (); | |||
return onMouseMoved (where, buttons); | |||
} | |||
//------------------------------------------------------------------------ | |||
CMouseEventResult CMovieButton::onMouseUp (CPoint& where, const CButtonState& buttons) | |||
{ | |||
if (isEditing ()) | |||
endEdit (); | |||
return kMouseEventHandled; | |||
} | |||
//------------------------------------------------------------------------ | |||
CMouseEventResult CMovieButton::onMouseMoved (CPoint& where, const CButtonState& buttons) | |||
{ | |||
if (isEditing ()) | |||
{ | |||
if (where.x >= getViewSize ().left && | |||
where.y >= getViewSize ().top && | |||
where.x <= getViewSize ().right && | |||
where.y <= getViewSize ().bottom) | |||
value = (fEntryState == getMax ()) ? getMin () : getMax (); | |||
else | |||
value = fEntryState; | |||
if (isDirty ()) | |||
{ | |||
valueChanged (); | |||
invalid (); | |||
} | |||
return kMouseEventHandled; | |||
} | |||
return kMouseEventNotHandled; | |||
} | |||
//------------------------------------------------------------------------ | |||
CMouseEventResult CMovieButton::onMouseCancel () | |||
{ | |||
if (isEditing ()) | |||
{ | |||
value = fEntryState; | |||
if (isDirty ()) | |||
{ | |||
valueChanged (); | |||
invalid (); | |||
} | |||
endEdit (); | |||
} | |||
return kMouseEventHandled; | |||
} | |||
//------------------------------------------------------------------------ | |||
int32_t CMovieButton::onKeyDown (VstKeyCode& keyCode) | |||
{ | |||
if (keyCode.virt == VKEY_RETURN && keyCode.modifier == 0) | |||
{ | |||
value = (value == getMax ()) ? getMin () : getMax (); | |||
invalid (); | |||
beginEdit (); | |||
valueChanged (); | |||
endEdit (); | |||
return 1; | |||
} | |||
return -1; | |||
} | |||
//----------------------------------------------------------------------------------------------- | |||
bool CMovieButton::sizeToFit () | |||
{ | |||
if (getDrawBackground ()) | |||
{ | |||
CRect vs (getViewSize ()); | |||
vs.setWidth (getDrawBackground ()->getWidth ()); | |||
vs.setHeight (getHeightOfOneImage ()); | |||
setViewSize (vs); | |||
setMouseableArea (vs); | |||
return true; | |||
} | |||
return false; | |||
} | |||
} // VSTGUI |
@@ -0,0 +1,44 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "ccontrol.h" | |||
namespace VSTGUI { | |||
//----------------------------------------------------------------------------- | |||
// CMovieButton Declaration | |||
//! @brief a bi-states button with 2 subbitmaps | |||
/// @ingroup controls | |||
//----------------------------------------------------------------------------- | |||
class CMovieButton : public CControl, public IMultiBitmapControl | |||
{ | |||
public: | |||
CMovieButton (const CRect& size, IControlListener* listener, int32_t tag, CBitmap* background, const CPoint& offset = CPoint (0, 0)); | |||
CMovieButton (const CRect& size, IControlListener* listener, int32_t tag, CCoord heightOfOneImage, CBitmap* background, const CPoint& offset = CPoint (0, 0)); | |||
CMovieButton (const CMovieButton& movieButton); | |||
void draw (CDrawContext*) override; | |||
CMouseEventResult onMouseDown (CPoint& where, const CButtonState& buttons) override; | |||
CMouseEventResult onMouseUp (CPoint& where, const CButtonState& buttons) override; | |||
CMouseEventResult onMouseMoved (CPoint& where, const CButtonState& buttons) override; | |||
CMouseEventResult onMouseCancel () override; | |||
int32_t onKeyDown (VstKeyCode& keyCode) override; | |||
bool sizeToFit () override; | |||
void setNumSubPixmaps (int32_t numSubPixmaps) override { IMultiBitmapControl::setNumSubPixmaps (numSubPixmaps); invalid (); } | |||
CLASS_METHODS(CMovieButton, CControl) | |||
protected: | |||
~CMovieButton () noexcept override = default; | |||
CPoint offset; | |||
float buttonState; | |||
private: | |||
float fEntryState; | |||
}; | |||
} // VSTGUI |
@@ -0,0 +1,770 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#include "coptionmenu.h" | |||
#include "../cbitmap.h" | |||
#include "../cframe.h" | |||
#include "../cstring.h" | |||
#include "../platform/iplatformoptionmenu.h" | |||
#include "../platform/iplatformframe.h" | |||
namespace VSTGUI { | |||
//------------------------------------------------------------------------ | |||
// CMenuItem | |||
//------------------------------------------------------------------------ | |||
/*! @class CMenuItem | |||
Defines an item of a VSTGUI::COptionMenu | |||
*/ | |||
//------------------------------------------------------------------------ | |||
/** | |||
* CMenuItem constructor. | |||
* @param inTitle title of item | |||
* @param inFlags CMenuItem::Flags of item | |||
* @param inKeycode keycode of item | |||
* @param inKeyModifiers keymodifiers of item | |||
* @param inIcon icon of item | |||
*/ | |||
//------------------------------------------------------------------------ | |||
CMenuItem::CMenuItem (const UTF8String& inTitle, const UTF8String& inKeycode, int32_t inKeyModifiers, CBitmap* inIcon, int32_t inFlags) | |||
: flags (inFlags) | |||
{ | |||
setTitle (inTitle); | |||
setKey (inKeycode, inKeyModifiers); | |||
setIcon (inIcon); | |||
} | |||
//------------------------------------------------------------------------ | |||
/** | |||
* CMenuItem constructor. | |||
* @param inTitle title of item | |||
* @param inSubmenu submenu of item | |||
* @param inIcon icon of item | |||
*/ | |||
//------------------------------------------------------------------------ | |||
CMenuItem::CMenuItem (const UTF8String& inTitle, COptionMenu* inSubmenu, CBitmap* inIcon) | |||
{ | |||
setTitle (inTitle); | |||
setSubmenu (inSubmenu); | |||
setIcon (inIcon); | |||
} | |||
//------------------------------------------------------------------------ | |||
/** | |||
* CMenuItem constructor. | |||
* @param inTitle title of item | |||
* @param inTag tag of item | |||
*/ | |||
//------------------------------------------------------------------------ | |||
CMenuItem::CMenuItem (const UTF8String& inTitle, int32_t inTag) | |||
{ | |||
setTitle (inTitle); | |||
setTag (inTag); | |||
} | |||
//------------------------------------------------------------------------ | |||
/** | |||
* CMenuItem copy constructor. | |||
* @param item item to copy | |||
*/ | |||
//------------------------------------------------------------------------ | |||
CMenuItem::CMenuItem (const CMenuItem& item) | |||
: flags (item.flags) | |||
{ | |||
setTitle (item.getTitle ()); | |||
setIcon (item.getIcon ()); | |||
if (item.getVirtualKeyCode ()) | |||
setVirtualKey (item.getVirtualKeyCode (), item.getKeyModifiers ()); | |||
else | |||
setKey (item.getKeycode (), item.getKeyModifiers ()); | |||
setTag (item.getTag ()); | |||
setSubmenu (item.getSubmenu ()); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CMenuItem::setTitle (const UTF8String& inTitle) | |||
{ | |||
title = inTitle; | |||
} | |||
//------------------------------------------------------------------------ | |||
void CMenuItem::setKey (const UTF8String& inKeycode, int32_t inKeyModifiers) | |||
{ | |||
keyCode = inKeycode; | |||
keyModifiers = inKeyModifiers; | |||
virtualKeyCode = 0; | |||
} | |||
//------------------------------------------------------------------------ | |||
void CMenuItem::setVirtualKey (int32_t inVirtualKeyCode, int32_t inKeyModifiers) | |||
{ | |||
setKey (nullptr, inKeyModifiers); | |||
virtualKeyCode = inVirtualKeyCode; | |||
} | |||
//------------------------------------------------------------------------ | |||
void CMenuItem::setSubmenu (COptionMenu* inSubmenu) | |||
{ | |||
submenu = inSubmenu; | |||
} | |||
//------------------------------------------------------------------------ | |||
void CMenuItem::setIcon (CBitmap* inIcon) | |||
{ | |||
icon = inIcon; | |||
} | |||
//------------------------------------------------------------------------ | |||
void CMenuItem::setTag (int32_t t) | |||
{ | |||
tag = t; | |||
} | |||
//------------------------------------------------------------------------ | |||
void CMenuItem::setEnabled (bool state) | |||
{ | |||
setBit (flags, kDisabled, !state); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CMenuItem::setChecked (bool state) | |||
{ | |||
setBit (flags, kChecked, state); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CMenuItem::setIsTitle (bool state) | |||
{ | |||
setBit (flags, kTitle, state); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CMenuItem::setIsSeparator (bool state) | |||
{ | |||
setBit (flags, kSeparator, state); | |||
} | |||
//------------------------------------------------------------------------ | |||
/*! @class CCommandMenuItem | |||
The CCommandMenuItem supports setting a category, name and a target. The target will get a @link CBaseObject::notify notify()@endlink call before the item is | |||
displayed and after it was selected. @see CCommandMenuItem::kMsgMenuItemValidate and @see CCommandMenuItem::kMsgMenuItemSelected | |||
*/ | |||
//------------------------------------------------------------------------ | |||
CCommandMenuItem::CCommandMenuItem (Desc&& args) | |||
: CMenuItem (args.title, args.keycode, args.keyModifiers, args.icon, args.flags) | |||
, commandCategory (std::move (args.commandCategory)) | |||
, commandName (std::move (args.commandName)) | |||
, itemTarget (std::move (args.target)) | |||
{ | |||
} | |||
//------------------------------------------------------------------------ | |||
CCommandMenuItem::CCommandMenuItem (const Desc& args) | |||
: CMenuItem (args.title, args.keycode, args.keyModifiers, args.icon, args.flags) | |||
, commandCategory (args.commandCategory) | |||
, commandName (args.commandName) | |||
, itemTarget (args.target) | |||
{ | |||
} | |||
//------------------------------------------------------------------------ | |||
CCommandMenuItem::CCommandMenuItem (const CCommandMenuItem& item) | |||
: CMenuItem (item) | |||
, validateFunc (item.validateFunc) | |||
, selectedFunc (item.selectedFunc) | |||
, commandCategory (item.commandCategory) | |||
, commandName (item.commandName) | |||
{ | |||
setItemTarget (item.itemTarget); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CCommandMenuItem::setItemTarget (ICommandMenuItemTarget* target) | |||
{ | |||
itemTarget = target; | |||
} | |||
//------------------------------------------------------------------------ | |||
void CCommandMenuItem::setCommandCategory (const UTF8String& category) | |||
{ | |||
commandCategory = category; | |||
} | |||
//------------------------------------------------------------------------ | |||
bool CCommandMenuItem::isCommandCategory (const UTF8String& category) const | |||
{ | |||
return commandCategory == category; | |||
} | |||
//------------------------------------------------------------------------ | |||
void CCommandMenuItem::setCommandName (const UTF8String& name) | |||
{ | |||
commandName = name; | |||
} | |||
//------------------------------------------------------------------------ | |||
bool CCommandMenuItem::isCommandName (const UTF8String& name) const | |||
{ | |||
return commandName == name; | |||
} | |||
//------------------------------------------------------------------------ | |||
void CCommandMenuItem::setActions (SelectedCallbackFunction&& selected, ValidateCallbackFunction&& validate) | |||
{ | |||
selectedFunc = std::move (selected); | |||
validateFunc = std::move (validate); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CCommandMenuItem::execute () | |||
{ | |||
if (selectedFunc) | |||
selectedFunc (this); | |||
if (itemTarget) | |||
itemTarget->onCommandMenuItemSelected (this); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CCommandMenuItem::validate () | |||
{ | |||
if (validateFunc) | |||
validateFunc (this); | |||
if (itemTarget) | |||
itemTarget->validateCommandMenuItem (this); | |||
} | |||
//------------------------------------------------------------------------ | |||
// COptionMenu | |||
//------------------------------------------------------------------------ | |||
/*! @class COptionMenu | |||
Define a rectangle view where a text-value can be displayed with a given font and color. | |||
The text-value is centered in the given rect. | |||
A bitmap can be used as background, a second bitmap can be used when the option menu is popuped. | |||
There are 2 styles with or without a shadowed text. When a mouse click occurs, a popup menu is displayed. | |||
*/ | |||
//------------------------------------------------------------------------ | |||
/** | |||
* COptionMenu constructor. | |||
* @param size the size of this view | |||
* @param listener the listener | |||
* @param tag the control tag | |||
* @param background the background bitmap | |||
* @param bgWhenClick the background bitmap if the option menu is displayed | |||
* @param style the style of the display (see CParamDisplay for styles) | |||
*/ | |||
//------------------------------------------------------------------------ | |||
COptionMenu::COptionMenu (const CRect& size, IControlListener* listener, int32_t tag, CBitmap* background, CBitmap* bgWhenClick, const int32_t style) | |||
: CParamDisplay (size, background, style) | |||
, bgWhenClick (bgWhenClick) | |||
{ | |||
this->listener = listener; | |||
this->tag = tag; | |||
lastButton = kRButton; | |||
menuItems = new CMenuItemList; | |||
setWantsFocus (true); | |||
} | |||
//------------------------------------------------------------------------ | |||
COptionMenu::COptionMenu () | |||
: CParamDisplay (CRect (0, 0, 0, 0)) | |||
{ | |||
menuItems = new CMenuItemList; | |||
setWantsFocus (true); | |||
} | |||
//------------------------------------------------------------------------ | |||
COptionMenu::COptionMenu (const COptionMenu& v) | |||
: CParamDisplay (v) | |||
, menuItems (new CMenuItemList (*v.menuItems)) | |||
, nbItemsPerColumn (v.nbItemsPerColumn) | |||
, bgWhenClick (v.bgWhenClick) | |||
{ | |||
setWantsFocus (true); | |||
} | |||
//------------------------------------------------------------------------ | |||
COptionMenu::~COptionMenu () noexcept | |||
{ | |||
removeAllEntry (); | |||
delete menuItems; | |||
} | |||
//------------------------------------------------------------------------ | |||
void COptionMenu::registerOptionMenuListener (IOptionMenuListener* listener) | |||
{ | |||
if (!listeners) | |||
listeners = std::unique_ptr<MenuListenerList> (new MenuListenerList ()); | |||
listeners->add (listener); | |||
} | |||
//------------------------------------------------------------------------ | |||
void COptionMenu::unregisterOptionMenuListener (IOptionMenuListener* listener) | |||
{ | |||
if (listeners) | |||
listeners->remove (listener); | |||
} | |||
//------------------------------------------------------------------------ | |||
int32_t COptionMenu::onKeyDown (VstKeyCode& keyCode) | |||
{ | |||
if (keyCode.modifier == 0 && keyCode.character == 0) | |||
{ | |||
if (keyCode.virt == VKEY_RETURN) | |||
{ | |||
auto self = shared (this); | |||
getFrame ()->doAfterEventProcessing ([self] () { | |||
self->doPopup (); | |||
}); | |||
return 1; | |||
} | |||
if (!(style & (kMultipleCheckStyle & ~kCheckStyle))) | |||
{ | |||
if (keyCode.virt == VKEY_UP) | |||
{ | |||
int32_t value = (int32_t)getValue ()-1; | |||
if (value >= 0) | |||
{ | |||
CMenuItem* entry = getEntry (value); | |||
while (entry && (entry->isSeparator () || entry->isTitle () || !entry->isEnabled () || entry->getSubmenu ())) | |||
entry = getEntry (--value); | |||
if (entry) | |||
{ | |||
beginEdit (); | |||
setValue ((float)value); | |||
lastResult = (int32_t)getValue (); | |||
valueChanged (); | |||
endEdit (); | |||
invalid (); | |||
} | |||
} | |||
return 1; | |||
} | |||
if (keyCode.virt == VKEY_DOWN) | |||
{ | |||
int32_t value = (int32_t)getValue ()+1; | |||
if (value < getNbEntries ()) | |||
{ | |||
CMenuItem* entry = getEntry (value); | |||
while (entry && (entry->isSeparator () || entry->isTitle () || !entry->isEnabled () || entry->getSubmenu ())) | |||
entry = getEntry (++value); | |||
if (entry) | |||
{ | |||
beginEdit (); | |||
setValue ((float)value); | |||
lastResult = (int32_t)getValue (); | |||
valueChanged (); | |||
endEdit (); | |||
invalid (); | |||
} | |||
} | |||
return 1; | |||
} | |||
} | |||
} | |||
return CParamDisplay::onKeyDown (keyCode); | |||
} | |||
//------------------------------------------------------------------------ | |||
void COptionMenu::beforePopup () | |||
{ | |||
if (listeners) | |||
listeners->forEach ([this] (IOptionMenuListener* l) { l->onOptionMenuPrePopup (this); }); | |||
for (auto& menuItem : *menuItems) | |||
{ | |||
CCommandMenuItem* commandItem = menuItem.cast<CCommandMenuItem> (); | |||
if (commandItem) | |||
commandItem->validate (); | |||
if (menuItem->getSubmenu ()) | |||
menuItem->getSubmenu ()->beforePopup (); | |||
} | |||
} | |||
//------------------------------------------------------------------------ | |||
void COptionMenu::afterPopup () | |||
{ | |||
for (auto& menuItem : *menuItems) | |||
{ | |||
if (menuItem->getSubmenu ()) | |||
menuItem->getSubmenu ()->afterPopup (); | |||
} | |||
if (listeners) | |||
listeners->forEach ([this] (IOptionMenuListener* l) { l->onOptionMenuPostPopup (this); }); | |||
} | |||
//------------------------------------------------------------------------ | |||
bool COptionMenu::doPopup () | |||
{ | |||
if (bgWhenClick) | |||
invalid (); | |||
auto result = popup (); | |||
if (bgWhenClick) | |||
invalid (); | |||
return result; | |||
} | |||
//------------------------------------------------------------------------ | |||
bool COptionMenu::popup (const PopupCallback& callback) | |||
{ | |||
if (!getFrame ()) | |||
return false; | |||
beforePopup (); | |||
lastResult = -1; | |||
lastMenu = nullptr; | |||
if (!menuItems->empty ()) | |||
{ | |||
getFrame ()->onStartLocalEventLoop (); | |||
if (auto platformMenu = getFrame ()->getPlatformFrame ()->createPlatformOptionMenu ()) | |||
{ | |||
inPopup = true; | |||
auto self = shared (this); | |||
platformMenu->popup (this, [self, callback] (COptionMenu* menu, PlatformOptionMenuResult result) { | |||
if (result.menu != nullptr) | |||
{ | |||
self->beginEdit (); | |||
self->lastMenu = result.menu; | |||
self->lastResult = result.index; | |||
self->lastMenu->setValue (static_cast<float> (self->lastResult)); | |||
self->valueChanged (); | |||
self->invalid (); | |||
if (auto commandItem = dynamic_cast<CCommandMenuItem*> ( | |||
self->lastMenu->getEntry (self->lastResult))) | |||
commandItem->execute (); | |||
self->endEdit (); | |||
} | |||
self->afterPopup (); | |||
if (callback) | |||
callback (self); | |||
self->inPopup = false; | |||
}); | |||
} | |||
} | |||
return true; | |||
} | |||
//------------------------------------------------------------------------ | |||
bool COptionMenu::popup (CFrame* frame, const CPoint& frameLocation, const PopupCallback& callback) | |||
{ | |||
if (frame == nullptr || menuItems->empty ()) | |||
return false; | |||
if (isAttached ()) | |||
return false; | |||
CView* oldFocusView = frame->getFocusView (); | |||
CRect size (frameLocation, CPoint (0, 0)); | |||
setViewSize (size); | |||
frame->addView (this); | |||
auto prevFocusView = shared (oldFocusView); | |||
popup ([prevFocusView, callback] (COptionMenu* menu) { | |||
if (auto frame = menu->getFrame ()) | |||
{ | |||
frame->removeView (menu, false); | |||
frame->setFocusView (prevFocusView); | |||
} | |||
if (callback) | |||
callback (menu); | |||
}); | |||
return true; | |||
} | |||
//------------------------------------------------------------------------ | |||
void COptionMenu::cleanupSeparators (bool deep) | |||
{ | |||
if (getItems ()->empty ()) | |||
return; | |||
std::list<int32_t>indicesToRemove; | |||
bool lastEntryWasSeparator = true; | |||
for (auto i = 0; i < getNbEntries () - 1; ++i) | |||
{ | |||
auto entry = getEntry (i); | |||
vstgui_assert (entry); | |||
if (entry->isSeparator ()) | |||
{ | |||
if (lastEntryWasSeparator) | |||
{ | |||
indicesToRemove.push_front (i); | |||
} | |||
lastEntryWasSeparator = true; | |||
} | |||
else | |||
lastEntryWasSeparator = false; | |||
if (deep) | |||
{ | |||
if (auto subMenu = entry->getSubmenu ()) | |||
{ | |||
subMenu->cleanupSeparators (deep); | |||
} | |||
} | |||
} | |||
auto lastIndex = getNbEntries () - 1; | |||
if (getEntry (lastIndex)->isSeparator ()) | |||
{ | |||
indicesToRemove.push_front (lastIndex); | |||
} | |||
for (auto index : indicesToRemove) | |||
{ | |||
removeEntry (index); | |||
} | |||
} | |||
//------------------------------------------------------------------------ | |||
void COptionMenu::setPrefixNumbers (int32_t preCount) | |||
{ | |||
if (preCount >= 0 && preCount <= 4) | |||
prefixNumbers = preCount; | |||
} | |||
/** | |||
* @param item menu item to add. Takes ownership of item. | |||
* @param index position of insertation. -1 appends the item | |||
*/ | |||
//----------------------------------------------------------------------------- | |||
CMenuItem* COptionMenu::addEntry (CMenuItem* item, int32_t index) | |||
{ | |||
if (index < 0 || index > getNbEntries ()) | |||
menuItems->emplace_back (owned (item)); | |||
else | |||
{ | |||
menuItems->insert (menuItems->begin () + index, owned (item)); | |||
} | |||
return item; | |||
} | |||
//----------------------------------------------------------------------------- | |||
CMenuItem* COptionMenu::addEntry (COptionMenu* submenu, const UTF8String& title) | |||
{ | |||
CMenuItem* item = new CMenuItem (title, submenu); | |||
return addEntry (item); | |||
} | |||
//----------------------------------------------------------------------------- | |||
CMenuItem* COptionMenu::addEntry (const UTF8String& title, int32_t index, int32_t itemFlags) | |||
{ | |||
if (title == "-") | |||
return addSeparator (index); | |||
CMenuItem* item = new CMenuItem (title, nullptr, 0, nullptr, itemFlags); | |||
return addEntry (item, index); | |||
} | |||
//----------------------------------------------------------------------------- | |||
CMenuItem* COptionMenu::addSeparator (int32_t index) | |||
{ | |||
CMenuItem* item = new CMenuItem ("", nullptr, 0, nullptr, CMenuItem::kSeparator); | |||
return addEntry (item, index); | |||
} | |||
//----------------------------------------------------------------------------- | |||
CMenuItem* COptionMenu::getCurrent () const | |||
{ | |||
return getEntry (currentIndex); | |||
} | |||
//----------------------------------------------------------------------------- | |||
CMenuItem* COptionMenu::getEntry (int32_t index) const | |||
{ | |||
if (index < 0 || menuItems->empty () || index >= getNbEntries ()) | |||
return nullptr; | |||
return (*menuItems)[static_cast<size_t> (index)]; | |||
} | |||
//----------------------------------------------------------------------------- | |||
int32_t COptionMenu::getNbEntries () const | |||
{ | |||
return static_cast<int32_t> (menuItems->size ()); | |||
} | |||
//------------------------------------------------------------------------ | |||
COptionMenu* COptionMenu::getSubMenu (int32_t idx) const | |||
{ | |||
CMenuItem* item = getEntry (idx); | |||
if (item) | |||
return item->getSubmenu (); | |||
return nullptr; | |||
} | |||
//------------------------------------------------------------------------ | |||
int32_t COptionMenu::getCurrentIndex (bool countSeparator) const | |||
{ | |||
if (countSeparator) | |||
return currentIndex; | |||
int32_t i = 0; | |||
int32_t numSeparators = 0; | |||
for (auto& item : *menuItems) | |||
{ | |||
if (item->isSeparator ()) | |||
numSeparators++; | |||
if (i == currentIndex) | |||
break; | |||
i++; | |||
} | |||
return currentIndex - numSeparators; | |||
} | |||
//------------------------------------------------------------------------ | |||
bool COptionMenu::setCurrent (int32_t index, bool countSeparator) | |||
{ | |||
CMenuItem* item = nullptr; | |||
if (countSeparator) | |||
{ | |||
item = getEntry (index); | |||
if (!item || item->isSeparator ()) | |||
return false; | |||
currentIndex = index; | |||
} | |||
else | |||
{ | |||
int32_t i = 0; | |||
for (auto& item : *menuItems) | |||
{ | |||
if (i > index) | |||
break; | |||
if (item->isSeparator ()) | |||
index++; | |||
i++; | |||
} | |||
currentIndex = index; | |||
item = getEntry (currentIndex); | |||
} | |||
if (item && style & (kMultipleCheckStyle & ~kCheckStyle)) | |||
item->setChecked (!item->isChecked ()); | |||
// to force the redraw | |||
setDirty (); | |||
return true; | |||
} | |||
//------------------------------------------------------------------------ | |||
bool COptionMenu::removeEntry (int32_t index) | |||
{ | |||
if (index < 0 || menuItems->empty () || index >= getNbEntries ()) | |||
return false; | |||
menuItems->erase (menuItems->begin () + index); | |||
return true; | |||
} | |||
//------------------------------------------------------------------------ | |||
bool COptionMenu::removeAllEntry () | |||
{ | |||
menuItems->clear (); | |||
return true; | |||
} | |||
//------------------------------------------------------------------------ | |||
bool COptionMenu::checkEntry (int32_t index, bool state) | |||
{ | |||
CMenuItem* item = getEntry (index); | |||
if (item) | |||
{ | |||
item->setChecked (state); | |||
return true; | |||
} | |||
return false; | |||
} | |||
//------------------------------------------------------------------------ | |||
bool COptionMenu::checkEntryAlone (int32_t index) | |||
{ | |||
int32_t pos = 0; | |||
for (auto& item : *menuItems) | |||
{ | |||
item->setChecked (pos == index); | |||
pos++; | |||
} | |||
return true; | |||
} | |||
//------------------------------------------------------------------------ | |||
bool COptionMenu::isCheckEntry (int32_t index) const | |||
{ | |||
CMenuItem* item = getEntry (index); | |||
if (item && item->isChecked ()) | |||
return true; | |||
return false; | |||
} | |||
//------------------------------------------------------------------------ | |||
void COptionMenu::draw (CDrawContext *pContext) | |||
{ | |||
CMenuItem* item = getEntry (currentIndex); | |||
drawBack (pContext, inPopup ? bgWhenClick : nullptr); | |||
if (item) | |||
drawPlatformText (pContext, UTF8String (item->getTitle ()).getPlatformString ()); | |||
setDirty (false); | |||
} | |||
//------------------------------------------------------------------------ | |||
CMouseEventResult COptionMenu::onMouseDown (CPoint& where, const CButtonState& buttons) | |||
{ | |||
lastButton = buttons; | |||
if (lastButton & (kLButton|kRButton|kApple)) | |||
{ | |||
auto self = shared (this); | |||
getFrame ()->doAfterEventProcessing ([self] () { | |||
self->doPopup (); | |||
}); | |||
return kMouseDownEventHandledButDontNeedMovedOrUpEvents; | |||
} | |||
return kMouseEventNotHandled; | |||
} | |||
//------------------------------------------------------------------------ | |||
COptionMenu *COptionMenu::getLastItemMenu (int32_t &idxInMenu) const | |||
{ | |||
idxInMenu = lastMenu ? (int32_t)lastMenu->getValue (): -1; | |||
return lastMenu; | |||
} | |||
//------------------------------------------------------------------------ | |||
void COptionMenu::setValue (float val) | |||
{ | |||
auto newIndex = static_cast<int32_t> (std::round (val)); | |||
if (newIndex < 0 || newIndex >= getNbEntries ()) | |||
return; | |||
currentIndex = newIndex; | |||
if (style & (kMultipleCheckStyle & ~kCheckStyle)) | |||
{ | |||
CMenuItem* item = getCurrent (); | |||
if (item) | |||
item->setChecked (!item->isChecked ()); | |||
} | |||
CParamDisplay::setValue (static_cast<float> (newIndex)); | |||
// to force the redraw | |||
setDirty (); | |||
} | |||
//------------------------------------------------------------------------ | |||
void COptionMenu::takeFocus () | |||
{ | |||
CParamDisplay::takeFocus (); | |||
} | |||
//------------------------------------------------------------------------ | |||
void COptionMenu::looseFocus () | |||
{ | |||
CView* receiver = getParentView () ? getParentView () : getFrame (); | |||
while (receiver) | |||
{ | |||
if (receiver->notify (this, kMsgLooseFocus) == kMessageNotified) | |||
break; | |||
receiver = receiver->getParentView (); | |||
} | |||
CParamDisplay::looseFocus (); | |||
} | |||
} // VSTGUI |
@@ -0,0 +1,340 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "cparamdisplay.h" | |||
#include "icommandmenuitemtarget.h" | |||
#include "ioptionmenulistener.h" | |||
#include "../cstring.h" | |||
#include "../dispatchlist.h" | |||
#include "../cbitmap.h" | |||
#include <vector> | |||
#include <functional> | |||
namespace VSTGUI { | |||
//----------------------------------------------------------------------------- | |||
// CMenuItem Declaration | |||
//! @brief a menu item | |||
//----------------------------------------------------------------------------- | |||
class CMenuItem : public CBaseObject | |||
{ | |||
public: | |||
enum Flags { | |||
kNoFlags = 0, | |||
/** item is gray and not selectable */ | |||
kDisabled = 1 << 0, | |||
/** item indicates a title and is not selectable */ | |||
kTitle = 1 << 1, | |||
/** item has a checkmark */ | |||
kChecked = 1 << 2, | |||
/** item is a separator */ | |||
kSeparator = 1 << 3 | |||
}; | |||
CMenuItem (const UTF8String& title, const UTF8String& keycode = "", int32_t keyModifiers = 0, CBitmap* icon = nullptr, int32_t flags = kNoFlags); | |||
CMenuItem (const UTF8String& title, COptionMenu* submenu, CBitmap* icon = nullptr); | |||
CMenuItem (const UTF8String& title, int32_t tag); | |||
CMenuItem (const CMenuItem& item); | |||
//----------------------------------------------------------------------------- | |||
/// @name CMenuItem Methods | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
/** set title of menu item */ | |||
virtual void setTitle (const UTF8String& title); | |||
/** set submenu of menu item */ | |||
virtual void setSubmenu (COptionMenu* submenu); | |||
/** set keycode and key modifiers of menu item */ | |||
virtual void setKey (const UTF8String& keyCode, int32_t keyModifiers = 0); | |||
/** set virtual keycode and key modifiers of menu item */ | |||
virtual void setVirtualKey (int32_t virtualKeyCode, int32_t keyModifiers = 0); | |||
/** set menu item enabled state */ | |||
virtual void setEnabled (bool state = true); | |||
/** set menu item checked state */ | |||
virtual void setChecked (bool state = true); | |||
/** set menu item title state */ | |||
virtual void setIsTitle (bool state = true); | |||
/** set menu item separator state */ | |||
virtual void setIsSeparator (bool state = true); | |||
/** set menu item icon */ | |||
virtual void setIcon (CBitmap* icon); | |||
/** set menu item tag */ | |||
virtual void setTag (int32_t tag); | |||
/** returns whether the item is enabled or not */ | |||
bool isEnabled () const { return !hasBit (flags, kDisabled); } | |||
/** returns whether the item is checked or not */ | |||
bool isChecked () const { return hasBit (flags, kChecked); } | |||
/** returns whether the item is a title item or not */ | |||
bool isTitle () const { return hasBit (flags, kTitle); } | |||
/** returns whether the item is a separator or not */ | |||
bool isSeparator () const { return hasBit (flags, kSeparator); } | |||
/** returns the title of the item */ | |||
const UTF8String& getTitle () const { return title; } | |||
/** returns the key modifiers of the item */ | |||
int32_t getKeyModifiers () const { return keyModifiers; } | |||
/** returns the keycode of the item */ | |||
const UTF8String& getKeycode () const { return keyCode; } | |||
/** returns the virtual keycode of the item */ | |||
int32_t getVirtualKeyCode () const { return virtualKeyCode; } | |||
/** returns the submenu of the item */ | |||
COptionMenu* getSubmenu () const { return submenu; } | |||
/** returns the icon of the item */ | |||
CBitmap* getIcon () const { return icon; } | |||
/** returns the tag of the item */ | |||
int32_t getTag () const { return tag; } | |||
//@} | |||
//------------------------------------------------------------------------ | |||
protected: | |||
~CMenuItem () noexcept override = default; | |||
UTF8String title; | |||
UTF8String keyCode; | |||
SharedPointer<COptionMenu> submenu; | |||
SharedPointer<CBitmap> icon; | |||
int32_t flags {0}; | |||
int32_t keyModifiers {0}; | |||
int32_t virtualKeyCode {0}; | |||
int32_t tag {-1}; | |||
}; | |||
//----------------------------------------------------------------------------- | |||
// CCommandMenuItem Declaration | |||
/// @brief a command menu item | |||
/// @ingroup new_in_4_1 | |||
//----------------------------------------------------------------------------- | |||
class CCommandMenuItem : public CMenuItem | |||
{ | |||
public: | |||
struct Desc | |||
{ | |||
UTF8String title; | |||
UTF8String commandCategory; | |||
UTF8String commandName; | |||
UTF8String keycode; | |||
SharedPointer<ICommandMenuItemTarget> target; | |||
SharedPointer<CBitmap> icon; | |||
int32_t keyModifiers {0}; | |||
int32_t flags {kNoFlags}; | |||
Desc () = default; | |||
~Desc () noexcept = default; | |||
Desc (const UTF8String& title, const UTF8String& keycode = nullptr, | |||
int32_t keyModifiers = 0, CBitmap* icon = nullptr, | |||
int32_t flags = kNoFlags, ICommandMenuItemTarget* target = nullptr, | |||
const UTF8String& commandCategory = nullptr, | |||
const UTF8String& commandName = nullptr) | |||
: title (title) | |||
, commandCategory (commandCategory) | |||
, commandName (commandName) | |||
, keycode (keycode) | |||
, target (target) | |||
, icon (icon) | |||
, keyModifiers (keyModifiers) | |||
, flags (flags) | |||
{ | |||
} | |||
Desc (const UTF8String& title, int32_t tag, | |||
ICommandMenuItemTarget* target = nullptr, | |||
const UTF8String& commandCategory = nullptr, | |||
const UTF8String& commandName = nullptr) | |||
: title (title) | |||
, commandCategory (commandCategory) | |||
, commandName (commandName) | |||
, target (target) | |||
{ | |||
} | |||
Desc (const UTF8String& title, ICommandMenuItemTarget* target, | |||
const UTF8String& commandCategory = nullptr, | |||
const UTF8String& commandName = nullptr) | |||
: title (title) | |||
, commandCategory (commandCategory) | |||
, commandName (commandName) | |||
, target (target) | |||
{ | |||
} | |||
}; | |||
CCommandMenuItem (Desc&& args); | |||
CCommandMenuItem (const Desc& args); | |||
CCommandMenuItem (const CCommandMenuItem& item); | |||
~CCommandMenuItem () noexcept override = default; | |||
//----------------------------------------------------------------------------- | |||
/// @name CCommandMenuItem Methods | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
void setCommandCategory (const UTF8String& category); | |||
const UTF8String& getCommandCategory () const { return commandCategory; } | |||
bool isCommandCategory (const UTF8String& category) const; | |||
void setCommandName (const UTF8String& name); | |||
const UTF8String& getCommandName () const { return commandName; } | |||
bool isCommandName (const UTF8String& name) const; | |||
void setItemTarget (ICommandMenuItemTarget* target); | |||
ICommandMenuItemTarget* getItemTarget () const { return itemTarget; } | |||
using ValidateCallbackFunction = std::function<void(CCommandMenuItem* item)>; | |||
using SelectedCallbackFunction = std::function<void(CCommandMenuItem* item)>; | |||
void setActions (SelectedCallbackFunction&& selected, ValidateCallbackFunction&& validate = [](CCommandMenuItem*){}); | |||
//@} | |||
void execute (); | |||
void validate (); | |||
protected: | |||
ValidateCallbackFunction validateFunc; | |||
SelectedCallbackFunction selectedFunc; | |||
UTF8String commandCategory; | |||
UTF8String commandName; | |||
SharedPointer<ICommandMenuItemTarget> itemTarget; | |||
}; | |||
using CMenuItemList = std::vector<SharedPointer<CMenuItem>>; | |||
using CMenuItemIterator = CMenuItemList::iterator; | |||
using CConstMenuItemIterator = CMenuItemList::const_iterator; | |||
//----------------------------------------------------------------------------- | |||
// COptionMenu Declaration | |||
//! @brief a popup menu control | |||
/// @ingroup controls | |||
//----------------------------------------------------------------------------- | |||
class COptionMenu : public CParamDisplay | |||
{ | |||
private: | |||
enum StyleEnum | |||
{ | |||
StylePopup = CParamDisplay::LastStyle, | |||
StyleCheck, | |||
StyleMultipleCheck, | |||
}; | |||
public: | |||
COptionMenu (); | |||
COptionMenu (const CRect& size, IControlListener* listener, int32_t tag, CBitmap* background = nullptr, CBitmap* bgWhenClick = nullptr, const int32_t style = 0); | |||
COptionMenu (const COptionMenu& menu); | |||
~COptionMenu () noexcept override; | |||
enum Style | |||
{ | |||
kPopupStyle = 1 << StylePopup, | |||
kCheckStyle = 1 << StyleCheck, | |||
kMultipleCheckStyle = 1 << StyleMultipleCheck | |||
}; | |||
bool isPopupStyle () const { return hasBit (getStyle (), kPopupStyle); } | |||
bool isCheckStyle () const { return hasBit (getStyle (), kCheckStyle); } | |||
bool isMultipleCheckStyle () const { return hasBit (getStyle (), kMultipleCheckStyle); } | |||
//----------------------------------------------------------------------------- | |||
/// @name COptionMenu Methods | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
/** add a new entry */ | |||
virtual CMenuItem* addEntry (CMenuItem* item, int32_t index = -1); | |||
/** add a new submenu entry */ | |||
virtual CMenuItem* addEntry (COptionMenu* submenu, const UTF8String& title); | |||
/** add a new entry */ | |||
virtual CMenuItem* addEntry (const UTF8String& title, int32_t index = -1, int32_t itemFlags = CMenuItem::kNoFlags); | |||
/** add a new separator entry */ | |||
virtual CMenuItem* addSeparator (int32_t index = -1); | |||
/** get current entry */ | |||
virtual CMenuItem* getCurrent () const; | |||
/** TODO: Doc */ | |||
virtual int32_t getCurrentIndex (bool countSeparator = false) const; | |||
/** get entry at index position */ | |||
virtual CMenuItem* getEntry (int32_t index) const; | |||
/** get number of entries */ | |||
virtual int32_t getNbEntries () const; | |||
/** set current entry */ | |||
virtual bool setCurrent (int32_t index, bool countSeparator = true); | |||
/** remove an entry */ | |||
virtual bool removeEntry (int32_t index); | |||
/** remove all entries */ | |||
virtual bool removeAllEntry (); | |||
/** change check state of entry at index */ | |||
virtual bool checkEntry (int32_t index, bool state); | |||
/** check entry at index and uncheck every other item */ | |||
virtual bool checkEntryAlone (int32_t index); | |||
/** get check state of entry at index */ | |||
virtual bool isCheckEntry (int32_t index) const; | |||
/** Windows only */ | |||
virtual void setNbItemsPerColumn (int32_t val) { nbItemsPerColumn = val; } | |||
/** Windows only */ | |||
virtual int32_t getNbItemsPerColumn () const { return nbItemsPerColumn; } | |||
/** get last index of choosen entry */ | |||
int32_t getLastResult () const { return lastResult; } | |||
/** get last menu and index of choosen entry */ | |||
COptionMenu* getLastItemMenu (int32_t& idxInMenu) const; | |||
/** set prefix numbering */ | |||
virtual void setPrefixNumbers (int32_t preCount); | |||
/** get prefix numbering */ | |||
int32_t getPrefixNumbers () const { return prefixNumbers; } | |||
/** get a submenu */ | |||
COptionMenu* getSubMenu (int32_t idx) const; | |||
/** popup callback function */ | |||
using PopupCallback = std::function<void (COptionMenu* menu)>; | |||
/** pops up the menu */ | |||
bool popup (const PopupCallback& callback = {}); | |||
/** pops up the menu at frameLocation */ | |||
bool popup (CFrame* frame, const CPoint& frameLocation, const PopupCallback& callback = {}); | |||
CMenuItemList* getItems () const { return menuItems; } | |||
/** remove separators as first and last item and double separators */ | |||
void cleanupSeparators (bool deep); | |||
void registerOptionMenuListener (IOptionMenuListener* listener); | |||
void unregisterOptionMenuListener (IOptionMenuListener* listener); | |||
//@} | |||
// overrides | |||
void setValue (float val) override; | |||
void setMin (float val) override {} | |||
float getMin () const override { return 0; } | |||
void setMax (float val) override {} | |||
float getMax () const override { return (float)(menuItems->size () - 1); } | |||
void draw (CDrawContext* pContext) override; | |||
CMouseEventResult onMouseDown (CPoint& where, const CButtonState& buttons) override; | |||
int32_t onKeyDown (VstKeyCode& keyCode) override; | |||
void takeFocus () override; | |||
void looseFocus () override; | |||
CLASS_METHODS(COptionMenu, CParamDisplay) | |||
protected: | |||
bool doPopup (); | |||
void beforePopup (); | |||
void afterPopup (); | |||
CMenuItemList* menuItems; | |||
bool inPopup {false}; | |||
int32_t currentIndex {-1}; | |||
CButtonState lastButton {0}; | |||
int32_t nbItemsPerColumn {-1}; | |||
int32_t lastResult {-1}; | |||
int32_t prefixNumbers {0}; | |||
SharedPointer<CBitmap> bgWhenClick; | |||
COptionMenu* lastMenu {nullptr}; | |||
using MenuListenerList = DispatchList<IOptionMenuListener*>; | |||
std::unique_ptr<MenuListenerList> listeners; | |||
}; | |||
} // VSTGUI |
@@ -0,0 +1,504 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#include "cparamdisplay.h" | |||
#include "../cbitmap.h" | |||
#include "../cframe.h" | |||
#include "../cstring.h" | |||
#include "../cgraphicspath.h" | |||
#include "../cdrawcontext.h" | |||
#include <string> | |||
namespace VSTGUI { | |||
//------------------------------------------------------------------------ | |||
// CParamDisplay | |||
//------------------------------------------------------------------------ | |||
/*! @class CParamDisplay | |||
Define a rectangle view where a text-value can be displayed with a given font and color. | |||
The user can specify its convert function (from float to char) by default the string format is "%2.2f". | |||
The text-value is centered in the given rect. | |||
*/ | |||
CParamDisplay::CParamDisplay (const CRect& size, CBitmap* background, int32_t inStyle) | |||
: CControl (size, nullptr, -1, background) | |||
, horiTxtAlign (kCenterText) | |||
, style (inStyle) | |||
, valuePrecision (2) | |||
, roundRectRadius (6.) | |||
, frameWidth (1.) | |||
, textRotation (0.) | |||
{ | |||
setBit (style, kAntialias, true); | |||
backOffset (0, 0); | |||
fontID = kNormalFont; fontID->remember (); | |||
fontColor = kWhiteCColor; | |||
backColor = kBlackCColor; | |||
frameColor = kBlackCColor; | |||
shadowColor = kRedCColor; | |||
if (hasBit (style, kNoDrawStyle)) | |||
setDirty (false); | |||
} | |||
//------------------------------------------------------------------------ | |||
CParamDisplay::CParamDisplay (const CParamDisplay& v) | |||
: CControl (v) | |||
, valueToStringFunction (v.valueToStringFunction) | |||
, horiTxtAlign (v.horiTxtAlign) | |||
, style (v.style) | |||
, valuePrecision (v.valuePrecision) | |||
, fontID (v.fontID) | |||
, fontColor (v.fontColor) | |||
, backColor (v.backColor) | |||
, frameColor (v.frameColor) | |||
, shadowColor (v.shadowColor) | |||
, textInset (v.textInset) | |||
, backOffset (v.backOffset) | |||
, roundRectRadius (v.roundRectRadius) | |||
, frameWidth (v.frameWidth) | |||
, textRotation (v.textRotation) | |||
{ | |||
fontID->remember (); | |||
} | |||
//------------------------------------------------------------------------ | |||
CParamDisplay::~CParamDisplay () noexcept | |||
{ | |||
if (fontID) | |||
fontID->forget (); | |||
} | |||
//------------------------------------------------------------------------ | |||
bool CParamDisplay::removed (CView* parent) | |||
{ | |||
return CControl::removed (parent); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CParamDisplay::setStyle (int32_t val) | |||
{ | |||
setBit (val, kAntialias, hasBit (style, kAntialias)); | |||
if (style != val) | |||
{ | |||
style = val; | |||
drawStyleChanged (); | |||
} | |||
} | |||
//------------------------------------------------------------------------ | |||
int32_t CParamDisplay::getStyle () const | |||
{ | |||
auto tmp = style; | |||
setBit (tmp, kAntialias, false); | |||
return tmp; | |||
} | |||
//------------------------------------------------------------------------ | |||
void CParamDisplay::setPrecision (uint8_t precision) | |||
{ | |||
if (valuePrecision != precision) | |||
{ | |||
valuePrecision = precision; | |||
drawStyleChanged (); | |||
} | |||
} | |||
//------------------------------------------------------------------------ | |||
void CParamDisplay::setValueToStringFunction2 (const ValueToStringFunction2& valueToStringFunc) | |||
{ | |||
valueToStringFunction = valueToStringFunc; | |||
} | |||
//------------------------------------------------------------------------ | |||
void CParamDisplay::setValueToStringFunction2 (ValueToStringFunction2&& valueToStringFunc) | |||
{ | |||
valueToStringFunction = std::move (valueToStringFunc); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CParamDisplay::setValueToStringFunction (const ValueToStringFunction& func) | |||
{ | |||
if (!func) | |||
{ | |||
setValueToStringFunction2 (nullptr); | |||
return; | |||
} | |||
setValueToStringFunction2 ([=] (float value, std::string& str, CParamDisplay* display) { | |||
char string[256]; | |||
string[0] = 0; | |||
if (func (value, string, display)) | |||
{ | |||
str = string; | |||
return true; | |||
} | |||
return false; | |||
}); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CParamDisplay::setValueToStringFunction (ValueToStringFunction&& func) | |||
{ | |||
setValueToStringFunction (func); | |||
} | |||
//------------------------------------------------------------------------ | |||
bool CParamDisplay::getFocusPath (CGraphicsPath& outPath) | |||
{ | |||
if (wantsFocus ()) | |||
{ | |||
auto lineWidth = getFrameWidth (); | |||
if (lineWidth < 0.) | |||
lineWidth = 1.; | |||
CCoord focusWidth = getFrame ()->getFocusWidth (); | |||
CRect r (getViewSize ()); | |||
if (hasBit (style, kRoundRectStyle)) | |||
{ | |||
r.inset (lineWidth / 2., lineWidth / 2.); | |||
outPath.addRoundRect (r, roundRectRadius); | |||
outPath.closeSubpath (); | |||
r.extend (focusWidth, focusWidth); | |||
outPath.addRoundRect (r, roundRectRadius); | |||
} | |||
else | |||
{ | |||
r.inset (lineWidth / 2., lineWidth / 2.); | |||
outPath.addRect (r); | |||
r.extend (focusWidth, focusWidth); | |||
outPath.addRect (r); | |||
} | |||
} | |||
return true; | |||
} | |||
//------------------------------------------------------------------------ | |||
void CParamDisplay::draw (CDrawContext *pContext) | |||
{ | |||
if (hasBit (style, kNoDrawStyle)) | |||
return; | |||
std::string string; | |||
bool converted = false; | |||
if (valueToStringFunction) | |||
converted = valueToStringFunction (value, string, this); | |||
if (!converted) | |||
{ | |||
char tmp[255]; | |||
char precisionStr[10]; | |||
sprintf (precisionStr, "%%.%hhuf", valuePrecision); | |||
sprintf (tmp, precisionStr, value); | |||
string = tmp; | |||
} | |||
drawBack (pContext); | |||
drawPlatformText (pContext, UTF8String (string).getPlatformString ()); | |||
setDirty (false); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CParamDisplay::drawBack (CDrawContext* pContext, CBitmap* newBack) | |||
{ | |||
pContext->setDrawMode (kAliasing); | |||
auto lineWidth = getFrameWidth (); | |||
if (lineWidth < 0.) | |||
lineWidth = pContext->getHairlineSize (); | |||
if (newBack) | |||
{ | |||
newBack->draw (pContext, getViewSize (), backOffset); | |||
} | |||
else if (getDrawBackground ()) | |||
{ | |||
getDrawBackground ()->draw (pContext, getViewSize (), backOffset); | |||
} | |||
else | |||
{ | |||
if (!getTransparency ()) | |||
{ | |||
bool strokePath = !(hasBit (style, (k3DIn|k3DOut|kNoFrame))); | |||
pContext->setFillColor (backColor); | |||
if (hasBit (style, kRoundRectStyle)) | |||
{ | |||
CRect pathRect = getViewSize (); | |||
pathRect.inset (lineWidth/2., lineWidth/2.); | |||
SharedPointer<CGraphicsPath> path = owned (pContext->createRoundRectGraphicsPath (pathRect, roundRectRadius)); | |||
if (path) | |||
{ | |||
pContext->setDrawMode (kAntiAliasing); | |||
pContext->drawGraphicsPath (path, CDrawContext::kPathFilled); | |||
if (strokePath) | |||
{ | |||
pContext->setLineStyle (kLineSolid); | |||
pContext->setLineWidth (lineWidth); | |||
pContext->setFrameColor (frameColor); | |||
pContext->drawGraphicsPath (path, CDrawContext::kPathStroked); | |||
} | |||
} | |||
} | |||
else | |||
{ | |||
pContext->setDrawMode (kAntiAliasing); | |||
SharedPointer<CGraphicsPath> path = owned (pContext->createGraphicsPath ()); | |||
if (path) | |||
{ | |||
CRect frameRect = getViewSize (); | |||
if (strokePath) | |||
frameRect.inset (lineWidth/2., lineWidth/2.); | |||
path->addRect (frameRect); | |||
pContext->drawGraphicsPath (path, CDrawContext::kPathFilled); | |||
if (strokePath) | |||
{ | |||
pContext->setLineStyle (kLineSolid); | |||
pContext->setLineWidth (lineWidth); | |||
pContext->setFrameColor (frameColor); | |||
pContext->drawGraphicsPath (path, CDrawContext::kPathStroked); | |||
} | |||
} | |||
else | |||
{ | |||
pContext->drawRect (getViewSize (), kDrawFilled); | |||
if (strokePath) | |||
{ | |||
CRect frameRect = getViewSize (); | |||
frameRect.inset (lineWidth/2., lineWidth/2.); | |||
pContext->setLineStyle (kLineSolid); | |||
pContext->setLineWidth (lineWidth); | |||
pContext->setFrameColor (frameColor); | |||
pContext->drawRect (frameRect); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
// draw the frame for the 3D effect | |||
if (hasBit (style, (k3DIn|k3DOut))) | |||
{ | |||
CRect r (getViewSize ()); | |||
r.inset (lineWidth/2., lineWidth/2.); | |||
pContext->setDrawMode (kAliasing); | |||
pContext->setLineWidth (lineWidth); | |||
pContext->setLineStyle (kLineSolid); | |||
if (hasBit (style, k3DIn)) | |||
pContext->setFrameColor (backColor); | |||
else | |||
pContext->setFrameColor (frameColor); | |||
CPoint p; | |||
SharedPointer<CGraphicsPath> path = owned (pContext->createGraphicsPath ()); | |||
if (path) | |||
{ | |||
path->beginSubpath (p (r.left, r.bottom)); | |||
path->addLine (p (r.left, r.top)); | |||
path->addLine (p (r.right, r.top)); | |||
pContext->drawGraphicsPath (path, CDrawContext::kPathStroked); | |||
} | |||
else | |||
{ | |||
pContext->drawLine (CPoint (r.left, r.bottom), CPoint (r.left, r.top)); | |||
pContext->drawLine (CPoint (r.left, r.top), CPoint (r.right, r.top)); | |||
} | |||
if (hasBit (style, k3DIn)) | |||
pContext->setFrameColor (frameColor); | |||
else | |||
pContext->setFrameColor (backColor); | |||
path = owned (pContext->createGraphicsPath ()); | |||
if (path) | |||
{ | |||
path->beginSubpath (p (r.right, r.top)); | |||
path->addLine (p (r.right, r.bottom)); | |||
path->addLine (p (r.left, r.bottom)); | |||
pContext->drawGraphicsPath (path, CDrawContext::kPathStroked); | |||
} | |||
else | |||
{ | |||
pContext->drawLine (CPoint (r.right, r.top), CPoint (r.right, r.bottom)); | |||
pContext->drawLine (CPoint (r.right, r.bottom), CPoint (r.left, r.bottom)); | |||
} | |||
} | |||
} | |||
//------------------------------------------------------------------------ | |||
void CParamDisplay::drawPlatformText (CDrawContext* pContext, IPlatformString* string) | |||
{ | |||
drawPlatformText (pContext, string, getViewSize ()); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CParamDisplay::drawPlatformText (CDrawContext* pContext, IPlatformString* string, const CRect& size) | |||
{ | |||
if (!hasBit (style, kNoTextStyle)) | |||
{ | |||
pContext->saveGlobalState (); | |||
CRect textRect (size); | |||
textRect.inset (textInset.x, textInset.y); | |||
CRect oldClip; | |||
pContext->getClipRect (oldClip); | |||
CRect newClip (textRect); | |||
newClip.bound (oldClip); | |||
pContext->setClipRect (newClip); | |||
CPoint center (textRect.getCenter ()); | |||
CGraphicsTransform transform; | |||
transform.rotate (textRotation, center); | |||
CDrawContext::Transform ctxTransform (*pContext, transform); | |||
pContext->setDrawMode (kAntiAliasing); | |||
pContext->setFont (fontID); | |||
// draw darker text (as shadow) | |||
if (hasBit (style, kShadowText)) | |||
{ | |||
CRect newSize (textRect); | |||
newSize.offset (shadowTextOffset); | |||
pContext->setFontColor (shadowColor); | |||
pContext->drawString (string, newSize, horiTxtAlign, hasBit (style, kAntialias)); | |||
} | |||
pContext->setFontColor (fontColor); | |||
pContext->drawString (string, textRect, horiTxtAlign, hasBit (style, kAntialias)); | |||
pContext->restoreGlobalState (); | |||
} | |||
} | |||
//------------------------------------------------------------------------ | |||
void CParamDisplay::setFont (CFontRef fontID) | |||
{ | |||
if (this->fontID) | |||
this->fontID->forget (); | |||
this->fontID = fontID; | |||
fontID->remember (); | |||
drawStyleChanged (); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CParamDisplay::setFontColor (CColor color) | |||
{ | |||
// to force the redraw | |||
if (fontColor != color) | |||
{ | |||
fontColor = color; | |||
drawStyleChanged (); | |||
} | |||
} | |||
//------------------------------------------------------------------------ | |||
void CParamDisplay::setBackColor (CColor color) | |||
{ | |||
// to force the redraw | |||
if (backColor != color) | |||
{ | |||
backColor = color; | |||
drawStyleChanged (); | |||
} | |||
} | |||
//------------------------------------------------------------------------ | |||
void CParamDisplay::setFrameColor (CColor color) | |||
{ | |||
// to force the redraw | |||
if (frameColor != color) | |||
{ | |||
frameColor = color; | |||
drawStyleChanged (); | |||
} | |||
} | |||
//------------------------------------------------------------------------ | |||
void CParamDisplay::setShadowColor (CColor color) | |||
{ | |||
// to force the redraw | |||
if (shadowColor != color) | |||
{ | |||
shadowColor = color; | |||
drawStyleChanged (); | |||
} | |||
} | |||
//------------------------------------------------------------------------ | |||
void CParamDisplay::setShadowTextOffset (const CPoint& offset) | |||
{ | |||
if (shadowTextOffset != offset) | |||
{ | |||
shadowTextOffset = offset; | |||
drawStyleChanged (); | |||
} | |||
} | |||
//------------------------------------------------------------------------ | |||
void CParamDisplay::setHoriAlign (CHoriTxtAlign hAlign) | |||
{ | |||
// to force the redraw | |||
if (horiTxtAlign != hAlign) | |||
{ | |||
horiTxtAlign = hAlign; | |||
drawStyleChanged (); | |||
} | |||
} | |||
//------------------------------------------------------------------------ | |||
void CParamDisplay::setTextInset (const CPoint& p) | |||
{ | |||
if (textInset != p) | |||
{ | |||
textInset = p; | |||
drawStyleChanged (); | |||
} | |||
} | |||
//------------------------------------------------------------------------ | |||
void CParamDisplay::setTextRotation (double angle) | |||
{ | |||
while (angle < 0.) | |||
angle += 360.; | |||
while (angle > 360.) | |||
angle -= 360.; | |||
if (textRotation != angle) | |||
{ | |||
textRotation = angle; | |||
drawStyleChanged (); | |||
} | |||
} | |||
//------------------------------------------------------------------------ | |||
void CParamDisplay::setRoundRectRadius (const CCoord& radius) | |||
{ | |||
if (roundRectRadius != radius) | |||
{ | |||
roundRectRadius = radius; | |||
drawStyleChanged (); | |||
} | |||
} | |||
//------------------------------------------------------------------------ | |||
void CParamDisplay::setFrameWidth (const CCoord& width) | |||
{ | |||
if (frameWidth != width) | |||
{ | |||
frameWidth = width; | |||
drawStyleChanged (); | |||
} | |||
} | |||
//------------------------------------------------------------------------ | |||
void CParamDisplay::drawStyleChanged () | |||
{ | |||
setDirty (); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CParamDisplay::setBackOffset (const CPoint &offset) | |||
{ | |||
backOffset = offset; | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CParamDisplay::copyBackOffset () | |||
{ | |||
backOffset (getViewSize ().left, getViewSize ().top); | |||
} | |||
} // VSTGUI |
@@ -0,0 +1,153 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "ccontrol.h" | |||
#include "../cfont.h" | |||
#include "../ccolor.h" | |||
#include "../cdrawdefs.h" | |||
#include <functional> | |||
namespace VSTGUI { | |||
//----------------------------------------------------------------------------- | |||
using CParamDisplayValueToStringProc = bool (*) (float value, char utf8String[256], void* userData); | |||
//----------------------------------------------------------------------------- | |||
// CParamDisplay Declaration | |||
//! @brief a parameter display | |||
/// @ingroup views | |||
//----------------------------------------------------------------------------- | |||
class CParamDisplay : public CControl | |||
{ | |||
protected: | |||
enum StyleEnum | |||
{ | |||
StyleShadowText = 0, | |||
Style3DIn, | |||
Style3DOut, | |||
StyleNoText, | |||
StyleNoDraw, | |||
StyleRoundRect, | |||
StyleNoFrame, | |||
StyleAntialias, | |||
LastStyle | |||
}; | |||
public: | |||
CParamDisplay (const CRect& size, CBitmap* background = nullptr, int32_t style = 0); | |||
CParamDisplay (const CParamDisplay& paramDisplay); | |||
//----------------------------------------------------------------------------- | |||
/// @name CParamDisplay Methods | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
virtual void setFont (CFontRef fontID); | |||
const CFontRef getFont () const { return fontID; } | |||
virtual void setFontColor (CColor color); | |||
CColor getFontColor () const { return fontColor; } | |||
virtual void setBackColor (CColor color); | |||
CColor getBackColor () const { return backColor; } | |||
virtual void setFrameColor (CColor color); | |||
CColor getFrameColor () const { return frameColor; } | |||
virtual void setShadowColor (CColor color); | |||
CColor getShadowColor () const { return shadowColor; } | |||
virtual void setShadowTextOffset (const CPoint& offset); | |||
CPoint getShadowTextOffset () const { return shadowTextOffset; } | |||
virtual void setAntialias (bool state) { setBit (style, kAntialias, state); } | |||
bool getAntialias () const { return hasBit (style, kAntialias); } | |||
virtual void setHoriAlign (CHoriTxtAlign hAlign); | |||
CHoriTxtAlign getHoriAlign () const { return horiTxtAlign; } | |||
virtual void setTextInset (const CPoint& p); | |||
CPoint getTextInset () const { return textInset; } | |||
virtual void setTextRotation (double angle); | |||
double getTextRotation () const { return textRotation; } | |||
virtual void setRoundRectRadius (const CCoord& radius); | |||
CCoord getRoundRectRadius () const { return roundRectRadius; } | |||
virtual void setFrameWidth (const CCoord& width); | |||
CCoord getFrameWidth () const { return frameWidth; } | |||
using ValueToStringUserData = CParamDisplay; | |||
using ValueToStringFunction = std::function<bool (float value, char utf8String[256], CParamDisplay* display)>; | |||
void setValueToStringFunction (const ValueToStringFunction& valueToStringFunc); | |||
void setValueToStringFunction (ValueToStringFunction&& valueToStringFunc); | |||
using ValueToStringFunction2 = std::function<bool (float value, std::string& result, CParamDisplay* display)>; | |||
void setValueToStringFunction2 (const ValueToStringFunction2& valueToStringFunc); | |||
void setValueToStringFunction2 (ValueToStringFunction2&& valueToStringFunc); | |||
enum Style | |||
{ | |||
kShadowText = 1 << StyleShadowText, | |||
k3DIn = 1 << Style3DIn, | |||
k3DOut = 1 << Style3DOut, | |||
kNoTextStyle = 1 << StyleNoText, | |||
kNoDrawStyle = 1 << StyleNoDraw, | |||
kRoundRectStyle = 1 << StyleRoundRect, | |||
kNoFrame = 1 << StyleNoFrame, | |||
}; | |||
virtual void setStyle (int32_t val); | |||
int32_t getStyle () const; | |||
virtual void setPrecision (uint8_t precision); | |||
uint8_t getPrecision () const { return valuePrecision; } | |||
virtual void setBackOffset (const CPoint& offset); | |||
const CPoint& getBackOffset () const { return backOffset; } | |||
void copyBackOffset (); | |||
//@} | |||
void draw (CDrawContext* pContext) override; | |||
bool getFocusPath (CGraphicsPath& outPath) override; | |||
bool removed (CView* parent) override; | |||
CLASS_METHODS(CParamDisplay, CControl) | |||
protected: | |||
~CParamDisplay () noexcept override; | |||
virtual void drawBack (CDrawContext* pContext, CBitmap* newBack = nullptr); | |||
virtual void drawPlatformText (CDrawContext* pContext, IPlatformString* string); | |||
virtual void drawPlatformText (CDrawContext* pContext, IPlatformString* string, const CRect& size); | |||
virtual void drawStyleChanged (); | |||
ValueToStringFunction2 valueToStringFunction; | |||
enum StylePrivate { | |||
kAntialias = 1 << StyleAntialias, | |||
}; | |||
CHoriTxtAlign horiTxtAlign; | |||
int32_t style; | |||
uint8_t valuePrecision; | |||
CFontRef fontID; | |||
CColor fontColor; | |||
CColor backColor; | |||
CColor frameColor; | |||
CColor shadowColor; | |||
CPoint textInset; | |||
CPoint shadowTextOffset {1., 1.}; | |||
CPoint backOffset; | |||
CCoord roundRectRadius; | |||
CCoord frameWidth; | |||
double textRotation; | |||
}; | |||
} // VSTGUI |
@@ -0,0 +1,402 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#include "cscrollbar.h" | |||
#include "../cvstguitimer.h" | |||
#include "../animation/animations.h" | |||
#include "../animation/timingfunctions.h" | |||
#include "../cframe.h" | |||
#include "../cgraphicspath.h" | |||
#include "../cdrawcontext.h" | |||
namespace VSTGUI { | |||
//----------------------------------------------------------------------------- | |||
CScrollbar::CScrollbar (const CRect& size, IControlListener* listener, int32_t tag, ScrollbarDirection direction, const CRect& scrollSize) | |||
: CControl (size, listener, tag, nullptr) | |||
, direction (direction) | |||
, scrollSize (scrollSize) | |||
, scrollerArea (size) | |||
, stepValue (0.1f) | |||
, scrollerLength (0) | |||
, overlayStyle (false) | |||
, mouseIsInside (false) | |||
, drawer (nullptr) | |||
{ | |||
setTransparency (true); | |||
setWheelInc (0.05f); | |||
scrollerArea.inset (2, 2); | |||
calculateScrollerLength (); | |||
frameColor (0, 0, 0, 255); | |||
scrollerColor (0, 0, 255, 255); | |||
backgroundColor (255, 255, 255, 200); | |||
} | |||
//----------------------------------------------------------------------------- | |||
CScrollbar::CScrollbar (const CScrollbar& v) | |||
: CControl (v) | |||
, direction (v.direction) | |||
, scrollSize (v.scrollSize) | |||
, scrollerArea (v.scrollerArea) | |||
, stepValue (v.stepValue) | |||
, scrollerLength (v.scrollerLength) | |||
, frameColor (v.frameColor) | |||
, scrollerColor (v.scrollerColor) | |||
, backgroundColor (v.backgroundColor) | |||
, overlayStyle (v.overlayStyle) | |||
, mouseIsInside (false) | |||
, drawer (v.drawer) | |||
{ | |||
calculateScrollerLength (); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CScrollbar::setViewSize (const CRect &newSize, bool invalid) | |||
{ | |||
scrollerArea = newSize; | |||
scrollerArea.inset (2, 2); | |||
CControl::setViewSize (newSize, invalid); | |||
calculateScrollerLength (); | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CScrollbar::setScrollSize (const CRect& ssize) | |||
{ | |||
if (scrollSize != ssize) | |||
{ | |||
scrollSize = ssize; | |||
calculateScrollerLength (); | |||
setDirty (true); | |||
} | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CScrollbar::calculateScrollerLength () | |||
{ | |||
CCoord newScrollerLength; | |||
if (direction == kHorizontal) | |||
{ | |||
double factor = scrollSize.getWidth () > 0. ? getViewSize ().getWidth () / scrollSize.getWidth () : 0.; | |||
if (factor >= 1.f) | |||
factor = 0; | |||
newScrollerLength = (CCoord) (getViewSize ().getWidth () * factor); | |||
} | |||
else | |||
{ | |||
double factor = scrollSize.getHeight () > 0 ? getViewSize ().getHeight () / scrollSize.getHeight () : 0.; | |||
if (factor >= 1.f) | |||
factor = 0; | |||
newScrollerLength = (CCoord) (getViewSize ().getHeight () * factor); | |||
} | |||
if (newScrollerLength < 8. && newScrollerLength > 0.) | |||
newScrollerLength = 8.; | |||
if (newScrollerLength != scrollerLength) | |||
{ | |||
scrollerLength = newScrollerLength; | |||
setDirty (true); | |||
} | |||
} | |||
//----------------------------------------------------------------------------- | |||
CRect CScrollbar::getScrollerRect () | |||
{ | |||
CRect scrollerRect (scrollerArea); | |||
CCoord l = (direction == kHorizontal) ? scrollerArea.getWidth () : scrollerArea.getHeight (); | |||
CCoord scrollerOffset = (CCoord) (value * (l - scrollerLength)); | |||
if (direction == kHorizontal) | |||
{ | |||
scrollerRect.setWidth (scrollerLength); | |||
scrollerRect.offset (scrollerOffset, 0); | |||
} | |||
else | |||
{ | |||
scrollerRect.setHeight (scrollerLength); | |||
scrollerRect.offset (0, scrollerOffset); | |||
} | |||
return scrollerRect; | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CScrollbar::doStepping () | |||
{ | |||
CRect scrollerRect = getScrollerRect (); | |||
if (timer) | |||
{ | |||
if (!getViewSize ().pointInside (startPoint) || scrollerRect.pointInside (startPoint)) | |||
return; | |||
} | |||
bool dir = (direction == kHorizontal && startPoint.x < scrollerRect.left) || (direction == kVertical && startPoint.y < scrollerRect.top); | |||
float newValue; | |||
if (direction == kHorizontal) | |||
{ | |||
if (dir) | |||
newValue = value - (float)scrollerLength / (float)scrollerArea.getWidth (); | |||
else | |||
newValue = value + (float)scrollerLength / (float)scrollerArea.getWidth (); | |||
} | |||
else | |||
{ | |||
if (dir) | |||
newValue = value - (float)scrollerLength / (float)scrollerArea.getHeight (); | |||
else | |||
newValue = value + (float)scrollerLength / (float)scrollerArea.getHeight (); | |||
} | |||
if (newValue < 0.f) newValue = 0.f; | |||
if (newValue > 1.f) newValue = 1.f; | |||
if (newValue != value) | |||
{ | |||
value = newValue; | |||
valueChanged (); | |||
invalid (); | |||
} | |||
} | |||
//----------------------------------------------------------------------------- | |||
CMessageResult CScrollbar::notify (CBaseObject* sender, IdStringPtr message) | |||
{ | |||
if (message == CVSTGUITimer::kMsgTimer && timer) | |||
{ | |||
doStepping (); | |||
timer->setFireTime (80); | |||
return kMessageNotified; | |||
} | |||
return kMessageUnknown; | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CScrollbar::setOverlayStyle (bool state) | |||
{ | |||
if (overlayStyle != state) | |||
{ | |||
overlayStyle = state; | |||
setAlphaValue (overlayStyle ? 0.001f : 1.f); | |||
} | |||
} | |||
//----------------------------------------------------------------------------- | |||
CMouseEventResult CScrollbar::onMouseEntered (CPoint& where, const CButtonState& buttons) | |||
{ | |||
if (overlayStyle && scrollerLength != 0) | |||
{ | |||
addAnimation ("AlphaValueAnimation", new Animation::AlphaValueAnimation (1.f), new Animation::LinearTimingFunction (100)); | |||
} | |||
mouseIsInside = true; | |||
return kMouseEventNotHandled; | |||
} | |||
//----------------------------------------------------------------------------- | |||
CMouseEventResult CScrollbar::onMouseExited (CPoint& where, const CButtonState& buttons) | |||
{ | |||
if (overlayStyle && scrollerLength != 0) | |||
{ | |||
Animation::ITimingFunction* timingFunction = nullptr; | |||
if (getAlphaValue () == 1.f) | |||
{ | |||
Animation::InterpolationTimingFunction* interpolTimingFunction = new Animation::InterpolationTimingFunction (400); | |||
interpolTimingFunction->addPoint (300.f/400.f, 1.f); | |||
timingFunction = interpolTimingFunction; | |||
} | |||
else | |||
timingFunction = new Animation::LinearTimingFunction (100); | |||
addAnimation ("AlphaValueAnimation", new Animation::AlphaValueAnimation (0.001f), timingFunction); | |||
} | |||
mouseIsInside = false; | |||
return kMouseEventNotHandled; | |||
} | |||
//----------------------------------------------------------------------------- | |||
CMouseEventResult CScrollbar::onMouseDown (CPoint &where, const CButtonState& buttons) | |||
{ | |||
if (buttons != kLButton || scrollerLength == 0) | |||
return kMouseDownEventHandledButDontNeedMovedOrUpEvents; | |||
startPoint = where; | |||
scrollerRect = getScrollerRect (); | |||
scrolling = scrollerRect.pointInside (where); | |||
if (scrolling) | |||
{ | |||
scrollerRect = getScrollerRect (); | |||
return kMouseEventHandled; | |||
} | |||
else if (scrollerArea.pointInside (where)) | |||
{ | |||
doStepping (); | |||
timer = makeOwned<CVSTGUITimer> (this, 250, true); | |||
return kMouseEventHandled; | |||
} | |||
return kMouseDownEventHandledButDontNeedMovedOrUpEvents; | |||
} | |||
//----------------------------------------------------------------------------- | |||
CMouseEventResult CScrollbar::onMouseUp (CPoint &where, const CButtonState& buttons) | |||
{ | |||
timer = nullptr; | |||
return kMouseEventHandled; | |||
} | |||
//----------------------------------------------------------------------------- | |||
CMouseEventResult CScrollbar::onMouseMoved (CPoint &where, const CButtonState& buttons) | |||
{ | |||
if (buttons & kLButton) | |||
{ | |||
if (scrolling) | |||
{ | |||
float newValue = 0.f; | |||
CPoint newPoint (where); | |||
newPoint.x -= startPoint.x - scrollerRect.left; | |||
newPoint.y -= startPoint.y - scrollerRect.top; | |||
if (direction == kHorizontal) | |||
{ | |||
newValue = (float)((float)(newPoint.x - scrollerArea.left) / ((float)scrollerArea.getWidth () - scrollerRect.getWidth ())); | |||
} | |||
else | |||
{ | |||
newValue = (float)((float)(newPoint.y - scrollerArea.top) / ((float)scrollerArea.getHeight () - scrollerRect.getHeight ())); | |||
} | |||
if (newValue < 0.f) newValue = 0.f; | |||
if (newValue > 1.f) newValue = 1.f; | |||
if (newValue != value) | |||
{ | |||
value = newValue; | |||
valueChanged (); | |||
invalid (); | |||
} | |||
} | |||
else | |||
{ | |||
CPoint old (startPoint); | |||
startPoint = where; | |||
CRect scollerRect = getScrollerRect (); | |||
if (getViewSize ().pointInside (where) && scollerRect.pointInside (old) && !scrollerRect.pointInside (startPoint)) | |||
doStepping (); | |||
} | |||
return kMouseEventHandled; | |||
} | |||
return kMouseEventNotHandled; | |||
} | |||
//------------------------------------------------------------------------ | |||
CMouseEventResult CScrollbar::onMouseCancel () | |||
{ | |||
timer = nullptr; | |||
return kMouseEventHandled; | |||
} | |||
//------------------------------------------------------------------------ | |||
void CScrollbar::onVisualChange () | |||
{ | |||
if (isAttached () && overlayStyle && !mouseIsInside) | |||
{ | |||
if (scrollerLength != 0) | |||
{ | |||
auto timingFunction = new Animation::InterpolationTimingFunction (1100); | |||
timingFunction->addPoint (1000.f/1100.f, 0); | |||
addAnimation ("AlphaValueAnimation", new Animation::AlphaValueAnimation (0.001f), timingFunction); | |||
setAlphaValue (1.f); | |||
} | |||
else | |||
{ | |||
removeAnimation ("AlphaValueAnimation"); | |||
setAlphaValue (0.f); | |||
} | |||
} | |||
} | |||
//------------------------------------------------------------------------ | |||
bool CScrollbar::onWheel (const CPoint &where, const CMouseWheelAxis &axis, const float &_distance, const CButtonState &buttons) | |||
{ | |||
if (scrollerLength == 0 || !getMouseEnabled ()) | |||
return false; | |||
if (buttons != 0 && !(buttons & (kShift|kMouseWheelInverted))) | |||
return false; | |||
if (direction == kHorizontal && axis == kMouseWheelAxisY) | |||
return false; | |||
if (direction == kVertical && axis == kMouseWheelAxisX) | |||
return false; | |||
float distance = _distance; | |||
if (direction == kHorizontal && axis == kMouseWheelAxisY) | |||
distance *= -1; | |||
if (buttons & kMouseWheelInverted) | |||
distance *= -1; | |||
if (buttons & kShift) | |||
value -= 0.1f * distance * wheelInc; | |||
else | |||
value -= distance * wheelInc; | |||
bounceValue (); | |||
if (isDirty ()) | |||
{ | |||
onVisualChange (); | |||
valueChanged (); | |||
invalid (); | |||
} | |||
return true; | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CScrollbar::drawBackground (CDrawContext* pContext) | |||
{ | |||
CRect r (getViewSize ()); | |||
if (drawer) | |||
drawer->drawScrollbarBackground (pContext, r, direction, this); | |||
else | |||
{ | |||
pContext->setDrawMode (kAliasing); | |||
pContext->setLineWidth (1); | |||
pContext->setFillColor (backgroundColor); | |||
pContext->setFrameColor (frameColor); | |||
pContext->setLineStyle (kLineSolid); | |||
pContext->drawRect (r, kDrawFilledAndStroked); | |||
} | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CScrollbar::drawScroller (CDrawContext* pContext, const CRect& size) | |||
{ | |||
CRect r (size); | |||
if (drawer) | |||
drawer->drawScrollbarScroller (pContext, r, direction, this); | |||
else | |||
{ | |||
pContext->setLineWidth (1); | |||
pContext->setFillColor (scrollerColor); | |||
pContext->setFrameColor (frameColor); | |||
CCoord wideness = (direction == kVertical ? getWidth() : getHeight()) / 2 - 2; | |||
auto path = (wideness > 2) ? owned (pContext->createGraphicsPath ()) : nullptr; | |||
if (path) | |||
{ | |||
if (wideness > 4) | |||
wideness = 4; | |||
pContext->setDrawMode (kAntiAliasing|kNonIntegralMode); | |||
path->addRoundRect (r, wideness); | |||
pContext->drawGraphicsPath (path, CDrawContext::kPathFilled); | |||
pContext->drawGraphicsPath (path, CDrawContext::kPathStroked); | |||
} | |||
else | |||
{ | |||
pContext->setDrawMode (kAliasing|kNonIntegralMode); | |||
pContext->drawRect (r, kDrawFilledAndStroked); | |||
} | |||
} | |||
} | |||
//----------------------------------------------------------------------------- | |||
void CScrollbar::draw (CDrawContext* pContext) | |||
{ | |||
drawBackground (pContext); | |||
if (scrollerLength > 0) | |||
{ | |||
CRect scrollerRect = getScrollerRect (); | |||
drawScroller (pContext, scrollerRect); | |||
} | |||
setDirty (false); | |||
} | |||
} |
@@ -0,0 +1,109 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "ccontrol.h" | |||
#include "../ccolor.h" | |||
namespace VSTGUI { | |||
//----------------------------------------------------------------------------- | |||
// CScrollbar Declaration | |||
//! @brief a scrollbar control | |||
/// @ingroup controls | |||
//----------------------------------------------------------------------------- | |||
class CScrollbar : public CControl | |||
{ | |||
public: | |||
enum ScrollbarDirection { | |||
kHorizontal, | |||
kVertical | |||
}; | |||
CScrollbar (const CRect& size, IControlListener* listener, int32_t tag, ScrollbarDirection style, const CRect& scrollSize); | |||
CScrollbar (const CScrollbar& scrollbar); | |||
//----------------------------------------------------------------------------- | |||
/// @name CScrollbar Methods | |||
//----------------------------------------------------------------------------- | |||
//@{ | |||
virtual void setDrawer (IScrollbarDrawer* d) { drawer = d; } | |||
virtual void setScrollSize (const CRect& ssize); | |||
virtual void setStep (float newStep) { stepValue = newStep; } | |||
CRect& getScrollSize (CRect& rect) const { rect = scrollSize; return rect; } | |||
float getStep () const { return stepValue; } | |||
virtual void setFrameColor (const CColor& color) { frameColor = color; } | |||
virtual void setScrollerColor (const CColor& color) { scrollerColor = color; } | |||
virtual void setBackgroundColor (const CColor& color) { backgroundColor = color; } | |||
CColor getFrameColor () const { return frameColor; } | |||
CColor getScrollerColor () const { return scrollerColor; } | |||
CColor getBackgroundColor () const { return backgroundColor; } | |||
bool getOverlayStyle () const { return overlayStyle; } | |||
virtual void setOverlayStyle (bool state); | |||
virtual void onVisualChange (); | |||
CRect getScrollerRect (); | |||
//@} | |||
// overwrite | |||
void draw (CDrawContext* pContext) override; | |||
bool onWheel (const CPoint& where, const CMouseWheelAxis& axis, const float& distance, const CButtonState& buttons) override; | |||
CMouseEventResult onMouseDown (CPoint& where, const CButtonState& buttons) override; | |||
CMouseEventResult onMouseUp (CPoint& where, const CButtonState& buttons) override; | |||
CMouseEventResult onMouseMoved (CPoint& where, const CButtonState& buttons) override; | |||
CMouseEventResult onMouseCancel () override; | |||
CMessageResult notify (CBaseObject* sender, IdStringPtr message) override; | |||
void setViewSize (const CRect& newSize, bool invalid) override; | |||
CMouseEventResult onMouseEntered (CPoint& where, const CButtonState& buttons) override; | |||
CMouseEventResult onMouseExited (CPoint& where, const CButtonState& buttons) override; | |||
CLASS_METHODS(CScrollbar, CControl) | |||
//----------------------------------------------------------------------------- | |||
protected: | |||
~CScrollbar () noexcept override = default; | |||
void drawBackground (CDrawContext* pContext); | |||
void drawScroller (CDrawContext* pContext, const CRect& size); | |||
void calculateScrollerLength (); | |||
void doStepping (); | |||
ScrollbarDirection direction; | |||
CRect scrollSize; | |||
CRect scrollerArea; | |||
float stepValue; | |||
CCoord scrollerLength; | |||
CColor frameColor; | |||
CColor scrollerColor; | |||
CColor backgroundColor; | |||
bool overlayStyle; | |||
bool mouseIsInside; | |||
IScrollbarDrawer* drawer; | |||
private: | |||
SharedPointer<CVSTGUITimer> timer; | |||
CPoint startPoint; | |||
CRect scrollerRect; | |||
bool scrolling; | |||
}; | |||
//----------------------------------------------------------------------------- | |||
class IScrollbarDrawer | |||
//----------------------------------------------------------------------------- | |||
{ | |||
public: | |||
virtual void drawScrollbarBackground (CDrawContext* pContext, const CRect& size, CScrollbar::ScrollbarDirection direction, CScrollbar* bar) = 0; | |||
virtual void drawScrollbarScroller (CDrawContext* pContext, const CRect& size, CScrollbar::ScrollbarDirection direction, CScrollbar* bar) = 0; | |||
}; | |||
} // VSTGUI |
@@ -0,0 +1,165 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#include "csearchtextedit.h" | |||
#include "../cframe.h" | |||
#include "../cgraphicspath.h" | |||
namespace VSTGUI { | |||
//---------------------------------------------------------------------------------------------------- | |||
CSearchTextEdit::CSearchTextEdit (const CRect& size, IControlListener* listener, int32_t tag, UTF8StringPtr txt, CBitmap* background, const int32_t style) | |||
: CTextEdit (size, listener, tag, nullptr, background, style) | |||
{ | |||
setPlaceholderString ("Search"); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CSearchTextEdit::setClearMarkInset (CPoint inset) | |||
{ | |||
if (inset != clearMarkInset) | |||
{ | |||
clearMarkInset = inset; | |||
invalid (); | |||
} | |||
} | |||
//------------------------------------------------------------------------ | |||
CPoint CSearchTextEdit::getClearMarkInset () const | |||
{ | |||
return clearMarkInset; | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
CRect CSearchTextEdit::getClearMarkRect () const | |||
{ | |||
CRect r (getViewSize ()); | |||
if (getHoriAlign () == kRightText) | |||
r.right = r.left + getHeight (); | |||
else | |||
r.left = r.right - getHeight (); | |||
r.inset (getClearMarkInset ()); | |||
return r; | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
CMouseEventResult CSearchTextEdit::onMouseDown (CPoint& where, const CButtonState& buttons) | |||
{ | |||
if (buttons.isLeftButton ()) | |||
{ | |||
if (!getText ().empty ()) | |||
{ | |||
if (getClearMarkRect ().pointInside (where)) | |||
{ | |||
beginEdit (); | |||
setText (""); | |||
valueChanged (); | |||
endEdit (); | |||
return kMouseDownEventHandledButDontNeedMovedOrUpEvents; | |||
} | |||
} | |||
} | |||
return CTextEdit::onMouseDown (where, buttons); | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
void CSearchTextEdit::drawClearMark (CDrawContext* context) const | |||
{ | |||
if (!((platformControl && !platformControl->getText ().empty ()) || !getText ().empty ())) | |||
return; | |||
auto path = owned (context->createGraphicsPath ()); | |||
if (path == nullptr) | |||
return; | |||
CRect r = getClearMarkRect (); | |||
CColor color (fontColor); | |||
color.alpha /= 2; | |||
context->setFillColor (color); | |||
context->setDrawMode (kAntiAliasing); | |||
context->drawEllipse (r, kDrawFilled); | |||
double h,s,v; | |||
color.toHSV (h, s, v); | |||
v = 1. - v; | |||
color.fromHSV (h, s, v); | |||
context->setFrameColor (color); | |||
context->setLineWidth (2.); | |||
r.inset (r.getWidth () / (M_PI * 2.) + 1, r.getHeight () / (M_PI * 2.) + 1); | |||
path->beginSubpath (r.getTopLeft ()); | |||
path->addLine (r.getBottomRight ()); | |||
path->beginSubpath (r.getBottomLeft ()); | |||
path->addLine (r.getTopRight ()); | |||
context->setDrawMode (kAntiAliasing); | |||
context->drawGraphicsPath (path, CDrawContext::kPathStroked); | |||
} | |||
//---------------------------------------------------------------------------------------------------- | |||
void CSearchTextEdit::draw (CDrawContext *pContext) | |||
{ | |||
drawBack (pContext); | |||
drawClearMark (pContext); | |||
if (platformControl) | |||
{ | |||
setDirty (false); | |||
return; | |||
} | |||
pContext->setDrawMode (kAntiAliasing); | |||
CColor origFontColor (fontColor); | |||
if (getText ().empty ()) | |||
{ | |||
CColor color (fontColor); | |||
color.alpha /= 2; | |||
setFontColor (color); | |||
drawPlatformText (pContext, getPlaceholderString ().getPlatformString (), getTextRect ()); | |||
} | |||
else | |||
drawPlatformText (pContext, getText ().getPlatformString (), getTextRect ()); | |||
setDirty (false); | |||
setFontColor (origFontColor); | |||
} | |||
//------------------------------------------------------------------------ | |||
CRect CSearchTextEdit::getTextRect () const | |||
{ | |||
CRect rect = getViewSize (); | |||
CRect cmr = getClearMarkRect (); | |||
if (getHoriAlign () == kRightText) | |||
rect.left = cmr.right; | |||
else | |||
rect.right = cmr.left; | |||
return rect; | |||
} | |||
//------------------------------------------------------------------------ | |||
CRect CSearchTextEdit::platformGetSize () const | |||
{ | |||
return translateToGlobal (getTextRect ()); | |||
} | |||
//------------------------------------------------------------------------ | |||
CRect CSearchTextEdit::platformGetVisibleSize () const | |||
{ | |||
CRect rect = getTextRect (); | |||
if (getParentView ()) | |||
rect = getParentView ()->asViewContainer ()->getVisibleSize (rect); | |||
else if (getFrame ()) | |||
rect = getFrame ()->getVisibleSize (rect); | |||
return translateToGlobal (rect); | |||
} | |||
//------------------------------------------------------------------------ | |||
void CSearchTextEdit::platformTextDidChange () | |||
{ | |||
invalidRect (getClearMarkRect ()); | |||
CTextEdit::platformTextDidChange (); | |||
} | |||
//------------------------------------------------------------------------ | |||
} // VSTGUI |
@@ -0,0 +1,37 @@ | |||
// This file is part of VSTGUI. It is subject to the license terms | |||
// in the LICENSE file found in the top-level directory of this | |||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE | |||
#pragma once | |||
#include "ctextedit.h" | |||
namespace VSTGUI { | |||
//----------------------------------------------------------------------------- | |||
/** Search text edit field | |||
* @ingroup new_in_4_5 | |||
*/ | |||
class CSearchTextEdit : public CTextEdit | |||
{ | |||
public: | |||
CSearchTextEdit (const CRect& size, IControlListener* listener, int32_t tag, UTF8StringPtr txt = nullptr, CBitmap* background = nullptr, const int32_t style = 0); | |||
void setClearMarkInset (CPoint inset); | |||
CPoint getClearMarkInset () const; | |||
void draw (CDrawContext *pContext) override; | |||
CMouseEventResult onMouseDown (CPoint& where, const CButtonState& buttons) override; | |||
protected: | |||
void drawClearMark (CDrawContext* context) const; | |||
CRect getClearMarkRect () const; | |||
CRect getTextRect () const; | |||
CRect platformGetSize () const override; | |||
CRect platformGetVisibleSize () const override; | |||
void platformTextDidChange () override; | |||
CPoint clearMarkInset {2., 2.}; | |||
}; | |||
} // VSTGUI |