Initial release

This commit is contained in:
civ
2026-08-16 18:24:52 +07:00
commit 876886a39a
13244 changed files with 2353959 additions and 0 deletions
+112
View File
@@ -0,0 +1,112 @@
#Language: Cpp
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Right
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: true
AllowShortIfStatementsOnASingleLine: false
AllowShortLambdasOnASingleLine: Inline
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: true
BinPackArguments: true
BinPackParameters: true
BreakBeforeBraces: Custom
BraceWrapping:
AfterCaseLabel: true
AfterClass: true
AfterControlStatement: true
AfterEnum: true
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: true
AfterStruct: true
AfterUnion: true
AfterExternBlock: true
BeforeCatch: true
BeforeElse: true
# BeforeLambdaBody: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeInheritanceComma: true
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeComma
BreakAfterJavaFieldAnnotations: false
BreakInheritanceList: AfterComma
BreakStringLiterals: true
ColumnLimit: 100
# CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 0
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: None
IndentWidth: 4
IndentWrappedFunctionNames: true
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
SpaceBeforeCpp11BracedList: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: Always
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 4
UseTab: Always
+164
View File
@@ -0,0 +1,164 @@
##########################################################################################
cmake_minimum_required(VERSION 3.25.0)
if(NOT PROJECT_NAME)
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15 CACHE STRING "")
project(vstgui)
set(VSTGUI_MAIN_PROJECT_BUILD 1)
endif()
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake/modules/")
include(vstgui_init)
##########################################################################################
function(vstgui_set_cxx_version target version)
target_compile_features(${target} PUBLIC cxx_std_${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 "")
get_property(sources TARGET ${target} PROPERTY SOURCES)
foreach(file ${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(LINUX)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
find_package (Wayland REQUIRED COMPONENTS client server protocols)
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)
pkg_check_modules(GLIB REQUIRED glib-2.0)
pkg_check_modules(CAIRO REQUIRED cairo)
pkg_check_modules(PANGO REQUIRED pangocairo pangoft2)
pkg_check_modules(FONTCONFIG REQUIRED fontconfig)
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}
${GLIB_LIBRARIES}
${CAIRO_LIBRARIES}
${PANGO_LIBRARIES}
${FONTCONFIG_LIBRARIES}
Threads::Threads
dl
vstgui_wayland_protocols
)
endif()
##########################################################################################
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(STATUS "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)
#### UIDescription Scripting
option(VSTGUI_UISCRIPTING "Add Scripting Support to the UIDescription editor" ON)
if(VSTGUI_UISCRIPTING)
add_compile_definitions(VSTGUI_UISCRIPTING)
add_subdirectory(uidescription-scripting)
endif(VSTGUI_UISCRIPTING)
##########################################################################################
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()
if(NOT DEFINED VSTGUI_TOOLS)
option(VSTGUI_TOOLS "Build VSTGUI Tools" ON)
endif()
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()
File diff suppressed because it is too large Load Diff
@@ -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,6 @@
After checking out the sources, you need to run doxygen for the actual documentation.
- Please download doxygen here: http://www.doxygen.nl
- Run the doxygen app
- Load the config file from vstgui/doxygen/Doxyfile
- Switch to the run tab and execute "Run doxygen"
@@ -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,192 @@
#************************************************************************************************
#
# Wayland Server Delegate
#
# Copyright (c) 2023 CCL Software Licensing GmbH. 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 wayland-server-delegate project 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 HOLDERS 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.
#
# Filename : FindWayland.cmake
# Description : Find Wayland libraries and generate protocol headers
#
#[*****************************************************************************************[.rst:
# FindWayland
# -------
#
# Finds wayland libraries and includes.
#
# Targets
# ^^^^^^^
#
# This module provides the following targets, if found:
#
# ``wayland-client``
# ``wayland-server``
# ``wayland-egl``
# ``wayland-protocols``
#
# Result Variables
# ^^^^^^^^^^^^^^^^
#
# This will define the following variables:
#
# ``WAYLAND_FOUND``
# True if wayland libraries have been found.
# ``WAYLAND_INCLUDE_DIRS``
# Wayland include directories.
# ``WAYLAND_LIBRARIES``
# Wayland libraries.
# ``WAYLAND_DEFINITIONS``
# Wayland compiler definitions.
#]**********************************************************************************************]
find_package (PkgConfig)
pkg_check_modules (PKG_WAYLAND QUIET wayland-client)
set (WAYLAND_DEFINITIONS ${PKG_WAYLAND_CFLAGS})
set (WAYLAND_VERSION ${PKG_WAYLAND_VERSION})
# Find wayland libraries / includes
# When cross-compiling, these libraries and headers need to be found for the target architecture.
find_path (WAYLAND_CLIENT_INCLUDE_DIR NAMES wayland-client.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS} ONLY_CMAKE_FIND_ROOT_PATH)
mark_as_advanced (WAYLAND_CLIENT_INCLUDE_DIR)
if ("client" IN_LIST Wayland_FIND_COMPONENTS)
find_library (WAYLAND_CLIENT_LIBRARIES NAMES wayland-client HINTS ${PKG_WAYLAND_LIBRARY_DIRS})
find_library (WAYLAND_CURSOR_LIBRARIES NAMES wayland-cursor HINTS ${PKG_WAYLAND_LIBRARY_DIRS})
endif ()
if ("egl" IN_LIST Wayland_FIND_COMPONENTS)
find_library (WAYLAND_EGL_LIBRARIES NAMES wayland-egl HINTS ${PKG_WAYLAND_LIBRARY_DIRS})
endif ()
if ("server" IN_LIST Wayland_FIND_COMPONENTS)
find_library (WAYLAND_SERVER_LIBRARIES NAMES wayland-server HINTS ${PKG_WAYLAND_LIBRARY_DIRS})
endif ()
if ("protocols" IN_LIST Wayland_FIND_COMPONENTS)
# Find wayland-scanner
# When cross-compiling, this program needs to be found for the host architecture. However, we need to make sure that the version matches the library version on the target system.
find_program (WAYLAND_SCANNER NAMES "wayland-scanner.${WAYLAND_VERSION}")
if (NOT WAYLAND_SCANNER)
find_program (WAYLAND_SCANNER NAMES wayland-scanner)
endif ()
mark_as_advanced (WAYLAND_SCANNER)
# Generate extra protocol headers
find_path (WAYLAND_PROTOCOLS_BASEDIR NAMES "stable/xdg-shell/xdg-shell.xml" HINTS "/usr/share/wayland-protocols")
mark_as_advanced (WAYLAND_PROTOCOLS_BASEDIR)
list (APPEND WAYLAND_PROTOCOLS
"stable/xdg-shell/xdg-shell.xml"
"stable/linux-dmabuf/linux-dmabuf-v1.xml"
"unstable/xdg-decoration/xdg-decoration-unstable-v1.xml"
)
list (REMOVE_DUPLICATES WAYLAND_PROTOCOLS)
set (WAYLAND_PROTOCOLS_DIR "${CMAKE_CURRENT_BINARY_DIR}/wayland-protocols")
file (MAKE_DIRECTORY ${WAYLAND_PROTOCOLS_DIR})
foreach (protocol ${WAYLAND_PROTOCOLS})
get_filename_component (protocol_name "${protocol}" NAME_WLE)
# Generate client header
set (header "${WAYLAND_PROTOCOLS_DIR}/${protocol_name}-client-protocol.h")
if (NOT EXISTS "${WAYLAND_PROTOCOLS_BASEDIR}/${protocol}")
message (WARNING "Unknown Wayland protocol: ${protocol_name}")
file (WRITE "${header}" "")
continue ()
endif ()
execute_process(
COMMAND
/bin/sh -c "${WAYLAND_SCANNER} client-header < ${WAYLAND_PROTOCOLS_BASEDIR}/${protocol} > \"${header}\""
)
# add_custom_command (OUTPUT ${header}
# COMMAND /bin/sh -c "${WAYLAND_SCANNER} client-header < ${WAYLAND_PROTOCOLS_BASEDIR}/${protocol} > \"${header}\""
# DEPENDS ${WAYLAND_PROTOCOLS_BASEDIR}/${protocol}
# VERBATIM USES_TERMINAL
# )
list (APPEND protocol_headers ${header})
# Generate server header
set (header "${WAYLAND_PROTOCOLS_DIR}/${protocol_name}-server-protocol.h")
execute_process(
COMMAND
/bin/sh -c "${WAYLAND_SCANNER} server-header < ${WAYLAND_PROTOCOLS_BASEDIR}/${protocol} > \"${header}\""
)
# add_custom_command (OUTPUT ${header}
# COMMAND /bin/sh -c "${WAYLAND_SCANNER} server-header < ${WAYLAND_PROTOCOLS_BASEDIR}/${protocol} > \"${header}\""
# DEPENDS ${WAYLAND_PROTOCOLS_BASEDIR}/${protocol}
# VERBATIM USES_TERMINAL
# )
list (APPEND protocol_headers ${header})
# Generate source file
set (sourcefile "${WAYLAND_PROTOCOLS_DIR}/${protocol_name}-protocol.c")
execute_process(
COMMAND
/bin/sh -c "${WAYLAND_SCANNER} private-code < ${WAYLAND_PROTOCOLS_BASEDIR}/${protocol} > \"${sourcefile}\""
)
# add_custom_command (OUTPUT ${sourcefile}
# COMMAND /bin/sh -c "${WAYLAND_SCANNER} private-code < ${WAYLAND_PROTOCOLS_BASEDIR}/${protocol} > \"${sourcefile}\""
# DEPENDS ${WAYLAND_PROTOCOLS_BASEDIR}/${protocol}
# VERBATIM USES_TERMINAL
# )
list (APPEND protocol_source_files "${sourcefile}")
endforeach ()
add_library (vstgui_wayland_protocols OBJECT ${protocol_headers} ${protocol_source_files} ${CMAKE_CURRENT_LIST_FILE})
set_target_properties (vstgui_wayland_protocols PROPERTIES
USE_FOLDERS ON
FOLDER libs
)
endif ()
# Set result variables
set (WAYLAND_LIBRARIES ${WAYLAND_CLIENT_LIBRARIES} ${WAYLAND_CURSOR_LIBRARIES} ${WAYLAND_EGL_LIBRARIES} ${WAYLAND_SERVER_LIBRARIES})
set (WAYLAND_INCLUDE_DIRS ${WAYLAND_CLIENT_INCLUDE_DIR} ${WAYLAND_PROTOCOLS_DIR})
list (REMOVE_DUPLICATES WAYLAND_INCLUDE_DIRS)
if (TARGET vstgui_wayland_protocols)
list (APPEND WAYLAND_LIBRARIES vstgui_wayland_protocols)
target_include_directories (vstgui_wayland_protocols PUBLIC ${WAYLAND_INCLUDE_DIRS})
endif ()
include (FindPackageHandleStandardArgs)
find_package_handle_standard_args (Wayland
FOUND_VAR WAYLAND_FOUND
REQUIRED_VARS WAYLAND_LIBRARIES WAYLAND_INCLUDE_DIRS
VERSION_VAR WAYLAND_VERSION
)
@@ -0,0 +1,109 @@
cmake_minimum_required(VERSION 3.25.0)
enable_language(CXX)
if(NOT DEFINED VSTGUI_CXX_VERSION)
set(VSTGUI_CXX_VERSION "17" CACHE STRING "The C++ language version to compile VSTGUI")
endif()
if(NOT DEFINED VSTGUI_ENABLE_DEPRECATED_METHODS)
option(VSTGUI_ENABLE_DEPRECATED_METHODS "Enable VSTGUI deprecated methods" ON)
endif()
if(NOT DEFINED VSTGUI_ENABLE_XMLPARSER)
option(VSTGUI_ENABLE_XMLPARSER "Enable building deprecated Expat based XML Parser" ON)
endif()
if(NOT DEFINED VSTGUI_ENABLE_OPENGL_SUPPORT)
option(VSTGUI_ENABLE_OPENGL_SUPPORT "Enable OpenGL support" ON)
endif()
##########################################################################################
if(UNIX AND NOT CMAKE_HOST_APPLE)
set(LINUX TRUE CACHE INTERNAL "VSTGUI linux platform")
endif()
##########################################################################################
if(CMAKE_CONFIGURATION_TYPES)
set(CMAKE_CONFIGURATION_TYPES Debug Release ReleaseLTO)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
endif()
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 "")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g")
enable_language(OBJCXX)
endif()
if(LINUX)
set(VSTGUI_LTO_COMPILER_FLAGS "-O3 -flto")
set(VSTGUI_LTO_LINKER_FLAGS "")
if(VSTGUI_WARN_EVERYTHING)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-multichar")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g")
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_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zi")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /utf-8")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zc:__cplusplus")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /permissive-")
set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /IGNORE:4221")
endif()
##########################################################################################
set(VSTGUI_COMPILE_DEFINITIONS_DEBUG "${VSTGUI_COMPILE_DEFINITIONS_DEBUG};VSTGUI_LIVE_EDITING;DEBUG")
set(VSTGUI_COMPILE_DEFINITIONS_RELEASE "${VSTGUI_COMPILE_DEFINITIONS_RELEASE};NDEBUG;RELEASE")
if(VSTGUI_ENABLE_DEPRECATED_METHODS)
set(VSTGUI_COMPILE_DEFINITIONS_DEBUG "${VSTGUI_COMPILE_DEFINITIONS_DEBUG};VSTGUI_ENABLE_DEPRECATED_METHODS=1")
set(VSTGUI_COMPILE_DEFINITIONS_RELEASE "${VSTGUI_COMPILE_DEFINITIONS_RELEASE};VSTGUI_ENABLE_DEPRECATED_METHODS=1")
else()
set(VSTGUI_COMPILE_DEFINITIONS_DEBUG "${VSTGUI_COMPILE_DEFINITIONS_DEBUG};VSTGUI_ENABLE_DEPRECATED_METHODS=0")
set(VSTGUI_COMPILE_DEFINITIONS_RELEASE "${VSTGUI_COMPILE_DEFINITIONS_RELEASE};VSTGUI_ENABLE_DEPRECATED_METHODS=0")
endif()
if(VSTGUI_ENABLE_XMLPARSER)
set(VSTGUI_COMPILE_DEFINITIONS_DEBUG "${VSTGUI_COMPILE_DEFINITIONS_DEBUG};VSTGUI_ENABLE_XML_PARSER=1")
set(VSTGUI_COMPILE_DEFINITIONS_RELEASE "${VSTGUI_COMPILE_DEFINITIONS_RELEASE};VSTGUI_ENABLE_XML_PARSER=1")
else()
set(VSTGUI_COMPILE_DEFINITIONS_DEBUG "${VSTGUI_COMPILE_DEFINITIONS_DEBUG};VSTGUI_ENABLE_XML_PARSER=0")
set(VSTGUI_COMPILE_DEFINITIONS_RELEASE "${VSTGUI_COMPILE_DEFINITIONS_RELEASE};VSTGUI_ENABLE_XML_PARSER=0")
endif()
if(VSTGUI_ENABLE_OPENGL_SUPPORT)
set(VSTGUI_COMPILE_DEFINITIONS_DEBUG "${VSTGUI_COMPILE_DEFINITIONS_DEBUG};VSTGUI_OPENGL_SUPPORT=1")
set(VSTGUI_COMPILE_DEFINITIONS_RELEASE "${VSTGUI_COMPILE_DEFINITIONS_RELEASE};VSTGUI_OPENGL_SUPPORT=1")
else()
set(VSTGUI_COMPILE_DEFINITIONS_DEBUG "${VSTGUI_COMPILE_DEFINITIONS_DEBUG};VSTGUI_OPENGL_SUPPORT=0")
set(VSTGUI_COMPILE_DEFINITIONS_RELEASE "${VSTGUI_COMPILE_DEFINITIONS_RELEASE};VSTGUI_OPENGL_SUPPORT=0")
endif()
set(VSTGUI_COMPILE_DEFINITIONS PRIVATE
$<$<CONFIG:Debug>:${VSTGUI_COMPILE_DEFINITIONS_DEBUG}>
$<$<CONFIG:Release>:${VSTGUI_COMPILE_DEFINITIONS_RELEASE}>
$<$<CONFIG:ReleaseLTO>:${VSTGUI_COMPILE_DEFINITIONS_RELEASE}>
CACHE INTERNAL "VSTGUI compile definitions"
)
##########################################################################################
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}"
)
@@ -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,54 @@
// 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/iexternalview.h"
#include <functional>
#include <memory>
//------------------------------------------------------------------------
namespace VSTGUI {
namespace ExternalView {
//------------------------------------------------------------------------
class DatePicker : public ViewAdapter
{
public:
DatePicker ();
~DatePicker () noexcept;
struct Date
{
int32_t day {0};
int32_t month {0};
int32_t year {0};
};
void setDate (Date date);
using ChangeCallback = std::function<void (Date)>;
void setChangeCallback (const ChangeCallback& callback);
private:
bool platformViewTypeSupported (PlatformViewType type) override;
bool attach (void* parent, PlatformViewType parentViewType) override;
bool remove () override;
void setViewSize (IntRect frame, IntRect visible) override;
void setContentScaleFactor (double scaleFactor) override;
void setMouseEnabled (bool state) override;
void takeFocus () override;
void looseFocus () override;
void setTookFocusCallback (const TookFocusCallback& callback) override;
struct Impl;
std::unique_ptr<Impl> impl;
};
//------------------------------------------------------------------------
} // ExternalView
} // VSTGUI
@@ -0,0 +1,199 @@
// 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 "datepicker.h"
#import "externalview_nsview.h"
//------------------------------------------------------------------------
namespace VSTGUI {
namespace ExternalView {
//------------------------------------------------------------------------
struct DatePickerDelegate : RuntimeObjCClass<DatePickerDelegate>
{
using DoneCallback = std::function<void ()>;
using ValidateCallback = std::function<void (NSDate**, NSTimeInterval*)>;
static constexpr const auto DoneCallbackVarName = "DoneCallback";
static constexpr const auto ValidateCallbackVarName = "ValidateCallback";
static id allocAndInit (DoneCallback&& doneCallback, ValidateCallback&& callback)
{
id obj = Base::alloc ();
initWithCallbacks (obj, std::move (doneCallback), std::move (callback));
return obj;
}
static Class CreateClass ()
{
return ObjCClassBuilder ()
.init ("DatePickerDelegate", [NSObject class])
.addProtocol ("NSDatePickerCellDelegate")
.addMethod (@selector (datePickerCell:validateProposedDateValue:timeInterval:),
validate)
.addMethod (@selector (complete:), complete)
.addIvar<ValidateCallback> (ValidateCallbackVarName)
.addIvar<DoneCallback> (DoneCallbackVarName)
.finalize ();
}
static id initWithCallbacks (id self, DoneCallback&& doneCallback, ValidateCallback&& callback)
{
if ((self = makeInstance (self).callSuper<id (), id> (@selector (init))))
{
auto instance = makeInstance (self);
if (auto var = instance.getVariable<DoneCallback> (DoneCallbackVarName))
var->set (doneCallback);
if (auto var = instance.getVariable<ValidateCallback> (ValidateCallbackVarName))
var->set (callback);
}
return self;
}
static void complete (id self, SEL cmd, id sender)
{
if (auto var = makeInstance (self).getVariable<DoneCallback> (DoneCallbackVarName))
{
const auto& callback = var->get ();
if (callback)
callback ();
}
}
static void validate (id self, SEL cmd, NSDatePickerCell* datePickerCell,
NSDate* _Nonnull* _Nonnull proposedDateValue,
NSTimeInterval* _Nullable proposedTimeInterval)
{
if (auto var = makeInstance (self).getVariable<ValidateCallback> (ValidateCallbackVarName))
{
const auto& callback = var->get ();
if (callback)
callback (proposedDateValue, proposedTimeInterval);
}
}
};
//------------------------------------------------------------------------
struct DatePicker::Impl : ExternalNSViewBase<NSDatePicker>
{
using Base::Base;
id delegate {nil};
ChangeCallback changeCallback;
#if !__has_feature(objc_arc)
~Impl () noexcept
{
if (delegate)
[delegate release];
}
#endif
};
//------------------------------------------------------------------------
DatePicker::DatePicker ()
{
impl = std::make_unique<Impl> ([[NSDatePicker alloc] initWithFrame: {0., 0., 10., 10.}]);
impl->view.datePickerStyle = NSDatePickerStyleTextField;
impl->view.datePickerMode = NSDatePickerModeSingle;
impl->view.datePickerElements = NSDatePickerElementFlagYearMonthDay;
if (@available (macOS 10.15.4, *))
impl->view.presentsCalendarOverlay = YES;
impl->view.dateValue = [NSDate date];
impl->view.calendar = [NSCalendar currentCalendar];
[impl->container addSubview:impl->view];
impl->delegate = DatePickerDelegate::allocAndInit (
[impl = impl.get ()] () {
if (impl->changeCallback)
{
auto dateValue = impl->view.dateValue;
auto calendar = impl->view.calendar;
auto components = [calendar
components:NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay
fromDate:dateValue];
Date date;
date.day = static_cast<int32_t> (components.day);
date.month = static_cast<int32_t> (components.month);
date.year = static_cast<int32_t> (components.year);
impl->changeCallback (date);
}
},
[] (NSDate** date, NSTimeInterval* time) {
// TODO: add validation mechanism
});
impl->view.delegate = impl->delegate;
impl->view.target = impl->delegate;
impl->view.action = @selector (complete:);
}
//------------------------------------------------------------------------
DatePicker::~DatePicker () noexcept {}
//------------------------------------------------------------------------
void DatePicker::setDate (Date date)
{
auto calendar = impl->view.calendar;
auto dateComponents = [NSDateComponents new];
dateComponents.calendar = calendar;
dateComponents.day = date.day;
dateComponents.month = date.month;
dateComponents.year = date.year;
impl->view.dateValue = [calendar dateFromComponents:dateComponents];
#if !__has_feature(objc_arc)
[dateComponents release];
#endif
}
//------------------------------------------------------------------------
void DatePicker::setChangeCallback (const ChangeCallback& callback)
{
impl->changeCallback = callback;
}
//------------------------------------------------------------------------
bool DatePicker::platformViewTypeSupported (PlatformViewType type)
{
return impl->platformViewTypeSupported (type);
}
//------------------------------------------------------------------------
bool DatePicker::attach (void* parent, PlatformViewType parentViewType)
{
return impl->attach (parent, parentViewType);
}
//------------------------------------------------------------------------
bool DatePicker::remove () { return impl->remove (); }
//------------------------------------------------------------------------
void DatePicker::setViewSize (IntRect frame, IntRect visible)
{
impl->setViewSize (frame, visible);
}
//------------------------------------------------------------------------
void DatePicker::setContentScaleFactor (double scaleFactor)
{
impl->setContentScaleFactor (scaleFactor);
}
//------------------------------------------------------------------------
void DatePicker::setMouseEnabled (bool state) { impl->setMouseEnabled (state); }
//------------------------------------------------------------------------
void DatePicker::takeFocus () { impl->takeFocus (); }
//------------------------------------------------------------------------
void DatePicker::looseFocus () { impl->looseFocus (); }
//------------------------------------------------------------------------
void DatePicker::setTookFocusCallback (const TookFocusCallback& callback)
{
impl->setTookFocusCallback (callback);
}
//------------------------------------------------------------------------
} // ExternalView
} // VSTGUI
@@ -0,0 +1,132 @@
#include "datepicker.h"
#include "externalview_hwnd.h"
#include "vstgui/lib/platform/win32/win32factory.h"
#include <CommCtrl.h>
//------------------------------------------------------------------------
namespace VSTGUI {
namespace ExternalView {
//------------------------------------------------------------------------
struct DatePicker::Impl : ExternalHWNDBase
{
using Base::Base;
~Impl () noexcept
{
if (font)
DeleteObject (font);
}
ChangeCallback changeCallback;
HFONT font {nullptr};
};
//------------------------------------------------------------------------
DatePicker::DatePicker ()
{
auto hInstance = getPlatformFactory ().asWin32Factory ()->getInstance ();
impl = std::make_unique<Impl> (hInstance);
impl->child = CreateWindowExW (0, DATETIMEPICK_CLASS, TEXT ("DateTime"),
WS_BORDER | WS_CHILD | WS_VISIBLE | DTS_SHORTDATEFORMAT, 0, 0,
80, 20, impl->container.getHWND (), NULL, hInstance, NULL);
impl->container.setWindowProc ([this] (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message)
{
case WM_NOTIFY:
{
LPNMHDR hdr = reinterpret_cast<LPNMHDR> (lParam);
switch (hdr->code)
{
case DTN_DATETIMECHANGE:
{
LPNMDATETIMECHANGE lpChange = reinterpret_cast<LPNMDATETIMECHANGE> (lParam);
if (impl->changeCallback)
{
Date date;
date.day = lpChange->st.wDay;
date.month = lpChange->st.wMonth;
date.year = lpChange->st.wYear;
impl->changeCallback (date);
}
break;
}
}
break;
}
}
return DefWindowProc (hwnd, message, wParam, lParam);
});
}
//------------------------------------------------------------------------
DatePicker::~DatePicker () noexcept {}
//------------------------------------------------------------------------
void DatePicker::setDate (Date date)
{
SYSTEMTIME st = {};
st.wDay = date.day;
st.wMonth = date.month;
st.wYear = date.year;
DateTime_SetSystemtime (impl->child, GDT_VALID, &st);
}
//------------------------------------------------------------------------
void DatePicker::setChangeCallback (const ChangeCallback& callback)
{
impl->changeCallback = callback;
}
//------------------------------------------------------------------------
bool DatePicker::platformViewTypeSupported (PlatformViewType type)
{
return impl->platformViewTypeSupported (type);
}
//------------------------------------------------------------------------
bool DatePicker::attach (void* parent, PlatformViewType parentViewType)
{
return impl->attach (parent, parentViewType);
}
//------------------------------------------------------------------------
bool DatePicker::remove () { return impl->remove (); }
//------------------------------------------------------------------------
void DatePicker::setViewSize (IntRect frame, IntRect visible)
{
impl->setViewSize (frame, visible);
}
//------------------------------------------------------------------------
void DatePicker::setContentScaleFactor (double scaleFactor)
{
if (impl->font)
DeleteObject (impl->font);
auto logFont = NonClientMetrics::get ().lfCaptionFont;
logFont.lfHeight = static_cast<LONG> (std::round (logFont.lfHeight * scaleFactor));
impl->font = CreateFontIndirect (&logFont);
if (impl->font)
SendMessage (impl->child, WM_SETFONT, (WPARAM)impl->font, 0);
}
//------------------------------------------------------------------------
void DatePicker::setMouseEnabled (bool state) { impl->setMouseEnabled (state); }
//------------------------------------------------------------------------
void DatePicker::takeFocus () { impl->takeFocus (); }
//------------------------------------------------------------------------
void DatePicker::looseFocus () { impl->looseFocus (); }
void DatePicker::setTookFocusCallback (const TookFocusCallback& callback)
{
impl->setTookFocusCallback (callback);
}
//------------------------------------------------------------------------
} // ExternalView
} // VSTGUI
+54
View File
@@ -0,0 +1,54 @@
// 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/iexternalview.h"
#include "../lib/cstring.h"
#include <memory>
//------------------------------------------------------------------------
namespace VSTGUI {
namespace ExternalView {
//------------------------------------------------------------------------
class Button : public ControlViewAdapter
{
public:
enum class Type
{
Checkbox,
Push,
Radio,
OnOff
};
Button (Type type, const UTF8String& title);
~Button () noexcept;
private:
bool platformViewTypeSupported (PlatformViewType type) override;
bool attach (void* parent, PlatformViewType parentViewType) override;
bool remove () override;
void setViewSize (IntRect frame, IntRect visible) override;
void setContentScaleFactor (double scaleFactor) override;
void setMouseEnabled (bool state) override;
void takeFocus () override;
void looseFocus () override;
void setTookFocusCallback (const TookFocusCallback& callback) override;
bool setValue (double value) override;
bool setEditCallbacks (const EditCallbacks& callbacks) override;
struct Impl;
std::unique_ptr<Impl> impl;
};
//------------------------------------------------------------------------
} // ExternalView
} // VSTGUI
@@ -0,0 +1,232 @@
// 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 "evbutton.h"
#import "externalview_nsview.h"
#import "../lib/platform/mac/macstring.h"
//------------------------------------------------------------------------
namespace VSTGUI {
namespace ExternalView {
//------------------------------------------------------------------------
struct ButtonDelegate : RuntimeObjCClass<ButtonDelegate>
{
using ActionCallback = std::function<void ()>;
static constexpr const auto ActionCallbackVarName = "ActionCallback";
static id allocAndInit (ActionCallback&& actionCallback)
{
id obj = Base::alloc ();
initWithCallbacks (obj, std::move (actionCallback));
return obj;
}
static Class CreateClass ()
{
return ObjCClassBuilder ()
.init ("ButtonDelegate", [NSObject class])
.addMethod (@selector (onAction:), onAction)
.addIvar<ActionCallback> (ActionCallbackVarName)
.finalize ();
}
static id initWithCallbacks (id self, ActionCallback&& actionCallback)
{
if ((self = makeInstance (self).callSuper<id (), id> (@selector (init))))
{
auto instance = makeInstance (self);
if (auto var = instance.getVariable<ActionCallback> (ActionCallbackVarName))
var->set (actionCallback);
}
return self;
}
static void onAction (id self, SEL cmd, id sender)
{
if (auto var = makeInstance (self).getVariable<ActionCallback> (ActionCallbackVarName))
{
const auto& callback = var->get ();
if (callback)
callback ();
}
}
};
//------------------------------------------------------------------------
struct Button::Impl : ExternalNSViewBase<NSButton>,
IControlViewExtension
{
using Base::Base;
id delegate {nil};
EditCallbacks callbacks {};
#if !__has_feature(objc_arc)
~Impl () noexcept
{
if (delegate)
[delegate release];
}
#endif
bool setValue (double value) override
{
if (value < 0.5)
view.state = NSControlStateValueOff;
else if (value == 0.5)
view.state = NSControlStateValueMixed;
else
view.state = NSControlStateValueOn;
return true;
}
bool setEditCallbacks (const EditCallbacks& editCallbacks) override
{
callbacks = editCallbacks;
return true;
}
};
//------------------------------------------------------------------------
Button::Button (Type type, const UTF8String& inTitle)
{
NSString* title = fromUTF8String<NSString*> (inTitle);
ButtonDelegate::ActionCallback actionCallback = [this] () {
double value = 0.;
switch (impl->view.state)
{
case NSControlStateValueOn:
value = 1.;
break;
case NSControlStateValueOff:
value = 0.;
break;
case NSControlStateValueMixed:
value = 0.5;
break;
}
if (impl->callbacks.beginEdit)
impl->callbacks.beginEdit ();
if (impl->callbacks.performEdit)
impl->callbacks.performEdit (value);
if (impl->callbacks.endEdit)
impl->callbacks.endEdit ();
};
NSButton* button = {};
switch (type)
{
case Type::Checkbox:
{
button = [NSButton checkboxWithTitle:title target:nullptr action:nullptr];
break;
}
case Type::Push:
{
button = [NSButton buttonWithTitle:title target:nullptr action:nullptr];
[button setButtonType:NSButtonTypeMomentaryLight];
actionCallback = [this] () {
if (impl->callbacks.beginEdit)
impl->callbacks.beginEdit ();
if (impl->callbacks.performEdit)
impl->callbacks.performEdit (1.);
if (impl->callbacks.endEdit)
impl->callbacks.endEdit ();
if (impl->callbacks.beginEdit)
impl->callbacks.beginEdit ();
if (impl->callbacks.performEdit)
impl->callbacks.performEdit (0.);
if (impl->callbacks.endEdit)
impl->callbacks.endEdit ();
};
break;
}
case Type::OnOff:
{
button = [NSButton buttonWithTitle:title target:nullptr action:nullptr];
[button setButtonType:NSButtonTypePushOnPushOff];
break;
}
case Type::Radio:
{
button = [NSButton radioButtonWithTitle:title target:nullptr action:nullptr];
break;
}
}
[button sizeToFit];
impl = std::make_unique<Impl> (button);
impl->delegate = ButtonDelegate::allocAndInit (std::move (actionCallback));
impl->view.target = impl->delegate;
impl->view.action = @selector (onAction:);
[impl->container addSubview:impl->view];
[button retain];
}
//------------------------------------------------------------------------
Button::~Button () noexcept = default;
//------------------------------------------------------------------------
bool Button::platformViewTypeSupported (PlatformViewType type)
{
return impl->platformViewTypeSupported (type);
}
//------------------------------------------------------------------------
bool Button::attach (void* parent, PlatformViewType parentViewType)
{
return impl->attach (parent, parentViewType);
}
//------------------------------------------------------------------------
bool Button::remove () { return impl->remove (); }
//------------------------------------------------------------------------
void Button::setViewSize (IntRect frame, IntRect visible)
{
static constexpr const NSControlSize controlSizes[] = {NSControlSizeRegular, NSControlSizeSmall,
NSControlSizeMini};
for (auto i = 0; i < std::size (controlSizes); i++)
{
impl->view.controlSize = controlSizes[i];
auto size = [impl->view sizeThatFits:NSMakeSize (frame.size.width, frame.size.height)];
if (size.height <= frame.size.height)
break;
}
impl->setViewSize (frame, visible);
}
//------------------------------------------------------------------------
void Button::setContentScaleFactor (double scaleFactor)
{
impl->setContentScaleFactor (scaleFactor);
}
//------------------------------------------------------------------------
void Button::setMouseEnabled (bool state) { impl->setMouseEnabled (state); }
//------------------------------------------------------------------------
void Button::takeFocus () { impl->takeFocus (); }
//------------------------------------------------------------------------
void Button::looseFocus () { impl->looseFocus (); }
//------------------------------------------------------------------------
void Button::setTookFocusCallback (const TookFocusCallback& callback)
{
impl->setTookFocusCallback (callback);
}
//------------------------------------------------------------------------
bool Button::setValue (double value) { return impl->setValue (value); }
//------------------------------------------------------------------------
bool Button::setEditCallbacks (const EditCallbacks& callbacks)
{
return impl->setEditCallbacks (callbacks);
}
//------------------------------------------------------------------------
} // ExternalView
} // VSTGUI
@@ -0,0 +1,198 @@
// 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 "evbutton.h"
#include "externalview_hwnd.h"
#include "vstgui/lib/platform/win32/win32factory.h"
#include "vstgui/lib/platform/win32/winstring.h"
#include <windowsx.h>
//------------------------------------------------------------------------
namespace VSTGUI {
namespace ExternalView {
//------------------------------------------------------------------------
struct Button::Impl : ExternalHWNDBase,
IControlViewExtension
{
using ExternalHWNDBase::ExternalHWNDBase;
Type type {};
EditCallbacks callbacks {};
double value {0.};
bool setValue (double val) override
{
value = val;
auto state = Button_GetState (child);
switch (type)
{
case Type::Checkbox:
case Type::Radio:
{
Button_SetCheck (child, value > 0.5);
break;
}
{
break;
}
case Type::OnOff:
{
if (value == 0)
state = 0; //~BST_PUSHED;
else
state = BST_PUSHED;
Button_SetState (child, state);
break;
}
case Type::Push:
{
break;
}
}
return true;
}
bool setEditCallbacks (const EditCallbacks& editCallbacks) override
{
callbacks = editCallbacks;
return true;
}
void onButtonClick (double val)
{
if (callbacks.beginEdit)
callbacks.beginEdit ();
if (callbacks.performEdit)
callbacks.performEdit (val);
if (callbacks.endEdit)
callbacks.endEdit ();
}
};
//------------------------------------------------------------------------
Button::Button (Type type, const UTF8String& inTitle)
{
DWORD addStyle = 0;
switch (type)
{
case Type::Checkbox:
addStyle = BS_AUTOCHECKBOX;
break;
case Type::Radio:
addStyle = BS_RADIOBUTTON;
break;
case Type::OnOff:
addStyle = BS_PUSHBUTTON;
break;
case Type::Push:
addStyle = BS_PUSHBUTTON;
break;
}
auto winString = dynamic_cast<WinString*> (inTitle.getPlatformString ());
auto hInstance = getPlatformFactory ().asWin32Factory ()->getInstance ();
impl = std::make_unique<Impl> (hInstance);
impl->type = type;
impl->child = CreateWindowExW (WS_EX_COMPOSITED, TEXT ("BUTTON"),
winString ? winString->getWideString () : nullptr,
WS_CHILD | WS_VISIBLE | BS_TEXT | addStyle, 0, 0, 80, 20,
impl->container.getHWND (), NULL, hInstance, NULL);
impl->container.setWindowProc (
[this] (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) -> LRESULT {
switch (message)
{
case WM_COMMAND:
{
if (HIWORD (wParam) == BN_CLICKED)
{
switch (impl->type)
{
case Type::Checkbox:
{
impl->onButtonClick (impl->value == 0. ? 1 : 0.);
break;
}
case Type::Radio:
{
impl->onButtonClick (impl->value == 0. ? 1 : 0.);
break;
}
case Type::OnOff:
{
impl->onButtonClick (impl->value == 0. ? 1 : 0.);
break;
}
case Type::Push:
{
impl->onButtonClick (1.);
impl->onButtonClick (0.);
break;
}
}
return 0;
}
break;
}
case WM_ERASEBKGND:
return 0;
}
return DefWindowProc (hwnd, message, wParam, lParam);
});
}
//------------------------------------------------------------------------
Button::~Button () noexcept = default;
//------------------------------------------------------------------------
bool Button::platformViewTypeSupported (PlatformViewType type)
{
return impl->platformViewTypeSupported (type);
}
//------------------------------------------------------------------------
bool Button::attach (void* parent, PlatformViewType parentViewType)
{
return impl->attach (parent, parentViewType);
}
//------------------------------------------------------------------------
bool Button::remove () { return impl->remove (); }
//------------------------------------------------------------------------
void Button::setViewSize (IntRect frame, IntRect visible) { impl->setViewSize (frame, visible); }
//------------------------------------------------------------------------
void Button::setContentScaleFactor (double scaleFactor)
{
impl->setContentScaleFactor (scaleFactor);
}
//------------------------------------------------------------------------
void Button::setMouseEnabled (bool state) { impl->setMouseEnabled (state); }
//------------------------------------------------------------------------
void Button::takeFocus () { impl->takeFocus (); }
//------------------------------------------------------------------------
void Button::looseFocus () { impl->looseFocus (); }
//------------------------------------------------------------------------
void Button::setTookFocusCallback (const TookFocusCallback& callback)
{
impl->setTookFocusCallback (callback);
}
//------------------------------------------------------------------------
bool Button::setValue (double value) { return impl->setValue (value); }
//------------------------------------------------------------------------
bool Button::setEditCallbacks (const EditCallbacks& callbacks)
{
return impl->setEditCallbacks (callbacks);
}
//------------------------------------------------------------------------
} // ExternalView
} // VSTGUI
@@ -0,0 +1,481 @@
// 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 "externalview_hwnd.h"
#include <d3d12.h>
#include <dcomp.h>
#include <dxgi1_4.h>
#include <wrl.h>
#include <comdef.h>
#include <mutex>
#ifdef _MSC_VER
#pragma comment(lib, "dcomp.lib")
#pragma comment(lib, "d3d12.lib")
#pragma comment(lib, "dxgi.lib")
#endif
//------------------------------------------------------------------------
namespace VSTGUI {
//------------------------------------------------------------------------
//------------------------------------------------------------------------
struct Win32Exception : std::exception
{
explicit Win32Exception (HRESULT hr) : _hr (hr)
{
FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, hr, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&_errorStr, 0,
NULL);
}
~Win32Exception () noexcept
{
if (_errorStr)
LocalFree ((HLOCAL)_errorStr);
}
const char* what () const noexcept override { return _errorStr; }
HRESULT hr () const noexcept { return _hr; }
private:
HRESULT _hr;
char* _errorStr {nullptr};
};
inline void ThrowIfFailed (HRESULT hr)
{
if (FAILED (hr))
{
throw Win32Exception (hr);
}
}
//------------------------------------------------------------------------
namespace ExternalView {
//------------------------------------------------------------------------
struct IDirect3D12View
{
virtual ~IDirect3D12View () noexcept = default;
virtual ID3D12CommandAllocator* getCommandAllocator () const = 0;
virtual IDXGISwapChain3* getSwapChain () const = 0;
virtual ID3D12Device* getDevice () const = 0;
virtual INT getFrameIndex () const = 0;
virtual void setFrameIndex (INT index) = 0;
virtual void render () = 0;
};
//------------------------------------------------------------------------
struct IDirect3D12Renderer
{
virtual ~IDirect3D12Renderer () noexcept = default;
virtual bool init (IDirect3D12View* view) = 0;
virtual void render (ID3D12CommandQueue* queue) = 0;
virtual void beforeSizeUpdate () = 0;
virtual void onSizeUpdate (IntSize newSize, double scaleFactor) = 0;
virtual void onAttach () = 0;
virtual void onRemove () = 0;
virtual uint32_t getFrameCount () const = 0;
};
//------------------------------------------------------------------------
using Direct3D12RendererPtr = std::shared_ptr<IDirect3D12Renderer>;
//------------------------------------------------------------------------
struct GPUFence
{
template<typename T>
using ComPtr = Microsoft::WRL::ComPtr<T>;
GPUFence () = default;
GPUFence (ID3D12Device* device, UINT64 initialValue = 0)
{
ThrowIfFailed (device->CreateFence (0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS (&m_fence)));
m_event = CreateEvent (nullptr, FALSE, FALSE, nullptr);
if (m_event == nullptr)
{
ThrowIfFailed (HRESULT_FROM_WIN32 (GetLastError ()));
}
m_value = initialValue;
}
~GPUFence () noexcept
{
if (m_event)
CloseHandle (m_event);
}
GPUFence& operator=(GPUFence&& o) noexcept
{
m_event = o.m_event;
m_fence = o.m_fence;
m_value = o.m_value;
o.m_event = nullptr;
o.m_fence.Reset ();
o.m_value = {};
return *this;
}
void wait (ID3D12CommandQueue* queue)
{
if (m_fence == nullptr)
return;
const auto value = m_value;
ThrowIfFailed (queue->Signal (m_fence.Get (), value));
m_value++;
if (m_fence->GetCompletedValue () < value)
{
ThrowIfFailed (m_fence->SetEventOnCompletion (value, m_event));
WaitForSingleObject (m_event, INFINITE);
}
}
HANDLE m_event {nullptr};
ComPtr<ID3D12Fence> m_fence;
UINT64 m_value {0};
};
//------------------------------------------------------------------------
struct Direct3D12View : public ExternalHWNDBase,
IDirect3D12View
{
template<typename T>
using ComPtr = Microsoft::WRL::ComPtr<T>;
Direct3D12View (HINSTANCE instance, const Direct3D12RendererPtr& renderer,
ComPtr<IDXGIFactory4> factory = nullptr, ComPtr<ID3D12Device> device = nullptr, ComPtr<ID3D12CommandQueue> commandQueue = nullptr)
: Base (instance), m_renderer (renderer), m_factory (factory), m_device (device), m_commandQueue (commandQueue)
{
vstgui_assert ((factory && device) || (!factory && !device), "Either both factory and device are provided or none of both!");
vstgui_assert (commandQueue ? device : true, "If a command queue is provided, the device must also be provided!");
}
static std::shared_ptr<Direct3D12View> make (HINSTANCE instance,
const Direct3D12RendererPtr& renderer,
ComPtr<IDXGIFactory4> factory = nullptr,
ComPtr<ID3D12Device> device = nullptr,
ComPtr<ID3D12CommandQueue> queue = nullptr)
{
return std::make_shared<Direct3D12View> (instance, renderer, factory, device, queue);
}
void render () override { doRender (); }
Direct3D12RendererPtr& getRenderer () { return m_renderer; }
const Direct3D12RendererPtr& getRenderer () const { return m_renderer; }
private:
ID3D12CommandAllocator* getCommandAllocator () const { return m_commandAllocator.Get (); }
IDXGISwapChain3* getSwapChain () const { return m_swapChain.Get (); }
ID3D12Device* getDevice () const { return m_device.Get (); }
INT getFrameIndex () const { return m_frameIndex; }
void setFrameIndex (INT index) { m_frameIndex = index; }
void doRender ()
{
if (mutex.try_lock ())
{
if (m_commandQueue)
{
HRESULT result = S_FALSE;
try
{
waitForPreviousFrame ();
m_renderer->render (m_commandQueue.Get ());
result = getSwapChain ()->Present (1, 0);
ThrowIfFailed (result);
}
catch (const Win32Exception& e)
{
try
{
freeResources ();
}
catch (...)
{
}
throw (e);
}
}
mutex.unlock ();
}
}
bool attach (void* parent, PlatformViewType parentViewType) override
{
if (Base::attach (parent, parentViewType))
{
try
{
if (m_renderer->init (this))
{
init ();
m_renderer->onAttach ();
}
}
catch (...)
{
auto reasonHR = m_device->GetDeviceRemovedReason ();
Win32Exception e (reasonHR);
freeResources ();
}
return true;
}
return false;
}
bool remove () override
{
Guard g (mutex);
waitForPreviousFrame ();
freeResources ();
return Base::remove ();
}
void setViewSize (IntRect frame, IntRect visible) override
{
Guard g (mutex);
Base::setViewSize (frame, visible);
m_visibleRect = visible;
updateSizes ();
}
void setContentScaleFactor (double factor) override
{
Guard g (mutex);
m_scaleFactor = factor;
updateSizes ();
}
void updateSizes ()
{
if (m_swapChain)
{
if (m_size.width == m_visibleRect.size.width &&
m_size.height == m_visibleRect.size.height)
return;
m_size = m_visibleRect.size;
waitForPreviousFrame ();
m_renderer->beforeSizeUpdate ();
ThrowIfFailed (m_dcompVisual->SetContent (nullptr));
ThrowIfFailed (m_swapChain->ResizeBuffers (
m_renderer->getFrameCount (), static_cast<UINT> (m_size.width),
static_cast<UINT> (m_size.height), DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_SWAP_EFFECT_FLIP_DISCARD));
ThrowIfFailed (m_dcompVisual->SetContent (m_swapChain.Get ()));
m_renderer->onSizeUpdate (m_size, m_scaleFactor);
ThrowIfFailed (m_dcompDevice->Commit ());
}
}
void freeResources ()
{
m_fence = {};
try
{
m_renderer->onRemove ();
}
catch (...)
{
}
m_commandAllocator.Reset ();
m_commandQueue.Reset ();
m_dcompDevice.Reset ();
m_dcompTarget.Reset ();
m_dcompVisual.Reset ();
m_swapChain.Reset ();
m_device.Reset ();
}
void init ()
{
#if defined(_DEBUG)
// Enable the D3D12 debug layer.
{
ComPtr<ID3D12Debug> debugController;
if (SUCCEEDED (D3D12GetDebugInterface (IID_PPV_ARGS (&debugController))))
{
debugController->EnableDebugLayer ();
}
}
#endif
if (!m_factory)
ThrowIfFailed (CreateDXGIFactory1 (IID_PPV_ARGS (&m_factory)));
if (m_device == nullptr)
{
ComPtr<IDXGIAdapter1> hardwareAdapter;
getHardwareAdapter (m_factory.Get (), &hardwareAdapter);
if (!hardwareAdapter)
{
throw;
}
ThrowIfFailed (D3D12CreateDevice (hardwareAdapter.Get (), D3D_FEATURE_LEVEL_11_0,
IID_PPV_ARGS (&m_device)));
}
if (!m_commandQueue)
{
// Describe and create the command queue.
D3D12_COMMAND_QUEUE_DESC queueDesc = {};
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
ThrowIfFailed (m_device->CreateCommandQueue (&queueDesc, IID_PPV_ARGS (&m_commandQueue)));
}
try
{
createSwapChain (m_factory.Get ());
setupDirectComposition ();
}
catch (...)
{
auto exc = std::current_exception ();
throw (exc);
}
ThrowIfFailed (
m_factory->MakeWindowAssociation (container.getHWND (), DXGI_MWA_NO_ALT_ENTER));
ThrowIfFailed (m_device->CreateCommandAllocator (D3D12_COMMAND_LIST_TYPE_DIRECT,
IID_PPV_ARGS (&m_commandAllocator)));
m_fence = GPUFence (m_device.Get (), 1);
}
void createSwapChain (IDXGIFactory4* factory)
{
// Describe and create the swap chain.
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
swapChainDesc.BufferCount = m_renderer->getFrameCount ();
swapChainDesc.Width = static_cast<UINT> (m_size.width);
swapChainDesc.Height = static_cast<UINT> (m_size.height);
swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
ComPtr<IDXGISwapChain1> swapChain;
ThrowIfFailed (factory->CreateSwapChainForComposition (
m_commandQueue.Get (), // Swap chain needs the queue so that it can force a flush on it.
&swapChainDesc, nullptr, &swapChain));
ThrowIfFailed (swapChain.As (&m_swapChain));
}
void setupDirectComposition ()
{
// Create the DirectComposition device
ThrowIfFailed (DCompositionCreateDevice (
nullptr, IID_PPV_ARGS (m_dcompDevice.ReleaseAndGetAddressOf ())));
// Create a DirectComposition target associated with the window (pass in hWnd here)
ThrowIfFailed (m_dcompDevice->CreateTargetForHwnd (
container.getHWND (), true, m_dcompTarget.ReleaseAndGetAddressOf ()));
// Create a DirectComposition "visual"
ThrowIfFailed (m_dcompDevice->CreateVisual (m_dcompVisual.ReleaseAndGetAddressOf ()));
// Associate the visual with the swap chain
ThrowIfFailed (m_dcompVisual->SetContent (m_swapChain.Get ()));
// Set the visual as the root of the DirectComposition target's composition tree
ThrowIfFailed (m_dcompTarget->SetRoot (m_dcompVisual.Get ()));
ThrowIfFailed (m_dcompDevice->Commit ());
}
static void getHardwareAdapter (IDXGIFactory2* pFactory, IDXGIAdapter1** ppAdapter)
{
ComPtr<IDXGIAdapter1> adapter;
*ppAdapter = nullptr;
for (UINT adapterIndex = 0;
DXGI_ERROR_NOT_FOUND != pFactory->EnumAdapters1 (adapterIndex, &adapter);
++adapterIndex)
{
DXGI_ADAPTER_DESC1 desc;
adapter->GetDesc1 (&desc);
if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)
{
// Don't select the Basic Render Driver adapter.
// If you want a software adapter, pass in "/warp" on the command line.
continue;
}
// Check to see if the adapter supports Direct3D 12, but don't create the
// actual device yet.
if (SUCCEEDED (D3D12CreateDevice (adapter.Get (), D3D_FEATURE_LEVEL_11_0,
_uuidof(ID3D12Device), nullptr)))
{
break;
}
}
*ppAdapter = adapter.Detach ();
}
void waitForPreviousFrame ()
{
if (!m_commandQueue || !m_swapChain)
return;
// WAITING FOR THE FRAME TO COMPLETE BEFORE CONTINUING IS NOT BEST PRACTICE.
// This is code implemented as such for simplicity. The D3D12HelloFrameBuffering
// sample illustrates how to use fences for efficient resource usage and to
// maximize GPU utilization.
m_fence.wait (m_commandQueue.Get ());
m_frameIndex = m_swapChain->GetCurrentBackBufferIndex ();
}
using Mutex = std::recursive_mutex;
using Guard = std::lock_guard<Mutex>;
Mutex mutex;
IntSize m_size {100, 100};
IntRect m_visibleRect {};
double m_scaleFactor {1.};
UINT m_frameIndex {0};
// Synchronization objects.
GPUFence m_fence;
ComPtr<IDXGIFactory4> m_factory;
ComPtr<IDXGISwapChain3> m_swapChain;
ComPtr<ID3D12Device> m_device;
ComPtr<ID3D12CommandQueue> m_commandQueue;
ComPtr<ID3D12CommandAllocator> m_commandAllocator;
// DirectComposition objects.
ComPtr<IDCompositionDevice> m_dcompDevice;
ComPtr<IDCompositionTarget> m_dcompTarget;
ComPtr<IDCompositionVisual> m_dcompVisual;
Direct3D12RendererPtr m_renderer;
};
//------------------------------------------------------------------------
} // ExternalView
} // VSTGUI
@@ -0,0 +1,223 @@
// 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/vstguibase.h"
#include "../lib/iexternalview.h"
#include <windows.h>
#include <cassert>
#include <functional>
#include <cstdint>
#include <string>
//------------------------------------------------------------------------
namespace VSTGUI {
namespace ExternalView {
//------------------------------------------------------------------------
inline void setWindowSize (HWND window, IntRect r)
{
SetWindowPos (window, HWND_TOP, static_cast<int> (r.origin.x), static_cast<int> (r.origin.y),
static_cast<int> (r.size.width), static_cast<int> (r.size.height),
SWP_NOZORDER | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_DEFERERASE);
}
//------------------------------------------------------------------------
struct HWNDWindow final
{
using WindowProcFunc =
std::function<LONG_PTR (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)>;
HWNDWindow (HINSTANCE instance) : instance (instance) {}
~HWNDWindow () noexcept
{
if (window)
{
SetWindowLongPtr (window, GWLP_USERDATA, (__int3264)(LONG_PTR) nullptr);
DestroyWindow (window);
}
destroyWindowClass ();
}
bool create (const TCHAR* title, const IntRect& frame, HWND parent, DWORD exStyle = 0,
DWORD style = WS_CHILD)
{
if (!initWindowClass ())
return false;
window = CreateWindowEx (
exStyle, MAKEINTATOM (windowClassAtom), title, style, static_cast<int> (frame.origin.x),
static_cast<int> (frame.origin.y), static_cast<int> (frame.size.width),
static_cast<int> (frame.size.height), parent, nullptr, instance, nullptr);
if (!window)
return false;
SetWindowLongPtr (window, GWLP_USERDATA, (__int3264)(LONG_PTR)this);
return true;
}
void setWindowProc (WindowProcFunc&& func) { windowProc = std::move (func); }
void setSize (const IntRect& r)
{
if (!window)
return;
setWindowSize (window, r);
}
void show (bool state) { ShowWindow (window, state ? SW_SHOW : SW_HIDE); }
void setEnabled (bool state) { EnableWindow (window, state); }
HWND getHWND () const { return window; }
HINSTANCE getInstance () const { return instance; }
private:
bool initWindowClass ()
{
assert (instance != nullptr);
if (windowClassAtom != 0)
return true;
std::wstring windowClassName;
windowClassName = TEXT ("VSTGUI ExternalView Container ");
windowClassName += std::to_wstring (reinterpret_cast<uint64_t> (this));
WNDCLASS windowClass;
windowClass.style = CS_GLOBALCLASS;
windowClass.lpfnWndProc = WindowProc;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hInstance = instance;
windowClass.hIcon = 0;
windowClass.hCursor = LoadCursor (NULL, IDC_ARROW);
windowClass.hbrBackground = 0;
windowClass.lpszMenuName = 0;
windowClass.lpszClassName = windowClassName.data ();
windowClassAtom = RegisterClass (&windowClass);
return windowClassAtom != 0;
}
void destroyWindowClass ()
{
if (windowClassAtom == 0)
return;
UnregisterClass (MAKEINTATOM (windowClassAtom), instance);
windowClassAtom = 0;
}
static LONG_PTR WINAPI WindowProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_ERASEBKGND)
return 1;
auto instance = reinterpret_cast<HWNDWindow*> (GetWindowLongPtr (hwnd, GWLP_USERDATA));
if (instance && instance->windowProc)
return instance->windowProc (hwnd, message, wParam, lParam);
return DefWindowProc (hwnd, message, wParam, lParam);
}
WindowProcFunc windowProc;
HWND window {nullptr};
HINSTANCE instance {nullptr};
ATOM windowClassAtom {0};
};
//------------------------------------------------------------------------
struct NonClientMetrics
{
static const NONCLIENTMETRICS& get ()
{
static NonClientMetrics gInstance;
return gInstance.nonClientMetrics;
}
private:
NonClientMetrics ()
{
nonClientMetrics.cbSize = sizeof (nonClientMetrics);
SystemParametersInfoForDpi (SPI_GETNONCLIENTMETRICS, nonClientMetrics.cbSize,
&nonClientMetrics, 0, 96);
}
NONCLIENTMETRICS nonClientMetrics {};
};
//------------------------------------------------------------------------
struct ExternalHWNDBase : ViewAdapter
{
using Base = ExternalHWNDBase;
using PlatformViewType = ExternalView::PlatformViewType;
using IntRect = ExternalView::IntRect;
HWNDWindow container;
HWND child {nullptr};
ExternalHWNDBase (HINSTANCE hInst) : container (hInst)
{
container.create (nullptr, {{0, 0}, {1, 1}}, HWND_MESSAGE,
WS_EX_NOPARENTNOTIFY | WS_EX_COMPOSITED, WS_CHILD | WS_VISIBLE);
}
virtual ~ExternalHWNDBase () noexcept
{
if (child)
DestroyWindow (child);
}
bool platformViewTypeSupported (PlatformViewType type) override
{
return type == PlatformViewType::HWND;
}
bool attach (void* parent, PlatformViewType parentViewType) override
{
assert (container.getHWND ());
if (parent == nullptr || parentViewType != PlatformViewType::HWND)
return false;
auto parentHWND = reinterpret_cast<HWND> (parent);
SetParent (container.getHWND (), parentHWND);
return true;
}
bool remove () override
{
assert (container.getHWND ());
SetParent (container.getHWND (), HWND_MESSAGE);
return true;
}
void setViewSize (IntRect frame, IntRect visible) override
{
assert (container.getHWND ());
container.setSize (visible);
if (child)
{
frame.origin.x -= visible.origin.x;
frame.origin.y -= visible.origin.y;
setWindowSize (child, frame);
}
}
void setContentScaleFactor (double scaleFactor) override {}
void setMouseEnabled (bool state) override { EnableWindow (container.getHWND (), state); }
void takeFocus () override { SetFocus (child); }
void looseFocus () override
{
if (GetFocus () == child)
{
SetFocus (GetParent (container.getHWND ()));
}
}
};
//------------------------------------------------------------------------
} // ExternalView
} // 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
#import "externalview_nsview.h"
#import <Metal/Metal.h>
#import <QuartzCore/CAMetalLayer.h>
#import <functional>
#import <mutex>
//------------------------------------------------------------------------
using VSTGUIMetalLayerDelegateDrawCallback = std::function<void ()>;
using VSTGUIMetalViewScreenChangedCallack = std::function<void (NSScreen*)>;
@interface NSObject ()
- (void)setDrawCallback:(const VSTGUIMetalLayerDelegateDrawCallback&)callback;
- (void)setScreenChangedCallback:(const VSTGUIMetalViewScreenChangedCallack&)callback;
@end
//------------------------------------------------------------------------
namespace VSTGUI {
namespace ExternalView {
//------------------------------------------------------------------------
struct IMetalView
{
virtual ~IMetalView () noexcept = default;
virtual void render () = 0;
};
//------------------------------------------------------------------------
/** metal render interface to be used as the renderer of the MetalView
*
* The renderer has to set the metal device of the metal layer before it can draw to it.
*/
struct IMetalRenderer
{
virtual ~IMetalRenderer () noexcept = default;
virtual bool init (IMetalView* metalView, CAMetalLayer* metalLayer) = 0;
virtual void draw (id<CAMetalDrawable> drawable) = 0;
virtual void onSizeUpdate (int32_t width, int32_t height, double scaleFactor) = 0;
virtual void onAttached () = 0;
virtual void onRemoved () = 0;
virtual void onScreenChanged (NSScreen* screen) = 0;
};
using MetalRendererPtr = std::shared_ptr<IMetalRenderer>;
//------------------------------------------------------------------------
struct MetalLayerDelegate : RuntimeObjCClass<MetalLayerDelegate>
{
static constexpr auto CallbackVarName = "callback";
static Class CreateClass ()
{
return ObjCClassBuilder ()
.init ("MetalLayerDelegate", [NSObject class])
.addMethod (@selector (displayLayer:), displayLayer)
.addMethod (@selector (actionForLayer:forKey:), actionForLayer)
.addMethod (@selector (setDrawCallback:), setCallback)
.addProtocol ("CALayerDelegate")
.addIvar<VSTGUIMetalLayerDelegateDrawCallback> (CallbackVarName)
.finalize ();
}
static void setCallback (id self, SEL cmd, VSTGUIMetalLayerDelegateDrawCallback callback)
{
auto instance = makeInstance (self);
if (auto var = instance.getVariable<VSTGUIMetalLayerDelegateDrawCallback> (CallbackVarName))
var->set (callback);
}
static void displayLayer (id self, SEL cmd, CALayer* layer)
{
auto instance = makeInstance (self);
if (auto var = instance.getVariable<VSTGUIMetalLayerDelegateDrawCallback> (CallbackVarName))
{
if (auto callback = var->get ())
callback ();
}
}
static id<CAAction> actionForLayer (CALayer* layer, NSString* key) { return [NSNull null]; }
};
//------------------------------------------------------------------------
struct MetalNSView : RuntimeObjCClass<MetalNSView>
{
static constexpr auto CallbackVarName = "callback";
static Class CreateClass ()
{
return ObjCClassBuilder ()
.init ("MetalNSView", [NSView class])
.addIvar<VSTGUIMetalViewScreenChangedCallack> (CallbackVarName)
.addMethod (@selector (viewDidMoveToWindow), viewDidMoveToWindow)
.addMethod (@selector (viewWillMoveToWindow:), viewWillMoveToWindow)
.addMethod (@selector (windowDidChangeScreen:), windowDidChangeScreen)
.addMethod (@selector (setScreenChangedCallback:), setCallback)
.finalize ();
}
static void setCallback (id self, SEL cmd, VSTGUIMetalViewScreenChangedCallack callback)
{
auto instance = makeInstance (self);
if (auto var = instance.getVariable<VSTGUIMetalViewScreenChangedCallack> (CallbackVarName))
var->set (callback);
}
static void viewDidMoveToWindow (id self, SEL cmd)
{
windowDidChangeScreen (self, cmd, nullptr);
makeInstance (self).callSuper<void ()> (cmd);
}
static void viewWillMoveToWindow (id self, SEL cmd, NSWindow* window)
{
if (auto prevWindow = [self window])
{
[NSNotificationCenter.defaultCenter removeObserver:self];
}
if (window)
{
[NSNotificationCenter.defaultCenter addObserver:self
selector:@selector (windowDidChangeScreen:)
name:NSWindowDidChangeScreenNotification
object:window];
}
makeInstance (self).callSuper<void (NSWindow*)> (cmd, window);
}
static void windowDidChangeScreen (id self, SEL cmd, NSNotification* n)
{
if (NSScreen* screen = [[self window] screen])
{
auto instance = makeInstance (self);
if (auto var =
instance.getVariable<VSTGUIMetalViewScreenChangedCallack> (CallbackVarName))
{
if (auto callback = var->get ())
callback (screen);
}
}
}
};
//------------------------------------------------------------------------
struct MetalView : ExternalNSViewBase<NSView>,
IMetalView
{
/** make a new metal view.
*
* The metal view can render on a background thread (only use one thread for rendering) or on
* the main thread.
* Rendering and view resizing is automatically guarded by a mutex.
* The view will automatically trigger a rendering when the view is resized.
*/
static std::shared_ptr<MetalView> make (const MetalRendererPtr& renderer)
{
if (!renderer)
return {};
if (auto metalView = std::shared_ptr<MetalView> (new MetalView (renderer)))
{
if (renderer->init (metalView.get (), metalView->metalLayer))
return metalView;
}
return {};
}
/** immediately render the view [thread safe] */
void render () override
{
doLocked ([&] () { renderer->draw (metalLayer.nextDrawable); });
}
/** do something locked [thread safe] */
template<typename Proc>
void doLocked (Proc proc)
{
LockGuard g (mutex);
@autoreleasepool
{
proc ();
}
}
private:
CAMetalLayer* metalLayer {nullptr};
id metalLayerDelegate {nullptr};
double contentScaleFactor {1.};
using Mutex = std::recursive_mutex;
using LockGuard = std::lock_guard<Mutex>;
Mutex mutex;
MetalRendererPtr renderer;
MetalView (const MetalRendererPtr& renderer)
: Base ([MetalNSView::alloc () init]), renderer (renderer)
{
metalLayerDelegate = [MetalLayerDelegate::alloc () init];
metalLayer = [CAMetalLayer new];
metalLayer.delegate = metalLayerDelegate;
view.layer = metalLayer;
metalLayer.needsDisplayOnBoundsChange = YES;
metalLayer.geometryFlipped = YES;
metalLayer.opaque = NO;
metalLayer.contentsGravity = kCAGravityBottomLeft;
[metalLayerDelegate setDrawCallback:[this] () {
render ();
}];
[view setScreenChangedCallback:[this] (NSScreen* screen) {
this->renderer->onScreenChanged (screen);
}];
}
bool attach (void* parent, PlatformViewType parentViewType) override
{
if (Base::attach (parent, parentViewType))
{
renderer->onAttached ();
return true;
}
return false;
}
bool remove () override
{
if (Base::remove ())
{
renderer->onRemoved ();
return true;
}
return false;
}
void setContentScaleFactor (double scaleFactor) override
{
contentScaleFactor = scaleFactor;
metalLayer.contentsScale = scaleFactor;
[metalLayer setNeedsDisplay];
onSizeUpdate ();
}
void setViewSize (IntRect frame, IntRect visible) override
{
Base::setViewSize (frame, visible);
onSizeUpdate ();
}
void onSizeUpdate ()
{
doLocked ([this] () {
auto size = view.frame.size;
metalLayer.drawableSize =
NSMakeSize (size.width * contentScaleFactor, size.height * contentScaleFactor);
renderer->onSizeUpdate (size.width, size.height, contentScaleFactor);
});
}
#if !__has_feature(objc_arc)
public:
~MetalView () noexcept override
{
[metalLayerDelegate release];
[metalLayer release];
}
#endif
};
//------------------------------------------------------------------------
} // ExternalView
} // VSTGUI
@@ -0,0 +1,249 @@
// 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
#import "../lib/platform/mac/cocoa/objcclassbuilder.h"
#import "../lib/iexternalview.h"
#import <Cocoa/Cocoa.h>
//------------------------------------------------------------------------
namespace VSTGUI {
namespace ExternalView {
//------------------------------------------------------------------------
inline NSRect toNSRect (const IntRect& r)
{
return NSMakeRect (r.origin.x, r.origin.y, r.size.width, r.size.height);
}
//------------------------------------------------------------------------
/** a NSView that has a flipped coordinate system (top-left is {0, 0}, not AppKits default which is
* bottom-left)
*
* to create it call [ExternalViewContainerNSView::alloc () initWithFrame: rect]
*/
struct ExternalViewContainerNSView : RuntimeObjCClass<ExternalViewContainerNSView>
{
static constexpr auto TookFocusCallbackVarName = "TookFocusCallback";
static Class CreateClass ()
{
return ObjCClassBuilder ()
.init ("ExternalViewContainerNSView", [NSView class])
.addMethod (@selector (isFlipped), isFlipped)
.addMethod (@selector (viewWillMoveToWindow:), viewWillMoveToWindow)
.addMethod (@selector (observeValueForKeyPath:ofObject:change:context:),
observeValueForKeyPath)
.addIvar<IView::TookFocusCallback> (TookFocusCallbackVarName)
.finalize ();
}
static BOOL isFlipped (id self, SEL cmd) { return YES; }
static void viewWillMoveToWindow (id self, SEL _cmd, NSWindow* window)
{
if ([self window] && [self window] != window)
{
[[self window] removeObserver:self forKeyPath:@"firstResponder"];
}
if (window)
{
[window addObserver:self forKeyPath:@"firstResponder" options:0 context:nullptr];
}
}
static void observeValueForKeyPath (id self, SEL cmd, NSString* keyPath, id object,
NSDictionary<NSKeyValueChangeKey, id>* change,
void* context)
{
if ([keyPath isEqualToString:@"firstResponder"])
{
auto view = [self window].firstResponder;
if ([view isKindOfClass:[NSView class]] &&
[static_cast<NSView*> (view) isDescendantOf:self])
{
if (auto var = makeInstance (self).getVariable<IView::TookFocusCallback> (
TookFocusCallbackVarName))
{
if (var.value ().get ())
var.value ().get () ();
}
}
}
}
};
//------------------------------------------------------------------------
/** a template helper class for embedding NSViews into VSTGUI via ExternalView::IView
*
* Example to add a simple NSView:
*
* // Header: ExampleNSView.h
*
* class ExampleNSView : IView
* {
* public:
* ExampleNSView ();
* ~ExampleNSView () noexcept;
*
* private:
* bool platformViewTypeSupported (PlatformViewType type) override;
* bool attach (void* parent, PlatformViewType parentViewType) override;
* bool remove () override;
* void setViewSize (IntRect frame, IntRect visible) override;
* void setContentScaleFactor (double scaleFactor) override;
* void setMouseEnabled (bool state) override;
* void takeFocus () override;
* void looseFocus () override;
*
* struct Impl;
* std::unique_ptr<Impl> impl;
* };
*
* // Source: ExampleNSView.mm
*
* #import "ExampleNSView.h"
* #import "externalview_nsview.h"
*
* struct ExampleNSView::Impl : ExternalNSViewBase<NSView>
* {
* Impl () : Base ([NSView new])
* {
* // configure the view here
* view.alphaValue = 0.5;
* }
* };
*
* ExampleNSView::ExampleNSView () { impl = std::make_unique<Impl> (); }
* ExampleNSView::~ExampleNSView () noexcept = default;
* bool ExampleNSView::platformViewTypeSupported (PlatformViewType type)
* {
* return impl->platformViewTypeSupported (type);
* }
* bool ExampleNSView::attach (void* parent, PlatformViewType parentViewType)
* {
* return impl->attach (parent, parentViewType);
* }
* bool ExampleNSView::remove () { return impl->remove (); }
* void ExampleNSView::setViewSize (IntRect frame, IntRect visible)
* {
* impl->setViewSize (frame, visible);
* }
* void ExampleNSView::setContentScaleFactor (double scaleFactor)
* {
* impl->setContentScaleFactor (scaleFactor);
* }
* void ExampleNSView::setMouseEnabled (bool state) { impl->setMouseEnabled (state); }
* void ExampleNSView::takeFocus () { impl->takeFocus (); }
* void ExampleNSView::looseFocus () { impl->looseFocus (); }
*
*/
template<typename ViewType>
struct ExternalNSViewBase : ViewAdapter
{
using Base = ExternalNSViewBase<ViewType>;
using PlatformViewType = ExternalView::PlatformViewType;
using IntRect = ExternalView::IntRect;
NSView* container {
[ExternalViewContainerNSView::alloc () initWithFrame: {{0., 0.}, {10., 10.}}]};
ViewType* view {nullptr};
ExternalNSViewBase (ViewType* inView) : view (inView)
{
if (@available (macOS 14, *))
{
#ifdef MAC_OS_VERSION_14_0
// only available when building with the mac os sdk 14.0
container.clipsToBounds = YES;
#else
// but necessary to set to YES on macOS 14 even when not building with Xcode 15
if ([container respondsToSelector:@selector (setClipsToBounds:)])
{
BOOL clipsToBounds = YES;
auto* signature = [[container class]
instanceMethodSignatureForSelector:@selector (setClipsToBounds:)];
auto* invocation = [NSInvocation invocationWithMethodSignature:signature];
invocation.target = container;
invocation.selector = @selector (setClipsToBounds:);
[invocation setArgument:&clipsToBounds atIndex:2];
[invocation invoke];
}
#endif
}
[container addSubview:view];
}
#if !__has_feature(objc_arc)
virtual ~ExternalNSViewBase () noexcept
{
[container release];
[view release];
}
#endif
bool platformViewTypeSupported (PlatformViewType type) override
{
return type == PlatformViewType::NSView;
}
bool attach (void* parent, PlatformViewType parentViewType) override
{
if (!parent || parentViewType != PlatformViewType::NSView)
return false;
auto parentNSView = (__bridge NSView*)parent;
[parentNSView addSubview:container];
return true;
}
bool remove () override
{
[container removeFromSuperview];
return true;
}
void setViewSize (IntRect frame, IntRect visible) override
{
container.frame = toNSRect (visible);
frame.origin.x -= visible.origin.x;
frame.origin.y -= visible.origin.y;
view.frame = toNSRect (frame);
}
void setContentScaleFactor (double scaleFactor) override {}
void setMouseEnabled (bool state) override
{
if ([view respondsToSelector:@selector (setEnabled:)])
[(id)view setEnabled:state];
}
void takeFocus () override
{
if (view.acceptsFirstResponder)
{
if (auto window = view.window)
[window makeFirstResponder:view];
}
}
void looseFocus () override
{
if (auto window = view.window)
[window makeFirstResponder:container.superview];
}
void setTookFocusCallback (const TookFocusCallback& callback) override
{
if (auto var = ObjCInstance (container).getVariable<TookFocusCallback> (
ExternalViewContainerNSView::TookFocusCallbackVarName))
{
var->set (callback);
}
}
};
//------------------------------------------------------------------------
} // ExternalView
} // VSTGUI
File diff suppressed because it is too large Load Diff
@@ -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* inDelegate) { delegate = inDelegate; }
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
File diff suppressed because it is too large Load Diff
+84
View File
@@ -0,0 +1,84 @@
// 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_uidescription_editor @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 2015/2017/2019 and Windows 7 Platform SDK)
- 7 (32 and 64 bit)
- 8 (32 and 64 bit)
- 10 (32 and 64 bit)
\par Apple macOS (with Xcode 7.3 or newer)
- 10.9 - 10.15 (32 and 64 bit)
\par Apple iOS
- 8.0 - 13.0 (32 and 64 bit)
\par Linux (with gcc >= 5.4 or clang >= 3.8)
- Ubuntu 2016.04 or newer
\sa [VSTGUI @ GitHub](https://github.com/steinbergmedia/vstgui)
@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
- Cocoa
- QuartzCore
- OpenGL (Optional)
\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-dev
- libx11-xcb-dev
- libxcb-util-dev
- libxcb-cursor-dev
- libxcb-keysyms1-dev
- libxcb-xkb-dev
- libxkbcommon-dev
- libxkbcommon-x11-dev
- libfontconfig1-dev
- libcairo2-dev
- libfreetype6-dev
- libpango1.0-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,457 @@
// 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
@tableofcontents
- @ref version4_introduction @n
- @ref new_stuff @n
- @ref code_changes @n
- @ref hidpi_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_15 Version 4.15
- add support for custom view layouts (see IViewLayouter and CViewContainer::setViewLayouter).
- add a grid view layouter that is similar to CSS Grid (see GridLayouter).
- add Scripting for UIDescription (see uidescription-scripting/uiscripting.md)
- add new text editor view (see lib/ctexteditor.h)
- a scroll view can now have a top and a left edge view (see CScrollView::setEdgeView)
- preliminary Wayland support
@subsection version4_14 Version 4.14
- add crosshair mouse cursor (kCursorCrosshair)
- customizable knob range (see CKnob::setKnobRange)
- new layouts for CRowColumnView
@subsection version4_13 Version 4.13
- support embedding platform views (HWND & NSView) as sub views (see CExternalView and ExternalView::IView) and examples in the contrib folder.
@subsection version4_12_2 Version 4.12.2
- make it possible to draw only frames in a range for views using multi frame bitmaps.
@subsection version4_12_1 Version 4.12.1
- make it possible to use the new multi frame bitmap feature with custom value to frame index mappings by subclassing.
@subsection version4_12 Version 4.12
- new multi frame bitmap representation that allows to support more frames per bitmap on current
hardware by supporting to layout the frames in the bitmap by rows and multiple columns instead of
one column as before. See VSTGUI::CMultiFrameBitmap. All included controls are updated to support
it, while the old method is deprecated but still supported for now.
- the image stitcher tool was updated to support the creation of multi row/column frames bitmap
@subsection version4_11 Version 4.11
- Using DirectComposition on Windows now with support for CLayeredViewContainer
- Removed 32-bit Carbon support
- Reworked event handling, please see @ref code_changes_4_10_to_4_11
- Reworked unit test framework to be able to debug the tests
@subsection version4_10 Version 4.10
- VSTGUI now needs to be initialized and terminated explicitly. See VSTGUI::init() and VSTGUI::exit().
- UIDescription files are now written in JSON format and the old XML format is deprecated
- It's now possible to conditionally remove the XML parser and the expat library from building (set VSTGUI_ENABLE_XML_PARSER to 0)
- This is the last version not depending on c++17 compiler support.
@subsection version4_9 Version 4.9
- new control: VSTGUI::CListControl in play with VSTGUI::CStringList
- custom font support: VSTGUI now supports using fonts embedded in its Bundle/Package at Resources/Fonts. Note that this works on Windows only when building with the Windows 10 SDK and it does also only work on Windows 10. There's no such restriction on macOS or Linux.
@subsection version4_8 Version 4.8
- new VSTGUI::CSegmentButton selection mode \link VSTGUI::CSegmentButton::SelectionMode::kSingleToggle kSingleToggle\endlink and styles \link VSTGUI::CSegmentButton::Style::kHorizontalInverse kHorizontalInverse\endlink and \link VSTGUI::CSegmentButton::Style::kVerticalInverse kVerticalInverse\endlink.
@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: VSTGUI::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_uidescription_editor @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_13_to_4_14 VSTGUI 4.13 -> VSTGUI 4.14
- In CParamDisplay::drawPlatformText(..) the string argument changed from IPlatformString to UTF8Text
@subsection code_changes_4_12_to_4_13 VSTGUI 4.12 -> VSTGUI 4.13
- the context argument of IFontPainter has changed to use the new platform graphics device context
@subsection code_changes_4_11_to_4_12 VSTGUI 4.11 -> VSTGUI 4.12
- The CMultiFrameBitmap change deprecated the VSTGUI::IMultiBitmapControl class. If you use it,
update your uses and use a VSTGUI::CMultiFrameBitmap instead.
- If you compile with VSTGUI_ENABLE_DEPRECATED_METHODS=0 you need to update your multi frame bitmaps
to use VSTGUI::CMultiFrameBitmap.
- In 4.12.2 the following constructors have lost their offset parameter:
- CKickButton
- CAnimKnob
- CMovieBitmap
- CMovieButton
- CSwitchBase
- CVerticalSwitch
- CHorizontalSwitch
- CRockerSwitch
@subsection code_changes_4_10_to_4_11 VSTGUI 4.10 -> VSTGUI 4.11
Changes due to event handling rework:
- IKeyboardHook changed its methods. If you inherit from it, you need to adopt to the new methods or use OldKeyboardHookAdapter
- IMouseObserver changed a few of its methods. If you inherit from it, you need to adopt to the new methods or use OldMouseObserverAdapter
- CViewContainer::onWheel is now marked final, you cannot inherit this method, please override the new CView::onMouseWheelEvent instead if you need to handle mouse wheel events in a custom view container
- DragEventData has changed it's modifiers type from CButtonState to Modifiers
- CView::hitTest uses an Event now instead of a CButtonState (the method with a CButtonState still works but is deprecated)
- CControl::checkDefaultValue(CButtonState) was removed and replaced by a generic method which uses
the static function CControl::CheckDefaultValueEventFunc to reset a control to its default value
CView has the following new methods:
- dispatchEvent
- onMouseDownEvent
- onMouseMoveEvent
- onMouseUpEvent
- onMouseCancelEvent
- onMouseEnterEvent
- onMouseExitEvent
- onMouseWheelEvent
- onZoomGestureEvent
- onKeyboardEvent
Which replaces the following old methods:
- onKeyDown
- onKeyUp
- onWheel
The old mouse methods (onMouseDown, onMouseUp, onMouseMoved, etc) are still supported but should be replaced with the new methods in the long run.
@subsection code_changes_4_9_to_4_10 VSTGUI 4.9 -> VSTGUI 4.10
- one has to use VSTGUI::init() before using VSTGUI and VSTGUI::exit() after use
@subsection code_changes_4_8_to_4_9 VSTGUI 4.8 -> VSTGUI 4.9
- removed method CView::onWheel (..) where the axis of the event was not included. You have to use the other onWheel method for your custom classes now.
- new IViewMouseListener interface method IViewMouseListener::viewOnMouseEnabled
- changed ModalViewSession type name to ModalViewSessionID and its type to an integer type
- changed the CFrame::beginModalViewSession return value to be an Optional<ModalViewSessionID> for safer use.
@subsection code_changes_4_7_to_4_8 VSTGUI 4.7 -> VSTGUI 4.8
- CCommandMenuItem constructor takes a CCommandMenuItem::Desc argument now. You will get compiler errors when not adopting to this change.
- removed Message sending for:
- kMsgMenuItemValidate, kMsgMenuItemSelected -> use ICommandMenuItemTarget
- kMessageValueChanged, kMessageBeginEdit, kMessageEndEdit -> use IControlListener
- kMsgTruncatedTextChanged -> use ITextLabelListener
- kMsgBeforePopup -> use IOptionMenuListener
- IDependency is deprecated. Please use explicit interfaces for communicating changes.
- removed "using namespace VSTGUI" from vstgui.h
@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 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 new_in_4_9 Version 4.9
* @ingroup new_in
*/
//------------------------------------------------------------------------
/*! @defgroup new_in_4_10 Version 4.10
* @ingroup new_in
*/
//------------------------------------------------------------------------
/*! @defgroup new_in_4_11 Version 4.11
* @ingroup new_in
*/
//------------------------------------------------------------------------
/*! @defgroup new_in_4_12 Version 4.12
* @ingroup new_in
*/
//------------------------------------------------------------------------
/*! @defgroup new_in_4_12_1 Version 4.12.1
* @ingroup new_in
*/
//------------------------------------------------------------------------
/*! @defgroup new_in_4_12_2 Version 4.12.2
* @ingroup new_in
*/
//------------------------------------------------------------------------
/*! @defgroup new_in_4_15 Version 4.15
* @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
*/
//------------------------------------------------------------------------
/*! @defgroup uses_multi_frame_bitmaps Views using Multi-Frame Bitmaps
* \see CMultiFrameBitmap
*/
//------------------------------------------------------------------------
@@ -0,0 +1,179 @@
/**
@page create_your_own_view Create your own view for the WYSIWYG editor in VSTGUI
@section create_your_own_view_intro Introduction
When you want to edit your own VST3 plugin. You can find the need to create your own View.
You can edit your plugin by doing "Right click > Open UIDescription Editor"
![Edit VST3 plugin](screenshots/editVST3.png)
You can find more information about this interface in the documentation : "VSTGUI 4 > VSTGUI > New Inline UI Editor for VST3 (WYSIWYG) > The Editor".
During this tutorial we will make a new view that will appear in the "Views Tab" at the bottom right of the editor and it allow us to drag and drop it inside our VST3 plugin.
@section create_your_own_view_createView Create the new view class
To create a new graphical view you need to create a class that inherites from *CView* or *CControl*. We recommend that you start with the *CControl* class when you plan to have an interactive view, otherwise if it only should display data use *CView*.
Your header file should look like this :
~~~~~~~~~~~~~{.cpp}
#pragma once
#include "vstgui/vstgui.h"
namespace VSTGUI {
class MyControl : public CControl
{
public:
MyControl (const CRect& size );
void draw (CDrawContext *pContext) override;
CLASS_METHODS (MyControl, CControl)
};
} // namespace VSTGUI
~~~~~~~~~~~~~
And your cpp file :
~~~~~~~~~~~~~{.cpp}
#include "MyControl.h"
namespace VSTGUI {
MyControl::MyControl (const CRect& size) : CControl (size) {}
void MyControl::draw (CDrawContext* pContext)
{
// --- setup the background rectangle
pContext->setLineWidth (1);
pContext->setFillColor (CColor (255, 255, 255, 255)); // white background
pContext->setFrameColor (CColor (0, 0, 0, 255)); // black borders
// --- draw the rect filled (with white) and stroked (line around rectangle)
pContext->drawRect (getViewSize (), kDrawFilledAndStroked);
setDirty (false);
}
} // namespace VSTGUI
~~~~~~~~~~~~~
We have two functions, the constructor which only calls the parent constructor and the *draw* function which will define the design of the view. In this example we draw a white rectangle with black borders.
@section create_your_own_view_registerView Register your view
So now you have a basic graphical view. But it will not appear in the list when you edit your plugin.
You need to create a new class, a "factory", that will register your view and create it. This class only needs a cpp file (if you strip dead code in your linker settings, then you need to make sure that this class is not stripped).
Let us begin by creating an empty class that inherites from *'ViewCreatorAdapter'* :
~~~~~~~~~~~~~{.cpp}
#pragma once
#include "vstgui/vstgui.h"
#include "vstgui/vstgui_uidescription.h"
#include "vstgui/uidescription/detail/uiviewcreatorattributes.h"
// Replace this include by the header file of your new view.
#include "MyControl.h"
namespace VSTGUI {
class MyControlFactory : public ViewCreatorAdapter
{
public:
};
} // namespace VSTGUI
~~~~~~~~~~~~~
In the constructor we need to register our view to the UIViewFactory. If we don't do that it will not appear in the list that will allow us to add the view to our VST3 plugin.
~~~~~~~~~~~~~{.cpp}
MyControlFactory () { UIViewFactory::registerViewCreator (*this); }
~~~~~~~~~~~~~
The main factory needs 3 others functions :
* The name of the view (as shown in the WYSIWYS editor)
~~~~~~~~~~~~~{.cpp}
IdStringPtr getViewName () const { return "Name of my UI component"; }
~~~~~~~~~~~~~
* The parent class of the view (In this tutorial we're using *CControl*)
~~~~~~~~~~~~~{.cpp}
IdStringPtr getBaseViewName () const { return UIViewCreator::kCControl; }
~~~~~~~~~~~~~
* and a creator method which returns a new view with a default size
~~~~~~~~~~~~~{.cpp}
CView* create (const UIAttributes& attributes, const IUIDescription* description) const
{
return new MyControl (CRect (0, 0, 100, 100));
}
~~~~~~~~~~~~~
You also need to create a static variable having the same type as our factory. This variable will call the constructor of your factory. Thus, your view will be registered automatically.
~~~~~~~~~~~~~{.cpp}
MyControlFactory __gMyControlFactory;
~~~~~~~~~~~~~
So at the end you should have something like this :
~~~~~~~~~~~~~{.cpp}
#pragma once
#include "vstgui/vstgui.h"
#include "vstgui/vstgui_uidescription.h"
#include "vstgui/uidescription/detail/uiviewcreatorattributes.h"
#include "MyControl.h"
namespace VSTGUI {
class MyControlFactory : public ViewCreatorAdapter
{
public:
// register this class with the view factory
MyControlFactory () { UIViewFactory::registerViewCreator (*this); }
// return an unique name here
IdStringPtr getViewName () const override { return "Name of my UI component"; }
// return the name here from where your custom view inherites.
// Your view automatically supports the attributes from it.
IdStringPtr getBaseViewName () const override { return UIViewCreator::kCControl; }
// create your view here.
// Note you don't need to apply attributes here as
// the apply method will be called with this new view
CView* create (const UIAttributes& attributes, const IUIDescription* description) const override
{
CRect size (CPoint (45, 45), CPoint (400, 150) );
return new MyControl (size);
}
};
// create a static instance so that it registers itself with the view factory
MyControlFactory __gMyControlFactory;
} // namespace VSTGUI
~~~~~~~~~~~~~
@section create_your_own_view_result Result
Now if you come back to the VST 3 plugin Editor you can find your new view in the list.
![Edit VST3 plugin](screenshots/newuicompname.png)
*/
@@ -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,8 @@
/**
@page page_misc Miscellaneous
- @subpage page_animation
- @subpage key_event_flow
*/
@@ -0,0 +1,114 @@
/**
@page the_view_system The view system overview
A view is a rectangular section which is contained in a window.
It is responsible for handling user events and drawing to the screen.
In VSTGUI this is the CView class.
Another aspect of a view is that it can be part of a parent view.
The main parent view is always a CFrame object. It is itself a view and it is a
view container which can contain one or more child views.
If you need to group multiple views you can use the CViewContainer class.
It is also a view but it can have child views.
@section inherit_from_cview Inherit from CView
If you want to draw custom data which cannot be presented via the included
CView subclasses you need to create a new subclass of CView:
~~~~~~~~~~~~~{.cpp}
class MyView : public CView
{
public:
MyView (const CRect& size) : CView (size) {}
};
~~~~~~~~~~~~~
If you want to draw some custom stuff, you need to override the draw method:
~~~~~~~~~~~~~{.cpp}
class MyView : public CView
{
public:
MyView (const CRect& size) : CView (size) {}
void draw (CDrawContext* context) override
{}
};
~~~~~~~~~~~~~
As you see, the draw method has a CDrawContext argument. The draw context has all the methods to
draw stuff into the view. Below I just show you a very simple thing, drawing a green line.
~~~~~~~~~~~~~{.cpp}
void MyView::draw (CDrawContext* context) override
{
context->setFrameColor (kGreenColor);
context->drawLine (CPoint (0,0), CPoint (10, 10));
}
~~~~~~~~~~~~~
Now a little strange concept of VSTGUI is that the draw context is not automatically adjusted to the
position of the view, so that if the position of the view is at x=50 and y=50, you will not see the line
(because it is drawn from 0,0 to 10,10 and that is outside the views boundaries).
So you need to offset your drawing by the position of the view.
~~~~~~~~~~~~~{.cpp}
void MyView::draw (CDrawContext* context) override
{
auto viewPos = getViewSize ().getTopLeft ();
CDrawContext::Transform t (*context, CGraphicsTransform ().translate (viewPos));
context->setFrameColor (kGreenColor);
context->drawLine (CPoint (0,0), CPoint (10, 10));
}
~~~~~~~~~~~~~
If CDrawContext::Transform is not defined in your VSTGUI version you have a version older than 4.2
and you need to offset the points yourself.
If you have a complex view which takes a long time to draw, you can also override the CView::drawRect (CDrawContext*, const CRect&) method
and only draw the region which needs to be drawn.
@section handling_mouse_events Handling mouse events
Next you may want to add user interactions via mouse events.
For this you have to override two or three methods depending on if you want to track mouse movement or just want to get a mouse click.
For a simple mouse click you have to do this :
~~~~~~~~~~~~~{.cpp}
class MyView : public CView
{
public:
CMouseEventResult onMouseDown (CPoint& where, const CButtonState& buttons) override
{
return kMouseEventHandled; // needed to get the onMouseUp call
}
CMouseEventResult onMouseUp (CPoint& where, const CButtonState& buttons) override
{
if (buttons.isLeftButton () && getViewSize ().pointInside (where))
doMouseClick ();
return kMouseEventHandled;
}
void doMouseClick () {}
};
~~~~~~~~~~~~~
If a user clicks inside MyView the doMouseClick() method is called.
If you need to track mouse movement in your view you have to additionally override the onMouseMoved method:
~~~~~~~~~~~~~{.cpp}
class MyView : public CView
{
public:
CMouseEventResult onMouseMove (CPoint& where, const CButtonState& buttons) override
{
return kMouseEventHandled;
}
};
~~~~~~~~~~~~~
This method is always called if the mouse moves inside your view, even if no buttons are down.
So if you want to track the mouse only if the left button is down you have to check for it with buttons.isLeftButton () inside that method.
*/
Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

+438
View File
@@ -0,0 +1,438 @@
##########################################################################################
# VSTGUI Library
##########################################################################################
set(target vstgui)
option(
VSTGUI_TEXTRENDERING_LEGACY_INCONSISTENCY
"Use the legacy platform inconsistency text rendering"
OFF
)
if(${VSTGUI_TEXTRENDERING_LEGACY_INCONSISTENCY})
target_compile_definitions(${target} PRIVATE VSTGUI_TEXTRENDERING_LEGACY_INCONSISTENCY=1)
endif()
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
algorithm.h
cbitmap.cpp
cbitmap.h
cbitmapfilter.cpp
cbitmapfilter.h
cbuttonstate.h
cclipboard.cpp
cclipboard.h
ccolor.cpp
ccolor.h
cdatabrowser.cpp
cdatabrowser.h
cdrawcontext.cpp
cdrawcontext.h
cdrawdefs.h
cdrawmethods.cpp
cdrawmethods.h
cdropsource.cpp
cdropsource.h
cexternalview.cpp
cexternalview.h
cfileselector.cpp
cfileselector.h
cfont.cpp
cfont.h
cframe.cpp
cframe.h
cgradient.cpp
cgradient.h
cgradientview.cpp
cgradientview.h
cgraphicspath.cpp
cgraphicspath.h
cgraphicstransform.h
cinvalidrectlist.h
clayeredviewcontainer.cpp
clayeredviewcontainer.h
clinestyle.cpp
clinestyle.h
ctexteditor.h
ctexteditor.cpp
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/clistcontrol.cpp
controls/clistcontrol.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/cstringlist.cpp
controls/cstringlist.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/itexteditlistener.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
enumbitset.h
events.cpp
events.h
finally.h
genericstringlistdatabrowsersource.cpp
genericstringlistdatabrowsersource.h
idatabrowserdelegate.h
idatapackage.h
idependency.h
iexternalview.h
ifocusdrawing.h
iscalefactorchangedlistener.h
itouchevent.h
iviewlayouter.h
iviewlistener.h
malloc.h
optional.h
pixelbuffer.h
pixelbuffer.cpp
platform/iplatformbitmap.h
platform/iplatformgraphicsdevice.h
platform/iplatformfileselector.h
platform/iplatformfont.h
platform/iplatformframe.h
platform/iplatformframecallback.h
platform/iplatformgradient.h
platform/iplatformgraphicspath.h
platform/iplatformopenglview.h
platform/iplatformoptionmenu.h
platform/iplatformresourceinputstream.h
platform/iplatformstring.h
platform/iplatformtaskexecutor.h
platform/iplatformtextedit.h
platform/iplatformtextinputclient.h
platform/iplatformtimer.h
platform/iplatformviewlayer.h
platform/platformfactory.cpp
platform/platformfactory.h
platform/platformfwd.h
platform/platform_macos.h
platform/platform_linux.h
platform/platform_wayland.h
platform/platform_win32.h
platform/platform_x11.h
platform/std_unorderedmap.h
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/gradientbase.h
platform/common/threadpooltaskexecutor.h
viewlayouter/autosizeviewlayouter.cpp
viewlayouter/autosizeviewlayouter.h
viewlayouter/baseviewlayouter.h
viewlayouter/gridlayouter.cpp
viewlayouter/gridlayouter.h
viewlayouter/noviewlayouter.h
tasks.cpp
tasks.h
vstguibase.h
vstguidebug.cpp
vstguidebug.h
vstguifwd.h
vstguiinit.cpp
vstguiinit.h
vstkeycode.h
)
##########################################################################################
set(${target}_mac_sources
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/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/cocoa/objcclassbuilder.h
platform/mac/coregraphicsdevicecontext.h
platform/mac/coregraphicsdevicecontext.mm
platform/mac/macclipboard.h
platform/mac/macclipboard.mm
platform/mac/macfactory.h
platform/mac/macfactory.mm
platform/mac/macfileselector.mm
platform/mac/macfileselector.h
platform/mac/macglobals.cpp
platform/mac/macglobals.h
platform/mac/macstring.h
platform/mac/macstring.mm
platform/mac/mactaskexecutor.mm
platform/mac/mactaskexecutor.h
platform/mac/mactimer.cpp
platform/mac/mactimer.h
platform/mac/quartzgraphicspath.cpp
platform/mac/quartzgraphicspath.h
platform/win32
platform/linux
platform/mac/ios
../doxygen
)
##########################################################################################
set(${target}_win32_sources
platform/win32/direct2d/d2d.h
platform/win32/direct2d/d2dbitmap.cpp
platform/win32/direct2d/d2dbitmap.h
platform/win32/direct2d/d2dbitmapcache.cpp
platform/win32/direct2d/d2dbitmapcache.h
platform/win32/direct2d/d2dfont.cpp
platform/win32/direct2d/d2dfont.h
platform/win32/direct2d/d2dgradient.cpp
platform/win32/direct2d/d2dgradient.h
platform/win32/direct2d/d2dgraphicscontext.cpp
platform/win32/direct2d/d2dgraphicscontext.h
platform/win32/direct2d/d2dgraphicspath.cpp
platform/win32/direct2d/d2dgraphicspath.h
platform/win32/win32bitmapbase.h
platform/win32/win32taskexecutor.cpp
platform/win32/win32taskexecutor.h
platform/win32/win32dll.h
platform/win32/win32datapackage.cpp
platform/win32/win32datapackage.h
platform/win32/win32directcomposition.cpp
platform/win32/win32directcomposition.h
platform/win32/win32dragging.cpp
platform/win32/win32dragging.h
platform/win32/win32factory.cpp
platform/win32/win32factory.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/win32resourcestream.cpp
platform/win32/win32resourcestream.h
platform/win32/win32support.cpp
platform/win32/win32support.h
platform/win32/win32textedit.cpp
platform/win32/win32textedit.h
platform/win32/win32viewlayer.cpp
platform/win32/win32viewlayer.h
platform/win32/winfileselector.cpp
platform/win32/winfileselector.h
platform/win32/winstring.cpp
platform/win32/winstring.h
platform/win32/wintimer.cpp
platform/win32/wintimer.h
)
##########################################################################################
set(${target}_linux_sources
platform/linux/cairobitmap.cpp
platform/linux/cairobitmap.h
platform/linux/cairofont.cpp
platform/linux/cairofont.h
platform/linux/cairogradient.cpp
platform/linux/cairogradient.h
platform/linux/cairographicscontext.cpp
platform/linux/cairographicscontext.h
platform/linux/cairopath.cpp
platform/linux/cairopath.h
platform/linux/cairoutils.h
platform/linux/linuxstring.cpp
platform/linux/linuxstring.h
platform/linux/x11dragging.cpp
platform/linux/x11dragging.h
platform/linux/x11fileselector.cpp
platform/linux/x11fileselector.h
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
platform/linux/linuxfactory.cpp
platform/linux/linuxfactory.h
platform/linux/linuxtaskexecutor.cpp
platform/linux/linuxtaskexecutor.h
)
if(LINUX AND VSTGUI_ENABLE_WAYLAND_SUPPORT)
set(${target}_linux_sources
${${target}_linux_sources}
platform/linux/waylandframe.cpp
platform/linux/waylandframe.h
platform/linux/waylandplatform.cpp
platform/linux/waylandplatform.h
platform/linux/waylandutils.cpp
platform/linux/waylandutils.h
platform/linux/waylandclientcontext.cpp
platform/linux/waylandclientcontext.h
)
endif()
##########################################################################################
if(CMAKE_HOST_APPLE)
set(${target}_sources ${${target}_common_sources} ${${target}_mac_sources})
endif()
##########################################################################################
if(WIN32)
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_precompile_headers(${target} PRIVATE cviewcontainer.h cdrawcontext.h)
target_compile_definitions(${target} ${VSTGUI_COMPILE_DEFINITIONS})
vstgui_set_cxx_version(${target} ${VSTGUI_CXX_VERSION})
vstgui_source_group_by_folder(${target})
if(LINUX AND VSTGUI_ENABLE_WAYLAND_SUPPORT)
# Fetch wayland-server-delegate to get iwaylandclientcontext.h
include (FetchContent)
FetchContent_Declare(
ccl_wayland_server_delegate
GIT_REPOSITORY https://github.com/cclsoftware/wayland-server-delegate.git
GIT_TAG 86c32c61f0c861448635c041da5c343ce097ccff
)
FetchContent_MakeAvailable(ccl_wayland_server_delegate)
target_include_directories(${target}
PRIVATE
${ccl_wayland_server_delegate_SOURCE_DIR}
)
target_link_libraries(${target} PRIVATE ${WAYLAND_LIBRARIES})
target_compile_definitions(${target} PRIVATE VSTGUI_ENABLE_WAYLAND_SUPPORT=1)
endif()
if(LINUX)
target_include_directories(${target} PRIVATE ${X11_INCLUDE_DIR})
target_include_directories(${target} PRIVATE ${FREETYPE_INCLUDE_DIRS})
target_include_directories(${target} PRIVATE ${GLIB_INCLUDE_DIRS})
target_include_directories(${target} PRIVATE ${CAIRO_INCLUDE_DIRS})
target_include_directories(${target} PRIVATE ${PANGO_INCLUDE_DIRS})
target_include_directories(${target} PRIVATE ${FONTCONFIG_INCLUDE_DIRS})
target_link_libraries(${target} PRIVATE ${LINUX_LIBRARIES})
endif()
if(CMAKE_HOST_APPLE)
target_compile_options(${target} PRIVATE -Wall -Werror)
set(PLATFORM_LIBRARIES
"-framework Cocoa"
"-framework QuartzCore"
"-framework Accelerate"
)
if(CMAKE_OSX_DEPLOYMENT_TARGET VERSION_GREATER_EQUAL 11.0)
target_compile_definitions(${target} PRIVATE "VSTGUI_USE_OBJC_UTTYPE")
set(PLATFORM_LIBRARIES
${PLATFORM_LIBRARIES}
"-framework UniformTypeIdentifiers"
)
endif()
if(VSTGUI_ENABLE_OPENGL_SUPPORT)
set(PLATFORM_LIBRARIES
${PLATFORM_LIBRARIES}
"-framework OpenGL"
)
endif()
target_link_libraries(${target}
PUBLIC
${PLATFORM_LIBRARIES}
)
endif()
+97
View File
@@ -0,0 +1,97 @@
// 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 "optional.h"
#include "vstguidebug.h"
#include <cstdint>
#include <algorithm>
//------------------------------------------------------------------------
namespace VSTGUI {
//------------------------------------------------------------------------
/** Returns the index of the value */
template <typename Iter, typename Type, typename ResultType = int32_t>
Optional<ResultType> indexOf (Iter first, Iter last, const Type& value)
{
auto it = std::find (first, last, value);
if (it == last)
return {};
return {static_cast<ResultType> (std::distance (first, it))};
}
//------------------------------------------------------------------------
/** Returns the index of the element for which predicate p returns true */
template <typename Iter, typename Proc, typename ResultType = int32_t>
Optional<ResultType> indexOfTest (Iter first, Iter last, Proc p)
{
auto it = std::find_if (first, last, p);
if (it == last)
return {};
return {static_cast<ResultType> (std::distance (first, it))};
}
//------------------------------------------------------------------------
/** Returns the value clamped to min and max */
template <typename T>
T clamp (T value, T min, T max)
{
return std::min (max, std::max (value, min));
}
//------------------------------------------------------------------------
/** Returns the value clamped to zero and one */
template <typename T>
T clampNorm (T value)
{
static_assert (std::is_floating_point<T>::value, "Only floating point types allowed");
return clamp (value, static_cast<T> (0), static_cast<T> (1));
}
//------------------------------------------------------------------------
/** Returns the value projected lineary between stepOffset and stepOffset + steps */
template<typename NormT, typename StepT = int32_t>
StepT normalizedToSteps (NormT value, StepT numSteps, StepT stepStart = static_cast<StepT> (0))
{
static_assert (std::is_integral<StepT>::value, "Step type must be integral");
vstgui_assert (value >= 0. && value <= 1., "Only normalized values are allowed");
return std::min<StepT> (numSteps, static_cast<StepT> ((numSteps + 1) * value)) + stepStart;
}
//------------------------------------------------------------------------
/** Returns the normalized value from the step value */
template<typename NormT, typename StepValueT, typename StepT>
NormT stepsToNormalized (StepValueT value, StepT steps, StepT stepOffset = static_cast<StepT> (0))
{
static_assert (std::is_integral<StepT>::value, "Step type must be integral");
vstgui_assert ((value - stepOffset) <= steps, "Value must be smaller or equal then steps");
return static_cast<NormT> (value - stepOffset) / static_cast<NormT> (steps);
}
//------------------------------------------------------------------------
/** Returns the normalized value from a plain one */
template<typename NormT, typename PlainT>
NormT plainToNormalized (PlainT value, PlainT minValue, PlainT maxValue)
{
static_assert (std::is_floating_point<NormT>::value,
"Only floating point types for NormT allowed");
vstgui_assert (maxValue - minValue != 0., "min and max value must be different");
return (value - minValue) / static_cast<NormT> (maxValue - minValue);
}
//------------------------------------------------------------------------
/** Returns the plain value from a normalized one */
template<typename PlainT, typename NormT>
PlainT normalizedToPlain (NormT value, PlainT minValue, PlainT maxValue)
{
static_assert (std::is_floating_point<NormT>::value,
"Only floating point types for NormT allowed");
vstgui_assert (maxValue - minValue != 0., "min and max value must be different");
return static_cast<PlainT> ((maxValue - minValue) * value + minValue);
}
//------------------------------------------------------------------------
} // VSTGUI
@@ -0,0 +1,387 @@
// 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 (view->getViewSize ());
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 (view->getViewSize ());
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)
{
auto* control = dynamic_cast<CControl*> (view);
if (control)
startValue = control->getValue ();
}
//-----------------------------------------------------------------------------
void ControlValueAnimation::animationTick (CView* view, IdStringPtr name, float pos)
{
auto* 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)
{
auto* control = dynamic_cast<CControl*> (view);
if (control)
{
if (!wasCanceled || forceEndValueOnFinish)
control->setValue (endValue);
}
}
//------------------------------------------------------------------------
FuncAnimation::FuncAnimation (StartFunc&& start, TickFunc&& tick, FinishedFunc&& finished)
: start (std::move (start)), tick (std::move (tick)), finished (std::move (finished))
{
}
//------------------------------------------------------------------------
void FuncAnimation::animationStart (CView* view, IdStringPtr name) { start (view, name); }
//------------------------------------------------------------------------
void FuncAnimation::animationTick (CView* view, IdStringPtr name, float pos)
{
tick (view, name, pos);
}
//------------------------------------------------------------------------
void FuncAnimation::animationFinished (CView* view, IdStringPtr name, bool wasCanceled)
{
finished (view, name, wasCanceled);
}
}} // namespaces
@@ -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
#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;
};
//------------------------------------------------------------------------
/// @brief animation via custom functions
/// @ingroup AnimationTargets
/// @ingroup new_in_4_14
//------------------------------------------------------------------------
class FuncAnimation : public IAnimationTarget,
public NonAtomicReferenceCounted
{
public:
using StartFunc = std::function<void (CView*, IdStringPtr)>;
using TickFunc = std::function<void (CView*, IdStringPtr, float)>;
using FinishedFunc = std::function<void (CView*, IdStringPtr, bool)>;
FuncAnimation (StartFunc&& start, TickFunc&& tick, FinishedFunc&& finished);
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;
private:
StartFunc start;
TickFunc tick;
FinishedFunc finished;
};
} // Animation
} // VSTGUI
@@ -0,0 +1,374 @@
// 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/platformfactory.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, bool notifyOnCancel);
~Animation () noexcept override;
std::string name;
SharedPointer<CView> view;
IAnimationTarget* animationTarget;
ITimingFunction* timingFunction;
DoneFunction notification;
uint64_t startTime {0};
float lastPos {-1.};
bool done {false};
bool notifyOnCancel;
};
//-----------------------------------------------------------------------------
Animation::Animation (CView* view, const std::string& name, IAnimationTarget* at,
ITimingFunction* t, DoneFunction&& notification, bool notifyOnCancel)
: name (name)
, view (view)
, animationTarget (at)
, timingFunction (t)
, notification (std::move (notification))
, notifyOnCancel (notifyOnCancel)
{
}
//-----------------------------------------------------------------------------
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,
bool notifyOnCancel)
{
if (pImpl->animations.empty ())
Detail::Timer::addAnimator (this);
removeAnimation (view, name);
pImpl->animations.add (makeOwned<Detail::Animation> (view, name, target, timingFunction,
std::move (notification), notifyOnCancel));
#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);
}
if (!animation->notifyOnCancel)
animation->notification = nullptr;
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);
auto currentTicks = getPlatformFactory ().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 = static_cast<uint32_t> (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,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 <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 or on cancelation
of the animation if notifyOnCancel is true (new in 4.11)
*/
void addAnimation (CView* view, IdStringPtr name, IAnimationTarget* target,
ITimingFunction* timingFunction, DoneFunction notification = nullptr,
bool notifyOnCancel = false);
/** 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; }
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,219 @@
// 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)
{
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.));
}
//------------------------------------------------------------------------
CubicBezierTimingFunction* CubicBezierTimingFunction::make (Style style, uint32_t time)
{
using Func = CubicBezierTimingFunction;
switch (style)
{
case Easy:
return new CubicBezierTimingFunction (Func::easy (time));
case EasyIn:
return new CubicBezierTimingFunction (Func::easyIn (time));
case EasyOut:
return new CubicBezierTimingFunction (Func::easyOut (time));
case EasyInOut:
return new CubicBezierTimingFunction (Func::easyInOut (time));
}
return nullptr;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
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,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
#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 (CubicBezierTimingFunction&&) = default;
CubicBezierTimingFunction& operator= (const CubicBezierTimingFunction&) = default;
CubicBezierTimingFunction& operator= (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);
enum Style
{
Easy,
EasyIn,
EasyOut,
EasyInOut
};
static CubicBezierTimingFunction* make (Style style, uint32_t time);
private:
static CPoint lerp (CPoint p1, CPoint p2, float pos);
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
+371
View File
@@ -0,0 +1,371 @@
// 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 "algorithm.h"
#include "platform/iplatformbitmap.h"
#include "platform/platformfactory.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 = getPlatformFactory ().createBitmap (desc))
bitmaps.emplace_back (platformBitmap);
}
//-----------------------------------------------------------------------------
CBitmap::CBitmap (CCoord width, CCoord height)
{
if (auto platformBitmap = getPlatformFactory ().createBitmap ({width, height}))
bitmaps.emplace_back (platformBitmap);
}
//------------------------------------------------------------------------
CBitmap::CBitmap (CPoint size, double scaleFactor)
{
size.x *= scaleFactor;
size.y *= scaleFactor;
size.makeIntegral ();
if (auto platformBitmap = getPlatformFactory ().createBitmap (size))
{
platformBitmap->setScaleFactor (scaleFactor);
bitmaps.emplace_back (platformBitmap);
}
}
//-----------------------------------------------------------------------------
CBitmap::CBitmap (const PlatformBitmapPtr& platformBitmap)
{
bitmaps.emplace_back (platformBitmap);
}
//-----------------------------------------------------------------------------
void CBitmap::draw (CDrawContext* context, const CRect& rect, const CPoint& offset, float alpha)
{
drawClipped (context, rect, [&] () {
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;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
CMultiFrameBitmap::CMultiFrameBitmap (const CResourceDescription& desc,
CMultiFrameBitmapDescription multiFrameDesc)
: CBitmap (desc), description (multiFrameDesc)
{
}
//-----------------------------------------------------------------------------
bool CMultiFrameBitmap::setMultiFrameDesc (CMultiFrameBitmapDescription desc)
{
if (desc.frameSize.x * desc.framesPerRow > getSize ().x)
return false;
if (desc.frameSize.y * (desc.numFrames / desc.framesPerRow) > getSize ().y)
return false;
description = desc;
return true;
}
//-----------------------------------------------------------------------------
CMultiFrameBitmapDescription CMultiFrameBitmap::getMultiFrameDesc () const { return description; }
//-----------------------------------------------------------------------------
CPoint CMultiFrameBitmap::getFrameSize () const { return description.frameSize; }
//-----------------------------------------------------------------------------
uint16_t CMultiFrameBitmap::getNumFrames () const { return description.numFrames; }
//-----------------------------------------------------------------------------
uint16_t CMultiFrameBitmap::getNumFramesPerRow () const { return description.framesPerRow; }
//-----------------------------------------------------------------------------
CRect CMultiFrameBitmap::calcFrameRect (uint32_t frameIndex) const
{
if (getNumFrames () == 0)
return CRect ({}, getSize ());
if (frameIndex >= getNumFrames ())
frameIndex = getNumFrames () - 1;
auto rowIndex = frameIndex / getNumFramesPerRow ();
auto colIndex = frameIndex - (rowIndex * getNumFramesPerRow ());
CRect r;
r.left = getFrameSize ().x * colIndex;
r.right = r.left + getFrameSize ().x;
r.top = getFrameSize ().y * rowIndex;
r.bottom = r.top + getFrameSize ().y;
return r;
}
//-----------------------------------------------------------------------------
void CMultiFrameBitmap::drawFrame (CDrawContext* context, uint16_t frameIndex, CPoint pos)
{
auto fr = calcFrameRect (frameIndex);
auto r = CRect (pos, getFrameSize ());
draw (context, r, fr.getTopLeft ());
}
//-----------------------------------------------------------------------------
uint16_t CMultiFrameBitmap::normalizedValueToFrameIndex (float value) const
{
return normalizedToSteps<float, uint16_t> (value, getNumFrames () - 1);
}
//-----------------------------------------------------------------------------
float CMultiFrameBitmap::frameIndexToNormalizedValue (uint16_t frameIndex) const
{
return stepsToNormalized<float, uint16_t> (frameIndex, getNumFrames () - 1);
}
//-----------------------------------------------------------------------------
// 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
+443
View File
@@ -0,0 +1,443 @@
// 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 "pixelbuffer.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 BitmapVector = std::vector<PlatformBitmapPtr>;
using const_iterator = BitmapVector::const_iterator;
/** 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;
const_iterator begin () const { return bitmaps.begin (); }
const_iterator end () const { return bitmaps.end (); }
//@}
//-----------------------------------------------------------------------------
protected:
CBitmap ();
CResourceDescription resourceDesc;
BitmapVector bitmaps;
};
//-----------------------------------------------------------------------------
/** Description for a multi frame bitmap
*
* @ingroup new_in_4_12
*/
struct CMultiFrameBitmapDescription
{
/** size of one frame */
CPoint frameSize {};
/** number of total frames */
uint16_t numFrames {};
/** number of frames per row */
uint16_t framesPerRow {1};
};
//-----------------------------------------------------------------------------
/** Multi frame bitmap
*
* A bitmap describing multiple frames ordered in rows and columns
*
* The index order is columns and then rows:
*
* 1.Row: 1 -> 2 -> 3
* 2.Row: 4 -> 5 -> 6
* ...
*
* @ingroup new_in_4_12
*/
class CMultiFrameBitmap : public CBitmap
{
public:
using CBitmap::CBitmap;
CMultiFrameBitmap (const CResourceDescription& desc,
CMultiFrameBitmapDescription multiFrameDesc);
/** set the multi frame description
*
* @param desc the multi frame description
* @return true if bitmap is big enough for the description
*/
bool setMultiFrameDesc (CMultiFrameBitmapDescription desc);
/** get the mult frame description */
CMultiFrameBitmapDescription getMultiFrameDesc () const;
/** get the frame size */
CPoint getFrameSize () const;
/** get the number of frames */
uint16_t getNumFrames () const;
/** get the number of frames per row */
uint16_t getNumFramesPerRow () const;
/** calculate the rect for one frame */
CRect calcFrameRect (uint32_t frameIndex) const;
/** draw one frame at the position in the context */
void drawFrame (CDrawContext* context, uint16_t frameIndex, CPoint pos);
/** return the frame to display for a normalized value
*
* defaults to:
* normalizedToSteps<float, uint16_t> (value, getNumFrames () - 1);
*
* subclasses can adopt this to other value mappings
*
* @ingroup new_in_4_12_1
*/
virtual uint16_t normalizedValueToFrameIndex (float value) const;
/** return the normalized value from the frame index
*
* defaults to:
* stepsToNormalized<float, uint16_t> (frameIndex, getNumFrames () - 1);
*
* subclasses can adopt this to other value mappings
*
* @ingroup new_in_4_12_1
*/
virtual float frameIndexToNormalizedValue (uint16_t frameIndex) const;
private:
CMultiFrameBitmapDescription description;
};
//------------------------------------------------------------------------
/** an injection class for views that draw frames of a CMultiFrameBitmap
*
* a view/control can inherit from this class to support drawing only frames in a range of the
* multi-frame bitmap.
*
* @ingroup new_in_4_12_2
*/
template<typename T>
class MultiFrameBitmapView
{
using This = T;
public:
/** set the range of the CMultiBitmapFrame this view will use for drawing
*
* @param startIndex the first frame to draw
* @param endIndex the last frame to draw
*/
void setMultiFrameBitmapRange (int32_t startIndex, int32_t endIndex)
{
if (endIndex >= 0 && startIndex > endIndex)
std::swap (startIndex, endIndex);
frameStartIndex = startIndex;
frameEndIndex = endIndex;
static_cast<This*> (this)->invalid ();
}
/** get the range of the CMulitBitmapFrame this view will use for drawing
*
* @return a std::pair with the start and end index
*/
std::pair<int32_t, int32_t> getMultiFrameBitmapRange () const
{
return {frameStartIndex, frameEndIndex};
}
/** get the number of frames this view will use for drawing
*
* @param mfb the bitmap
* @return the number of frames
*/
uint16_t getMultiFrameBitmapRangeLength (const CMultiFrameBitmap& mfb) const
{
auto endIndex = frameEndIndex >= 0 ? frameEndIndex : mfb.getNumFrames ();
return endIndex - frameStartIndex;
}
/** get the inverse index
*
* @param mfb the bitmap
* @param index the index
* @return the inverse index
*/
uint16_t getInverseIndex (const CMultiFrameBitmap& mfb, uint16_t index) const
{
auto endIndex = frameEndIndex >= 0 ? frameEndIndex : mfb.getNumFrames () - 1;
if (index >= frameStartIndex && index <= endIndex)
{
return endIndex - (index - frameStartIndex);
}
return index;
}
/** get the frame index for a normalized value
*
* @param mfb the bitmap
* @param normValue the normalized value
* @return the index of the frame for the value
*/
uint16_t getMultiFrameBitmapIndex (const CMultiFrameBitmap& mfb, float normValue) const
{
if (frameStartIndex == 0 && frameEndIndex < 0)
return mfb.normalizedValueToFrameIndex (normValue);
auto startNorm = mfb.frameIndexToNormalizedValue (frameStartIndex);
auto endNorm = mfb.frameIndexToNormalizedValue (
frameEndIndex >= 0 ? frameEndIndex : mfb.getNumFrames () - 1);
normValue = normValue * (endNorm - startNorm) + startNorm;
return mfb.normalizedValueToFrameIndex (normValue);
}
/** get the normalized value for a frame index
*
* @param mfb the bitmap
* @param index the frame index
* @return the normalized value
*/
float getNormValueFromMultiFrameBitmapIndex (const CMultiFrameBitmap& mfb, uint16_t index) const
{
auto startNorm = mfb.frameIndexToNormalizedValue (frameStartIndex);
auto endNorm = mfb.frameIndexToNormalizedValue (
frameEndIndex >= 0 ? frameEndIndex : mfb.getNumFrames () - 1);
auto indexNorm = mfb.frameIndexToNormalizedValue (index);
return (indexNorm - startNorm) / (endNorm - startNorm);
}
private:
int32_t frameStartIndex {0};
int32_t frameEndIndex {-1};
};
//-----------------------------------------------------------------------------
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;
};
//------------------------------------------------------------------------
/** Convert between Platform Pixel Accessor pixel format and PixelBuffer format */
template<typename T1, typename T2,
typename std::enable_if<
std::is_same<PixelBuffer::Format, T2>::value ||
std::is_same<IPlatformBitmapPixelAccess::PixelFormat, T2>::value>::type* = nullptr>
inline T1 convert (T2 format)
{
using PlPixelFormat = IPlatformBitmapPixelAccess::PixelFormat;
using Format = PixelBuffer::Format;
static_assert (std::is_same<Format, T1>::value || std::is_same<PlPixelFormat, T1>::value,
"Unexpected Format");
static_assert (!std::is_same<T1, T2>::value, "Unexpected Format");
static_assert (static_cast<int32_t> (Format::ARGB) == PlPixelFormat::kARGB, "Format Mismatch");
static_assert (static_cast<int32_t> (Format::ABGR) == PlPixelFormat::kABGR, "Format Mismatch");
static_assert (static_cast<int32_t> (Format::RGBA) == PlPixelFormat::kRGBA, "Format Mismatch");
static_assert (static_cast<int32_t> (Format::BGRA) == PlPixelFormat::kBGRA, "Format Mismatch");
return static_cast<T1> (format);
}
//------------------------------------------------------------------------
// 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
File diff suppressed because it is too large Load Diff
+236
View File
@@ -0,0 +1,236 @@
// 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
- Property::kAlphaChannelOnly
*/
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::kInteger] */
static const IdStringPtr kAlphaChannelOnly = "AlphaChannelOnly";
} // 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
+95
View File
@@ -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
+104
View File
@@ -0,0 +1,104 @@
// 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 "cclipboard.h"
#include "platform/platformfactory.h"
#include <string_view>
namespace VSTGUI {
namespace CClipboardDetail {
//-----------------------------------------------------------------------------
template<bool AsFile>
struct StringDataPackage : IDataPackage
{
StringDataPackage (std::string_view str) : str (str) {}
uint32_t getCount () const final { return 1; }
uint32_t getDataSize (uint32_t index) const final
{
return static_cast<uint32_t> (str.size ());
}
Type getDataType (uint32_t index) const final { return AsFile ? Type::kFilePath : Type::kText; }
uint32_t getData (uint32_t index, const void*& buffer, Type& type) const final
{
buffer = str.data ();
type = getDataType (index);
return getDataSize (index);
}
std::string str;
};
//-----------------------------------------------------------------------------
template<bool AsFile>
Optional<UTF8String> getString (IDataPackage* cb)
{
for (auto i = 0u, count = cb->getCount (); i < count; i++)
{
if (cb->getDataType (i) == (AsFile ? IDataPackage::Type::kFilePath
: IDataPackage::Type::kText))
{
IDataPackage::Type type;
const void* data = nullptr;
auto size = cb->getData (i, data, type);
if (size > 0)
{
return {UTF8String (std::string (static_cast<const char*> (data), size))};
}
}
}
return {};
}
} // CClipboardDetail
//-----------------------------------------------------------------------------
SharedPointer<IDataPackage> CClipboard::get ()
{
return getPlatformFactory ().getClipboard ();
}
//-----------------------------------------------------------------------------
bool CClipboard::set (const SharedPointer<IDataPackage>& data)
{
return getPlatformFactory ().setClipboard (data);
}
//-----------------------------------------------------------------------------
bool CClipboard::setString (UTF8StringPtr str)
{
return set (makeOwned<CClipboardDetail::StringDataPackage<false>> (
std::string_view (str, strlen (str))));
}
//-----------------------------------------------------------------------------
bool CClipboard::setFilePath (UTF8StringPtr str)
{
return set (makeOwned<CClipboardDetail::StringDataPackage<true>> (
std::string_view (str, strlen (str))));
}
//-----------------------------------------------------------------------------
Optional<UTF8String> CClipboard::getString ()
{
if (auto cb = get ())
{
return CClipboardDetail::getString<false> (cb);
}
return {};
}
//-----------------------------------------------------------------------------
Optional<UTF8String> CClipboard::getFilePath ()
{
if (auto cb = get ())
{
return CClipboardDetail::getString<true> (cb);
}
return {};
}
} // VSTGUI
+32
View File
@@ -0,0 +1,32 @@
// 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 "cstring.h"
#include "idatapackage.h"
#include "optional.h"
namespace VSTGUI {
//-----------------------------------------------------------------------------
struct CClipboard
{
/** get the global clipboard data */
static SharedPointer<IDataPackage> get ();
/** set the global clipboard data */
static bool set (const SharedPointer<IDataPackage>& data);
/** get the string from the global clipboard if it exists */
static Optional<UTF8String> getString ();
/** get the file path from the global clipboard if it exists */
static Optional<UTF8String> getFilePath ();
/** set the string of the global clipboard */
static bool setString (UTF8StringPtr str);
/** set the file path of the global clipboard */
static bool setFilePath (UTF8StringPtr str);
};
} // VSTGUI
+487
View File
@@ -0,0 +1,487 @@
// 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 "algorithm.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 = normRed<double> ();
double g = normGreen<double> ();
double b = normBlue<double> ();
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.);
setNormRed (clampNorm (r + m));
setNormGreen (clampNorm (g + m));
setNormBlue (clampNorm (b + m));
}
//-----------------------------------------------------------------------------
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 = normRed<double> () / value;
double g = normGreen<double> () / value;
double b = normBlue<double> () / 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;
}
}
setNormRed (clampNorm (r));
setNormGreen (clampNorm (g));
setNormBlue (clampNorm (b));
}
//------------------------------------------------------------------------
bool CColor::fromString (std::string_view str)
{
if (!isColorRepresentation (str))
return false;
std::string rv (str.data () + 1, 2);
std::string gv (str.data () + 3, 2);
std::string bv (str.data () + 5, 2);
std::string av (str.data () + 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;
}
//------------------------------------------------------------------------
bool CColor::isColorRepresentation (std::string_view str)
{
return (str.size () == 9 && str.data ()[0] == '#');
}
#if VSTGUI_ENABLE_DEPRECATED_METHODS
//-----------------------------------------------------------------------------
bool CColor::isColorRepresentation (UTF8StringPtr str)
{
if (str && isColorRepresentation ({str, strlen (str)}))
return true;
return false;
}
//-----------------------------------------------------------------------------
bool CColor::fromString (UTF8StringPtr str)
{
if (!str)
return false;
return fromString ({str, strlen (str)});
}
#endif // VSTGUI_ENABLE_DEPRECATED_METHODS
//-----------------------------------------------------------------------------
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 ());
}
using namespace std::literals;
//-----------------------------------------------------------------------------
static constexpr std::array<CSSNamedColor, 148> namedColors = {
{{"transparent"sv, {0, 0, 0, 0}},
{"aliceblue"sv, {240, 248, 255, 255}},
{"antiquewhite"sv, {250, 235, 215, 255}},
{"aqua"sv, {0, 255, 255, 255}},
{"aquamarine"sv, {127, 255, 212, 255}},
{"azure"sv, {240, 255, 255, 255}},
{"beige"sv, {245, 245, 220, 255}},
{"bisque"sv, {255, 228, 196, 255}},
{"black"sv, {0, 0, 0, 255}},
{"blanchedalmond"sv, {255, 235, 205, 255}},
{"blue"sv, {0, 0, 255, 255}},
{"blueviolet"sv, {138, 43, 226, 255}},
{"brown"sv, {165, 42, 42, 255}},
{"burlywood"sv, {222, 184, 135, 255}},
{"cadetblue"sv, {95, 158, 160, 255}},
{"chartreuse"sv, {127, 255, 0, 255}},
{"chocolate"sv, {210, 105, 30, 255}},
{"coral"sv, {255, 127, 80, 255}},
{"cornflowerblue"sv, {100, 149, 237, 255}},
{"cornsilk"sv, {255, 248, 220, 255}},
{"crimson"sv, {220, 20, 60, 255}},
{"cyan"sv, {0, 255, 255, 255}},
{"darkblue"sv, {0, 0, 139, 255}},
{"darkcyan"sv, {0, 139, 139, 255}},
{"darkgoldenrod"sv, {184, 134, 11, 255}},
{"darkgray"sv, {169, 169, 169, 255}},
{"darkgreen"sv, {0, 100, 0, 255}},
{"darkgrey"sv, {169, 169, 169, 255}},
{"darkkhaki"sv, {189, 183, 107, 255}},
{"darkmagenta"sv, {139, 0, 139, 255}},
{"darkolivegreen"sv, {85, 107, 47, 255}},
{"darkorange"sv, {255, 140, 0, 255}},
{"darkorchid"sv, {153, 50, 204, 255}},
{"darkred"sv, {139, 0, 0, 255}},
{"darksalmon"sv, {233, 150, 122, 255}},
{"darkseagreen"sv, {143, 188, 143, 255}},
{"darkslateblue"sv, {72, 61, 139, 255}},
{"darkslategray"sv, {47, 79, 79, 255}},
{"darkslategrey"sv, {47, 79, 79, 255}},
{"darkturquoise"sv, {0, 206, 209, 255}},
{"darkviolet"sv, {148, 0, 211, 255}},
{"deeppink"sv, {255, 20, 147, 255}},
{"deepskyblue"sv, {0, 191, 255, 255}},
{"dimgray"sv, {105, 105, 105, 255}},
{"dimgrey"sv, {105, 105, 105, 255}},
{"dodgerblue"sv, {30, 144, 255, 255}},
{"firebrick"sv, {178, 34, 34, 255}},
{"floralwhite"sv, {255, 250, 240, 255}},
{"forestgreen"sv, {34, 139, 34, 255}},
{"fuchsia"sv, {255, 0, 255, 255}},
{"gainsboro"sv, {220, 220, 220, 255}},
{"ghostwhite"sv, {248, 248, 255, 255}},
{"gold"sv, {255, 215, 0, 255}},
{"goldenrod"sv, {218, 165, 32, 255}},
{"gray"sv, {128, 128, 128, 255}},
{"green"sv, {0, 128, 0, 255}},
{"greenyellow"sv, {173, 255, 47, 255}},
{"grey"sv, {128, 128, 128, 255}},
{"honeydew"sv, {240, 255, 240, 255}},
{"hotpink"sv, {255, 105, 180, 255}},
{"indianred"sv, {205, 92, 92, 255}},
{"indigo"sv, {75, 0, 130, 255}},
{"ivory"sv, {255, 255, 240, 255}},
{"khaki"sv, {240, 230, 140, 255}},
{"lavender"sv, {230, 230, 250, 255}},
{"lavenderblush"sv, {255, 240, 245, 255}},
{"lawngreen"sv, {124, 252, 0, 255}},
{"lemonchiffon"sv, {255, 250, 205, 255}},
{"lightblue"sv, {173, 216, 230, 255}},
{"lightcoral"sv, {240, 128, 128, 255}},
{"lightcyan"sv, {224, 255, 255, 255}},
{"lightgoldenrodyellow"sv, {250, 250, 210, 255}},
{"lightgray"sv, {211, 211, 211, 255}},
{"lightgreen"sv, {144, 238, 144, 255}},
{"lightgrey"sv, {211, 211, 211, 255}},
{"lightpink"sv, {255, 182, 193, 255}},
{"lightsalmon"sv, {255, 160, 122, 255}},
{"lightseagreen"sv, {32, 178, 170, 255}},
{"lightskyblue"sv, {135, 206, 250, 255}},
{"lightslategray"sv, {119, 136, 153, 255}},
{"lightslategrey"sv, {119, 136, 153, 255}},
{"lightsteelblue"sv, {176, 196, 222, 255}},
{"lightyellow"sv, {255, 255, 224, 255}},
{"lime"sv, {0, 255, 0, 255}},
{"limegreen"sv, {50, 205, 50, 255}},
{"linen"sv, {250, 240, 230, 255}},
{"magenta"sv, {255, 0, 255, 255}},
{"maroon"sv, {128, 0, 0, 255}},
{"mediumaquamarine"sv, {102, 205, 170, 255}},
{"mediumblue"sv, {0, 0, 205, 255}},
{"mediumorchid"sv, {186, 85, 211, 255}},
{"mediumpurple"sv, {147, 112, 219, 255}},
{"mediumseagreen"sv, {60, 179, 113, 255}},
{"mediumslateblue"sv, {123, 104, 238, 255}},
{"mediumspringgreen"sv, {0, 250, 154, 255}},
{"mediumturquoise"sv, {72, 209, 204, 255}},
{"mediumvioletred"sv, {199, 21, 133, 255}},
{"midnightblue"sv, {25, 25, 112, 255}},
{"mintcream"sv, {245, 255, 250, 255}},
{"mistyrose"sv, {255, 228, 225, 255}},
{"moccasin"sv, {255, 228, 181, 255}},
{"navajowhite"sv, {255, 222, 173, 255}},
{"navy"sv, {0, 0, 128, 255}},
{"oldlace"sv, {253, 245, 230, 255}},
{"olive"sv, {128, 128, 0, 255}},
{"olivedrab"sv, {107, 142, 35, 255}},
{"orange"sv, {255, 165, 0, 255}},
{"orangered"sv, {255, 69, 0, 255}},
{"orchid"sv, {218, 112, 214, 255}},
{"palegoldenrod"sv, {238, 232, 170, 255}},
{"palegreen"sv, {152, 251, 152, 255}},
{"paleturquoise"sv, {175, 238, 238, 255}},
{"palevioletred"sv, {219, 112, 147, 255}},
{"papayawhip"sv, {255, 239, 213, 255}},
{"peachpuff"sv, {255, 218, 185, 255}},
{"peru"sv, {205, 133, 63, 255}},
{"pink"sv, {255, 192, 203, 255}},
{"plum"sv, {221, 160, 221, 255}},
{"powderblue"sv, {176, 224, 230, 255}},
{"purple"sv, {128, 0, 128, 255}},
{"red"sv, {255, 0, 0, 255}},
{"rosybrown"sv, {188, 143, 143, 255}},
{"royalblue"sv, {65, 105, 225, 255}},
{"saddlebrown"sv, {139, 69, 19, 255}},
{"salmon"sv, {250, 128, 114, 255}},
{"sandybrown"sv, {244, 164, 96, 255}},
{"seagreen"sv, {46, 139, 87, 255}},
{"seashell"sv, {255, 245, 238, 255}},
{"sienna"sv, {160, 82, 45, 255}},
{"silver"sv, {192, 192, 192, 255}},
{"skyblue"sv, {135, 206, 235, 255}},
{"slateblue"sv, {106, 90, 205, 255}},
{"slategray"sv, {112, 128, 144, 255}},
{"slategrey"sv, {112, 128, 144, 255}},
{"snow"sv, {255, 250, 250, 255}},
{"springgreen"sv, {0, 255, 127, 255}},
{"steelblue"sv, {70, 130, 180, 255}},
{"tan"sv, {210, 180, 140, 255}},
{"teal"sv, {0, 128, 128, 255}},
{"thistle"sv, {216, 191, 216, 255}},
{"tomato"sv, {255, 99, 71, 255}},
{"turquoise"sv, {64, 224, 208, 255}},
{"violet"sv, {238, 130, 238, 255}},
{"wheat"sv, {245, 222, 179, 255}},
{"white"sv, {255, 255, 255, 255}},
{"whitesmoke"sv, {245, 245, 245, 255}},
{"yellow"sv, {255, 255, 0, 255}},
{"yellowgreen"sv, {154, 205, 50, 255}}}};
//-----------------------------------------------------------------------------
const CSSNamedColorArray& getCSSNamedColors () { return namedColors; }
} // VSTGUI
+246
View File
@@ -0,0 +1,246 @@
// 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"
#include <cmath>
#include <array>
#include <string_view>
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 */
inline constexpr uint8_t getLuma () const;
/** get the lightness of the color */
uint8_t getLightness () const;
/** get the normalized red value */
template<typename T>
constexpr T normRed () const;
/** get the normalized green value */
template<typename T>
constexpr T normGreen () const;
/** get the normalized blue value */
template<typename T>
constexpr T normBlue () const;
/** get the normalized alpha value */
template<typename T>
constexpr T normAlpha () const;
/** set the red value normalized */
template<typename T>
void setNormRed (T v);
/** set the green value normalized */
template<typename T>
void setNormGreen (T v);
/** set the blue value normalized */
template<typename T>
void setNormBlue (T v);
/** set the alpha value normalized */
template<typename T>
void setNormAlpha (T v);
//@}
UTF8String toString () const;
bool fromString (std::string_view str);
static bool isColorRepresentation (std::string_view str);
VSTGUI_DEPRECATED_MSG (bool fromString (UTF8StringPtr str);
, "use fromString with a std::string_view")
VSTGUI_DEPRECATED_MSG (static bool isColorRepresentation (UTF8StringPtr str);
, "use isColorRepresentation with a std::string_view")
/** 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);
//-----------------------------------------------------------------------------
// CSS Colors
struct CSSNamedColor
{
const std::string_view name;
const CColor color;
};
using CSSNamedColorArray = std::array<CSSNamedColor, 148>;
/** get the CSS color array
*
* @ingroup new_in_4_15
*/
const CSSNamedColorArray& getCSSNamedColors ();
//-----------------------------------------------------------------------------
inline constexpr uint8_t CColor::getLuma () const
{
return static_cast<uint8_t> (static_cast<float> (red) * 0.3f +
static_cast<float> (green) * 0.59f +
static_cast<float> (blue) * 0.11f);
}
//-----------------------------------------------------------------------------
template <typename T>
constexpr T CColor::normRed () const
{
return static_cast<T> (red) / static_cast<T> (255.);
}
//-----------------------------------------------------------------------------
template <typename T>
constexpr T CColor::normGreen () const
{
return static_cast<T> (green) / static_cast<T> (255.);
}
//-----------------------------------------------------------------------------
template <typename T>
constexpr T CColor::normBlue () const
{
return static_cast<T> (blue) / static_cast<T> (255.);
}
//-----------------------------------------------------------------------------
template <typename T>
constexpr T CColor::normAlpha () const
{
return static_cast<T> (alpha) / static_cast<T> (255.);
}
//-----------------------------------------------------------------------------
template <typename T>
void CColor::setNormRed (T v)
{
vstgui_assert (v >= 0. && v <= 1.);
red = static_cast<uint8_t> (std::round (v * 255.));
}
//-----------------------------------------------------------------------------
template <typename T>
void CColor::setNormGreen (T v)
{
vstgui_assert (v >= 0. && v <= 1.);
green = static_cast<uint8_t> (std::round (v * 255.));
}
//-----------------------------------------------------------------------------
template <typename T>
void CColor::setNormBlue (T v)
{
vstgui_assert (v >= 0. && v <= 1.);
blue = static_cast<uint8_t> (std::round (v * 255.));
}
//-----------------------------------------------------------------------------
template <typename T>
void CColor::setNormAlpha (T v)
{
vstgui_assert (v >= 0. && v <= 1.);
alpha = static_cast<uint8_t> (std::round (v * 255.));
}
} // VSTGUI
File diff suppressed because it is too large Load Diff
+128
View File
@@ -0,0 +1,128 @@
// 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;
void onKeyboardEvent (KeyboardEvent& event) 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 validateSelection ();
IDataBrowserDelegate* db;
CDataBrowserView* dbView;
CDataBrowserHeader* dbHeader;
CViewContainer* dbHeaderContainer;
Selection selection;
};
//-----------------------------------------------------------------------------
} // VSTGUI
@@ -0,0 +1,779 @@
// 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 "cgradient.h"
#include "cbitmap.h"
#include "cstring.h"
#include "platform/iplatformgraphicsdevice.h"
#include "platform/iplatformfont.h"
#include "platform/iplatformgraphicspath.h"
#include "platform/iplatformgradient.h"
#include "platform/platformfactory.h"
#include <cassert>
#include <stack>
namespace VSTGUI {
//-----------------------------------------------------------------------------
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 ();
}
//-----------------------------------------------------------------------------
struct CDrawContext::Impl
{
//-----------------------------------------------------------------------------
struct State
{
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};
State () = default;
State (const State& state);
State& operator= (const State& state) = default;
State (State&& state) noexcept;
State& operator= (State&& state) noexcept;
};
UTF8String* drawStringHelper {nullptr};
CRect surfaceRect;
double scaleFactor {1.};
State currentState;
std::stack<State> globalStatesStack;
std::stack<CGraphicsTransform> transformStack;
PlatformGraphicsDeviceContextPtr device;
};
//-----------------------------------------------------------------------------
CDrawContext::Impl::State::State (const State& state) { *this = state; }
//-----------------------------------------------------------------------------
CDrawContext::Impl::State::State (State&& state) noexcept { *this = std::move (state); }
//-----------------------------------------------------------------------------
CDrawContext::Impl::State&
CDrawContext::Impl::State::operator= (CDrawContext::Impl::State&& 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::CDrawContext (const CRect& surfaceRect)
{
impl = std::make_unique<Impl> ();
impl->surfaceRect = surfaceRect;
impl->transformStack.push (CGraphicsTransform ());
}
//------------------------------------------------------------------------
CDrawContext::CDrawContext (const PlatformGraphicsDeviceContextPtr device, const CRect& surfaceRect,
double scaleFactor)
: CDrawContext (surfaceRect)
{
impl->device = device;
impl->scaleFactor = scaleFactor;
setClipRect (surfaceRect);
}
//-----------------------------------------------------------------------------
CDrawContext::~CDrawContext () noexcept
{
#if DEBUG
if (!impl->globalStatesStack.empty ())
DebugPrint ("Global state stack not empty. Save and restore global state must be called in sequence !\n");
#endif
if (impl->drawStringHelper)
delete impl->drawStringHelper;
}
//------------------------------------------------------------------------
const PlatformGraphicsDeviceContextPtr& CDrawContext::getPlatformDeviceContext () const
{
return impl->device;
}
//-----------------------------------------------------------------------------
const CRect& CDrawContext::getSurfaceRect () const { return impl->surfaceRect; }
//------------------------------------------------------------------------
double CDrawContext::getScaleFactor () const { return impl->scaleFactor; }
//-----------------------------------------------------------------------------
void CDrawContext::init ()
{
// set the default values
setFrameColor (kWhiteCColor);
setLineStyle (kLineSolid);
setLineWidth (1);
setFillColor (kBlackCColor);
setFontColor (kWhiteCColor);
setFont (kSystemFont);
setDrawMode (kAliasing);
setClipRect (impl->surfaceRect);
}
//-----------------------------------------------------------------------------
void CDrawContext::saveGlobalState ()
{
impl->globalStatesStack.push (impl->currentState);
if (impl->device)
impl->device->saveGlobalState ();
}
//-----------------------------------------------------------------------------
void CDrawContext::restoreGlobalState ()
{
if (impl->device)
impl->device->restoreGlobalState ();
if (!impl->globalStatesStack.empty ())
{
impl->currentState = std::move (impl->globalStatesStack.top ());
impl->globalStatesStack.pop ();
}
else
{
#if DEBUG
DebugPrint ("No saved global state in draw context !!!\n");
#endif
}
}
//-----------------------------------------------------------------------------
void CDrawContext::setBitmapInterpolationQuality (BitmapInterpolationQuality quality)
{
impl->currentState.bitmapQuality = quality;
}
//-----------------------------------------------------------------------------
BitmapInterpolationQuality CDrawContext::getBitmapInterpolationQuality () const
{
return impl->currentState.bitmapQuality;
}
//-----------------------------------------------------------------------------
void CDrawContext::setLineStyle (const CLineStyle& style)
{
if (impl->device)
impl->device->setLineStyle (style);
impl->currentState.lineStyle = style;
}
//-----------------------------------------------------------------------------
const CLineStyle& CDrawContext::getLineStyle () const { return impl->currentState.lineStyle; }
//-----------------------------------------------------------------------------
void CDrawContext::setLineWidth (CCoord width)
{
if (impl->device)
impl->device->setLineWidth (width);
impl->currentState.frameWidth = width;
}
//-----------------------------------------------------------------------------
CCoord CDrawContext::getLineWidth () const { return impl->currentState.frameWidth; }
//-----------------------------------------------------------------------------
void CDrawContext::setDrawMode (CDrawMode mode)
{
if (impl->device)
impl->device->setDrawMode (mode);
impl->currentState.drawMode = mode;
}
//-----------------------------------------------------------------------------
CDrawMode CDrawContext::getDrawMode () const { return impl->currentState.drawMode; }
//-----------------------------------------------------------------------------
CRect& CDrawContext::getClipRect (CRect &clip) const
{
clip = impl->currentState.clipRect;
getCurrentTransform ().inverse ().transform (clip);
clip.normalize ();
return clip;
}
//-----------------------------------------------------------------------------
const CRect& CDrawContext::getAbsoluteClipRect () const { return impl->currentState.clipRect; }
//-----------------------------------------------------------------------------
void CDrawContext::setClipRect (const CRect &clip)
{
impl->currentState.clipRect = clip;
getCurrentTransform ().transform (impl->currentState.clipRect);
impl->currentState.clipRect.normalize ();
if (impl->device)
impl->device->setClipRect (impl->currentState.clipRect);
}
//-----------------------------------------------------------------------------
void CDrawContext::resetClipRect ()
{
if (impl->device)
impl->device->setClipRect (getSurfaceRect ());
impl->currentState.clipRect = getSurfaceRect ();
}
//-----------------------------------------------------------------------------
void CDrawContext::setFillColor (const CColor& color)
{
if (impl->device)
impl->device->setFillColor (color);
impl->currentState.fillColor = color;
}
//-----------------------------------------------------------------------------
CColor CDrawContext::getFillColor () const { return impl->currentState.fillColor; }
//-----------------------------------------------------------------------------
void CDrawContext::setFrameColor (const CColor& color)
{
if (impl->device)
impl->device->setFrameColor (color);
impl->currentState.frameColor = color;
}
//-----------------------------------------------------------------------------
CColor CDrawContext::getFrameColor () const { return impl->currentState.frameColor; }
//-----------------------------------------------------------------------------
void CDrawContext::setFontColor (const CColor& color) { impl->currentState.fontColor = color; }
//-----------------------------------------------------------------------------
CColor CDrawContext::getFontColor () const { return impl->currentState.fontColor; }
//-----------------------------------------------------------------------------
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))
{
impl->currentState.font = makeOwned<CFontDesc> (*newFont);
if (size > 0)
impl->currentState.font->setSize (size);
if (style != -1)
impl->currentState.font->setStyle (style);
}
else
{
impl->currentState.font = newFont;
}
}
//-----------------------------------------------------------------------------
const CFontRef CDrawContext::getFont () const { return impl->currentState.font; }
//-----------------------------------------------------------------------------
void CDrawContext::setGlobalAlpha (float newAlpha)
{
if (impl->device)
impl->device->setGlobalAlpha (newAlpha);
impl->currentState.globalAlpha = newAlpha;
}
//-----------------------------------------------------------------------------
float CDrawContext::getGlobalAlpha () const { return impl->currentState.globalAlpha; }
//-----------------------------------------------------------------------------
const UTF8String& CDrawContext::getDrawString (UTF8StringPtr string)
{
if (impl->drawStringHelper == nullptr)
impl->drawStringHelper = new UTF8String (string);
else
impl->drawStringHelper->assign (string);
return *impl->drawStringHelper;
}
//-----------------------------------------------------------------------------
void CDrawContext::clearDrawString ()
{
if (impl->drawStringHelper)
impl->drawStringHelper->clear ();
}
//------------------------------------------------------------------------
CCoord CDrawContext::getStringWidth (IPlatformString* string)
{
CCoord result = -1;
if (impl->currentState.font == nullptr || string == nullptr)
return result;
if (auto painter = impl->currentState.font->getFontPainter ())
result = painter->getStringWidth (impl->device, string, true);
return result;
}
//------------------------------------------------------------------------
void CDrawContext::drawString (IPlatformString* string, const CRect& _rect, const CHoriTxtAlign hAlign, bool antialias)
{
if (!string || impl->currentState.font == nullptr)
return;
auto painter = impl->currentState.font->getFontPainter ();
if (painter == nullptr)
return;
CRect rect (_rect);
double capHeight = -1;
auto platformFont = impl->currentState.font->getPlatformFont ();
if (platformFont)
capHeight = platformFont->getCapHeight ();
if (capHeight > 0.)
rect.bottom -= (rect.getHeight () / 2. - capHeight / 2.);
else
rect.bottom -= (rect.getHeight () / 2. - impl->currentState.font->getSize () / 2.) + 1.;
if (hAlign != kLeftText)
{
CCoord stringWidth = painter->getStringWidth (impl->device, string, antialias);
if (hAlign == kRightText)
rect.left = rect.right - stringWidth;
else
rect.left = rect.left + (rect.getWidth () / 2.) - (stringWidth / 2.);
}
painter->drawString (impl->device, string, CPoint (rect.left, rect.bottom),
impl->currentState.fontColor, antialias);
}
//------------------------------------------------------------------------
void CDrawContext::drawString (IPlatformString* string, const CPoint& point, bool antialias)
{
if (string == nullptr || impl->currentState.font == nullptr)
return;
if (auto painter = impl->currentState.font->getFontPainter ())
painter->drawString (impl->device, string, point, impl->currentState.fontColor, 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;
if (srcRect.getWidth () == dstRect.getWidth () && srcRect.getHeight () == dstRect.getHeight ())
{
drawBitmap (bitmap, dstRect, srcRect.getTopLeft (), alpha);
return;
}
if (impl->device)
{
if (auto deviceBitmapExt = impl->device->asBitmapExt ())
{
double transformedScaleFactor = getScaleFactor ();
CGraphicsTransform t = getCurrentTransform ();
if (t.m11 == t.m22 && t.m12 == 0 && t.m21 == 0)
transformedScaleFactor *= t.m11;
if (auto pb = bitmap->getBestPlatformBitmapForScaleFactor (transformedScaleFactor))
{
if (deviceBitmapExt->fillRectWithBitmap (*pb, srcRect, dstRect, alpha,
getBitmapInterpolationQuality ()))
{
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)
{
if (impl->device)
{
if (auto deviceBitmapExt = impl->device->asBitmapExt ())
{
double transformedScaleFactor = getScaleFactor ();
CGraphicsTransform t = getCurrentTransform ();
if (t.m11 == t.m22 && t.m12 == 0 && t.m21 == 0)
transformedScaleFactor *= t.m11;
if (auto pb = bitmap->getBestPlatformBitmapForScaleFactor (transformedScaleFactor))
{
if (deviceBitmapExt->drawBitmapNinePartTiled (*pb, dest, desc, alpha,
getBitmapInterpolationQuality ()))
{
return;
}
}
}
}
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)
{
if (auto path = createGraphicsPath ())
{
path->addRoundRect (size, radius);
return path;
}
return {};
}
//-----------------------------------------------------------------------------
void CDrawContext::pushTransform (const CGraphicsTransform& transformation)
{
vstgui_assert (!impl->transformStack.empty ());
const CGraphicsTransform& currentTransform = impl->transformStack.top ();
CGraphicsTransform newTransform = currentTransform * transformation;
impl->transformStack.push (newTransform);
if (impl->device)
impl->device->setTransformMatrix (newTransform);
}
//-----------------------------------------------------------------------------
void CDrawContext::popTransform ()
{
vstgui_assert (impl->transformStack.size () > 1);
impl->transformStack.pop ();
if (impl->device)
impl->device->setTransformMatrix (impl->transformStack.top ());
}
//-----------------------------------------------------------------------------
const CGraphicsTransform& CDrawContext::getCurrentTransform () const
{
return impl->transformStack.top ();
}
//------------------------------------------------------------------------
CCoord CDrawContext::getHairlineSize () const
{
return 1. / (getScaleFactor () * getCurrentTransform ().m11);
}
//------------------------------------------------------------------------
static PlatformGraphicsDrawStyle convert (CDrawStyle s)
{
switch (s)
{
case CDrawStyle::kDrawFilled:
return PlatformGraphicsDrawStyle::Filled;
case CDrawStyle::kDrawStroked:
return PlatformGraphicsDrawStyle::Stroked;
case CDrawStyle::kDrawFilledAndStroked:
return PlatformGraphicsDrawStyle::FilledAndStroked;
default:
assert (false);
}
return {};
}
//------------------------------------------------------------------------
void CDrawContext::drawLine (const LinePair& line)
{
if (impl->device)
impl->device->drawLine (line);
}
//------------------------------------------------------------------------
void CDrawContext::drawLines (const LineList& lines)
{
if (impl->device)
impl->device->drawLines (lines);
}
//------------------------------------------------------------------------
void CDrawContext::drawPolygon (const PointList& polygonPointList, const CDrawStyle drawStyle)
{
if (impl->device)
impl->device->drawPolygon (polygonPointList, convert (drawStyle));
}
//------------------------------------------------------------------------
void CDrawContext::drawRect (const CRect& rect, const CDrawStyle drawStyle)
{
if (impl->device)
impl->device->drawRect (rect, convert (drawStyle));
}
//------------------------------------------------------------------------
void CDrawContext::drawArc (const CRect& rect, const float startAngle1, const float endAngle2,
const CDrawStyle drawStyle)
{
if (impl->device)
impl->device->drawArc (rect, startAngle1, endAngle2, convert (drawStyle));
}
//------------------------------------------------------------------------
void CDrawContext::drawEllipse (const CRect& rect, const CDrawStyle drawStyle)
{
if (impl->device)
impl->device->drawEllipse (rect, convert (drawStyle));
}
//------------------------------------------------------------------------
void CDrawContext::drawPoint (const CPoint& point, const CColor& color)
{
if (impl->device && impl->device->drawPoint (point, color))
return;
// if the platform does not support drawing points, emulate it somehow
saveGlobalState ();
CRect r (point.x, point.y, point.x, point.y);
r.inset (-0.5, -0.5);
setDrawMode (kAliasing);
setFillColor (color);
drawRect (r, kDrawFilled);
restoreGlobalState ();
}
//------------------------------------------------------------------------
void CDrawContext::drawBitmap (CBitmap* bitmap, const CRect& dest, const CPoint& offset,
float alpha)
{
if (impl->device)
{
double transformedScaleFactor = getScaleFactor ();
CGraphicsTransform t = getCurrentTransform ();
if (t.m11 == t.m22 && t.m12 == 0 && t.m21 == 0)
transformedScaleFactor *= t.m11;
if (auto pb = bitmap->getBestPlatformBitmapForScaleFactor (transformedScaleFactor))
impl->device->drawBitmap (*pb, dest, offset, alpha, getBitmapInterpolationQuality ());
}
}
//------------------------------------------------------------------------
void CDrawContext::clearRect (const CRect& rect)
{
if (impl->device)
impl->device->clearRect (rect);
}
//------------------------------------------------------------------------
static PlatformGraphicsPathDrawMode convert (CDrawContext::PathDrawMode mode)
{
switch (mode)
{
case CDrawContext::PathDrawMode::kPathFilled:
return PlatformGraphicsPathDrawMode::Filled;
case CDrawContext::PathDrawMode::kPathStroked:
return PlatformGraphicsPathDrawMode::Stroked;
case CDrawContext::PathDrawMode::kPathFilledEvenOdd:
return PlatformGraphicsPathDrawMode::FilledEvenOdd;
default:
assert (false);
}
return {};
}
//------------------------------------------------------------------------
void CDrawContext::drawGraphicsPath (CGraphicsPath* path, PathDrawMode mode,
CGraphicsTransform* transformation)
{
if (impl->device)
{
if (auto& pp = path->getPlatformPath (mode == kPathFilledEvenOdd
? PlatformGraphicsPathFillMode::Alternate
: PlatformGraphicsPathFillMode::Winding))
impl->device->drawGraphicsPath (*pp.get (), convert (mode), transformation);
}
}
//------------------------------------------------------------------------
void CDrawContext::fillLinearGradient (CGraphicsPath* path, const CGradient& gradient,
const CPoint& startPoint, const CPoint& endPoint,
bool evenOdd, CGraphicsTransform* transformation)
{
if (impl->device)
{
if (auto& platformGradient = gradient.getPlatformGradient ())
{
if (auto& pp = path->getPlatformPath (evenOdd ? PlatformGraphicsPathFillMode::Alternate
: PlatformGraphicsPathFillMode::Winding))
{
impl->device->fillLinearGradient (*pp.get (), *platformGradient, startPoint,
endPoint, evenOdd, transformation);
}
}
}
}
//------------------------------------------------------------------------
void CDrawContext::fillRadialGradient (CGraphicsPath* path, const CGradient& gradient,
const CPoint& center, CCoord radius,
const CPoint& originOffset, bool evenOdd,
CGraphicsTransform* transformation)
{
if (impl->device)
{
if (auto& platformGradient = gradient.getPlatformGradient ())
{
if (auto& pp = path->getPlatformPath (evenOdd ? PlatformGraphicsPathFillMode::Alternate
: PlatformGraphicsPathFillMode::Winding))
{
impl->device->fillRadialGradient (*pp.get (), *platformGradient, center, radius,
originOffset, evenOdd, transformation);
}
}
}
}
//------------------------------------------------------------------------
bool CDrawContext::drawLinearGradientLine (const DrawLinearGradientLineCallback& cb)
{
if (auto ext =
std::dynamic_pointer_cast<IPlatformGraphicsDeviceContextGradientExt> (impl->device))
{
struct Tmp : IDrawLinearGradientLine
{
std::shared_ptr<IPlatformGraphicsDeviceContextGradientExt> obj;
bool draw (const PointList& line, const CGradient& gradient, CCoord lineWidth,
CLineStyle::LineCap cap, CLineStyle::LineJoin join) const override
{
const auto& platformGradient = gradient.getPlatformGradient ();
if (!platformGradient)
return false;
return obj->drawLinearGradientLine (line, *gradient.getPlatformGradient ().get (),
lineWidth, static_cast<LineCap> (cap),
static_cast<LineJoin> (join));
}
};
Tmp t;
t.obj = ext;
cb (t);
return true;
}
return false;
}
//------------------------------------------------------------------------
CGraphicsPath* CDrawContext::createGraphicsPath ()
{
if (impl->device)
return new CGraphicsPath (impl->device->getGraphicsPathFactory (), nullptr);
return nullptr;
}
//------------------------------------------------------------------------
CGraphicsPath* CDrawContext::createTextPath (const CFontRef font, UTF8StringPtr text)
{
if (impl->device)
{
auto platformFont = font->getPlatformFont ();
auto pathFactory = impl->device->getGraphicsPathFactory ();
if (platformFont && pathFactory)
{
if (auto textPath = pathFactory->createTextPath (platformFont, text))
return new CGraphicsPath (pathFactory, std::move (textPath));
}
}
return nullptr;
}
//------------------------------------------------------------------------
void CDrawContext::beginDraw ()
{
if (impl->device)
impl->device->beginDraw ();
}
//------------------------------------------------------------------------
void CDrawContext::endDraw ()
{
if (impl->device)
impl->device->endDraw ();
}
} // VSTGUI
+311
View File
@@ -0,0 +1,311 @@
// 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 <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 = VSTGUI::LinePair;
using LineList = VSTGUI::LineList;
using PointList = VSTGUI::PointList;
inline void drawLine (const CPoint& start, const CPoint& end)
{
drawLine (std::make_pair (start, end));
}
/** draw a line */
void drawLine (const LinePair& line);
/** draw multiple lines at once */
void drawLines (const LineList& lines);
/** draw a polygon */
void drawPolygon (const PointList& polygonPointList, const CDrawStyle drawStyle = kDrawStroked);
/** draw a rect */
void drawRect (const CRect& rect, const CDrawStyle drawStyle = kDrawStroked);
/** draw an arc, angles are in degree */
void drawArc (const CRect& rect, const float startAngle1, const float endAngle2,
const CDrawStyle drawStyle = kDrawStroked);
/** draw an ellipse */
void drawEllipse (const CRect& rect, const CDrawStyle drawStyle = kDrawStroked);
/** draw a point */
void drawPoint (const CPoint& point, const CColor& color);
/** don't call directly, please use CBitmap::draw instead */
void drawBitmap (CBitmap* bitmap, const CRect& dest, const CPoint& offset = CPoint (0, 0),
float alpha = 1.f);
void drawBitmapNinePartTiled (CBitmap* bitmap, const CRect& dest,
const CNinePartTiledDescription& desc, float alpha = 1.f);
void fillRectWithBitmap (CBitmap* bitmap, const CRect& srcRect, const CRect& dstRect,
float alpha);
/** clears the rect (makes r = 0, g = 0, b = 0, a = 0) */
void clearRect (const CRect& rect);
//@}
//-----------------------------------------------------------------------------
// @name Bitmap Interpolation Quality
//-----------------------------------------------------------------------------
//@{
/** set the current bitmap interpolation quality */
void setBitmapInterpolationQuality (BitmapInterpolationQuality quality);
/** get the current bitmap interpolation quality */
BitmapInterpolationQuality getBitmapInterpolationQuality () const;
//@}
//-----------------------------------------------------------------------------
/// @name Line Mode
//-----------------------------------------------------------------------------
//@{
/** set the current line style */
void setLineStyle (const CLineStyle& style);
/** get the current line style */
const CLineStyle& getLineStyle () const;
/** set the current line width */
void setLineWidth (CCoord width);
/** get the current line width */
CCoord getLineWidth () const;
//@}
//-----------------------------------------------------------------------------
/// @name Draw Mode
//-----------------------------------------------------------------------------
//@{
/** set the current draw mode, see CDrawMode */
void setDrawMode (CDrawMode mode);
/** get the current draw mode, see CDrawMode */
CDrawMode getDrawMode () const;
//@}
//-----------------------------------------------------------------------------
/// @name Clipping
//-----------------------------------------------------------------------------
//@{
/** set the current clip */
void setClipRect (const CRect& clip);
/** get the current clip */
CRect& getClipRect (CRect &clip) const;
/** reset the clip to the default state */
void resetClipRect ();
//@}
//-----------------------------------------------------------------------------
/// @name Color
//-----------------------------------------------------------------------------
//@{
/** set current fill color */
void setFillColor (const CColor& color);
/** get current fill color */
CColor getFillColor () const;
/** set current stroke color */
void setFrameColor (const CColor& color);
/** get current stroke color */
CColor getFrameColor () const;
//@}
//-----------------------------------------------------------------------------
/// @name Font
//-----------------------------------------------------------------------------
//@{
/** set current font color */
void setFontColor (const CColor& color);
/** get current font color */
CColor getFontColor () const;
/** set current font */
void setFont (const CFontRef font, const CCoord& size = 0, const int32_t& style = -1);
/** get current font */
const CFontRef getFont () const;
//@}
//-----------------------------------------------------------------------------
/// @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] */
void setGlobalAlpha (float newAlpha);
/** get current global alpha value */
float getGlobalAlpha () const;
//@}
//-----------------------------------------------------------------------------
/// @name Global State Stack
//-----------------------------------------------------------------------------
//@{
void saveGlobalState ();
void restoreGlobalState ();
//@}
//-----------------------------------------------------------------------------
/// @name Transformation
//-----------------------------------------------------------------------------
//@{
const CGraphicsTransform& getCurrentTransform () const;
const CRect& getAbsoluteClipRect () const;
/** returns the backend scale factor. */
double getScaleFactor () const;
/** 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 */
CGraphicsPath* createGraphicsPath ();
/** create a graphics path from a text */
CGraphicsPath* createTextPath (const CFontRef font, UTF8StringPtr text);
/** 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
};
void drawGraphicsPath (CGraphicsPath* path, PathDrawMode mode = kPathFilled,
CGraphicsTransform* transformation = nullptr);
void fillLinearGradient (CGraphicsPath* path, const CGradient& gradient,
const CPoint& startPoint, const CPoint& endPoint, bool evenOdd = false,
CGraphicsTransform* transformation = nullptr);
void fillRadialGradient (CGraphicsPath* path, const CGradient& gradient, const CPoint& center,
CCoord radius, const CPoint& originOffset = CPoint (0, 0),
bool evenOdd = false, CGraphicsTransform* transformation = nullptr);
//@}
struct IDrawLinearGradientLine
{
virtual bool draw (const PointList& line, const CGradient& gradient, CCoord lineWidth,
CLineStyle::LineCap, CLineStyle::LineJoin) const = 0;
};
using DrawLinearGradientLineCallback = std::function<void (IDrawLinearGradientLine&)>;
bool drawLinearGradientLine (const DrawLinearGradientLineCallback& cb);
void beginDraw ();
void endDraw ();
const CRect& getSurfaceRect () const;
CDrawContext (const PlatformGraphicsDeviceContextPtr device, const CRect& surfaceRect,
double scaleFactor);
~CDrawContext () noexcept override;
const PlatformGraphicsDeviceContextPtr& getPlatformDeviceContext () const;
protected:
CDrawContext () = delete;
explicit CDrawContext (const CRect& surfaceRect);
void init ();
void pushTransform (const CGraphicsTransform& transformation);
void popTransform ();
const UTF8String& getDrawString (UTF8StringPtr string);
void clearDrawString ();
private:
struct Impl;
std::unique_ptr<Impl> impl;
};
//-----------------------------------------------------------------------------
struct ConcatClip
{
ConcatClip (CDrawContext& context, const CRect& rect)
: context (context), newClip (rect)
{
context.getClipRect (origClip);
newClip.normalize ();
newClip.bound (origClip);
context.setClipRect (newClip);
}
~ConcatClip () noexcept
{
context.setClipRect (origClip);
}
bool isEmpty () const { return newClip.isEmpty (); }
const CRect& get () const { return newClip; }
private:
CDrawContext& context;
CRect origClip;
CRect newClip;
};
//-----------------------------------------------------------------------------
template<typename Proc>
void drawClipped (CDrawContext* context, const CRect& clip, Proc proc)
{
ConcatClip cc (*context, clip);
if (!cc.isEmpty ())
proc ();
}
} // VSTGUI
+68
View File
@@ -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) = default;
constexpr CDrawMode& operator= (const CDrawMode& m) = default;
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,183 @@
// 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 || text.length () < 2)
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 ();
size_t distance = std::distance (left, right) - 1;
int32_t dir = 1;
while (distance > 0 && width != maxWidth)
{
distance = (distance / 2);
while ((dir > 0 ? (width > maxWidth) : (width < maxWidth)) && distance > 0)
{
if (mode == kTextTruncateHead)
{
if (dir > 0)
{
for (auto i = distance; i > 0 && left != right; --i)
++left;
}
else
{
for (auto i = distance; i > 0 && left != text.begin (); --i)
--left;
}
truncatedText = "..";
}
else if (mode == kTextTruncateTail)
{
if (dir > 0)
{
for (auto i = distance; i > 0 && left != right; --i)
--right;
}
else
{
for (auto i = distance; i > 0 && right != text.end (); --i)
++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)
break;
}
dir *= -1;
}
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
+74
View File
@@ -0,0 +1,74 @@
// 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 : uint16_t {
/** icon left, text centered in the area next to the icon*/
kIconLeft = 0,
/** 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 : uint16_t {
kTextTruncateNone = 0,
kTextTruncateHead,
kTextTruncateTail
};
//-----------------------------------------------------------------------------
enum CreateTextTruncateFlags : uint16_t {
/** 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 truncation 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);
}} // namespaces
@@ -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
+50
View File
@@ -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,314 @@
// 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 "cexternalview.h"
#include "cframe.h"
#include "platform/iplatformframe.h"
//------------------------------------------------------------------------
namespace VSTGUI {
//------------------------------------------------------------------------
struct CExternalViewBaseImpl
{
private:
using ExternalViewPtr = std::shared_ptr<ExternalView::IView>;
ExternalViewPtr view;
bool isAttached {false};
static ExternalView::IntRect fromCRect (const CRect& r)
{
ExternalView::IntRect res;
res.origin.x = static_cast<int64_t> (std::ceil (r.left));
res.origin.y = static_cast<int64_t> (std::ceil (r.top));
res.size.width = static_cast<int64_t> (std::floor (r.getWidth ()));
res.size.height = static_cast<int64_t> (std::floor (r.getHeight ()));
return res;
}
static CRect calculateSize (CViewContainer* parent, CRect newSize)
{
CFrame* frame = parent ? parent->getFrame () : nullptr;
while (parent && parent != frame)
{
CRect parentSize = parent->getViewSize ();
parent->getTransform ().transform (newSize);
newSize.offset (parentSize.left, parentSize.top);
newSize.bound (parentSize);
parent = static_cast<CViewContainer*> (parent->getParentView ());
}
if (frame)
frame->getTransform ().transform (newSize);
return newSize;
}
public:
CExternalViewBaseImpl (const ExternalViewPtr& v) : view (v) {}
void updateSize (CViewContainer* parent, CRect localSize, CRect globalSize)
{
if (!view)
return;
localSize = calculateSize (parent, localSize);
view->setViewSize (fromCRect (globalSize), fromCRect (localSize));
}
void attach (CFrame* frame)
{
if (!frame || !view)
return;
auto platformFrame = frame->getPlatformFrame ();
if (!platformFrame)
return;
ExternalView::PlatformViewType viewType = {};
switch (platformFrame->getPlatformType ())
{
case PlatformType::kHWND:
viewType = ExternalView::PlatformViewType::HWND;
break;
case PlatformType::kNSView:
viewType = ExternalView::PlatformViewType::NSView;
break;
default:
return;
}
if (!view->platformViewTypeSupported (viewType))
return;
isAttached = view->attach (platformFrame->getPlatformRepresentation (), viewType);
}
void remove ()
{
if (view && isAttached)
{
view->remove ();
isAttached = false;
}
}
void scaleFactorChanged (double scaleFactor)
{
if (view)
view->setContentScaleFactor (scaleFactor);
}
void takeFocus ()
{
if (view)
view->takeFocus ();
}
void looseFocus ()
{
if (view)
view->looseFocus ();
}
void enableMouse (bool state)
{
if (view)
view->setMouseEnabled (state);
}
ExternalView::IView* getView () const { return view.get (); }
};
//------------------------------------------------------------------------
struct CExternalView::Impl : CExternalViewBaseImpl
{
using CExternalViewBaseImpl::CExternalViewBaseImpl;
};
//------------------------------------------------------------------------
CExternalView::CExternalView (const CRect& r, const ExternalViewPtr& view) : CView (r)
{
impl = std::make_unique<Impl> (view);
impl->getView ()->setTookFocusCallback ([this] () {
if (auto frame = getFrame ())
frame->setFocusView (this);
});
}
//------------------------------------------------------------------------
CExternalView::~CExternalView () noexcept { impl->getView ()->setTookFocusCallback (nullptr); }
//------------------------------------------------------------------------
bool CExternalView::attached (CView* parent)
{
if (CView::attached (parent))
{
auto frame = parent->getFrame ();
impl->updateSize (parent->asViewContainer (), getViewSize (),
translateToGlobal (getViewSize ()));
impl->scaleFactorChanged (frame->getScaleFactor ());
impl->attach (frame);
frame->registerScaleFactorChangedListener (this);
return true;
}
return false;
}
//------------------------------------------------------------------------
bool CExternalView::removed (CView* parent)
{
if (auto frame = parent->getFrame ())
{
frame->unregisterScaleFactorChangedListener (this);
}
impl->remove ();
return CView::removed (parent);
}
//------------------------------------------------------------------------
void CExternalView::takeFocus () { impl->takeFocus (); }
//------------------------------------------------------------------------
void CExternalView::looseFocus () { impl->looseFocus (); }
//------------------------------------------------------------------------
void CExternalView::setViewSize (const CRect& rect, bool invalid)
{
CView::setViewSize (rect, invalid);
impl->updateSize (getParentView () ? getParentView ()->asViewContainer () : nullptr,
getViewSize (), translateToGlobal (getViewSize ()));
}
//------------------------------------------------------------------------
void CExternalView::parentSizeChanged ()
{
impl->updateSize (getParentView () ? getParentView ()->asViewContainer () : nullptr,
getViewSize (), translateToGlobal (getViewSize ()));
}
//------------------------------------------------------------------------
void CExternalView::onScaleFactorChanged (CFrame* frame, double newScaleFactor)
{
impl->scaleFactorChanged (newScaleFactor);
}
//------------------------------------------------------------------------
void CExternalView::setMouseEnabled (bool enable)
{
impl->enableMouse (enable);
CView::setMouseEnabled (enable);
}
//------------------------------------------------------------------------
ExternalView::IView* CExternalView::getExternalView () const { return impl->getView (); }
//------------------------------------------------------------------------
//------------------------------------------------------------------------
//------------------------------------------------------------------------
//------------------------------------------------------------------------
struct CExternalControl::Impl : CExternalViewBaseImpl
{
using CExternalViewBaseImpl::CExternalViewBaseImpl;
};
//------------------------------------------------------------------------
CExternalControl::CExternalControl (const CRect& r, const ExternalControlPtr& view)
: CControl (r, nullptr)
{
impl = std::make_unique<Impl> (view);
impl->getView ()->setTookFocusCallback ([this] () {
if (auto frame = getFrame ())
frame->setFocusView (this);
});
auto control = dynamic_cast<ExternalView::IControlViewExtension*> (impl->getView ());
vstgui_assert (
control, "Please provide an object that inherits from ExternalView::IControlViewExtension");
control->setEditCallbacks ({
[this] () { beginEdit (); },
[this] (double newValue) {
auto old = getValue ();
setValueNormalized (static_cast<float> (newValue));
if (old != getValue ())
valueChanged ();
},
[this] () { endEdit (); },
});
setWantsFocus (true);
}
//------------------------------------------------------------------------
CExternalControl::~CExternalControl () noexcept
{
impl->getView ()->setTookFocusCallback (nullptr);
auto control = dynamic_cast<ExternalView::IControlViewExtension*> (impl->getView ());
control->setEditCallbacks ({});
}
//------------------------------------------------------------------------
void CExternalControl::setValue (float val)
{
CControl::setValue (val);
auto control = dynamic_cast<ExternalView::IControlViewExtension*> (impl->getView ());
control->setValue (getValueNormalized ());
}
//------------------------------------------------------------------------
bool CExternalControl::attached (CView* parent)
{
if (CControl::attached (parent))
{
auto frame = parent->getFrame ();
impl->updateSize (parent->asViewContainer (), getViewSize (),
translateToGlobal (getViewSize ()));
impl->scaleFactorChanged (frame->getScaleFactor ());
impl->attach (frame);
frame->registerScaleFactorChangedListener (this);
return true;
}
return false;
}
//------------------------------------------------------------------------
bool CExternalControl::removed (CView* parent)
{
if (auto frame = parent->getFrame ())
{
frame->unregisterScaleFactorChangedListener (this);
}
impl->remove ();
return CControl::removed (parent);
}
//------------------------------------------------------------------------
void CExternalControl::takeFocus () { impl->takeFocus (); }
//------------------------------------------------------------------------
void CExternalControl::looseFocus () { impl->looseFocus (); }
//------------------------------------------------------------------------
void CExternalControl::setViewSize (const CRect& rect, bool invalid)
{
CControl::setViewSize (rect, invalid);
impl->updateSize (getParentView () ? getParentView ()->asViewContainer () : nullptr,
getViewSize (), translateToGlobal (getViewSize ()));
}
//------------------------------------------------------------------------
void CExternalControl::parentSizeChanged ()
{
impl->updateSize (getParentView () ? getParentView ()->asViewContainer () : nullptr,
getViewSize (), translateToGlobal (getViewSize ()));
}
//------------------------------------------------------------------------
void CExternalControl::onScaleFactorChanged (CFrame* frame, double newScaleFactor)
{
impl->scaleFactorChanged (newScaleFactor);
}
//------------------------------------------------------------------------
void CExternalControl::setMouseEnabled (bool enable)
{
impl->enableMouse (enable);
CControl::setMouseEnabled (enable);
}
//------------------------------------------------------------------------
ExternalView::IView* CExternalControl::getExternalView () const { return impl->getView (); }
//------------------------------------------------------------------------
bool CExternalControl::getFocusPath (CGraphicsPath& outPath) { return true; }
//------------------------------------------------------------------------
} // VSTGUI
@@ -0,0 +1,86 @@
// 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 "controls/ccontrol.h"
#include "iscalefactorchangedlistener.h"
#include "iexternalview.h"
#include <memory>
//------------------------------------------------------------------------
namespace VSTGUI {
//------------------------------------------------------------------------
/** View to embed non CView views into VSTGUI
*
* This view is the umbrella for views from other view systems (like HWND child windows or
* NSViews).
* The actual implementation for the external view must be done via ExternalView::IView
*
* @ingroup new_in_4_13
*/
class CExternalView : public CView,
public IScaleFactorChangedListener,
public ExternalView::IViewEmbedder
{
public:
using ExternalViewPtr = std::shared_ptr<ExternalView::IView>;
CExternalView (const CRect& r, const ExternalViewPtr& view);
~CExternalView () noexcept;
bool attached (CView* parent) override;
bool removed (CView* parent) override;
void takeFocus () override;
void looseFocus () override;
void setViewSize (const CRect& rect, bool invalid = true) override;
void parentSizeChanged () override;
void onScaleFactorChanged (CFrame* frame, double newScaleFactor) override;
void setMouseEnabled (bool enable = true) override;
ExternalView::IView* getExternalView () const override;
private:
struct Impl;
std::unique_ptr<Impl> impl;
};
//------------------------------------------------------------------------
class CExternalControl : public CControl,
public IScaleFactorChangedListener,
public ExternalView::IViewEmbedder
{
public:
using ExternalControlPtr = std::shared_ptr<ExternalView::IView>;
CExternalControl (const CRect& r, const ExternalControlPtr& control);
~CExternalControl () noexcept;
void setValue (float val) override;
bool attached (CView* parent) override;
bool removed (CView* parent) override;
void takeFocus () override;
void looseFocus () override;
void setViewSize (const CRect& rect, bool invalid = true) override;
void parentSizeChanged () override;
void onScaleFactorChanged (CFrame* frame, double newScaleFactor) override;
void setMouseEnabled (bool enable = true) override;
ExternalView::IView* getExternalView () const override;
CLASS_METHODS_NOCOPY (CExternalControl, CControl)
private:
void draw (CDrawContext* pContext) override {}
bool getFocusPath (CGraphicsPath& outPath) override;
struct Impl;
std::unique_ptr<Impl> impl;
};
//------------------------------------------------------------------------
} // 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 "platform/iplatformfileselector.h"
#include "platform/platformfactory.h"
#include "cfileselector.h"
#include "cframe.h"
#include "cstring.h"
#include <algorithm>
namespace VSTGUI {
//-----------------------------------------------------------------------------
struct CFileExtension::Impl : PlatformFileExtension
{
};
//-----------------------------------------------------------------------------
CFileExtension::CFileExtension ()
{
impl = std::make_unique<Impl> ();
}
//-----------------------------------------------------------------------------
CFileExtension::CFileExtension (const UTF8String& inDescription, const UTF8String& inExtension,
const UTF8String& inMimeType, int32_t inMacType,
const UTF8String& inUti)
: CFileExtension ()
{
init (inDescription, inExtension, inMimeType, inUti);
}
//-----------------------------------------------------------------------------
CFileExtension::CFileExtension (const CFileExtension& ext) : CFileExtension ()
{
*impl = *ext.impl;
}
//-----------------------------------------------------------------------------
CFileExtension::~CFileExtension () noexcept = default;
//-----------------------------------------------------------------------------
CFileExtension::CFileExtension (CFileExtension&& ext) noexcept
{
*this = std::move (ext);
}
//-----------------------------------------------------------------------------
CFileExtension& CFileExtension::operator= (CFileExtension&& ext) noexcept
{
std::swap (impl, ext.impl);
return *this;
}
//-----------------------------------------------------------------------------
void CFileExtension::init (const UTF8String& inDescription, const UTF8String& inExtension,
const UTF8String& inMimeType, const UTF8String& inUti)
{
impl->description = inDescription;
impl->extension = inExtension;
impl->mimeType = inMimeType;
impl->uti = inUti;
if (impl->description == nullptr && !impl->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 = impl->extension == ext.impl->extension;
if (!result)
result = impl->mimeType == ext.impl->mimeType;
if (!result)
result = impl->uti == ext.impl->uti;
if (!result && impl->macType != 0 && ext.impl->macType != 0)
result = (impl->macType == ext.impl->macType);
return result;
}
//-----------------------------------------------------------------------------
const UTF8String& CFileExtension::getDescription () const
{
return impl->description;
}
//-----------------------------------------------------------------------------
const UTF8String& CFileExtension::getExtension () const
{
return impl->extension;
}
//-----------------------------------------------------------------------------
const UTF8String& CFileExtension::getMimeType () const
{
return impl->mimeType;
}
//-----------------------------------------------------------------------------
const UTF8String& CFileExtension::getUTI () const
{
return impl->uti;
}
//-----------------------------------------------------------------------------
int32_t CFileExtension::getMacType () const
{
return impl->macType;
}
//-----------------------------------------------------------------------------
CFileExtension::CFileExtension (const PlatformFileExtension& ext) : CFileExtension ()
{
impl->description = ext.description;
impl->extension = ext.extension;
impl->mimeType = ext.mimeType;
impl->uti = ext.uti;
impl->macType = ext.macType;
}
//-----------------------------------------------------------------------------
const PlatformFileExtension& CFileExtension::getPlatformFileExtension () const
{
return *impl;
}
//-----------------------------------------------------------------------------
const CFileExtension& CNewFileSelector::getAllFilesExtension ()
{
static CFileExtension allFilesExtension (PlatformAllFilesExtension);
return allFilesExtension;
}
//-----------------------------------------------------------------------------
IdStringPtr CNewFileSelector::kSelectEndMessage = "CNewFileSelector Select End Message";
//-----------------------------------------------------------------------------
// CNewFileSelector Implementation
//-----------------------------------------------------------------------------
struct CNewFileSelector::Impl : PlatformFileSelectorConfig
{
PlatformFileSelectorPtr platformFileSelector;
CFrame* frame {nullptr};
std::vector<UTF8String> result;
};
//-----------------------------------------------------------------------------
CNewFileSelector::CNewFileSelector (PlatformFileSelectorPtr&& platformFileSelector, CFrame* parent)
{
impl = std::make_unique<Impl> ();
impl->platformFileSelector = std::move (platformFileSelector);
impl->frame = parent;
}
//-----------------------------------------------------------------------------
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 (impl->frame)
impl->frame->onStartLocalEventLoop ();
impl->doneCallback = [this, del = shared (delegate)] (std::vector<UTF8String>&& files) {
impl->result = std::move (files);
del->notify (this, CNewFileSelector::kSelectEndMessage);
};
setBit (impl->flags, PlatformFileSelectorFlags::RunModal, false);
return impl->platformFileSelector->run (*impl);
}
//-----------------------------------------------------------------------------
bool CNewFileSelector::run (CallbackFunc&& callback)
{
if (impl->frame)
impl->frame->onStartLocalEventLoop ();
remember ();
impl->doneCallback = [this,
cb = std::move (callback)] (std::vector<UTF8String>&& files) {
impl->result = std::move (files);
cb (this);
forget ();
};
setBit (impl->flags, PlatformFileSelectorFlags::RunModal, false);
return impl->platformFileSelector->run (*impl);
}
//-----------------------------------------------------------------------------
void CNewFileSelector::cancel ()
{
impl->platformFileSelector->cancel ();
}
//-----------------------------------------------------------------------------
bool CNewFileSelector::runModal ()
{
if (impl->frame)
impl->frame->onStartLocalEventLoop ();
setBit (impl->flags, PlatformFileSelectorFlags::RunModal, true);
impl->doneCallback = [&] (std::vector<UTF8String>&& files) {
impl->result = std::move (files);
};
return impl->platformFileSelector->run (*impl);
}
//-----------------------------------------------------------------------------
void CNewFileSelector::setTitle (const UTF8String& inTitle)
{
impl->title = inTitle;
}
//-----------------------------------------------------------------------------
void CNewFileSelector::setInitialDirectory (const UTF8String& path)
{
impl->initialPath = path;
}
//-----------------------------------------------------------------------------
void CNewFileSelector::setDefaultSaveName (const UTF8String& name)
{
impl->defaultSaveName = name;
}
//-----------------------------------------------------------------------------
void CNewFileSelector::setAllowMultiFileSelection (bool state)
{
setBit (impl->flags, PlatformFileSelectorFlags::MultiFileSelection, state);
}
//-----------------------------------------------------------------------------
void CNewFileSelector::setDefaultExtension (const CFileExtension& extension)
{
if (impl->defaultExtension != PlatformNoFileExtension)
{
#if DEBUG
DebugPrint ("VSTGUI Warning: It's not allowed to set a default extension twice on a "
"CFileSelector instance\n");
#endif
return;
}
auto it = std::find (impl->extensions.begin (), impl->extensions.end (),
extension.getPlatformFileExtension ());
if (it == impl->extensions.end ())
addFileExtension (extension);
impl->defaultExtension = extension.getPlatformFileExtension ();
}
//-----------------------------------------------------------------------------
void CNewFileSelector::addFileExtension (const CFileExtension& extension)
{
impl->extensions.emplace_back (extension.getPlatformFileExtension ());
}
//-----------------------------------------------------------------------------
void CNewFileSelector::addFileExtension (CFileExtension&& extension)
{
impl->extensions.emplace_back (std::move (extension.getPlatformFileExtension ()));
}
//-----------------------------------------------------------------------------
uint32_t CNewFileSelector::getNumSelectedFiles () const
{
return static_cast<uint32_t> (impl->result.size ());
}
//-----------------------------------------------------------------------------
UTF8StringPtr CNewFileSelector::getSelectedFile (uint32_t index) const
{
if (index < impl->result.size ())
return impl->result[index];
return nullptr;
}
//------------------------------------------------------------------------
CNewFileSelector* CNewFileSelector::create (CFrame* parent, Style style)
{
PlatformFileSelectorStyle platformStyle;
switch (style)
{
case Style::kSelectFile:
platformStyle = PlatformFileSelectorStyle::SelectFile;
break;
case Style::kSelectDirectory:
platformStyle = PlatformFileSelectorStyle::SelectDirectory;
break;
case Style::kSelectSaveFile:
platformStyle = PlatformFileSelectorStyle::SelectSaveFile;
break;
default:
vstgui_assert (false);
return nullptr;
}
if (auto platformSelector = getPlatformFactory ().createFileSelector (
platformStyle, parent ? parent->getPlatformFrame () : nullptr))
{
return new CNewFileSelector (std::move (platformSelector), parent);
}
return nullptr;
}
} // VSTGUI
+162
View File
@@ -0,0 +1,162 @@
// 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 <functional>
#include <memory>
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;
const UTF8String& getExtension () const;
const UTF8String& getMimeType () const;
const UTF8String& getUTI () const;
int32_t getMacType () const;
bool operator== (const CFileExtension& ext) const;
//-----------------------------------------------------------------------------
CFileExtension (CFileExtension&& ext) noexcept;
CFileExtension& operator= (CFileExtension&& ext) noexcept;
CFileExtension (const PlatformFileExtension&);
const PlatformFileExtension& getPlatformFileExtension () const;
protected:
CFileExtension ();
void init (const UTF8String& description, const UTF8String& extension,
const UTF8String& mimeType, const UTF8String& uti);
struct Impl;
std::unique_ptr<Impl> impl;
};
//-----------------------------------------------------------------------------
// 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 final : 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);
CNewFileSelector (PlatformFileSelectorPtr&& platformFileSelector, CFrame* parent);
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:
~CNewFileSelector () noexcept override;
struct Impl;
std::unique_ptr<Impl> impl;
};
} // VSTGUI
+221
View File
@@ -0,0 +1,221 @@
// 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/platformfactory.h"
#include "platform/iplatformfont.h"
namespace VSTGUI {
//-----------------------------------------------------------------------------
// Global Fonts
//-----------------------------------------------------------------------------
struct GlobalFonts
{
SharedPointer<CFontDesc> systemFont;
SharedPointer<CFontDesc> normalFontVeryBig;
SharedPointer<CFontDesc> normalFontBig;
SharedPointer<CFontDesc> normalFont;
SharedPointer<CFontDesc> normalFontSmall;
SharedPointer<CFontDesc> normalFontSmaller;
SharedPointer<CFontDesc> normalFontVerySmall;
SharedPointer<CFontDesc> symbolFont;
};
static GlobalFonts globalFonts;
//-----------------------------------------------------------------------------
CFontRef kSystemFont = nullptr;
CFontRef kNormalFontVeryBig = nullptr;
CFontRef kNormalFontBig = nullptr;
CFontRef kNormalFont = nullptr;
CFontRef kNormalFontSmall = nullptr;
CFontRef kNormalFontSmaller = nullptr;
CFontRef kNormalFontVerySmall = nullptr;
CFontRef kSymbolFont = nullptr;
//-----------------------------------------------------------------------------
void CFontDesc::init ()
{
#if MAC
#if TARGET_OS_IPHONE
globalFonts.systemFont = makeOwned<CFontDesc> ("Helvetica", 12);
globalFonts.normalFontVeryBig = makeOwned<CFontDesc> ("ArialMT", 18);
globalFonts.normalFontBig = makeOwned<CFontDesc> ("ArialMT", 14);
globalFonts.normalFont = makeOwned<CFontDesc> ("ArialMT", 12);
globalFonts.normalFontSmall = makeOwned<CFontDesc> ("ArialMT", 11);
globalFonts.normalFontSmaller = makeOwned<CFontDesc> ("ArialMT", 10);
globalFonts.normalFontVerySmall = makeOwned<CFontDesc> ("ArialMT", 9);
globalFonts.symbolFont = makeOwned<CFontDesc> ("Symbol", 12);
#else
globalFonts.systemFont = makeOwned<CFontDesc> ("Lucida Grande", 12);
globalFonts.normalFontVeryBig = makeOwned<CFontDesc> ("Arial", 18);
globalFonts.normalFontBig = makeOwned<CFontDesc> ("Arial", 14);
globalFonts.normalFont = makeOwned<CFontDesc> ("Arial", 12);
globalFonts.normalFontSmall = makeOwned<CFontDesc> ("Arial", 11);
globalFonts.normalFontSmaller = makeOwned<CFontDesc> ("Arial", 10);
globalFonts.normalFontVerySmall = makeOwned<CFontDesc> ("Arial", 9);
globalFonts.symbolFont = makeOwned<CFontDesc> ("Symbol", 12);
#endif
#elif WINDOWS
globalFonts.systemFont = makeOwned<CFontDesc> ("Arial", 12);
globalFonts.normalFontVeryBig = makeOwned<CFontDesc> ("Arial", 18);
globalFonts.normalFontBig = makeOwned<CFontDesc> ("Arial", 14);
globalFonts.normalFont = makeOwned<CFontDesc> ("Arial", 12);
globalFonts.normalFontSmall = makeOwned<CFontDesc> ("Arial", 11);
globalFonts.normalFontSmaller = makeOwned<CFontDesc> ("Arial", 10);
globalFonts.normalFontVerySmall = makeOwned<CFontDesc> ("Arial", 9);
globalFonts.symbolFont = makeOwned<CFontDesc> ("Symbol", 13);
#else
globalFonts.systemFont = makeOwned<CFontDesc> ("Arial", 12);
globalFonts.normalFontVeryBig = makeOwned<CFontDesc> ("Arial", 18);
globalFonts.normalFontBig = makeOwned<CFontDesc> ("Arial", 14);
globalFonts.normalFont = makeOwned<CFontDesc> ("Arial", 12);
globalFonts.normalFontSmall = makeOwned<CFontDesc> ("Arial", 11);
globalFonts.normalFontSmaller = makeOwned<CFontDesc> ("Arial", 10);
globalFonts.normalFontVerySmall = makeOwned<CFontDesc> ("Arial", 9);
globalFonts.symbolFont = makeOwned<CFontDesc> ("Symbol", 13);
#endif
kSystemFont = globalFonts.systemFont;
kNormalFontVeryBig = globalFonts.normalFontVeryBig;
kNormalFontBig = globalFonts.normalFontBig;
kNormalFont = globalFonts.normalFont;
kNormalFontSmall = globalFonts.normalFontSmall;
kNormalFontSmaller = globalFonts.normalFontSmaller;
kNormalFontVerySmall = globalFonts.normalFontVerySmall;
kSymbolFont = globalFonts.symbolFont;
}
//-----------------------------------------------------------------------------
void CFontDesc::cleanup ()
{
globalFonts.systemFont = nullptr;
globalFonts.normalFontVeryBig = nullptr;
globalFonts.normalFontBig = nullptr;
globalFonts.normalFont = nullptr;
globalFonts.normalFontSmall = nullptr;
globalFonts.normalFontSmaller = nullptr;
globalFonts.normalFontVerySmall = nullptr;
globalFonts.symbolFont = nullptr;
kSystemFont = nullptr;
kNormalFontVeryBig = nullptr;
kNormalFontBig = nullptr;
kNormalFont = nullptr;
kNormalFontSmall = nullptr;
kNormalFontSmaller = nullptr;
kNormalFontVerySmall = nullptr;
kSymbolFont = nullptr;
}
//-----------------------------------------------------------------------------
// 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.
\note New in 4.9: It's now possible to use custom fonts. Fonts must reside inside the Bundle/Package at PackageRoot/Resources/Fonts/.
*/
//-----------------------------------------------------------------------------
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;
}
//------------------------------------------------------------------------
CFontDesc::~CFontDesc () noexcept
{
vstgui_assert (getNbReference () == 0, "Always use shared pointers with CFontDesc!");
}
//-----------------------------------------------------------------------------
void CFontDesc::beforeDelete ()
{
freePlatformFont ();
}
//-----------------------------------------------------------------------------
auto CFontDesc::getPlatformFont () const -> const PlatformFontPtr
{
if (platformFont == nullptr)
platformFont = getPlatformFactory ().createFont (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;
}
} // VSTGUI
+76
View File
@@ -0,0 +1,76 @@
// 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 {
//-----------------------------------------------------------------------------
// CFontDesc Declaration
//! @brief font class
//-----------------------------------------------------------------------------
class CFontDesc : public AtomicReferenceCounted
{
public:
CFontDesc (const UTF8String& name = "", const CCoord& size = 0, const int32_t style = 0);
CFontDesc (const CFontDesc& font);
~CFontDesc () noexcept override;
//-----------------------------------------------------------------------------
/// @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 init ();
static void cleanup ();
protected:
void beforeDelete () override;
virtual void freePlatformFont ();
UTF8String name;
CCoord size;
int32_t style;
mutable PlatformFontPtr platformFont;
};
//-----------------------------------------------------------------------------
// Global fonts
//-----------------------------------------------------------------------------
extern CFontRef kSystemFont;
extern CFontRef kNormalFontVeryBig;
extern CFontRef kNormalFontBig;
extern CFontRef kNormalFont;
extern CFontRef kNormalFontSmall;
extern CFontRef kNormalFontSmaller;
extern CFontRef kNormalFontVerySmall;
extern CFontRef kSymbolFont;
} // VSTGUI
File diff suppressed because it is too large Load Diff
+395
View File
@@ -0,0 +1,395 @@
// 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 "optional.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 = PlatformType::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) */
uint64_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;
CPoint checkSizeConstraint (const CPoint& newSize) const;
VSTGUI_DEPRECATED (
/** set a modal view. deprecated use beginModalViewSession instead */
bool setModalView (CView* pView);)
/** get the currently active modal view or nullptr if there is none */
CView* getModalView () const;
/** begin a new modal view session
*
* A modal view session is active until endModalViewSession is called and in that time all UI
* events are only dispatched to the modal view or its child views.
* Modal view sessions can be stacked but must be ended in the same order.
*
* @param view new modal view (ownership is transfered to frame, the same as addView)
* @return a unique session identifier
*/
Optional<ModalViewSessionID> beginModalViewSession (CView* view);
/** end a modal view session
*
* @param session a session identifer
* @return true on success
*/
bool endModalViewSession (ModalViewSessionID 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);
VSTGUI_DEPRECATED_MSG (
void registerScaleFactorChangedListeneer (IScaleFactorChangedListener* listener) {
registerScaleFactorChangedListener (listener);
},
"use registerScaleFactorChangedListener")
VSTGUI_DEPRECATED_MSG (
void unregisterScaleFactorChangedListeneer (IScaleFactorChangedListener* listener) {
unregisterScaleFactorChangedListener (listener);
},
"use unregisterScaleFactorChangedListener")
void registerScaleFactorChangedListener (IScaleFactorChangedListener* listener);
void unregisterScaleFactorChangedListener (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 EventProcessingFunction = 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 (EventProcessingFunction&& 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 EventProcessingFunction& func);
/** Returns true if an event is currently being processed. */
bool inEventProcessing () const;
void onStartLocalEventLoop ();
bool performDrag (const DragDescription& desc, const SharedPointer<IDragCallback>& callback);
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 getViewsAt (const CPoint& where, ViewList& views, const GetViewOptions& options = GetViewOptions ().deep ()) const override;
bool hitTestSubViews (const CPoint& where, const Event& event) override;
CPoint& frameToLocal (CPoint& point) const override { return point; }
CPoint& localToFrame (CPoint& point) const override { return point; }
// CView
bool attached (CView* parent) override;
void draw (CDrawContext* pContext) override;
void drawRect (CDrawContext* pContext, const CRect& updateRect) override;
void setViewSize (const CRect& rect, bool invalid = true) override;
void dispatchEvent (Event& event) override;
VSTGUIEditorInterface* getEditor () const override;
IPlatformFrame* getPlatformFrame () const;
#if DEBUG
void dumpHierarchy () override;
#endif
CLASS_METHODS_NOCOPY(CFrame, CViewContainer)
//-------------------------------------------
protected:
struct CollectInvalidRects;
CFrame (const CFrame&) = delete;
~CFrame () noexcept override = default;
void beforeDelete () override;
void checkMouseViews (const MouseEvent& event);
void clearMouseViews (const CPoint& where, Modifiers modifiers, bool callMouseExit = true);
void removeFromMouseViews (CView* view);
void setCollectInvalidRects (CollectInvalidRects* collectInvalidRects);
// keyboard hooks
void dispatchKeyboardEventToHooks (KeyboardEvent& event);
// mouse observers
void callMouseObserverMouseEntered (CView* view);
void callMouseObserverMouseExited (CView* view);
void callMouseObserverOtherMouseEvent (MouseEvent& event);
void dispatchNewScaleFactor (double newScaleFactor);
// platform frame
void platformDrawRects (const PlatformGraphicsDeviceContextPtr& context, double scaleFactor,
const std::vector<CRect>& rects) override;
void platformOnEvent (Event& event) override;
DragOperation platformOnDragEnter (DragEventData data) override;
DragOperation platformOnDragMove (DragEventData data) override;
void platformOnDragLeave (DragEventData data) override;
bool platformOnDrop (DragEventData data) 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 (const ModalViewSession& session);
void clearModalViewSessions ();
void dispatchKeyboardEvent (KeyboardEvent& event);
void dispatchMouseEvent (MouseEvent& event);
void dispatchMouseDownEvent (MouseDownEvent& event);
void dispatchMouseMoveEvent (MouseMoveEvent& event);
void dispatchMouseUpEvent (MouseUpEvent& event);
void dispatchEvent (CView* view, Event& event);
void dispatchEventToChildren (Event& event);
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;
virtual void onMouseEvent (MouseEvent& event, CFrame* frame) = 0;
};
#if VSTGUI_ENABLE_DEPRECATED_METHODS
//-----------------------------------------------------------------------------
class OldMouseObserverAdapter : public IMouseObserver
{
public:
void onMouseEntered (CView* view, CFrame* frame) override {}
void onMouseExited (CView* view, CFrame* frame) override {}
void onMouseEvent (MouseEvent& event, CFrame* frame) override;
virtual CMouseEventResult onMouseMoved (CFrame* frame, const CPoint& where, const CButtonState& buttons);
virtual CMouseEventResult onMouseDown (CFrame* frame, const CPoint& where, const CButtonState& buttons);
};
#endif
//-----------------------------------------------------------------------------
// IKeyboardHook Declaration
//! @brief generic keyboard hook interface for CFrame
//! @ingroup new_in_4_0
//-----------------------------------------------------------------------------
class IKeyboardHook
{
public:
virtual ~IKeyboardHook () noexcept = default;
/** the event will not be dispatched further if it is consumed. */
virtual void onKeyboardEvent (KeyboardEvent& event, CFrame* frame) = 0;
};
#if VSTGUI_ENABLE_DEPRECATED_METHODS
//------------------------------------------------------------------------
class OldKeyboardHookAdapter : public IKeyboardHook
{
public:
virtual int32_t onKeyDown (const VstKeyCode& code, CFrame* frame) = 0;
virtual int32_t onKeyUp (const VstKeyCode& code, CFrame* frame) = 0;
private:
void onKeyboardEvent (KeyboardEvent& event, CFrame* frame) override;
};
#endif
//-----------------------------------------------------------------------------
// 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
+65
View File
@@ -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
#include "cgradient.h"
#include "platform/iplatformgradient.h"
#include "platform/platformfactory.h"
namespace VSTGUI {
//-----------------------------------------------------------------------------
CGradient* CGradient::create (const GradientColorStopMap& colorStopMap)
{
if (auto pg = getPlatformFactory ().createGradient ())
{
pg->setColorStops (colorStopMap);
return new CGradient (std::move (pg));
}
return nullptr;
}
//-----------------------------------------------------------------------------
CGradient* CGradient::create (double color1Start, double color2Start, const CColor& color1,
const CColor& color2)
{
GradientColorStopMap map;
map.emplace (color1Start, color1);
map.emplace (color2Start, color2);
return create (map);
}
//-----------------------------------------------------------------------------
CGradient::CGradient (PlatformGradientPtr&& platformGradient)
: platformGradient (std::move (platformGradient))
{
}
//-----------------------------------------------------------------------------
CGradient::~CGradient () noexcept = default;
//-----------------------------------------------------------------------------
void CGradient::addColorStop (double start, const CColor& color)
{
addColorStop (std::make_pair (start, color));
}
//-----------------------------------------------------------------------------
void CGradient::addColorStop (const GradientColorStop& colorStop)
{
platformGradient->addColorStop (colorStop);
}
//-----------------------------------------------------------------------------
const GradientColorStopMap& CGradient::getColorStops () const
{
return platformGradient->getColorStops ();
}
//-----------------------------------------------------------------------------
const PlatformGradientPtr& CGradient::getPlatformGradient () const
{
return platformGradient;
}
} // VSTGUI
+43
View File
@@ -0,0 +1,43 @@
// 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:
static CGradient* create (const GradientColorStopMap& colorStopMap);
static CGradient* create (double color1Start, double color2Start, const CColor& color1, const CColor& color2);
CGradient (PlatformGradientPtr&& platformGradient);
~CGradient () noexcept override;
//-----------------------------------------------------------------------------
/// @name Member Access
//-----------------------------------------------------------------------------
//@{
void addColorStop (double start, const CColor& color);
void addColorStop (const GradientColorStop& colorStop);
const GradientColorStopMap& getColorStops () const;
//@}
const PlatformGradientPtr& getPlatformGradient () const;
protected:
PlatformGradientPtr platformGradient;
};
} // 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,330 @@
// 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 "cgradient.h"
#include "cgraphicspath.h"
#include "cgraphicstransform.h"
#include "platform/iplatformgraphicspath.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& inPath, CGraphicsTransform* transformation)
{
for (auto e : inPath.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 ();
}
//-----------------------------------------------------------------------------
CGraphicsPath::CGraphicsPath (const PlatformGraphicsPathFactoryPtr& factory,
PlatformGraphicsPathPtr&& path)
: factory (factory), path (std::move (path))
{
}
//------------------------------------------------------------------------
CGraphicsPath::CGraphicsPath (const CGraphicsPath& p) : elements (p.elements), factory (p.factory)
{
}
//-----------------------------------------------------------------------------
CGraphicsPath::~CGraphicsPath () noexcept {}
//-----------------------------------------------------------------------------
CGradient* CGraphicsPath::createGradient (double color1Start, double color2Start,
const CColor& color1, const CColor& color2)
{
return CGradient::create (color1Start, color2Start, color1, color2);
}
//-----------------------------------------------------------------------------
void CGraphicsPath::makePlatformGraphicsPath (PlatformGraphicsPathFillMode fillMode)
{
if (!factory)
return;
path = factory->createPath (fillMode);
if (!path)
return;
for (const auto& e : elements)
{
switch (e.type)
{
case Element::kArc:
{
path->addArc (rect2CRect (e.instruction.arc.rect), e.instruction.arc.startAngle,
e.instruction.arc.endAngle, e.instruction.arc.clockwise);
break;
}
case Element::kEllipse:
{
path->addEllipse (rect2CRect (e.instruction.rect));
break;
}
case Element::kRect:
{
path->addRect (rect2CRect (e.instruction.rect));
break;
}
case Element::kLine:
{
path->addLine (point2CPoint (e.instruction.point));
break;
}
case Element::kBezierCurve:
{
path->addBezierCurve (point2CPoint (e.instruction.curve.control1),
point2CPoint (e.instruction.curve.control2),
point2CPoint (e.instruction.curve.end));
break;
}
case Element::kBeginSubpath:
{
path->beginSubpath (point2CPoint (e.instruction.point));
break;
}
case Element::kCloseSubpath:
{
path->closeSubpath ();
break;
}
}
}
path->finishBuilding ();
}
//-----------------------------------------------------------------------------
bool CGraphicsPath::ensurePlatformGraphicsPathValid (PlatformGraphicsPathFillMode fillMode)
{
if (path == nullptr || (path->getFillMode () != PlatformGraphicsPathFillMode::Ignored &&
path->getFillMode () != fillMode))
{
makePlatformGraphicsPath (fillMode);
}
return path != nullptr;
}
//-----------------------------------------------------------------------------
void CGraphicsPath::dirty ()
{
path = nullptr;
}
//-----------------------------------------------------------------------------
bool CGraphicsPath::hitTest (const CPoint& p, bool evenOddFilled, CGraphicsTransform* transform)
{
ensurePlatformGraphicsPathValid (evenOddFilled ? PlatformGraphicsPathFillMode::Alternate
: PlatformGraphicsPathFillMode::Winding);
return path ? path->hitTest (p, evenOddFilled, transform) : false;
}
//-----------------------------------------------------------------------------
CPoint CGraphicsPath::getCurrentPosition ()
{
CPoint res;
if (!elements.empty ())
{
const auto& e = elements.back ();
switch (e.type)
{
case Element::kBeginSubpath:
{
res = point2CPoint (e.instruction.point);
break;
}
case Element::kCloseSubpath:
{
// TODO: find opening point
break;
}
case Element::kArc:
{
// TODO: calculate end point
break;
}
case Element::kEllipse:
{
res = {e.instruction.rect.left +
(e.instruction.rect.right - e.instruction.rect.left) / 2.,
e.instruction.rect.bottom};
break;
}
case Element::kRect:
{
res = rect2CRect (e.instruction.rect).getTopLeft ();
break;
}
case Element::kLine:
{
res = point2CPoint (e.instruction.point);
break;
}
case Element::kBezierCurve:
{
res = point2CPoint (e.instruction.curve.end);
break;
}
}
}
return res;
}
//-----------------------------------------------------------------------------
CRect CGraphicsPath::getBoundingBox ()
{
ensurePlatformGraphicsPathValid (path ? path->getFillMode ()
: PlatformGraphicsPathFillMode::Winding);
return path ? path->getBoundingBox () : CRect ();
}
//-----------------------------------------------------------------------------
const PlatformGraphicsPathPtr&
CGraphicsPath::getPlatformPath (PlatformGraphicsPathFillMode fillMode)
{
ensurePlatformGraphicsPathValid (fillMode);
return path;
}
} // VSTGUI
+167
View File
@@ -0,0 +1,167 @@
// 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
*/
CGradient* createGradient (double color1Start, double color2Start, const CColor& color1,
const CColor& color2);
//@}
//-----------------------------------------------------------------------------
/// @name Adding Elements
//-----------------------------------------------------------------------------
//@{
/** add an arc to the path. Begins a new subpath if no elements were added before. */
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. */
void addEllipse (const CRect& rect);
/** add a rectangle to the path. Begins a new subpath if no elements were added before. */
void addRect (const CRect& rect);
/** add another path to the path. Begins a new subpath if no elements were added before. */
void addPath (const CGraphicsPath& path, CGraphicsTransform* transformation = nullptr);
/** add a line to the path. A subpath must begin before */
void addLine (const CPoint& to);
/** add a bezier curve to the path. A subpath must begin before */
void addBezierCurve (const CPoint& control1, const CPoint& control2, const CPoint& end);
/** begin a new subpath. */
void beginSubpath (const CPoint& start);
/** close a subpath. A straight line will be added from the current point to the start point. */
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
//-----------------------------------------------------------------------------
//@{
bool hitTest (const CPoint& p, bool evenOddFilled = false,
CGraphicsTransform* transform = nullptr);
//@}
//-----------------------------------------------------------------------------
/// @name States
//-----------------------------------------------------------------------------
//@{
CPoint getCurrentPosition ();
CRect getBoundingBox ();
//@}
CGraphicsPath (const PlatformGraphicsPathFactoryPtr& factory, PlatformGraphicsPathPtr&& path);
CGraphicsPath (const CGraphicsPath& p);
~CGraphicsPath () noexcept override;
const PlatformGraphicsPathPtr& getPlatformPath (PlatformGraphicsPathFillMode fillMode);
protected:
void makePlatformGraphicsPath (PlatformGraphicsPathFillMode fillMode);
bool ensurePlatformGraphicsPathValid (PlatformGraphicsPathFillMode fillMode);
void dirty ();
/// @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;
};
static void CRect2Rect (const CRect& rect, CGraphicsPath::Rect& r) {r.left = rect.left;r.right = rect.right;r.top = rect.top;r.bottom = rect.bottom;}
static void CPoint2Point (const CPoint& point, CGraphicsPath::Point& p) {p.x = point.x;p.y = point.y;}
static CRect rect2CRect (const Rect& r) { return CRect (r.left, r.top, r.right, r.bottom); }
static CPoint point2CPoint (const Point& p) { return CPoint (p.x, p.y); }
/// @endcond
using ElementList = std::vector<Element>;
ElementList elements;
PlatformGraphicsPathFactoryPtr factory;
PlatformGraphicsPathPtr path;
};
} // 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,111 @@
// 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 "crect.h"
#include <vector>
namespace VSTGUI {
//-----------------------------------------------------------------------------
struct CInvalidRectList
{
using RectList = std::vector<CRect>;
bool add (const CRect& r);
RectList::iterator begin () { return list.begin (); }
RectList::iterator end () { return list.end (); }
RectList::const_iterator begin () const { return list.begin (); }
RectList::const_iterator end () const { return list.end (); }
void erase (RectList::iterator it) { list.erase (it); }
void clear () { list.clear (); }
const RectList& data () const { return list; }
bool empty () const { return list.empty (); }
private:
RectList list;
};
//-----------------------------------------------------------------------------
inline bool CInvalidRectList::add (const CRect& r)
{
for (auto it = list.begin (), end = list.end (); it != end; ++it)
{
// the same rectangle is already in the list
if (*it == r)
return false;
// the new rectangle is part of one already in the list
if (it->rectInside (r))
return false;
// if the new rectangle contains one of the previous rectangles
if (r.rectInside (*it))
{
list.erase (it);
return add (r);
}
// now check if the combined rect has the same or less area as both rects together
auto area1 = r.getWidth () * r.getHeight ();
auto area2 = it->getWidth () * it->getHeight ();
CRect jr (*it);
jr.unite (r);
auto joinedArea = jr.getWidth () * jr.getHeight ();
if (joinedArea <= (area1 + area2))
{
list.erase (it);
return add (jr);
}
}
list.emplace_back (r);
return true;
}
//-----------------------------------------------------------------------------
inline void joinNearbyInvalidRects (CInvalidRectList& list, CCoord maxDistance)
{
for (auto it = list.begin (); it != list.end (); ++it)
{
for (auto it2 = list.begin (); it2 != list.end (); ++it2)
{
if (it2 == it)
continue;
if (it->left == it2->left && it->right == it2->right)
{
CCoord distance;
if (it->bottom < it2->top)
distance = it2->top - it->bottom;
else
distance = it->top - it2->bottom;
if (distance <= maxDistance)
{
it->unite (*it2);
list.erase (it2);
joinNearbyInvalidRects (list, maxDistance);
return;
}
}
if (it->top == it2->top && it->bottom == it2->bottom)
{
CCoord distance;
if (it->right < it2->left)
distance = it2->left - it->right;
else
distance = it->left - it2->right;
if (distance <= maxDistance)
{
it->unite (*it2);
list.erase (it2);
joinNearbyInvalidRects (list, maxDistance);
return;
}
}
}
}
}
//-----------------------------------------------------------------------------
} // VSTGUI
@@ -0,0 +1,260 @@
// 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 "coffscreencontext.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 ()
{
if (!layer)
return;
CRect newSize = getViewSize ();
getTransform ().transform (newSize);
auto frame = getFrame ();
auto* parent = static_cast<CViewContainer*> (getParentView ());
while (parent && parent != frame)
{
CRect parentSize = parent->getViewSize ();
parent->getTransform ().transform (newSize);
newSize.offset (parentSize.left, parentSize.top);
newSize.bound (parentSize);
parent = static_cast<CViewContainer*> (parent->getParentView ());
}
frame->getTransform ().transform (newSize);
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 ()->unregisterScaleFactorChangedListener (this);
}
return CViewContainer::removed (parent);
}
//-----------------------------------------------------------------------------
bool CLayeredViewContainer::attached (CView* parent)
{
if (isAttached ())
return false;
setParentView (parent);
setParentFrame (parent->getFrame ());
if (auto frame = getFrame ())
{
while (parent && dynamic_cast<CFrame*>(parent) == nullptr)
{
parentLayerView = dynamic_cast<CLayeredViewContainer*>(parent);
if (parentLayerView)
{
break;
}
parent = parent->getParentView ();
}
layer = frame->getPlatformFrame ()->createPlatformViewLayer (this, parentLayerView ? parentLayerView->layer : nullptr);
if (layer)
{
layer->setZIndex (zIndex);
layer->setAlpha (getAlphaValue ());
updateLayerSize ();
frame->registerScaleFactorChangedListener (this);
}
}
parent = getParentView ();
registerListeners (true);
setParentView (nullptr);
setParentFrame (nullptr);
return CViewContainer::attached (parent);
}
//-----------------------------------------------------------------------------
void CLayeredViewContainer::registerListeners (bool state)
{
auto* 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)
{
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);
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)
{
auto drawsIntoBitmap = false;
if (auto offscreenContext = dynamic_cast<COffscreenContext*> (pContext))
drawsIntoBitmap = offscreenContext->getBitmap () != nullptr;
if (!layer || drawsIntoBitmap)
CViewContainer::drawRect (pContext, updateRect);
}
//-----------------------------------------------------------------------------
void CLayeredViewContainer::drawViewLayerRects (const PlatformGraphicsDeviceContextPtr& context,
double scaleFactor, const std::vector<CRect>& rects)
{
CGraphicsTransform drawTransform = getDrawTransform ();
CRect visibleSize = getVisibleViewSize ();
CRect viewSize = getViewSize ();
CPoint p (viewSize.left < 0 ? viewSize.left - visibleSize.left : visibleSize.left,
viewSize.top < 0 ? viewSize.top - visibleSize.top : visibleSize.top);
auto surfaceSize = getViewSize ();
surfaceSize.originize ();
CDrawContext drawContext (context, surfaceSize, scaleFactor);
CDrawContext::Transform transform (
drawContext, drawTransform * CGraphicsTransform ().translate (-p.x, -p.y));
for (auto dirtyRect : rects)
{
drawTransform.inverse ().transform (dirtyRect);
dirtyRect.offset (p.x, p.y);
drawContext.saveGlobalState ();
drawContext.setClipRect (dirtyRect);
CViewContainer::drawRect (&drawContext, dirtyRect);
drawContext.restoreGlobalState ();
}
}
//-----------------------------------------------------------------------------
CGraphicsTransform CLayeredViewContainer::getDrawTransform () const
{
using ParentViews = std::list<CViewContainer*>;
CGraphicsTransform transform;
ParentViews parents;
auto frame = getFrame ();
auto* parent = static_cast<CViewContainer*> (getParentView ());
while (parent && parent != frame)
{
parents.push_front (parent);
parent = static_cast<CViewContainer*> (parent->getParentView ());
}
for (const auto& p : parents)
transform = p->getTransform () * transform;
auto self = static_cast<const CViewContainer*> (this);
if (self)
transform = self->getTransform () * transform;
if (frame)
transform = frame->getTransform () * transform;
return transform;
}
//-----------------------------------------------------------------------------
void CLayeredViewContainer::onScaleFactorChanged (CFrame* frame, double newScaleFactor)
{
if (layer)
layer->onScaleFactorChanged (newScaleFactor);
}
}
@@ -0,0 +1,59 @@
// 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 drawViewLayerRects (const PlatformGraphicsDeviceContextPtr& context, double scaleFactor,
const std::vector<CRect>& rects) 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
+91
View File
@@ -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);
}
+69
View File
@@ -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,99 @@
// 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/platformfactory.h"
#include "platform/iplatformgraphicsdevice.h"
namespace VSTGUI {
//-----------------------------------------------------------------------------
COffscreenContext::COffscreenContext (CBitmap* bitmap)
: CDrawContext (CRect (0, 0, bitmap->getWidth (), bitmap->getHeight ()))
, bitmap (bitmap)
{
}
//-----------------------------------------------------------------------------
COffscreenContext::COffscreenContext (const CRect& surfaceRect)
: CDrawContext (surfaceRect)
{
}
//-----------------------------------------------------------------------------
COffscreenContext::COffscreenContext (const PlatformGraphicsDeviceContextPtr device,
const CRect& surfaceRect,
const PlatformBitmapPtr& platformBitmap)
: CDrawContext (device, surfaceRect, platformBitmap->getScaleFactor ())
, bitmap (makeOwned<CBitmap> (platformBitmap))
{
}
//-----------------------------------------------------------------------------
void COffscreenContext::copyFrom (CDrawContext *pContext, CRect destRect, CPoint srcOffset)
{
if (bitmap)
bitmap->draw (pContext, destRect, srcOffset);
}
#if VSTGUI_ENABLE_DEPRECATED_METHODS
//-----------------------------------------------------------------------------
SharedPointer<COffscreenContext> COffscreenContext::create (CFrame* frame, CCoord width, CCoord height, double scaleFactor)
{
return create ({width, height}, scaleFactor);
}
#endif
//-----------------------------------------------------------------------------
SharedPointer<COffscreenContext> COffscreenContext::create (const CPoint& size, double scaleFactor)
{
if (size.x >= 1. && size.y >= 1.)
{
if (auto graphicsDevice =
getPlatformFactory ().getGraphicsDeviceFactory ().getDeviceForScreen (
DefaultScreenIdentifier))
{
if (auto bitmap = getPlatformFactory ().createBitmap (size * scaleFactor))
{
bitmap->setScaleFactor (scaleFactor);
if (auto context = graphicsDevice->createBitmapContext (bitmap))
{
CRect surfaceRect (CPoint (), size * scaleFactor);
return makeOwned<COffscreenContext> (context, surfaceRect, bitmap);
}
}
}
}
return nullptr;
}
//-----------------------------------------------------------------------------
CCoord COffscreenContext::getWidth () const
{
return bitmap ? bitmap->getWidth () : 0.;
}
//-----------------------------------------------------------------------------
CCoord COffscreenContext::getHeight () const
{
return bitmap ? bitmap->getHeight () : 0.;
}
//-----------------------------------------------------------------------------
SharedPointer<CBitmap> renderBitmapOffscreen (
const CPoint& size, double scaleFactor,
const std::function<void (CDrawContext& drawContext)> drawCallback)
{
auto context = COffscreenContext::create (size, scaleFactor);
if (!context)
return nullptr;
context->beginDraw ();
drawCallback (*context);
context->endDraw ();
return shared (context->getBitmap ());
}
} // VSTGUI
@@ -0,0 +1,99 @@
// 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 (const CPoint& size, double scaleFactor = 1.);
VSTGUI_DEPRECATED (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; }
COffscreenContext (const PlatformGraphicsDeviceContextPtr device, const CRect& surfaceRect,
const PlatformBitmapPtr& platformBitmap);
protected:
explicit COffscreenContext (CBitmap* bitmap);
explicit COffscreenContext (const CRect& surfaceRect);
SharedPointer<CBitmap> bitmap;
};
//-----------------------------------------------------------------------------
/** Render a bitmap offscreen
* @param size size of the bitmap
* @param scaleFactor scale factor (bitmap size will be scaled by this)
* @param drawFunction user supplied draw function
* @return bitmap pointer on success and nullptr on failure
*/
SharedPointer<CBitmap> renderBitmapOffscreen (
const CPoint& size, double scaleFactor,
const std::function<void (CDrawContext& drawContext)> drawFunction);
} // VSTGUI
@@ -0,0 +1,294 @@
// 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 "../algorithm.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). Use a CMultiFrameBitmap for its background bitmap.
*/
// 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
*/
//------------------------------------------------------------------------
CAutoAnimation::CAutoAnimation (const CRect& size, IControlListener* listener, int32_t tag,
CBitmap* background)
: CControl (size, listener, tag, background)
{
#if VSTGUI_ENABLE_DEPRECATED_METHODS
heightOfOneImage = size.getHeight ();
setNumSubPixmaps (background ? (int32_t)(background->getHeight () / heightOfOneImage) : 0);
totalHeightOfBitmap = heightOfOneImage * getNumSubPixmaps ();
#else
#endif
}
#if VSTGUI_ENABLE_DEPRECATED_METHODS
//------------------------------------------------------------------------
/**
* 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)
{
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)
{
setNumSubPixmaps (subPixmaps);
setHeightOfOneImage (heightOfOneImage);
totalHeightOfBitmap = heightOfOneImage * getNumSubPixmaps ();
setMin (0.f);
setMax ((float)(totalHeightOfBitmap - (heightOfOneImage + 1.)));
}
//------------------------------------------------------------------------
void CAutoAnimation::setBitmapOffset (const CPoint& off)
{
offset = off;
invalid ();
}
//------------------------------------------------------------------------
CPoint CAutoAnimation::getBitmapOffset () const { return offset; }
#endif // VSTGUI_ENABLE_DEPRECATED_METHODS
//------------------------------------------------------------------------
CAutoAnimation::CAutoAnimation (const CAutoAnimation& v)
: CControl (v)
#if VSTGUI_ENABLE_DEPRECATED_METHODS
, offset (v.offset)
, totalHeightOfBitmap (v.totalHeightOfBitmap)
#endif
{
#if VSTGUI_ENABLE_DEPRECATED_METHODS
setNumSubPixmaps (v.subPixmaps);
setHeightOfOneImage (v.heightOfOneImage);
#endif
}
//------------------------------------------------------------------------
bool CAutoAnimation::isWindowOpened () const { return bWindowOpened; }
//------------------------------------------------------------------------
void CAutoAnimation::draw (CDrawContext *pContext)
{
if (isWindowOpened ())
{
if (auto bitmap = getDrawBackground ())
{
if (auto mfb = dynamic_cast<CMultiFrameBitmap*> (bitmap))
{
auto frameIndex = getMultiFrameBitmapIndex (*mfb, getValueNormalized ());
mfb->drawFrame (pContext, frameIndex, getViewSize ().getTopLeft ());
}
else
{
#if VSTGUI_ENABLE_DEPRECATED_METHODS
CPoint where;
where.y = (int32_t)value + offset.y;
where.x = offset.x;
bitmap->draw (pContext, getViewSize (), where);
#else
CView::draw (pContext);
#endif
}
}
}
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;
}
//------------------------------------------------------------------------
bool CAutoAnimation::attached (CView* parent)
{
if (CControl::attached (parent))
{
if (animationFrameTime > 0 && isWindowOpened ())
startTimer ();
return true;
}
return false;
}
//------------------------------------------------------------------------
bool CAutoAnimation::removed (CView* parent)
{
timer = nullptr;
return CControl::removed (parent);
}
//------------------------------------------------------------------------
void CAutoAnimation::startTimer ()
{
if (animationFrameTime > 0)
{
timer = makeOwned<CVSTGUITimer> (
[this] (auto*) {
nextPixmap ();
invalid ();
},
animationFrameTime, true);
}
}
//------------------------------------------------------------------------
void CAutoAnimation::openWindow ()
{
bWindowOpened = true;
if (isAttached ())
startTimer ();
}
//------------------------------------------------------------------------
void CAutoAnimation::closeWindow ()
{
bWindowOpened = false;
timer = nullptr;
}
//------------------------------------------------------------------------
void CAutoAnimation::updateMinMaxFromBackground ()
{
if (auto bitmap = getDrawBackground ())
{
if (auto mfb = dynamic_cast<CMultiFrameBitmap*> (bitmap))
{
auto numFrames = getMultiFrameBitmapRangeLength (*mfb);
setMin (0.f);
setMax (numFrames);
#if VSTGUI_ENABLE_DEPRECATED_METHODS
heightOfOneImage = mfb->getFrameSize ().y;
totalHeightOfBitmap = heightOfOneImage * numFrames;
#endif
}
}
}
//------------------------------------------------------------------------
void CAutoAnimation::setBackground (CBitmap* background)
{
CControl::setBackground (background);
updateMinMaxFromBackground ();
}
//------------------------------------------------------------------------
void CAutoAnimation::nextPixmap ()
{
if (auto bitmap = getDrawBackground ())
{
if (dynamic_cast<CMultiFrameBitmap*> (bitmap))
{
if (getValue () == getMax ())
setValue (getMin ());
else
setValue (getValue () + 1.f);
return;
}
}
#if VSTGUI_ENABLE_DEPRECATED_METHODS
value += (float)heightOfOneImage;
if (value >= (totalHeightOfBitmap - heightOfOneImage))
value = 0;
#endif
}
//------------------------------------------------------------------------
void CAutoAnimation::previousPixmap ()
{
if (auto bitmap = getDrawBackground ())
{
if (dynamic_cast<CMultiFrameBitmap*> (bitmap))
{
if (getValue () == getMin ())
setValue (getMax ());
else
setValue (getValue () - 1.f);
return;
}
}
#if VSTGUI_ENABLE_DEPRECATED_METHODS
value -= (float)heightOfOneImage;
if (value < 0.f)
value = (float)(totalHeightOfBitmap - heightOfOneImage - 1);
#endif
}
//------------------------------------------------------------------------
void CAutoAnimation::setAnimationTime (uint32_t animationTime)
{
animationFrameTime = animationTime;
if (timer)
startTimer ();
}
//------------------------------------------------------------------------
uint32_t CAutoAnimation::getAnimationTime () const { return animationFrameTime; }
} // VSTGUI
@@ -0,0 +1,90 @@
// 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 "../cbitmap.h"
#include "../cvstguitimer.h"
namespace VSTGUI {
//-----------------------------------------------------------------------------
// CAutoAnimation Declaration
//!
/// @ingroup controls uses_multi_frame_bitmaps
//-----------------------------------------------------------------------------
class CAutoAnimation : public CControl,
public MultiFrameBitmapView<CAutoAnimation>
#if VSTGUI_ENABLE_DEPRECATED_METHODS
,
public IMultiBitmapControl
#endif
{
public:
CAutoAnimation (const CRect& size, IControlListener* listener, int32_t tag,
CBitmap* background);
CAutoAnimation (const CAutoAnimation& autoAnimation);
void draw (CDrawContext*) override;
CMouseEventResult onMouseDown (CPoint& where, const CButtonState& buttons) override;
bool attached (CView* parent) override;
bool removed (CView* parent) override;
//-----------------------------------------------------------------------------
/// @name CAutoAnimation Methods
//-----------------------------------------------------------------------------
//@{
/** enabled drawing */
virtual void openWindow ();
/** disable drawing */
virtual void closeWindow ();
/** the next sub bitmap should be displayed */
virtual void nextPixmap ();
/** the previous sub bitmap should be displayed */
virtual void previousPixmap ();
bool isWindowOpened () const;
void setAnimationTime (uint32_t animationTime);
uint32_t getAnimationTime () const;
//@}
void setBackground (CBitmap* background) override;
#if VSTGUI_ENABLE_DEPRECATED_METHODS
CAutoAnimation (const CRect& size, IControlListener* listener, int32_t tag, CBitmap* background,
const CPoint& offset);
CAutoAnimation (const CRect& size, IControlListener* listener, int32_t tag, int32_t subPixmaps,
CCoord heightOfOneImage, CBitmap* background,
const CPoint& offset = CPoint (0, 0));
void setNumSubPixmaps (int32_t numSubPixmaps) override
{
IMultiBitmapControl::setNumSubPixmaps (numSubPixmaps);
invalid ();
}
void setBitmapOffset (const CPoint& off);
CPoint getBitmapOffset () const;
#endif
CLASS_METHODS(CAutoAnimation, CControl)
protected:
~CAutoAnimation () noexcept override = default;
void updateMinMaxFromBackground ();
void startTimer ();
uint32_t animationFrameTime {0u};
SharedPointer<CVSTGUITimer> timer;
bool bWindowOpened {false};
#if VSTGUI_ENABLE_DEPRECATED_METHODS
CPoint offset {};
CCoord totalHeightOfBitmap {0};
#endif
};
} // VSTGUI
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,288 @@
// 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;
void onKeyboardEvent (KeyboardEvent& event) 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,
/** do not limit the box drawing to the cap height */
kIgnoreCapHeightOnDraw = 1 << 2,
};
//-----------------------------------------------------------------------------
/// @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;
void onKeyboardEvent (KeyboardEvent& event) 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 uses_multi_frame_bitmaps
//-----------------------------------------------------------------------------
class CKickButton : public CControl,
public MultiFrameBitmapView<CKickButton>
#if VSTGUI_ENABLE_DEPRECATED_METHODS
,
public IMultiBitmapControl
#endif
{
public:
CKickButton (const CRect& size, IControlListener* listener, int32_t tag, CBitmap* background);
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;
void onKeyboardEvent (KeyboardEvent& event) override;
bool sizeToFit () override;
#if VSTGUI_ENABLE_DEPRECATED_METHODS
void setNumSubPixmaps (int32_t numSubPixmaps) override { IMultiBitmapControl::setNumSubPixmaps (numSubPixmaps); invalid (); }
CKickButton (const CRect& size, IControlListener* listener, int32_t tag,
CCoord heightOfOneImage, CBitmap* background,
const CPoint& offset = CPoint (0, 0));
#endif
CLASS_METHODS(CKickButton, CControl)
protected:
~CKickButton () noexcept override = default;
#if VSTGUI_ENABLE_DEPRECATED_METHODS
CPoint offset {};
#endif
};
//-----------------------------------------------------------------------------
// 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;
void onKeyboardEvent (KeyboardEvent& event) override;
CLASS_METHODS_NOCOPY (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,593 @@
// 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 ())
setHandleSizePrivate (size.getHeight (), size.getHeight ());
else
setHandleSizePrivate (size.getWidth (), size.getWidth ());
const 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 = getControlSizePrivate ();
auto sliderSize = getHandleSizePrivate ();
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)
{
for (auto item : drag)
{
if (item.type != IDataPackage::kText)
continue;
std::string colorString (static_cast<const char*> (item.data), item.dataSize);
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 dragColor;
if (dragContainerHasColor (data.drag, &dragColor))
{
setColor (dragColor);
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)
{
snprintf (string, 255, "%.3f", value);
return true;
}
//-----------------------------------------------------------------------------
bool CColorChooser::convertColorValueToString (float value, char string[256], CParamDisplay::ValueToStringUserData* userData)
{
snprintf (string, 255, "%d", (int32_t)(value * 255.f));
return true;
}
//-----------------------------------------------------------------------------
bool CColorChooser::convertAngleToString (float value, char string[256], CParamDisplay::ValueToStringUserData* userData)
{
snprintf (string, 255, "%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);
auto* 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.setNormRed (control->getValue ());
break;
}
case kGreenTag:
{
color.setNormGreen (control->getValue ());
break;
}
case kBlueTag:
{
color.setNormBlue (control->getValue ());
break;
}
case kAlphaTag:
{
color.setNormAlpha (control->getValue ());
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.normRed<float> ());
greenSlider->setValue (color.normGreen<float> ());
blueSlider->setValue (color.normBlue<float> ());
alphaSlider->setValue (color.normAlpha<float> ());
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 = nullptr, 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,390 @@
// 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 "../algorithm.h"
#include "../events.h"
#include "../cframe.h"
#include "../cgraphicspath.h"
#include "../cvstguitimer.h"
#include "../dispatchlist.h"
#include "../iviewlistener.h"
#include <cassert>
#define VSTGUI_CCONTROL_LOG_EDITING 0 //DEBUG
namespace VSTGUI {
//------------------------------------------------------------------------
struct CControl::Impl : ViewEventListenerAdapter
{
using SubListenerDispatcher = DispatchList<IControlListener*>;
SubListenerDispatcher subListeners;
float oldValue {1};
float defaultValue {0.5};
float vmin {0};
float vmax {1.f};
float wheelInc {0.1f};
int32_t editing {0};
void viewOnEvent (CView* view, Event& event) override
{
if (event.type != EventType::MouseDown)
return;
auto control = static_cast<CControl*> (view);
auto& mouseDownEvent = castMouseDownEvent (event);
if (CControl::CheckDefaultValueEventFunc (control, mouseDownEvent))
{
auto defValue = control->getDefaultValue ();
if (defValue != control->getValue ())
{
control->beginEdit ();
control->setValue (defValue);
control->valueChanged ();
control->endEdit ();
control->setDirty ();
}
mouseDownEvent.consumed = true;
mouseDownEvent.ignoreFollowUpMoveAndUpEvents (true);
}
}
};
//------------------------------------------------------------------------
// 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)
, value (0)
{
impl = std::unique_ptr<Impl> (new Impl);
setTransparency (false);
setMouseEnabled (true);
setBackground (pBackground);
registerViewEventListener (impl.get ());
}
//------------------------------------------------------------------------
CControl::CControl (const CControl& c)
: CView (c)
, listener (c.listener)
, tag (c.tag)
, value (c.value)
{
impl = std::unique_ptr<Impl> (new Impl);
impl->oldValue = c.impl->oldValue;
impl->defaultValue = c.impl->defaultValue;
impl->vmin = c.impl->vmin;
impl->vmax = c.impl->vmax;
impl->wheelInc = c.impl->wheelInc;
registerViewEventListener (impl.get ());
}
//------------------------------------------------------------------------
CControl::~CControl () noexcept
{
unregisterViewEventListener (impl.get ());
}
//------------------------------------------------------------------------
void CControl::registerControlListener (IControlListener* subListener)
{
vstgui_assert (listener != subListener, "the subListener is already the main listener");
impl->subListeners.add (subListener);
}
//------------------------------------------------------------------------
void CControl::unregisterControlListener (IControlListener* subListener)
{
impl->subListeners.remove (subListener);
}
//------------------------------------------------------------------------
void CControl::setWheelInc (float val)
{
impl->wheelInc = val;
}
//------------------------------------------------------------------------
float CControl::getWheelInc () const
{
return impl->wheelInc;
}
//------------------------------------------------------------------------
void CControl::setMin (float val)
{
impl->vmin = val;
bounceValue ();
}
//------------------------------------------------------------------------
float CControl::getMin () const
{
return impl->vmin;
}
//------------------------------------------------------------------------
void CControl::setMax (float val)
{
impl->vmax = val;
bounceValue ();
}
//------------------------------------------------------------------------
float CControl::getMax () const
{
return impl->vmax;
}
//------------------------------------------------------------------------
void CControl::setOldValue (float val)
{
impl->oldValue = val;
}
//------------------------------------------------------------------------
float CControl::getOldValue (void) const
{
return impl->oldValue;
}
//------------------------------------------------------------------------
void CControl::setDefaultValue (float val)
{
impl->defaultValue = val;
}
//------------------------------------------------------------------------
float CControl::getDefaultValue (void) const
{
return impl->defaultValue;
}
//------------------------------------------------------------------------
void CControl::setTag (int32_t val)
{
if (listener)
listener->controlTagWillChange (this);
tag = val;
if (listener)
listener->controlTagDidChange (this);
}
//------------------------------------------------------------------------
bool CControl::isEditing () const
{
return impl->editing > 0;
}
//------------------------------------------------------------------------
void CControl::beginEdit ()
{
// begin of edit parameter
impl->editing++;
if (impl->editing == 1)
{
if (listener)
listener->controlBeginEdit (this);
impl->subListeners.forEach ([this] (IControlListener* l) { l->controlBeginEdit (this); });
if (getFrame ())
getFrame ()->beginEdit (tag);
}
#if VSTGUI_CCONTROL_LOG_EDITING
DebugPrint("beginEdit [%d] - %d\n", tag, impl->editing);
#endif
}
//------------------------------------------------------------------------
void CControl::endEdit ()
{
if (!isEditing ())
return;
--impl->editing;
if (impl->editing == 0)
{
if (getFrame ())
getFrame ()->endEdit (tag);
if (listener)
listener->controlEndEdit (this);
impl->subListeners.forEach ([this] (IControlListener* l) { l->controlEndEdit (this); });
}
#if VSTGUI_CCONTROL_LOG_EDITING
DebugPrint("endEdit [%d] - %d\n", tag, impl->editing);
#endif
}
//------------------------------------------------------------------------
void CControl::setValue (float val) { value = clamp (val, getMin (), getMax ()); }
//------------------------------------------------------------------------
void CControl::setValueNormalized (float val)
{
if (getRange () == 0.f)
{
value = getMin ();
return;
}
val = clampNorm (val);
setValue (normalizedToPlain (val, getMin (), getMax ()));
}
//------------------------------------------------------------------------
float CControl::getValueNormalized () const
{
auto range = getRange ();
if (range == 0.f)
return 0.f;
return plainToNormalized<float> (value, getMin (), getMax ());
}
//------------------------------------------------------------------------
void CControl::valueChanged ()
{
if (listener)
listener->valueChanged (this);
impl->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 () { value = clamp (value, getMin (), getMax ()); }
#if VSTGUI_ENABLE_DEPRECATED_METHODS
//------------------------------------------------------------------------
CControl::CheckDefaultValueFuncT CControl::CheckDefaultValueFunc = [] (CControl*,
CButtonState button) {
#if TARGET_OS_IPHONE
return button.isDoubleClick ();
#else
return (button.isLeftButton () && button.getModifierState () == kDefaultValueModifier);
#endif // TARGET_OS_IPHONE
};
#endif // VSTGUI_ENABLE_DEPRECATED_METHODS
//------------------------------------------------------------------------
CControl::CheckDefaultValueEventFuncT CControl::CheckDefaultValueEventFunc =
[] (CControl* c, MouseDownEvent& event) {
#if VSTGUI_ENABLE_DEPRECATED_METHODS
if (event.buttonState.isLeft ())
{
return CheckDefaultValueFunc (c, buttonStateFromMouseEvent (event));
}
return false;
#else
#if TARGET_OS_IPHONE
return event.buttonState.isLeft () && event.clickCount == 2;
#else
return event.buttonState.isLeft () && event.modifiers.is (ModifierKey::Control);
#endif // TARGET_OS_IPHONE
#endif // VSTGUI_ENABLE_DEPRECATED_METHODS
};
//------------------------------------------------------------------------
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;
}
#if VSTGUI_ENABLE_DEPRECATED_METHODS
//-----------------------------------------------------------------------------
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;
}
#endif // VSTGUI_ENABLE_DEPRECATED_METHODS
#if VSTGUI_ENABLE_DEPRECATED_METHODS
//------------------------------------------------------------------------
//------------------------------------------------------------------------
//------------------------------------------------------------------------
void IMultiBitmapControl::autoComputeHeightOfOneImage ()
{
auto* view = dynamic_cast<CView*>(this);
if (view)
{
const CRect& viewSize = view->getViewSize ();
heightOfOneImage = viewSize.getHeight ();
}
}
#endif
//------------------------------------------------------------------------
//------------------------------------------------------------------------
//------------------------------------------------------------------------
void CMouseWheelEditingSupport::onMouseWheelEditing (CControl* control)
{
if (!control->isEditing ())
control->beginEdit ();
endEditTimer = makeOwned<CVSTGUITimer> (
[control] (CVSTGUITimer* timer) {
control->endEdit ();
timer->stop ();
},
500);
}
//------------------------------------------------------------------------
void CMouseWheelEditingSupport::invalidMouseWheelEditTimer (CControl* control)
{
if (endEditTimer)
endEditTimer = nullptr;
if (control->isEditing ())
control->endEdit ();
}
} // 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
#pragma once
#include "../cview.h"
#include "../ifocusdrawing.h"
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);
virtual float getMin () const;
virtual void setMax (float val);
virtual float getMax () const;
float getRange () const { return getMax () - getMin (); }
virtual void setOldValue (float val);
virtual float getOldValue () const;
virtual void setDefaultValue (float val);
virtual float getDefaultValue () const;
virtual void bounceValue ();
/** 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;
/** 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);
virtual float getWheelInc () const;
//@}
// 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;
using CheckDefaultValueEventFuncT = bool (*) (CControl*, MouseDownEvent&);
/** Function to check if a mouse down event should reset the value to its default value for a
*control. Per default this checks for a left mouse down button and the control modifier key. */
static CheckDefaultValueEventFuncT CheckDefaultValueEventFunc;
/** zoom modifier key, per default is the shift key */
inline static int32_t kZoomModifier = kShift;
#if VSTGUI_ENABLE_DEPRECATED_METHODS
/** \deprecated default value modifier key, per default is the control key */
inline static int32_t kDefaultValueModifier = kControl;
using CheckDefaultValueFuncT = bool (*) (CControl*, CButtonState);
/** \deprecated Function to check if the button state is the state to set the control value to
* its default value. The default implementation uses the kDefaultValueModifier (see above). Use
* this to change this to double click per example. But consider to change this to the same
* behaviour as the host you are running in for best user experience. */
static CheckDefaultValueFuncT CheckDefaultValueFunc;
#endif
CLASS_METHODS_VIRTUAL(CControl, CView)
protected:
~CControl () noexcept override;
VSTGUI_DEPRECATED (static int32_t mapVstKeyModifier (int32_t vstModifier);)
IControlListener* listener;
int32_t tag;
float value;
private:
struct Impl;
std::unique_ptr<Impl> impl;
};
#if VSTGUI_ENABLE_DEPRECATED_METHODS
//-----------------------------------------------------------------------------
// 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;
};
#endif
//-----------------------------------------------------------------------------
// CMouseWheelEditingSupport Declaration
//! @brief Helper class for mouse wheel editing
//-----------------------------------------------------------------------------
class CMouseWheelEditingSupport
{
protected:
void invalidMouseWheelEditTimer (CControl* control);
void onMouseWheelEditing (CControl* control);
private:
SharedPointer<CBaseObject> endEditTimer {nullptr};
};
} // VSTGUI

Some files were not shown because too many files have changed in this diff Show More