Initial release
This commit is contained in:
@@ -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()
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
|
||||
@@ -0,0 +1,95 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "vstguibase.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//----------------------------
|
||||
// @brief Button Types (+modifiers)
|
||||
//----------------------------
|
||||
enum CButton
|
||||
{
|
||||
/** left mouse button */
|
||||
kLButton = 1 << 1,
|
||||
/** middle mouse button */
|
||||
kMButton = 1 << 2,
|
||||
/** right mouse button */
|
||||
kRButton = 1 << 3,
|
||||
/** shift modifier */
|
||||
kShift = 1 << 4,
|
||||
/** control modifier (Command Key on Mac OS X and Control Key on Windows) */
|
||||
kControl = 1 << 5,
|
||||
/** alt modifier */
|
||||
kAlt = 1 << 6,
|
||||
/** apple modifier (Mac OS X only. Is the Control key) */
|
||||
kApple = 1 << 7,
|
||||
/** 4th mouse button */
|
||||
kButton4 = 1 << 8,
|
||||
/** 5th mouse button */
|
||||
kButton5 = 1 << 9,
|
||||
/** mouse button is double click */
|
||||
kDoubleClick = 1 << 10,
|
||||
/** system mouse wheel setting is inverted (Only valid for onMouseWheel methods). The distance
|
||||
value is already transformed back to non inverted. But for scroll views we need to know if we
|
||||
need to invert it back. */
|
||||
kMouseWheelInverted = 1 << 11
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CButtonState Declaration
|
||||
//! @brief Button and Modifier state
|
||||
//-----------------------------------------------------------------------------
|
||||
struct CButtonState
|
||||
{
|
||||
public:
|
||||
CButtonState (int32_t state = 0) : state (state) {}
|
||||
CButtonState (const CButtonState& bs) : state (bs.state) {}
|
||||
|
||||
int32_t getButtonState () const { return state & (kLButton | kRButton | kMButton | kButton4 | kButton5); }
|
||||
int32_t getModifierState () const { return state & (kShift | kAlt | kControl | kApple); }
|
||||
|
||||
/** returns true if only the left button is set. Ignores modifier state */
|
||||
bool isLeftButton () const { return getButtonState () == kLButton; }
|
||||
/** returns true if only the middle button is set. Ignores modifier state */
|
||||
bool isMiddleButton () const { return getButtonState () == kMButton; }
|
||||
/** returns true if only the right button is set. Ignores modifier state */
|
||||
bool isRightButton () const { return getButtonState () == kRButton; }
|
||||
/** returns true if only the 4th button is set. Ignores modifier state */
|
||||
bool isButton4 () const { return getButtonState () == kButton4; }
|
||||
/** returns true if only the 5th button is set. Ignores modifier state */
|
||||
bool isButton5 () const { return getButtonState () == kButton5; }
|
||||
|
||||
/** returns true if the double click flag is set. */
|
||||
bool isDoubleClick () const { return hasBit<int32_t> (state, kDoubleClick); }
|
||||
|
||||
/** returns true if the shift modifier is set. */
|
||||
bool isShiftSet () const { return hasBit<int32_t> (state, kShift); }
|
||||
/** returns true if the alt modifier is set. */
|
||||
bool isAltSet () const { return hasBit<int32_t> (state, kAlt); }
|
||||
/** returns true if the control modifier is set. */
|
||||
bool isControlSet () const { return hasBit<int32_t> (state, kControl); }
|
||||
/** returns true if the apple modifier is set. */
|
||||
bool isAppleSet () const { return hasBit<int32_t> (state, kApple); }
|
||||
|
||||
bool isMouseWheelInverted () const { return hasBit<int32_t> (state, kMouseWheelInverted); }
|
||||
|
||||
int32_t operator() () const { return state; }
|
||||
CButtonState& operator= (int32_t s) { state = s; return *this; }
|
||||
CButtonState& operator&= (int32_t s) { state &= s; return *this; }
|
||||
CButtonState& operator|= (int32_t s) { state |= s; return *this; }
|
||||
|
||||
int32_t operator& (const CButtonState& s) const { return state & s.state; }
|
||||
int32_t operator| (const CButtonState& s) const { return state | s.state; }
|
||||
int32_t operator~ () const { return ~state; }
|
||||
|
||||
bool operator== (const CButtonState& s) const { return state == s.state; }
|
||||
bool operator!= (const CButtonState& s) const { return state != s.state; }
|
||||
protected:
|
||||
int32_t state;
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,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
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
+2030
File diff suppressed because it is too large
Load Diff
+395
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,91 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#include "clinestyle.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
CLineStyle::CLineStyle (LineCap _cap, LineJoin _join, CCoord _dashPhase, uint32_t _dashCount, const CCoord* _dashLengths)
|
||||
: cap (_cap)
|
||||
, join (_join)
|
||||
, dashPhase (_dashPhase)
|
||||
{
|
||||
if (_dashCount && _dashLengths)
|
||||
{
|
||||
for (uint32_t i = 0; i < _dashCount; i++)
|
||||
dashLengths.emplace_back (_dashLengths[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CLineStyle::CLineStyle (LineCap _cap, LineJoin _join, CCoord _dashPhase, const CoordVector& _dashLengths)
|
||||
: cap (_cap)
|
||||
, join (_join)
|
||||
, dashPhase (_dashPhase)
|
||||
, dashLengths (_dashLengths)
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CLineStyle::CLineStyle (const CLineStyle& lineStyle)
|
||||
{
|
||||
*this = lineStyle;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CLineStyle::CLineStyle (LineCap _cap, LineJoin _join, CCoord _dashPhase, CoordVector&& _dashLengths) noexcept
|
||||
: cap (_cap)
|
||||
, join (_join)
|
||||
, dashPhase (_dashPhase)
|
||||
, dashLengths (std::move (_dashLengths))
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CLineStyle::CLineStyle (CLineStyle&& cls) noexcept
|
||||
{
|
||||
*this = std::move (cls);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CLineStyle& CLineStyle::operator= (CLineStyle&& cls) noexcept
|
||||
{
|
||||
dashLengths.clear ();
|
||||
cap = cls.cap;
|
||||
join = cls.join;
|
||||
dashPhase = cls.dashPhase;
|
||||
dashLengths = std::move (cls.dashLengths);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CLineStyle::operator== (const CLineStyle& cls) const
|
||||
{
|
||||
if (cap == cls.cap && join == cls.join && dashPhase == cls.dashPhase && dashLengths == cls.dashLengths)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CLineStyle& CLineStyle::operator= (const CLineStyle& cls)
|
||||
{
|
||||
dashLengths.clear ();
|
||||
cap = cls.cap;
|
||||
join = cls.join;
|
||||
dashPhase = cls.dashPhase;
|
||||
dashLengths = cls.dashLengths;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
static const CCoord kDefaultOnOffDashLength[] = {1, 1};
|
||||
const CLineStyle kLineSolid {};
|
||||
const CLineStyle kLineOnOffDash (CLineStyle::kLineCapButt, CLineStyle::kLineJoinMiter, 0, 2, kDefaultOnOffDashLength);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "vstguifwd.h"
|
||||
#include <vector>
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//-----------
|
||||
// @brief Line Style
|
||||
//-----------
|
||||
class CLineStyle
|
||||
{
|
||||
public:
|
||||
using CoordVector = std::vector<CCoord>;
|
||||
|
||||
enum LineCap
|
||||
{
|
||||
kLineCapButt = 0,
|
||||
kLineCapRound,
|
||||
kLineCapSquare
|
||||
};
|
||||
|
||||
enum LineJoin
|
||||
{
|
||||
kLineJoinMiter = 0,
|
||||
kLineJoinRound,
|
||||
kLineJoinBevel
|
||||
};
|
||||
|
||||
CLineStyle () = default;
|
||||
explicit CLineStyle (LineCap cap, LineJoin join = kLineJoinMiter, CCoord dashPhase = 0., uint32_t dashCount = 0, const CCoord* dashLengths = nullptr);
|
||||
CLineStyle (LineCap cap, LineJoin join, CCoord dashPhase, const CoordVector& dashLengths);
|
||||
CLineStyle (const CLineStyle& lineStyle);
|
||||
~CLineStyle () noexcept = default;
|
||||
|
||||
CLineStyle (LineCap cap, LineJoin join, CCoord dashPhase, CoordVector&& dashLengths) noexcept;
|
||||
CLineStyle (CLineStyle&& cls) noexcept;
|
||||
CLineStyle& operator= (CLineStyle&& cls) noexcept;
|
||||
|
||||
LineCap getLineCap () const { return cap; }
|
||||
LineJoin getLineJoin () const { return join; }
|
||||
CCoord getDashPhase () const { return dashPhase; }
|
||||
uint32_t getDashCount () const { return static_cast<uint32_t> (dashLengths.size ()); }
|
||||
CoordVector& getDashLengths () { return dashLengths; }
|
||||
const CoordVector& getDashLengths() const { return dashLengths; }
|
||||
|
||||
void setLineCap (LineCap newCap) { cap = newCap; }
|
||||
void setLineJoin (LineJoin newJoin) { join = newJoin; }
|
||||
void setDashPhase (CCoord phase) { dashPhase = phase; }
|
||||
|
||||
bool operator== (const CLineStyle& cls) const;
|
||||
bool operator!= (const CLineStyle& cls) const { return !(*this == cls); }
|
||||
CLineStyle& operator= (const CLineStyle& cls);
|
||||
|
||||
protected:
|
||||
LineCap cap {kLineCapButt};
|
||||
LineJoin join {kLineJoinMiter};
|
||||
CCoord dashPhase {0.};
|
||||
CoordVector dashLengths;
|
||||
};
|
||||
|
||||
extern const CLineStyle kLineSolid;
|
||||
extern const CLineStyle kLineOnOffDash;
|
||||
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,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
|
||||
@@ -0,0 +1,302 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#include "cfontchooser.h"
|
||||
#include "../cdatabrowser.h"
|
||||
#include "../cdrawcontext.h"
|
||||
#include "cbuttons.h"
|
||||
#include "ctextedit.h"
|
||||
#include "cscrollbar.h"
|
||||
#include "../cstring.h"
|
||||
#include "../platform/platformfactory.h"
|
||||
#include "../platform/iplatformfont.h"
|
||||
#include <list>
|
||||
#include <cmath>
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
/// @cond ignore
|
||||
|
||||
namespace CFontChooserInternal {
|
||||
|
||||
class FontPreviewView : public CView
|
||||
{
|
||||
public:
|
||||
FontPreviewView (const CRect& size, const CColor& color = kWhiteCColor) : CView (size), font (nullptr), fontColor (color) {}
|
||||
~FontPreviewView () noexcept override { if (font) font->forget (); }
|
||||
|
||||
void setFont (CFontRef newFont)
|
||||
{
|
||||
if (font)
|
||||
font->forget ();
|
||||
font = newFont;
|
||||
if (font)
|
||||
font->remember ();
|
||||
invalid ();
|
||||
}
|
||||
|
||||
void draw (CDrawContext *context) override
|
||||
{
|
||||
context->setFontColor (fontColor);
|
||||
context->setFont (font);
|
||||
std::string text;
|
||||
char string[2];
|
||||
CRect glyphRect (getViewSize ().left, getViewSize ().top, getViewSize ().left, getViewSize ().top);
|
||||
CCoord height = ceil (font->getPlatformFont ()->getAscent () + font->getPlatformFont ()->getDescent () + font->getPlatformFont ()->getLeading () + 2.);
|
||||
glyphRect.setHeight (height);
|
||||
for (int8_t i = 33; i < 126;)
|
||||
{
|
||||
while (glyphRect.right < getViewSize ().right && i < 126)
|
||||
{
|
||||
snprintf (string, 2, "%c", i++);
|
||||
text += string;
|
||||
glyphRect.setWidth (context->getStringWidth (text.c_str ()));
|
||||
}
|
||||
context->drawString (text.c_str (), glyphRect, kLeftText);
|
||||
glyphRect.left = glyphRect.right = getViewSize ().left;
|
||||
glyphRect.offset (0, height);
|
||||
text = "";
|
||||
}
|
||||
setDirty (false);
|
||||
}
|
||||
|
||||
protected:
|
||||
CFontRef font;
|
||||
CColor fontColor;
|
||||
};
|
||||
|
||||
enum {
|
||||
kFontChooserSizeTag,
|
||||
kFontChooserBoldTag,
|
||||
kFontChooserItalicTag,
|
||||
kFontChooserUnderlineTag,
|
||||
kFontChooserStrikeoutTag
|
||||
};
|
||||
|
||||
} // CFontChooserInternal
|
||||
|
||||
/// @endcond
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
CFontChooser::CFontChooser (IFontChooserDelegate* delegate, CFontRef initialFont, const CFontChooserUIDefinition& uiDef)
|
||||
: CViewContainer (CRect (0, 0, 300, 500))
|
||||
, delegate (nullptr)
|
||||
, fontBrowser (nullptr)
|
||||
, selFont (nullptr)
|
||||
{
|
||||
std::list<std::string> fnList;
|
||||
getPlatformFactory ().getAllFontFamilies ([&fnList] (const std::string& name) {
|
||||
fnList.push_back (name);
|
||||
return true;
|
||||
});
|
||||
fnList.sort ();
|
||||
std::list<std::string>::const_iterator it = fnList.begin ();
|
||||
while (it != fnList.end ())
|
||||
{
|
||||
fontNames.emplace_back (*it);
|
||||
++it;
|
||||
}
|
||||
auto* dbSource = new GenericStringListDataBrowserSource (&fontNames, this);
|
||||
dbSource->setupUI (uiDef.selectionColor, uiDef.fontColor, uiDef.rowlineColor, uiDef.rowBackColor, uiDef.rowAlternateBackColor, uiDef.font, uiDef.rowHeight);
|
||||
int32_t dbStyle = CDataBrowser::kDrawRowLines | CScrollView::kVerticalScrollbar | CScrollView::kDontDrawFrame | CScrollView::kOverlayScrollbars;
|
||||
fontBrowser = new CDataBrowser (CRect (0, 0, 200, 500), dbSource, dbStyle, uiDef.scrollbarWidth);
|
||||
dbSource->forget ();
|
||||
fontBrowser->setAutosizeFlags (kAutosizeLeft | kAutosizeTop | kAutosizeBottom);
|
||||
fontBrowser->setTransparency (true);
|
||||
CScrollbar* scrollbar = fontBrowser->getVerticalScrollbar ();
|
||||
if (scrollbar)
|
||||
{
|
||||
scrollbar->setBackgroundColor (uiDef.scrollbarBackgroundColor);
|
||||
scrollbar->setFrameColor (uiDef.scrollbarFrameColor);
|
||||
scrollbar->setScrollerColor (uiDef.scrollbarScrollerColor);
|
||||
}
|
||||
addView (fontBrowser);
|
||||
CRect controlRect (210, 0, 300, 20);
|
||||
auto* label = new CTextLabel (controlRect, "Size:");
|
||||
label->setFont (uiDef.font);
|
||||
label->setFontColor (uiDef.fontColor);
|
||||
label->sizeToFit ();
|
||||
label->setHoriAlign (kLeftText);
|
||||
label->setTransparency (true);
|
||||
label->setAutosizeFlags (kAutosizeLeft | kAutosizeTop);
|
||||
addView (label);
|
||||
CRect teRect = label->getViewSize ();
|
||||
teRect.left = teRect.right + 5.;
|
||||
teRect.right = controlRect.right;
|
||||
sizeEdit = new CTextEdit (teRect, this, CFontChooserInternal::kFontChooserSizeTag);
|
||||
sizeEdit->setFont (uiDef.font);
|
||||
sizeEdit->setFontColor (uiDef.fontColor);
|
||||
sizeEdit->setHoriAlign (kLeftText);
|
||||
sizeEdit->setTransparency (true);
|
||||
sizeEdit->setAutosizeFlags (kAutosizeLeft | kAutosizeTop);
|
||||
sizeEdit->setMax (2000);
|
||||
sizeEdit->setMin (6);
|
||||
sizeEdit->setValue (2000);
|
||||
sizeEdit->sizeToFit ();
|
||||
sizeEdit->setStringToValueFunction ([] (UTF8StringPtr txt, float& result, CTextEdit* textEdit) { result = UTF8StringView (txt).toFloat (); return true; });
|
||||
addView (sizeEdit);
|
||||
controlRect.offset (0, 20);
|
||||
boldBox = new CCheckBox (controlRect, this, CFontChooserInternal::kFontChooserBoldTag, "Bold");
|
||||
boldBox->setFont (uiDef.font);
|
||||
boldBox->setFontColor (uiDef.fontColor);
|
||||
boldBox->setAutosizeFlags (kAutosizeLeft | kAutosizeTop);
|
||||
boldBox->sizeToFit ();
|
||||
addView (boldBox);
|
||||
controlRect.offset (0, 20);
|
||||
italicBox = new CCheckBox (controlRect, this, CFontChooserInternal::kFontChooserItalicTag, "Italic");
|
||||
italicBox->setFont (uiDef.font);
|
||||
italicBox->setFontColor (uiDef.fontColor);
|
||||
italicBox->setAutosizeFlags (kAutosizeLeft | kAutosizeTop);
|
||||
italicBox->sizeToFit ();
|
||||
addView (italicBox);
|
||||
controlRect.offset (0, 20);
|
||||
underlineBox = new CCheckBox (controlRect, this, CFontChooserInternal::kFontChooserUnderlineTag, "Underline");
|
||||
underlineBox->setFont (uiDef.font);
|
||||
underlineBox->setFontColor (uiDef.fontColor);
|
||||
underlineBox->setAutosizeFlags (kAutosizeLeft | kAutosizeTop);
|
||||
underlineBox->sizeToFit ();
|
||||
addView (underlineBox);
|
||||
controlRect.offset (0, 20);
|
||||
strikeoutBox = new CCheckBox (controlRect, this, CFontChooserInternal::kFontChooserStrikeoutTag, "Strikeout");
|
||||
strikeoutBox->setFont (uiDef.font);
|
||||
strikeoutBox->setFontColor (uiDef.fontColor);
|
||||
strikeoutBox->setAutosizeFlags (kAutosizeLeft | kAutosizeTop);
|
||||
strikeoutBox->sizeToFit ();
|
||||
addView (strikeoutBox);
|
||||
|
||||
CViewContainer* container = new CViewContainer (CRect (controlRect.left, controlRect.bottom+10, 300, 500));
|
||||
container->setBackgroundColor (uiDef.previewBackgroundColor);
|
||||
container->setAutosizeFlags (kAutosizeTop | kAutosizeBottom | kAutosizeLeft | kAutosizeRight);
|
||||
fontPreviewView = new CFontChooserInternal::FontPreviewView (CRect (10, 10, container->getWidth () - 10, container->getHeight () - 10), uiDef.previewTextColor);
|
||||
fontPreviewView->setAutosizeFlags (kAutosizeAll);
|
||||
container->addView (fontPreviewView);
|
||||
addView (container);
|
||||
|
||||
setFont (initialFont ? initialFont : kSystemFont);
|
||||
|
||||
sizeToFit ();
|
||||
|
||||
this->delegate = delegate;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CFontChooser::~CFontChooser () noexcept
|
||||
{
|
||||
if (selFont)
|
||||
selFont->forget ();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFontChooser::setFont (CFontRef font)
|
||||
{
|
||||
if (font)
|
||||
{
|
||||
if (selFont)
|
||||
selFont->forget ();
|
||||
selFont = new CFontDesc (*font);
|
||||
sizeEdit->setValue ((float)font->getSize ());
|
||||
boldBox->setValue ((font->getStyle () & kBoldFace) ? 1.f : 0.f);
|
||||
italicBox->setValue ((font->getStyle () & kItalicFace) ? 1.f : 0.f);
|
||||
underlineBox->setValue ((font->getStyle () & kUnderlineFace) ? 1.f : 0.f);
|
||||
strikeoutBox->setValue ((font->getStyle () & kStrikethroughFace) ? 1.f : 0.f);
|
||||
|
||||
auto it = fontNames.begin ();
|
||||
int32_t row = 0;
|
||||
while (it != fontNames.end ())
|
||||
{
|
||||
if (*it == font->getName ())
|
||||
{
|
||||
fontBrowser->setSelectedRow (row, true);
|
||||
break;
|
||||
}
|
||||
++it;
|
||||
row++;
|
||||
}
|
||||
static_cast<CFontChooserInternal::FontPreviewView*> (fontPreviewView)->setFont (selFont);
|
||||
}
|
||||
invalid ();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFontChooser::valueChanged (CControl* pControl)
|
||||
{
|
||||
if (selFont == nullptr)
|
||||
return;
|
||||
|
||||
switch (pControl->getTag ())
|
||||
{
|
||||
case CFontChooserInternal::kFontChooserSizeTag:
|
||||
{
|
||||
pControl->setValue (pControl->getValue ());
|
||||
selFont->setSize (pControl->getValue ());
|
||||
break;
|
||||
}
|
||||
case CFontChooserInternal::kFontChooserBoldTag:
|
||||
{
|
||||
if (pControl->getValue () == 1)
|
||||
selFont->setStyle (selFont->getStyle () | kBoldFace);
|
||||
else
|
||||
selFont->setStyle (selFont->getStyle () & ~kBoldFace);
|
||||
break;
|
||||
}
|
||||
case CFontChooserInternal::kFontChooserItalicTag:
|
||||
{
|
||||
if (pControl->getValue () == 1)
|
||||
selFont->setStyle (selFont->getStyle () | kItalicFace);
|
||||
else
|
||||
selFont->setStyle (selFont->getStyle () & ~kItalicFace);
|
||||
break;
|
||||
}
|
||||
case CFontChooserInternal::kFontChooserUnderlineTag:
|
||||
{
|
||||
if (pControl->getValue () == 1)
|
||||
selFont->setStyle (selFont->getStyle () | kUnderlineFace);
|
||||
else
|
||||
selFont->setStyle (selFont->getStyle () & ~kUnderlineFace);
|
||||
break;
|
||||
}
|
||||
case CFontChooserInternal::kFontChooserStrikeoutTag:
|
||||
{
|
||||
if (pControl->getValue () == 1)
|
||||
selFont->setStyle (selFont->getStyle () | kStrikethroughFace);
|
||||
else
|
||||
selFont->setStyle (selFont->getStyle () & ~kStrikethroughFace);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (delegate)
|
||||
delegate->fontChanged (this, selFont);
|
||||
static_cast<CFontChooserInternal::FontPreviewView*> (fontPreviewView)->setFont (selFont);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFontChooser::dbSelectionChanged (int32_t selectedRow, GenericStringListDataBrowserSource* source)
|
||||
{
|
||||
if (selectedRow >= 0 && static_cast<size_t> (selectedRow) <= fontNames.size ())
|
||||
selFont->setName (fontNames[static_cast<size_t> (selectedRow)].data ());
|
||||
static_cast<CFontChooserInternal::FontPreviewView*> (fontPreviewView)->setFont (selFont);
|
||||
if (delegate)
|
||||
delegate->fontChanged (this, selFont);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CFontChooser::attached (CView* parent)
|
||||
{
|
||||
if (CViewContainer::attached (parent))
|
||||
{
|
||||
fontBrowser->makeRowVisible (fontBrowser->getSelectedRow ());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFontChooser::onKeyboardEvent (KeyboardEvent& event)
|
||||
{
|
||||
fontBrowser->onKeyboardEvent (event);
|
||||
}
|
||||
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,92 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../vstguifwd.h"
|
||||
#include "../cviewcontainer.h"
|
||||
#include "../cfont.h"
|
||||
#include "../cdatabrowser.h"
|
||||
#include "../genericstringlistdatabrowsersource.h"
|
||||
#include "icontrollistener.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
/// @ingroup new_in_4_0
|
||||
//-----------------------------------------------------------------------------
|
||||
class IFontChooserDelegate
|
||||
{
|
||||
public:
|
||||
virtual void fontChanged (CFontChooser* chooser, CFontRef newFont) = 0;
|
||||
};
|
||||
|
||||
/// @ingroup new_in_4_0
|
||||
//-----------------------------------------------------------------------------
|
||||
struct CFontChooserUIDefinition
|
||||
{
|
||||
CFontRef font;
|
||||
int32_t rowHeight;
|
||||
CColor fontColor;
|
||||
CColor selectionColor;
|
||||
CColor rowlineColor;
|
||||
CColor rowBackColor;
|
||||
CColor rowAlternateBackColor;
|
||||
CColor previewTextColor;
|
||||
CColor previewBackgroundColor;
|
||||
CColor scrollbarScrollerColor;
|
||||
CColor scrollbarFrameColor;
|
||||
CColor scrollbarBackgroundColor;
|
||||
CCoord scrollbarWidth;
|
||||
|
||||
CFontChooserUIDefinition (CFontRef font = kSystemFont,
|
||||
const CColor& fontColor = kWhiteCColor,
|
||||
const CColor& selectionColor = kBlueCColor,
|
||||
const CColor& rowlineColor = kGreyCColor,
|
||||
const CColor& rowBackColor = kTransparentCColor,
|
||||
const CColor& rowAlternateBackColor = kTransparentCColor,
|
||||
const CColor& previewTextColor = kBlackCColor,
|
||||
const CColor& previewBackgroundColor = kWhiteCColor,
|
||||
const CColor& scrollbarScrollerColor = kBlueCColor,
|
||||
const CColor& scrollbarFrameColor = kBlackCColor,
|
||||
const CColor& scrollbarBackgroundColor = kGreyCColor,
|
||||
int32_t rowHeight = -1,
|
||||
CCoord scrollbarWidth = 16)
|
||||
: font (font), rowHeight (rowHeight), fontColor (fontColor), selectionColor (selectionColor), rowlineColor (rowlineColor)
|
||||
, rowBackColor (rowBackColor), rowAlternateBackColor (rowAlternateBackColor), previewTextColor (previewTextColor), previewBackgroundColor (previewBackgroundColor)
|
||||
, scrollbarScrollerColor (scrollbarScrollerColor), scrollbarFrameColor (scrollbarFrameColor)
|
||||
, scrollbarBackgroundColor (scrollbarBackgroundColor), scrollbarWidth (scrollbarWidth)
|
||||
{}
|
||||
};
|
||||
|
||||
/// @ingroup new_in_4_0
|
||||
//-----------------------------------------------------------------------------
|
||||
class CFontChooser : public CViewContainer, public IControlListener, public GenericStringListDataBrowserSourceSelectionChanged
|
||||
{
|
||||
public:
|
||||
CFontChooser (IFontChooserDelegate* delegate, CFontRef initialFont = nullptr, const CFontChooserUIDefinition& uiDef = CFontChooserUIDefinition ());
|
||||
~CFontChooser () noexcept override;
|
||||
|
||||
void setFont (CFontRef font);
|
||||
|
||||
protected:
|
||||
void dbSelectionChanged (int32_t selectedRow, GenericStringListDataBrowserSource* source) override;
|
||||
void valueChanged (CControl* pControl) override;
|
||||
bool attached (CView* parent) override;
|
||||
void onKeyboardEvent (KeyboardEvent& event) override;
|
||||
|
||||
IFontChooserDelegate* delegate;
|
||||
CDataBrowser* fontBrowser;
|
||||
CTextEdit* sizeEdit;
|
||||
CCheckBox* boldBox;
|
||||
CCheckBox* italicBox;
|
||||
CCheckBox* underlineBox;
|
||||
CCheckBox* strikeoutBox;
|
||||
CView* fontPreviewView;
|
||||
GenericStringListDataBrowserSource::StringVector fontNames;
|
||||
|
||||
CFontRef selFont;
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
|
||||
@@ -0,0 +1,911 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#include "cknob.h"
|
||||
#include "../cbitmap.h"
|
||||
#include "../cdrawcontext.h"
|
||||
#include "../cframe.h"
|
||||
#include "../cgraphicspath.h"
|
||||
#include "../cvstguitimer.h"
|
||||
#include "../events.h"
|
||||
#include <cmath>
|
||||
|
||||
namespace VSTGUI {
|
||||
#if TARGET_OS_IPHONE
|
||||
static const float kCKnobRangeDefault = 300.f;
|
||||
#else
|
||||
static const float kCKnobRangeDefault = 200.f;
|
||||
#endif
|
||||
|
||||
static constexpr CViewAttributeID kCKnobMouseStateAttribute = 'knms';
|
||||
//------------------------------------------------------------------------
|
||||
struct CKnobBase::MouseEditingState
|
||||
{
|
||||
CPoint firstPoint;
|
||||
CPoint lastPoint;
|
||||
float startValue;
|
||||
float entryState;
|
||||
float range;
|
||||
float coef;
|
||||
CButtonState oldButton;
|
||||
bool modeLinear;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CKnobBase::CKnobBase (const CRect& size, IControlListener* listener, int32_t tag, CBitmap* background)
|
||||
: CControl (size, listener, tag, background)
|
||||
{
|
||||
rangeAngle = 1.f;
|
||||
setStartAngle ((float)(3.f * Constants::quarter_pi));
|
||||
setRangeAngle ((float)(3.f * Constants::half_pi));
|
||||
zoomFactor = 1.5f;
|
||||
knobRange = kCKnobRangeDefault;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CKnobBase::CKnobBase (const CKnobBase& k)
|
||||
: CControl (k)
|
||||
, startAngle (k.startAngle)
|
||||
, rangeAngle (k.rangeAngle)
|
||||
, zoomFactor (k.zoomFactor)
|
||||
, inset (k.inset)
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CKnobBase::setViewSize (const CRect &rect, bool invalid)
|
||||
{
|
||||
CControl::setViewSize (rect, invalid);
|
||||
compute ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool CKnobBase::sizeToFit ()
|
||||
{
|
||||
if (getDrawBackground ())
|
||||
{
|
||||
CRect vs (getViewSize ());
|
||||
vs.setWidth (getDrawBackground ()->getWidth ());
|
||||
vs.setHeight (getDrawBackground ()->getHeight ());
|
||||
setViewSize (vs);
|
||||
setMouseableArea (vs);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
auto CKnobBase::getMouseEditingState () -> MouseEditingState&
|
||||
{
|
||||
MouseEditingState* state = nullptr;
|
||||
if (!getAttribute (kCKnobMouseStateAttribute, state))
|
||||
{
|
||||
state = new MouseEditingState;
|
||||
setAttribute (kCKnobMouseStateAttribute, state);
|
||||
}
|
||||
return *state;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CKnobBase::clearMouseEditingState ()
|
||||
{
|
||||
MouseEditingState* state = nullptr;
|
||||
if (!getAttribute (kCKnobMouseStateAttribute, state))
|
||||
return;
|
||||
delete state;
|
||||
removeAttribute (kCKnobMouseStateAttribute);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMouseEventResult CKnobBase::onMouseDown (CPoint& where, const CButtonState& buttons)
|
||||
{
|
||||
if (!buttons.isLeftButton ())
|
||||
return kMouseEventNotHandled;
|
||||
|
||||
invalidMouseWheelEditTimer (this);
|
||||
beginEdit ();
|
||||
|
||||
auto& mouseState = getMouseEditingState ();
|
||||
mouseState.firstPoint = where;
|
||||
mouseState.lastPoint (-1, -1);
|
||||
mouseState.startValue = getOldValue ();
|
||||
|
||||
mouseState.modeLinear = false;
|
||||
mouseState.entryState = value;
|
||||
mouseState.range = knobRange;
|
||||
mouseState.coef = (getMax () - getMin ()) / mouseState.range;
|
||||
mouseState.oldButton = buttons;
|
||||
|
||||
int32_t mode = kCircularMode;
|
||||
int32_t newMode = getFrame ()->getKnobMode ();
|
||||
if (kLinearMode == newMode)
|
||||
{
|
||||
if (!(buttons & kAlt))
|
||||
mode = newMode;
|
||||
}
|
||||
else if (buttons & kAlt)
|
||||
{
|
||||
mode = kLinearMode;
|
||||
}
|
||||
|
||||
if (mode == kLinearMode)
|
||||
{
|
||||
if (buttons & kZoomModifier)
|
||||
mouseState.range *= zoomFactor;
|
||||
mouseState.lastPoint = where;
|
||||
mouseState.modeLinear = true;
|
||||
mouseState.coef = (getMax () - getMin ()) / mouseState.range;
|
||||
}
|
||||
else
|
||||
{
|
||||
CPoint where2 (where);
|
||||
where2.offset (-getViewSize ().left, -getViewSize ().top);
|
||||
mouseState.startValue = valueFromPoint (where2);
|
||||
mouseState.lastPoint = where;
|
||||
}
|
||||
|
||||
return onMouseMoved (where, buttons);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMouseEventResult CKnobBase::onMouseUp (CPoint& where, const CButtonState& buttons)
|
||||
{
|
||||
if (isEditing ())
|
||||
{
|
||||
endEdit ();
|
||||
clearMouseEditingState ();
|
||||
}
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMouseEventResult CKnobBase::onMouseCancel ()
|
||||
{
|
||||
if (isEditing ())
|
||||
{
|
||||
auto& mouseState = getMouseEditingState ();
|
||||
value = mouseState.startValue;
|
||||
if (isDirty ())
|
||||
{
|
||||
valueChanged ();
|
||||
invalid ();
|
||||
}
|
||||
endEdit ();
|
||||
clearMouseEditingState ();
|
||||
}
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMouseEventResult CKnobBase::onMouseMoved (CPoint& where, const CButtonState& buttons)
|
||||
{
|
||||
if (buttons.isLeftButton () && isEditing ())
|
||||
{
|
||||
auto& mouseState = getMouseEditingState ();
|
||||
|
||||
float middle = (getMax () - getMin ()) * 0.5f;
|
||||
|
||||
if (where != mouseState.lastPoint)
|
||||
{
|
||||
mouseState.lastPoint = where;
|
||||
if (mouseState.modeLinear)
|
||||
{
|
||||
CCoord diff = (mouseState.firstPoint.y - where.y) + (where.x - mouseState.firstPoint.x);
|
||||
if (buttons != mouseState.oldButton)
|
||||
{
|
||||
mouseState.range = knobRange;
|
||||
if (buttons & kZoomModifier)
|
||||
mouseState.range *= zoomFactor;
|
||||
|
||||
float coef2 = (getMax () - getMin ()) / mouseState.range;
|
||||
mouseState.entryState += (float)(diff * (mouseState.coef - coef2));
|
||||
mouseState.coef = coef2;
|
||||
mouseState.oldButton = buttons;
|
||||
}
|
||||
value = (float)(mouseState.entryState + diff * mouseState.coef);
|
||||
bounceValue ();
|
||||
}
|
||||
else
|
||||
{
|
||||
where.offset (-getViewSize ().left, -getViewSize ().top);
|
||||
value = valueFromPoint (where);
|
||||
if (mouseState.startValue - value > middle)
|
||||
value = getMax ();
|
||||
else if (value - mouseState.startValue > middle)
|
||||
value = getMin ();
|
||||
else
|
||||
mouseState.startValue = value;
|
||||
}
|
||||
if (value != getOldValue ())
|
||||
valueChanged ();
|
||||
if (isDirty ())
|
||||
invalid ();
|
||||
}
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
return kMouseEventNotHandled;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CKnobBase::onMouseWheelEvent (MouseWheelEvent& event)
|
||||
{
|
||||
onMouseWheelEditing (this);
|
||||
|
||||
float v = getValueNormalized ();
|
||||
if (buttonStateFromEventModifiers (event.modifiers) & kZoomModifier)
|
||||
v += 0.1f * static_cast<float> (event.deltaY) * getWheelInc ();
|
||||
else
|
||||
v += static_cast<float> (event.deltaY) * getWheelInc ();
|
||||
setValueNormalized (v);
|
||||
|
||||
if (isDirty ())
|
||||
{
|
||||
invalid ();
|
||||
valueChanged ();
|
||||
}
|
||||
event.consumed = true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CKnobBase::onKeyboardEvent (KeyboardEvent& event)
|
||||
{
|
||||
if (event.type != EventType::KeyDown)
|
||||
return;
|
||||
switch (event.virt)
|
||||
{
|
||||
case VirtualKey::Up :
|
||||
case VirtualKey::Right :
|
||||
case VirtualKey::Down :
|
||||
case VirtualKey::Left :
|
||||
{
|
||||
float distance = 1.f;
|
||||
if (event.virt == VirtualKey::Down || event.virt == VirtualKey::Left)
|
||||
distance = -distance;
|
||||
|
||||
float v = getValueNormalized ();
|
||||
if (buttonStateFromEventModifiers (event.modifiers) & kZoomModifier)
|
||||
v += 0.1f * distance * getWheelInc ();
|
||||
else
|
||||
v += distance * getWheelInc ();
|
||||
setValueNormalized (v);
|
||||
|
||||
if (isDirty ())
|
||||
{
|
||||
invalid ();
|
||||
beginEdit ();
|
||||
valueChanged ();
|
||||
endEdit ();
|
||||
}
|
||||
event.consumed = true;
|
||||
}
|
||||
case VirtualKey::Escape:
|
||||
{
|
||||
if (isEditing ())
|
||||
{
|
||||
onMouseCancel ();
|
||||
event.consumed = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CKnobBase::setStartAngle (float val)
|
||||
{
|
||||
startAngle = val;
|
||||
compute ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CKnobBase::setRangeAngle (float val)
|
||||
{
|
||||
rangeAngle = val;
|
||||
compute ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CKnobBase::compute ()
|
||||
{
|
||||
setDirty ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CKnobBase::valueToPoint (CPoint &point) const
|
||||
{
|
||||
float alpha = (value - getMin()) / (getMax() - getMin());
|
||||
alpha = startAngle + alpha*rangeAngle;
|
||||
|
||||
CPoint c (getViewSize ().getWidth () / 2., getViewSize ().getHeight () / 2.);
|
||||
double xradius = c.x - inset;
|
||||
double yradius = c.y - inset;
|
||||
|
||||
point.x = (CCoord)(c.x + cosf (alpha) * xradius + 0.5f);
|
||||
point.y = (CCoord)(c.y + sinf (alpha) * yradius + 0.5f);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
float CKnobBase::valueFromPoint (CPoint &point) const
|
||||
{
|
||||
float v;
|
||||
double d = rangeAngle * 0.5;
|
||||
double a = startAngle + d;
|
||||
|
||||
CPoint c (getViewSize ().getWidth () / 2., getViewSize ().getHeight () / 2.);
|
||||
double xradius = c.x - inset;
|
||||
double yradius = c.y - inset;
|
||||
|
||||
double dx = (point.x - c.x) / xradius;
|
||||
double dy = (point.y - c.y) / yradius;
|
||||
|
||||
double alpha = atan2 (dy, dx) - a;
|
||||
while (alpha >= Constants::pi)
|
||||
alpha -= Constants::double_pi;
|
||||
while (alpha < -Constants::pi)
|
||||
alpha += Constants::double_pi;
|
||||
|
||||
if (d < 0.0)
|
||||
alpha = -alpha;
|
||||
|
||||
if (alpha > d)
|
||||
v = getMax ();
|
||||
else if (alpha < -d)
|
||||
v = getMin ();
|
||||
else
|
||||
{
|
||||
v = float (0.5 + alpha / rangeAngle);
|
||||
v = getMin () + (v * getRange ());
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CKnobBase::setMin (float val)
|
||||
{
|
||||
CControl::setMin (val);
|
||||
if (getValue () < val)
|
||||
setValue (val);
|
||||
compute ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CKnobBase::setMax (float val)
|
||||
{
|
||||
CControl::setMax (val);
|
||||
if (getValue () > val)
|
||||
setValue (val);
|
||||
compute ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// CKnob
|
||||
//------------------------------------------------------------------------
|
||||
/*! @class CKnob
|
||||
Define a knob with a given background and foreground handle.
|
||||
The handle describes a circle over the background (between -45deg and +225deg).
|
||||
By clicking alt modifier and left mouse button the default value is used.
|
||||
By clicking alt modifier and left mouse button the value changes with a vertical move (version 2.1)
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
/**
|
||||
* CKnob constructor.
|
||||
* @param size the size of this view
|
||||
* @param listener the listener
|
||||
* @param tag the control tag
|
||||
* @param background background bitmap
|
||||
* @param handle handle bitmap
|
||||
* @param offset offset of background bitmap
|
||||
* @param drawStyle draw style
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
CKnob::CKnob (const CRect& size, IControlListener* listener, int32_t tag, CBitmap* background, CBitmap* handle, const CPoint& offset, int32_t drawStyle)
|
||||
: CKnobBase (size, listener, tag, background)
|
||||
, offset (offset)
|
||||
, drawStyle (drawStyle)
|
||||
, handleLineWidth (1.)
|
||||
, coronaInset (0)
|
||||
, coronaOutlineWidthAdd (2.)
|
||||
, pHandle (handle)
|
||||
{
|
||||
if (pHandle)
|
||||
{
|
||||
pHandle->remember ();
|
||||
inset = (CCoord)((float)pHandle->getWidth () / 2.f + 2.5f);
|
||||
}
|
||||
else
|
||||
{
|
||||
inset = 3;
|
||||
}
|
||||
|
||||
colorShadowHandle = kGreyCColor;
|
||||
colorHandle = kWhiteCColor;
|
||||
coronaLineStyle = kLineOnOffDash;
|
||||
coronaLineStyle.getDashLengths ()[1] = 2.;
|
||||
|
||||
setWantsFocus (true);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CKnob::CKnob (const CKnob& v)
|
||||
: CKnobBase (v)
|
||||
, offset (v.offset)
|
||||
, drawStyle (v.drawStyle)
|
||||
, colorHandle (v.colorHandle)
|
||||
, colorShadowHandle (v.colorShadowHandle)
|
||||
, handleLineWidth (v.handleLineWidth)
|
||||
, coronaInset (v.coronaInset)
|
||||
, coronaOutlineWidthAdd (v.coronaInset)
|
||||
, coronaLineStyle (v.coronaLineStyle)
|
||||
, pHandle (v.pHandle)
|
||||
{
|
||||
if (pHandle)
|
||||
pHandle->remember ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CKnob::~CKnob () noexcept
|
||||
{
|
||||
if (pHandle)
|
||||
pHandle->forget ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool CKnob::drawFocusOnTop ()
|
||||
{
|
||||
if (drawStyle & kCoronaDrawing && wantsFocus ())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return CKnobBase::drawFocusOnTop ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool CKnob::getFocusPath (CGraphicsPath &outPath)
|
||||
{
|
||||
if (drawStyle & kCoronaDrawing && wantsFocus ())
|
||||
{
|
||||
CRect corona (getViewSize ());
|
||||
corona.inset (coronaInset, coronaInset);
|
||||
corona.inset (handleLineWidth/2., handleLineWidth/2.);
|
||||
outPath.addEllipse (corona);
|
||||
return true;
|
||||
}
|
||||
return CKnobBase::getFocusPath (outPath);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CKnob::draw (CDrawContext *pContext)
|
||||
{
|
||||
if (getDrawBackground ())
|
||||
{
|
||||
getDrawBackground ()->draw (pContext, getViewSize (), offset);
|
||||
}
|
||||
if (pHandle)
|
||||
drawHandle (pContext);
|
||||
else
|
||||
{
|
||||
if (drawStyle & kCoronaOutline)
|
||||
drawCoronaOutline (pContext);
|
||||
if (drawStyle & kCoronaDrawing)
|
||||
drawCorona (pContext);
|
||||
if (!(drawStyle & kSkipHandleDrawing))
|
||||
{
|
||||
if (drawStyle & kHandleCircleDrawing)
|
||||
drawHandleAsCircle (pContext);
|
||||
else
|
||||
drawHandleAsLine (pContext);
|
||||
}
|
||||
}
|
||||
setDirty (false);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CKnob::addArc (CGraphicsPath* path, const CRect& r, double startAngle, double sweepAngle)
|
||||
{
|
||||
CCoord w = r.getWidth ();
|
||||
CCoord h = r.getHeight ();
|
||||
double endAngle = startAngle + sweepAngle;
|
||||
if (w != h)
|
||||
{
|
||||
startAngle = atan2 (sin (startAngle) * h, cos (startAngle) * w);
|
||||
endAngle = atan2 (sin (endAngle) * h, cos (endAngle) * w);
|
||||
}
|
||||
path->addArc (r, startAngle / Constants::pi * 180, endAngle / Constants::pi * 180, sweepAngle >= 0);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CKnob::drawCoronaOutline (CDrawContext* pContext) const
|
||||
{
|
||||
auto path = owned (pContext->createGraphicsPath ());
|
||||
if (path == nullptr)
|
||||
return;
|
||||
CRect corona (getViewSize ());
|
||||
corona.inset (coronaInset, coronaInset);
|
||||
auto start = startAngle;
|
||||
auto range = rangeAngle;
|
||||
if (coronaOutlineWidthAdd && (drawStyle & kCoronaLineCapButt))
|
||||
{
|
||||
auto a = static_cast<float> (coronaOutlineWidthAdd / getWidth ());
|
||||
start -= a;
|
||||
range += a * 2.f;
|
||||
}
|
||||
addArc (path, corona, start, range);
|
||||
pContext->setFrameColor (colorShadowHandle);
|
||||
CLineStyle lineStyle (kLineSolid);
|
||||
if (!(drawStyle & kCoronaLineCapButt))
|
||||
lineStyle.setLineCap (CLineStyle::kLineCapRound);
|
||||
pContext->setLineStyle (lineStyle);
|
||||
pContext->setLineWidth (handleLineWidth+coronaOutlineWidthAdd);
|
||||
pContext->setDrawMode (kAntiAliasing | kNonIntegralMode);
|
||||
pContext->drawGraphicsPath (path, CDrawContext::kPathStroked);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CKnob::drawCorona (CDrawContext* pContext) const
|
||||
{
|
||||
auto path = owned (pContext->createGraphicsPath ());
|
||||
if (path == nullptr)
|
||||
return;
|
||||
float coronaValue = getValueNormalized ();
|
||||
if (drawStyle & kCoronaInverted)
|
||||
coronaValue = 1.f - coronaValue;
|
||||
CRect corona (getViewSize ());
|
||||
corona.inset (coronaInset, coronaInset);
|
||||
if (drawStyle & kCoronaFromCenter)
|
||||
addArc (path, corona, 1.5 * Constants::pi, rangeAngle * (coronaValue - 0.5));
|
||||
else
|
||||
{
|
||||
if (drawStyle & kCoronaInverted)
|
||||
addArc (path, corona, startAngle + rangeAngle, -rangeAngle * coronaValue);
|
||||
else
|
||||
addArc (path, corona, startAngle, rangeAngle * coronaValue);
|
||||
}
|
||||
pContext->setFrameColor (coronaColor);
|
||||
if (!(drawStyle & kCoronaLineCapButt))
|
||||
{
|
||||
CLineStyle lineStyle (kLineSolid);
|
||||
lineStyle.setLineCap (CLineStyle::kLineCapRound);
|
||||
pContext->setLineStyle (lineStyle);
|
||||
}
|
||||
else if (drawStyle & kCoronaLineDashDot)
|
||||
pContext->setLineStyle (coronaLineStyle);
|
||||
else
|
||||
pContext->setLineStyle (kLineSolid);
|
||||
|
||||
pContext->setLineWidth (handleLineWidth);
|
||||
pContext->setDrawMode (kAntiAliasing | kNonIntegralMode);
|
||||
pContext->drawGraphicsPath (path, CDrawContext::kPathStroked);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CKnob::drawHandleAsCircle (CDrawContext* pContext) const
|
||||
{
|
||||
CPoint where;
|
||||
valueToPoint (where);
|
||||
|
||||
where.offset (getViewSize ().left, getViewSize ().top);
|
||||
CRect r (where.x - 0.5, where.y - 0.5, where.x + 0.5, where.y + 0.5);
|
||||
r.extend (handleLineWidth, handleLineWidth);
|
||||
pContext->setDrawMode (kAntiAliasing);
|
||||
pContext->setFrameColor (colorShadowHandle);
|
||||
pContext->setFillColor (colorHandle);
|
||||
pContext->setLineWidth (0.5);
|
||||
pContext->setLineStyle (kLineSolid);
|
||||
pContext->setDrawMode (kAntiAliasing | kNonIntegralMode);
|
||||
pContext->drawEllipse (r, kDrawFilledAndStroked);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CKnob::drawHandleAsLine (CDrawContext* pContext) const
|
||||
{
|
||||
CPoint where;
|
||||
valueToPoint (where);
|
||||
|
||||
CPoint origin (getViewSize ().getWidth () / 2, getViewSize ().getHeight () / 2);
|
||||
where.offset (getViewSize ().left - 1, getViewSize ().top);
|
||||
origin.offset (getViewSize ().left - 1, getViewSize ().top);
|
||||
pContext->setFrameColor (colorShadowHandle);
|
||||
pContext->setLineWidth (handleLineWidth);
|
||||
pContext->setLineStyle (CLineStyle (CLineStyle::kLineCapRound));
|
||||
pContext->setDrawMode (kAntiAliasing | kNonIntegralMode);
|
||||
pContext->drawLine (where, origin);
|
||||
|
||||
where.offset (1, -1);
|
||||
origin.offset (1, -1);
|
||||
pContext->setFrameColor (colorHandle);
|
||||
pContext->drawLine (where, origin);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CKnob::drawHandle (CDrawContext *pContext)
|
||||
{
|
||||
CPoint where;
|
||||
valueToPoint (where);
|
||||
|
||||
CCoord width = pHandle->getWidth ();
|
||||
CCoord height = pHandle->getHeight ();
|
||||
where.offset (getViewSize ().left - width / 2, getViewSize ().top - height / 2);
|
||||
|
||||
where.x = floor (where.x);
|
||||
where.y = floor (where.y);
|
||||
|
||||
CRect handleSize (0, 0, width, height);
|
||||
handleSize.offset (where.x, where.y);
|
||||
pHandle->draw (pContext, handleSize);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CKnob::setCoronaInset (CCoord inset)
|
||||
{
|
||||
if (inset != coronaInset)
|
||||
{
|
||||
coronaInset = inset;
|
||||
setDirty ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CKnob::setCoronaColor (CColor color)
|
||||
{
|
||||
if (color != coronaColor)
|
||||
{
|
||||
coronaColor = color;
|
||||
setDirty ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CKnob::setColorShadowHandle (CColor color)
|
||||
{
|
||||
if (color != colorShadowHandle)
|
||||
{
|
||||
colorShadowHandle = color;
|
||||
setDirty ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CKnob::setColorHandle (CColor color)
|
||||
{
|
||||
if (color != colorHandle)
|
||||
{
|
||||
colorHandle = color;
|
||||
setDirty ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CKnob::setHandleLineWidth (CCoord width)
|
||||
{
|
||||
if (width != handleLineWidth)
|
||||
{
|
||||
handleLineWidth = width;
|
||||
setDirty ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CKnob::setCoronaOutlineWidthAdd (CCoord width)
|
||||
{
|
||||
if (width != coronaOutlineWidthAdd)
|
||||
{
|
||||
coronaOutlineWidthAdd = width;
|
||||
setDirty ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
const CLineStyle::CoordVector& CKnob::getCoronaDashDotLengths () const
|
||||
{
|
||||
return coronaLineStyle.getDashLengths ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CKnob::setCoronaDashDotLengths (const CLineStyle::CoordVector& lengths)
|
||||
{
|
||||
if (coronaLineStyle.getDashLengths () != lengths)
|
||||
{
|
||||
coronaLineStyle.getDashLengths () = lengths;
|
||||
setDirty ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CKnob::setDrawStyle (int32_t style)
|
||||
{
|
||||
if (style != drawStyle)
|
||||
{
|
||||
drawStyle = style;
|
||||
setDirty ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CKnob::setHandleBitmap (CBitmap* bitmap)
|
||||
{
|
||||
if (pHandle)
|
||||
{
|
||||
pHandle->forget ();
|
||||
pHandle = nullptr;
|
||||
}
|
||||
|
||||
if (bitmap)
|
||||
{
|
||||
pHandle = bitmap;
|
||||
pHandle->remember ();
|
||||
inset = (CCoord)((float)pHandle->getWidth () / 2.f + 2.5f);
|
||||
}
|
||||
setDirty ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// CAnimKnob
|
||||
//------------------------------------------------------------------------
|
||||
/*! @class CAnimKnob
|
||||
Such as a CKnob control object, but there is a unique bitmap which contains different views
|
||||
(subbitmaps) of this knob. According to the value, a specific subbitmap is displayed. Use a
|
||||
CMultiFrameBitmap for its background bitmap.
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
/**
|
||||
* CAnimKnob constructor.
|
||||
* @param size the size of this view
|
||||
* @param listener the listener
|
||||
* @param tag the control tag
|
||||
* @param background the background bitmap
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
CAnimKnob::CAnimKnob (const CRect& size, IControlListener* listener, int32_t tag,
|
||||
CBitmap* background)
|
||||
: CKnobBase (size, listener, tag, background), bInverseBitmap (false)
|
||||
{
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
heightOfOneImage = size.getHeight ();
|
||||
setNumSubPixmaps (0);
|
||||
if (background)
|
||||
{
|
||||
if (auto frameBitmap = dynamic_cast<CMultiFrameBitmap*> (background))
|
||||
{
|
||||
heightOfOneImage = frameBitmap->getFrameSize ().y;
|
||||
setNumSubPixmaps (frameBitmap->getNumFrames ());
|
||||
}
|
||||
else
|
||||
{
|
||||
setNumSubPixmaps ((int32_t)(background->getHeight () / heightOfOneImage));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
inset = 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CAnimKnob::CAnimKnob (const CAnimKnob& v)
|
||||
: CKnobBase (v)
|
||||
, bInverseBitmap (v.bInverseBitmap)
|
||||
{
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
setNumSubPixmaps (v.subPixmaps);
|
||||
setHeightOfOneImage (v.heightOfOneImage);
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool CAnimKnob::sizeToFit ()
|
||||
{
|
||||
if (auto bitmap = getDrawBackground ())
|
||||
{
|
||||
CRect vs (getViewSize ());
|
||||
if (auto frameBitmap = dynamic_cast<CMultiFrameBitmap*> (bitmap))
|
||||
{
|
||||
vs.setSize (frameBitmap->getFrameSize ());
|
||||
}
|
||||
else
|
||||
{
|
||||
vs.setWidth (bitmap->getWidth ());
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
vs.setHeight (getHeightOfOneImage ());
|
||||
#else
|
||||
vs.setHeight (bitmap->getHeight ());
|
||||
#endif
|
||||
}
|
||||
setViewSize (vs);
|
||||
setMouseableArea (vs);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
//------------------------------------------------------------------------
|
||||
/**
|
||||
* CAnimKnob constructor.
|
||||
* @param size the size of this view
|
||||
* @param listener the listener
|
||||
* @param tag the control tag
|
||||
* @param subPixmaps number of sub bitmaps in background
|
||||
* @param heightOfOneImage the height of one sub bitmap
|
||||
* @param background the background bitmap
|
||||
* @param offset unused
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
CAnimKnob::CAnimKnob (const CRect& size, IControlListener* listener, int32_t tag,
|
||||
int32_t subPixmaps, CCoord heightOfOneImage, CBitmap* background,
|
||||
const CPoint& offset)
|
||||
: CKnobBase (size, listener, tag, background), bInverseBitmap (false)
|
||||
{
|
||||
vstgui_assert (background && !dynamic_cast<CMultiFrameBitmap*> (background),
|
||||
"Use the other constrcutor when using a CMultiFrameBitmap");
|
||||
setNumSubPixmaps (subPixmaps);
|
||||
setHeightOfOneImage (heightOfOneImage);
|
||||
inset = 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
void CAnimKnob::setHeightOfOneImage (const CCoord& height)
|
||||
{
|
||||
if (dynamic_cast<CMultiFrameBitmap*> (getDrawBackground ()))
|
||||
return;
|
||||
IMultiBitmapControl::setHeightOfOneImage (height);
|
||||
if (getDrawBackground () && heightOfOneImage > 0)
|
||||
setNumSubPixmaps ((int32_t)(getDrawBackground ()->getHeight () / heightOfOneImage));
|
||||
}
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
void CAnimKnob::setBackground (CBitmap *background)
|
||||
{
|
||||
CKnobBase::setBackground (background);
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
if (auto frameBitmap = dynamic_cast<CMultiFrameBitmap*> (background))
|
||||
{
|
||||
heightOfOneImage = frameBitmap->getFrameSize ().y;
|
||||
setNumSubPixmaps (frameBitmap->getNumFrames ());
|
||||
return;
|
||||
}
|
||||
|
||||
if (heightOfOneImage == 0)
|
||||
heightOfOneImage = getViewSize ().getHeight ();
|
||||
if (background && heightOfOneImage > 0)
|
||||
setNumSubPixmaps ((int32_t)(background->getHeight () / heightOfOneImage));
|
||||
#endif
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CAnimKnob::draw (CDrawContext *pContext)
|
||||
{
|
||||
if (auto bitmap = getDrawBackground ())
|
||||
{
|
||||
if (auto mfb = dynamic_cast<CMultiFrameBitmap*> (bitmap))
|
||||
{
|
||||
auto frameIndex = getMultiFrameBitmapIndex (*mfb, getValueNormalized ());
|
||||
if (bInverseBitmap)
|
||||
frameIndex = getInverseIndex (*mfb, frameIndex);
|
||||
mfb->drawFrame (pContext, frameIndex, getViewSize ().getTopLeft ());
|
||||
}
|
||||
else
|
||||
{
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
CPoint where (0, 0);
|
||||
float val = getValueNormalized ();
|
||||
if (val >= 0.f && heightOfOneImage > 0.)
|
||||
{
|
||||
CCoord tmp = heightOfOneImage * (getNumSubPixmaps () - 1);
|
||||
if (bInverseBitmap)
|
||||
where.y = floor ((1. - val) * tmp);
|
||||
else
|
||||
where.y = floor (val * tmp);
|
||||
where.y -= (int32_t)where.y % (int32_t)heightOfOneImage;
|
||||
}
|
||||
bitmap->draw (pContext, getViewSize (), where);
|
||||
#else
|
||||
CView::draw (pContext);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
setDirty (false);
|
||||
}
|
||||
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,202 @@
|
||||
// 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 "../ccolor.h"
|
||||
#include "../clinestyle.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
class CKnobBase : public CControl, protected CMouseWheelEditingSupport
|
||||
{
|
||||
public:
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @name CKnobBase Methods
|
||||
//-----------------------------------------------------------------------------
|
||||
//@{
|
||||
virtual void valueToPoint (CPoint& point) const;
|
||||
virtual float valueFromPoint (CPoint& point) const;
|
||||
|
||||
virtual void setStartAngle (float val);
|
||||
virtual float getStartAngle () const { return startAngle; }
|
||||
|
||||
virtual void setRangeAngle (float val);
|
||||
virtual float getRangeAngle () const { return rangeAngle; }
|
||||
|
||||
virtual void setZoomFactor (float val) { zoomFactor = val; }
|
||||
virtual float getZoomFactor () const { return zoomFactor; }
|
||||
|
||||
virtual CCoord getInsetValue () const { return inset; }
|
||||
virtual void setInsetValue (CCoord val) { inset = val; }
|
||||
|
||||
virtual void setKnobRange (float val) { if (val > 0.f) knobRange = val; }
|
||||
virtual float getKnobRange () const { return knobRange; }
|
||||
//@}
|
||||
|
||||
// overrides
|
||||
void onMouseWheelEvent (MouseWheelEvent& event) override;
|
||||
void onKeyboardEvent (KeyboardEvent& event) override;
|
||||
void setViewSize (const CRect &rect, bool invalid = true) override;
|
||||
bool sizeToFit () override;
|
||||
void setMin (float val) override;
|
||||
void setMax (float val) override;
|
||||
|
||||
CMouseEventResult onMouseDown (CPoint& where, const CButtonState& buttons) override;
|
||||
CMouseEventResult onMouseUp (CPoint& where, const CButtonState& buttons) override;
|
||||
CMouseEventResult onMouseMoved (CPoint& where, const CButtonState& buttons) override;
|
||||
CMouseEventResult onMouseCancel () override;
|
||||
|
||||
CLASS_METHODS_VIRTUAL(CKnobBase, CControl)
|
||||
protected:
|
||||
CKnobBase (const CRect& size, IControlListener* listener, int32_t tag, CBitmap* background);
|
||||
CKnobBase (const CKnobBase& knob);
|
||||
void compute ();
|
||||
|
||||
float startAngle, rangeAngle;
|
||||
float zoomFactor;
|
||||
float knobRange;
|
||||
CCoord inset;
|
||||
|
||||
private:
|
||||
struct MouseEditingState;
|
||||
|
||||
MouseEditingState& getMouseEditingState ();
|
||||
void clearMouseEditingState ();
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CKnob Declaration
|
||||
//! @brief a knob control
|
||||
/// @ingroup controls
|
||||
//-----------------------------------------------------------------------------
|
||||
class CKnob : public CKnobBase
|
||||
{
|
||||
public:
|
||||
enum DrawStyle {
|
||||
kLegacyHandleLineDrawing = 0,
|
||||
kHandleCircleDrawing = 1 << 0,
|
||||
kCoronaDrawing = 1 << 1,
|
||||
kCoronaFromCenter = 1 << 2,
|
||||
kCoronaInverted = 1 << 3,
|
||||
kCoronaLineDashDot = 1 << 4,
|
||||
kCoronaOutline = 1 << 5,
|
||||
kCoronaLineCapButt = 1 << 6,
|
||||
kSkipHandleDrawing = 1 << 7,
|
||||
};
|
||||
|
||||
CKnob (const CRect& size, IControlListener* listener, int32_t tag, CBitmap* background, CBitmap* handle, const CPoint& offset = CPoint (0, 0), int32_t drawStyle = kLegacyHandleLineDrawing);
|
||||
CKnob (const CKnob& knob);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @name CKnob Methods
|
||||
//-----------------------------------------------------------------------------
|
||||
//@{
|
||||
int32_t getDrawStyle () const { return drawStyle; }
|
||||
virtual void setDrawStyle (int32_t style);
|
||||
|
||||
CColor getCoronaColor () const { return coronaColor; }
|
||||
virtual void setCoronaColor (CColor color);
|
||||
|
||||
CCoord getCoronaInset () const { return coronaInset; }
|
||||
virtual void setCoronaInset (CCoord inset);
|
||||
|
||||
CColor getColorShadowHandle () const { return colorShadowHandle; }
|
||||
virtual void setColorShadowHandle (CColor color);
|
||||
|
||||
CColor getColorHandle () const { return colorHandle; }
|
||||
virtual void setColorHandle (CColor color);
|
||||
|
||||
CCoord getHandleLineWidth () const { return handleLineWidth; }
|
||||
virtual void setHandleLineWidth (CCoord width);
|
||||
|
||||
CCoord getCoronaOutlineWidthAdd () const { return coronaOutlineWidthAdd; }
|
||||
virtual void setCoronaOutlineWidthAdd (CCoord width);
|
||||
|
||||
const CLineStyle::CoordVector& getCoronaDashDotLengths () const;
|
||||
virtual void setCoronaDashDotLengths (const CLineStyle::CoordVector& lengths);
|
||||
|
||||
CBitmap* getHandleBitmap () const { return pHandle; }
|
||||
void setHandleBitmap (CBitmap* bitmap);
|
||||
//@}
|
||||
|
||||
// overrides
|
||||
void draw (CDrawContext* pContext) override;
|
||||
bool getFocusPath (CGraphicsPath& outPath) override;
|
||||
bool drawFocusOnTop () override;
|
||||
|
||||
CLASS_METHODS(CKnob, CKnobBase)
|
||||
protected:
|
||||
~CKnob () noexcept override;
|
||||
|
||||
virtual void drawHandle (CDrawContext* pContext);
|
||||
virtual void drawCoronaOutline (CDrawContext* pContext) const;
|
||||
virtual void drawCorona (CDrawContext* pContext) const;
|
||||
virtual void drawHandleAsCircle (CDrawContext* pContext) const;
|
||||
virtual void drawHandleAsLine (CDrawContext* pContext) const;
|
||||
|
||||
static void addArc (CGraphicsPath* path, const CRect& r, double startAngle, double sweepAngle);
|
||||
|
||||
CPoint offset;
|
||||
|
||||
int32_t drawStyle;
|
||||
CColor colorHandle, colorShadowHandle, coronaColor;
|
||||
CCoord handleLineWidth;
|
||||
CCoord coronaInset;
|
||||
CCoord coronaOutlineWidthAdd;
|
||||
|
||||
CLineStyle coronaLineStyle;
|
||||
CBitmap* pHandle;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CAnimKnob Declaration
|
||||
//! @brief a bitmap knob control
|
||||
/// @ingroup controls uses_multi_frame_bitmaps
|
||||
//-----------------------------------------------------------------------------
|
||||
class CAnimKnob : public CKnobBase,
|
||||
public MultiFrameBitmapView<CAnimKnob>
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
,
|
||||
public IMultiBitmapControl
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
CAnimKnob (const CRect& size, IControlListener* listener, int32_t tag, CBitmap* background);
|
||||
CAnimKnob (const CAnimKnob& knob);
|
||||
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
CAnimKnob (const CRect& size, IControlListener* listener, int32_t tag, int32_t subPixmaps,
|
||||
CCoord heightOfOneImage, CBitmap* background, const CPoint& offset = CPoint (0, 0));
|
||||
void setHeightOfOneImage (const CCoord& height) override;
|
||||
void setNumSubPixmaps (int32_t numSubPixmaps) override
|
||||
{
|
||||
IMultiBitmapControl::setNumSubPixmaps (numSubPixmaps);
|
||||
invalid ();
|
||||
}
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @name CAnimKnob Methods
|
||||
//-----------------------------------------------------------------------------
|
||||
//@{
|
||||
void setInverseBitmap (bool val) { bInverseBitmap = val; }
|
||||
bool getInverseBitmap () const { return bInverseBitmap; }
|
||||
//@}
|
||||
|
||||
// overrides
|
||||
void draw (CDrawContext* pContext) override;
|
||||
bool sizeToFit () override;
|
||||
void setBackground (CBitmap* background) override;
|
||||
|
||||
CLASS_METHODS(CAnimKnob, CKnobBase)
|
||||
protected:
|
||||
~CAnimKnob () noexcept override = default;
|
||||
bool bInverseBitmap;
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,568 @@
|
||||
// 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 "../cframe.h"
|
||||
#include "../cgraphicspath.h"
|
||||
#include "../cscrollview.h"
|
||||
#include "../events.h"
|
||||
#include "clistcontrol.h"
|
||||
#include <vector>
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
namespace VSTGUI {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
struct CListControl::Impl
|
||||
{
|
||||
SharedPointer<IListControlDrawer> drawer;
|
||||
SharedPointer<IListControlConfigurator> configurator;
|
||||
|
||||
std::vector<CListControlRowDesc> rowDescriptions;
|
||||
Optional<int32_t> hoveredRow {};
|
||||
bool doHoverCheck {false};
|
||||
CCoord minHeight {0.};
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CListControl::CListControl (const CRect& size, IControlListener* listener, int32_t tag)
|
||||
: CControl (size, listener, tag)
|
||||
{
|
||||
impl = std::unique_ptr<Impl> (new Impl);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CListControl::~CListControl () = default;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CListControl::setDrawer (IListControlDrawer* d)
|
||||
{
|
||||
impl->drawer = d;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CListControl::setConfigurator (IListControlConfigurator* c)
|
||||
{
|
||||
impl->configurator = c;
|
||||
recalculateLayout ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
IListControlDrawer* CListControl::getDrawer () const
|
||||
{
|
||||
return impl->drawer;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
IListControlConfigurator* CListControl::getConfigurator () const
|
||||
{
|
||||
return impl->configurator;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
Optional<int32_t> CListControl::getHoveredRow () const
|
||||
{
|
||||
if (impl->hoveredRow)
|
||||
return makeOptional (*impl->hoveredRow);
|
||||
return {};
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
int32_t CListControl::getNumRows () const
|
||||
{
|
||||
auto numRows = static_cast<int32_t> (std::round (getRange ())) + 1;
|
||||
return std::max (0, numRows);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
int32_t CListControl::getIntValue () const
|
||||
{
|
||||
return static_cast<int32_t> (std::round (getValue ()));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CListControl::recalculateLayout ()
|
||||
{
|
||||
if (!impl->configurator)
|
||||
return;
|
||||
|
||||
CCoord height = 0.;
|
||||
auto numRows = getNumRows ();
|
||||
impl->rowDescriptions.resize (static_cast<size_t> (numRows));
|
||||
impl->doHoverCheck = false;
|
||||
|
||||
for (auto row = 0; row < numRows; ++row)
|
||||
{
|
||||
impl->rowDescriptions[row] = impl->configurator->getRowDesc (row);
|
||||
height += impl->rowDescriptions[row].height;
|
||||
impl->doHoverCheck |= (impl->rowDescriptions[row].flags & CListControlRowDesc::Hoverable) != 0;
|
||||
}
|
||||
|
||||
if (impl->minHeight > 0 && height < impl->minHeight)
|
||||
height = impl->minHeight;
|
||||
|
||||
auto viewSize = getViewSize ();
|
||||
if (viewSize.getHeight () != height)
|
||||
{
|
||||
viewSize.setHeight (height);
|
||||
setViewSize (viewSize);
|
||||
setMouseableArea (viewSize);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
Optional<CRect> CListControl::getRowRect (int32_t row) const
|
||||
{
|
||||
if (row < getMinRowIndex () || row > getMaxRowIndex ())
|
||||
return {};
|
||||
row -= getMinRowIndex ();
|
||||
CRect rowSize;
|
||||
rowSize.setWidth (getWidth ());
|
||||
for (auto i = 0u; i < impl->rowDescriptions.size (); ++i)
|
||||
{
|
||||
rowSize.setHeight (impl->rowDescriptions[i].height);
|
||||
if (i == row)
|
||||
break;
|
||||
rowSize.offset (0, impl->rowDescriptions[i].height);
|
||||
}
|
||||
rowSize.offset (getViewSize ().getTopLeft ());
|
||||
return makeOptional (rowSize);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CListControl::invalidRow (int32_t row)
|
||||
{
|
||||
if (auto rect = getRowRect (row))
|
||||
invalidRect (*rect);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
Optional<int32_t> CListControl::getRowAtPoint (CPoint where) const
|
||||
{
|
||||
where.offsetInverse (getViewSize ().getTopLeft ());
|
||||
|
||||
auto numRows = getNumRows ();
|
||||
for (auto row = 0; row < numRows; ++row)
|
||||
{
|
||||
if (where.y < impl->rowDescriptions[row].height)
|
||||
return {row + getMinRowIndex ()};
|
||||
where.y -= impl->rowDescriptions[row].height;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CListControl::draw (CDrawContext* context)
|
||||
{
|
||||
drawRect (context, getViewSize ());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CListControl::drawRect (CDrawContext* context, const CRect& updateRect)
|
||||
{
|
||||
setDirty (false);
|
||||
ConcatClip cc (*context, updateRect);
|
||||
if (cc.isEmpty ())
|
||||
return;
|
||||
|
||||
if (auto bitmap = getDrawBackground ())
|
||||
bitmap->draw (context, getViewSize ());
|
||||
|
||||
if (!impl->drawer)
|
||||
return;
|
||||
|
||||
if (!getTransparency ())
|
||||
impl->drawer->drawBackground (context, getViewSize ());
|
||||
|
||||
CRect rowSize;
|
||||
rowSize.setTopLeft (getViewSize ().getTopLeft ());
|
||||
rowSize.setWidth (getWidth ());
|
||||
rowSize.setHeight (0);
|
||||
auto numRows = getNumRows ();
|
||||
auto selectedRow = static_cast<int32_t> (getNormalizedRowIndex (getIntValue ()));
|
||||
for (auto row = 0; row < numRows; ++row)
|
||||
{
|
||||
rowSize.setHeight (impl->rowDescriptions[row].height);
|
||||
if (updateRect.rectOverlap (rowSize))
|
||||
{
|
||||
IListControlDrawer::Row::Flags flags;
|
||||
if (selectedRow == row)
|
||||
flags = IListControlDrawer::Row::Selected;
|
||||
if (impl->rowDescriptions[row].flags & CListControlRowDesc::Selectable)
|
||||
flags |= IListControlDrawer::Row::Selectable;
|
||||
if (impl->hoveredRow && *impl->hoveredRow == row + getMinRowIndex ())
|
||||
flags |= IListControlDrawer::Row::Hovered;
|
||||
if (row == numRows - 1)
|
||||
flags |= IListControlDrawer::Row::LastRow;
|
||||
impl->drawer->drawRow (context, rowSize, {row + getMinRowIndex (), flags});
|
||||
}
|
||||
rowSize.offset (0, impl->rowDescriptions[row].height);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool CListControl::attached (CView* parent)
|
||||
{
|
||||
if (auto scrollView = dynamic_cast<CScrollView*> (parent->getParentView ()))
|
||||
{
|
||||
impl->minHeight = scrollView->calculateOptimalContainerSize ().getHeight ();
|
||||
struct SizeListener : ViewListenerAdapter
|
||||
{
|
||||
SizeListener (CListControl* listControl, CScrollView* scrollView)
|
||||
: control (listControl), scrollView (scrollView)
|
||||
{
|
||||
listControl->registerViewListener (this);
|
||||
scrollView->registerViewListener (this);
|
||||
}
|
||||
~SizeListener () noexcept
|
||||
{
|
||||
control->unregisterViewListener (this);
|
||||
scrollView->unregisterViewListener (this);
|
||||
}
|
||||
void viewSizeChanged (CView* view, const CRect& oldSize) override
|
||||
{
|
||||
if (view != scrollView)
|
||||
return;
|
||||
control->impl->minHeight =
|
||||
scrollView->calculateOptimalContainerSize ().getHeight ();
|
||||
control->recalculateLayout ();
|
||||
}
|
||||
void viewWillDelete (CView* view) override
|
||||
{
|
||||
if (view == control || view == scrollView)
|
||||
delete this;
|
||||
}
|
||||
void viewAttached (CView* view) override {}
|
||||
void viewRemoved (CView* view) override {}
|
||||
|
||||
CListControl* control {nullptr};
|
||||
CScrollView* scrollView {nullptr};
|
||||
};
|
||||
new SizeListener (this, scrollView);
|
||||
}
|
||||
recalculateLayout ();
|
||||
return CControl::attached (parent);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CListControl::setMin (float val)
|
||||
{
|
||||
if (getMin () != val && val < getMax ())
|
||||
{
|
||||
auto ov = getValue ();
|
||||
CControl::setMin (val);
|
||||
if (isAttached ())
|
||||
recalculateLayout ();
|
||||
if (ov != getValue ())
|
||||
valueChanged ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CListControl::setMax (float val)
|
||||
{
|
||||
if (getMax () != val && val >= getMin ())
|
||||
{
|
||||
auto ov = getValue ();
|
||||
CControl::setMax (val);
|
||||
if (isAttached ())
|
||||
recalculateLayout ();
|
||||
if (ov != getValue ())
|
||||
valueChanged ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
size_t CListControl::getNormalizedRowIndex (int32_t row) const
|
||||
{
|
||||
vstgui_assert (row >= getMinRowIndex ());
|
||||
return row - getMinRowIndex ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMouseEventResult CListControl::onMouseDown (CPoint& where, const CButtonState& buttons)
|
||||
{
|
||||
if (buttons.isLeftButton ())
|
||||
return kMouseEventHandled;
|
||||
return kMouseDownEventHandledButDontNeedMovedOrUpEvents;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CListControl::clearHoveredRow ()
|
||||
{
|
||||
if (impl->hoveredRow)
|
||||
{
|
||||
invalidRow (*impl->hoveredRow);
|
||||
impl->hoveredRow.reset ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMouseEventResult CListControl::onMouseMoved (CPoint& where, const CButtonState& buttons)
|
||||
{
|
||||
if (impl->doHoverCheck)
|
||||
{
|
||||
auto row = getRowAtPoint (where);
|
||||
if (row)
|
||||
{
|
||||
if (impl->rowDescriptions[getNormalizedRowIndex (*row)].flags &
|
||||
CListControlRowDesc::Hoverable)
|
||||
{
|
||||
if (!impl->hoveredRow || *impl->hoveredRow != *row)
|
||||
{
|
||||
clearHoveredRow ();
|
||||
impl->hoveredRow = makeOptional (*row);
|
||||
invalidRow (*row);
|
||||
}
|
||||
}
|
||||
else
|
||||
clearHoveredRow ();
|
||||
}
|
||||
else
|
||||
clearHoveredRow ();
|
||||
}
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMouseEventResult CListControl::onMouseUp (CPoint& where, const CButtonState& buttons)
|
||||
{
|
||||
if (impl->rowDescriptions.empty () || !buttons.isLeftButton ())
|
||||
return kMouseEventHandled;
|
||||
|
||||
auto row = getRowAtPoint (where);
|
||||
if (row && getIntValue () != *row)
|
||||
{
|
||||
if (rowSelectable (*row))
|
||||
{
|
||||
invalidRow (getIntValue ());
|
||||
beginEdit ();
|
||||
setValue (static_cast<float> (*row));
|
||||
valueChanged ();
|
||||
endEdit ();
|
||||
invalidRow (getIntValue ());
|
||||
}
|
||||
}
|
||||
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMouseEventResult CListControl::onMouseExited (CPoint& where, const CButtonState& buttons)
|
||||
{
|
||||
clearHoveredRow ();
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
int32_t CListControl::getMinRowIndex () const
|
||||
{
|
||||
return static_cast<int32_t> (getMin ());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
int32_t CListControl::getMaxRowIndex () const
|
||||
{
|
||||
return static_cast<int32_t> (getMax ());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
int32_t CListControl::getNextSelectableRow (int32_t r, int32_t direction) const
|
||||
{
|
||||
auto minRowIndex = getMinRowIndex ();
|
||||
auto maxRowIndex = getMaxRowIndex ();
|
||||
int32_t row = r;
|
||||
do
|
||||
{
|
||||
row += direction;
|
||||
if (row > maxRowIndex)
|
||||
row = minRowIndex;
|
||||
else if (row < minRowIndex)
|
||||
row = maxRowIndex;
|
||||
if (rowSelectable (row))
|
||||
break;
|
||||
} while (row != r);
|
||||
return row;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool CListControl::rowSelectable (int32_t row) const
|
||||
{
|
||||
return (impl->rowDescriptions[getNormalizedRowIndex (row)].flags &
|
||||
CListControlRowDesc::Selectable) != 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CListControl::onKeyboardEvent (KeyboardEvent& event)
|
||||
{
|
||||
if (event.type != EventType::KeyDown)
|
||||
return;
|
||||
if (getMouseEnabled () && event.character == 0)
|
||||
{
|
||||
int32_t newRow = getIntValue ();
|
||||
switch (event.virt)
|
||||
{
|
||||
default: return;
|
||||
case VirtualKey::Home:
|
||||
{
|
||||
if (!event.modifiers.empty ())
|
||||
break;
|
||||
newRow = getMinRowIndex ();
|
||||
if (!rowSelectable (newRow))
|
||||
newRow = getNextSelectableRow (newRow, 1);
|
||||
break;
|
||||
}
|
||||
case VirtualKey::End:
|
||||
{
|
||||
if (!event.modifiers.empty ())
|
||||
break;
|
||||
newRow = getMaxRowIndex ();
|
||||
if (!rowSelectable (newRow))
|
||||
newRow = getNextSelectableRow (newRow, -1);
|
||||
break;
|
||||
}
|
||||
case VirtualKey::Up:
|
||||
{
|
||||
if (!event.modifiers.empty ())
|
||||
break;
|
||||
newRow = getNextSelectableRow (newRow, -1);
|
||||
break;
|
||||
}
|
||||
case VirtualKey::Down:
|
||||
{
|
||||
if (!event.modifiers.empty ())
|
||||
break;
|
||||
newRow = getNextSelectableRow (newRow, 1);
|
||||
break;
|
||||
}
|
||||
case VirtualKey::PageUp:
|
||||
{
|
||||
if (!event.modifiers.empty ())
|
||||
break;
|
||||
auto vr = getVisibleViewSize ();
|
||||
auto rr = getRowRect (newRow);
|
||||
if (rr && !vr.rectOverlap (*rr))
|
||||
{
|
||||
if (auto parent = getParentView ())
|
||||
{
|
||||
if (auto scrollView = dynamic_cast<CScrollView*> (parent->getParentView ()))
|
||||
{
|
||||
scrollView->makeRectVisible (*rr);
|
||||
onKeyboardEvent (event);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
vr.top += 2;
|
||||
if (auto firstVisibleRow = getRowAtPoint (vr.getTopLeft ()))
|
||||
{
|
||||
while (!rowSelectable (*firstVisibleRow))
|
||||
*firstVisibleRow += 1;
|
||||
if (*firstVisibleRow == getIntValue ())
|
||||
{
|
||||
vr.offset (0, -vr.getHeight ());
|
||||
if ((firstVisibleRow = getRowAtPoint (vr.getTopLeft ())))
|
||||
newRow = *firstVisibleRow;
|
||||
else
|
||||
newRow = getMinRowIndex ();
|
||||
}
|
||||
else
|
||||
{
|
||||
newRow = *firstVisibleRow;
|
||||
}
|
||||
}
|
||||
if (!rowSelectable (newRow))
|
||||
newRow = getNextSelectableRow (newRow, -1);
|
||||
break;
|
||||
}
|
||||
case VirtualKey::PageDown:
|
||||
{
|
||||
if (!event.modifiers.empty ())
|
||||
break;
|
||||
auto vr = getVisibleViewSize ();
|
||||
auto rr = getRowRect (newRow);
|
||||
if (rr && !vr.rectOverlap (*rr))
|
||||
{
|
||||
if (auto parent = getParentView ())
|
||||
{
|
||||
if (auto scrollView = dynamic_cast<CScrollView*> (parent->getParentView ()))
|
||||
{
|
||||
scrollView->makeRectVisible (*rr);
|
||||
onKeyboardEvent (event);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
vr.bottom -= 2;
|
||||
if (auto lastVisibleRow = getRowAtPoint (vr.getBottomLeft ()))
|
||||
{
|
||||
while (!rowSelectable (*lastVisibleRow))
|
||||
*lastVisibleRow -= 1;
|
||||
if (*lastVisibleRow == getIntValue ())
|
||||
{
|
||||
vr.offset (0, vr.getHeight ());
|
||||
if ((lastVisibleRow = getRowAtPoint (vr.getBottomLeft ())))
|
||||
newRow = *lastVisibleRow;
|
||||
else
|
||||
newRow = getMaxRowIndex ();
|
||||
}
|
||||
else
|
||||
{
|
||||
newRow = *lastVisibleRow;
|
||||
}
|
||||
}
|
||||
if (!rowSelectable (newRow))
|
||||
newRow = getNextSelectableRow (newRow, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (newRow != getIntValue () && rowSelectable (newRow))
|
||||
{
|
||||
invalidRow (getIntValue ());
|
||||
beginEdit ();
|
||||
setValue (static_cast<float> (newRow));
|
||||
valueChanged ();
|
||||
endEdit ();
|
||||
if (auto rowRect = getRowRect (getIntValue ()))
|
||||
{
|
||||
invalidRect (*rowRect);
|
||||
if (auto parent = getParentView ())
|
||||
{
|
||||
if (auto scrollView = dynamic_cast<CScrollView*> (parent->getParentView ()))
|
||||
scrollView->makeRectVisible (*rowRect);
|
||||
}
|
||||
}
|
||||
event.consumed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CListControl::setViewSize (const CRect& rect, bool invalid)
|
||||
{
|
||||
CControl::setViewSize (rect, invalid);
|
||||
impl->hoveredRow.reset ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool CListControl::drawFocusOnTop ()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool CListControl::getFocusPath (CGraphicsPath& outPath)
|
||||
{
|
||||
CRect r = getVisibleViewSize ();
|
||||
outPath.addRect (r);
|
||||
CCoord focusWidth = getFrame ()->getFocusWidth ();
|
||||
r.inset (focusWidth, focusWidth);
|
||||
outPath.addRect (r);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,197 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../optional.h"
|
||||
#include "../enumbitset.h"
|
||||
#include "ccontrol.h"
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
namespace VSTGUI {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
/** Control which draws a list of configurable rows
|
||||
*
|
||||
* This control needs to be setup with an instance of a IListControlDrawer and a
|
||||
* IListControlConfigurator. The number of rows is configured via the min and max values. And the
|
||||
* selected row is the value of this control.
|
||||
* The actual drawing is done via the IListControlDrawer instance. And the row configuration is
|
||||
* handled via the IListControlConfigurator instance. Every row can have different heights and
|
||||
* flags.
|
||||
*
|
||||
* @ingroup new_in_4_9
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
class CListControl final : public CControl
|
||||
{
|
||||
public:
|
||||
CListControl (const CRect& size, IControlListener* listener = nullptr, int32_t tag = -1);
|
||||
~CListControl () override;
|
||||
|
||||
void setDrawer (IListControlDrawer* d);
|
||||
void setConfigurator (IListControlConfigurator* c);
|
||||
|
||||
IListControlDrawer* getDrawer () const;
|
||||
IListControlConfigurator* getConfigurator () const;
|
||||
|
||||
void recalculateLayout ();
|
||||
|
||||
void invalidRow (int32_t row);
|
||||
Optional<int32_t> getRowAtPoint (CPoint where) const;
|
||||
Optional<CRect> getRowRect (int32_t row) const;
|
||||
Optional<int32_t> getHoveredRow () const;
|
||||
|
||||
int32_t getIntValue () const;
|
||||
int32_t getNumRows () const;
|
||||
|
||||
// overrides
|
||||
void setMin (float val) override;
|
||||
void setMax (float val) override;
|
||||
|
||||
bool attached (CView* parent) override;
|
||||
void draw (CDrawContext* context) override;
|
||||
void drawRect (CDrawContext* context, const CRect& updateRect) 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 onMouseExited (CPoint& where, const CButtonState& buttons) override;
|
||||
void onKeyboardEvent (KeyboardEvent& event) override;
|
||||
void setViewSize (const CRect& rect, bool invalid = true) override;
|
||||
bool drawFocusOnTop () override;
|
||||
bool getFocusPath (CGraphicsPath& outPath) override;
|
||||
|
||||
CLASS_METHODS_NOCOPY (CListControl, CControl)
|
||||
private:
|
||||
int32_t getNextSelectableRow (int32_t r, int32_t direction) const;
|
||||
int32_t getMinRowIndex () const;
|
||||
int32_t getMaxRowIndex () const;
|
||||
size_t getNormalizedRowIndex (int32_t row) const;
|
||||
bool rowSelectable (int32_t row) const;
|
||||
void clearHoveredRow ();
|
||||
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> impl;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
/** The description of one row for the CListControl
|
||||
*
|
||||
* This is returned by an instance of IListControlConfigurator for every row.
|
||||
*
|
||||
* @ingroup new_in_4_9
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
struct CListControlRowDesc
|
||||
{
|
||||
enum Flag : uint32_t
|
||||
{
|
||||
/** Indicates that the row is selectable */
|
||||
Selectable = 1 << 0,
|
||||
/** Indicates that the row should be redrawn when the mouse hovers it */
|
||||
Hoverable = 1 << 1,
|
||||
};
|
||||
using Flags = EnumBitset<Flag, true>;
|
||||
|
||||
/** The height of the row */
|
||||
CCoord height {0};
|
||||
/** The flags of the row, see the Flags enum above */
|
||||
Flags flags {Selectable};
|
||||
|
||||
CListControlRowDesc () = default;
|
||||
CListControlRowDesc (CCoord h, Flags f) : height (h), flags (f) {}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
/** The list control drawer interface
|
||||
*
|
||||
* This is used to do the actual drawing of the list control.
|
||||
*
|
||||
* @ingroup new_in_4_9
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
class IListControlDrawer : virtual public IReference
|
||||
{
|
||||
public:
|
||||
virtual ~IListControlDrawer () noexcept {}
|
||||
|
||||
struct Row
|
||||
{
|
||||
enum Flag : uint32_t
|
||||
{
|
||||
Selectable = 1 << 0,
|
||||
Selected = 1 << 1,
|
||||
Hovered = 1 << 2,
|
||||
LastRow = 1 << 3,
|
||||
};
|
||||
using Flags = EnumBitset<Flag, true>;
|
||||
|
||||
operator int32_t () const { return getIndex (); }
|
||||
int32_t getIndex () const { return index; }
|
||||
|
||||
bool isSelectable () const { return (flags & Selectable) != 0; }
|
||||
bool isSelected () const { return (flags & Selected) != 0; }
|
||||
bool isHovered () const { return (flags & Hovered) != 0; }
|
||||
bool isLastRow () const { return (flags & LastRow) != 0; }
|
||||
|
||||
Row (int32_t index, Flags flags) : index (index), flags (flags) {}
|
||||
|
||||
private:
|
||||
int32_t index;
|
||||
Flags flags;
|
||||
};
|
||||
|
||||
virtual void drawBackground (CDrawContext* context, CRect size) = 0;
|
||||
virtual void drawRow (CDrawContext* context, CRect size, Row row) = 0;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
/** The list control configurator interface
|
||||
*
|
||||
* @ingroup new_in_4_9
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
class IListControlConfigurator : virtual public IReference
|
||||
{
|
||||
public:
|
||||
virtual ~IListControlConfigurator () noexcept {}
|
||||
|
||||
virtual CListControlRowDesc getRowDesc (int32_t row) const = 0;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
/** A list control configurator implementation.
|
||||
*
|
||||
* Returns the same row description for all row indices
|
||||
*
|
||||
* @ingroup new_in_4_9
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
class StaticListControlConfigurator : public IListControlConfigurator,
|
||||
public NonAtomicReferenceCounted
|
||||
{
|
||||
public:
|
||||
using Flags = CListControlRowDesc::Flags;
|
||||
|
||||
StaticListControlConfigurator (CCoord inRowHeight,
|
||||
Flags inFlags = {CListControlRowDesc::Selectable,
|
||||
CListControlRowDesc::Hoverable})
|
||||
: rowHeight (inRowHeight), flags (inFlags)
|
||||
{
|
||||
}
|
||||
|
||||
void setRowHeight (CCoord height) { rowHeight = height; }
|
||||
void setFlags (Flags f) { flags = f; }
|
||||
CCoord getRowHeight () const { return rowHeight; }
|
||||
Flags getFlags () const { return flags; }
|
||||
|
||||
CListControlRowDesc getRowDesc (int32_t row) const override { return {rowHeight, flags}; }
|
||||
|
||||
private:
|
||||
CCoord rowHeight;
|
||||
Flags flags;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,133 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#include "cmoviebitmap.h"
|
||||
#include "../cdrawcontext.h"
|
||||
#include "../cbitmap.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
//------------------------------------------------------------------------
|
||||
bool CMovieBitmap::useLegacyFrameCalculation = false;
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// CMovieBitmap
|
||||
//------------------------------------------------------------------------
|
||||
/**
|
||||
* CMovieBitmap constructor.
|
||||
* @param size the size of this view
|
||||
* @param listener the listener
|
||||
* @param tag the control tag
|
||||
* @param background bitmap
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
CMovieBitmap::CMovieBitmap (const CRect& size, IControlListener* listener, int32_t tag,
|
||||
CBitmap* background)
|
||||
: CControl (size, listener, tag, background)
|
||||
{
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
setHeightOfOneImage (size.getHeight ());
|
||||
setNumSubPixmaps (background ? (int32_t)(background->getHeight () / heightOfOneImage) : 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
//------------------------------------------------------------------------
|
||||
/**
|
||||
* CMovieBitmap constructor.
|
||||
* @param size the size of this view
|
||||
* @param listener the listener
|
||||
* @param tag the control tag
|
||||
* @param subPixmaps number of subPixmaps
|
||||
* @param heightOfOneImage height of one image in pixel
|
||||
* @param background bitmap
|
||||
* @param offset
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
CMovieBitmap::CMovieBitmap (const CRect& size, IControlListener* listener, int32_t tag, int32_t subPixmaps, CCoord heightOfOneImage, CBitmap* background, const CPoint &offset)
|
||||
: CControl (size, listener, tag, background)
|
||||
, offset (offset)
|
||||
{
|
||||
setNumSubPixmaps (subPixmaps);
|
||||
setHeightOfOneImage (heightOfOneImage);
|
||||
}
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMovieBitmap::CMovieBitmap (const CMovieBitmap& v) : CControl (v)
|
||||
{
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
offset = v.offset;
|
||||
setNumSubPixmaps (v.subPixmaps);
|
||||
setHeightOfOneImage (v.heightOfOneImage);
|
||||
#endif
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CMovieBitmap::draw (CDrawContext *pContext)
|
||||
{
|
||||
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
|
||||
#include "../private/disabledeprecatedmessage.h"
|
||||
CPoint where (offset.x, offset.y);
|
||||
if (useLegacyFrameCalculation)
|
||||
{
|
||||
where.y += heightOfOneImage *
|
||||
(int32_t)(getValueNormalized () * (getNumSubPixmaps () - 1) + 0.5);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto step = static_cast<int32_t> (std::min (
|
||||
getNumSubPixmaps () - 1.f, getValueNormalized () * getNumSubPixmaps ()));
|
||||
where.y += heightOfOneImage * step;
|
||||
}
|
||||
|
||||
bitmap->draw (pContext, getViewSize (), where);
|
||||
#include "../private/enabledeprecatedmessage.h"
|
||||
|
||||
#else
|
||||
bitmap->draw (pContext, getViewSize ());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
setDirty (false);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool CMovieBitmap::sizeToFit ()
|
||||
{
|
||||
if (auto bitmap = getDrawBackground ())
|
||||
{
|
||||
CRect vs (getViewSize ());
|
||||
if (auto mfb = dynamic_cast<CMultiFrameBitmap*> (bitmap))
|
||||
{
|
||||
vs.setSize (mfb->getFrameSize ());
|
||||
}
|
||||
else
|
||||
{
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
vs.setHeight (getHeightOfOneImage ());
|
||||
#else
|
||||
vs.setHeight (bitmap->getHeight ());
|
||||
#endif
|
||||
vs.setWidth (bitmap->getWidth ());
|
||||
}
|
||||
setViewSize (vs);
|
||||
setMouseableArea (vs);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,52 @@
|
||||
// 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"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CMovieBitmap Declaration
|
||||
//! @brief a bitmap view that displays different bitmaps according to its current value
|
||||
///
|
||||
/// Use a CMultiFrameBitmap for its background bitmap.
|
||||
///
|
||||
/// @ingroup views uses_multi_frame_bitmaps
|
||||
//-----------------------------------------------------------------------------
|
||||
class CMovieBitmap : public CControl,
|
||||
public MultiFrameBitmapView<CMovieBitmap>
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
,
|
||||
public IMultiBitmapControl
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
CMovieBitmap (const CRect& size, IControlListener* listener, int32_t tag, CBitmap* background);
|
||||
CMovieBitmap (const CMovieBitmap& movieBitmap);
|
||||
|
||||
void draw (CDrawContext*) override;
|
||||
bool sizeToFit () override;
|
||||
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
CMovieBitmap (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 (); }
|
||||
#endif
|
||||
|
||||
VSTGUI_DEPRECATED_MSG (static bool useLegacyFrameCalculation;
|
||||
, "Use CMultiFrameBitmap::normalizedValueToFrameIndex() instead")
|
||||
|
||||
CLASS_METHODS(CMovieBitmap, CControl)
|
||||
protected:
|
||||
~CMovieBitmap () noexcept override = default;
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
CPoint offset {};
|
||||
#endif
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,189 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#include "cmoviebutton.h"
|
||||
#include "../cdrawcontext.h"
|
||||
#include "../cbitmap.h"
|
||||
#include "../events.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// CMovieButton
|
||||
//------------------------------------------------------------------------
|
||||
/**
|
||||
* CMovieButton constructor.
|
||||
* @param size the size of this view
|
||||
* @param listener the listener
|
||||
* @param tag the control tag
|
||||
* @param background bitmap
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
CMovieButton::CMovieButton (const CRect& size, IControlListener* listener, int32_t tag,
|
||||
CBitmap* background)
|
||||
: CControl (size, listener, tag, background), buttonState (value)
|
||||
{
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
heightOfOneImage = size.getHeight ();
|
||||
#endif
|
||||
setWantsFocus (true);
|
||||
}
|
||||
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
//------------------------------------------------------------------------
|
||||
/**
|
||||
* CMovieButton constructor.
|
||||
* @param size the size of this view
|
||||
* @param listener the listener
|
||||
* @param tag the control tag
|
||||
* @param heightOfOneImage height of one image in pixel
|
||||
* @param background bitmap
|
||||
* @param offset
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
CMovieButton::CMovieButton (const CRect& size, IControlListener* listener, int32_t tag, CCoord heightOfOneImage, CBitmap* background, const CPoint &offset)
|
||||
: CControl (size, listener, tag, background)
|
||||
, offset (offset)
|
||||
, buttonState (value)
|
||||
{
|
||||
setHeightOfOneImage (heightOfOneImage);
|
||||
setWantsFocus (true);
|
||||
}
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMovieButton::CMovieButton (const CMovieButton& v) : CControl (v), buttonState (v.buttonState)
|
||||
{
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
offset = v.offset;
|
||||
setHeightOfOneImage (v.heightOfOneImage);
|
||||
#endif
|
||||
setWantsFocus (true);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CMovieButton::draw (CDrawContext *pContext)
|
||||
{
|
||||
if (auto bitmap = getDrawBackground ())
|
||||
{
|
||||
if (auto mfb = dynamic_cast<CMultiFrameBitmap*> (bitmap))
|
||||
{
|
||||
auto frameIndex = getMultiFrameBitmapIndex (*mfb, getValueNormalized ());
|
||||
mfb->drawFrame (pContext, frameIndex, getViewSize ().getTopLeft ());
|
||||
}
|
||||
else
|
||||
{
|
||||
CPoint where {};
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
if (value == getMax ())
|
||||
where.y = heightOfOneImage;
|
||||
#endif
|
||||
bitmap->draw (pContext, getViewSize (), where);
|
||||
}
|
||||
}
|
||||
buttonState = value;
|
||||
|
||||
setDirty (false);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMouseEventResult CMovieButton::onMouseDown (CPoint& where, const CButtonState& buttons)
|
||||
{
|
||||
if (!(buttons & kLButton))
|
||||
return kMouseEventNotHandled;
|
||||
fEntryState = value;
|
||||
beginEdit ();
|
||||
return onMouseMoved (where, buttons);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMouseEventResult CMovieButton::onMouseUp (CPoint& where, const CButtonState& buttons)
|
||||
{
|
||||
if (isEditing ())
|
||||
endEdit ();
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMouseEventResult CMovieButton::onMouseMoved (CPoint& where, const CButtonState& buttons)
|
||||
{
|
||||
if (isEditing ())
|
||||
{
|
||||
if (where.x >= getViewSize ().left &&
|
||||
where.y >= getViewSize ().top &&
|
||||
where.x <= getViewSize ().right &&
|
||||
where.y <= getViewSize ().bottom)
|
||||
value = (fEntryState == getMax ()) ? getMin () : getMax ();
|
||||
else
|
||||
value = fEntryState;
|
||||
|
||||
if (isDirty ())
|
||||
{
|
||||
valueChanged ();
|
||||
invalid ();
|
||||
}
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
return kMouseEventNotHandled;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMouseEventResult CMovieButton::onMouseCancel ()
|
||||
{
|
||||
if (isEditing ())
|
||||
{
|
||||
value = fEntryState;
|
||||
if (isDirty ())
|
||||
{
|
||||
valueChanged ();
|
||||
invalid ();
|
||||
}
|
||||
endEdit ();
|
||||
}
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CMovieButton::onKeyboardEvent (KeyboardEvent& event)
|
||||
{
|
||||
if (event.type != EventType::KeyDown || event.modifiers.empty () == false)
|
||||
return;
|
||||
if (event.virt == VirtualKey::Return)
|
||||
{
|
||||
value = (value == getMax ()) ? getMin () : getMax ();
|
||||
invalid ();
|
||||
beginEdit ();
|
||||
valueChanged ();
|
||||
endEdit ();
|
||||
event.consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool CMovieButton::sizeToFit ()
|
||||
{
|
||||
if (auto bitmap = getDrawBackground ())
|
||||
{
|
||||
CRect vs (getViewSize ());
|
||||
if (auto mfb = dynamic_cast<CMultiFrameBitmap*> (bitmap))
|
||||
{
|
||||
vs.setSize (mfb->getFrameSize ());
|
||||
}
|
||||
else
|
||||
{
|
||||
vs.setWidth (bitmap->getWidth ());
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
vs.setHeight (getHeightOfOneImage ());
|
||||
#else
|
||||
vs.setHeight (bitmap->getHeight ());
|
||||
#endif
|
||||
}
|
||||
setViewSize (vs);
|
||||
setMouseableArea (vs);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // VSTGUI
|
||||
@@ -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 "ccontrol.h"
|
||||
#include "../cbitmap.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CMovieButton Declaration
|
||||
//! @brief a bi-states button with 2 subbitmaps
|
||||
///
|
||||
/// Use a CMultiFrameBitmap for its background bitmap.
|
||||
///
|
||||
/// @ingroup controls uses_multi_frame_bitmaps
|
||||
//-----------------------------------------------------------------------------
|
||||
class CMovieButton : public CControl,
|
||||
public MultiFrameBitmapView<CMovieButton>
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
,
|
||||
public IMultiBitmapControl
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
CMovieButton (const CRect& size, IControlListener* listener, int32_t tag, CBitmap* background);
|
||||
CMovieButton (const CMovieButton& movieButton);
|
||||
|
||||
void draw (CDrawContext*) override;
|
||||
|
||||
CMouseEventResult onMouseDown (CPoint& where, const CButtonState& buttons) override;
|
||||
CMouseEventResult onMouseUp (CPoint& where, const CButtonState& buttons) override;
|
||||
CMouseEventResult onMouseMoved (CPoint& where, const CButtonState& buttons) override;
|
||||
CMouseEventResult onMouseCancel () override;
|
||||
void onKeyboardEvent (KeyboardEvent& event) override;
|
||||
bool sizeToFit () override;
|
||||
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
CMovieButton (const CRect& size, IControlListener* listener, int32_t tag,
|
||||
CCoord heightOfOneImage, CBitmap* background,
|
||||
const CPoint& offset = CPoint (0, 0));
|
||||
void setNumSubPixmaps (int32_t numSubPixmaps) override { IMultiBitmapControl::setNumSubPixmaps (numSubPixmaps); invalid (); }
|
||||
#endif
|
||||
|
||||
CLASS_METHODS(CMovieButton, CControl)
|
||||
protected:
|
||||
~CMovieButton () noexcept override = default;
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
CPoint offset {};
|
||||
#endif
|
||||
float buttonState;
|
||||
|
||||
private:
|
||||
float fEntryState;
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,918 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#include "coptionmenu.h"
|
||||
#include "../cbitmap.h"
|
||||
#include "../cframe.h"
|
||||
#include "../cstring.h"
|
||||
#include "../events.h"
|
||||
|
||||
#include "../platform/iplatformoptionmenu.h"
|
||||
#include "../platform/iplatformframe.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
struct CMenuItem::Impl
|
||||
{
|
||||
UTF8String title;
|
||||
UTF8String keyCode;
|
||||
SharedPointer<COptionMenu> submenu;
|
||||
SharedPointer<CBitmap> icon;
|
||||
int32_t flags {0};
|
||||
int32_t keyModifiers {0};
|
||||
VirtualKey virtualKey {VirtualKey::None};
|
||||
int32_t tag {-1};
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// CMenuItem
|
||||
//------------------------------------------------------------------------
|
||||
/*! @class CMenuItem
|
||||
Defines an item of a VSTGUI::COptionMenu
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMenuItem::CMenuItem ()
|
||||
{
|
||||
impl = std::make_unique<Impl> ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMenuItem::~CMenuItem () noexcept = default;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
/**
|
||||
* CMenuItem constructor.
|
||||
* @param inTitle title of item
|
||||
* @param inFlags CMenuItem::Flags of item
|
||||
* @param inKeycode keycode of item
|
||||
* @param inKeyModifiers keymodifiers of item
|
||||
* @param inIcon icon of item
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
CMenuItem::CMenuItem (const UTF8String& inTitle, const UTF8String& inKeycode, int32_t inKeyModifiers, CBitmap* inIcon, int32_t inFlags)
|
||||
: CMenuItem ()
|
||||
{
|
||||
impl->flags = inFlags;
|
||||
setTitle (inTitle);
|
||||
setKey (inKeycode, inKeyModifiers);
|
||||
setIcon (inIcon);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
/**
|
||||
* CMenuItem constructor.
|
||||
* @param inTitle title of item
|
||||
* @param inSubmenu submenu of item
|
||||
* @param inIcon icon of item
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
CMenuItem::CMenuItem (const UTF8String& inTitle, COptionMenu* inSubmenu, CBitmap* inIcon)
|
||||
: CMenuItem ()
|
||||
{
|
||||
setTitle (inTitle);
|
||||
setSubmenu (inSubmenu);
|
||||
setIcon (inIcon);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
/**
|
||||
* CMenuItem constructor.
|
||||
* @param inTitle title of item
|
||||
* @param inTag tag of item
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
CMenuItem::CMenuItem (const UTF8String& inTitle, int32_t inTag)
|
||||
: CMenuItem ()
|
||||
{
|
||||
setTitle (inTitle);
|
||||
setTag (inTag);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
/**
|
||||
* CMenuItem copy constructor.
|
||||
* @param item item to copy
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
CMenuItem::CMenuItem (const CMenuItem& item)
|
||||
: CMenuItem ()
|
||||
{
|
||||
impl->flags = item.impl->flags;
|
||||
setTitle (item.getTitle ());
|
||||
setIcon (item.getIcon ());
|
||||
if (item.getVirtualKey () != VirtualKey::None)
|
||||
setVirtualKey (item.getVirtualKey (), item.getKeyModifiers ());
|
||||
else
|
||||
setKey (item.getKeycode (), item.getKeyModifiers ());
|
||||
setTag (item.getTag ());
|
||||
setSubmenu (item.getSubmenu ());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CMenuItem::setTitle (const UTF8String& inTitle)
|
||||
{
|
||||
impl->title = inTitle;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CMenuItem::setKey (const UTF8String& inKeycode, int32_t inKeyModifiers)
|
||||
{
|
||||
impl->keyCode = inKeycode;
|
||||
impl->keyModifiers = inKeyModifiers;
|
||||
impl->virtualKey = VirtualKey::None;
|
||||
}
|
||||
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
//------------------------------------------------------------------------
|
||||
void CMenuItem::setVirtualKey (int32_t inVirtualKeyCode, int32_t inKeyModifiers)
|
||||
{
|
||||
setKey (nullptr, inKeyModifiers);
|
||||
impl->virtualKey = fromVstVirtualKey (inVirtualKeyCode);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
int32_t CMenuItem::getVirtualKeyCode () const
|
||||
{
|
||||
return toVstVirtualKey (impl->virtualKey);
|
||||
}
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CMenuItem::setVirtualKey (VirtualKey inVirtualKey, int32_t inKeyModifiers)
|
||||
{
|
||||
setKey (nullptr, inKeyModifiers);
|
||||
impl->virtualKey = inVirtualKey;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CMenuItem::setSubmenu (COptionMenu* inSubmenu)
|
||||
{
|
||||
impl->submenu = inSubmenu;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CMenuItem::setIcon (CBitmap* inIcon)
|
||||
{
|
||||
impl->icon = inIcon;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CMenuItem::setTag (int32_t t)
|
||||
{
|
||||
impl->tag = t;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CMenuItem::setEnabled (bool state)
|
||||
{
|
||||
setBit (impl->flags, kDisabled, !state);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CMenuItem::setChecked (bool state)
|
||||
{
|
||||
setBit (impl->flags, kChecked, state);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CMenuItem::setIsTitle (bool state)
|
||||
{
|
||||
setBit (impl->flags, kTitle, state);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CMenuItem::setIsSeparator (bool state)
|
||||
{
|
||||
setBit (impl->flags, kSeparator, state);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool CMenuItem::isEnabled () const
|
||||
{
|
||||
return !hasBit (impl->flags, kDisabled);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool CMenuItem::isChecked () const
|
||||
{
|
||||
return hasBit (impl->flags, kChecked);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool CMenuItem::isTitle () const
|
||||
{
|
||||
return hasBit (impl->flags, kTitle);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool CMenuItem::isSeparator () const
|
||||
{
|
||||
return hasBit (impl->flags, kSeparator);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
const UTF8String& CMenuItem::getTitle () const
|
||||
{
|
||||
return impl->title;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
int32_t CMenuItem::getKeyModifiers () const
|
||||
{
|
||||
return impl->keyModifiers;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
const UTF8String& CMenuItem::getKeycode () const
|
||||
{
|
||||
return impl->keyCode;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
VirtualKey CMenuItem::getVirtualKey () const
|
||||
{
|
||||
return impl->virtualKey;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
COptionMenu* CMenuItem::getSubmenu () const
|
||||
{
|
||||
return impl->submenu;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CBitmap* CMenuItem::getIcon () const
|
||||
{
|
||||
return impl->icon;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
int32_t CMenuItem::getTag () const
|
||||
{
|
||||
return impl->tag;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
/*! @class CCommandMenuItem
|
||||
|
||||
The CCommandMenuItem supports setting a category, name and a target. The target will get a @link CBaseObject::notify notify()@endlink call before the item is
|
||||
displayed and after it was selected. @see CCommandMenuItem::kMsgMenuItemValidate and @see CCommandMenuItem::kMsgMenuItemSelected
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
CCommandMenuItem::CCommandMenuItem (Desc&& args)
|
||||
: CMenuItem (args.title, args.keycode, args.keyModifiers, args.icon, args.flags)
|
||||
, commandCategory (std::move (args.commandCategory))
|
||||
, commandName (std::move (args.commandName))
|
||||
, itemTarget (std::move (args.target))
|
||||
{
|
||||
setTag (args.tag);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CCommandMenuItem::CCommandMenuItem (const Desc& args)
|
||||
: CMenuItem (args.title, args.keycode, args.keyModifiers, args.icon, args.flags)
|
||||
, commandCategory (args.commandCategory)
|
||||
, commandName (args.commandName)
|
||||
, itemTarget (args.target)
|
||||
{
|
||||
setTag (args.tag);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CCommandMenuItem::CCommandMenuItem (const CCommandMenuItem& item)
|
||||
: CMenuItem (item)
|
||||
, validateFunc (item.validateFunc)
|
||||
, selectedFunc (item.selectedFunc)
|
||||
, commandCategory (item.commandCategory)
|
||||
, commandName (item.commandName)
|
||||
{
|
||||
setItemTarget (item.itemTarget);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CCommandMenuItem::setItemTarget (ICommandMenuItemTarget* target)
|
||||
{
|
||||
itemTarget = target;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CCommandMenuItem::setCommandCategory (const UTF8String& category)
|
||||
{
|
||||
commandCategory = category;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool CCommandMenuItem::isCommandCategory (const UTF8String& category) const
|
||||
{
|
||||
return commandCategory == category;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CCommandMenuItem::setCommandName (const UTF8String& name)
|
||||
{
|
||||
commandName = name;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool CCommandMenuItem::isCommandName (const UTF8String& name) const
|
||||
{
|
||||
return commandName == name;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CCommandMenuItem::setActions (SelectedCallbackFunction&& selected, ValidateCallbackFunction&& validate)
|
||||
{
|
||||
selectedFunc = std::move (selected);
|
||||
validateFunc = std::move (validate);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CCommandMenuItem::execute ()
|
||||
{
|
||||
if (selectedFunc)
|
||||
selectedFunc (this);
|
||||
|
||||
if (itemTarget)
|
||||
itemTarget->onCommandMenuItemSelected (this);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CCommandMenuItem::validate ()
|
||||
{
|
||||
if (validateFunc)
|
||||
validateFunc (this);
|
||||
|
||||
if (itemTarget)
|
||||
itemTarget->validateCommandMenuItem (this);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// COptionMenu
|
||||
//------------------------------------------------------------------------
|
||||
/*! @class COptionMenu
|
||||
Define a rectangle view where a text-value can be displayed with a given font and color.
|
||||
The text-value is centered in the given rect.
|
||||
A bitmap can be used as background, a second bitmap can be used when the option menu is popuped.
|
||||
There are 2 styles with or without a shadowed text. When a mouse click occurs, a popup menu is displayed.
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
/**
|
||||
* COptionMenu constructor.
|
||||
* @param size the size of this view
|
||||
* @param listener the listener
|
||||
* @param tag the control tag
|
||||
* @param background the background bitmap
|
||||
* @param bgWhenClick the background bitmap if the option menu is displayed
|
||||
* @param style the style of the display (see CParamDisplay for styles)
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
COptionMenu::COptionMenu (const CRect& size, IControlListener* listener, int32_t tag, CBitmap* background, CBitmap* bgWhenClick, const int32_t style)
|
||||
: CParamDisplay (size, background, style)
|
||||
, bgWhenClick (bgWhenClick)
|
||||
{
|
||||
this->listener = listener;
|
||||
this->tag = tag;
|
||||
|
||||
lastButton = kRButton;
|
||||
|
||||
menuItems = new CMenuItemList;
|
||||
setWantsFocus (true);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
COptionMenu::COptionMenu ()
|
||||
: CParamDisplay (CRect (0, 0, 0, 0))
|
||||
{
|
||||
menuItems = new CMenuItemList;
|
||||
setWantsFocus (true);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
COptionMenu::COptionMenu (const COptionMenu& v)
|
||||
: CParamDisplay (v)
|
||||
, menuItems (new CMenuItemList (*v.menuItems))
|
||||
, nbItemsPerColumn (v.nbItemsPerColumn)
|
||||
, bgWhenClick (v.bgWhenClick)
|
||||
{
|
||||
setWantsFocus (true);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
COptionMenu::~COptionMenu () noexcept
|
||||
{
|
||||
removeAllEntry ();
|
||||
|
||||
delete menuItems;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void COptionMenu::registerOptionMenuListener (IOptionMenuListener* listener)
|
||||
{
|
||||
if (!listeners)
|
||||
listeners = std::unique_ptr<MenuListenerList> (new MenuListenerList ());
|
||||
listeners->add (listener);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void COptionMenu::unregisterOptionMenuListener (IOptionMenuListener* listener)
|
||||
{
|
||||
if (listeners)
|
||||
listeners->remove (listener);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void COptionMenu::onKeyboardEvent (KeyboardEvent& event)
|
||||
{
|
||||
if (event.type != EventType::KeyUp && event.modifiers.empty () && event.character == 0)
|
||||
{
|
||||
if (event.virt == VirtualKey::Return)
|
||||
{
|
||||
auto self = shared (this);
|
||||
getFrame ()->doAfterEventProcessing ([self] () {
|
||||
self->doPopup ();
|
||||
});
|
||||
event.consumed = true;
|
||||
return;
|
||||
}
|
||||
if (!(style & (kMultipleCheckStyle & ~kCheckStyle)))
|
||||
{
|
||||
if (event.virt == VirtualKey::Up)
|
||||
{
|
||||
int32_t value = (int32_t)getValue ()-1;
|
||||
if (value >= 0)
|
||||
{
|
||||
CMenuItem* entry = getEntry (value);
|
||||
while (entry && (entry->isSeparator () || entry->isTitle () || !entry->isEnabled () || entry->getSubmenu ()))
|
||||
entry = getEntry (--value);
|
||||
if (entry)
|
||||
{
|
||||
beginEdit ();
|
||||
setValue ((float)value);
|
||||
lastResult = (int32_t)getValue ();
|
||||
valueChanged ();
|
||||
endEdit ();
|
||||
invalid ();
|
||||
}
|
||||
}
|
||||
event.consumed = true;
|
||||
return;
|
||||
}
|
||||
if (event.virt == VirtualKey::Down)
|
||||
{
|
||||
int32_t value = (int32_t)getValue ()+1;
|
||||
if (value < getNbEntries ())
|
||||
{
|
||||
CMenuItem* entry = getEntry (value);
|
||||
while (entry && (entry->isSeparator () || entry->isTitle () || !entry->isEnabled () || entry->getSubmenu ()))
|
||||
entry = getEntry (++value);
|
||||
if (entry)
|
||||
{
|
||||
beginEdit ();
|
||||
setValue ((float)value);
|
||||
lastResult = (int32_t)getValue ();
|
||||
valueChanged ();
|
||||
endEdit ();
|
||||
invalid ();
|
||||
}
|
||||
}
|
||||
event.consumed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
CParamDisplay::onKeyboardEvent (event);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void COptionMenu::beforePopup ()
|
||||
{
|
||||
if (listeners)
|
||||
listeners->forEach ([this] (IOptionMenuListener* l) { l->onOptionMenuPrePopup (this); });
|
||||
for (auto& menuItem : *menuItems)
|
||||
{
|
||||
if (auto* commandItem = menuItem.cast<CCommandMenuItem> ())
|
||||
commandItem->validate ();
|
||||
if (menuItem->getSubmenu ())
|
||||
menuItem->getSubmenu ()->beforePopup ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void COptionMenu::afterPopup ()
|
||||
{
|
||||
for (auto& menuItem : *menuItems)
|
||||
{
|
||||
if (menuItem->getSubmenu ())
|
||||
menuItem->getSubmenu ()->afterPopup ();
|
||||
}
|
||||
if (listeners)
|
||||
listeners->forEach ([this] (IOptionMenuListener* l) { l->onOptionMenuPostPopup (this); });
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool COptionMenu::doPopup ()
|
||||
{
|
||||
if (bgWhenClick)
|
||||
invalid ();
|
||||
auto result = popup ();
|
||||
if (bgWhenClick)
|
||||
invalid ();
|
||||
return result;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool COptionMenu::popup (const PopupCallback& callback)
|
||||
{
|
||||
if (!getFrame ())
|
||||
return false;
|
||||
|
||||
beforePopup ();
|
||||
|
||||
lastResult = -1;
|
||||
lastMenu = nullptr;
|
||||
|
||||
if (!menuItems->empty ())
|
||||
{
|
||||
getFrame ()->onStartLocalEventLoop ();
|
||||
if (auto platformMenu = getFrame ()->getPlatformFrame ()->createPlatformOptionMenu ())
|
||||
{
|
||||
inPopup = true;
|
||||
auto self = shared (this);
|
||||
platformMenu->popup (this, [self, callback] (COptionMenu* menu, PlatformOptionMenuResult result) {
|
||||
if (result.menu != nullptr)
|
||||
{
|
||||
bool preventSettingValue = false;
|
||||
if (self->listeners)
|
||||
{
|
||||
self->listeners->forEach (
|
||||
[self, &result] (IOptionMenuListener* l) {
|
||||
return l->onOptionMenuSetPopupResult (self, result.menu,
|
||||
result.index);
|
||||
},
|
||||
[&preventSettingValue] (bool result) {
|
||||
if (result)
|
||||
preventSettingValue = true;
|
||||
return result;
|
||||
});
|
||||
}
|
||||
if (!preventSettingValue)
|
||||
{
|
||||
self->beginEdit ();
|
||||
self->lastMenu = result.menu;
|
||||
self->lastResult = result.index;
|
||||
self->lastMenu->setValue (static_cast<float> (self->lastResult));
|
||||
self->valueChanged ();
|
||||
self->invalid ();
|
||||
if (auto commandItem = dynamic_cast<CCommandMenuItem*> (
|
||||
self->lastMenu->getEntry (self->lastResult)))
|
||||
commandItem->execute ();
|
||||
self->endEdit ();
|
||||
}
|
||||
}
|
||||
self->afterPopup ();
|
||||
if (callback)
|
||||
callback (self);
|
||||
self->inPopup = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool COptionMenu::popup (CFrame* frame, const CPoint& frameLocation, const PopupCallback& callback)
|
||||
{
|
||||
if (frame == nullptr || menuItems->empty ())
|
||||
return false;
|
||||
if (isAttached ())
|
||||
return false;
|
||||
CView* oldFocusView = frame->getFocusView ();
|
||||
CRect size (frameLocation, CPoint (0, 0));
|
||||
setViewSize (size);
|
||||
frame->addView (this);
|
||||
|
||||
auto prevFocusView = shared (oldFocusView);
|
||||
popup ([prevFocusView, callback] (COptionMenu* menu) {
|
||||
if (auto frame = menu->getFrame ())
|
||||
{
|
||||
frame->removeView (menu, false);
|
||||
frame->setFocusView (prevFocusView);
|
||||
}
|
||||
else
|
||||
{
|
||||
// if the selected menu item is a command menu and the command menu has removed this
|
||||
// option menu from the view hierarchy then we have to make sure the reference count is
|
||||
// corrected
|
||||
menu->remember ();
|
||||
}
|
||||
if (callback)
|
||||
callback (menu);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void COptionMenu::cleanupSeparators (bool deep)
|
||||
{
|
||||
if (getItems ()->empty ())
|
||||
return;
|
||||
|
||||
std::list<int32_t>indicesToRemove;
|
||||
bool lastEntryWasSeparator = true;
|
||||
for (auto i = 0; i < getNbEntries () - 1; ++i)
|
||||
{
|
||||
auto entry = getEntry (i);
|
||||
vstgui_assert (entry);
|
||||
if (!entry)
|
||||
continue;
|
||||
|
||||
if (entry->isSeparator ())
|
||||
{
|
||||
if (lastEntryWasSeparator)
|
||||
{
|
||||
indicesToRemove.push_front (i);
|
||||
}
|
||||
lastEntryWasSeparator = true;
|
||||
}
|
||||
else
|
||||
lastEntryWasSeparator = false;
|
||||
if (deep)
|
||||
{
|
||||
if (auto subMenu = entry->getSubmenu ())
|
||||
{
|
||||
subMenu->cleanupSeparators (deep);
|
||||
}
|
||||
}
|
||||
}
|
||||
auto lastIndex = getNbEntries () - 1;
|
||||
if (getEntry (lastIndex)->isSeparator ())
|
||||
{
|
||||
indicesToRemove.push_front (lastIndex);
|
||||
}
|
||||
|
||||
for (auto index : indicesToRemove)
|
||||
{
|
||||
removeEntry (index);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void COptionMenu::setPrefixNumbers (int32_t preCount)
|
||||
{
|
||||
if (preCount >= 0 && preCount <= 4)
|
||||
prefixNumbers = preCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param item menu item to add. Takes ownership of item.
|
||||
* @param index position of insertation. -1 appends the item
|
||||
*/
|
||||
//-----------------------------------------------------------------------------
|
||||
CMenuItem* COptionMenu::addEntry (CMenuItem* item, int32_t index)
|
||||
{
|
||||
if (index < 0 || index > getNbEntries ())
|
||||
menuItems->emplace_back (owned (item));
|
||||
else
|
||||
{
|
||||
menuItems->insert (menuItems->begin () + index, owned (item));
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CMenuItem* COptionMenu::addEntry (COptionMenu* submenu, const UTF8String& title)
|
||||
{
|
||||
auto* item = new CMenuItem (title, submenu);
|
||||
return addEntry (item);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CMenuItem* COptionMenu::addEntry (const UTF8String& title, int32_t index, int32_t itemFlags)
|
||||
{
|
||||
if (title == "-")
|
||||
return addSeparator (index);
|
||||
auto* item = new CMenuItem (title, nullptr, 0, nullptr, itemFlags);
|
||||
return addEntry (item, index);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CMenuItem* COptionMenu::addSeparator (int32_t index)
|
||||
{
|
||||
auto* item = new CMenuItem ("", nullptr, 0, nullptr, CMenuItem::kSeparator);
|
||||
return addEntry (item, index);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CMenuItem* COptionMenu::getCurrent () const
|
||||
{
|
||||
return getEntry (currentIndex);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CMenuItem* COptionMenu::getEntry (int32_t index) const
|
||||
{
|
||||
if (index < 0 || menuItems->empty () || index >= getNbEntries ())
|
||||
return nullptr;
|
||||
|
||||
return (*menuItems)[static_cast<size_t> (index)];
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
int32_t COptionMenu::getNbEntries () const
|
||||
{
|
||||
return static_cast<int32_t> (menuItems->size ());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
COptionMenu* COptionMenu::getSubMenu (int32_t idx) const
|
||||
{
|
||||
CMenuItem* item = getEntry (idx);
|
||||
if (item)
|
||||
return item->getSubmenu ();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
int32_t COptionMenu::getCurrentIndex (bool countSeparator) const
|
||||
{
|
||||
if (countSeparator)
|
||||
return currentIndex;
|
||||
int32_t i = 0;
|
||||
int32_t numSeparators = 0;
|
||||
for (auto& item : *menuItems)
|
||||
{
|
||||
if (item->isSeparator ())
|
||||
numSeparators++;
|
||||
if (i == currentIndex)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
return currentIndex - numSeparators;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool COptionMenu::setCurrent (int32_t index, bool countSeparator)
|
||||
{
|
||||
CMenuItem* item = nullptr;
|
||||
if (countSeparator)
|
||||
{
|
||||
item = getEntry (index);
|
||||
if (!item || item->isSeparator ())
|
||||
return false;
|
||||
currentIndex = index;
|
||||
}
|
||||
else
|
||||
{
|
||||
int32_t i = 0;
|
||||
for (auto& menuItem : *menuItems)
|
||||
{
|
||||
if (i > index)
|
||||
break;
|
||||
if (menuItem->isSeparator ())
|
||||
index++;
|
||||
i++;
|
||||
}
|
||||
currentIndex = index;
|
||||
item = getEntry (currentIndex);
|
||||
}
|
||||
if (item && style & (kMultipleCheckStyle & ~kCheckStyle))
|
||||
item->setChecked (!item->isChecked ());
|
||||
|
||||
// to force the redraw
|
||||
setDirty ();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool COptionMenu::removeEntry (int32_t index)
|
||||
{
|
||||
if (index < 0 || menuItems->empty () || index >= getNbEntries ())
|
||||
return false;
|
||||
menuItems->erase (menuItems->begin () + index);
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool COptionMenu::removeAllEntry ()
|
||||
{
|
||||
menuItems->clear ();
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool COptionMenu::checkEntry (int32_t index, bool state)
|
||||
{
|
||||
CMenuItem* item = getEntry (index);
|
||||
if (item)
|
||||
{
|
||||
item->setChecked (state);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool COptionMenu::checkEntryAlone (int32_t index)
|
||||
{
|
||||
int32_t pos = 0;
|
||||
for (auto& item : *menuItems)
|
||||
{
|
||||
item->setChecked (pos == index);
|
||||
pos++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool COptionMenu::isCheckEntry (int32_t index) const
|
||||
{
|
||||
CMenuItem* item = getEntry (index);
|
||||
if (item && item->isChecked ())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void COptionMenu::draw (CDrawContext *pContext)
|
||||
{
|
||||
CMenuItem* item = getEntry (currentIndex);
|
||||
drawBack (pContext, inPopup ? bgWhenClick : nullptr);
|
||||
if (item)
|
||||
drawPlatformText (pContext, item->getTitle ());
|
||||
setDirty (false);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMouseEventResult COptionMenu::onMouseDown (CPoint& where, const CButtonState& buttons)
|
||||
{
|
||||
lastButton = buttons;
|
||||
if (lastButton & (kLButton|kRButton|kApple))
|
||||
{
|
||||
auto self = shared (this);
|
||||
getFrame ()->doAfterEventProcessing ([self] () {
|
||||
self->doPopup ();
|
||||
});
|
||||
return kMouseDownEventHandledButDontNeedMovedOrUpEvents;
|
||||
}
|
||||
return kMouseEventNotHandled;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
COptionMenu *COptionMenu::getLastItemMenu (int32_t &idxInMenu) const
|
||||
{
|
||||
idxInMenu = lastMenu ? (int32_t)lastMenu->getValue (): -1;
|
||||
return lastMenu;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void COptionMenu::setValue (float val)
|
||||
{
|
||||
auto newIndex = static_cast<int32_t> (std::round (val));
|
||||
if (newIndex < 0 || newIndex >= getNbEntries ())
|
||||
return;
|
||||
|
||||
currentIndex = newIndex;
|
||||
if (style & (kMultipleCheckStyle & ~kCheckStyle))
|
||||
{
|
||||
CMenuItem* item = getCurrent ();
|
||||
if (item)
|
||||
item->setChecked (!item->isChecked ());
|
||||
}
|
||||
CParamDisplay::setValue (static_cast<float> (newIndex));
|
||||
|
||||
// to force the redraw
|
||||
setDirty ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
float COptionMenu::getMax () const
|
||||
{
|
||||
if (menuItems->empty ())
|
||||
return 0.f;
|
||||
return static_cast<float> (menuItems->size () - 1);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void COptionMenu::takeFocus ()
|
||||
{
|
||||
CParamDisplay::takeFocus ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void COptionMenu::looseFocus ()
|
||||
{
|
||||
CView* receiver = getParentView () ? getParentView () : getFrame ();
|
||||
while (receiver)
|
||||
{
|
||||
if (receiver->notify (this, kMsgLooseFocus) == kMessageNotified)
|
||||
break;
|
||||
receiver = receiver->getParentView ();
|
||||
}
|
||||
CParamDisplay::looseFocus ();
|
||||
}
|
||||
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,339 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cparamdisplay.h"
|
||||
#include "icommandmenuitemtarget.h"
|
||||
#include "ioptionmenulistener.h"
|
||||
#include "../cstring.h"
|
||||
#include "../dispatchlist.h"
|
||||
#include "../cbitmap.h"
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CMenuItem Declaration
|
||||
//! @brief a menu item
|
||||
//-----------------------------------------------------------------------------
|
||||
class CMenuItem : public CBaseObject
|
||||
{
|
||||
public:
|
||||
enum Flags {
|
||||
kNoFlags = 0,
|
||||
/** item is gray and not selectable */
|
||||
kDisabled = 1 << 0,
|
||||
/** item indicates a title and is not selectable */
|
||||
kTitle = 1 << 1,
|
||||
/** item has a checkmark */
|
||||
kChecked = 1 << 2,
|
||||
/** item is a separator */
|
||||
kSeparator = 1 << 3
|
||||
};
|
||||
|
||||
CMenuItem (const UTF8String& title, const UTF8String& keycode = "", int32_t keyModifiers = 0, CBitmap* icon = nullptr, int32_t flags = kNoFlags);
|
||||
CMenuItem (const UTF8String& title, COptionMenu* submenu, CBitmap* icon = nullptr);
|
||||
CMenuItem (const UTF8String& title, int32_t tag);
|
||||
CMenuItem (const CMenuItem& item);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @name CMenuItem Methods
|
||||
//-----------------------------------------------------------------------------
|
||||
//@{
|
||||
/** set title of menu item */
|
||||
virtual void setTitle (const UTF8String& title);
|
||||
/** set submenu of menu item */
|
||||
virtual void setSubmenu (COptionMenu* submenu);
|
||||
/** set keycode and key modifiers of menu item */
|
||||
virtual void setKey (const UTF8String& keyCode, int32_t keyModifiers = 0);
|
||||
/** set virtual key and key modifiers of menu item */
|
||||
virtual void setVirtualKey (VirtualKey virtualKey, int32_t keyModifiers = 0);
|
||||
/** set menu item enabled state */
|
||||
virtual void setEnabled (bool state = true);
|
||||
/** set menu item checked state */
|
||||
virtual void setChecked (bool state = true);
|
||||
/** set menu item title state */
|
||||
virtual void setIsTitle (bool state = true);
|
||||
/** set menu item separator state */
|
||||
virtual void setIsSeparator (bool state = true);
|
||||
/** set menu item icon */
|
||||
virtual void setIcon (CBitmap* icon);
|
||||
/** set menu item tag */
|
||||
virtual void setTag (int32_t tag);
|
||||
|
||||
/** returns whether the item is enabled or not */
|
||||
bool isEnabled () const;
|
||||
/** returns whether the item is checked or not */
|
||||
bool isChecked () const;
|
||||
/** returns whether the item is a title item or not */
|
||||
bool isTitle () const;
|
||||
/** returns whether the item is a separator or not */
|
||||
bool isSeparator () const;
|
||||
|
||||
/** returns the title of the item */
|
||||
const UTF8String& getTitle () const;
|
||||
/** returns the key modifiers of the item */
|
||||
int32_t getKeyModifiers () const;
|
||||
/** returns the keycode of the item */
|
||||
const UTF8String& getKeycode () const;
|
||||
/** returns the virtual key of the item */
|
||||
VirtualKey getVirtualKey () const;
|
||||
/** returns the submenu of the item */
|
||||
COptionMenu* getSubmenu () const;
|
||||
/** returns the icon of the item */
|
||||
CBitmap* getIcon () const;
|
||||
/** returns the tag of the item */
|
||||
int32_t getTag () const;
|
||||
//@}
|
||||
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
int32_t getVirtualKeyCode () const;
|
||||
virtual void setVirtualKey (int32_t virtualKeyCode, int32_t keyModifiers = 0);
|
||||
#endif
|
||||
//------------------------------------------------------------------------
|
||||
protected:
|
||||
CMenuItem ();
|
||||
~CMenuItem () noexcept override;
|
||||
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> impl;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CCommandMenuItem Declaration
|
||||
/// @brief a command menu item
|
||||
/// @ingroup new_in_4_1
|
||||
//-----------------------------------------------------------------------------
|
||||
class CCommandMenuItem : public CMenuItem
|
||||
{
|
||||
public:
|
||||
struct Desc
|
||||
{
|
||||
UTF8String title;
|
||||
UTF8String commandCategory;
|
||||
UTF8String commandName;
|
||||
UTF8String keycode;
|
||||
SharedPointer<ICommandMenuItemTarget> target;
|
||||
SharedPointer<CBitmap> icon;
|
||||
int32_t keyModifiers {0};
|
||||
int32_t flags {kNoFlags};
|
||||
int32_t tag {-1};
|
||||
|
||||
Desc () = default;
|
||||
~Desc () noexcept = default;
|
||||
|
||||
Desc (const UTF8String& title, const UTF8String& keycode = nullptr,
|
||||
int32_t keyModifiers = 0, CBitmap* icon = nullptr,
|
||||
int32_t flags = kNoFlags, ICommandMenuItemTarget* target = nullptr,
|
||||
const UTF8String& commandCategory = nullptr,
|
||||
const UTF8String& commandName = nullptr)
|
||||
: title (title)
|
||||
, commandCategory (commandCategory)
|
||||
, commandName (commandName)
|
||||
, keycode (keycode)
|
||||
, target (target)
|
||||
, icon (icon)
|
||||
, keyModifiers (keyModifiers)
|
||||
, flags (flags)
|
||||
{
|
||||
}
|
||||
|
||||
Desc (const UTF8String& title, int32_t tag, ICommandMenuItemTarget* target = nullptr,
|
||||
const UTF8String& commandCategory = nullptr, const UTF8String& commandName = nullptr)
|
||||
: title (title)
|
||||
, commandCategory (commandCategory)
|
||||
, commandName (commandName)
|
||||
, target (target)
|
||||
, tag (tag)
|
||||
{
|
||||
}
|
||||
|
||||
Desc (const UTF8String& title, ICommandMenuItemTarget* target,
|
||||
const UTF8String& commandCategory = nullptr,
|
||||
const UTF8String& commandName = nullptr)
|
||||
: title (title)
|
||||
, commandCategory (commandCategory)
|
||||
, commandName (commandName)
|
||||
, target (target)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
CCommandMenuItem (Desc&& args);
|
||||
CCommandMenuItem (const Desc& args);
|
||||
CCommandMenuItem (const CCommandMenuItem& item);
|
||||
~CCommandMenuItem () noexcept override = default;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @name CCommandMenuItem Methods
|
||||
//-----------------------------------------------------------------------------
|
||||
//@{
|
||||
void setCommandCategory (const UTF8String& category);
|
||||
const UTF8String& getCommandCategory () const { return commandCategory; }
|
||||
bool isCommandCategory (const UTF8String& category) const;
|
||||
|
||||
void setCommandName (const UTF8String& name);
|
||||
const UTF8String& getCommandName () const { return commandName; }
|
||||
bool isCommandName (const UTF8String& name) const;
|
||||
|
||||
void setItemTarget (ICommandMenuItemTarget* target);
|
||||
ICommandMenuItemTarget* getItemTarget () const { return itemTarget; }
|
||||
|
||||
using ValidateCallbackFunction = std::function<void(CCommandMenuItem* item)>;
|
||||
using SelectedCallbackFunction = std::function<void(CCommandMenuItem* item)>;
|
||||
|
||||
void setActions (SelectedCallbackFunction&& selected, ValidateCallbackFunction&& validate = [](CCommandMenuItem*){});
|
||||
//@}
|
||||
|
||||
void execute ();
|
||||
void validate ();
|
||||
|
||||
protected:
|
||||
ValidateCallbackFunction validateFunc;
|
||||
SelectedCallbackFunction selectedFunc;
|
||||
UTF8String commandCategory;
|
||||
UTF8String commandName;
|
||||
SharedPointer<ICommandMenuItemTarget> itemTarget;
|
||||
};
|
||||
|
||||
using CMenuItemList = std::vector<SharedPointer<CMenuItem>>;
|
||||
using CMenuItemIterator = CMenuItemList::iterator;
|
||||
using CConstMenuItemIterator = CMenuItemList::const_iterator;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// COptionMenu Declaration
|
||||
//! @brief a popup menu control
|
||||
/// @ingroup controls
|
||||
//-----------------------------------------------------------------------------
|
||||
class COptionMenu : public CParamDisplay
|
||||
{
|
||||
private:
|
||||
enum StyleEnum
|
||||
{
|
||||
StylePopup = CParamDisplay::LastStyle,
|
||||
StyleCheck,
|
||||
StyleMultipleCheck,
|
||||
};
|
||||
public:
|
||||
COptionMenu ();
|
||||
COptionMenu (const CRect& size, IControlListener* listener, int32_t tag, CBitmap* background = nullptr, CBitmap* bgWhenClick = nullptr, const int32_t style = 0);
|
||||
COptionMenu (const COptionMenu& menu);
|
||||
~COptionMenu () noexcept override;
|
||||
|
||||
enum Style
|
||||
{
|
||||
kPopupStyle = 1 << StylePopup,
|
||||
kCheckStyle = 1 << StyleCheck,
|
||||
kMultipleCheckStyle = 1 << StyleMultipleCheck
|
||||
};
|
||||
|
||||
bool isPopupStyle () const { return hasBit (getStyle (), kPopupStyle); }
|
||||
bool isCheckStyle () const { return hasBit (getStyle (), kCheckStyle); }
|
||||
bool isMultipleCheckStyle () const { return hasBit (getStyle (), kMultipleCheckStyle); }
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @name COptionMenu Methods
|
||||
//-----------------------------------------------------------------------------
|
||||
//@{
|
||||
/** add a new entry */
|
||||
virtual CMenuItem* addEntry (CMenuItem* item, int32_t index = -1);
|
||||
/** add a new submenu entry */
|
||||
virtual CMenuItem* addEntry (COptionMenu* submenu, const UTF8String& title);
|
||||
/** add a new entry */
|
||||
virtual CMenuItem* addEntry (const UTF8String& title, int32_t index = -1, int32_t itemFlags = CMenuItem::kNoFlags);
|
||||
/** add a new separator entry */
|
||||
virtual CMenuItem* addSeparator (int32_t index = -1);
|
||||
/** get current entry */
|
||||
virtual CMenuItem* getCurrent () const;
|
||||
/** TODO: Doc */
|
||||
virtual int32_t getCurrentIndex (bool countSeparator = false) const;
|
||||
/** get entry at index position */
|
||||
virtual CMenuItem* getEntry (int32_t index) const;
|
||||
/** get number of entries */
|
||||
virtual int32_t getNbEntries () const;
|
||||
/** set current entry */
|
||||
virtual bool setCurrent (int32_t index, bool countSeparator = true);
|
||||
/** remove an entry */
|
||||
virtual bool removeEntry (int32_t index);
|
||||
/** remove all entries */
|
||||
virtual bool removeAllEntry ();
|
||||
|
||||
/** change check state of entry at index */
|
||||
virtual bool checkEntry (int32_t index, bool state);
|
||||
/** check entry at index and uncheck every other item */
|
||||
virtual bool checkEntryAlone (int32_t index);
|
||||
/** get check state of entry at index */
|
||||
virtual bool isCheckEntry (int32_t index) const;
|
||||
/** Windows only */
|
||||
virtual void setNbItemsPerColumn (int32_t val) { nbItemsPerColumn = val; }
|
||||
/** Windows only */
|
||||
virtual int32_t getNbItemsPerColumn () const { return nbItemsPerColumn; }
|
||||
|
||||
/** get last index of choosen entry */
|
||||
int32_t getLastResult () const { return lastResult; }
|
||||
/** get last menu and index of choosen entry */
|
||||
COptionMenu* getLastItemMenu (int32_t& idxInMenu) const;
|
||||
|
||||
/** set prefix numbering */
|
||||
virtual void setPrefixNumbers (int32_t preCount);
|
||||
/** get prefix numbering */
|
||||
int32_t getPrefixNumbers () const { return prefixNumbers; }
|
||||
|
||||
/** get a submenu */
|
||||
COptionMenu* getSubMenu (int32_t idx) const;
|
||||
|
||||
/** popup callback function */
|
||||
using PopupCallback = std::function<void (COptionMenu* menu)>;
|
||||
|
||||
/** pops up the menu */
|
||||
bool popup (const PopupCallback& callback = {});
|
||||
/** pops up the menu at frameLocation */
|
||||
bool popup (CFrame* frame, const CPoint& frameLocation, const PopupCallback& callback = {});
|
||||
|
||||
CMenuItemList* getItems () const { return menuItems; }
|
||||
|
||||
/** remove separators as first and last item and double separators */
|
||||
void cleanupSeparators (bool deep);
|
||||
|
||||
void registerOptionMenuListener (IOptionMenuListener* listener);
|
||||
void unregisterOptionMenuListener (IOptionMenuListener* listener);
|
||||
//@}
|
||||
|
||||
// overrides
|
||||
void setValue (float val) override;
|
||||
void setMin (float val) override {}
|
||||
float getMin () const override { return 0; }
|
||||
void setMax (float val) override {}
|
||||
float getMax () const override;
|
||||
|
||||
void draw (CDrawContext* pContext) override;
|
||||
CMouseEventResult onMouseDown (CPoint& where, const CButtonState& buttons) override;
|
||||
void onKeyboardEvent (KeyboardEvent& event) override;
|
||||
|
||||
void takeFocus () override;
|
||||
void looseFocus () override;
|
||||
|
||||
CLASS_METHODS(COptionMenu, CParamDisplay)
|
||||
protected:
|
||||
bool doPopup ();
|
||||
void beforePopup ();
|
||||
void afterPopup ();
|
||||
|
||||
CMenuItemList* menuItems;
|
||||
|
||||
bool inPopup {false};
|
||||
int32_t currentIndex {-1};
|
||||
CButtonState lastButton {0};
|
||||
int32_t nbItemsPerColumn {-1};
|
||||
int32_t lastResult {-1};
|
||||
int32_t prefixNumbers {0};
|
||||
SharedPointer<CBitmap> bgWhenClick;
|
||||
COptionMenu* lastMenu {nullptr};
|
||||
using MenuListenerList = DispatchList<IOptionMenuListener*>;
|
||||
std::unique_ptr<MenuListenerList> listeners;
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,504 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#include "cparamdisplay.h"
|
||||
#include "../cbitmap.h"
|
||||
#include "../cframe.h"
|
||||
#include "../cstring.h"
|
||||
#include "../cgraphicspath.h"
|
||||
#include "../cdrawcontext.h"
|
||||
#include <string>
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// CParamDisplay
|
||||
//------------------------------------------------------------------------
|
||||
/*! @class CParamDisplay
|
||||
Define a rectangle view where a text-value can be displayed with a given font and color.
|
||||
The user can specify its convert function (from float to char) by default the string format is "%2.2f".
|
||||
The text-value is centered in the given rect.
|
||||
*/
|
||||
CParamDisplay::CParamDisplay (const CRect& size, CBitmap* background, int32_t inStyle)
|
||||
: CControl (size, nullptr, -1, background)
|
||||
, horiTxtAlign (kCenterText)
|
||||
, style (inStyle)
|
||||
, valuePrecision (2)
|
||||
, roundRectRadius (6.)
|
||||
, frameWidth (1.)
|
||||
, textRotation (0.)
|
||||
{
|
||||
setBit (style, kAntialias, true);
|
||||
backOffset (0, 0);
|
||||
|
||||
fontID = kNormalFont; fontID->remember ();
|
||||
fontColor = kWhiteCColor;
|
||||
backColor = kBlackCColor;
|
||||
frameColor = kBlackCColor;
|
||||
shadowColor = kRedCColor;
|
||||
if (hasBit (style, kNoDrawStyle))
|
||||
setDirty (false);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CParamDisplay::CParamDisplay (const CParamDisplay& v)
|
||||
: CControl (v)
|
||||
, valueToStringFunction (v.valueToStringFunction)
|
||||
, horiTxtAlign (v.horiTxtAlign)
|
||||
, style (v.style)
|
||||
, valuePrecision (v.valuePrecision)
|
||||
, fontID (v.fontID)
|
||||
, fontColor (v.fontColor)
|
||||
, backColor (v.backColor)
|
||||
, frameColor (v.frameColor)
|
||||
, shadowColor (v.shadowColor)
|
||||
, textInset (v.textInset)
|
||||
, backOffset (v.backOffset)
|
||||
, roundRectRadius (v.roundRectRadius)
|
||||
, frameWidth (v.frameWidth)
|
||||
, textRotation (v.textRotation)
|
||||
{
|
||||
fontID->remember ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CParamDisplay::~CParamDisplay () noexcept
|
||||
{
|
||||
if (fontID)
|
||||
fontID->forget ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool CParamDisplay::removed (CView* parent)
|
||||
{
|
||||
return CControl::removed (parent);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CParamDisplay::setStyle (int32_t val)
|
||||
{
|
||||
setBit (val, kAntialias, hasBit (style, kAntialias));
|
||||
if (style != val)
|
||||
{
|
||||
style = val;
|
||||
drawStyleChanged ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
int32_t CParamDisplay::getStyle () const
|
||||
{
|
||||
auto tmp = style;
|
||||
setBit (tmp, kAntialias, false);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CParamDisplay::setPrecision (uint8_t precision)
|
||||
{
|
||||
if (valuePrecision != precision)
|
||||
{
|
||||
valuePrecision = precision;
|
||||
drawStyleChanged ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CParamDisplay::setValueToStringFunction2 (const ValueToStringFunction2& valueToStringFunc)
|
||||
{
|
||||
valueToStringFunction = valueToStringFunc;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CParamDisplay::setValueToStringFunction2 (ValueToStringFunction2&& valueToStringFunc)
|
||||
{
|
||||
valueToStringFunction = std::move (valueToStringFunc);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CParamDisplay::setValueToStringFunction (const ValueToStringFunction& func)
|
||||
{
|
||||
if (!func)
|
||||
{
|
||||
setValueToStringFunction2 (nullptr);
|
||||
return;
|
||||
}
|
||||
setValueToStringFunction2 ([=] (float value, std::string& str, CParamDisplay* display) {
|
||||
char string[256];
|
||||
string[0] = 0;
|
||||
if (func (value, string, display))
|
||||
{
|
||||
str = string;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CParamDisplay::setValueToStringFunction (ValueToStringFunction&& func)
|
||||
{
|
||||
setValueToStringFunction (func);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool CParamDisplay::getFocusPath (CGraphicsPath& outPath)
|
||||
{
|
||||
if (wantsFocus ())
|
||||
{
|
||||
auto lineWidth = getFrameWidth ();
|
||||
if (lineWidth < 0.)
|
||||
lineWidth = 1.;
|
||||
CCoord focusWidth = getFrame ()->getFocusWidth ();
|
||||
CRect r (getViewSize ());
|
||||
if (hasBit (style, kRoundRectStyle))
|
||||
{
|
||||
r.inset (lineWidth / 2., lineWidth / 2.);
|
||||
outPath.addRoundRect (r, roundRectRadius);
|
||||
outPath.closeSubpath ();
|
||||
r.extend (focusWidth, focusWidth);
|
||||
outPath.addRoundRect (r, roundRectRadius);
|
||||
}
|
||||
else
|
||||
{
|
||||
r.inset (lineWidth / 2., lineWidth / 2.);
|
||||
outPath.addRect (r);
|
||||
r.extend (focusWidth, focusWidth);
|
||||
outPath.addRect (r);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CParamDisplay::draw (CDrawContext *pContext)
|
||||
{
|
||||
if (hasBit (style, kNoDrawStyle))
|
||||
return;
|
||||
|
||||
std::string string;
|
||||
|
||||
bool converted = false;
|
||||
if (valueToStringFunction)
|
||||
converted = valueToStringFunction (value, string, this);
|
||||
if (!converted)
|
||||
{
|
||||
char tmp[255];
|
||||
char precisionStr[10];
|
||||
snprintf (precisionStr, 10, "%%.%hhuf", valuePrecision);
|
||||
snprintf (tmp, 255, precisionStr, value);
|
||||
string = tmp;
|
||||
}
|
||||
|
||||
drawBack (pContext);
|
||||
drawPlatformText (pContext, UTF8String (string));
|
||||
setDirty (false);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CParamDisplay::drawBack (CDrawContext* pContext, CBitmap* newBack)
|
||||
{
|
||||
pContext->setDrawMode (kAliasing);
|
||||
auto lineWidth = getFrameWidth ();
|
||||
if (lineWidth < 0.)
|
||||
lineWidth = pContext->getHairlineSize ();
|
||||
if (newBack)
|
||||
{
|
||||
newBack->draw (pContext, getViewSize (), backOffset);
|
||||
}
|
||||
else if (getDrawBackground ())
|
||||
{
|
||||
getDrawBackground ()->draw (pContext, getViewSize (), backOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!getTransparency ())
|
||||
{
|
||||
bool strokePath = !(hasBit (style, (k3DIn|k3DOut|kNoFrame)));
|
||||
pContext->setFillColor (backColor);
|
||||
if (hasBit (style, kRoundRectStyle))
|
||||
{
|
||||
CRect pathRect = getViewSize ();
|
||||
pathRect.inset (lineWidth/2., lineWidth/2.);
|
||||
SharedPointer<CGraphicsPath> path = owned (pContext->createRoundRectGraphicsPath (pathRect, roundRectRadius));
|
||||
if (path)
|
||||
{
|
||||
pContext->setDrawMode (kAntiAliasing);
|
||||
pContext->drawGraphicsPath (path, CDrawContext::kPathFilled);
|
||||
if (strokePath)
|
||||
{
|
||||
pContext->setLineStyle (kLineSolid);
|
||||
pContext->setLineWidth (lineWidth);
|
||||
pContext->setFrameColor (frameColor);
|
||||
pContext->drawGraphicsPath (path, CDrawContext::kPathStroked);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pContext->setDrawMode (kAntiAliasing);
|
||||
SharedPointer<CGraphicsPath> path = owned (pContext->createGraphicsPath ());
|
||||
if (path)
|
||||
{
|
||||
CRect frameRect = getViewSize ();
|
||||
if (strokePath)
|
||||
frameRect.inset (lineWidth/2., lineWidth/2.);
|
||||
path->addRect (frameRect);
|
||||
pContext->drawGraphicsPath (path, CDrawContext::kPathFilled);
|
||||
if (strokePath)
|
||||
{
|
||||
pContext->setLineStyle (kLineSolid);
|
||||
pContext->setLineWidth (lineWidth);
|
||||
pContext->setFrameColor (frameColor);
|
||||
pContext->drawGraphicsPath (path, CDrawContext::kPathStroked);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pContext->drawRect (getViewSize (), kDrawFilled);
|
||||
|
||||
if (strokePath)
|
||||
{
|
||||
CRect frameRect = getViewSize ();
|
||||
frameRect.inset (lineWidth/2., lineWidth/2.);
|
||||
|
||||
pContext->setLineStyle (kLineSolid);
|
||||
pContext->setLineWidth (lineWidth);
|
||||
pContext->setFrameColor (frameColor);
|
||||
pContext->drawRect (frameRect);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// draw the frame for the 3D effect
|
||||
if (hasBit (style, (k3DIn|k3DOut)))
|
||||
{
|
||||
CRect r (getViewSize ());
|
||||
r.inset (lineWidth/2., lineWidth/2.);
|
||||
pContext->setDrawMode (kAliasing);
|
||||
pContext->setLineWidth (lineWidth);
|
||||
pContext->setLineStyle (kLineSolid);
|
||||
if (hasBit (style, k3DIn))
|
||||
pContext->setFrameColor (backColor);
|
||||
else
|
||||
pContext->setFrameColor (frameColor);
|
||||
|
||||
CPoint p;
|
||||
SharedPointer<CGraphicsPath> path = owned (pContext->createGraphicsPath ());
|
||||
if (path)
|
||||
{
|
||||
path->beginSubpath (p (r.left, r.bottom));
|
||||
path->addLine (p (r.left, r.top));
|
||||
path->addLine (p (r.right, r.top));
|
||||
pContext->drawGraphicsPath (path, CDrawContext::kPathStroked);
|
||||
}
|
||||
else
|
||||
{
|
||||
pContext->drawLine (CPoint (r.left, r.bottom), CPoint (r.left, r.top));
|
||||
pContext->drawLine (CPoint (r.left, r.top), CPoint (r.right, r.top));
|
||||
}
|
||||
|
||||
if (hasBit (style, k3DIn))
|
||||
pContext->setFrameColor (frameColor);
|
||||
else
|
||||
pContext->setFrameColor (backColor);
|
||||
|
||||
path = owned (pContext->createGraphicsPath ());
|
||||
if (path)
|
||||
{
|
||||
path->beginSubpath (p (r.right, r.top));
|
||||
path->addLine (p (r.right, r.bottom));
|
||||
path->addLine (p (r.left, r.bottom));
|
||||
pContext->drawGraphicsPath (path, CDrawContext::kPathStroked);
|
||||
}
|
||||
else
|
||||
{
|
||||
pContext->drawLine (CPoint (r.right, r.top), CPoint (r.right, r.bottom));
|
||||
pContext->drawLine (CPoint (r.right, r.bottom), CPoint (r.left, r.bottom));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CParamDisplay::drawPlatformText (CDrawContext* pContext, const UTF8String& string)
|
||||
{
|
||||
drawPlatformText (pContext, string, getViewSize ());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CParamDisplay::drawPlatformText (CDrawContext* pContext, const UTF8String& string,
|
||||
const CRect& size)
|
||||
{
|
||||
if (!hasBit (style, kNoTextStyle))
|
||||
{
|
||||
pContext->saveGlobalState ();
|
||||
CRect textRect (size);
|
||||
textRect.inset (textInset.x, textInset.y);
|
||||
|
||||
drawClipped (pContext, textRect, [&] () {
|
||||
CPoint center (textRect.getCenter ());
|
||||
CGraphicsTransform transform;
|
||||
transform.rotate (textRotation, center);
|
||||
CDrawContext::Transform ctxTransform (*pContext, transform);
|
||||
|
||||
pContext->setDrawMode (kAntiAliasing);
|
||||
pContext->setFont (fontID);
|
||||
|
||||
// draw darker text (as shadow)
|
||||
if (hasBit (style, kShadowText))
|
||||
{
|
||||
CRect newSize (textRect);
|
||||
newSize.offset (shadowTextOffset);
|
||||
pContext->setFontColor (shadowColor);
|
||||
pContext->drawString (string.getPlatformString (), newSize, horiTxtAlign,
|
||||
hasBit (style, kAntialias));
|
||||
}
|
||||
pContext->setFontColor (fontColor);
|
||||
pContext->drawString (string.getPlatformString (), textRect, horiTxtAlign,
|
||||
hasBit (style, kAntialias));
|
||||
});
|
||||
pContext->restoreGlobalState ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CParamDisplay::setFont (CFontRef inFontID)
|
||||
{
|
||||
if (fontID)
|
||||
fontID->forget ();
|
||||
fontID = inFontID;
|
||||
if (fontID)
|
||||
fontID->remember ();
|
||||
drawStyleChanged ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CParamDisplay::setFontColor (CColor color)
|
||||
{
|
||||
// to force the redraw
|
||||
if (fontColor != color)
|
||||
{
|
||||
fontColor = color;
|
||||
drawStyleChanged ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CParamDisplay::setBackColor (CColor color)
|
||||
{
|
||||
// to force the redraw
|
||||
if (backColor != color)
|
||||
{
|
||||
backColor = color;
|
||||
drawStyleChanged ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CParamDisplay::setFrameColor (CColor color)
|
||||
{
|
||||
// to force the redraw
|
||||
if (frameColor != color)
|
||||
{
|
||||
frameColor = color;
|
||||
drawStyleChanged ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CParamDisplay::setShadowColor (CColor color)
|
||||
{
|
||||
// to force the redraw
|
||||
if (shadowColor != color)
|
||||
{
|
||||
shadowColor = color;
|
||||
drawStyleChanged ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CParamDisplay::setShadowTextOffset (const CPoint& offset)
|
||||
{
|
||||
if (shadowTextOffset != offset)
|
||||
{
|
||||
shadowTextOffset = offset;
|
||||
drawStyleChanged ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CParamDisplay::setHoriAlign (CHoriTxtAlign hAlign)
|
||||
{
|
||||
// to force the redraw
|
||||
if (horiTxtAlign != hAlign)
|
||||
{
|
||||
horiTxtAlign = hAlign;
|
||||
drawStyleChanged ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CParamDisplay::setTextInset (const CPoint& p)
|
||||
{
|
||||
if (textInset != p)
|
||||
{
|
||||
textInset = p;
|
||||
drawStyleChanged ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CParamDisplay::setTextRotation (double angle)
|
||||
{
|
||||
while (angle < 0.)
|
||||
angle += 360.;
|
||||
while (angle > 360.)
|
||||
angle -= 360.;
|
||||
if (textRotation != angle)
|
||||
{
|
||||
textRotation = angle;
|
||||
drawStyleChanged ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CParamDisplay::setRoundRectRadius (const CCoord& radius)
|
||||
{
|
||||
if (roundRectRadius != radius)
|
||||
{
|
||||
roundRectRadius = radius;
|
||||
drawStyleChanged ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CParamDisplay::setFrameWidth (const CCoord& width)
|
||||
{
|
||||
if (frameWidth != width)
|
||||
{
|
||||
frameWidth = width;
|
||||
drawStyleChanged ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CParamDisplay::drawStyleChanged ()
|
||||
{
|
||||
setDirty ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CParamDisplay::setBackOffset (const CPoint &offset)
|
||||
{
|
||||
backOffset = offset;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CParamDisplay::copyBackOffset ()
|
||||
{
|
||||
backOffset (getViewSize ().left, getViewSize ().top);
|
||||
}
|
||||
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,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 "ccontrol.h"
|
||||
#include "../cfont.h"
|
||||
#include "../ccolor.h"
|
||||
#include "../cdrawdefs.h"
|
||||
#include <functional>
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
using CParamDisplayValueToStringProc = bool (*) (float value, char utf8String[256], void* userData);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CParamDisplay Declaration
|
||||
//! @brief a parameter display
|
||||
/// @ingroup views
|
||||
//-----------------------------------------------------------------------------
|
||||
class CParamDisplay : public CControl
|
||||
{
|
||||
protected:
|
||||
enum StyleEnum
|
||||
{
|
||||
StyleShadowText = 0,
|
||||
Style3DIn,
|
||||
Style3DOut,
|
||||
StyleNoText,
|
||||
StyleNoDraw,
|
||||
StyleRoundRect,
|
||||
StyleNoFrame,
|
||||
StyleAntialias,
|
||||
LastStyle
|
||||
};
|
||||
|
||||
public:
|
||||
CParamDisplay (const CRect& size, CBitmap* background = nullptr, int32_t style = 0);
|
||||
CParamDisplay (const CParamDisplay& paramDisplay);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @name CParamDisplay Methods
|
||||
//-----------------------------------------------------------------------------
|
||||
//@{
|
||||
virtual void setFont (CFontRef fontID);
|
||||
const CFontRef getFont () const { return fontID; }
|
||||
|
||||
virtual void setFontColor (CColor color);
|
||||
CColor getFontColor () const { return fontColor; }
|
||||
|
||||
virtual void setBackColor (CColor color);
|
||||
CColor getBackColor () const { return backColor; }
|
||||
|
||||
virtual void setFrameColor (CColor color);
|
||||
CColor getFrameColor () const { return frameColor; }
|
||||
|
||||
virtual void setShadowColor (CColor color);
|
||||
CColor getShadowColor () const { return shadowColor; }
|
||||
|
||||
virtual void setShadowTextOffset (const CPoint& offset);
|
||||
CPoint getShadowTextOffset () const { return shadowTextOffset; }
|
||||
|
||||
virtual void setAntialias (bool state) { setBit (style, kAntialias, state); }
|
||||
bool getAntialias () const { return hasBit (style, kAntialias); }
|
||||
|
||||
virtual void setHoriAlign (CHoriTxtAlign hAlign);
|
||||
CHoriTxtAlign getHoriAlign () const { return horiTxtAlign; }
|
||||
|
||||
virtual void setTextInset (const CPoint& p);
|
||||
CPoint getTextInset () const { return textInset; }
|
||||
|
||||
virtual void setTextRotation (double angle);
|
||||
double getTextRotation () const { return textRotation; }
|
||||
|
||||
virtual void setRoundRectRadius (const CCoord& radius);
|
||||
CCoord getRoundRectRadius () const { return roundRectRadius; }
|
||||
|
||||
virtual void setFrameWidth (const CCoord& width);
|
||||
CCoord getFrameWidth () const { return frameWidth; }
|
||||
|
||||
using ValueToStringUserData = CParamDisplay;
|
||||
using ValueToStringFunction = std::function<bool (float value, char utf8String[256], CParamDisplay* display)>;
|
||||
|
||||
void setValueToStringFunction (const ValueToStringFunction& valueToStringFunc);
|
||||
void setValueToStringFunction (ValueToStringFunction&& valueToStringFunc);
|
||||
|
||||
using ValueToStringFunction2 = std::function<bool (float value, std::string& result, CParamDisplay* display)>;
|
||||
|
||||
void setValueToStringFunction2 (const ValueToStringFunction2& valueToStringFunc);
|
||||
void setValueToStringFunction2 (ValueToStringFunction2&& valueToStringFunc);
|
||||
|
||||
enum Style
|
||||
{
|
||||
kShadowText = 1 << StyleShadowText,
|
||||
k3DIn = 1 << Style3DIn,
|
||||
k3DOut = 1 << Style3DOut,
|
||||
kNoTextStyle = 1 << StyleNoText,
|
||||
kNoDrawStyle = 1 << StyleNoDraw,
|
||||
kRoundRectStyle = 1 << StyleRoundRect,
|
||||
kNoFrame = 1 << StyleNoFrame,
|
||||
};
|
||||
virtual void setStyle (int32_t val);
|
||||
int32_t getStyle () const;
|
||||
|
||||
virtual void setPrecision (uint8_t precision);
|
||||
uint8_t getPrecision () const { return valuePrecision; }
|
||||
|
||||
virtual void setBackOffset (const CPoint& offset);
|
||||
const CPoint& getBackOffset () const { return backOffset; }
|
||||
void copyBackOffset ();
|
||||
|
||||
//@}
|
||||
|
||||
void draw (CDrawContext* pContext) override;
|
||||
bool getFocusPath (CGraphicsPath& outPath) override;
|
||||
bool removed (CView* parent) override;
|
||||
|
||||
CLASS_METHODS(CParamDisplay, CControl)
|
||||
protected:
|
||||
~CParamDisplay () noexcept override;
|
||||
virtual void drawBack (CDrawContext* pContext, CBitmap* newBack = nullptr);
|
||||
|
||||
virtual void drawPlatformText (CDrawContext* pContext, const UTF8String& string);
|
||||
virtual void drawPlatformText (CDrawContext* pContext, const UTF8String& string,
|
||||
const CRect& size);
|
||||
|
||||
virtual void drawStyleChanged ();
|
||||
|
||||
ValueToStringFunction2 valueToStringFunction;
|
||||
|
||||
enum StylePrivate {
|
||||
kAntialias = 1 << StyleAntialias,
|
||||
};
|
||||
|
||||
CHoriTxtAlign horiTxtAlign;
|
||||
int32_t style;
|
||||
uint8_t valuePrecision;
|
||||
|
||||
CFontRef fontID;
|
||||
CColor fontColor;
|
||||
CColor backColor;
|
||||
CColor frameColor;
|
||||
CColor shadowColor;
|
||||
CPoint textInset;
|
||||
CPoint shadowTextOffset {1., 1.};
|
||||
CPoint backOffset;
|
||||
CCoord roundRectRadius;
|
||||
CCoord frameWidth;
|
||||
double textRotation;
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,416 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#include "cscrollbar.h"
|
||||
#include "../cvstguitimer.h"
|
||||
#include "../animation/animations.h"
|
||||
#include "../animation/timingfunctions.h"
|
||||
#include "../cframe.h"
|
||||
#include "../cgraphicspath.h"
|
||||
#include "../cdrawcontext.h"
|
||||
#include "../events.h"
|
||||
#include "../algorithm.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CScrollbar::CScrollbar (const CRect& size, IControlListener* listener, int32_t tag, ScrollbarDirection direction, const CRect& scrollSize)
|
||||
: CControl (size, listener, tag, nullptr)
|
||||
, direction (direction)
|
||||
, scrollSize (scrollSize)
|
||||
, scrollerArea (size)
|
||||
, stepValue (0.1f)
|
||||
, scrollerLength (0)
|
||||
, overlayStyle (false)
|
||||
, mouseIsInside (false)
|
||||
, drawer (nullptr)
|
||||
{
|
||||
setTransparency (true);
|
||||
setWheelInc (0.05f);
|
||||
scrollerArea.inset (2, 2);
|
||||
calculateScrollerLength ();
|
||||
frameColor (0, 0, 0, 255);
|
||||
scrollerColor (0, 0, 255, 255);
|
||||
backgroundColor (255, 255, 255, 200);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CScrollbar::CScrollbar (const CScrollbar& v)
|
||||
: CControl (v)
|
||||
, direction (v.direction)
|
||||
, scrollSize (v.scrollSize)
|
||||
, scrollerArea (v.scrollerArea)
|
||||
, stepValue (v.stepValue)
|
||||
, scrollerLength (v.scrollerLength)
|
||||
, frameColor (v.frameColor)
|
||||
, scrollerColor (v.scrollerColor)
|
||||
, backgroundColor (v.backgroundColor)
|
||||
, overlayStyle (v.overlayStyle)
|
||||
, mouseIsInside (false)
|
||||
, drawer (v.drawer)
|
||||
{
|
||||
calculateScrollerLength ();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CScrollbar::setViewSize (const CRect &newSize, bool invalid)
|
||||
{
|
||||
scrollerArea = newSize;
|
||||
scrollerArea.inset (2, 2);
|
||||
CControl::setViewSize (newSize, invalid);
|
||||
calculateScrollerLength ();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CScrollbar::setScrollSize (const CRect& ssize)
|
||||
{
|
||||
if (scrollSize != ssize)
|
||||
{
|
||||
scrollSize = ssize;
|
||||
calculateScrollerLength ();
|
||||
setDirty (true);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CScrollbar::calculateScrollerLength ()
|
||||
{
|
||||
CCoord newScrollerLength;
|
||||
if (direction == kHorizontal)
|
||||
{
|
||||
double factor = scrollSize.getWidth () > 0. ? getViewSize ().getWidth () / scrollSize.getWidth () : 0.;
|
||||
if (factor >= 1.f)
|
||||
factor = 0;
|
||||
newScrollerLength = (CCoord) (getViewSize ().getWidth () * factor);
|
||||
}
|
||||
else
|
||||
{
|
||||
double factor = scrollSize.getHeight () > 0 ? getViewSize ().getHeight () / scrollSize.getHeight () : 0.;
|
||||
if (factor >= 1.f)
|
||||
factor = 0;
|
||||
newScrollerLength = (CCoord) (getViewSize ().getHeight () * factor);
|
||||
}
|
||||
if (newScrollerLength < minScrollerLenght && newScrollerLength > 0.)
|
||||
newScrollerLength = minScrollerLenght;
|
||||
if (newScrollerLength != scrollerLength)
|
||||
{
|
||||
scrollerLength = newScrollerLength;
|
||||
setDirty (true);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CRect CScrollbar::getScrollerRect ()
|
||||
{
|
||||
CRect sr (scrollerArea);
|
||||
CCoord l = (direction == kHorizontal) ? scrollerArea.getWidth () : scrollerArea.getHeight ();
|
||||
CCoord scrollerOffset = (CCoord)(getValueNormalized () * (l - scrollerLength));
|
||||
if (direction == kHorizontal)
|
||||
{
|
||||
sr.setWidth (scrollerLength);
|
||||
sr.offset (scrollerOffset, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
sr.setHeight (scrollerLength);
|
||||
sr.offset (0, scrollerOffset);
|
||||
}
|
||||
return sr;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CScrollbar::doStepping ()
|
||||
{
|
||||
CRect sr = getScrollerRect ();
|
||||
if (timer)
|
||||
{
|
||||
if (!getViewSize ().pointInside (startPoint) || sr.pointInside (startPoint))
|
||||
return;
|
||||
}
|
||||
bool dir = (direction == kHorizontal && startPoint.x < sr.left) || (direction == kVertical && startPoint.y < sr.top);
|
||||
float newValue = getValueNormalized ();
|
||||
if (direction == kHorizontal)
|
||||
{
|
||||
if (dir)
|
||||
newValue -= (float)scrollerLength / (float)scrollerArea.getWidth ();
|
||||
else
|
||||
newValue += (float)scrollerLength / (float)scrollerArea.getWidth ();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dir)
|
||||
newValue -= (float)scrollerLength / (float)scrollerArea.getHeight ();
|
||||
else
|
||||
newValue += (float)scrollerLength / (float)scrollerArea.getHeight ();
|
||||
}
|
||||
newValue = clampNorm (newValue);
|
||||
if (newValue != getValueNormalized ())
|
||||
{
|
||||
setValueNormalized (newValue);
|
||||
valueChanged ();
|
||||
invalid ();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CMessageResult CScrollbar::notify (CBaseObject* sender, IdStringPtr message)
|
||||
{
|
||||
if (message == CVSTGUITimer::kMsgTimer && timer)
|
||||
{
|
||||
doStepping ();
|
||||
timer->setFireTime (80);
|
||||
return kMessageNotified;
|
||||
}
|
||||
return kMessageUnknown;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CScrollbar::setOverlayStyle (bool state)
|
||||
{
|
||||
if (overlayStyle != state)
|
||||
{
|
||||
overlayStyle = state;
|
||||
setAlphaValue (overlayStyle ? 0.001f : 1.f);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CScrollbar::setMinScrollerLength (CCoord length)
|
||||
{
|
||||
if (minScrollerLenght != length)
|
||||
{
|
||||
minScrollerLenght = length;
|
||||
calculateScrollerLength ();
|
||||
setDirty ();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CMouseEventResult CScrollbar::onMouseEntered (CPoint& where, const CButtonState& buttons)
|
||||
{
|
||||
if (overlayStyle && scrollerLength != 0)
|
||||
{
|
||||
addAnimation ("AlphaValueAnimation", new Animation::AlphaValueAnimation (1.f), new Animation::LinearTimingFunction (100));
|
||||
}
|
||||
mouseIsInside = true;
|
||||
return kMouseEventNotHandled;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CMouseEventResult CScrollbar::onMouseExited (CPoint& where, const CButtonState& buttons)
|
||||
{
|
||||
if (overlayStyle && scrollerLength != 0)
|
||||
{
|
||||
Animation::ITimingFunction* timingFunction = nullptr;
|
||||
if (getAlphaValue () == 1.f)
|
||||
{
|
||||
auto* interpolTimingFunction = new Animation::InterpolationTimingFunction (400);
|
||||
interpolTimingFunction->addPoint (300.f/400.f, 1.f);
|
||||
timingFunction = interpolTimingFunction;
|
||||
}
|
||||
else
|
||||
timingFunction = new Animation::LinearTimingFunction (100);
|
||||
addAnimation ("AlphaValueAnimation", new Animation::AlphaValueAnimation (0.001f), timingFunction);
|
||||
}
|
||||
mouseIsInside = false;
|
||||
return kMouseEventNotHandled;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CMouseEventResult CScrollbar::onMouseDown (CPoint &where, const CButtonState& buttons)
|
||||
{
|
||||
if (buttons != kLButton || scrollerLength == 0)
|
||||
return kMouseDownEventHandledButDontNeedMovedOrUpEvents;
|
||||
|
||||
startPoint = where;
|
||||
scrollerRect = getScrollerRect ();
|
||||
scrolling = scrollerRect.pointInside (where);
|
||||
if (scrolling)
|
||||
{
|
||||
scrollerRect = getScrollerRect ();
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
else if (scrollerArea.pointInside (where))
|
||||
{
|
||||
doStepping ();
|
||||
timer = makeOwned<CVSTGUITimer> (this, 250, true);
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
return kMouseDownEventHandledButDontNeedMovedOrUpEvents;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CMouseEventResult CScrollbar::onMouseUp (CPoint &where, const CButtonState& buttons)
|
||||
{
|
||||
timer = nullptr;
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CMouseEventResult CScrollbar::onMouseMoved (CPoint &where, const CButtonState& buttons)
|
||||
{
|
||||
if (buttons & kLButton)
|
||||
{
|
||||
if (scrolling)
|
||||
{
|
||||
float newValue = 0.f;
|
||||
CPoint newPoint (where);
|
||||
newPoint.x -= startPoint.x - scrollerRect.left;
|
||||
newPoint.y -= startPoint.y - scrollerRect.top;
|
||||
if (direction == kHorizontal)
|
||||
{
|
||||
newValue = (float)((float)(newPoint.x - scrollerArea.left) / ((float)scrollerArea.getWidth () - scrollerRect.getWidth ()));
|
||||
}
|
||||
else
|
||||
{
|
||||
newValue = (float)((float)(newPoint.y - scrollerArea.top) / ((float)scrollerArea.getHeight () - scrollerRect.getHeight ()));
|
||||
}
|
||||
newValue = clampNorm (newValue);
|
||||
if (newValue != getValueNormalized ())
|
||||
{
|
||||
setValueNormalized (newValue);
|
||||
valueChanged ();
|
||||
invalid ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CPoint old (startPoint);
|
||||
startPoint = where;
|
||||
CRect scollerRect = getScrollerRect ();
|
||||
if (getViewSize ().pointInside (where) && scollerRect.pointInside (old) && !scrollerRect.pointInside (startPoint))
|
||||
doStepping ();
|
||||
}
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
return kMouseEventNotHandled;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMouseEventResult CScrollbar::onMouseCancel ()
|
||||
{
|
||||
timer = nullptr;
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CScrollbar::onVisualChange ()
|
||||
{
|
||||
if (isAttached () && overlayStyle && !mouseIsInside)
|
||||
{
|
||||
if (scrollerLength != 0)
|
||||
{
|
||||
auto timingFunction = new Animation::InterpolationTimingFunction (1100);
|
||||
timingFunction->addPoint (1000.f/1100.f, 0);
|
||||
addAnimation ("AlphaValueAnimation", new Animation::AlphaValueAnimation (0.001f), timingFunction);
|
||||
setAlphaValue (1.f);
|
||||
}
|
||||
else
|
||||
{
|
||||
removeAnimation ("AlphaValueAnimation");
|
||||
setAlphaValue (0.f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CScrollbar::onMouseWheelEvent (MouseWheelEvent& event)
|
||||
{
|
||||
if (scrollerLength == 0 || !getMouseEnabled ())
|
||||
return;
|
||||
|
||||
if (!event.modifiers.empty () && !(event.modifiers.has (ModifierKey::Shift) &&
|
||||
event.flags & MouseWheelEvent::DirectionInvertedFromDevice))
|
||||
return;
|
||||
|
||||
float distance = 0.f;
|
||||
if (direction == kHorizontal)
|
||||
distance = static_cast<float> (event.deltaX);
|
||||
else
|
||||
distance = static_cast<float> (event.deltaY);
|
||||
|
||||
if (distance == 0.f)
|
||||
return;
|
||||
|
||||
if (event.flags & MouseWheelEvent::DirectionInvertedFromDevice)
|
||||
distance *= -1;
|
||||
|
||||
float newValue = getValueNormalized ();
|
||||
if (event.modifiers.has (ModifierKey::Shift))
|
||||
newValue -= 0.1f * distance * getWheelInc ();
|
||||
else
|
||||
newValue -= distance * getWheelInc ();
|
||||
newValue = clampNorm (newValue);
|
||||
|
||||
if (newValue != getValueNormalized ())
|
||||
{
|
||||
setValueNormalized (newValue);
|
||||
onVisualChange ();
|
||||
valueChanged ();
|
||||
invalid ();
|
||||
}
|
||||
event.consumed = true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CScrollbar::drawBackground (CDrawContext* pContext)
|
||||
{
|
||||
CRect r (getViewSize ());
|
||||
if (drawer)
|
||||
drawer->drawScrollbarBackground (pContext, r, direction, this);
|
||||
else
|
||||
{
|
||||
pContext->setDrawMode (kAliasing);
|
||||
pContext->setLineWidth (1);
|
||||
pContext->setFillColor (backgroundColor);
|
||||
pContext->setFrameColor (frameColor);
|
||||
pContext->setLineStyle (kLineSolid);
|
||||
pContext->drawRect (r, kDrawFilledAndStroked);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CScrollbar::drawScroller (CDrawContext* pContext, const CRect& size)
|
||||
{
|
||||
CRect r (size);
|
||||
if (drawer)
|
||||
drawer->drawScrollbarScroller (pContext, r, direction, this);
|
||||
else
|
||||
{
|
||||
pContext->setLineWidth (1);
|
||||
pContext->setFillColor (scrollerColor);
|
||||
pContext->setFrameColor (frameColor);
|
||||
|
||||
CCoord wideness = (direction == kVertical ? getWidth() : getHeight()) / 2 - 2;
|
||||
auto path = (wideness > 2) ? owned (pContext->createGraphicsPath ()) : nullptr;
|
||||
if (path)
|
||||
{
|
||||
if (wideness > 4)
|
||||
wideness = 4;
|
||||
pContext->setDrawMode (kAntiAliasing|kNonIntegralMode);
|
||||
path->addRoundRect (r, wideness);
|
||||
pContext->drawGraphicsPath (path, CDrawContext::kPathFilled);
|
||||
pContext->drawGraphicsPath (path, CDrawContext::kPathStroked);
|
||||
}
|
||||
else
|
||||
{
|
||||
pContext->setDrawMode (kAliasing|kNonIntegralMode);
|
||||
pContext->drawRect (r, kDrawFilledAndStroked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CScrollbar::draw (CDrawContext* pContext)
|
||||
{
|
||||
drawBackground (pContext);
|
||||
if (scrollerLength > 0)
|
||||
{
|
||||
CRect sr = getScrollerRect ();
|
||||
drawScroller (pContext, sr);
|
||||
}
|
||||
setDirty (false);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ccontrol.h"
|
||||
#include "../ccolor.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CScrollbar Declaration
|
||||
//! @brief a scrollbar control
|
||||
/// @ingroup controls
|
||||
//-----------------------------------------------------------------------------
|
||||
class CScrollbar : public CControl
|
||||
{
|
||||
public:
|
||||
enum ScrollbarDirection {
|
||||
kHorizontal,
|
||||
kVertical
|
||||
};
|
||||
|
||||
CScrollbar (const CRect& size, IControlListener* listener, int32_t tag, ScrollbarDirection style, const CRect& scrollSize);
|
||||
CScrollbar (const CScrollbar& scrollbar);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @name CScrollbar Methods
|
||||
//-----------------------------------------------------------------------------
|
||||
//@{
|
||||
virtual void setDrawer (IScrollbarDrawer* d) { drawer = d; }
|
||||
virtual void setScrollSize (const CRect& ssize);
|
||||
virtual void setStep (float newStep) { stepValue = newStep; }
|
||||
|
||||
CRect& getScrollSize (CRect& rect) const { rect = scrollSize; return rect; }
|
||||
float getStep () const { return stepValue; }
|
||||
|
||||
virtual void setFrameColor (const CColor& color) { frameColor = color; }
|
||||
virtual void setScrollerColor (const CColor& color) { scrollerColor = color; }
|
||||
virtual void setBackgroundColor (const CColor& color) { backgroundColor = color; }
|
||||
|
||||
CColor getFrameColor () const { return frameColor; }
|
||||
CColor getScrollerColor () const { return scrollerColor; }
|
||||
CColor getBackgroundColor () const { return backgroundColor; }
|
||||
|
||||
bool getOverlayStyle () const { return overlayStyle; }
|
||||
virtual void setOverlayStyle (bool state);
|
||||
|
||||
void setMinScrollerLength (CCoord length);
|
||||
CCoord getMinScrollerLength () const { return minScrollerLenght; }
|
||||
|
||||
virtual void onVisualChange ();
|
||||
CRect getScrollerRect ();
|
||||
//@}
|
||||
|
||||
// overwrite
|
||||
void draw (CDrawContext* pContext) override;
|
||||
void onMouseWheelEvent (MouseWheelEvent& event) override;
|
||||
CMouseEventResult onMouseDown (CPoint& where, const CButtonState& buttons) override;
|
||||
CMouseEventResult onMouseUp (CPoint& where, const CButtonState& buttons) override;
|
||||
CMouseEventResult onMouseMoved (CPoint& where, const CButtonState& buttons) override;
|
||||
CMouseEventResult onMouseCancel () override;
|
||||
CMessageResult notify (CBaseObject* sender, IdStringPtr message) override;
|
||||
void setViewSize (const CRect& newSize, bool invalid) override;
|
||||
|
||||
CMouseEventResult onMouseEntered (CPoint& where, const CButtonState& buttons) override;
|
||||
CMouseEventResult onMouseExited (CPoint& where, const CButtonState& buttons) override;
|
||||
|
||||
CLASS_METHODS(CScrollbar, CControl)
|
||||
//-----------------------------------------------------------------------------
|
||||
protected:
|
||||
~CScrollbar () noexcept override = default;
|
||||
|
||||
void drawBackground (CDrawContext* pContext);
|
||||
void drawScroller (CDrawContext* pContext, const CRect& size);
|
||||
|
||||
void calculateScrollerLength ();
|
||||
void doStepping ();
|
||||
|
||||
ScrollbarDirection direction;
|
||||
CRect scrollSize;
|
||||
CRect scrollerArea;
|
||||
|
||||
float stepValue;
|
||||
CCoord scrollerLength;
|
||||
CCoord minScrollerLenght {8.0};
|
||||
|
||||
CColor frameColor;
|
||||
CColor scrollerColor;
|
||||
CColor backgroundColor;
|
||||
|
||||
bool overlayStyle;
|
||||
bool mouseIsInside;
|
||||
|
||||
IScrollbarDrawer* drawer;
|
||||
private:
|
||||
SharedPointer<CVSTGUITimer> timer;
|
||||
CPoint startPoint;
|
||||
CRect scrollerRect;
|
||||
bool scrolling;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
class IScrollbarDrawer
|
||||
//-----------------------------------------------------------------------------
|
||||
{
|
||||
public:
|
||||
virtual void drawScrollbarBackground (CDrawContext* pContext, const CRect& size, CScrollbar::ScrollbarDirection direction, CScrollbar* bar) = 0;
|
||||
virtual void drawScrollbarScroller (CDrawContext* pContext, const CRect& size, CScrollbar::ScrollbarDirection direction, CScrollbar* bar) = 0;
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,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
|
||||
|
||||
#include "csearchtextedit.h"
|
||||
|
||||
#include "../cframe.h"
|
||||
#include "../cgraphicspath.h"
|
||||
#include "../cdrawcontext.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
CSearchTextEdit::CSearchTextEdit (const CRect& size, IControlListener* listener, int32_t tag,
|
||||
UTF8StringPtr txt, CBitmap* background, const int32_t style)
|
||||
: CTextEdit (size, listener, tag, nullptr, background, style)
|
||||
{
|
||||
setPlaceholderString ("Search");
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CSearchTextEdit::setClearMarkInset (CPoint inset)
|
||||
{
|
||||
if (inset != clearMarkInset)
|
||||
{
|
||||
clearMarkInset = inset;
|
||||
invalid ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CPoint CSearchTextEdit::getClearMarkInset () const
|
||||
{
|
||||
return clearMarkInset;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
CRect CSearchTextEdit::getClearMarkRect () const
|
||||
{
|
||||
CRect r (getViewSize ());
|
||||
if (getHoriAlign () == kRightText)
|
||||
r.right = r.left + getHeight ();
|
||||
else
|
||||
r.left = r.right - getHeight ();
|
||||
r.inset (getClearMarkInset ());
|
||||
return r;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
CMouseEventResult CSearchTextEdit::onMouseDown (CPoint& where, const CButtonState& buttons)
|
||||
{
|
||||
if (buttons.isLeftButton ())
|
||||
{
|
||||
if (!getText ().empty ())
|
||||
{
|
||||
if (getClearMarkRect ().pointInside (where))
|
||||
{
|
||||
beginEdit ();
|
||||
setText ("");
|
||||
valueChanged ();
|
||||
endEdit ();
|
||||
return kMouseDownEventHandledButDontNeedMovedOrUpEvents;
|
||||
}
|
||||
}
|
||||
}
|
||||
return CTextEdit::onMouseDown (where, buttons);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void CSearchTextEdit::drawClearMark (CDrawContext* context) const
|
||||
{
|
||||
if (!((platformControl && !platformControl->getText ().empty ()) || !getText ().empty ()))
|
||||
return;
|
||||
|
||||
auto path = owned (context->createGraphicsPath ());
|
||||
if (path == nullptr)
|
||||
return;
|
||||
|
||||
CRect r = getClearMarkRect ();
|
||||
CColor color (fontColor);
|
||||
color.alpha /= 2;
|
||||
context->setFillColor (color);
|
||||
context->setDrawMode (kAntiAliasing);
|
||||
context->drawEllipse (r, kDrawFilled);
|
||||
double h,s,v;
|
||||
color.toHSV (h, s, v);
|
||||
v = 1. - v;
|
||||
color.fromHSV (h, s, v);
|
||||
context->setFrameColor (color);
|
||||
context->setLineWidth (2.);
|
||||
r.inset (r.getWidth () / (M_PI * 2.) + 1, r.getHeight () / (M_PI * 2.) + 1);
|
||||
path->beginSubpath (r.getTopLeft ());
|
||||
path->addLine (r.getBottomRight ());
|
||||
path->beginSubpath (r.getBottomLeft ());
|
||||
path->addLine (r.getTopRight ());
|
||||
context->setDrawMode (kAntiAliasing);
|
||||
context->drawGraphicsPath (path, CDrawContext::kPathStroked);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void CSearchTextEdit::draw (CDrawContext *pContext)
|
||||
{
|
||||
drawBack (pContext);
|
||||
drawClearMark (pContext);
|
||||
|
||||
if (platformControl)
|
||||
{
|
||||
setDirty (false);
|
||||
return;
|
||||
}
|
||||
|
||||
pContext->setDrawMode (kAntiAliasing);
|
||||
|
||||
CColor origFontColor (fontColor);
|
||||
if (getText ().empty ())
|
||||
{
|
||||
CColor color (fontColor);
|
||||
color.alpha /= 2;
|
||||
setFontColor (color);
|
||||
drawPlatformText (pContext, getPlaceholderString (), getTextRect ());
|
||||
}
|
||||
else
|
||||
drawPlatformText (pContext, getText (), getTextRect ());
|
||||
|
||||
setDirty (false);
|
||||
setFontColor (origFontColor);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CRect CSearchTextEdit::getTextRect () const
|
||||
{
|
||||
CRect rect = getViewSize ();
|
||||
CRect cmr = getClearMarkRect ();
|
||||
if (getHoriAlign () == kRightText)
|
||||
rect.left = cmr.right;
|
||||
else
|
||||
rect.right = cmr.left;
|
||||
return rect;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CRect CSearchTextEdit::platformGetSize () const
|
||||
{
|
||||
return translateToGlobal (getTextRect ());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CRect CSearchTextEdit::platformGetVisibleSize () const
|
||||
{
|
||||
CRect rect = getTextRect ();
|
||||
if (getParentView ())
|
||||
rect = getParentView ()->asViewContainer ()->getVisibleSize (rect);
|
||||
else if (getFrame ())
|
||||
rect = getFrame ()->getVisibleSize (rect);
|
||||
|
||||
return translateToGlobal (rect);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CSearchTextEdit::platformTextDidChange ()
|
||||
{
|
||||
invalidRect (getClearMarkRect ());
|
||||
CTextEdit::platformTextDidChange ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,39 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ctextedit.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Search text edit field
|
||||
* @ingroup new_in_4_5
|
||||
*/
|
||||
class CSearchTextEdit : public CTextEdit
|
||||
{
|
||||
public:
|
||||
CSearchTextEdit (const CRect& size, IControlListener* listener, int32_t tag,
|
||||
UTF8StringPtr txt = nullptr, CBitmap* background = nullptr,
|
||||
const int32_t style = 0);
|
||||
|
||||
void setClearMarkInset (CPoint inset);
|
||||
CPoint getClearMarkInset () const;
|
||||
|
||||
void draw (CDrawContext *pContext) override;
|
||||
CMouseEventResult onMouseDown (CPoint& where, const CButtonState& buttons) override;
|
||||
protected:
|
||||
void drawClearMark (CDrawContext* context) const;
|
||||
CRect getClearMarkRect () const;
|
||||
CRect getTextRect () const;
|
||||
|
||||
CRect platformGetSize () const override;
|
||||
CRect platformGetVisibleSize () const override;
|
||||
void platformTextDidChange () override;
|
||||
|
||||
CPoint clearMarkInset {2., 2.};
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,634 @@
|
||||
// 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 "csegmentbutton.h"
|
||||
#include "../cdrawcontext.h"
|
||||
#include "../cframe.h"
|
||||
#include "../cgraphicspath.h"
|
||||
#include "../events.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CSegmentButton::CSegmentButton (const CRect& size, IControlListener* listener, int32_t tag)
|
||||
: CControl (size, listener, tag), font (kNormalFont)
|
||||
{
|
||||
setWantsFocus (true);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CSegmentButton::canAddOneMoreSegment () const
|
||||
{
|
||||
return (getSelectionMode () != SelectionMode::kMultiple || segments.size () < 32);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CSegmentButton::addSegment (const Segment& segment, uint32_t index)
|
||||
{
|
||||
if (!canAddOneMoreSegment ())
|
||||
return false;
|
||||
if (index == kPushBack && segments.size () < kPushBack)
|
||||
segments.emplace_back (segment);
|
||||
else if (index < segments.size ())
|
||||
{
|
||||
auto it = segments.begin ();
|
||||
std::advance (it, index);
|
||||
segments.insert (it, segment);
|
||||
}
|
||||
updateSegmentSizes ();
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CSegmentButton::addSegment (Segment&& segment, uint32_t index)
|
||||
{
|
||||
if (!canAddOneMoreSegment ())
|
||||
return false;
|
||||
if (index == kPushBack && segments.size () < kPushBack)
|
||||
segments.emplace_back (std::move (segment));
|
||||
else if (index < segments.size ())
|
||||
{
|
||||
auto it = segments.begin ();
|
||||
std::advance (it, index);
|
||||
segments.insert (it, std::move (segment));
|
||||
}
|
||||
updateSegmentSizes ();
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSegmentButton::removeSegment (uint32_t index)
|
||||
{
|
||||
if (index < segments.size ())
|
||||
{
|
||||
auto it = segments.begin ();
|
||||
std::advance (it, index);
|
||||
segments.erase (it);
|
||||
}
|
||||
updateSegmentSizes ();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSegmentButton::removeAllSegments ()
|
||||
{
|
||||
segments.clear ();
|
||||
invalid ();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSegmentButton::valueChanged ()
|
||||
{
|
||||
switch (getSelectionMode ())
|
||||
{
|
||||
case SelectionMode::kSingle:
|
||||
case SelectionMode::kSingleToggle:
|
||||
{
|
||||
auto index = static_cast<int64_t> (getSelectedSegment ());
|
||||
for (auto& segment : segments)
|
||||
{
|
||||
bool state = index == 0;
|
||||
if (state != segment.selected)
|
||||
{
|
||||
segment.selected = state;
|
||||
invalidRect (segment.rect);
|
||||
}
|
||||
--index;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SelectionMode::kMultiple:
|
||||
{
|
||||
auto bitset = static_cast<uint32_t> (value);
|
||||
size_t index = 0;
|
||||
for (auto& segment : segments)
|
||||
{
|
||||
bool state = (hasBit (bitset, 1 << index));
|
||||
if (state != segment.selected)
|
||||
{
|
||||
segment.selected = state;
|
||||
invalidRect (segment.rect);
|
||||
}
|
||||
++index;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
CControl::valueChanged ();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSegmentButton::setSelectedSegment (uint32_t index)
|
||||
{
|
||||
if (index >= segments.size ())
|
||||
return;
|
||||
beginEdit ();
|
||||
setValueNormalized (static_cast<float> (index) / static_cast<float> (segments.size () - 1));
|
||||
valueChanged ();
|
||||
endEdit ();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
uint32_t CSegmentButton::getSelectedSegment () const
|
||||
{
|
||||
return getSegmentIndex (getValueNormalized ());
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSegmentButton::setStyle (Style newStyle)
|
||||
{
|
||||
if (style != newStyle)
|
||||
{
|
||||
style = newStyle;
|
||||
updateSegmentSizes ();
|
||||
invalid ();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSegmentButton::setSelectionMode (SelectionMode mode)
|
||||
{
|
||||
if (mode != selectionMode)
|
||||
{
|
||||
selectionMode = mode;
|
||||
if (isAttached ())
|
||||
{
|
||||
verifySelections ();
|
||||
invalid ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSegmentButton::setTextTruncateMode (CDrawMethods::TextTruncateMode mode)
|
||||
{
|
||||
if (textTruncateMode != mode)
|
||||
{
|
||||
textTruncateMode = mode;
|
||||
invalid ();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSegmentButton::setGradient (CGradient* newGradient)
|
||||
{
|
||||
if (gradient != newGradient)
|
||||
{
|
||||
gradient = newGradient;
|
||||
invalid ();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSegmentButton::setGradientHighlighted (CGradient* newGradient)
|
||||
{
|
||||
if (gradientHighlighted != newGradient)
|
||||
{
|
||||
gradientHighlighted = newGradient;
|
||||
invalid ();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSegmentButton::setRoundRadius (CCoord newRoundRadius)
|
||||
{
|
||||
if (roundRadius != newRoundRadius)
|
||||
{
|
||||
roundRadius = newRoundRadius;
|
||||
invalid ();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSegmentButton::setFont (CFontRef newFont)
|
||||
{
|
||||
if (font != newFont)
|
||||
{
|
||||
font = newFont;
|
||||
invalid ();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSegmentButton::setTextAlignment (CHoriTxtAlign newAlignment)
|
||||
{
|
||||
if (textAlignment != newAlignment)
|
||||
{
|
||||
textAlignment = newAlignment;
|
||||
invalid ();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSegmentButton::setTextMargin (CCoord newMargin)
|
||||
{
|
||||
if (textMargin != newMargin)
|
||||
{
|
||||
textMargin = newMargin;
|
||||
invalid ();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSegmentButton::setTextColor (CColor newColor)
|
||||
{
|
||||
if (textColor != newColor)
|
||||
{
|
||||
textColor = newColor;
|
||||
invalid ();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSegmentButton::setTextColorHighlighted (CColor newColor)
|
||||
{
|
||||
if (textColorHighlighted != newColor)
|
||||
{
|
||||
textColorHighlighted = newColor;
|
||||
invalid ();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSegmentButton::setFrameColor (CColor newColor)
|
||||
{
|
||||
if (frameColor != newColor)
|
||||
{
|
||||
frameColor = newColor;
|
||||
invalid ();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSegmentButton::setFrameWidth (CCoord newWidth)
|
||||
{
|
||||
if (frameWidth != newWidth)
|
||||
{
|
||||
frameWidth = newWidth;
|
||||
invalid ();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CSegmentButton::attached (CView* parent)
|
||||
{
|
||||
if (CControl::attached (parent))
|
||||
{
|
||||
verifySelections ();
|
||||
updateSegmentSizes ();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSegmentButton::setViewSize (const CRect& rect, bool invalid)
|
||||
{
|
||||
CControl::setViewSize (rect, invalid);
|
||||
updateSegmentSizes ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CSegmentButton::selectSegment (uint32_t index, bool state)
|
||||
{
|
||||
beginEdit ();
|
||||
auto bitset = static_cast<uint32_t> (value);
|
||||
setBit (bitset, (1 << index), state);
|
||||
value = static_cast<float> (bitset);
|
||||
valueChanged ();
|
||||
endEdit ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool CSegmentButton::isSegmentSelected (uint32_t index) const
|
||||
{
|
||||
return segments[index].selected;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CMouseEventResult CSegmentButton::onMouseDown (CPoint& where, const CButtonState& buttons)
|
||||
{
|
||||
if (buttons.isLeftButton ())
|
||||
{
|
||||
float newValue = 0;
|
||||
float valueOffset = 1.f / (segments.size () - 1);
|
||||
for (auto& segment : segments)
|
||||
{
|
||||
if (segment.rect.pointInside (where))
|
||||
{
|
||||
uint32_t newIndex = getSegmentIndex (newValue);
|
||||
switch (selectionMode)
|
||||
{
|
||||
case SelectionMode::kSingle:
|
||||
{
|
||||
uint32_t currentIndex = getSegmentIndex (getValueNormalized ());
|
||||
if (newIndex != currentIndex)
|
||||
setSelectedSegment (newIndex);
|
||||
break;
|
||||
}
|
||||
case SelectionMode::kSingleToggle:
|
||||
{
|
||||
uint32_t currentIndex = getSegmentIndex (getValueNormalized ());
|
||||
if (newIndex != currentIndex)
|
||||
setSelectedSegment (newIndex);
|
||||
else
|
||||
{
|
||||
++currentIndex;
|
||||
if (getSegments ().size () - 1 < currentIndex)
|
||||
currentIndex = 0;
|
||||
setSelectedSegment (currentIndex);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SelectionMode::kMultiple:
|
||||
{
|
||||
selectSegment (newIndex, !segment.selected);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break; // out of for loop
|
||||
}
|
||||
newValue += valueOffset;
|
||||
|
||||
// Last segment can lead to newValue > 1.0
|
||||
newValue = std::min(newValue, 1.f);
|
||||
}
|
||||
}
|
||||
return kMouseDownEventHandledButDontNeedMovedOrUpEvents;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSegmentButton::onKeyboardEvent (KeyboardEvent& event)
|
||||
{
|
||||
if (event.type != EventType::KeyDown || event.modifiers.empty () == false ||
|
||||
event.character != 0)
|
||||
return;
|
||||
if (selectionMode != SelectionMode::kMultiple)
|
||||
{
|
||||
uint32_t newIndex = getSegmentIndex (getValueNormalized ());
|
||||
uint32_t oldIndex = newIndex;
|
||||
switch (event.virt)
|
||||
{
|
||||
case VirtualKey::Left:
|
||||
{
|
||||
if (style == Style::kHorizontal && newIndex > 0)
|
||||
newIndex--;
|
||||
else if (style == Style::kHorizontalInverse && newIndex < segments.size () - 1)
|
||||
newIndex++;
|
||||
event.consumed = true;
|
||||
break;
|
||||
}
|
||||
case VirtualKey::Right:
|
||||
{
|
||||
if (style == Style::kHorizontal && newIndex < segments.size () - 1)
|
||||
newIndex++;
|
||||
else if (style == Style::kHorizontalInverse && newIndex > 0)
|
||||
newIndex--;
|
||||
event.consumed = true;
|
||||
break;
|
||||
}
|
||||
case VirtualKey::Up:
|
||||
{
|
||||
if (style == Style::kVertical && newIndex > 0)
|
||||
newIndex--;
|
||||
else if (style == Style::kVerticalInverse && newIndex < segments.size () - 1)
|
||||
newIndex++;
|
||||
event.consumed = true;
|
||||
break;
|
||||
}
|
||||
case VirtualKey::Down:
|
||||
{
|
||||
if (style == Style::kVertical && newIndex < segments.size () - 1)
|
||||
newIndex++;
|
||||
else if (style == Style::kVerticalInverse && newIndex > 0)
|
||||
newIndex--;
|
||||
event.consumed = true;
|
||||
break;
|
||||
}
|
||||
default: return;
|
||||
}
|
||||
if (newIndex != oldIndex)
|
||||
{
|
||||
setSelectedSegment (newIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSegmentButton::draw (CDrawContext* pContext)
|
||||
{
|
||||
CView::draw (pContext);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSegmentButton::drawRect (CDrawContext* pContext, const CRect& dirtyRect)
|
||||
{
|
||||
if (getOldValue () != getValue ())
|
||||
verifySelections ();
|
||||
|
||||
bool isHorizontal = isHorizontalStyle (style);
|
||||
bool drawLines = getFrameWidth () != 0. && getFrameColor ().alpha != 0;
|
||||
auto lineWidth = getFrameWidth ();
|
||||
if (lineWidth < 0.)
|
||||
{
|
||||
lineWidth = pContext->getHairlineSize ();
|
||||
}
|
||||
SharedPointer<CGraphicsPath> path;
|
||||
if (gradient || gradientHighlighted || drawLines)
|
||||
{
|
||||
CRect r (getViewSize ());
|
||||
r.inset (lineWidth / 2., lineWidth / 2.);
|
||||
path = owned (pContext->createGraphicsPath ());
|
||||
if (!path)
|
||||
return;
|
||||
path->addRoundRect (r, getRoundRadius ());
|
||||
}
|
||||
pContext->setDrawMode (kAntiAliasing);
|
||||
if (drawLines)
|
||||
{
|
||||
pContext->setLineStyle (kLineSolid);
|
||||
pContext->setLineWidth (lineWidth);
|
||||
pContext->setFrameColor (getFrameColor ());
|
||||
}
|
||||
if (gradient)
|
||||
{
|
||||
if (isHorizontal)
|
||||
{
|
||||
pContext->fillLinearGradient (path, *gradient, getViewSize ().getTopLeft (),
|
||||
getViewSize ().getBottomLeft ());
|
||||
}
|
||||
else
|
||||
{
|
||||
pContext->fillLinearGradient (path, *gradient, getViewSize ().getTopLeft (),
|
||||
getViewSize ().getTopRight ());
|
||||
}
|
||||
}
|
||||
auto lineIndexStart = 1u;
|
||||
auto lineIndexEnd = segments.size ();
|
||||
if (isInverseStyle (style))
|
||||
{
|
||||
--lineIndexStart;
|
||||
--lineIndexEnd;
|
||||
}
|
||||
|
||||
for (uint32_t index = 0u, end = static_cast<uint32_t> (segments.size ()); index < end; ++index)
|
||||
{
|
||||
const auto& segment = segments[index];
|
||||
if (!dirtyRect.rectOverlap (segment.rect))
|
||||
continue;
|
||||
|
||||
drawClipped (pContext, segment.rect, [&] () {
|
||||
if (segment.selected && gradientHighlighted)
|
||||
{
|
||||
if (isHorizontal)
|
||||
{
|
||||
pContext->fillLinearGradient (path, *gradientHighlighted,
|
||||
segment.rect.getTopLeft (),
|
||||
segment.rect.getBottomLeft ());
|
||||
}
|
||||
else
|
||||
{
|
||||
pContext->fillLinearGradient (path, *gradientHighlighted,
|
||||
segment.rect.getTopLeft (),
|
||||
segment.rect.getTopRight ());
|
||||
}
|
||||
}
|
||||
if (segment.selected && segment.backgroundHighlighted)
|
||||
{
|
||||
segment.backgroundHighlighted->draw (pContext, segment.rect);
|
||||
}
|
||||
else if (segment.background)
|
||||
{
|
||||
segment.background->draw (pContext, segment.rect);
|
||||
}
|
||||
CDrawMethods::drawIconAndText (
|
||||
pContext, segment.selected ? segment.iconHighlighted : segment.icon,
|
||||
segment.iconPosition, textAlignment, textMargin, segment.rect, segment.name, font,
|
||||
segment.selected ? textColorHighlighted : textColor, textTruncateMode);
|
||||
});
|
||||
if (drawLines && index >= lineIndexStart && index < lineIndexEnd)
|
||||
{
|
||||
path->beginSubpath (segment.rect.getTopLeft ());
|
||||
path->addLine (isHorizontal ? segment.rect.getBottomLeft () :
|
||||
segment.rect.getTopRight ());
|
||||
}
|
||||
}
|
||||
if (drawLines)
|
||||
pContext->drawGraphicsPath (path, CDrawContext::kPathStroked);
|
||||
setDirty (false);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
uint32_t CSegmentButton::getSegmentIndex (float value) const
|
||||
{
|
||||
if (value < 0.f || value > 1.f)
|
||||
return kPushBack;
|
||||
|
||||
return std::min<uint32_t> (static_cast<uint32_t> (segments.size () - 1),
|
||||
static_cast<uint32_t> (value * (segments.size ())));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSegmentButton::updateSegmentSizes ()
|
||||
{
|
||||
if (isAttached () && !segments.empty ())
|
||||
{
|
||||
switch (style)
|
||||
{
|
||||
case Style::kHorizontal:
|
||||
{
|
||||
CCoord width = getWidth () / segments.size ();
|
||||
CRect r (getViewSize ());
|
||||
r.setWidth (width);
|
||||
for (auto& segment : segments)
|
||||
{
|
||||
segment.rect = r;
|
||||
r.offset (width, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Style::kHorizontalInverse:
|
||||
{
|
||||
CCoord width = getWidth () / segments.size ();
|
||||
CRect r (getViewSize ());
|
||||
r.setWidth (width);
|
||||
for (auto it = segments.rbegin(); it != segments.rend(); ++it)
|
||||
{
|
||||
(*it).rect = r;
|
||||
r.offset (width, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Style::kVertical:
|
||||
{
|
||||
CCoord height = getHeight () / segments.size ();
|
||||
CRect r (getViewSize ());
|
||||
r.setHeight (height);
|
||||
for (auto& segment : segments)
|
||||
{
|
||||
segment.rect = r;
|
||||
r.offset (0, height);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Style::kVerticalInverse:
|
||||
{
|
||||
CCoord height = getHeight () / segments.size ();
|
||||
CRect r (getViewSize ());
|
||||
r.setHeight (height);
|
||||
for (auto it = segments.rbegin(); it != segments.rend(); ++it)
|
||||
{
|
||||
(*it).rect = r;
|
||||
r.offset (0, height);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSegmentButton::verifySelections ()
|
||||
{
|
||||
if (selectionMode == SelectionMode::kMultiple)
|
||||
{
|
||||
auto bitset = static_cast<uint32_t> (value);
|
||||
for (auto index = 0u; index < segments.size (); ++index)
|
||||
{
|
||||
segments[index].selected = (bitset & (1 << index)) != 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto selectedIndex = getSelectedSegment ();
|
||||
if (selectedIndex > segments.size ())
|
||||
selectedIndex = 0;
|
||||
for (auto& segment : segments)
|
||||
segment.selected = false;
|
||||
segments[selectedIndex].selected = true;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CSegmentButton::drawFocusOnTop ()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CSegmentButton::getFocusPath (CGraphicsPath& outPath)
|
||||
{
|
||||
auto lineWidth = getFrameWidth ();
|
||||
if (lineWidth < 0.)
|
||||
lineWidth = 1.;
|
||||
CRect r (getViewSize ());
|
||||
r.inset (lineWidth / 2., lineWidth / 2.);
|
||||
outPath.addRoundRect (r, getRoundRadius ());
|
||||
CCoord focusWidth = getFrame ()->getFocusWidth ();
|
||||
r.extend (focusWidth, focusWidth);
|
||||
outPath.addRoundRect (r, getRoundRadius ());
|
||||
return true;
|
||||
}
|
||||
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,177 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ccontrol.h"
|
||||
#include "../cdrawmethods.h"
|
||||
#include "../cbitmap.h"
|
||||
#include "../cgradient.h"
|
||||
#include "../cstring.h"
|
||||
#include "../ccolor.h"
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @brief Control which draws a segmented button
|
||||
/// @ingroup new_in_4_3
|
||||
//-----------------------------------------------------------------------------
|
||||
class CSegmentButton : public CControl
|
||||
{
|
||||
public:
|
||||
enum class Style {
|
||||
/** horizontally layouted segments */
|
||||
kHorizontal,
|
||||
/** vertically layouted segments */
|
||||
kVertical,
|
||||
/** horizontally inverse layouted segments */
|
||||
kHorizontalInverse,
|
||||
/** vertically inverse layouted segments */
|
||||
kVerticalInverse,
|
||||
};
|
||||
|
||||
enum class SelectionMode
|
||||
{
|
||||
/** a single segment is selected at any time */
|
||||
kSingle,
|
||||
/** a single segment is selected at any time, when a segment is clicked which is already
|
||||
selected, the next segment is selected */
|
||||
kSingleToggle,
|
||||
/** multiple segments may be selected */
|
||||
kMultiple,
|
||||
};
|
||||
|
||||
struct Segment {
|
||||
mutable UTF8String name;
|
||||
mutable SharedPointer<CBitmap> icon;
|
||||
mutable SharedPointer<CBitmap> iconHighlighted;
|
||||
mutable SharedPointer<CBitmap> background;
|
||||
mutable SharedPointer<CBitmap> backgroundHighlighted;
|
||||
mutable CDrawMethods::IconPosition iconPosition;
|
||||
|
||||
CRect rect;
|
||||
bool selected {false};
|
||||
};
|
||||
using Segments = std::vector<Segment>;
|
||||
static constexpr uint32_t kPushBack = (std::numeric_limits<uint32_t>::max) ();
|
||||
|
||||
CSegmentButton (const CRect& size, IControlListener* listener = nullptr, int32_t tag = -1);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @name Segment Methods
|
||||
//-----------------------------------------------------------------------------
|
||||
//@{
|
||||
bool addSegment (const Segment& segment, uint32_t index = kPushBack);
|
||||
bool addSegment (Segment&& segment, uint32_t index = kPushBack);
|
||||
void removeSegment (uint32_t index);
|
||||
void removeAllSegments ();
|
||||
const Segments& getSegments () const { return segments; }
|
||||
|
||||
/** set the selected segment in single selection mode */
|
||||
void setSelectedSegment (uint32_t index);
|
||||
/** get the selected segment in single selection mode */
|
||||
uint32_t getSelectedSegment () const;
|
||||
|
||||
/** set selection state for a segment in multiple selection mode */
|
||||
void selectSegment (uint32_t index, bool state);
|
||||
/** get selection state for a segment in multiple selection mode */
|
||||
bool isSegmentSelected (uint32_t index) const;
|
||||
//@}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @name CSegmentButton Style Methods
|
||||
//-----------------------------------------------------------------------------
|
||||
//@{
|
||||
void setStyle (Style newStyle);
|
||||
Style getStyle () const { return style; }
|
||||
|
||||
void setSelectionMode (SelectionMode mode);
|
||||
SelectionMode getSelectionMode () const { return selectionMode; }
|
||||
|
||||
void setTextTruncateMode (CDrawMethods::TextTruncateMode mode);
|
||||
CDrawMethods::TextTruncateMode getTextTruncateMode () const { return textTruncateMode; }
|
||||
|
||||
void setGradient (CGradient* newGradient);
|
||||
CGradient* getGradient () const { return gradient; }
|
||||
|
||||
void setGradientHighlighted (CGradient* newGradient);
|
||||
CGradient* getGradientHighlighted () const { return gradientHighlighted; }
|
||||
|
||||
void setRoundRadius (CCoord newRoundRadius);
|
||||
CCoord getRoundRadius () const { return roundRadius; }
|
||||
|
||||
void setFont (CFontRef font);
|
||||
CFontRef getFont () const { return font; }
|
||||
|
||||
void setTextAlignment (CHoriTxtAlign alignment);
|
||||
CHoriTxtAlign getTextAlignment () const { return textAlignment; }
|
||||
|
||||
void setTextMargin (CCoord newMargin);
|
||||
CCoord getTextMargin () const { return textMargin; }
|
||||
|
||||
void setTextColor (CColor newColor);
|
||||
CColor getTextColor () const { return textColor; }
|
||||
|
||||
void setTextColorHighlighted (CColor newColor);
|
||||
CColor getTextColorHighlighted () const { return textColorHighlighted; }
|
||||
|
||||
void setFrameColor (CColor newColor);
|
||||
CColor getFrameColor () const { return frameColor; }
|
||||
|
||||
void setFrameWidth (CCoord newWidth);
|
||||
CCoord getFrameWidth () const { return frameWidth; }
|
||||
//@}
|
||||
|
||||
// overrides
|
||||
bool attached (CView *parent) override;
|
||||
void setViewSize (const CRect& rect, bool invalid = true) override;
|
||||
CMouseEventResult onMouseDown (CPoint& where, const CButtonState& buttons) override;
|
||||
void onKeyboardEvent (KeyboardEvent& event) override;
|
||||
void draw (CDrawContext* pContext) override;
|
||||
void drawRect (CDrawContext* pContext, const CRect& dirtyRect) override;
|
||||
bool drawFocusOnTop () override;
|
||||
bool getFocusPath (CGraphicsPath& outPath) override;
|
||||
void valueChanged () override;
|
||||
|
||||
static bool isHorizontalStyle (Style style)
|
||||
{
|
||||
return style == Style::kHorizontal || style == Style::kHorizontalInverse;
|
||||
}
|
||||
|
||||
static bool isVerticalStyle (Style style)
|
||||
{
|
||||
return style == Style::kVertical || style == Style::kVerticalInverse;
|
||||
}
|
||||
|
||||
static bool isInverseStyle (Style style)
|
||||
{
|
||||
return style == Style::kHorizontalInverse || style == Style::kVerticalInverse;
|
||||
}
|
||||
|
||||
CLASS_METHODS (CSegmentButton, CControl)
|
||||
private:
|
||||
bool canAddOneMoreSegment () const;
|
||||
void updateSegmentSizes ();
|
||||
void verifySelections ();
|
||||
uint32_t getSegmentIndex (float value) const;
|
||||
|
||||
Segments segments;
|
||||
SharedPointer<CGradient> gradient;
|
||||
SharedPointer<CGradient> gradientHighlighted;
|
||||
SharedPointer<CFontDesc> font;
|
||||
CColor textColor {kBlackCColor};
|
||||
CColor textColorHighlighted {kWhiteCColor};
|
||||
CColor frameColor {kBlackCColor};
|
||||
CHoriTxtAlign textAlignment {kCenterText};
|
||||
CCoord textMargin {0.};
|
||||
CCoord roundRadius {5.};
|
||||
CCoord frameWidth {1.};
|
||||
Style style {Style::kHorizontal};
|
||||
SelectionMode selectionMode {SelectionMode::kSingle};
|
||||
CDrawMethods::TextTruncateMode textTruncateMode {CDrawMethods::kTextTruncateNone};
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,197 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../ccolor.h"
|
||||
#include "../enumbitset.h"
|
||||
#include "ccontrol.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
class CSliderBase : public CControl, protected CMouseWheelEditingSupport
|
||||
{
|
||||
public:
|
||||
enum Style : int32_t
|
||||
{
|
||||
kHorizontal,
|
||||
kVertical,
|
||||
kLeft,
|
||||
kRight,
|
||||
kTop,
|
||||
kBottom,
|
||||
};
|
||||
using Styles = EnumBitset<Style>;
|
||||
|
||||
CSliderBase (const CRect& size, IControlListener* listener, int32_t tag);
|
||||
CSliderBase (const CSliderBase& slider);
|
||||
|
||||
void setOffsetHandle (const CPoint& val);
|
||||
CPoint getOffsetHandle () const;
|
||||
|
||||
void setStyle (Styles style);
|
||||
Styles getStyle () const;
|
||||
bool isStyleHorizontal () const;
|
||||
bool isStyleRight () const;
|
||||
bool isStyleBottom () const;
|
||||
bool isInverseStyle () const;
|
||||
|
||||
void setZoomFactor (float val);
|
||||
float getZoomFactor () const;
|
||||
|
||||
void setSliderMode (CSliderMode mode);
|
||||
CSliderMode getSliderMode () const;
|
||||
CSliderMode getEffectiveSliderMode () const;
|
||||
|
||||
static void setGlobalMode (CSliderMode mode);
|
||||
static CSliderMode getGlobalMode ();
|
||||
|
||||
// overrides
|
||||
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 onMouseWheelEvent (MouseWheelEvent& event) override;
|
||||
void onKeyboardEvent (KeyboardEvent& event) override;
|
||||
|
||||
void setViewSize (const CRect& rect, bool invalid) override;
|
||||
|
||||
static bool kAlwaysUseZoomFactor;
|
||||
|
||||
protected:
|
||||
~CSliderBase () noexcept;
|
||||
|
||||
CRect calculateHandleRect (float normValue) const;
|
||||
|
||||
// for sub-classes to access private variables:
|
||||
void setHandleSizePrivate (CCoord width, CCoord height);
|
||||
CPoint getHandleSizePrivate () const;
|
||||
CPoint getControlSizePrivate () const;
|
||||
void setHandleRangePrivate (CCoord range);
|
||||
void setHandleMinPosPrivate (CCoord pos);
|
||||
CCoord getHandleMinPosPrivate () const;
|
||||
|
||||
private:
|
||||
void updateInternalHandleValues ();
|
||||
float calculateDelta (const CPoint& where, CRect* handleRect = nullptr) const;
|
||||
void doRamping ();
|
||||
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> impl;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// CSlider Declaration
|
||||
//! @brief a slider control
|
||||
/// @ingroup controls
|
||||
//------------------------------------------------------------------------
|
||||
class CSlider : public CSliderBase
|
||||
{
|
||||
private:
|
||||
public:
|
||||
CSlider (const CRect& size, IControlListener* listener, int32_t tag, int32_t iMinPos,
|
||||
int32_t iMaxPos, CBitmap* handle, CBitmap* background,
|
||||
const CPoint& offset = CPoint (0, 0), Styles style = {{kLeft, kHorizontal}});
|
||||
CSlider (const CRect& rect, IControlListener* listener, int32_t tag, const CPoint& offsetHandle,
|
||||
int32_t rangeHandle, CBitmap* handle, CBitmap* background,
|
||||
const CPoint& offset = CPoint (0, 0), Styles style = {{kLeft, kHorizontal}});
|
||||
CSlider (const CSlider& slider);
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
/// @name CSlider Methods
|
||||
//------------------------------------------------------------------------
|
||||
//@{
|
||||
VSTGUI_DEPRECATED (
|
||||
/** \deprecated use setBackgroundOffset */
|
||||
virtual void setOffset (const CPoint& val);)
|
||||
VSTGUI_DEPRECATED (
|
||||
/** \deprecated use getBackgroundOffset*/
|
||||
virtual CPoint getOffset () const;)
|
||||
|
||||
/** set background draw offset */
|
||||
void setBackgroundOffset (const CPoint& offset);
|
||||
/** get background draw offset */
|
||||
CPoint getBackgroundOffset () const;
|
||||
|
||||
virtual void setHandle (CBitmap* pHandle);
|
||||
virtual CBitmap* getHandle () const;
|
||||
//@}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
/// @name Draw Style Methods
|
||||
//------------------------------------------------------------------------
|
||||
//@{
|
||||
enum DrawStyle
|
||||
{
|
||||
kDrawFrame = 1 << 0,
|
||||
kDrawBack = 1 << 1,
|
||||
kDrawValue = 1 << 2,
|
||||
kDrawValueFromCenter = 1 << 3,
|
||||
kDrawInverted = 1 << 4
|
||||
};
|
||||
|
||||
virtual void setDrawStyle (int32_t style);
|
||||
virtual void setFrameWidth (CCoord width);
|
||||
virtual void setFrameColor (CColor color);
|
||||
virtual void setBackColor (CColor color);
|
||||
virtual void setValueColor (CColor color);
|
||||
|
||||
int32_t getDrawStyle () const;
|
||||
CCoord getFrameWidth () const;
|
||||
CColor getFrameColor () const;
|
||||
CColor getBackColor () const;
|
||||
CColor getValueColor () const;
|
||||
//@}
|
||||
|
||||
// overrides
|
||||
void draw (CDrawContext*) override;
|
||||
bool sizeToFit () override;
|
||||
|
||||
CLASS_METHODS (CSlider, CControl)
|
||||
protected:
|
||||
~CSlider () noexcept override;
|
||||
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> impl;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// CVerticalSlider Declaration
|
||||
//! @brief a vertical slider control
|
||||
/// @ingroup controls
|
||||
//------------------------------------------------------------------------
|
||||
class CVerticalSlider : public CSlider
|
||||
{
|
||||
public:
|
||||
CVerticalSlider (const CRect& size, IControlListener* listener, int32_t tag, int32_t iMinPos,
|
||||
int32_t iMaxPos, CBitmap* handle, CBitmap* background,
|
||||
const CPoint& offset = CPoint (0, 0), Styles style = kBottom);
|
||||
CVerticalSlider (const CRect& rect, IControlListener* listener, int32_t tag,
|
||||
const CPoint& offsetHandle, int32_t rangeHandle, CBitmap* handle,
|
||||
CBitmap* background, const CPoint& offset = CPoint (0, 0),
|
||||
Styles style = kBottom);
|
||||
CVerticalSlider (const CVerticalSlider& slider) = default;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// CHorizontalSlider Declaration
|
||||
//! @brief a horizontal slider control
|
||||
/// @ingroup controls
|
||||
//------------------------------------------------------------------------
|
||||
class CHorizontalSlider : public CSlider
|
||||
{
|
||||
public:
|
||||
CHorizontalSlider (const CRect& size, IControlListener* listener, int32_t tag, int32_t iMinPos,
|
||||
int32_t iMaxPos, CBitmap* handle, CBitmap* background,
|
||||
const CPoint& offset = CPoint (0, 0), Styles style = kRight);
|
||||
CHorizontalSlider (const CRect& rect, IControlListener* listener, int32_t tag,
|
||||
const CPoint& offsetHandle, int32_t rangeHandle, CBitmap* handle,
|
||||
CBitmap* background, const CPoint& offset = CPoint (0, 0),
|
||||
Styles style = kRight);
|
||||
CHorizontalSlider (const CHorizontalSlider& slider) = default;
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,130 @@
|
||||
// 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 "cspecialdigit.h"
|
||||
#include "../cdrawcontext.h"
|
||||
#include "../cbitmap.h"
|
||||
#include <cmath>
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// CSpecialDigit
|
||||
//------------------------------------------------------------------------
|
||||
/*! @class CSpecialDigit
|
||||
Can be used to display a counter with maximum 7 digits.
|
||||
All digit have the same size and are stacked in height in the bitmap.
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
/**
|
||||
* CSpecialDigit constructor.
|
||||
* @param size the size of this view
|
||||
* @param listener the listener
|
||||
* @param tag the control tag
|
||||
* @param dwPos actual value
|
||||
* @param iNumbers amount of numbers (max 7)
|
||||
* @param xpos array of all X positions, can be NULL
|
||||
* @param ypos array of all Y positions, can be NULL
|
||||
* @param width width of one number in the bitmap
|
||||
* @param height height of one number in the bitmap
|
||||
* @param background bitmap
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
CSpecialDigit::CSpecialDigit (const CRect& size, IControlListener* listener, int32_t tag, int32_t dwPos, int32_t inNumbers, int32_t* xpos, int32_t* ypos, int32_t width, int32_t height, CBitmap* background)
|
||||
: CControl (size, listener, tag, background)
|
||||
, iNumbers (inNumbers)
|
||||
, width (width)
|
||||
, height (height)
|
||||
{
|
||||
setValue ((float)dwPos); // actual value
|
||||
|
||||
if (iNumbers > 7)
|
||||
iNumbers = 7;
|
||||
|
||||
if (xpos == nullptr)
|
||||
{
|
||||
// automatically init xpos/ypos if not provided by caller
|
||||
const int32_t numw = (const int32_t)background->getWidth();
|
||||
int32_t x = (int32_t)size.left;
|
||||
for (int32_t i = 0; i < inNumbers; i++)
|
||||
{
|
||||
this->xpos[i] = x;
|
||||
this->ypos[i] = (int32_t)size.top;
|
||||
x += numw;
|
||||
}
|
||||
}
|
||||
else if (xpos && ypos)
|
||||
{
|
||||
// store coordinates of x/y pos of each digit
|
||||
for (int32_t i = 0; i < inNumbers; i++)
|
||||
{
|
||||
this->xpos[i] = xpos[i];
|
||||
this->ypos[i] = ypos[i];
|
||||
}
|
||||
}
|
||||
|
||||
setMax ((float)pow (10.f, (float)inNumbers) - 1.0f);
|
||||
setMin (0.0f);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CSpecialDigit::CSpecialDigit (const CSpecialDigit& v)
|
||||
: CControl (v)
|
||||
, iNumbers (v.iNumbers)
|
||||
, width (v.width)
|
||||
, height (v.height)
|
||||
{
|
||||
for (int32_t i = 0; i < 7; i++)
|
||||
{
|
||||
xpos[i] = v.xpos[i];
|
||||
ypos[i] = v.ypos[i];
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CSpecialDigit::draw (CDrawContext *pContext)
|
||||
{
|
||||
CPoint where;
|
||||
CRect rectDest;
|
||||
int32_t i, j;
|
||||
int32_t one_digit[16] = {};
|
||||
|
||||
int32_t dwValue = static_cast<int32_t> (getValue ());
|
||||
int32_t intMax = static_cast<int32_t> (getMax ());
|
||||
if (dwValue > intMax)
|
||||
dwValue = intMax;
|
||||
else if (dwValue < static_cast<int32_t> (getMin ()))
|
||||
dwValue = static_cast<int32_t> (getMin ());
|
||||
|
||||
for (i = 0, j = (intMax + 1) / 10; i < iNumbers; i++, j /= 10)
|
||||
{
|
||||
one_digit[i] = dwValue / j;
|
||||
dwValue -= (one_digit[i] * j);
|
||||
}
|
||||
|
||||
where.x = 0;
|
||||
for (i = 0; i < iNumbers; i++)
|
||||
{
|
||||
j = one_digit[i];
|
||||
if (j > 9)
|
||||
j = 9;
|
||||
|
||||
rectDest.left = (CCoord)xpos[i];
|
||||
rectDest.top = (CCoord)ypos[i];
|
||||
|
||||
rectDest.right = rectDest.left + width;
|
||||
rectDest.bottom = rectDest.top + height;
|
||||
|
||||
// where = src from bitmap
|
||||
where.y = (CCoord)j * height;
|
||||
if (getDrawBackground ())
|
||||
{
|
||||
getDrawBackground ()->draw (pContext, rectDest, where);
|
||||
}
|
||||
}
|
||||
|
||||
setDirty (false);
|
||||
}
|
||||
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,34 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ccontrol.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CSpecialDigit Declaration
|
||||
//! @brief special display with custom numbers (0...9)
|
||||
/// @ingroup views
|
||||
//-----------------------------------------------------------------------------
|
||||
class CSpecialDigit : public CControl
|
||||
{
|
||||
public:
|
||||
CSpecialDigit (const CRect& size, IControlListener* listener, int32_t tag, int32_t dwPos, int32_t iNumbers, int32_t* xpos, int32_t* ypos, int32_t width, int32_t height, CBitmap* background);
|
||||
CSpecialDigit (const CSpecialDigit& digit);
|
||||
|
||||
void draw (CDrawContext*) override;
|
||||
|
||||
CLASS_METHODS(CSpecialDigit, CControl)
|
||||
protected:
|
||||
~CSpecialDigit () noexcept override = default;
|
||||
int32_t iNumbers;
|
||||
int32_t xpos[7];
|
||||
int32_t ypos[7];
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,334 @@
|
||||
// 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 "csplashscreen.h"
|
||||
#include "../cdrawcontext.h"
|
||||
#include "../cbitmap.h"
|
||||
#include "../cframe.h"
|
||||
#include "../animation/animations.h"
|
||||
#include "../animation/timingfunctions.h"
|
||||
#include "../events.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
/// @cond ignore
|
||||
//------------------------------------------------------------------------
|
||||
class CDefaultSplashScreenView : public CControl
|
||||
{
|
||||
public:
|
||||
CDefaultSplashScreenView (const CRect& size, IControlListener* listener, CBitmap* bitmap,
|
||||
const CPoint& offset)
|
||||
: CControl (size, listener), offset (offset)
|
||||
{
|
||||
setBackground (bitmap);
|
||||
}
|
||||
|
||||
void draw (CDrawContext *pContext) override
|
||||
{
|
||||
if (getDrawBackground ())
|
||||
getDrawBackground ()->draw (pContext, getViewSize (), offset);
|
||||
setDirty (false);
|
||||
}
|
||||
|
||||
CMouseEventResult onMouseDown (CPoint& where, const CButtonState& buttons) override
|
||||
{
|
||||
if (buttons.isLeftButton ())
|
||||
{
|
||||
valueChanged ();
|
||||
return kMouseDownEventHandledButDontNeedMovedOrUpEvents;
|
||||
}
|
||||
return kMouseEventNotHandled;
|
||||
}
|
||||
CLASS_METHODS(CDefaultSplashScreenView, CControl)
|
||||
protected:
|
||||
CPoint offset;
|
||||
};
|
||||
/// @endcond
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// CSplashScreen
|
||||
//------------------------------------------------------------------------
|
||||
/*! @class CSplashScreen
|
||||
One click on its activated region and its bitmap or view is displayed, in this state the other controls can not be used,
|
||||
and another click on the displayed area will leave the modal mode.
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
/**
|
||||
* CSplashScreen constructor.
|
||||
* @param size the size of this view
|
||||
* @param listener the listener
|
||||
* @param tag the control tag
|
||||
* @param background the bitmap
|
||||
* @param toDisplay the region where to display the bitmap
|
||||
* @param offset offset of background bitmap
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
CSplashScreen::CSplashScreen (const CRect& size, IControlListener* listener, int32_t tag,
|
||||
CBitmap* background, const CRect& toDisplay, const CPoint& offset)
|
||||
: CControl (size, listener, tag, background), toDisplay (toDisplay), offset (offset)
|
||||
{
|
||||
modalView = new CDefaultSplashScreenView (toDisplay, this, background, offset);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
/**
|
||||
* CSplashScreen constructor.
|
||||
* @param size the size of this view
|
||||
* @param listener the listener
|
||||
* @param tag the control tag
|
||||
* @param splashView the view to show
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
CSplashScreen::CSplashScreen (const CRect& size, IControlListener* listener, int32_t tag, CView* splashView)
|
||||
: CControl (size, listener, tag)
|
||||
, modalView (splashView)
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CSplashScreen::CSplashScreen (const CSplashScreen& v)
|
||||
: CControl (v)
|
||||
, toDisplay (v.toDisplay)
|
||||
, keepSize (v.keepSize)
|
||||
, offset (v.offset)
|
||||
{
|
||||
modalView = static_cast<CView*> (v.modalView->newCopy ());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CSplashScreen::~CSplashScreen () noexcept
|
||||
{
|
||||
if (modalView)
|
||||
modalView->forget ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CSplashScreen::draw (CDrawContext *pContext)
|
||||
{
|
||||
setDirty (false);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool CSplashScreen::hitTest (const CPoint& where, const Event& event)
|
||||
{
|
||||
bool result = CView::hitTest (where, event);
|
||||
if (result)
|
||||
{
|
||||
if (auto mouseEvent = asMouseEvent (event))
|
||||
{
|
||||
if (!mouseEvent->buttonState.isLeft ())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMouseEventResult CSplashScreen::onMouseDown (CPoint& where, const CButtonState& buttons)
|
||||
{
|
||||
if (buttons & kLButton)
|
||||
{
|
||||
value = (value == getMax ()) ? getMin () : getMax ();
|
||||
if (value == getMax () && !modalViewSessionID && modalView)
|
||||
{
|
||||
if (auto frame = getFrame ())
|
||||
{
|
||||
if (modalView)
|
||||
{
|
||||
if ((modalViewSessionID = frame->beginModalViewSession (modalView)))
|
||||
{
|
||||
modalView->remember ();
|
||||
CControl::valueChanged ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return kMouseDownEventHandledButDontNeedMovedOrUpEvents;
|
||||
}
|
||||
return kMouseEventNotHandled;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CSplashScreen::valueChanged (CControl *pControl)
|
||||
{
|
||||
if (pControl == modalView)
|
||||
{
|
||||
unSplash ();
|
||||
CControl::valueChanged ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CSplashScreen::unSplash ()
|
||||
{
|
||||
value = getMin ();
|
||||
|
||||
if (auto frame = getFrame ())
|
||||
{
|
||||
if (modalViewSessionID)
|
||||
{
|
||||
if (modalView)
|
||||
modalView->invalid ();
|
||||
frame->endModalViewSession (*modalViewSessionID);
|
||||
modalViewSessionID = {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------
|
||||
CAnimationSplashScreen::CAnimationSplashScreen (const CRect& size, int32_t tag, CBitmap* background, CBitmap* splashBitmap)
|
||||
: CSplashScreen (size, nullptr, tag, splashBitmap, CRect (0, 0, 0, 0))
|
||||
{
|
||||
CView::setBackground (background);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CAnimationSplashScreen::setSplashBitmap (CBitmap* bitmap)
|
||||
{
|
||||
if (modalView)
|
||||
{
|
||||
modalView->setBackground (bitmap);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CBitmap* CAnimationSplashScreen::getSplashBitmap () const
|
||||
{
|
||||
if (modalView)
|
||||
return modalView->getBackground ();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CAnimationSplashScreen::setSplashRect (const CRect& splashRect)
|
||||
{
|
||||
if (modalView)
|
||||
{
|
||||
modalView->setViewSize (splashRect);
|
||||
modalView->setMouseableArea (splashRect);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
const CRect& CAnimationSplashScreen::getSplashRect () const
|
||||
{
|
||||
if (modalView)
|
||||
return modalView->getViewSize ();
|
||||
return getViewSize ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMouseEventResult CAnimationSplashScreen::onMouseDown (CPoint& where, const CButtonState& buttons)
|
||||
{
|
||||
CMouseEventResult result = CSplashScreen::onMouseDown (where, buttons);
|
||||
if (modalView && value == getMax ())
|
||||
{
|
||||
createAnimation (animationIndex, animationTime, modalView, false);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CAnimationSplashScreen::unSplash ()
|
||||
{
|
||||
value = getMin ();
|
||||
|
||||
if (auto frame = getFrame ())
|
||||
{
|
||||
if (frame->getModalView () == modalView)
|
||||
{
|
||||
if (!createAnimation (animationIndex, animationTime, modalView, true))
|
||||
{
|
||||
if (modalView)
|
||||
modalView->invalid ();
|
||||
if (modalViewSessionID)
|
||||
{
|
||||
frame->endModalViewSession (*modalViewSessionID);
|
||||
modalViewSessionID = {};
|
||||
}
|
||||
setMouseEnabled (true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CAnimationSplashScreen::draw (CDrawContext *pContext)
|
||||
{
|
||||
CView::draw (pContext);
|
||||
setDirty (false);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool CAnimationSplashScreen::sizeToFit ()
|
||||
{
|
||||
if (modalView && modalView->getBackground ())
|
||||
{
|
||||
CRect r = modalView->getViewSize ();
|
||||
r.setWidth (modalView->getBackground ()->getWidth ());
|
||||
r.setHeight (modalView->getBackground ()->getHeight ());
|
||||
if (getFrame ())
|
||||
{
|
||||
r.centerInside (getFrame ()->getViewSize ());
|
||||
}
|
||||
modalView->setViewSize (r);
|
||||
modalView->setMouseableArea (r);
|
||||
}
|
||||
if (getBackground ())
|
||||
{
|
||||
CRect r = getViewSize ();
|
||||
r.setWidth (getBackground ()->getWidth ());
|
||||
r.setHeight (getBackground ()->getHeight ());
|
||||
setViewSize (r);
|
||||
setMouseableArea (r);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool CAnimationSplashScreen::createAnimation (uint32_t animIndex, uint32_t animTime,
|
||||
CView* splashView, bool removeViewAnimation)
|
||||
{
|
||||
if (!isAttached ())
|
||||
return false;
|
||||
switch (animIndex)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
if (removeViewAnimation)
|
||||
{
|
||||
splashView->setMouseEnabled (false);
|
||||
splashView->addAnimation (
|
||||
"AnimationSplashScreenAnimation", new Animation::AlphaValueAnimation (0.f),
|
||||
new Animation::PowerTimingFunction (animTime, 2),
|
||||
[this] (CView*, const IdStringPtr, Animation::IAnimationTarget*) {
|
||||
if (modalView)
|
||||
{
|
||||
modalView->invalid ();
|
||||
modalView->setMouseEnabled (true);
|
||||
}
|
||||
if (modalViewSessionID)
|
||||
{
|
||||
if (auto frame = getFrame ())
|
||||
frame->endModalViewSession (*modalViewSessionID);
|
||||
modalViewSessionID = {};
|
||||
}
|
||||
setMouseEnabled (true);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
setMouseEnabled (false);
|
||||
splashView->setAlphaValue (0.f);
|
||||
splashView->addAnimation ("AnimationSplashScreenAnimation", new Animation::AlphaValueAnimation (1.f), new Animation::PowerTimingFunction (animTime, 2));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // 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 "ccontrol.h"
|
||||
#include "icontrollistener.h"
|
||||
#include "../optional.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CSplashScreen Declaration
|
||||
//!
|
||||
/// @ingroup views
|
||||
//-----------------------------------------------------------------------------
|
||||
class CSplashScreen : public CControl, public IControlListener
|
||||
{
|
||||
public:
|
||||
CSplashScreen (const CRect& size, IControlListener* listener, int32_t tag, CBitmap* background, const CRect& toDisplay, const CPoint& offset = CPoint (0, 0));
|
||||
CSplashScreen (const CRect& size, IControlListener* listener, int32_t tag, CView* splashView);
|
||||
CSplashScreen (const CSplashScreen& splashScreen);
|
||||
|
||||
void draw (CDrawContext*) override;
|
||||
bool hitTest (const CPoint& where, const Event& event) override;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @name CSplashScreen Methods
|
||||
//-----------------------------------------------------------------------------
|
||||
//@{
|
||||
virtual void unSplash ();
|
||||
|
||||
/** set the area in which the splash will be displayed */
|
||||
virtual void setDisplayArea (const CRect& rect) { toDisplay = rect; }
|
||||
/** get the area in which the splash will be displayed */
|
||||
virtual CRect& getDisplayArea (CRect& rect) const { rect = toDisplay; return rect; }
|
||||
//@}
|
||||
|
||||
CMouseEventResult onMouseDown (CPoint& where, const CButtonState& buttons) override;
|
||||
|
||||
CLASS_METHODS(CSplashScreen, CControl)
|
||||
protected:
|
||||
~CSplashScreen () noexcept override;
|
||||
using CControl::valueChanged;
|
||||
void valueChanged (CControl *pControl) override;
|
||||
|
||||
CRect toDisplay;
|
||||
CRect keepSize;
|
||||
CPoint offset;
|
||||
CView* modalView{nullptr};
|
||||
Optional<ModalViewSessionID> modalViewSessionID;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CAnimationSplashScreen Declaration
|
||||
/// @brief a splash screen which animates the opening and closing of the splash bitmap
|
||||
/// @ingroup views
|
||||
/// @ingroup new_in_4_0
|
||||
//-----------------------------------------------------------------------------
|
||||
class CAnimationSplashScreen : public CSplashScreen
|
||||
{
|
||||
public:
|
||||
CAnimationSplashScreen (const CRect& size, int32_t tag, CBitmap* background, CBitmap* splashBitmap);
|
||||
CAnimationSplashScreen (const CAnimationSplashScreen& splashScreen) = default;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @name CAnimationSplashScreen Methods
|
||||
//-----------------------------------------------------------------------------
|
||||
//@{
|
||||
virtual void setSplashBitmap (CBitmap* bitmap);
|
||||
CBitmap* getSplashBitmap () const;
|
||||
|
||||
virtual void setSplashRect (const CRect& splashRect);
|
||||
const CRect& getSplashRect () const;
|
||||
|
||||
virtual void setAnimationIndex (uint32_t index) { animationIndex = index; }
|
||||
uint32_t getAnimationIndex () const { return animationIndex; }
|
||||
|
||||
virtual void setAnimationTime (uint32_t time) { animationTime = time; }
|
||||
uint32_t getAnimationTime () const { return animationTime; }
|
||||
|
||||
/** create the animation. subclasses can override this to add special animations */
|
||||
virtual bool createAnimation (uint32_t animationIndex, uint32_t animationTime, CView* splashView, bool removeViewAnimation);
|
||||
//@}
|
||||
|
||||
void unSplash () override;
|
||||
void draw (CDrawContext*) override;
|
||||
CMouseEventResult onMouseDown (CPoint& where, const CButtonState& buttons) override;
|
||||
bool sizeToFit () override;
|
||||
|
||||
protected:
|
||||
~CAnimationSplashScreen () noexcept override = default;
|
||||
|
||||
uint32_t animationIndex{0};
|
||||
uint32_t animationTime{500};
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,222 @@
|
||||
// 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 "cstringlist.h"
|
||||
#include "../cdrawcontext.h"
|
||||
#include "../ccolor.h"
|
||||
#include "../cfont.h"
|
||||
#include "../platform/platformfactory.h"
|
||||
#include "../platform/iplatformstring.h"
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
namespace VSTGUI {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
struct StringListControlDrawer::Impl
|
||||
{
|
||||
Func func;
|
||||
|
||||
SharedPointer<CFontDesc> font {kNormalFont};
|
||||
CColor fontColor {kBlackCColor};
|
||||
CColor fontColorSelected {kWhiteCColor};
|
||||
CColor backColor {kWhiteCColor};
|
||||
CColor backColorSelected {kBlueCColor};
|
||||
CColor hoverColor {MakeCColor (0, 0, 0, 100)};
|
||||
CColor lineColor {kBlackCColor};
|
||||
CCoord lineWidth {1.};
|
||||
CCoord textInset {5.};
|
||||
CHoriTxtAlign textAlign {kLeftText};
|
||||
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
StringListControlDrawer::StringListControlDrawer ()
|
||||
{
|
||||
impl = std::unique_ptr<Impl> (new Impl);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
StringListControlDrawer::~StringListControlDrawer () noexcept = default;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void StringListControlDrawer::setStringProvider (Func&& getStringFunc)
|
||||
{
|
||||
impl->func = std::move (getStringFunc);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void StringListControlDrawer::setStringProvider (const Func& getStringFunc)
|
||||
{
|
||||
impl->func = getStringFunc;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void StringListControlDrawer::setFont (CFontRef f)
|
||||
{
|
||||
impl->font = f;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void StringListControlDrawer::setFontColor (CColor color)
|
||||
{
|
||||
impl->fontColor = color;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void StringListControlDrawer::setSelectedFontColor (CColor color)
|
||||
{
|
||||
impl->fontColorSelected = color;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void StringListControlDrawer::setBackColor (CColor color)
|
||||
{
|
||||
impl->backColor = color;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void StringListControlDrawer::setSelectedBackColor (CColor color)
|
||||
{
|
||||
impl->backColorSelected = color;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void StringListControlDrawer::setHoverColor (CColor color)
|
||||
{
|
||||
impl->hoverColor = color;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void StringListControlDrawer::setLineColor (CColor color)
|
||||
{
|
||||
impl->lineColor = color;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void StringListControlDrawer::setLineWidth (CCoord width)
|
||||
{
|
||||
impl->lineWidth = width;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void StringListControlDrawer::setTextInset (CCoord inset)
|
||||
{
|
||||
impl->textInset = inset;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void StringListControlDrawer::setTextAlign (CHoriTxtAlign align)
|
||||
{
|
||||
impl->textAlign = align;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CFontRef StringListControlDrawer::getFont () const
|
||||
{
|
||||
return impl->font;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CColor StringListControlDrawer::getFontColor () const
|
||||
{
|
||||
return impl->fontColor;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CColor StringListControlDrawer::getSelectedFontColor () const
|
||||
{
|
||||
return impl->fontColorSelected;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CColor StringListControlDrawer::getBackColor () const
|
||||
{
|
||||
return impl->backColor;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CColor StringListControlDrawer::getSelectedBackColor () const
|
||||
{
|
||||
return impl->backColorSelected;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CColor StringListControlDrawer::getHoverColor () const
|
||||
{
|
||||
return impl->hoverColor;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CColor StringListControlDrawer::getLineColor () const
|
||||
{
|
||||
return impl->lineColor;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CCoord StringListControlDrawer::getLineWidth () const
|
||||
{
|
||||
return impl->lineWidth;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CCoord StringListControlDrawer::getTextInset () const
|
||||
{
|
||||
return impl->textInset;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CHoriTxtAlign StringListControlDrawer::getTextAlign () const
|
||||
{
|
||||
return impl->textAlign;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void StringListControlDrawer::drawBackground (CDrawContext* context, CRect size)
|
||||
{
|
||||
context->setFillColor (impl->backColor);
|
||||
context->drawRect (size, kDrawFilled);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void StringListControlDrawer::drawRow (CDrawContext* context, CRect size, Row row)
|
||||
{
|
||||
context->setDrawMode (kAntiAliasing);
|
||||
if (row.isHovered ())
|
||||
{
|
||||
context->setFillColor (impl->hoverColor);
|
||||
context->drawRect (size, kDrawFilled);
|
||||
}
|
||||
if (row.isSelected ())
|
||||
{
|
||||
context->setFillColor (impl->backColorSelected);
|
||||
context->drawRect (size, kDrawFilled);
|
||||
}
|
||||
|
||||
auto lw = impl->lineWidth < 0. ? context->getHairlineSize () : impl->lineWidth;
|
||||
size.bottom -= lw * 0.5;
|
||||
|
||||
if (!(row.isLastRow ()) && lw != 0.)
|
||||
{
|
||||
context->setDrawMode (kAntiAliasing | kNonIntegralMode);
|
||||
context->setFrameColor (impl->lineColor);
|
||||
context->setLineWidth (lw);
|
||||
context->drawLine (size.getBottomLeft (), size.getBottomRight ());
|
||||
}
|
||||
if (auto string = getString (row))
|
||||
{
|
||||
size.inset (impl->textInset, 0);
|
||||
context->setFontColor (row.isSelected () ? impl->fontColorSelected : impl->fontColor);
|
||||
context->setFont (impl->font);
|
||||
context->drawString (string, size, impl->textAlign);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
PlatformStringPtr StringListControlDrawer::getString (int32_t row) const
|
||||
{
|
||||
return impl->func ? impl->func (row) : getPlatformFactory ().createString (toString (row));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,66 @@
|
||||
// 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 "clistcontrol.h"
|
||||
#include "../cdrawdefs.h"
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
namespace VSTGUI {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
/** A specialized list control drawer to draw strings
|
||||
*
|
||||
* You set an instance of this class as the drawer in a CListControl instance and it draws the
|
||||
* strings you setup via the provider function.
|
||||
*
|
||||
* @ingroup new_in_4_9
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
class StringListControlDrawer : public IListControlDrawer, public NonAtomicReferenceCounted
|
||||
{
|
||||
public:
|
||||
using Func = std::function<PlatformStringPtr (int32_t row)>;
|
||||
|
||||
StringListControlDrawer ();
|
||||
~StringListControlDrawer () noexcept override;
|
||||
|
||||
void setStringProvider (Func&& getStringFunc);
|
||||
void setStringProvider (const Func& getStringFunc);
|
||||
|
||||
void setFont (CFontRef f);
|
||||
void setFontColor (CColor color);
|
||||
void setSelectedFontColor (CColor color);
|
||||
void setBackColor (CColor color);
|
||||
void setSelectedBackColor (CColor color);
|
||||
void setHoverColor (CColor color);
|
||||
void setLineColor (CColor color);
|
||||
void setLineWidth (CCoord width);
|
||||
void setTextInset (CCoord inset);
|
||||
void setTextAlign (CHoriTxtAlign align);
|
||||
|
||||
CFontRef getFont () const;
|
||||
CColor getFontColor () const;
|
||||
CColor getSelectedFontColor () const;
|
||||
CColor getBackColor () const;
|
||||
CColor getSelectedBackColor () const;
|
||||
CColor getHoverColor () const;
|
||||
CColor getLineColor () const;
|
||||
CCoord getLineWidth () const;
|
||||
CCoord getTextInset () const;
|
||||
CHoriTxtAlign getTextAlign () const;
|
||||
|
||||
void drawBackground (CDrawContext* context, CRect size) override;
|
||||
void drawRow (CDrawContext* context, CRect size, Row row) override;
|
||||
|
||||
private:
|
||||
PlatformStringPtr getString (int32_t row) const;
|
||||
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> impl;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,770 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#include "cswitch.h"
|
||||
#include "../cdrawcontext.h"
|
||||
#include "../cbitmap.h"
|
||||
#include "../cvstguitimer.h"
|
||||
#include "../events.h"
|
||||
#include "../algorithm.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
bool CSwitchBase::useLegacyIndexCalculation = false;
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CSwitchBase::CSwitchBase (const CRect& size, IControlListener* listener, int32_t tag,
|
||||
CBitmap* background)
|
||||
: CControl (size, listener, tag, background)
|
||||
{
|
||||
setDefaultValue (0.f);
|
||||
setWantsFocus (true);
|
||||
}
|
||||
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
//------------------------------------------------------------------------
|
||||
CSwitchBase::CSwitchBase (const CRect& size, IControlListener* listener, int32_t tag,
|
||||
int32_t subPixmaps, CCoord heightOfOneImage, int32_t iMaxPositions,
|
||||
CBitmap* background, const CPoint& offset)
|
||||
: CControl (size, listener, tag, background), offset (offset)
|
||||
{
|
||||
setNumSubPixmaps (subPixmaps);
|
||||
setHeightOfOneImage (heightOfOneImage);
|
||||
setDefaultValue (0.f);
|
||||
setWantsFocus (true);
|
||||
}
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CSwitchBase::CSwitchBase (const CSwitchBase& other) : CControl (other)
|
||||
{
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
offset = other.offset;
|
||||
setNumSubPixmaps (other.subPixmaps);
|
||||
setHeightOfOneImage (other.heightOfOneImage);
|
||||
#endif
|
||||
setWantsFocus (true);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
int32_t CSwitchBase::normalizedToIndex (float norm) const
|
||||
{
|
||||
if (auto mfb = dynamic_cast<CMultiFrameBitmap*> (getDrawBackground ()))
|
||||
{
|
||||
return getMultiFrameBitmapIndex (*mfb, norm);
|
||||
}
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
#include "../private/disabledeprecatedmessage.h"
|
||||
if (useLegacyIndexCalculation)
|
||||
#include "../private/enabledeprecatedmessage.h"
|
||||
return static_cast<int32_t> (norm * (getNumSubPixmaps () - 1) + 0.5f);
|
||||
return normalizedToSteps (norm, getNumSubPixmaps () - 1);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
float CSwitchBase::indexToNormalized (int32_t index) const
|
||||
{
|
||||
if (auto mfb = dynamic_cast<CMultiFrameBitmap*> (getDrawBackground ()))
|
||||
{
|
||||
return getNormValueFromMultiFrameBitmapIndex (*mfb, static_cast<uint16_t> (index));
|
||||
}
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
return static_cast<float> (index) / static_cast<float> (getNumSubPixmaps () - 1);
|
||||
#else
|
||||
return 0.f;
|
||||
#endif
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CSwitchBase::draw (CDrawContext* pContext)
|
||||
{
|
||||
if (auto bitmap = getDrawBackground ())
|
||||
{
|
||||
float norm = getValueNormalized ();
|
||||
if (auto mfb = dynamic_cast<CMultiFrameBitmap*> (bitmap))
|
||||
{
|
||||
auto frameIndex = getMultiFrameBitmapIndex (*mfb, norm);
|
||||
if (inverseBitmap)
|
||||
frameIndex = getInverseIndex (*mfb, frameIndex);
|
||||
mfb->drawFrame (pContext, frameIndex, getViewSize ().getTopLeft ());
|
||||
}
|
||||
else
|
||||
{
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
if (inverseBitmap)
|
||||
norm = 1.f - norm;
|
||||
// source position in bitmap
|
||||
CPoint where (0, heightOfOneImage * normalizedToIndex (norm));
|
||||
bitmap->draw (pContext, getViewSize (), where);
|
||||
#else
|
||||
bitmap->draw (pContext, getViewSize ());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
setDirty (false);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool CSwitchBase::sizeToFit ()
|
||||
{
|
||||
if (auto bitmap = getDrawBackground ())
|
||||
{
|
||||
CRect vs (getViewSize ());
|
||||
if (auto mfb = dynamic_cast<CMultiFrameBitmap*> (bitmap))
|
||||
{
|
||||
vs.setSize (mfb->getFrameSize ());
|
||||
}
|
||||
else
|
||||
{
|
||||
vs.setWidth (bitmap->getWidth ());
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
vs.setHeight (getHeightOfOneImage ());
|
||||
#else
|
||||
vs.setHeight (bitmap->getHeight ());
|
||||
#endif
|
||||
}
|
||||
setViewSize (vs);
|
||||
setMouseableArea (vs);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMouseEventResult CSwitchBase::onMouseDown (CPoint& where, const CButtonState& buttons)
|
||||
{
|
||||
if (!(buttons & kLButton))
|
||||
return kMouseEventNotHandled;
|
||||
|
||||
coef = calculateCoef ();
|
||||
|
||||
beginEdit ();
|
||||
|
||||
mouseStartValue = getValue ();
|
||||
return onMouseMoved (where, buttons);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMouseEventResult CSwitchBase::onMouseUp (CPoint& where, const CButtonState& buttons)
|
||||
{
|
||||
if (isEditing ())
|
||||
endEdit ();
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMouseEventResult CSwitchBase::onMouseCancel ()
|
||||
{
|
||||
if (isEditing ())
|
||||
{
|
||||
value = mouseStartValue;
|
||||
if (isDirty ())
|
||||
{
|
||||
valueChanged ();
|
||||
invalid ();
|
||||
}
|
||||
endEdit ();
|
||||
}
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMouseEventResult CSwitchBase::onMouseMoved (CPoint& where, const CButtonState& buttons)
|
||||
{
|
||||
if (isEditing ())
|
||||
{
|
||||
float norm = calcNormFromPoint (where);
|
||||
if (inverseBitmap)
|
||||
norm = 1.f - norm;
|
||||
value = getMin () + norm * (getMax () - getMin ());
|
||||
bounceValue ();
|
||||
|
||||
if (isDirty ())
|
||||
{
|
||||
valueChanged ();
|
||||
invalid ();
|
||||
}
|
||||
}
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CSwitchBase::setInverseBitmap (bool state)
|
||||
{
|
||||
if (inverseBitmap != state)
|
||||
{
|
||||
inverseBitmap = state;
|
||||
invalid ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// CVerticalSwitch
|
||||
//------------------------------------------------------------------------
|
||||
/*! @class CVerticalSwitch
|
||||
Define a switch with a given number of positions, the current position is defined by the position
|
||||
of the last click on this object (the object is divided in its height by the number of position).
|
||||
Each position has its subbitmap, each subbitmap is stacked in the given handle bitmap.
|
||||
By clicking Alt+Left Mouse the default value is used.
|
||||
Use a CMultiFrameBitmap for its background bitmap.
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
/**
|
||||
* CVerticalSwitch constructor.
|
||||
* @param size the size of this view
|
||||
* @param listener the listener
|
||||
* @param tag the control tag
|
||||
* @param background the switch bitmap
|
||||
* @param offset unused
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
CVerticalSwitch::CVerticalSwitch (const CRect& size, IControlListener* listener, int32_t tag,
|
||||
CBitmap* background)
|
||||
: CSwitchBase (size, listener, tag, background)
|
||||
{
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
heightOfOneImage = size.getHeight ();
|
||||
setNumSubPixmaps (
|
||||
background ? static_cast<int32_t> (background->getHeight () / heightOfOneImage) : 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
//------------------------------------------------------------------------
|
||||
/**
|
||||
* CVerticalSwitch 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 iMaxPositions TODO
|
||||
* @param background the switch bitmap
|
||||
* @param offset unused
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
CVerticalSwitch::CVerticalSwitch (const CRect& size, IControlListener* listener, int32_t tag,
|
||||
int32_t subPixmaps, CCoord heightOfOneImage,
|
||||
int32_t iMaxPositions, CBitmap* background, const CPoint& offset)
|
||||
: CSwitchBase (size, listener, tag, subPixmaps, heightOfOneImage, iMaxPositions, background, offset)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CVerticalSwitch::CVerticalSwitch (const CVerticalSwitch& v)
|
||||
: CSwitchBase (v)
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
double CVerticalSwitch::calculateCoef () const
|
||||
{
|
||||
if (auto mfb = dynamic_cast<CMultiFrameBitmap*> (getDrawBackground ()))
|
||||
{
|
||||
return mfb->getFrameSize ().y / static_cast<double> (getMultiFrameBitmapRangeLength (*mfb));
|
||||
}
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
return static_cast<double> (heightOfOneImage) / static_cast<double> (getNumSubPixmaps ());
|
||||
#else
|
||||
return 1.;
|
||||
#endif
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
float CVerticalSwitch::calcNormFromPoint (const CPoint& where) const
|
||||
{
|
||||
if (auto mfb = dynamic_cast<CMultiFrameBitmap*> (getDrawBackground ()))
|
||||
{
|
||||
return static_cast<int32_t> ((where.y - getViewSize ().top) / getCoef ()) /
|
||||
static_cast<float> (getMultiFrameBitmapRangeLength (*mfb) - 1);
|
||||
}
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
return static_cast<int32_t> ((where.y - getViewSize ().top) / getCoef ()) /
|
||||
static_cast<float> (getNumSubPixmaps () - 1);
|
||||
#else
|
||||
return 0.f;
|
||||
#endif
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CVerticalSwitch::onKeyboardEvent (KeyboardEvent& event)
|
||||
{
|
||||
if (event.type != EventType::KeyDown || event.modifiers.empty () == false)
|
||||
return;
|
||||
float norm = getValueNormalized ();
|
||||
int32_t currentIndex = normalizedToIndex (norm);
|
||||
if (event.virt == VirtualKey::Up && currentIndex > 0)
|
||||
{
|
||||
--currentIndex;
|
||||
norm = indexToNormalized (currentIndex);
|
||||
value = (getMax () - getMin ()) * norm + getMin ();
|
||||
bounceValue ();
|
||||
}
|
||||
if (event.virt == VirtualKey::Down && norm < 1.f)
|
||||
{
|
||||
++currentIndex;
|
||||
norm = indexToNormalized (currentIndex);
|
||||
value = (getMax () - getMin ()) * norm + getMin ();
|
||||
bounceValue ();
|
||||
}
|
||||
if (isDirty ())
|
||||
{
|
||||
invalid ();
|
||||
beginEdit ();
|
||||
valueChanged ();
|
||||
endEdit ();
|
||||
event.consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// CHorizontalSwitch
|
||||
//------------------------------------------------------------------------
|
||||
/*! @class CHorizontalSwitch
|
||||
Same as the CVerticalSwitch but horizontal.
|
||||
Use a CMultiFrameBitmap for its background bitmap.
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
/**
|
||||
* CHorizontalSwitch constructor.
|
||||
* @param size the size of this view
|
||||
* @param listener the listener
|
||||
* @param tag the control tag
|
||||
* @param background the bitmap of the switch
|
||||
* @param offset unused
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
CHorizontalSwitch::CHorizontalSwitch (const CRect& size, IControlListener* listener, int32_t tag,
|
||||
CBitmap* background)
|
||||
: CSwitchBase (size, listener, tag, background)
|
||||
{
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
heightOfOneImage = size.getWidth ();
|
||||
setNumSubPixmaps (background ? (int32_t) (background->getWidth () / heightOfOneImage) : 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
//------------------------------------------------------------------------
|
||||
/**
|
||||
* CHorizontalSwitch 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 iMaxPositions ignored
|
||||
* @param background the switch bitmap
|
||||
* @param offset unused
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
CHorizontalSwitch::CHorizontalSwitch (const CRect& size, IControlListener* listener, int32_t tag,
|
||||
int32_t subPixmaps, CCoord heightOfOneImage,
|
||||
int32_t iMaxPositions, CBitmap* background,
|
||||
const CPoint& offset)
|
||||
: CSwitchBase (size, listener, tag, subPixmaps, heightOfOneImage, iMaxPositions, background, offset)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CHorizontalSwitch::CHorizontalSwitch (const CHorizontalSwitch& v)
|
||||
: CSwitchBase (v)
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
double CHorizontalSwitch::calculateCoef () const
|
||||
{
|
||||
if (auto mfb = dynamic_cast<CMultiFrameBitmap*> (getDrawBackground ()))
|
||||
{
|
||||
return mfb->getFrameSize ().x / static_cast<double> (getMultiFrameBitmapRangeLength (*mfb));
|
||||
}
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
return getDrawBackground ()->getWidth () / static_cast<double> (getNumSubPixmaps ());
|
||||
#else
|
||||
return 1.;
|
||||
#endif
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
float CHorizontalSwitch::calcNormFromPoint (const CPoint& where) const
|
||||
{
|
||||
if (auto mfb = dynamic_cast<CMultiFrameBitmap*> (getDrawBackground ()))
|
||||
{
|
||||
return static_cast<int32_t> ((where.x - getViewSize ().left) / getCoef ()) /
|
||||
static_cast<float> (getMultiFrameBitmapRangeLength (*mfb) - 1);
|
||||
}
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
return static_cast<int32_t> ((where.x - getViewSize ().left) / getCoef ()) /
|
||||
static_cast<float> (getNumSubPixmaps () - 1);
|
||||
#else
|
||||
return 0.f;
|
||||
#endif
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CHorizontalSwitch::onKeyboardEvent(KeyboardEvent &event)
|
||||
{
|
||||
if (event.type != EventType::KeyDown || event.modifiers.empty () == false)
|
||||
return;
|
||||
float norm = getValueNormalized ();
|
||||
int32_t currentIndex = normalizedToIndex (norm);
|
||||
if (event.virt == VirtualKey::Left && currentIndex > 0)
|
||||
{
|
||||
--currentIndex;
|
||||
norm = indexToNormalized (currentIndex);
|
||||
value = (getMax () - getMin ()) * norm + getMin ();
|
||||
bounceValue ();
|
||||
}
|
||||
if (event.virt == VirtualKey::Right && norm < 1.f)
|
||||
{
|
||||
++currentIndex;
|
||||
norm = indexToNormalized (currentIndex);
|
||||
value = (getMax () - getMin ()) * norm + getMin ();
|
||||
bounceValue ();
|
||||
}
|
||||
if (isDirty ())
|
||||
{
|
||||
invalid ();
|
||||
beginEdit ();
|
||||
valueChanged ();
|
||||
endEdit ();
|
||||
event.consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// CRockerSwitch
|
||||
//------------------------------------------------------------------------
|
||||
/*! @class CRockerSwitch
|
||||
Define a rocker switch with 3 states using 3 subbitmaps.
|
||||
One click on its leftside, then the first subbitmap is displayed.
|
||||
One click on its rightside, then the third subbitmap is displayed.
|
||||
When the mouse button is relaxed, the second subbitmap is framed. */
|
||||
//------------------------------------------------------------------------
|
||||
/**
|
||||
* CRockerSwitch constructor.
|
||||
* @param size the size of this view
|
||||
* @param listener the listener
|
||||
* @param tag the control tag
|
||||
* @param background bitmap with 3 stacked images of the rocker switch
|
||||
* @param style
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
CRockerSwitch::CRockerSwitch (const CRect& size, IControlListener* listener, int32_t tag,
|
||||
CBitmap* background, const int32_t style)
|
||||
: CControl (size, listener, tag, background), style (style), resetValueTimer (nullptr)
|
||||
{
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
setNumSubPixmaps (3);
|
||||
setHeightOfOneImage (size.getHeight ());
|
||||
#endif
|
||||
setWantsFocus (true);
|
||||
setMin (-1.f);
|
||||
setMax (1.f);
|
||||
setValue ((getMax () - getMin ()) / 2.f + getMin ());
|
||||
}
|
||||
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
//------------------------------------------------------------------------
|
||||
/**
|
||||
* CRockerSwitch constructor.
|
||||
* @param size the size of this view
|
||||
* @param listener the listener
|
||||
* @param tag the control tag
|
||||
* @param background bitmap with 3 stacked images of the rocker switch
|
||||
* @param offset
|
||||
* @param style
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
CRockerSwitch::CRockerSwitch (const CRect& size, IControlListener* listener, int32_t tag, CBitmap* background, const CPoint &offset, const int32_t style)
|
||||
: CControl (size, listener, tag, background)
|
||||
, offset (offset)
|
||||
, style (style)
|
||||
, resetValueTimer (nullptr)
|
||||
{
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
setNumSubPixmaps (3);
|
||||
setHeightOfOneImage (size.getHeight ());
|
||||
#endif
|
||||
setWantsFocus (true);
|
||||
setMin (-1.f);
|
||||
setMax (1.f);
|
||||
setValue ((getMax () - getMin ()) / 2.f + getMin ());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
/**
|
||||
* CRockerSwitch constructor.
|
||||
* @param size the size of this view
|
||||
* @param listener the listener
|
||||
* @param tag the control tag
|
||||
* @param heightOfOneImage height of one image in pixel
|
||||
* @param background bitmap with 3 stacked images of the rocker switch
|
||||
* @param offset
|
||||
* @param style
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
CRockerSwitch::CRockerSwitch (const CRect& size, IControlListener* listener, int32_t tag, CCoord heightOfOneImage, CBitmap* background, const CPoint &offset, const int32_t style)
|
||||
: CControl (size, listener, tag, background)
|
||||
, offset (offset)
|
||||
, style (style)
|
||||
, resetValueTimer (nullptr)
|
||||
{
|
||||
setNumSubPixmaps (3);
|
||||
setHeightOfOneImage (heightOfOneImage);
|
||||
setWantsFocus (true);
|
||||
setMin (-1.f);
|
||||
setMax (1.f);
|
||||
setValue ((getMax () - getMin ()) / 2.f + getMin ());
|
||||
}
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CRockerSwitch::CRockerSwitch (const CRockerSwitch& v)
|
||||
: CControl (v), style (v.style), resetValueTimer (nullptr)
|
||||
{
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
offset = v.offset;
|
||||
setHeightOfOneImage (v.heightOfOneImage);
|
||||
#endif
|
||||
setWantsFocus (true);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CRockerSwitch::~CRockerSwitch () noexcept
|
||||
{
|
||||
if (resetValueTimer)
|
||||
resetValueTimer->forget ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CRockerSwitch::draw (CDrawContext *pContext)
|
||||
{
|
||||
if (auto bitmap = getDrawBackground ())
|
||||
{
|
||||
if (auto mfb = dynamic_cast<CMultiFrameBitmap*> (bitmap))
|
||||
{
|
||||
uint16_t frameIndex = getMultiFrameBitmapIndex (*mfb, getValueNormalized ());
|
||||
mfb->drawFrame (pContext, frameIndex, getViewSize ().getTopLeft ());
|
||||
}
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
CPoint where (offset.x, offset.y);
|
||||
|
||||
if (value == getMax ())
|
||||
where.y += 2 * heightOfOneImage;
|
||||
else if (value == (getMax () - getMin ()) / 2.f + getMin ())
|
||||
where.y += heightOfOneImage;
|
||||
|
||||
bitmap->draw (pContext, getViewSize (), where);
|
||||
#else
|
||||
bitmap->draw (pContext, getViewSize ());
|
||||
#endif
|
||||
}
|
||||
setDirty (false);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMouseEventResult CRockerSwitch::onMouseDown (CPoint& where, const CButtonState& buttons)
|
||||
{
|
||||
if (!(buttons & kLButton))
|
||||
return kMouseEventNotHandled;
|
||||
mouseStartValue = value;
|
||||
beginEdit ();
|
||||
return onMouseMoved (where, buttons);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMouseEventResult CRockerSwitch::onMouseUp (CPoint& where, const CButtonState& buttons)
|
||||
{
|
||||
if (isEditing ())
|
||||
{
|
||||
value = (getMax () - getMin ()) / 2.f + getMin ();
|
||||
if (isDirty ())
|
||||
invalid ();
|
||||
endEdit ();
|
||||
}
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMouseEventResult CRockerSwitch::onMouseCancel ()
|
||||
{
|
||||
if (isEditing ())
|
||||
{
|
||||
value = mouseStartValue;
|
||||
if (isDirty ())
|
||||
{
|
||||
valueChanged ();
|
||||
invalid ();
|
||||
}
|
||||
endEdit ();
|
||||
}
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMouseEventResult CRockerSwitch::onMouseMoved (CPoint& where, const CButtonState& buttons)
|
||||
{
|
||||
if (isEditing ())
|
||||
{
|
||||
CCoord width_2 = getViewSize ().getWidth () / 2;
|
||||
CCoord height_2 = getViewSize ().getHeight () / 2;
|
||||
|
||||
if (style & kHorizontal)
|
||||
{
|
||||
if (where.x >= getViewSize ().left && where.y >= getViewSize ().top &&
|
||||
where.x <= (getViewSize ().left + width_2) && where.y <= getViewSize ().bottom)
|
||||
value = getMin ();
|
||||
else if (where.x >= (getViewSize ().left + width_2) && where.y >= getViewSize ().top &&
|
||||
where.x <= getViewSize ().right && where.y <= getViewSize ().bottom)
|
||||
value = getMax ();
|
||||
else
|
||||
value = mouseStartValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (where.x >= getViewSize ().left && where.y >= getViewSize ().top &&
|
||||
where.x <= getViewSize ().right && where.y <= (getViewSize ().top + height_2))
|
||||
value = getMin ();
|
||||
else if (where.x >= getViewSize ().left && where.y >= (getViewSize ().top + height_2) &&
|
||||
where.x <= getViewSize ().right && where.y <= getViewSize ().bottom)
|
||||
value = getMax ();
|
||||
else
|
||||
value = mouseStartValue;
|
||||
}
|
||||
|
||||
if (isDirty ())
|
||||
{
|
||||
valueChanged ();
|
||||
invalid ();
|
||||
}
|
||||
}
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CRockerSwitch::onKeyboardEvent (KeyboardEvent& event)
|
||||
{
|
||||
if (event.modifiers.empty () == false)
|
||||
return;
|
||||
if (event.type == EventType::KeyDown)
|
||||
{
|
||||
if (style & kHorizontal &&
|
||||
(event.virt == VirtualKey::Left || event.virt == VirtualKey::Right))
|
||||
{
|
||||
value = event.virt == VirtualKey::Left ? getMin () : getMax ();
|
||||
invalid ();
|
||||
beginEdit ();
|
||||
valueChanged ();
|
||||
event.consumed = true;
|
||||
}
|
||||
if (style & kVertical && (event.virt == VirtualKey::Up || event.virt == VirtualKey::Down))
|
||||
{
|
||||
value = event.virt == VirtualKey::Up ? getMin () : getMax ();
|
||||
invalid ();
|
||||
beginEdit ();
|
||||
valueChanged ();
|
||||
event.consumed = true;
|
||||
}
|
||||
}
|
||||
else if (event.type == EventType::KeyUp)
|
||||
{
|
||||
if ((style & kHorizontal &&
|
||||
(event.virt == VirtualKey::Left || event.virt == VirtualKey::Right)) ||
|
||||
(style & kVertical && (event.virt == VirtualKey::Up || event.virt == VirtualKey::Down)))
|
||||
{
|
||||
value = (getMax () - getMin ()) / 2.f + getMin ();
|
||||
invalid ();
|
||||
valueChanged ();
|
||||
endEdit ();
|
||||
event.consumed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CRockerSwitch::onMouseWheelEvent (MouseWheelEvent& event)
|
||||
{
|
||||
auto distance = event.deltaY;
|
||||
if (distance == 0.)
|
||||
return;
|
||||
|
||||
if (distance > 0)
|
||||
value = getMin ();
|
||||
else
|
||||
value = getMax ();
|
||||
|
||||
if (isDirty ())
|
||||
{
|
||||
invalid ();
|
||||
if (!isEditing ())
|
||||
beginEdit ();
|
||||
valueChanged ();
|
||||
}
|
||||
|
||||
if (resetValueTimer == nullptr)
|
||||
resetValueTimer = new CVSTGUITimer (this, 200);
|
||||
resetValueTimer->stop ();
|
||||
resetValueTimer->start ();
|
||||
|
||||
event.consumed = true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMessageResult CRockerSwitch::notify (CBaseObject* sender, IdStringPtr message)
|
||||
{
|
||||
if (sender == resetValueTimer)
|
||||
{
|
||||
float newValue = (getMax () - getMin ()) / 2.f + getMin ();
|
||||
if (value != newValue)
|
||||
{
|
||||
value = newValue;
|
||||
if (!isEditing ())
|
||||
beginEdit ();
|
||||
valueChanged ();
|
||||
endEdit ();
|
||||
setDirty (true);
|
||||
}
|
||||
resetValueTimer->forget ();
|
||||
resetValueTimer = nullptr;
|
||||
return kMessageNotified;
|
||||
}
|
||||
return CControl::notify (sender, message);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool CRockerSwitch::sizeToFit ()
|
||||
{
|
||||
if (auto bitmap = getDrawBackground ())
|
||||
{
|
||||
CRect vs (getViewSize ());
|
||||
if (auto mfb = dynamic_cast<CMultiFrameBitmap*> (bitmap))
|
||||
{
|
||||
vs.setSize (mfb->getFrameSize ());
|
||||
}
|
||||
else
|
||||
{
|
||||
vs.setWidth (bitmap->getWidth ());
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
vs.setHeight (getHeightOfOneImage ());
|
||||
#else
|
||||
vs.setHeight (bitmap->getHeight ());
|
||||
#endif
|
||||
}
|
||||
setViewSize (vs);
|
||||
setMouseableArea (vs);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,190 @@
|
||||
// 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 <algorithm>
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
class CSwitchBase : public CControl,
|
||||
public MultiFrameBitmapView<CSwitchBase>
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
,
|
||||
public IMultiBitmapControl
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
void setInverseBitmap (bool state);
|
||||
bool getInverseBitmap () const { return inverseBitmap; }
|
||||
|
||||
protected:
|
||||
CSwitchBase (const CRect& size, IControlListener* listener, int32_t tag, CBitmap* background);
|
||||
CSwitchBase (const CSwitchBase& other);
|
||||
~CSwitchBase () noexcept override = default;
|
||||
|
||||
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;
|
||||
bool sizeToFit () override;
|
||||
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
CSwitchBase (const CRect& size, IControlListener* listener, int32_t tag, int32_t subPixmaps,
|
||||
CCoord heightOfOneImage, int32_t iMaxPositions, CBitmap* background,
|
||||
const CPoint& offset = CPoint (0, 0));
|
||||
void setNumSubPixmaps (int32_t numSubPixmaps) override
|
||||
{
|
||||
IMultiBitmapControl::setNumSubPixmaps (numSubPixmaps);
|
||||
invalid ();
|
||||
}
|
||||
const CPoint& getOffset () const { return offset; }
|
||||
#endif
|
||||
|
||||
double getCoef () const { return coef; }
|
||||
int32_t normalizedToIndex (float norm) const;
|
||||
float indexToNormalized (int32_t index) const;
|
||||
|
||||
virtual double calculateCoef () const = 0;
|
||||
virtual float calcNormFromPoint (const CPoint& where) const = 0;
|
||||
|
||||
VSTGUI_DEPRECATED_MSG (static bool useLegacyIndexCalculation;
|
||||
, "Use CMultiFrameBitmap::normalizedValueToFrameIndex() instead")
|
||||
|
||||
private:
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
CPoint offset {};
|
||||
#endif
|
||||
double coef;
|
||||
float mouseStartValue;
|
||||
bool inverseBitmap{false};
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CVerticalSwitch Declaration
|
||||
//! @brief a vertical switch control
|
||||
/// @ingroup controls uses_multi_frame_bitmaps
|
||||
//-----------------------------------------------------------------------------
|
||||
class CVerticalSwitch : public CSwitchBase
|
||||
{
|
||||
public:
|
||||
CVerticalSwitch (const CRect& size, IControlListener* listener, int32_t tag,
|
||||
CBitmap* background);
|
||||
CVerticalSwitch (const CVerticalSwitch& vswitch);
|
||||
|
||||
void onKeyboardEvent (KeyboardEvent& event) override;
|
||||
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
CVerticalSwitch (const CRect& size, IControlListener* listener, int32_t tag, int32_t subPixmaps,
|
||||
CCoord heightOfOneImage, int32_t iMaxPositions, CBitmap* background,
|
||||
const CPoint& offset = CPoint (0, 0));
|
||||
#endif
|
||||
|
||||
CLASS_METHODS(CVerticalSwitch, CControl)
|
||||
protected:
|
||||
~CVerticalSwitch () noexcept override = default;
|
||||
|
||||
double calculateCoef () const override;
|
||||
float calcNormFromPoint (const CPoint& where) const override;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CHorizontalSwitch Declaration
|
||||
//! @brief a horizontal switch control
|
||||
/// @ingroup controls uses_multi_frame_bitmaps
|
||||
//-----------------------------------------------------------------------------
|
||||
class CHorizontalSwitch : public CSwitchBase
|
||||
{
|
||||
public:
|
||||
CHorizontalSwitch (const CRect& size, IControlListener* listener, int32_t tag,
|
||||
CBitmap* background);
|
||||
CHorizontalSwitch (const CHorizontalSwitch& hswitch);
|
||||
|
||||
void onKeyboardEvent (KeyboardEvent& event) override;
|
||||
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
CHorizontalSwitch (const CRect& size, IControlListener* listener, int32_t tag,
|
||||
int32_t subPixmaps, CCoord heightOfOneImage, int32_t iMaxPositions,
|
||||
CBitmap* background, const CPoint& offset = CPoint (0, 0));
|
||||
#endif
|
||||
|
||||
CLASS_METHODS(CHorizontalSwitch, CControl)
|
||||
protected:
|
||||
~CHorizontalSwitch () noexcept override = default;
|
||||
|
||||
double calculateCoef () const override;
|
||||
float calcNormFromPoint (const CPoint& where) const override;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CRockerSwitch Declaration
|
||||
//! @brief a switch control with 3 sub bitmaps
|
||||
/// @ingroup controls use_multi_frame_bitmaps
|
||||
//-----------------------------------------------------------------------------
|
||||
class CRockerSwitch : public CControl,
|
||||
public MultiFrameBitmapView<CRockerSwitch>
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
,
|
||||
public IMultiBitmapControl
|
||||
#endif
|
||||
{
|
||||
private:
|
||||
enum StyleEnum
|
||||
{
|
||||
StyleHorizontal = 0,
|
||||
StyleVertical,
|
||||
};
|
||||
public:
|
||||
enum Style
|
||||
{
|
||||
kHorizontal = 1 << StyleHorizontal,
|
||||
kVertical = 1 << StyleVertical,
|
||||
};
|
||||
|
||||
CRockerSwitch (const CRect& size, IControlListener* listener, int32_t tag, CBitmap* background,
|
||||
const int32_t style = kHorizontal);
|
||||
CRockerSwitch (const CRockerSwitch& rswitch);
|
||||
|
||||
void draw (CDrawContext*) override;
|
||||
void onMouseWheelEvent (MouseWheelEvent& event) 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
|
||||
CRockerSwitch (const CRect& size, IControlListener* listener, int32_t tag, CBitmap* background,
|
||||
const CPoint& offset, const int32_t style = kHorizontal);
|
||||
CRockerSwitch (const CRect& size, IControlListener* listener, int32_t tag,
|
||||
CCoord heightOfOneImage, CBitmap* background,
|
||||
const CPoint& offset = CPoint (0, 0), const int32_t style = kHorizontal);
|
||||
void setNumSubPixmaps (int32_t numSubPixmaps) override { IMultiBitmapControl::setNumSubPixmaps (numSubPixmaps); invalid (); }
|
||||
#endif
|
||||
|
||||
CLASS_METHODS(CRockerSwitch, CControl)
|
||||
protected:
|
||||
~CRockerSwitch () noexcept override;
|
||||
|
||||
CMessageResult notify (CBaseObject* sender, IdStringPtr message) override;
|
||||
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
CPoint offset {};
|
||||
#endif
|
||||
int32_t style;
|
||||
|
||||
CVSTGUITimer* resetValueTimer;
|
||||
private:
|
||||
float mouseStartValue;
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,421 @@
|
||||
// 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 "ctextedit.h"
|
||||
#include "itexteditlistener.h"
|
||||
#include "../cframe.h"
|
||||
#include "../cdrawcontext.h"
|
||||
#include "../events.h"
|
||||
#include "../platform/iplatformframe.h"
|
||||
#include <cassert>
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// CTextEdit
|
||||
//------------------------------------------------------------------------
|
||||
/*! @class CTextEdit
|
||||
Define a rectangle view where a text-value can be displayed and edited with a given font and color.
|
||||
The user can specify its convert function (from char to char). The text-value is centered in the given rect.
|
||||
A bitmap can be used as background.
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
/**
|
||||
* CTextEdit constructor.
|
||||
* @param size the size of this view
|
||||
* @param listener the listener
|
||||
* @param tag the control tag
|
||||
* @param txt the initial text as c string (UTF-8 encoded)
|
||||
* @param background the background bitmap
|
||||
* @param style the display style (see CParamDisplay for styles)
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
CTextEdit::CTextEdit (const CRect& size, IControlListener* listener, int32_t tag, UTF8StringPtr txt,
|
||||
CBitmap* background, const int32_t style)
|
||||
: CTextLabel (size, txt, background, style)
|
||||
{
|
||||
this->listener = listener;
|
||||
this->tag = tag;
|
||||
|
||||
setWantsFocus (true);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CTextEdit::CTextEdit (const CTextEdit& v)
|
||||
: CTextLabel (v)
|
||||
, bWasReturnPressed (false)
|
||||
, stringToValueFunction (v.stringToValueFunction)
|
||||
, immediateTextChange (v.immediateTextChange)
|
||||
, secureStyle (v.secureStyle)
|
||||
, platformFont (v.platformFont)
|
||||
, placeholderString (v.placeholderString)
|
||||
{
|
||||
setWantsFocus (true);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CTextEdit::~CTextEdit () noexcept
|
||||
{
|
||||
listener = nullptr;
|
||||
vstgui_assert (platformControl == nullptr);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CTextEdit::setStringToValueFunction (const StringToValueFunction& stringToValueFunc)
|
||||
{
|
||||
stringToValueFunction = stringToValueFunc;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CTextEdit::setStringToValueFunction (StringToValueFunction&& stringToValueFunc)
|
||||
{
|
||||
stringToValueFunction = std::move (stringToValueFunc);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CTextEdit::setImmediateTextChange (bool state)
|
||||
{
|
||||
immediateTextChange = state;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CTextEdit::setSecureStyle (bool state)
|
||||
{
|
||||
if (secureStyle != state)
|
||||
{
|
||||
secureStyle = state;
|
||||
if (platformControl)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool CTextEdit::getSecureStyle () const
|
||||
{
|
||||
return secureStyle;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CTextEdit::registerTextEditListener (ITextEditListener* listener)
|
||||
{
|
||||
textEditListeners.add (listener);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CTextEdit::unregisterTextEditListener (ITextEditListener* listener)
|
||||
{
|
||||
textEditListeners.remove (listener);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CTextEdit::setValue (float val)
|
||||
{
|
||||
CTextLabel::setValue (val);
|
||||
bool converted = false;
|
||||
std::string string;
|
||||
if (valueToStringFunction)
|
||||
converted = valueToStringFunction (getValue (), string, this);
|
||||
if (!converted)
|
||||
{
|
||||
char tmp[255];
|
||||
char precisionStr[10];
|
||||
snprintf (precisionStr, 10, "%%.%hhuf", valuePrecision);
|
||||
snprintf (tmp, 255, precisionStr, getValue ());
|
||||
string = tmp;
|
||||
}
|
||||
|
||||
if (converted)
|
||||
{
|
||||
CTextLabel::setText (UTF8String (std::move (string)));
|
||||
if (platformControl)
|
||||
platformControl->setText (getText ());
|
||||
}
|
||||
else
|
||||
setText (UTF8String (std::move (string)));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CTextEdit::setText (const UTF8String& txt)
|
||||
{
|
||||
if (stringToValueFunction)
|
||||
{
|
||||
float val = getValue ();
|
||||
if (stringToValueFunction (txt, val, this))
|
||||
{
|
||||
CTextLabel::setValue (val);
|
||||
if (valueToStringFunction)
|
||||
{
|
||||
std::string string;
|
||||
valueToStringFunction (getValue (), string, this);
|
||||
CTextLabel::setText (UTF8String (std::move (string)));
|
||||
if (platformControl)
|
||||
platformControl->setText (getText ());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
CTextLabel::setText (txt);
|
||||
if (platformControl)
|
||||
platformControl->setText (getText ());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CTextEdit::valueChanged ()
|
||||
{
|
||||
if (stringToValueFunction)
|
||||
CTextLabel::valueChanged ();
|
||||
|
||||
CParamDisplay::valueChanged ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CTextEdit::setPlaceholderString (const UTF8String& str)
|
||||
{
|
||||
placeholderString = str;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CTextEdit::draw (CDrawContext *pContext)
|
||||
{
|
||||
if (platformControl)
|
||||
{
|
||||
drawBack (pContext);
|
||||
if (!platformControl->drawsPlaceholder () && !placeholderString.empty () &&
|
||||
platformControl->getText ().empty ())
|
||||
{
|
||||
pContext->saveGlobalState ();
|
||||
pContext->setGlobalAlpha (pContext->getGlobalAlpha () * 0.5f);
|
||||
drawPlatformText (pContext, placeholderString);
|
||||
pContext->restoreGlobalState ();
|
||||
}
|
||||
setDirty (false);
|
||||
return;
|
||||
}
|
||||
drawBack (pContext);
|
||||
if (text.empty ())
|
||||
{
|
||||
if (!placeholderString.empty ())
|
||||
{
|
||||
pContext->saveGlobalState ();
|
||||
pContext->setGlobalAlpha (pContext->getGlobalAlpha () * 0.5f);
|
||||
drawPlatformText (pContext, placeholderString);
|
||||
pContext->restoreGlobalState ();
|
||||
}
|
||||
}
|
||||
else if (getSecureStyle ())
|
||||
{
|
||||
constexpr auto bulletCharacter = "\xE2\x80\xA2";
|
||||
UTF8String str;
|
||||
for (auto i = 0u; i < text.length (); ++i)
|
||||
str += bulletCharacter;
|
||||
drawPlatformText (pContext, str);
|
||||
}
|
||||
else
|
||||
CTextLabel::draw (pContext);
|
||||
setDirty (false);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMouseEventResult CTextEdit::onMouseDown (CPoint& where, const CButtonState& buttons)
|
||||
{
|
||||
if (buttons & kLButton)
|
||||
{
|
||||
if (getFrame ()->getFocusView () != this)
|
||||
{
|
||||
if (isDoubleClickStyle ())
|
||||
{
|
||||
if (!(buttons & kDoubleClick))
|
||||
return kMouseEventNotHandled;
|
||||
}
|
||||
|
||||
takeFocus ();
|
||||
return kMouseDownEventHandledButDontNeedMovedOrUpEvents;
|
||||
}
|
||||
}
|
||||
return kMouseEventNotHandled;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CTextEdit::onKeyboardEvent (KeyboardEvent& event)
|
||||
{
|
||||
if (!platformControl || event.type != EventType::KeyDown)
|
||||
return;
|
||||
|
||||
if (event.virt == VirtualKey::Escape)
|
||||
{
|
||||
bWasReturnPressed = false;
|
||||
platformControl->setText (text);
|
||||
getFrame ()->setFocusView (nullptr);
|
||||
looseFocus ();
|
||||
event.consumed = true;
|
||||
}
|
||||
else if (event.virt == VirtualKey::Return)
|
||||
{
|
||||
bWasReturnPressed = true;
|
||||
getFrame ()->setFocusView (nullptr);
|
||||
looseFocus ();
|
||||
event.consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CFontRef CTextEdit::platformGetFont () const
|
||||
{
|
||||
CFontRef font = getFont ();
|
||||
CCoord fontSize = font->getSize ();
|
||||
fontSize *= getGlobalTransform ().m11;
|
||||
if (fontSize == font->getSize ())
|
||||
return font;
|
||||
platformFont = makeOwned<CFontDesc> (*font);
|
||||
platformFont->setSize (fontSize);
|
||||
return platformFont;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CRect CTextEdit::platformGetSize () const
|
||||
{
|
||||
return translateToGlobal (getViewSize ());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CRect CTextEdit::platformGetVisibleSize () const
|
||||
{
|
||||
return translateToGlobal (getVisibleViewSize ());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CTextEdit::platformLooseFocus (bool returnPressed)
|
||||
{
|
||||
remember ();
|
||||
bWasReturnPressed = returnPressed;
|
||||
if (getFrame ()->getFocusView () == this)
|
||||
getFrame ()->setFocusView (nullptr);
|
||||
forget ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CTextEdit::platformOnKeyboardEvent (KeyboardEvent& event)
|
||||
{
|
||||
dynamic_cast<IPlatformFrameCallback*> (getFrame ())->platformOnEvent (event);
|
||||
if (event.consumed)
|
||||
return;
|
||||
if (event.virt == VirtualKey::Return)
|
||||
{
|
||||
platformLooseFocus (true);
|
||||
event.consumed = true;
|
||||
}
|
||||
else if (event.virt == VirtualKey::Escape)
|
||||
{
|
||||
platformLooseFocus (false);
|
||||
event.consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CTextEdit::platformTextDidChange ()
|
||||
{
|
||||
if (platformControl && immediateTextChange)
|
||||
updateText (platformControl);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool CTextEdit::platformIsSecureTextEdit ()
|
||||
{
|
||||
return getSecureStyle ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CTextEdit::parentSizeChanged ()
|
||||
{
|
||||
if (platformControl)
|
||||
platformControl->updateSize ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CTextEdit::setViewSize (const CRect& newSize, bool invalid)
|
||||
{
|
||||
CTextLabel::setViewSize (newSize, invalid);
|
||||
if (platformControl)
|
||||
platformControl->updateSize ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CTextEdit::createPlatformTextEdit ()
|
||||
{
|
||||
if (platformControl)
|
||||
return;
|
||||
|
||||
bWasReturnPressed = false;
|
||||
platformControl = getFrame ()->getPlatformFrame ()->createPlatformTextEdit (this);
|
||||
textEditListeners.forEach (
|
||||
[this] (ITextEditListener* l) { l->onTextEditPlatformControlTookFocus (this); });
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool CTextEdit::wantsFocus () const
|
||||
{
|
||||
if (isDoubleClickStyle () && !platformControl)
|
||||
return false;
|
||||
return CTextLabel::wantsFocus ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CTextEdit::takeFocus ()
|
||||
{
|
||||
if (!getFrame ())
|
||||
return;
|
||||
createPlatformTextEdit ();
|
||||
if (getFrame()->getFocusView () != this)
|
||||
getFrame()->setFocusView (this);
|
||||
CTextLabel::takeFocus ();
|
||||
invalid ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CTextEdit::looseFocus ()
|
||||
{
|
||||
if (platformControl == nullptr)
|
||||
return;
|
||||
|
||||
CBaseObjectGuard guard (this);
|
||||
|
||||
auto _platformControl = std::move (platformControl);
|
||||
updateText (_platformControl);
|
||||
|
||||
_platformControl = nullptr;
|
||||
|
||||
textEditListeners.forEach (
|
||||
[this] (ITextEditListener* l) { l->onTextEditPlatformControlLostFocus (this); });
|
||||
|
||||
// if you want to destroy the text edit do it with the loose focus message
|
||||
CView* receiver = getParentView () ? getParentView () : getFrame ();
|
||||
while (receiver)
|
||||
{
|
||||
if (receiver->notify (this, kMsgLooseFocus) == kMessageNotified)
|
||||
break;
|
||||
receiver = receiver->getParentView ();
|
||||
}
|
||||
CTextLabel::looseFocus ();
|
||||
invalid ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CTextEdit::updateText (IPlatformTextEdit* pte)
|
||||
{
|
||||
auto newText = pte->getText ();
|
||||
if (newText != getText ())
|
||||
{
|
||||
beginEdit ();
|
||||
|
||||
setText (newText);
|
||||
|
||||
CParamDisplay::valueChanged ();
|
||||
|
||||
endEdit ();
|
||||
}
|
||||
}
|
||||
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,122 @@
|
||||
// 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 "ctextlabel.h"
|
||||
#include "../dispatchlist.h"
|
||||
#include "../platform/iplatformtextedit.h"
|
||||
#include <functional>
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
using CTextEditStringToValueProc = bool (*) (UTF8StringPtr txt, float& result, void* userData);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CTextEdit Declaration
|
||||
//! @brief a text edit control
|
||||
/// @ingroup controls
|
||||
//-----------------------------------------------------------------------------
|
||||
class CTextEdit : public CTextLabel, public IPlatformTextEditCallback
|
||||
{
|
||||
private:
|
||||
enum StyleEnum
|
||||
{
|
||||
StyleDoubleClick = CParamDisplay::LastStyle,
|
||||
};
|
||||
public:
|
||||
using PlatformTextEditPtr = SharedPointer<IPlatformTextEdit>;
|
||||
|
||||
CTextEdit (const CRect& size, IControlListener* listener, int32_t tag, UTF8StringPtr txt = nullptr, CBitmap* background = nullptr, const int32_t style = 0);
|
||||
CTextEdit (const CTextEdit& textEdit);
|
||||
|
||||
enum Style
|
||||
{
|
||||
kDoubleClickStyle = 1 << StyleDoubleClick,
|
||||
};
|
||||
|
||||
bool isDoubleClickStyle () const { return hasBit (getStyle (), kDoubleClickStyle); }
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @name CTextEdit Methods
|
||||
//-----------------------------------------------------------------------------
|
||||
//@{
|
||||
using StringToValueUserData = CTextEdit;
|
||||
|
||||
using StringToValueFunction = std::function<bool(UTF8StringPtr txt, float& result, CTextEdit* textEdit)>;
|
||||
|
||||
void setStringToValueFunction (const StringToValueFunction& stringToValueFunc);
|
||||
void setStringToValueFunction (StringToValueFunction&& stringToValueFunc);
|
||||
|
||||
/** enable/disable immediate text change behaviour */
|
||||
virtual void setImmediateTextChange (bool state);
|
||||
/** get immediate text change behaviour */
|
||||
bool getImmediateTextChange () const { return immediateTextChange; }
|
||||
|
||||
/** enable/disable secure style */
|
||||
void setSecureStyle (bool state);
|
||||
/** get secure style */
|
||||
bool getSecureStyle () const;
|
||||
|
||||
virtual void setPlaceholderString (const UTF8String& str);
|
||||
const UTF8String& getPlaceholderString () const { return placeholderString; }
|
||||
|
||||
void registerTextEditListener (ITextEditListener* listener);
|
||||
void unregisterTextEditListener (ITextEditListener* listener);
|
||||
//@}
|
||||
|
||||
// overrides
|
||||
void setText (const UTF8String& txt) override;
|
||||
void valueChanged () override;
|
||||
void setValue (float val) override;
|
||||
void setTextRotation (double angle) override { } // not supported
|
||||
|
||||
void draw (CDrawContext* pContext) override;
|
||||
CMouseEventResult onMouseDown (CPoint& where, const CButtonState& buttons) override;
|
||||
void onKeyboardEvent (KeyboardEvent& event) override;
|
||||
|
||||
void takeFocus () override;
|
||||
void looseFocus () override;
|
||||
bool wantsFocus () const override;
|
||||
|
||||
void setViewSize (const CRect& newSize, bool invalid = true) override;
|
||||
void parentSizeChanged () override;
|
||||
|
||||
bool bWasReturnPressed {false};
|
||||
|
||||
PlatformTextEditPtr getPlatformTextEdit () const { return platformControl; }
|
||||
|
||||
CLASS_METHODS(CTextEdit, CParamDisplay)
|
||||
protected:
|
||||
~CTextEdit () noexcept override;
|
||||
|
||||
void createPlatformTextEdit ();
|
||||
void updateText (IPlatformTextEdit* pte);
|
||||
|
||||
CColor platformGetBackColor () const override { return getBackColor (); }
|
||||
CColor platformGetFontColor () const override { return getFontColor (); }
|
||||
CFontRef platformGetFont () const override;
|
||||
CHoriTxtAlign platformGetHoriTxtAlign () const override { return getHoriAlign (); }
|
||||
const UTF8String& platformGetText () const override { return text; }
|
||||
const UTF8String& platformGetPlaceholderText () const override { return placeholderString; }
|
||||
CRect platformGetSize () const override;
|
||||
CRect platformGetVisibleSize () const override;
|
||||
CPoint platformGetTextInset () const override { return getTextInset (); }
|
||||
void platformLooseFocus (bool returnPressed) override;
|
||||
void platformOnKeyboardEvent (KeyboardEvent& event) override;
|
||||
void platformTextDidChange () override;
|
||||
bool platformIsSecureTextEdit () override;
|
||||
|
||||
PlatformTextEditPtr platformControl;
|
||||
|
||||
StringToValueFunction stringToValueFunction;
|
||||
|
||||
bool immediateTextChange {false};
|
||||
bool secureStyle {false};
|
||||
mutable SharedPointer<CFontDesc> platformFont;
|
||||
UTF8String placeholderString;
|
||||
DispatchList<ITextEditListener*> textEditListeners;
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,483 @@
|
||||
// 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 "ctextlabel.h"
|
||||
#include "../platform/iplatformfont.h"
|
||||
#include "../cdrawmethods.h"
|
||||
#include "../cdrawcontext.h"
|
||||
#include <sstream>
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// CTextLabel
|
||||
//------------------------------------------------------------------------
|
||||
/*! @class CTextLabel
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
/**
|
||||
* CTextLabel constructor.
|
||||
* @param size the size of this view
|
||||
* @param txt the initial text as c string (UTF-8 encoded)
|
||||
* @param background the background bitmap
|
||||
* @param style the display style (see CParamDisplay for styles)
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
CTextLabel::CTextLabel (const CRect& size, UTF8StringPtr txt, CBitmap* background, const int32_t style)
|
||||
: CParamDisplay (size, background, style)
|
||||
, textTruncateMode (kTruncateNone)
|
||||
{
|
||||
setText (txt);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CTextLabel::CTextLabel (const CTextLabel& v)
|
||||
: CParamDisplay (v)
|
||||
, textTruncateMode (v.textTruncateMode)
|
||||
{
|
||||
setText (v.getText ());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CTextLabel::registerTextLabelListener (ITextLabelListener* listener)
|
||||
{
|
||||
if (!listeners)
|
||||
listeners = std::unique_ptr<TextLabelListenerList> (new TextLabelListenerList ());
|
||||
listeners->add (listener);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CTextLabel::unregisterTextLabelListener (ITextLabelListener* listener)
|
||||
{
|
||||
if (listeners)
|
||||
listeners->remove (listener);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CTextLabel::setText (const UTF8String& txt)
|
||||
{
|
||||
if (text == txt)
|
||||
return;
|
||||
text = txt;
|
||||
if (textTruncateMode != kTruncateNone)
|
||||
calculateTruncatedText ();
|
||||
setDirty (true);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CTextLabel::setTextTruncateMode (TextTruncateMode mode)
|
||||
{
|
||||
if (textTruncateMode != mode)
|
||||
{
|
||||
textTruncateMode = mode;
|
||||
calculateTruncatedText ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CTextLabel::calculateTruncatedText ()
|
||||
{
|
||||
if (textRotation != 0.) // currently truncation is only supported when not rotated
|
||||
{
|
||||
truncatedText = "";
|
||||
return;
|
||||
}
|
||||
if (!(textTruncateMode == kTruncateNone || text.empty () || fontID == nullptr || fontID->getPlatformFont () == nullptr || fontID->getPlatformFont ()->getPainter () == nullptr))
|
||||
{
|
||||
CDrawMethods::TextTruncateMode mode = textTruncateMode == kTruncateHead ? CDrawMethods::kTextTruncateHead : CDrawMethods::kTextTruncateTail;
|
||||
truncatedText = CDrawMethods::createTruncatedText (mode, text, fontID, getWidth () - getTextInset ().x * 2.);
|
||||
if (truncatedText == text)
|
||||
truncatedText.clear ();
|
||||
if (listeners)
|
||||
{
|
||||
listeners->forEach (
|
||||
[this] (ITextLabelListener* l) { l->onTextLabelTruncatedTextChanged (this); });
|
||||
}
|
||||
}
|
||||
else if (!truncatedText.empty ())
|
||||
truncatedText.clear ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
const UTF8String& CTextLabel::getText () const
|
||||
{
|
||||
return text;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CTextLabel::draw (CDrawContext *pContext)
|
||||
{
|
||||
drawBack (pContext);
|
||||
drawPlatformText (pContext, truncatedText.empty () ? text : truncatedText);
|
||||
setDirty (false);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool CTextLabel::sizeToFit ()
|
||||
{
|
||||
if (fontID == nullptr || fontID->getPlatformFont () == nullptr || fontID->getPlatformFont ()->getPainter () == nullptr)
|
||||
return false;
|
||||
CCoord width = fontID->getPlatformFont ()->getPainter ()->getStringWidth (nullptr, text.getPlatformString (), true);
|
||||
if (width > 0)
|
||||
{
|
||||
width += (getTextInset ().x * 2.);
|
||||
CRect newSize = getViewSize ();
|
||||
newSize.setWidth (width);
|
||||
setViewSize (newSize);
|
||||
setMouseableArea (newSize);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CTextLabel::setViewSize (const CRect& rect, bool invalid)
|
||||
{
|
||||
CRect current (getViewSize ());
|
||||
CParamDisplay::setViewSize (rect, invalid);
|
||||
if (textTruncateMode != kTruncateNone && current.getWidth () != getWidth ())
|
||||
{
|
||||
calculateTruncatedText ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CTextLabel::drawStyleChanged ()
|
||||
{
|
||||
if (textTruncateMode != kTruncateNone)
|
||||
{
|
||||
calculateTruncatedText ();
|
||||
}
|
||||
CParamDisplay::drawStyleChanged ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CTextLabel::valueChanged ()
|
||||
{
|
||||
if (valueToStringFunction)
|
||||
{
|
||||
std::string string;
|
||||
if (valueToStringFunction (getValue (), string, this))
|
||||
setText (UTF8String (std::move (string)));
|
||||
}
|
||||
CParamDisplay::valueChanged ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------
|
||||
CMultiLineTextLabel::CMultiLineTextLabel (const CRect& size)
|
||||
: CTextLabel (size)
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CMultiLineTextLabel::setValue (float val)
|
||||
{
|
||||
CTextLabel::setValue (val);
|
||||
|
||||
if (valueToStringFunction)
|
||||
{
|
||||
std::string string;
|
||||
if (valueToStringFunction (value, string, this))
|
||||
setText (UTF8String (string));
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CMultiLineTextLabel::setTextTruncateMode (TextTruncateMode)
|
||||
{
|
||||
// not supported on multi line labels
|
||||
CTextLabel::setTextTruncateMode (kTruncateNone);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CMultiLineTextLabel::setLineLayout (LineLayout layout)
|
||||
{
|
||||
if (lineLayout == layout)
|
||||
return;
|
||||
lineLayout = layout;
|
||||
lines.clear ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CMultiLineTextLabel::setAutoHeight (bool state)
|
||||
{
|
||||
if (autoHeight == state)
|
||||
return;
|
||||
autoHeight = state;
|
||||
if (autoHeight && isAttached ())
|
||||
{
|
||||
if (lines.empty ())
|
||||
recalculateLines (nullptr);
|
||||
recalculateHeight ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CMultiLineTextLabel::setVerticalCentered (bool state)
|
||||
{
|
||||
if (verticalCentered == state)
|
||||
return;
|
||||
verticalCentered = state;
|
||||
lines.clear ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CCoord CMultiLineTextLabel::getMaxLineWidth ()
|
||||
{
|
||||
if (lines.empty () && getText ().empty () == false)
|
||||
recalculateLines (nullptr);
|
||||
CCoord maxWidth {};
|
||||
for (const auto& line : lines)
|
||||
{
|
||||
if (line.r.getWidth () > maxWidth)
|
||||
maxWidth = line.r.getWidth ();
|
||||
}
|
||||
return maxWidth;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CMultiLineTextLabel::drawRect (CDrawContext* pContext, const CRect& updateRect)
|
||||
{
|
||||
if (getText ().empty () == false && lines.empty ())
|
||||
recalculateLines (pContext);
|
||||
drawBack (pContext);
|
||||
|
||||
CRect newClip (updateRect);
|
||||
newClip.inset (getTextInset ());
|
||||
ConcatClip clip (*pContext, newClip);
|
||||
newClip = clip.get ();
|
||||
|
||||
pContext->setDrawMode (kAntiAliasing);
|
||||
pContext->setFont (getFont ());
|
||||
|
||||
newClip.offsetInverse (getViewSize().getTopLeft ());
|
||||
|
||||
CDrawContext::Transform t (*pContext, CGraphicsTransform ().translate (getViewSize ().getTopLeft ()));
|
||||
|
||||
if (style & kShadowText)
|
||||
{
|
||||
CDrawContext::Transform t2 (*pContext, CGraphicsTransform ().translate (shadowTextOffset));
|
||||
pContext->setFontColor (getShadowColor ());
|
||||
for (const auto& line : lines)
|
||||
{
|
||||
if (line.r.rectOverlap (newClip))
|
||||
pContext->drawString (line.str.getPlatformString (), line.r, getHoriAlign (), getAntialias ());
|
||||
}
|
||||
}
|
||||
|
||||
pContext->setFontColor (getFontColor ());
|
||||
for (const auto& line : lines)
|
||||
{
|
||||
if (line.r.rectOverlap (newClip))
|
||||
pContext->drawString (line.str.getPlatformString (), line.r, getHoriAlign (), getAntialias ());
|
||||
else if (line.r.bottom > newClip.bottom)
|
||||
break;
|
||||
}
|
||||
|
||||
setDirty (false);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool CMultiLineTextLabel::sizeToFit ()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CMultiLineTextLabel::setText (const UTF8String& txt)
|
||||
{
|
||||
if (getText () == txt)
|
||||
return;
|
||||
CTextLabel::setText (txt);
|
||||
lines.clear ();
|
||||
if (autoHeight && isAttached ())
|
||||
{
|
||||
recalculateLines (nullptr);
|
||||
recalculateHeight ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CMultiLineTextLabel::recalculateHeight ()
|
||||
{
|
||||
auto viewSize = getViewSize ();
|
||||
if (lines.empty ())
|
||||
viewSize.setHeight (0.);
|
||||
else
|
||||
{
|
||||
auto lastLine = lines.back ().r;
|
||||
viewSize.setHeight (lastLine.bottom + getTextInset ().y);
|
||||
}
|
||||
CTextLabel::setViewSize (viewSize);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CMultiLineTextLabel::setViewSize (const CRect& rect, bool invalid)
|
||||
{
|
||||
auto viewSize = getViewSize ();
|
||||
auto normRect = rect;
|
||||
viewSize.originize ();
|
||||
normRect.originize ();
|
||||
if (viewSize != normRect)
|
||||
{
|
||||
if (lineLayout != LineLayout::clip ||
|
||||
(lineLayout == LineLayout::clip &&
|
||||
viewSize.getHeight () != normRect.getHeight ()))
|
||||
{
|
||||
lines.clear ();
|
||||
}
|
||||
}
|
||||
CTextLabel::setViewSize (rect, invalid);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CMultiLineTextLabel::drawStyleChanged ()
|
||||
{
|
||||
lines.clear ();
|
||||
CTextLabel::drawStyleChanged ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline bool isLineBreakSeparator (char32_t c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '-': return true;
|
||||
case '_': return true;
|
||||
case '/': return true;
|
||||
case '\\': return true;
|
||||
case '.': return true;
|
||||
case ',': return true;
|
||||
case ':': return true;
|
||||
case ';': return true;
|
||||
case '?': return true;
|
||||
case '!': return true;
|
||||
case '*': return true;
|
||||
case '+': return true;
|
||||
case '&': return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CMultiLineTextLabel::calculateWrapLine (CDrawContext* context,
|
||||
std::pair<UTF8String, double>& element,
|
||||
const IFontPainter* const& fontPainter, double lineHeight,
|
||||
double lineWidth, double maxWidth, const CPoint& textInset,
|
||||
CCoord& y)
|
||||
{
|
||||
auto start = element.first.begin ();
|
||||
auto lastSeparator = start;
|
||||
auto pos = start;
|
||||
while (pos != element.first.end () && *pos != 0)
|
||||
{
|
||||
if (isspace (*pos))
|
||||
lastSeparator = pos;
|
||||
else if (isLineBreakSeparator (*pos))
|
||||
lastSeparator = ++pos;
|
||||
if (pos == element.first.end ())
|
||||
break;
|
||||
auto tmpEnd = pos;
|
||||
UTF8String tmp ({start.base (), (++tmpEnd).base ()});
|
||||
auto width = fontPainter->getStringWidth (
|
||||
context ? context->getPlatformDeviceContext () : nullptr, tmp.getPlatformString ());
|
||||
if (width > maxWidth)
|
||||
{
|
||||
if (lastSeparator == element.first.end ())
|
||||
lastSeparator = pos;
|
||||
if (start == lastSeparator)
|
||||
lastSeparator = pos;
|
||||
lines.emplace_back (
|
||||
Line {CRect (textInset.x, y, lineWidth, y + lineHeight + textInset.y),
|
||||
UTF8String ({start.base (), lastSeparator.base ()})});
|
||||
y += lineHeight;
|
||||
pos = lastSeparator;
|
||||
start = pos;
|
||||
if (isspace (*start))
|
||||
++start;
|
||||
lastSeparator = element.first.end ();
|
||||
}
|
||||
++pos;
|
||||
}
|
||||
if (start != element.first.end ())
|
||||
{
|
||||
lines.emplace_back (Line {CRect (textInset.x, y, lineWidth, y + lineHeight + textInset.y),
|
||||
UTF8String ({start.base (), element.first.end ().base ()})});
|
||||
y += lineHeight;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CMultiLineTextLabel::recalculateLines (CDrawContext* context)
|
||||
{
|
||||
const auto& font = getFont ()->getPlatformFont ();
|
||||
const auto& fontPainter = getFont ()->getFontPainter ();
|
||||
auto ascent = font->getAscent ();
|
||||
auto descent = font->getDescent ();
|
||||
auto leading = font->getLeading ();
|
||||
auto lineHeight = ascent + descent + leading;
|
||||
|
||||
const auto& textInset = getTextInset ();
|
||||
auto maxWidth = getWidth () - (textInset.x * 2);
|
||||
|
||||
std::vector<std::pair<UTF8String, CCoord>> elements;
|
||||
std::stringstream stream (getText ().getString ());
|
||||
std::string line;
|
||||
while (std::getline (stream, line, '\n'))
|
||||
{
|
||||
UTF8String str (std::move (line));
|
||||
auto width = fontPainter->getStringWidth (
|
||||
context ? context->getPlatformDeviceContext () : nullptr, str.getPlatformString ());
|
||||
elements.emplace_back (std::move (str), width);
|
||||
}
|
||||
|
||||
CCoord y = textInset.y;
|
||||
|
||||
auto lineWidth = getWidth () - textInset.x;
|
||||
|
||||
for (auto& element : elements)
|
||||
{
|
||||
if (lineLayout == LineLayout::clip)
|
||||
{
|
||||
lines.emplace_back (Line {
|
||||
CRect (textInset.x, y, element.second + textInset.x, y + lineHeight + textInset.y),
|
||||
std::move (element.first)});
|
||||
}
|
||||
else
|
||||
{
|
||||
if (element.second > maxWidth)
|
||||
{
|
||||
if (lineLayout == LineLayout::truncate)
|
||||
{
|
||||
element.first = CDrawMethods::createTruncatedText (
|
||||
CDrawMethods::kTextTruncateTail, element.first, fontID, maxWidth);
|
||||
}
|
||||
else // wrap
|
||||
{
|
||||
calculateWrapLine (context, element, fontPainter, lineHeight, lineWidth,
|
||||
maxWidth, textInset, y);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
lines.emplace_back (
|
||||
Line {CRect (textInset.x, y, lineWidth, y + lineHeight + textInset.y),
|
||||
std::move (element.first)});
|
||||
}
|
||||
y += lineHeight;
|
||||
}
|
||||
if (getVerticalCentered () && !lines.empty ())
|
||||
{
|
||||
auto maxHeight = lines.back ().r.bottom;
|
||||
auto offset = ((getHeight () - textInset.y) - maxHeight) / 2.;
|
||||
if (offset > 0)
|
||||
{
|
||||
for (auto& l : lines)
|
||||
l.r.offset (0, offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,143 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cparamdisplay.h"
|
||||
#include "itextlabellistener.h"
|
||||
#include "../dispatchlist.h"
|
||||
#include "../cstring.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CLabel Declaration
|
||||
//! @brief a text label
|
||||
/// @ingroup controls
|
||||
//-----------------------------------------------------------------------------
|
||||
class CTextLabel : public CParamDisplay
|
||||
{
|
||||
public:
|
||||
CTextLabel (const CRect& size, UTF8StringPtr txt = nullptr, CBitmap* background = nullptr, const int32_t style = 0);
|
||||
CTextLabel (const CTextLabel& textLabel);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @name CTextLabel Methods
|
||||
//-----------------------------------------------------------------------------
|
||||
//@{
|
||||
/** set text */
|
||||
virtual void setText (const UTF8String& txt);
|
||||
/** read only access to text */
|
||||
virtual const UTF8String& getText () const;
|
||||
|
||||
enum TextTruncateMode {
|
||||
/** no characters will be removed */
|
||||
kTruncateNone = 0,
|
||||
/** characters will be removed from the beginning of the text */
|
||||
kTruncateHead,
|
||||
/** characters will be removed from the end of the text */
|
||||
kTruncateTail
|
||||
};
|
||||
|
||||
/** set text truncate mode */
|
||||
virtual void setTextTruncateMode (TextTruncateMode mode);
|
||||
/** get text truncate mode */
|
||||
TextTruncateMode getTextTruncateMode () const { return textTruncateMode; }
|
||||
/** get the truncated text */
|
||||
const UTF8String& getTruncatedText () const { return truncatedText; }
|
||||
|
||||
/** register a text label listener */
|
||||
void registerTextLabelListener (ITextLabelListener* listener);
|
||||
/** unregister a text label listener */
|
||||
void unregisterTextLabelListener (ITextLabelListener* listener);
|
||||
//@}
|
||||
|
||||
void draw (CDrawContext* pContext) override;
|
||||
bool sizeToFit () override;
|
||||
void setViewSize (const CRect& rect, bool invalid = true) override;
|
||||
void drawStyleChanged () override;
|
||||
void valueChanged () override;
|
||||
|
||||
CLASS_METHODS(CTextLabel, CParamDisplay)
|
||||
protected:
|
||||
~CTextLabel () noexcept override = default;
|
||||
void freeText ();
|
||||
void calculateTruncatedText ();
|
||||
|
||||
#if VSTGUI_ENABLE_DEPRECATED_METHODS
|
||||
bool onWheel (const CPoint& where, const CMouseWheelAxis& axis, const float& distance, const CButtonState& buttons) override { return false; }
|
||||
#endif
|
||||
|
||||
TextTruncateMode textTruncateMode;
|
||||
UTF8String text;
|
||||
UTF8String truncatedText;
|
||||
using TextLabelListenerList = DispatchList<ITextLabelListener*>;
|
||||
std::unique_ptr<TextLabelListenerList> listeners;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Multi line text label
|
||||
* @ingroup new_in_4_5
|
||||
*/
|
||||
class CMultiLineTextLabel : public CTextLabel
|
||||
{
|
||||
public:
|
||||
CMultiLineTextLabel (const CRect& size);
|
||||
CMultiLineTextLabel (const CMultiLineTextLabel&) = default;
|
||||
|
||||
enum class LineLayout {
|
||||
/** clip lines overflowing the view size width */
|
||||
clip,
|
||||
/** truncate lines overflowing the view size width */
|
||||
truncate,
|
||||
/** wrap overflowing words to next line */
|
||||
wrap
|
||||
};
|
||||
void setLineLayout (LineLayout layout);
|
||||
LineLayout getLineLayout () const { return lineLayout; }
|
||||
|
||||
/** automatically resize the view according to the contents (only the height)
|
||||
* @param state on or off
|
||||
*/
|
||||
void setAutoHeight (bool state);
|
||||
/** returns true if this view resizes itself according to the contents */
|
||||
bool getAutoHeight () const { return autoHeight; }
|
||||
|
||||
/** draw the lines vertical centered
|
||||
* @param state on or off
|
||||
*/
|
||||
void setVerticalCentered (bool state);
|
||||
/** returns true if the view draws the lines vertically centered */
|
||||
bool getVerticalCentered () const { return verticalCentered; }
|
||||
|
||||
/** return the maximum line width of all lines */
|
||||
CCoord getMaxLineWidth ();
|
||||
|
||||
void drawRect (CDrawContext* pContext, const CRect& updateRect) override;
|
||||
bool sizeToFit () override;
|
||||
void setText (const UTF8String& txt) override;
|
||||
void setViewSize (const CRect& rect, bool invalid = true) override;
|
||||
void setTextTruncateMode (TextTruncateMode mode) override;
|
||||
void setValue (float val) override;
|
||||
private:
|
||||
void drawStyleChanged () override;
|
||||
void calculateWrapLine (CDrawContext *context, std::pair<UTF8String, double> &element, const IFontPainter *const &fontPainter, double lineHeight, double lineWidth, double maxWidth, const CPoint &textInset, CCoord &y);
|
||||
|
||||
void recalculateLines (CDrawContext* context);
|
||||
void recalculateHeight ();
|
||||
|
||||
bool autoHeight {false};
|
||||
bool verticalCentered {false};
|
||||
LineLayout lineLayout {LineLayout::clip};
|
||||
|
||||
struct Line
|
||||
{
|
||||
CRect r;
|
||||
UTF8String str;
|
||||
};
|
||||
using Lines = std::vector<Line>;
|
||||
Lines lines;
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,155 @@
|
||||
// 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 "cvumeter.h"
|
||||
#include "../coffscreencontext.h"
|
||||
#include "../cbitmap.h"
|
||||
#include "../cvstguitimer.h"
|
||||
#include <list>
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// CVuMeter
|
||||
//------------------------------------------------------------------------
|
||||
/**
|
||||
* CVuMeter constructor.
|
||||
* @param size the size of this view
|
||||
* @param onBitmap TODO
|
||||
* @param offBitmap TODO
|
||||
* @param nbLed TODO
|
||||
* @param style kHorizontal or kVertical
|
||||
*/
|
||||
//------------------------------------------------------------------------
|
||||
CVuMeter::CVuMeter (const CRect& size, CBitmap* onBitmap, CBitmap* offBitmap, int32_t nbLed,
|
||||
Style style)
|
||||
: CControl (size, nullptr, 0), offBitmap (nullptr), nbLed (nbLed), style (style)
|
||||
{
|
||||
setDecreaseStepValue (0.1f);
|
||||
|
||||
setOnBitmap (onBitmap);
|
||||
setOffBitmap (offBitmap);
|
||||
|
||||
rectOn (size.left, size.top, size.right, size.bottom);
|
||||
rectOff (size.left, size.top, size.right, size.bottom);
|
||||
|
||||
setWantsIdle (true);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CVuMeter::CVuMeter (const CVuMeter& v)
|
||||
: CControl (v)
|
||||
, offBitmap (nullptr)
|
||||
, nbLed (v.nbLed)
|
||||
, style (v.style)
|
||||
, decreaseValue (v.decreaseValue)
|
||||
, rectOn (v.rectOn)
|
||||
, rectOff (v.rectOff)
|
||||
{
|
||||
setOffBitmap (v.offBitmap);
|
||||
setWantsIdle (true);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CVuMeter::~CVuMeter () noexcept
|
||||
{
|
||||
setOnBitmap (nullptr);
|
||||
setOffBitmap (nullptr);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CVuMeter::setViewSize (const CRect& newSize, bool invalid)
|
||||
{
|
||||
CControl::setViewSize (newSize, invalid);
|
||||
rectOn = getViewSize ();
|
||||
rectOff = getViewSize ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool CVuMeter::sizeToFit ()
|
||||
{
|
||||
if (getDrawBackground ())
|
||||
{
|
||||
CRect vs (getViewSize ());
|
||||
vs.setWidth (getDrawBackground ()->getWidth ());
|
||||
vs.setHeight (getDrawBackground ()->getHeight ());
|
||||
setViewSize (vs);
|
||||
setMouseableArea (vs);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CVuMeter::setOffBitmap (CBitmap* bitmap)
|
||||
{
|
||||
if (offBitmap)
|
||||
offBitmap->forget ();
|
||||
offBitmap = bitmap;
|
||||
if (offBitmap)
|
||||
offBitmap->remember ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CVuMeter::setDirty (bool state)
|
||||
{
|
||||
CView::setDirty (state);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CVuMeter::onIdle ()
|
||||
{
|
||||
if (getOldValue () != value)
|
||||
invalid ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CVuMeter::draw (CDrawContext *_pContext)
|
||||
{
|
||||
if (!getOnBitmap ())
|
||||
return;
|
||||
|
||||
CRect _rectOn (rectOn);
|
||||
CRect _rectOff (rectOff);
|
||||
CPoint pointOn;
|
||||
CPoint pointOff;
|
||||
CDrawContext *pContext = _pContext;
|
||||
|
||||
bounceValue ();
|
||||
|
||||
float newValue = getOldValue () - decreaseValue;
|
||||
if (newValue < value)
|
||||
newValue = value;
|
||||
setOldValue (newValue);
|
||||
|
||||
newValue = (newValue - getMin ()) / getRange (); // normalize
|
||||
|
||||
if (style == Style::kHorizontal)
|
||||
{
|
||||
auto tmp = (CCoord)(((int32_t)(nbLed * newValue + 0.5f) / (float)nbLed) * getOnBitmap ()->getWidth ());
|
||||
pointOff (tmp, 0);
|
||||
|
||||
_rectOff.left += tmp;
|
||||
_rectOn.right = tmp + rectOn.left;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto tmp = (CCoord)(((int32_t)(nbLed * (1.f - newValue) + 0.5f) / (float)nbLed) * getOnBitmap ()->getHeight ());
|
||||
pointOn (0, tmp);
|
||||
|
||||
_rectOff.bottom = tmp + rectOff.top;
|
||||
_rectOn.top += tmp;
|
||||
}
|
||||
|
||||
if (getOffBitmap ())
|
||||
{
|
||||
getOffBitmap ()->draw (pContext, _rectOff, pointOff);
|
||||
}
|
||||
|
||||
getOnBitmap ()->draw (pContext, _rectOn, pointOn);
|
||||
|
||||
setDirty (false);
|
||||
}
|
||||
|
||||
} // VSTGUI
|
||||
@@ -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 "../enumbitset.h"
|
||||
#include "ccontrol.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CVuMeter Declaration
|
||||
//!
|
||||
/// @ingroup controls
|
||||
//-----------------------------------------------------------------------------
|
||||
class CVuMeter : public CControl
|
||||
{
|
||||
public:
|
||||
enum class Style : int32_t
|
||||
{
|
||||
kHorizontal,
|
||||
kVertical,
|
||||
};
|
||||
|
||||
CVuMeter (const CRect& size, CBitmap* onBitmap, CBitmap* offBitmap, int32_t nbLed,
|
||||
Style style = Style::kVertical);
|
||||
CVuMeter (const CVuMeter& vuMeter);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/// @name CVuMeter Methods
|
||||
//-----------------------------------------------------------------------------
|
||||
//@{
|
||||
float getDecreaseStepValue () const { return decreaseValue; }
|
||||
virtual void setDecreaseStepValue (float value) { decreaseValue = value; }
|
||||
|
||||
virtual CBitmap* getOnBitmap () const { return getBackground (); }
|
||||
virtual CBitmap* getOffBitmap () const { return offBitmap; }
|
||||
virtual void setOnBitmap (CBitmap* bitmap) { setBackground (bitmap); }
|
||||
virtual void setOffBitmap (CBitmap* bitmap);
|
||||
|
||||
int32_t getNbLed () const { return nbLed; }
|
||||
void setNbLed (int32_t nb) { nbLed = nb; invalid (); }
|
||||
|
||||
void setStyle (Style newStyle)
|
||||
{
|
||||
style = newStyle;
|
||||
invalid ();
|
||||
}
|
||||
Style getStyle () const { return style; }
|
||||
//@}
|
||||
|
||||
// overrides
|
||||
void setDirty (bool state) override;
|
||||
void draw (CDrawContext* pContext) override;
|
||||
void setViewSize (const CRect& newSize, bool invalid = true) override;
|
||||
bool sizeToFit () override;
|
||||
void onIdle () override;
|
||||
|
||||
CLASS_METHODS(CVuMeter, CControl)
|
||||
protected:
|
||||
~CVuMeter () noexcept override;
|
||||
|
||||
CBitmap* offBitmap;
|
||||
|
||||
int32_t nbLed;
|
||||
Style style;
|
||||
float decreaseValue;
|
||||
|
||||
CRect rectOn;
|
||||
CRect rectOff;
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,225 @@
|
||||
// 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 "cxypad.h"
|
||||
#include "../cdrawcontext.h"
|
||||
#include "../events.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CXYPad::CXYPad (const CRect& size)
|
||||
: CParamDisplay (size)
|
||||
, stopTrackingOnMouseExit (false)
|
||||
{
|
||||
CParamDisplay::setMax (2.f);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CXYPad::setHandleBitmap (CBitmap* bitmap)
|
||||
{
|
||||
handle = bitmap;
|
||||
invalid ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CBitmap* CXYPad::getHandleBitmap () const
|
||||
{
|
||||
return handle;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CXYPad::draw (CDrawContext* context)
|
||||
{
|
||||
drawBack (context);
|
||||
|
||||
auto width = getWidth () - getRoundRectRadius ();
|
||||
auto height = getHeight () - getRoundRectRadius ();
|
||||
|
||||
float x, y;
|
||||
calculateXY (getValue (), x, y);
|
||||
|
||||
CRect r (x*width, y*height, x*width, y*height);
|
||||
if (auto bitmap = getHandleBitmap ())
|
||||
{
|
||||
auto bitmapSize = bitmap->getSize ();
|
||||
r.extend (bitmapSize.x / 2., bitmapSize.y / 2.);
|
||||
r.offset (getViewSize ().left + getRoundRectRadius () / 2.,
|
||||
getViewSize ().top + getRoundRectRadius () / 2.);
|
||||
bitmap->draw (context, r);
|
||||
}
|
||||
else
|
||||
{
|
||||
r.extend (getRoundRectRadius () / 2., getRoundRectRadius () / 2.);
|
||||
r.offset (getViewSize ().left + getRoundRectRadius () / 2.,
|
||||
getViewSize ().top + getRoundRectRadius () / 2.);
|
||||
context->setFillColor (getFontColor ());
|
||||
context->setDrawMode (kAntiAliasing);
|
||||
context->drawEllipse (r, kDrawFilled);
|
||||
}
|
||||
setDirty (false);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CXYPad::drawBack (CDrawContext* context, CBitmap* newBack)
|
||||
{
|
||||
CParamDisplay::drawBack (context);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CXYPad::onMouseDownEvent (MouseDownEvent& event)
|
||||
{
|
||||
if (event.buttonState.isLeft ())
|
||||
{
|
||||
invalidMouseWheelEditTimer (this);
|
||||
mouseStartValue = getValue ();
|
||||
mouseChangeStartPoint = event.mousePosition;
|
||||
mouseChangeStartPoint.offset (-getViewSize ().left - getRoundRectRadius () / 2.,
|
||||
-getViewSize ().top - getRoundRectRadius () / 2.);
|
||||
beginEdit ();
|
||||
onMouseMove (event);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CXYPad::onMouseUpEvent (MouseUpEvent& event)
|
||||
{
|
||||
if (isEditing ())
|
||||
{
|
||||
endEdit ();
|
||||
event.consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CXYPad::onMouseCancelEvent (MouseCancelEvent &event)
|
||||
{
|
||||
if (isEditing ())
|
||||
{
|
||||
value = mouseStartValue;
|
||||
if (isDirty ())
|
||||
{
|
||||
valueChanged ();
|
||||
invalid ();
|
||||
}
|
||||
endEdit ();
|
||||
event.consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CXYPad::onMouseMoveEvent (MouseMoveEvent& event)
|
||||
{
|
||||
if (event.buttonState.isLeft () && isEditing ())
|
||||
{
|
||||
onMouseMove (event);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CXYPad::onMouseMove (MouseDownUpMoveEvent& event)
|
||||
{
|
||||
auto where = event.mousePosition;
|
||||
if (stopTrackingOnMouseExit)
|
||||
{
|
||||
if (!hitTest (where, event))
|
||||
{
|
||||
endEdit ();
|
||||
event.ignoreFollowUpMoveAndUpEvents (true);
|
||||
event.consumed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
float x, y;
|
||||
CCoord width = getWidth() - getRoundRectRadius ();
|
||||
CCoord height = getHeight() - getRoundRectRadius ();
|
||||
where.offset (-getViewSize ().left - getRoundRectRadius () / 2.,
|
||||
-getViewSize ().top - getRoundRectRadius () / 2.);
|
||||
|
||||
x = (float)(where.x / width);
|
||||
y = (float)(where.y / height);
|
||||
|
||||
boundValues (x, y);
|
||||
setValue (calculateValue (x, y));
|
||||
if (isDirty ())
|
||||
{
|
||||
valueChanged ();
|
||||
invalid ();
|
||||
}
|
||||
lastMouseChangePoint = where;
|
||||
event.consumed = true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CXYPad::onMouseWheelEvent (MouseWheelEvent& event)
|
||||
{
|
||||
float x, y;
|
||||
calculateXY (getValue (), x, y);
|
||||
|
||||
auto distanceX = static_cast<float> (event.deltaX) * getWheelInc ();
|
||||
auto distanceY = static_cast<float> (event.deltaY) * getWheelInc ();
|
||||
if (event.flags & MouseWheelEvent::DirectionInvertedFromDevice)
|
||||
{
|
||||
distanceX *= -1.f;
|
||||
distanceY *= -1.f;
|
||||
}
|
||||
if (event.modifiers.has (ModifierKey::Shift))
|
||||
{
|
||||
distanceX *= 0.1f;
|
||||
distanceY *= 0.1f;
|
||||
}
|
||||
x += distanceX;
|
||||
y += distanceY;
|
||||
boundValues (x, y);
|
||||
onMouseWheelEditing (this);
|
||||
setValue (calculateValue (x, y));
|
||||
if (isDirty ())
|
||||
{
|
||||
invalid ();
|
||||
valueChanged ();
|
||||
}
|
||||
event.consumed = true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CXYPad::onKeyboardEvent (KeyboardEvent& event)
|
||||
{
|
||||
if (event.type != EventType::KeyDown)
|
||||
return;
|
||||
if (event.virt == VirtualKey::Escape)
|
||||
{
|
||||
if (isEditing ())
|
||||
{
|
||||
onMouseCancel ();
|
||||
event.consumed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CXYPad::boundValues (float& x, float& y)
|
||||
{
|
||||
if (x < 0.f)
|
||||
x = 0.f;
|
||||
else if (x > 1.f)
|
||||
x = 1.f;
|
||||
if (y < 0.f)
|
||||
y = 0.f;
|
||||
else if (y > 1.f)
|
||||
y = 1.f;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CXYPad::setDefaultValue (float val)
|
||||
{
|
||||
CControl::setDefaultValue (calculateValue (val, val));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CXYPad::setDefaultValues (float x, float y)
|
||||
{
|
||||
CControl::setDefaultValue (calculateValue (x, y));
|
||||
}
|
||||
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,68 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cparamdisplay.h"
|
||||
#include "../cbitmap.h"
|
||||
#include <cmath>
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
class CXYPad : public CParamDisplay, protected CMouseWheelEditingSupport
|
||||
{
|
||||
public:
|
||||
explicit CXYPad (const CRect& size = CRect (0, 0, 0, 0));
|
||||
|
||||
void setStopTrackingOnMouseExit (bool state) { stopTrackingOnMouseExit = state; }
|
||||
bool getStopTrackingOnMouseExit () const { return stopTrackingOnMouseExit; }
|
||||
|
||||
void setHandleBitmap (CBitmap* bitmap);
|
||||
CBitmap* getHandleBitmap () const;
|
||||
|
||||
void draw (CDrawContext* context) override;
|
||||
void drawBack (CDrawContext* pContext, CBitmap* newBack = nullptr) override;
|
||||
|
||||
void onMouseDownEvent (MouseDownEvent& event) override;
|
||||
void onMouseUpEvent (MouseUpEvent& event) override;
|
||||
void onMouseMoveEvent (MouseMoveEvent& event) override;
|
||||
void onMouseCancelEvent (MouseCancelEvent& event) override;
|
||||
void onMouseWheelEvent (MouseWheelEvent& event) override;
|
||||
void onKeyboardEvent (KeyboardEvent& event) override;
|
||||
|
||||
/** set default value so that x and y default to val */
|
||||
void setDefaultValue (float val) override;
|
||||
/** set default value for x and y */
|
||||
void setDefaultValues (float x, float y);
|
||||
|
||||
static float calculateValue (float x, float y)
|
||||
{
|
||||
x = std::floor (x * 1000.f + 0.5f) * 0.001f;
|
||||
y = std::floor (y * 1000.f + 0.5f) * 0.0000001f;
|
||||
return x + y;
|
||||
}
|
||||
|
||||
static void calculateXY (float value, float& x, float& y)
|
||||
{
|
||||
x = std::floor (value * 1000.f + 0.5f) * 0.001f;
|
||||
y = std::floor ((value - x) * 10000000.f + 0.5f) * 0.001f;
|
||||
}
|
||||
|
||||
protected:
|
||||
void onMouseMove (MouseDownUpMoveEvent& event);
|
||||
|
||||
void setMin (float val) override { }
|
||||
void setMax (float val) override { }
|
||||
|
||||
void boundValues (float& x, float& y);
|
||||
|
||||
float mouseStartValue;
|
||||
CPoint mouseChangeStartPoint;
|
||||
CPoint lastMouseChangePoint;
|
||||
bool stopTrackingOnMouseExit;
|
||||
SharedPointer<CBitmap> handle;
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,33 @@
|
||||
// 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 {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
/** Command menu item target
|
||||
* @ingroup new_in_4_7
|
||||
*/
|
||||
class ICommandMenuItemTarget : public virtual IReference
|
||||
{
|
||||
public:
|
||||
/** called before the item is shown to validate its state */
|
||||
virtual bool validateCommandMenuItem (CCommandMenuItem* item) = 0;
|
||||
/** called when the item was selected */
|
||||
virtual bool onCommandMenuItemSelected (CCommandMenuItem* item) = 0;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
class CommandMenuItemTargetAdapter : public ICommandMenuItemTarget
|
||||
{
|
||||
public:
|
||||
bool validateCommandMenuItem (CCommandMenuItem* item) override { return false; }
|
||||
bool onCommandMenuItemSelected (CCommandMenuItem* item) override { return false; }
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // 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 "../vstguifwd.h"
|
||||
#include "../cbuttonstate.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
class IControlListener
|
||||
{
|
||||
public:
|
||||
virtual ~IControlListener () noexcept = default;
|
||||
virtual void valueChanged (CControl* pControl) = 0;
|
||||
/** return 1 if you want the control to not handle it, otherwise 0 */
|
||||
virtual int32_t controlModifierClicked (CControl* pControl, CButtonState button) { return 0; }
|
||||
virtual void controlBeginEdit (CControl* pControl) {}
|
||||
virtual void controlEndEdit (CControl* pControl) {}
|
||||
virtual void controlTagWillChange (CControl* pControl) {}
|
||||
virtual void controlTagDidChange (CControl* pControl) {}
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,50 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../vstguifwd.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Option menu listener
|
||||
* @ingroup new_in_4_7
|
||||
*/
|
||||
class IOptionMenuListener
|
||||
{
|
||||
public:
|
||||
/** called before the menu pops up */
|
||||
virtual void onOptionMenuPrePopup (COptionMenu* menu) = 0;
|
||||
/** called after the menu pops up */
|
||||
virtual void onOptionMenuPostPopup (COptionMenu* menu) = 0;
|
||||
/** called when the platform optionmenu returns the result and before the value of the option
|
||||
* menu is set.
|
||||
* @ingroup new_in_4_10
|
||||
*
|
||||
* @param menu the listened menu
|
||||
* @param selectedMenu the menu containing the selected item
|
||||
* @param selectedIndex the index of the selected item
|
||||
* @return return true to prevent further propagating the call to other listeners and to
|
||||
* prevent setting the value of the option menu
|
||||
*/
|
||||
virtual bool onOptionMenuSetPopupResult (COptionMenu* menu, COptionMenu* selectedMenu,
|
||||
int32_t selectedIndex) = 0;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
class OptionMenuListenerAdapter : public IOptionMenuListener
|
||||
{
|
||||
public:
|
||||
void onOptionMenuPrePopup (COptionMenu* menu) override {}
|
||||
void onOptionMenuPostPopup (COptionMenu* menu) override {}
|
||||
bool onOptionMenuSetPopupResult (COptionMenu* menu, COptionMenu* selectedMenu,
|
||||
int32_t selectedIndex) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // VSTGUI
|
||||
@@ -0,0 +1,33 @@
|
||||
// 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 {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
/** Listener for a text edit
|
||||
* @ingroup new_in_4_10
|
||||
*/
|
||||
class ITextEditListener
|
||||
{
|
||||
public:
|
||||
/** called when the native platform text edit control was created and started to listen for keyboard input. */
|
||||
virtual void onTextEditPlatformControlTookFocus (CTextEdit* textEdit) = 0;
|
||||
/** called when the natvie platform text edit control is going to be destroyed. */
|
||||
virtual void onTextEditPlatformControlLostFocus (CTextEdit* textEdit) = 0;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
class TextEditListenerAdapter : public ITextEditListener
|
||||
{
|
||||
public:
|
||||
void onTextEditPlatformControlTookFocus (CTextEdit* textEdit) override {}
|
||||
void onTextEditPlatformControlLostFocus (CTextEdit* textEdit) override {}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // VSTGUI
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user