Initial release

This commit is contained in:
civ
2026-08-16 18:24:52 +07:00
commit 876886a39a
13244 changed files with 2353959 additions and 0 deletions
@@ -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????
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

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})
Binary file not shown.

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>

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