Initial release
@@ -0,0 +1,140 @@
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")
|
||||
|
||||
include(vstgui_add_executable)
|
||||
|
||||
##########################################################################################
|
||||
set(target vstgui_standalone)
|
||||
|
||||
set(${target}_common_sources
|
||||
include/appinit.h
|
||||
include/doc.h
|
||||
include/fwd.h
|
||||
include/ialertbox.h
|
||||
include/iappdelegate.h
|
||||
include/iapplication.h
|
||||
include/iasync.h
|
||||
include/icommand.h
|
||||
include/icommondirectories.h
|
||||
include/imenubuilder.h
|
||||
include/interface.h
|
||||
include/ipreference.h
|
||||
include/ishareduiresources.h
|
||||
include/iuidescwindow.h
|
||||
include/ivalue.h
|
||||
include/ivaluelistener.h
|
||||
include/iwindow.h
|
||||
include/iwindowcontroller.h
|
||||
include/iwindowlistener.h
|
||||
include/helpers/appdelegate.h
|
||||
include/helpers/async.h
|
||||
include/helpers/menubuilder.h
|
||||
include/helpers/preferences.h
|
||||
include/helpers/value.h
|
||||
include/helpers/valuelistener.h
|
||||
include/helpers/windowcontroller.h
|
||||
include/helpers/windowlistener.h
|
||||
include/helpers/uidesc/modelbinding.h
|
||||
include/helpers/uidesc/customization.h
|
||||
source/application.cpp
|
||||
source/application.h
|
||||
source/async.cpp
|
||||
source/genericalertbox.cpp
|
||||
source/genericalertbox.h
|
||||
source/shareduiresources.cpp
|
||||
source/shareduiresources.h
|
||||
source/uidescriptionwindowcontroller.cpp
|
||||
source/window.cpp
|
||||
source/window.h
|
||||
source/platform/iplatformwindow.h
|
||||
source/helpers/value.cpp
|
||||
)
|
||||
|
||||
##########################################################################################
|
||||
set(${target}_mac_sources
|
||||
source/platform/mac/VSTGUICommand.h
|
||||
source/platform/mac/VSTGUICommand.mm
|
||||
source/platform/mac/macapplication.mm
|
||||
source/platform/mac/maccommondirectories.h
|
||||
source/platform/mac/maccommondirectories.mm
|
||||
source/platform/mac/macpreference.h
|
||||
source/platform/mac/macpreference.mm
|
||||
source/platform/mac/macutilities.h
|
||||
source/platform/mac/macwindow.h
|
||||
source/platform/mac/macwindow.mm
|
||||
source/platform/win32
|
||||
source/platform/gdk
|
||||
cmake/modules/
|
||||
)
|
||||
|
||||
##########################################################################################
|
||||
set(${target}_win32_sources
|
||||
source/platform/win32/win32application.cpp
|
||||
source/platform/win32/win32commondirectories.h
|
||||
source/platform/win32/win32commondirectories.cpp
|
||||
source/platform/win32/win32menu.cpp
|
||||
source/platform/win32/win32menu.h
|
||||
source/platform/win32/win32preference.cpp
|
||||
source/platform/win32/win32preference.h
|
||||
source/platform/win32/win32window.cpp
|
||||
source/platform/win32/win32window.h
|
||||
)
|
||||
|
||||
set(${target}_gdk_sources
|
||||
source/platform/gdk/gdkapplication.cpp
|
||||
source/platform/gdk/gdkapplication.h
|
||||
source/platform/gdk/gdkcommondirectories.cpp
|
||||
source/platform/gdk/gdkcommondirectories.h
|
||||
source/platform/gdk/gdkpreference.cpp
|
||||
source/platform/gdk/gdkpreference.h
|
||||
source/platform/gdk/gdkrunloop.cpp
|
||||
source/platform/gdk/gdkrunloop.h
|
||||
source/platform/gdk/gdkwindow.cpp
|
||||
source/platform/gdk/gdkwindow.h
|
||||
)
|
||||
|
||||
##########################################################################################
|
||||
if(CMAKE_HOST_APPLE)
|
||||
set(${target}_sources ${${target}_common_sources} ${${target}_mac_sources})
|
||||
|
||||
set_source_files_properties(${${target}_sources} PROPERTIES
|
||||
COMPILE_FLAGS "-fobjc-arc"
|
||||
)
|
||||
endif()
|
||||
|
||||
##########################################################################################
|
||||
if(MSVC)
|
||||
set(${target}_sources ${${target}_common_sources} ${${target}_win32_sources})
|
||||
endif()
|
||||
|
||||
##########################################################################################
|
||||
if(LINUX)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(SQLITE3 REQUIRED sqlite3)
|
||||
pkg_check_modules(ATKMM REQUIRED atkmm-1.6)
|
||||
|
||||
set(${target}_sources ${${target}_common_sources} ${${target}_gdk_sources})
|
||||
endif()
|
||||
|
||||
##########################################################################################
|
||||
add_library(${target} STATIC ${${target}_sources})
|
||||
|
||||
target_compile_definitions(${target} ${VSTGUI_COMPILE_DEFINITIONS})
|
||||
vstgui_set_cxx_version(${target} ${VSTGUI_CXX_VERSION})
|
||||
vstgui_source_group_by_folder(${target})
|
||||
|
||||
if(VSTGUI_STANDALONE_EXAMPLES)
|
||||
add_subdirectory(examples)
|
||||
endif()
|
||||
|
||||
if(LINUX)
|
||||
target_include_directories(${target} PRIVATE ${X11_INCLUDE_DIR})
|
||||
target_include_directories(${target} PRIVATE ${GTKMM3_INCLUDE_DIRS})
|
||||
target_include_directories(${target} PRIVATE ${ATKMM_INCLUDE_DIRS})
|
||||
target_include_directories(${target} PRIVATE ${FREETYPE_INCLUDE_DIRS})
|
||||
target_include_directories(${target} PRIVATE ${SQLITE3_INCLUDE_DIRS})
|
||||
target_link_libraries(${target} PRIVATE vstgui_uidescription ${LINUX_LIBRARIES} dl ${SQLITE3_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(CMAKE_HOST_APPLE)
|
||||
target_compile_options(${target} PRIVATE -Wall -Werror)
|
||||
endif()
|
||||
@@ -0,0 +1,138 @@
|
||||
###########################################################################################
|
||||
get_filename_component(PkgInfoResource "${CMAKE_CURRENT_SOURCE_DIR}/cmake/resources/PkgInfo" ABSOLUTE)
|
||||
|
||||
###########################################################################################
|
||||
if(LINUX)
|
||||
pkg_check_modules(GTKMM3 REQUIRED gtkmm-3.0)
|
||||
pkg_check_modules(ATKMM REQUIRED atkmm-1.6)
|
||||
endif(LINUX)
|
||||
|
||||
###########################################################################################
|
||||
function(vstgui_add_executable target sources)
|
||||
|
||||
if(MSVC)
|
||||
add_executable(${target} WIN32 ${sources})
|
||||
if(MSVC_CXX_ARCHITECTURE_ID MATCHES "^(x86|X86)$")
|
||||
set_target_properties(${target} PROPERTIES LINK_FLAGS "/INCLUDE:_wWinMain@16")
|
||||
elseif(MSVC_CXX_ARCHITECTURE_ID MATCHES "ARM64EC")
|
||||
set_target_properties(${target} PROPERTIES LINK_FLAGS "/INCLUDE:#wWinMain")
|
||||
else()
|
||||
set_target_properties(${target} PROPERTIES LINK_FLAGS "/INCLUDE:wWinMain")
|
||||
endif()
|
||||
get_target_property(OUTPUTDIR ${target} RUNTIME_OUTPUT_DIRECTORY)
|
||||
set_target_properties(${target} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${OUTPUTDIR}/${target}")
|
||||
endif(MSVC)
|
||||
|
||||
if(LINUX)
|
||||
add_executable(${target} ${sources})
|
||||
get_target_property(OUTPUTDIR ${target} RUNTIME_OUTPUT_DIRECTORY)
|
||||
set_target_properties(${target} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${OUTPUTDIR}/${target}")
|
||||
set(PLATFORM_LIBRARIES ${GTKMM3_LIBRARIES})
|
||||
endif(LINUX)
|
||||
|
||||
if(CMAKE_HOST_APPLE)
|
||||
set_source_files_properties(${PkgInfoResource} PROPERTIES
|
||||
MACOSX_PACKAGE_LOCATION "."
|
||||
)
|
||||
add_executable(${target} ${sources} ${PkgInfoResource})
|
||||
set_target_properties(${target} PROPERTIES
|
||||
MACOSX_BUNDLE TRUE
|
||||
XCODE_ATTRIBUTE_GENERATE_PKGINFO_FILE NO
|
||||
XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT $<$<CONFIG:Debug>:dwarf>$<$<NOT:$<CONFIG:Debug>>:dwarf-with-dsym>
|
||||
XCODE_ATTRIBUTE_DEPLOYMENT_POSTPROCESSING $<$<CONFIG:Debug>:NO>$<$<NOT:$<CONFIG:Debug>>:YES>
|
||||
OUTPUT_NAME "${target}"
|
||||
)
|
||||
endif(CMAKE_HOST_APPLE)
|
||||
|
||||
target_link_libraries(${target}
|
||||
PUBLIC
|
||||
vstgui
|
||||
vstgui_uidescription
|
||||
vstgui_standalone
|
||||
${PLATFORM_LIBRARIES}
|
||||
)
|
||||
target_compile_definitions(${target} ${VSTGUI_COMPILE_DEFINITIONS})
|
||||
|
||||
if(ARGC GREATER 2)
|
||||
vstgui_add_resources(${target} "${ARGV2}")
|
||||
message(DEPRECATION "Please use vstgui_add_resources to add resources to an executable now.")
|
||||
endif()
|
||||
|
||||
endfunction()
|
||||
|
||||
###########################################################################################
|
||||
function(vstgui_add_resources target resources)
|
||||
set(destination "Resources")
|
||||
if(ARGC GREATER 2)
|
||||
set(destination "${destination}/${ARGV2}")
|
||||
endif()
|
||||
if(CMAKE_HOST_APPLE)
|
||||
set_source_files_properties(${resources} PROPERTIES
|
||||
MACOSX_PACKAGE_LOCATION "${destination}"
|
||||
)
|
||||
target_sources(${target} PRIVATE ${resources})
|
||||
else()
|
||||
get_target_property(OUTPUTDIR ${target} RUNTIME_OUTPUT_DIRECTORY)
|
||||
set(destination "${OUTPUTDIR}/${destination}")
|
||||
foreach(resource ${resources})
|
||||
get_filename_component(resourceName "${resource}" NAME)
|
||||
get_filename_component(sourcePath "${resource}" ABSOLUTE "${CMAKE_CURRENT_LIST_DIR}")
|
||||
if(IS_DIRECTORY "${sourcePath}")
|
||||
get_filename_component(directoryName "${resource}" NAME)
|
||||
add_custom_command(TARGET ${target} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
"${sourcePath}"
|
||||
"${destination}/${directoryName}"
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-E echo
|
||||
"[VSTGUI] Copied directory ${sourcePath} to ${destination}"
|
||||
)
|
||||
else()
|
||||
add_custom_command(
|
||||
OUTPUT "${destination}/${resourceName}"
|
||||
MAIN_DEPENDENCY "${sourcePath}"
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory
|
||||
"${destination}"
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
"${sourcePath}"
|
||||
"${destination}"
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-E echo
|
||||
"[VSTGUI] Copied ${sourcePath} to ${destination}"
|
||||
)
|
||||
endif()
|
||||
endforeach(resource ${resources})
|
||||
target_sources(${target} PRIVATE ${resources})
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
###########################################################################################
|
||||
function(vstgui_set_target_bundle_id target identifier)
|
||||
if(CMAKE_HOST_APPLE)
|
||||
set_target_properties(${target} PROPERTIES
|
||||
XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER ${identifier}
|
||||
)
|
||||
endif(CMAKE_HOST_APPLE)
|
||||
target_compile_definitions(${target} PRIVATE VSTGUI_STANDALONE_APP_URI="${identifier}")
|
||||
endfunction()
|
||||
|
||||
###########################################################################################
|
||||
function(vstgui_set_target_infoplist target infoplist)
|
||||
if(CMAKE_HOST_APPLE)
|
||||
get_filename_component(InfoPlistFile "${infoplist}" ABSOLUTE)
|
||||
get_filename_component(IncludeDir "${InfoPlistFile}" DIRECTORY)
|
||||
set_target_properties(${target} PROPERTIES
|
||||
MACOSX_BUNDLE_INFO_PLIST ${InfoPlistFile}
|
||||
XCODE_ATTRIBUTE_INFOPLIST_PREPROCESS YES
|
||||
XCODE_ATTRIBUTE_INFOPLIST_OTHER_PREPROCESSOR_FLAGS "-I${IncludeDir}"
|
||||
XCODE_ATTRIBUTE_INFOPLIST_PREPROCESSOR_DEFINITIONS __plist_preprocessor__
|
||||
)
|
||||
endif(CMAKE_HOST_APPLE)
|
||||
endfunction()
|
||||
|
||||
###########################################################################################
|
||||
function(vstgui_set_target_rcfile target rcfile)
|
||||
if(MSVC)
|
||||
target_sources(${target} PRIVATE ${rcfile})
|
||||
endif(MSVC)
|
||||
endfunction()
|
||||
@@ -0,0 +1 @@
|
||||
APPL????
|
||||
@@ -0,0 +1,8 @@
|
||||
set(VSTGUI_STANDALONE_EXAMPLES_FOLDER FOLDER "VSTGUI Standalone Examples")
|
||||
|
||||
if(NOT MSVC_TOOLSET_VERSION OR MSVC_TOOLSET_VERSION VERSION_GREATER 140)
|
||||
add_subdirectory(mandelbrot)
|
||||
add_subdirectory(minesweeper)
|
||||
endif()
|
||||
add_subdirectory(simple_standalone)
|
||||
add_subdirectory(standalone)
|
||||
@@ -0,0 +1,36 @@
|
||||
##########################################################################################
|
||||
# VSTGUI Simple Standalone Application
|
||||
##########################################################################################
|
||||
set(target mandelbrot)
|
||||
|
||||
set(${target}_sources
|
||||
"source/mandelbrot.h"
|
||||
"source/mandelbrotapp.cpp"
|
||||
"source/mandelbrotview.cpp"
|
||||
"source/mandelbrotview.h"
|
||||
"source/mandelbrotwindow.cpp"
|
||||
"source/mandelbrotwindow.h"
|
||||
"source/modelbinding.h"
|
||||
)
|
||||
|
||||
set(mandelbrot_resources
|
||||
"resource/Window.uidesc"
|
||||
)
|
||||
|
||||
##########################################################################################
|
||||
if(CMAKE_HOST_APPLE)
|
||||
set(${target}_sources ${${target}_sources}
|
||||
"source/touchbarsupport.mm"
|
||||
"source/touchbarsupport.h"
|
||||
)
|
||||
endif()
|
||||
|
||||
##########################################################################################
|
||||
vstgui_add_executable(${target} "${${target}_sources}")
|
||||
vstgui_add_resources(${target} "${mandelbrot_resources}")
|
||||
vstgui_set_target_bundle_id(${target} "vstgui.examples.mandelbrot")
|
||||
vstgui_set_target_infoplist(${target} "resource/Info.plist")
|
||||
vstgui_set_target_rcfile(${target} "resource/mandelbrot.rc")
|
||||
vstgui_set_cxx_version(${target} ${VSTGUI_CXX_VERSION})
|
||||
target_include_directories(${target} PRIVATE ../../../../)
|
||||
set_target_properties(${target} PROPERTIES ${APP_PROPERTIES} ${VSTGUI_STANDALONE_EXAMPLES_FOLDER})
|
||||
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>mandelbrot</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>mandelbrot</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2016 Arne Scheffler. All rights reserved.</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1 @@
|
||||
BNDL????
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 54 KiB |
@@ -0,0 +1,139 @@
|
||||
// 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 "vstgui/lib/cpoint.h"
|
||||
#include "vstgui/lib/dispatchlist.h"
|
||||
#include <complex>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
namespace Mandelbrot {
|
||||
|
||||
using Point = VSTGUI::CPoint;
|
||||
using Complex = std::complex<double>;
|
||||
struct Model;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
struct IModelChangeListener
|
||||
{
|
||||
virtual void modelChanged (const Model& model) = 0;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
struct Model
|
||||
{
|
||||
using Ptr = std::shared_ptr<Model>;
|
||||
|
||||
void registerListener (IModelChangeListener* listener) { listeners.add (listener); }
|
||||
void unregisterListener (IModelChangeListener* listener) { listeners.remove (listener); }
|
||||
|
||||
const Point& getMax () const { return max; }
|
||||
const Point& getMin () const { return min; }
|
||||
uint32_t getIterations () const { return iterations; }
|
||||
|
||||
void setIterations (uint32_t newIterations)
|
||||
{
|
||||
if (newIterations != iterations)
|
||||
{
|
||||
iterations = newIterations;
|
||||
changed ();
|
||||
}
|
||||
}
|
||||
|
||||
void setMinMax (Point newMin, Point newMax)
|
||||
{
|
||||
if (max == newMax && min == newMin)
|
||||
return;
|
||||
max = newMax;
|
||||
min = newMin;
|
||||
changed ();
|
||||
}
|
||||
|
||||
private:
|
||||
void changed ()
|
||||
{
|
||||
listeners.forEach ([this] (auto& l) { l->modelChanged (*this); });
|
||||
}
|
||||
VSTGUI::DispatchList<IModelChangeListener*> listeners;
|
||||
|
||||
Point max {1.2, 1.7};
|
||||
Point min {-2.2, -1.7};
|
||||
uint32_t iterations {50};
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline Point pixelToPoint (Point max, Point min, Point size, Point pixel)
|
||||
{
|
||||
Point p;
|
||||
p.x = min.x + pixel.x / (size.x - 1.0) * (max.x - min.x);
|
||||
p.y = min.y + pixel.y / (size.y - 1.0) * (max.y - min.y);
|
||||
return p;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline double hypot (double x, double y)
|
||||
{
|
||||
return std::sqrt (x * x + y * y);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline Complex mulAdd (Complex z, Complex w, Complex v)
|
||||
{
|
||||
auto a = z.real ();
|
||||
auto b = z.imag ();
|
||||
auto c = w.real ();
|
||||
auto d = w.imag ();
|
||||
auto ac = a * c;
|
||||
auto bd = b * d;
|
||||
auto ad = a * d;
|
||||
auto bc = b * c;
|
||||
auto x = ac - bd;
|
||||
auto y = ad + bc;
|
||||
return Complex (x + v.real (), y + v.imag ());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template <typename SetPixelProc>
|
||||
inline void calculateLine (uint32_t line, Point size, const Model& model, SetPixelProc setPixel)
|
||||
{
|
||||
Point sizeInv (size);
|
||||
sizeInv -= {1, 1};
|
||||
sizeInv.x = 1. / sizeInv.x;
|
||||
sizeInv.y = 1. / sizeInv.y;
|
||||
Point diff;
|
||||
diff.x = model.getMax ().x - model.getMin ().x;
|
||||
diff.y = model.getMax ().y - model.getMin ().y;
|
||||
Point pos;
|
||||
pos.y = model.getMin ().y + line * sizeInv.y * diff.y;
|
||||
auto numIterations = static_cast<uint32_t> (size.x);
|
||||
std::vector<uint32_t> iterationResult (numIterations);
|
||||
for (auto x = 0u; x < numIterations; ++x)
|
||||
{
|
||||
pos.x = model.getMin ().x + x * sizeInv.x * diff.x;
|
||||
Complex c {pos.x, pos.y};
|
||||
Complex z {0};
|
||||
uint32_t iterations {};
|
||||
|
||||
for (; iterations < model.getIterations () && hypot (z.real (), z.imag ()) < 2.0;
|
||||
++iterations)
|
||||
z = mulAdd (z, z, c);
|
||||
iterationResult[x] = iterations;
|
||||
}
|
||||
for (auto x = 0u; x < size.x; ++x)
|
||||
setPixel (x, iterationResult[x]);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template <typename SetPixelProc>
|
||||
inline void calculate (Point size, const Model& model, SetPixelProc setPixel)
|
||||
{
|
||||
for (auto y = 0u; y < size.y; ++y)
|
||||
{
|
||||
calculateLine (y, size, model, setPixel);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // Mandelbrot
|
||||
@@ -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
|
||||
|
||||
#include "mandelbrotwindow.h"
|
||||
#include "vstgui/standalone/include/helpers/appdelegate.h"
|
||||
#include "vstgui/standalone/include/helpers/windowlistener.h"
|
||||
#include "vstgui/standalone/include/iapplication.h"
|
||||
#include "vstgui/standalone/include/icommand.h"
|
||||
#include "vstgui/standalone/include/iwindow.h"
|
||||
#include "vstgui/lib/platform/platformfactory.h"
|
||||
#include "vstgui/lib/platform/common/threadpooltaskexecutor.h"
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
namespace Mandelbrot {
|
||||
using namespace VSTGUI;
|
||||
using namespace VSTGUI::Standalone;
|
||||
using namespace VSTGUI::Standalone::Application;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
struct AppDelegate : DelegateAdapter, WindowListenerAdapter, ICommandHandler
|
||||
{
|
||||
AppDelegate () : DelegateAdapter ({"mandelbrot", "1.0.0", VSTGUI_STANDALONE_APP_URI}) {}
|
||||
|
||||
void finishLaunching () override
|
||||
{
|
||||
getPlatformFactory ().replaceTaskExecutor ([] (auto&& executor) {
|
||||
return std::make_unique<Tasks::ThreadPoolTaskExecutor> (std::move (executor));
|
||||
});
|
||||
IApplication::instance ().registerCommand (Commands::NewDocument, 'n');
|
||||
if (!handleCommand (Commands::NewDocument))
|
||||
IApplication::instance ().quit ();
|
||||
}
|
||||
|
||||
bool canHandleCommand (const Command& command) override
|
||||
{
|
||||
if (command == Commands::NewDocument)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool handleCommand (const Command& command) override
|
||||
{
|
||||
if (command == Commands::NewDocument)
|
||||
{
|
||||
if (auto window = makeMandelbrotWindow ())
|
||||
{
|
||||
window->show ();
|
||||
window->registerWindowListener (this);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void onClosed (const IWindow& window) override
|
||||
{
|
||||
if (IApplication::instance ().getWindows ().empty ())
|
||||
IApplication::instance ().quit ();
|
||||
}
|
||||
};
|
||||
|
||||
static Init gAppDelegate (std::make_unique<AppDelegate> ());
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // Mandelbrot
|
||||
@@ -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
|
||||
|
||||
#include "mandelbrotview.h"
|
||||
#include "vstgui/lib/cbitmap.h"
|
||||
#include "vstgui/lib/cdrawcontext.h"
|
||||
#include "vstgui/lib/cframe.h"
|
||||
#include "vstgui/lib/events.h"
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
namespace Mandelbrot {
|
||||
|
||||
using namespace VSTGUI;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
View::View (ChangedFunc&& func) : CView ({}), changed (std::move (func))
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMouseEventResult View::onMouseDown (CPoint& where, const CButtonState& buttons)
|
||||
{
|
||||
if (buttons.isLeftButton ())
|
||||
{
|
||||
setWantsFocus (true);
|
||||
getFrame ()->setFocusView (this);
|
||||
box.setTopLeft (where);
|
||||
box.setBottomRight (where);
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
return kMouseEventNotHandled;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMouseEventResult View::onMouseUp (CPoint& where, const CButtonState& buttons)
|
||||
{
|
||||
if (wantsFocus () && buttons.isLeftButton () && !box.isEmpty ())
|
||||
{
|
||||
if (changed)
|
||||
{
|
||||
CRect b {box};
|
||||
b.offsetInverse (getViewSize ().getTopLeft ());
|
||||
changed (b);
|
||||
}
|
||||
onMouseCancel ();
|
||||
}
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMouseEventResult View::onMouseMoved (CPoint& where, const CButtonState& buttons)
|
||||
{
|
||||
if (!wantsFocus () || !buttons.isLeftButton ())
|
||||
return kMouseEventNotHandled;
|
||||
CRect r (box);
|
||||
box.setBottomRight (where);
|
||||
r.unite (box);
|
||||
invalidRect (r);
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMouseEventResult View::onMouseCancel ()
|
||||
{
|
||||
invalidRect (box);
|
||||
box = {};
|
||||
setWantsFocus (false);
|
||||
getFrame ()->setFocusView (nullptr);
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void View::onKeyboardEvent (KeyboardEvent& event)
|
||||
{
|
||||
if (event.type == EventType::KeyDown && event.virt == VirtualKey::Escape)
|
||||
{
|
||||
onMouseCancel ();
|
||||
event.consumed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void View::draw (CDrawContext* context)
|
||||
{
|
||||
if (auto bitmap = getBackground ())
|
||||
{
|
||||
auto bitmapSize = bitmap->getSize ();
|
||||
CGraphicsTransform transform;
|
||||
transform.scale (getWidth () / bitmapSize.x, getHeight () / bitmapSize.y);
|
||||
transform.translate (getViewSize ().left, getViewSize ().top);
|
||||
CDrawContext::Transform t (*context, transform);
|
||||
bitmap->draw (context, CRect (0, 0, bitmapSize.x, bitmapSize.y));
|
||||
}
|
||||
if (box.isEmpty ())
|
||||
return;
|
||||
auto hairlineSize = context->getHairlineSize ();
|
||||
ConcatClip cc (*context, box);
|
||||
context->setLineWidth (hairlineSize);
|
||||
context->setDrawMode (kAliasing | kNonIntegralMode);
|
||||
context->setFrameColor (kBlackCColor);
|
||||
context->drawRect (box);
|
||||
CRect b2 (box);
|
||||
b2.inset (hairlineSize, hairlineSize);
|
||||
context->setFrameColor (kWhiteCColor);
|
||||
context->drawRect (b2);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // Mandelbrot
|
||||
@@ -0,0 +1,44 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "vstgui/lib/cview.h"
|
||||
#include "vstgui/lib/ifocusdrawing.h"
|
||||
#include <functional>
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
namespace Mandelbrot {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
struct View : public VSTGUI::CView, public VSTGUI::IFocusDrawing
|
||||
{
|
||||
using CRect = VSTGUI::CRect;
|
||||
using CPoint = VSTGUI::CPoint;
|
||||
using CMouseEventResult = VSTGUI::CMouseEventResult;
|
||||
using CButtonState = VSTGUI::CButtonState;
|
||||
using CDrawContext = VSTGUI::CDrawContext;
|
||||
using CGraphicsPath = VSTGUI::CGraphicsPath;
|
||||
using KeyboardEvent = VSTGUI::KeyboardEvent;
|
||||
using ChangedFunc = std::function<void (CRect box)>;
|
||||
|
||||
View (ChangedFunc&& func);
|
||||
|
||||
void onKeyboardEvent (KeyboardEvent& 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 draw (CDrawContext* context) override;
|
||||
|
||||
bool drawFocusOnTop () override { return false; }
|
||||
bool getFocusPath (CGraphicsPath& outPath) override { return false; }
|
||||
|
||||
private:
|
||||
CRect box;
|
||||
ChangedFunc changed;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // Mandelbrot
|
||||
@@ -0,0 +1,404 @@
|
||||
// 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 "mandelbrot.h"
|
||||
#include "mandelbrotview.h"
|
||||
#include "mandelbrotwindow.h"
|
||||
#include "modelbinding.h"
|
||||
#include "touchbarsupport.h"
|
||||
#include "vstgui/lib/animation/animations.h"
|
||||
#include "vstgui/lib/animation/ianimationtarget.h"
|
||||
#include "vstgui/lib/animation/timingfunctions.h"
|
||||
#include "vstgui/lib/cbitmap.h"
|
||||
#include "vstgui/lib/ccolor.h"
|
||||
#include "vstgui/lib/cfileselector.h"
|
||||
#include "vstgui/lib/cframe.h"
|
||||
#include "vstgui/lib/controls/ccontrol.h"
|
||||
#include "vstgui/lib/iscalefactorchangedlistener.h"
|
||||
#include "vstgui/lib/iviewlistener.h"
|
||||
#include "vstgui/lib/platform/platformfactory.h"
|
||||
#include "vstgui/standalone/include/helpers/async.h"
|
||||
#include "vstgui/standalone/include/helpers/uidesc/customization.h"
|
||||
#include "vstgui/standalone/include/helpers/value.h"
|
||||
#include "vstgui/standalone/include/helpers/valuelistener.h"
|
||||
#include "vstgui/standalone/include/helpers/windowcontroller.h"
|
||||
#include "vstgui/standalone/include/iapplication.h"
|
||||
#include "vstgui/standalone/include/iuidescwindow.h"
|
||||
#include "vstgui/uidescription/cstream.h"
|
||||
#include "vstgui/uidescription/delegationcontroller.h"
|
||||
#include "vstgui/uidescription/iuidescription.h"
|
||||
#include "vstgui/uidescription/uiattributes.h"
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <thread>
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
namespace Mandelbrot {
|
||||
|
||||
using namespace VSTGUI;
|
||||
using namespace VSTGUI::Standalone;
|
||||
using namespace VSTGUI::Standalone::Application;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline CColor calculateColor (uint32_t iteration, double maxIterationInv)
|
||||
{
|
||||
CColor color;
|
||||
const auto t = static_cast<double> (iteration) * maxIterationInv;
|
||||
color.setNormRed (9. * (1. - t) * t * t * t);
|
||||
color.setNormGreen (15. * (1. - t) * (1. - t) * t * t);
|
||||
color.setNormBlue (8.5 * (1. - t) * (1. - t) * (1. - t) * t);
|
||||
return color;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline std::function<uint32_t (CColor)> getColorToInt32 (IPlatformBitmapPixelAccess::PixelFormat f)
|
||||
{
|
||||
switch (f)
|
||||
{
|
||||
case IPlatformBitmapPixelAccess::kARGB:
|
||||
{
|
||||
return [] (CColor color) {
|
||||
return (color.red << 8) | (color.green << 16) | (color.blue << 24) | (color.alpha);
|
||||
};
|
||||
break;
|
||||
}
|
||||
case IPlatformBitmapPixelAccess::kABGR:
|
||||
{
|
||||
return [] (CColor color) {
|
||||
return (color.blue << 8) | (color.green << 16) | (color.red << 24) | (color.alpha);
|
||||
};
|
||||
break;
|
||||
}
|
||||
case IPlatformBitmapPixelAccess::kRGBA:
|
||||
{
|
||||
return [] (CColor color) {
|
||||
return (color.red) | (color.green << 8) | (color.blue << 16) | (color.alpha << 24);
|
||||
};
|
||||
break;
|
||||
}
|
||||
//case IPlatformBitmapPixelAccess::kBGRA:
|
||||
default:
|
||||
{
|
||||
return [] (CColor color) {
|
||||
return (color.blue) | (color.green << 8) | (color.red << 16) | (color.alpha << 24);
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template <typename ReadyCallback>
|
||||
inline void calculateMandelbrotBitmap (Model model, SharedPointer<CBitmap> bitmap, CPoint size,
|
||||
uint32_t id, const std::atomic<uint32_t>& taskID,
|
||||
ReadyCallback readyCallback)
|
||||
{
|
||||
if (auto pa = owned (CBitmapPixelAccess::create (bitmap)))
|
||||
{
|
||||
const auto numLinesPerTask =
|
||||
static_cast<uint32_t> (size.y / (std::thread::hardware_concurrency () * 8));
|
||||
|
||||
const auto maxIterationInv = 1. / model.getIterations ();
|
||||
|
||||
auto asyncGroup = Async::Group::make (Async::backgroundQueue ());
|
||||
|
||||
auto pixelAccess = shared (pa->getPlatformBitmapPixelAccess ());
|
||||
auto colorToInt32 = getColorToInt32 (pixelAccess->getPixelFormat ());
|
||||
for (auto y = 0u; y < static_cast<uint32_t> (size.y); y += numLinesPerTask)
|
||||
{
|
||||
auto task = [=, &taskID] () {
|
||||
for (auto i = 0u; i < numLinesPerTask; ++i)
|
||||
{
|
||||
if (y + i >= size.y || taskID != id)
|
||||
break;
|
||||
auto pixelPtr = reinterpret_cast<uint32_t*> (
|
||||
pixelAccess->getAddress () + (y + i) * pixelAccess->getBytesPerRow ());
|
||||
calculateLine (y + i, size, model, [&] (auto x, auto iteration) {
|
||||
auto color = calculateColor (iteration, maxIterationInv);
|
||||
*pixelPtr = colorToInt32 (color);
|
||||
pixelPtr++;
|
||||
});
|
||||
}
|
||||
};
|
||||
asyncGroup->add (std::move (task));
|
||||
}
|
||||
|
||||
asyncGroup->start ([callback = std::move (readyCallback), bitmap, id] () {
|
||||
Async::schedule (Async::mainQueue (),
|
||||
[call = std::move (callback), bitmap, id] () { call (id, bitmap); });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
struct ProgressController : DelegationController, ValueListenerAdapter
|
||||
{
|
||||
ProgressController (ValuePtr progressValue, IController* parent)
|
||||
: DelegationController (parent), progressValue (progressValue)
|
||||
{
|
||||
progressValue->registerListener (this);
|
||||
}
|
||||
|
||||
~ProgressController () noexcept override { progressValue->unregisterListener (this); }
|
||||
|
||||
CView* verifyView (CView* view, const UIAttributes& attributes,
|
||||
const IUIDescription* description) override
|
||||
{
|
||||
assert (control == nullptr);
|
||||
control = dynamic_cast<CControl*> (view);
|
||||
assert (control);
|
||||
|
||||
return controller->verifyView (view, attributes, description);
|
||||
}
|
||||
|
||||
void onPerformEdit (IValue& value, IValue::Type newValue) override
|
||||
{
|
||||
if (!control || !control->isAttached ())
|
||||
return;
|
||||
|
||||
if (newValue >= 0.5)
|
||||
{
|
||||
control->setValue (0.f);
|
||||
auto tf = new Animation::LinearTimingFunction (800);
|
||||
control->addAnimation ("Animation", new Animation::ControlValueAnimation (1.f),
|
||||
new Animation::RepeatTimingFunction (tf, -1, false));
|
||||
control->setAlphaValue (0.f);
|
||||
control->addAnimation ("Alpha", new Animation::AlphaValueAnimation (1.f),
|
||||
new Animation::CubicBezierTimingFunction (
|
||||
Animation::CubicBezierTimingFunction::easyIn (200)));
|
||||
}
|
||||
else
|
||||
{
|
||||
control->addAnimation (
|
||||
"Alpha", new Animation::AlphaValueAnimation (0.f),
|
||||
new Animation::CubicBezierTimingFunction (
|
||||
Animation::CubicBezierTimingFunction::easyOut (100)),
|
||||
[] (CView* view, const IdStringPtr, Animation::IAnimationTarget*) {
|
||||
view->removeAnimation ("Animation");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
CControl* control {nullptr};
|
||||
ValuePtr progressValue;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
struct ViewController : DelegationController,
|
||||
ViewListenerAdapter,
|
||||
IModelChangeListener,
|
||||
IScaleFactorChangedListener,
|
||||
AtomicReferenceCounted
|
||||
{
|
||||
ViewController (IController* parent, Model::Ptr model, ValuePtr progressValue)
|
||||
: DelegationController (parent), model (model), progressValue (progressValue)
|
||||
{
|
||||
model->registerListener (this);
|
||||
}
|
||||
~ViewController () noexcept override { model->unregisterListener (this); }
|
||||
|
||||
CView* createView (const UIAttributes& attributes, const IUIDescription* description) override
|
||||
{
|
||||
if (auto name = attributes.getAttributeValue (IUIDescription::kCustomViewName))
|
||||
{
|
||||
if (*name == "MandelbrotView")
|
||||
{
|
||||
mandelbrotView = new View ([&] (auto box) {
|
||||
auto min =
|
||||
pixelToPoint (model->getMax (), model->getMin (),
|
||||
mandelbrotView->getViewSize ().getSize (), box.getTopLeft ());
|
||||
auto max = pixelToPoint (model->getMax (), model->getMin (),
|
||||
mandelbrotView->getViewSize ().getSize (),
|
||||
box.getBottomRight ());
|
||||
model->setMinMax (min, max);
|
||||
});
|
||||
mandelbrotView->registerViewListener (this);
|
||||
return mandelbrotView;
|
||||
}
|
||||
}
|
||||
return controller->createView (attributes, description);
|
||||
}
|
||||
|
||||
IController* createSubController (IdStringPtr name, const IUIDescription* description) override
|
||||
{
|
||||
if (UTF8StringView (name) == "ProgressController")
|
||||
return new ProgressController (progressValue, this);
|
||||
return controller->createSubController (name, description);
|
||||
}
|
||||
|
||||
void viewSizeChanged (CView* view, const CRect& oldSize) override { updateMandelbrot (); }
|
||||
void viewAttached (CView* view) override
|
||||
{
|
||||
if (auto frame = view->getFrame ())
|
||||
{
|
||||
frame->registerScaleFactorChangedListener (this);
|
||||
scaleFactor = frame->getScaleFactor ();
|
||||
updateMandelbrot ();
|
||||
}
|
||||
}
|
||||
void viewRemoved (CView* view) override
|
||||
{
|
||||
if (auto frame = view->getFrame ())
|
||||
{
|
||||
frame->unregisterScaleFactorChangedListener (this);
|
||||
}
|
||||
}
|
||||
void viewWillDelete (CView* view) override
|
||||
{
|
||||
assert (mandelbrotView == view);
|
||||
++taskID; // cancel background calculation
|
||||
mandelbrotView->unregisterViewListener (this);
|
||||
mandelbrotView = nullptr;
|
||||
}
|
||||
|
||||
void onScaleFactorChanged (CFrame* frame, double newScaleFactor) override
|
||||
{
|
||||
if (scaleFactor != newScaleFactor)
|
||||
{
|
||||
scaleFactor = newScaleFactor;
|
||||
updateMandelbrot ();
|
||||
}
|
||||
}
|
||||
|
||||
void modelChanged (const Model&) override { updateMandelbrot (); }
|
||||
|
||||
void updateMandelbrot ()
|
||||
{
|
||||
CPoint size = mandelbrotView->getViewSize ().getSize ();
|
||||
size.x *= scaleFactor;
|
||||
size.y *= scaleFactor;
|
||||
size.makeIntegral ();
|
||||
if (size.x == 0 || size.y == 0)
|
||||
return;
|
||||
Value::performSingleEdit (*progressValue, 1.);
|
||||
auto bitmap = makeOwned<CBitmap> (size.x, size.y);
|
||||
bitmap->getPlatformBitmap ()->setScaleFactor (scaleFactor);
|
||||
auto id = ++taskID;
|
||||
auto This = shared (this);
|
||||
calculateMandelbrotBitmap (*model.get (), bitmap, size, id, taskID,
|
||||
[This] (uint32_t id, SharedPointer<CBitmap> bitmap) {
|
||||
if (id == This->taskID && This->mandelbrotView)
|
||||
{
|
||||
This->mandelbrotView->setBackground (bitmap);
|
||||
Value::performSingleEdit (*This->progressValue, 0.);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void saveBitmap (OutputStream& stream)
|
||||
{
|
||||
if (auto bitmap = mandelbrotView->getBackground ())
|
||||
{
|
||||
if (auto platformBitmap = bitmap->getPlatformBitmap ())
|
||||
{
|
||||
auto bytes =
|
||||
getPlatformFactory ().createBitmapMemoryPNGRepresentation (platformBitmap);
|
||||
if (!bytes.empty ())
|
||||
{
|
||||
stream.writeRaw (bytes.data (), static_cast<uint32_t> (bytes.size ()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Model::Ptr model;
|
||||
ValuePtr progressValue;
|
||||
CControl* progressControl {nullptr};
|
||||
CView* mandelbrotView {nullptr};
|
||||
double scaleFactor {1.};
|
||||
std::atomic<uint32_t> taskID {0};
|
||||
};
|
||||
|
||||
static const Command saveCommand {"File", "Save Bitmap"};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
struct WindowCustomization : public UIDesc::Customization,
|
||||
public WindowControllerAdapter,
|
||||
public ICommandHandler
|
||||
{
|
||||
static std::shared_ptr<WindowCustomization> make (const ValuePtr& maxIterations)
|
||||
{
|
||||
auto obj = std::make_shared<WindowCustomization> ();
|
||||
obj->maxIterations = maxIterations;
|
||||
return obj;
|
||||
}
|
||||
|
||||
void onSetContentView (IWindow& window, const SharedPointer<CFrame>& contentView) override
|
||||
{
|
||||
frame = contentView;
|
||||
if (!contentView)
|
||||
return;
|
||||
if (auto touchBarExt =
|
||||
dynamic_cast<IPlatformFrameTouchBarExtension*> (contentView->getPlatformFrame ()))
|
||||
{
|
||||
installTouchbarSupport (touchBarExt, maxIterations);
|
||||
}
|
||||
}
|
||||
|
||||
bool canHandleCommand (const Command& command) override
|
||||
{
|
||||
if (frame && command == saveCommand)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
bool handleCommand (const Command& command) override
|
||||
{
|
||||
if (frame && command == saveCommand)
|
||||
{
|
||||
if (auto fs =
|
||||
owned (CNewFileSelector::create (frame, CNewFileSelector::kSelectSaveFile)))
|
||||
{
|
||||
fs->addFileExtension ({"PNG File", "png", "image/png"});
|
||||
fs->run ([frame = shared (frame)] (CNewFileSelector * fs) {
|
||||
if (fs->getNumSelectedFiles () == 0)
|
||||
return;
|
||||
if (auto controller = findViewController<ViewController> (frame))
|
||||
{
|
||||
auto path = fs->getSelectedFile (0);
|
||||
assert (path != nullptr);
|
||||
CFileStream stream;
|
||||
if (!stream.open (path, CFileStream::kWriteMode | CFileStream::kBinaryMode |
|
||||
CFileStream::kTruncateMode))
|
||||
return;
|
||||
controller->saveBitmap (stream);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ValuePtr maxIterations;
|
||||
CFrame* frame {nullptr};
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
VSTGUI::Standalone::WindowPtr makeMandelbrotWindow ()
|
||||
{
|
||||
IApplication::instance ().registerCommand (saveCommand, 0);
|
||||
|
||||
auto model = std::make_shared<Model> ();
|
||||
auto modelBinding = ModelBinding::make (model);
|
||||
auto customization = WindowCustomization::make (modelBinding->getMaxIterationsValue ());
|
||||
|
||||
customization->addCreateViewControllerFunc (
|
||||
"mandelbrotviewcontroller", [=] (const auto& name, auto parent, const auto uiDesc) {
|
||||
return new ViewController (parent, model, modelBinding->getProgressValue ());
|
||||
});
|
||||
|
||||
UIDesc::Config config;
|
||||
config.uiDescFileName = "Window.uidesc";
|
||||
config.viewName = "Window";
|
||||
config.modelBinding = modelBinding;
|
||||
config.customization = customization;
|
||||
config.windowConfig.title = "Mandelbrot";
|
||||
config.windowConfig.autoSaveFrameName = "Mandelbrot";
|
||||
config.windowConfig.groupIdentifier = "Mandelbrot";
|
||||
config.windowConfig.style.border ().close ().size ().centered ();
|
||||
return UIDesc::makeWindow (config);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // Mandelbrot
|
||||
@@ -0,0 +1,15 @@
|
||||
// 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 "vstgui/standalone/include/fwd.h"
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
namespace Mandelbrot {
|
||||
|
||||
VSTGUI::Standalone::WindowPtr makeMandelbrotWindow ();
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // Mandelbrot
|
||||
@@ -0,0 +1,102 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "vstgui/standalone/include/helpers/value.h"
|
||||
#include "vstgui/standalone/include/helpers/valuelistener.h"
|
||||
#include "vstgui/standalone/include/iuidescwindow.h"
|
||||
|
||||
namespace Mandelbrot {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
struct ModelBinding : VSTGUI::Standalone::UIDesc::IModelBinding,
|
||||
VSTGUI::Standalone::ValueListenerAdapter,
|
||||
IModelChangeListener
|
||||
{
|
||||
using Ptr = std::shared_ptr<ModelBinding>;
|
||||
using IValue = VSTGUI::Standalone::IValue;
|
||||
using ValuePtr = VSTGUI::Standalone::ValuePtr;
|
||||
using ValueConverterPtr = VSTGUI::Standalone::ValueConverterPtr;
|
||||
|
||||
static Ptr make (Model::Ptr model) { return std::make_shared<ModelBinding> (model); }
|
||||
|
||||
ModelBinding (Model::Ptr model) : model (model)
|
||||
{
|
||||
using namespace VSTGUI::Standalone;
|
||||
Value::performSingleStepEdit (*maxIterations.get (), model->getIterations ());
|
||||
|
||||
values.emplace_back (maxIterations);
|
||||
values.emplace_back (minX);
|
||||
values.emplace_back (minY);
|
||||
values.emplace_back (maxX);
|
||||
values.emplace_back (maxY);
|
||||
values.emplace_back (progressValue);
|
||||
values.emplace_back (showParams);
|
||||
|
||||
maxIterations->registerListener (this);
|
||||
minX->registerListener (this);
|
||||
minY->registerListener (this);
|
||||
maxX->registerListener (this);
|
||||
maxY->registerListener (this);
|
||||
|
||||
model->registerListener (this);
|
||||
}
|
||||
|
||||
const ValueList& getValues () const override { return values; }
|
||||
|
||||
void modelChanged (const Model& m) override
|
||||
{
|
||||
using namespace VSTGUI::Standalone;
|
||||
Value::performSingleStepEdit (*maxIterations.get (), m.getIterations ());
|
||||
Value::performSinglePlainEdit (*minX.get (), m.getMin ().x);
|
||||
Value::performSinglePlainEdit (*minY.get (), m.getMin ().y);
|
||||
Value::performSinglePlainEdit (*maxX.get (), m.getMax ().x);
|
||||
Value::performSinglePlainEdit (*maxY.get (), m.getMax ().y);
|
||||
}
|
||||
|
||||
void onPerformEdit (IValue& value, IValue::Type newValue) override
|
||||
{
|
||||
using namespace VSTGUI::Standalone;
|
||||
if (&value == maxIterations.get ())
|
||||
{
|
||||
auto step = Value::currentStepValue (*maxIterations.get ());
|
||||
if (step < 1)
|
||||
step = 1;
|
||||
if (step != IStepValue::InvalidStep)
|
||||
model->setIterations (step);
|
||||
return;
|
||||
}
|
||||
auto min = model->getMin ();
|
||||
auto max = model->getMax ();
|
||||
if (&value == maxX.get ())
|
||||
max.x = Value::currentPlainValue (value);
|
||||
else if (&value == maxY.get ())
|
||||
max.y = Value::currentPlainValue (value);
|
||||
else if (&value == minX.get ())
|
||||
min.x = Value::currentPlainValue (value);
|
||||
else if (&value == minY.get ())
|
||||
min.y = Value::currentPlainValue (value);
|
||||
model->setMinMax (min, max);
|
||||
}
|
||||
|
||||
const ValuePtr& getProgressValue () const { return progressValue; }
|
||||
const ValuePtr& getMaxIterationsValue () const { return maxIterations; }
|
||||
private:
|
||||
static constexpr auto numMaxIterations = 2048u;
|
||||
ValueConverterPtr xConverter {VSTGUI::Standalone::Value::makeRangeConverter (-2.2, 1.2)};
|
||||
ValueConverterPtr yConverter {VSTGUI::Standalone::Value::makeRangeConverter (-1.7, 1.7)};
|
||||
|
||||
ValuePtr maxIterations {VSTGUI::Standalone::Value::makeStepValue ("max interations", numMaxIterations)};
|
||||
ValuePtr minX {VSTGUI::Standalone::Value::make ("minX", 0., xConverter)};
|
||||
ValuePtr minY {VSTGUI::Standalone::Value::make ("minY", 0., yConverter)};
|
||||
ValuePtr maxX {VSTGUI::Standalone::Value::make ("maxX", 1., xConverter)};
|
||||
ValuePtr maxY {VSTGUI::Standalone::Value::make ("maxY", 1., yConverter)};
|
||||
ValuePtr progressValue {VSTGUI::Standalone::Value::make ("progress")};
|
||||
ValuePtr showParams {VSTGUI::Standalone::Value::make ("showParams")};
|
||||
ValueList values;
|
||||
|
||||
Model::Ptr model;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
// 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 "vstgui/lib/animation/animations.h"
|
||||
#include "vstgui/lib/animation/ianimationtarget.h"
|
||||
#include "vstgui/lib/animation/timingfunctions.h"
|
||||
#include "vstgui/lib/cdrawcontext.h"
|
||||
#include "vstgui/lib/controls/ccontrol.h"
|
||||
#include "vstgui/uidescription/detail/uiviewcreatorattributes.h"
|
||||
#include "vstgui/uidescription/iviewcreator.h"
|
||||
#include "vstgui/uidescription/uiattributes.h"
|
||||
#include "vstgui/uidescription/uiviewfactory.h"
|
||||
#include <chrono>
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
namespace Mandelbrot {
|
||||
|
||||
using namespace VSTGUI;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
class ProgressIndicatorAnimation : public Animation::IAnimationTarget
|
||||
{
|
||||
public:
|
||||
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;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
class ProgressIndicatorView : public CControl
|
||||
{
|
||||
public:
|
||||
ProgressIndicatorView () : CControl ({}, nullptr, -1) {}
|
||||
|
||||
void draw (CDrawContext* context) override;
|
||||
void setRotation (double r);
|
||||
double getRotation () const { return rotation; }
|
||||
void setRotationTime (uint32_t t);
|
||||
uint32_t getRotationTime () const { return rotationTime; }
|
||||
CLASS_METHODS_NOCOPY (ProgressIndicatorView, CControl)
|
||||
private:
|
||||
void setValue (float val) override;
|
||||
|
||||
double rotation {0.};
|
||||
uint32_t rotationTime {1000};
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void ProgressIndicatorView::draw (CDrawContext* context)
|
||||
{
|
||||
CDrawContext::Transform t (
|
||||
*context, CGraphicsTransform ().rotate (rotation, getViewSize ().getCenter ()));
|
||||
CView::draw (context);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void ProgressIndicatorView::setRotation (double r)
|
||||
{
|
||||
rotation = r;
|
||||
invalid ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void ProgressIndicatorView::setRotationTime (uint32_t t)
|
||||
{
|
||||
rotationTime = t;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void ProgressIndicatorView::setValue (float val)
|
||||
{
|
||||
if (val == getValue ())
|
||||
return;
|
||||
CControl::setValue (val);
|
||||
if (!isAttached ())
|
||||
return;
|
||||
|
||||
bool animActive = getValueNormalized () >= 0.5;
|
||||
if (animActive)
|
||||
{
|
||||
auto tf = new Animation::LinearTimingFunction (rotationTime);
|
||||
addAnimation ("Animation", new ProgressIndicatorAnimation (),
|
||||
new Animation::RepeatTimingFunction (tf, -1, false));
|
||||
setAlphaValue (0.f);
|
||||
addAnimation ("Alpha", new Animation::AlphaValueAnimation (1.f),
|
||||
new Animation::LinearTimingFunction (200));
|
||||
}
|
||||
else
|
||||
{
|
||||
addAnimation ("Alpha", new Animation::AlphaValueAnimation (0.f),
|
||||
new Animation::LinearTimingFunction (80),
|
||||
[] (CView* view, const IdStringPtr, Animation::IAnimationTarget*) {
|
||||
view->removeAnimation ("Animation");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void ProgressIndicatorAnimation::animationStart (CView* view, IdStringPtr name)
|
||||
{
|
||||
static_cast<ProgressIndicatorView*> (view)->setRotation (0.);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void ProgressIndicatorAnimation::animationTick (CView* view, IdStringPtr name, float pos)
|
||||
{
|
||||
static_cast<ProgressIndicatorView*> (view)->setRotation (360. * static_cast<double> (pos));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void ProgressIndicatorAnimation::animationFinished (CView* view, IdStringPtr name, bool wasCanceled)
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
class ProgressIndicatorViewCreator : public ViewCreatorAdapter
|
||||
{
|
||||
public:
|
||||
const std::string kAttrRotation {"rotation"};
|
||||
const std::string kAttrRotationTime {"rotation-time"};
|
||||
|
||||
ProgressIndicatorViewCreator () { UIViewFactory::registerViewCreator (*this); }
|
||||
IdStringPtr getViewName () const override { return "ProgressIndicatorView"; }
|
||||
IdStringPtr getBaseViewName () const override { return UIViewCreator::kCControl; }
|
||||
UTF8StringPtr getDisplayName () const override { return "Progress Indicator View"; }
|
||||
CView* create (const UIAttributes& attributes, const IUIDescription* description) const override
|
||||
{
|
||||
return new ProgressIndicatorView ();
|
||||
}
|
||||
bool apply (CView* view, const UIAttributes& attributes,
|
||||
const IUIDescription* description) const override
|
||||
{
|
||||
auto piv = dynamic_cast<ProgressIndicatorView*> (view);
|
||||
if (!piv)
|
||||
return false;
|
||||
double rotation = 0.;
|
||||
if (attributes.getDoubleAttribute (kAttrRotation, rotation))
|
||||
piv->setRotation (rotation);
|
||||
int32_t time = 0;
|
||||
if (attributes.getIntegerAttribute (kAttrRotationTime, time))
|
||||
piv->setRotationTime (static_cast<uint32_t> (time));
|
||||
return true;
|
||||
}
|
||||
bool getAttributeNames (std::list<std::string>& attributeNames) const override
|
||||
{
|
||||
attributeNames.emplace_back (kAttrRotation);
|
||||
attributeNames.emplace_back (kAttrRotationTime);
|
||||
return true;
|
||||
}
|
||||
AttrType getAttributeType (const std::string& attributeName) const override
|
||||
{
|
||||
if (attributeName == kAttrRotation)
|
||||
return kFloatType;
|
||||
if (attributeName == kAttrRotationTime)
|
||||
return kIntegerType;
|
||||
return kUnknownType;
|
||||
}
|
||||
bool getAttributeValue (CView* view, const std::string& attributeName, std::string& stringValue,
|
||||
const IUIDescription* desc) const override
|
||||
{
|
||||
auto piv = dynamic_cast<ProgressIndicatorView*> (view);
|
||||
if (!piv)
|
||||
return false;
|
||||
if (attributeName == kAttrRotation)
|
||||
{
|
||||
stringValue = std::to_string (piv->getRotation ());
|
||||
return true;
|
||||
}
|
||||
if (attributeName == kAttrRotationTime)
|
||||
{
|
||||
stringValue = std::to_string (piv->getRotationTime ());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool getAttributeValueRange (const std::string& attributeName, double& minValue,
|
||||
double& maxValue) const override
|
||||
{
|
||||
if (attributeName == kAttrRotation)
|
||||
{
|
||||
minValue = 0.;
|
||||
maxValue = 360.;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
ProgressIndicatorViewCreator __gProgressIndicatorViewCreator;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // Mandelbrot
|
||||
@@ -0,0 +1,19 @@
|
||||
// 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 "vstgui/lib/platform/iplatformframe.h"
|
||||
#include "vstgui/standalone/include/fwd.h"
|
||||
|
||||
namespace Mandelbrot {
|
||||
|
||||
#if MAC && defined (MAC_OS_X_VERSION_10_12)
|
||||
void installTouchbarSupport (VSTGUI::IPlatformFrameTouchBarExtension*, const VSTGUI::Standalone::ValuePtr&);
|
||||
#else
|
||||
inline void installTouchbarSupport (VSTGUI::IPlatformFrameTouchBarExtension*, const VSTGUI::Standalone::ValuePtr&) {}
|
||||
#endif // MAC
|
||||
|
||||
} // Mandelbrot
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#import "touchbarsupport.h"
|
||||
|
||||
#ifdef MAC_OS_X_VERSION_10_12 // works only when building with the 10.12 SDK !
|
||||
|
||||
#import "vstgui/standalone/include/helpers/valuelistener.h"
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
@interface MandelbrotTouchbarSliderBinding : NSObject
|
||||
@property (retain) NSSlider* slider;
|
||||
@property VSTGUI::Standalone::ValuePtr value;
|
||||
@end
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
namespace Mandelbrot {
|
||||
|
||||
using namespace VSTGUI;
|
||||
using namespace VSTGUI::Standalone;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
class TouchBarMaker : public ITouchBarCreator, public ValueListenerAdapter
|
||||
{
|
||||
public:
|
||||
TouchBarMaker (const ValuePtr& value) : value (value)
|
||||
{
|
||||
value->registerListener (this);
|
||||
}
|
||||
|
||||
~TouchBarMaker () override
|
||||
{
|
||||
value->unregisterListener (this);
|
||||
}
|
||||
|
||||
void* createTouchBar () override
|
||||
{
|
||||
auto touchbar = [NSTouchBar new];
|
||||
sliderBinding = [MandelbrotTouchbarSliderBinding new];
|
||||
sliderBinding.value = value;
|
||||
sliderBinding.slider.doubleValue = value->getValue ();
|
||||
auto itemID = @"MandelBrotMaxIterationsID";
|
||||
touchbar.defaultItemIdentifiers = @[itemID];
|
||||
auto item = [[NSCustomTouchBarItem alloc] initWithIdentifier:itemID];
|
||||
item.view = sliderBinding.slider;
|
||||
touchbar.templateItems = [NSSet setWithObject:item];
|
||||
return touchbar;
|
||||
}
|
||||
|
||||
void onPerformEdit (IValue&, IValue::Type newValue) override
|
||||
{
|
||||
if (sliderBinding)
|
||||
{
|
||||
sliderBinding.slider.doubleValue = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
ValuePtr value;
|
||||
MandelbrotTouchbarSliderBinding* sliderBinding {nil};
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void installTouchbarSupport (IPlatformFrameTouchBarExtension* tbExt, const ValuePtr& value)
|
||||
{
|
||||
tbExt->setTouchBarCreator (owned<ITouchBarCreator> (new TouchBarMaker (value)));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // Mandelbrot
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
@implementation MandelbrotTouchbarSliderBinding
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
self->_slider = [NSSlider sliderWithTarget:self action:@selector(onSliderAction:)];
|
||||
return self;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
- (void)onSliderAction:(id)sender
|
||||
{
|
||||
self.value->performEdit ([sender doubleValue]);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,44 @@
|
||||
##########################################################################################
|
||||
# VSTGUI Minesweeper Example Application
|
||||
##########################################################################################
|
||||
set(target Minesweeper)
|
||||
|
||||
set(${target}_sources
|
||||
"source/commands.h"
|
||||
"source/highscorelist.cpp"
|
||||
"source/highscorelist.h"
|
||||
"source/highscores.cpp"
|
||||
"source/highscores.h"
|
||||
"source/highscoreviewcontroller.cpp"
|
||||
"source/highscoreviewcontroller.h"
|
||||
"source/keepchildviewscentered.h"
|
||||
"source/minefieldviewcontroller.cpp"
|
||||
"source/minefieldviewcontroller.h"
|
||||
"source/model.cpp"
|
||||
"source/model.h"
|
||||
"source/myapp.cpp"
|
||||
"source/windowcontroller.cpp"
|
||||
"source/windowcontroller.h"
|
||||
)
|
||||
|
||||
set(Minesweeper_resources
|
||||
"resource/Window.uidesc"
|
||||
"resource/Minesweeper.icns"
|
||||
)
|
||||
|
||||
set(Minesweeper_font
|
||||
"resource/font/LCD14.otf"
|
||||
"resource/font/NotoEmoji-Regular.ttf"
|
||||
)
|
||||
|
||||
##########################################################################################
|
||||
vstgui_add_executable(${target} "${${target}_sources}" )
|
||||
vstgui_add_resources(${target} "${Minesweeper_resources}")
|
||||
vstgui_add_resources(${target} "${Minesweeper_font}" "Fonts")
|
||||
vstgui_set_target_bundle_id(${target} "vstgui.examples.minesweeper")
|
||||
vstgui_set_target_infoplist(${target} "resource/Info.plist")
|
||||
vstgui_set_target_rcfile(${target} "resource/Minesweeper.rc")
|
||||
vstgui_set_cxx_version(${target} ${VSTGUI_CXX_VERSION})
|
||||
target_include_directories(${target} PRIVATE ../../../../)
|
||||
set_target_properties(${target} PROPERTIES ${APP_PROPERTIES} ${VSTGUI_STANDALONE_EXAMPLES_FOLDER})
|
||||
|
||||
|
After Width: | Height: | Size: 171 KiB |
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>Minesweeper</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>Minesweeper.icns</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2020 Arne Scheffler. All rights reserved.</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
</plist>
|
||||