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,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>
@@ -0,0 +1 @@
APPL????
@@ -0,0 +1,665 @@
{
"vstgui-ui-description": {
"version": "1",
"variables": {},
"bitmaps": {},
"fonts": {
"control": {
"font-name": "Arial",
"size": "10"
},
"emoji": {
"font-name": "Noto Emoji",
"size": "12"
},
"highscore": {
"font-name": "Arial",
"size": "12"
},
"lcd": {
"alternative-font-names": "LCD 14",
"font-name": "LCD",
"size": "14"
},
"lost": {
"font-name": "Arial",
"size": "20"
},
"time": {
"font-name": "Arial",
"size": "6"
}
},
"colors": {
"background": "#d9d9d9ff",
"card.closed.back": "#a0a0a0ff",
"card.closed.frame": "#000000ff",
"card.flaged.back": "#0000001f",
"card.flaged.frame": "#888888b4",
"card.opened.back": "#ffffff00",
"card.opened.frame": "#888888b4",
"focus": "#40afe3ff",
"highscore.font": "#000000ff",
"label": "#000000ff",
"lcd.font": "#ff0000ff",
"lost.back": "#2c2c2c8c",
"lost.font": "#ff0000ff",
"textedit.font": "#ffffffff",
"textedit.frame": "#9b9b9bff"
},
"gradients": {
"Default TextButton Gradient": [
{
"rgba": "#dcdcdcff",
"start": "0"
},
{
"rgba": "#b4b4b4ff",
"start": "1"
}
],
"Default TextButton Gradient Highlighted": [
{
"rgba": "#b4b4b4ff",
"start": "0"
},
{
"rgba": "#646464ff",
"start": "1"
}
]
},
"control-tags": {
"CloseHighscoreView": "9",
"Cols": "1",
"Flags": "3",
"Mines": "2",
"MouseMode": "6",
"NewHighScoreName": "7",
"NewHighScoreOK": "8",
"Rows": "0",
"Start": "5",
"Time": "4"
},
"custom": {
"UIGridController": {
"Grids": "1x 1,5x 5,10x 10,12x 12,15x 15",
"Size": "5, 5"
},
"UITemplateController": {
"SelectedTemplate": "Window"
},
"UIEditController": {
"EditViewScale": "1",
"EditorSize": "0, 0, 1640, 1005",
"SplitViewSize_0_0": "0.8151174668028600134306316249421797692776",
"SplitViewSize_0_1": "0.1644535240040858048438110472488915547729",
"SplitViewSize_1_0": "0.567926455566905019622936379164457321167",
"SplitViewSize_1_1": "0.426966292134831448823462096697767265141",
"SplitViewSize_2_0": "0.8073170731707317582248606413486413657665",
"SplitViewSize_2_1": "0.1896341463414634165296490664331940934062",
"TabSwitchValue": "6",
"Version": "1"
},
"UIAttributesController": {
"UIAttributesController": "contr"
},
"UIViewCreatorDataSource": {
"SelectedRow": "30"
},
"UIDescFilePath": {
"path": "/Users/scheffle/Source/vstgui/vstgui/standalone/examples/minesweeper/resource/Window.uidesc"
},
"UITagsDataSource": {
"SelectedRow": "-1"
},
"UIColorsDataSource": {
"SelectedRow": "8"
},
"UIFontsDataSource": {
"SelectedRow": "2"
},
"UIGradientsDataSource": {
"SelectedRow": "-1"
},
"UIBitmapsDataSource": {
"SelectedRow": "-1"
},
"FocusDrawing": {
"color": "focus",
"enabled": "true",
"width": "2"
}
},
"templates": {
"Window": {
"attributes": {
"autosize": "left right top bottom ",
"background-color": "background",
"background-color-draw-style": "filled and stroked",
"class": "CViewContainer",
"minSize": "364, 394",
"mouse-enabled": "true",
"opacity": "1",
"origin": "0, 0",
"size": "364, 394",
"transparent": "false",
"wants-focus": "false"
},
"children": {
"CTextLabel": {
"attributes": {
"back-color": "~ BlackCColor",
"background-offset": "0, 0",
"class": "CTextLabel",
"default-value": "0.5",
"font": "control",
"font-antialias": "true",
"font-color": "label",
"frame-color": "~ BlackCColor",
"frame-width": "1",
"max-value": "1",
"min-value": "0",
"mouse-enabled": "true",
"opacity": "1",
"origin": "10, 10",
"round-rect-radius": "6",
"shadow-color": "~ RedCColor",
"size": "35, 20",
"style-3D-in": "false",
"style-3D-out": "false",
"style-no-draw": "false",
"style-no-frame": "false",
"style-no-text": "false",
"style-round-rect": "false",
"style-shadow-text": "false",
"text-alignment": "left",
"text-inset": "0, 0",
"text-rotation": "0",
"text-shadow-offset": "1, 1",
"title": "Mines :",
"transparent": "true",
"value-precision": "2",
"wants-focus": "false",
"wheel-inc-value": "0.1"
}
},
"CTextLabel": {
"attributes": {
"back-color": "label",
"background-offset": "0, 0",
"class": "CTextLabel",
"control-tag": "Flags",
"default-value": "0.5",
"font": "lcd",
"font-antialias": "true",
"font-color": "lcd.font",
"frame-color": "textedit.frame",
"frame-width": "-1",
"max-value": "1",
"min-value": "0",
"mouse-enabled": "true",
"opacity": "1",
"origin": "45, 9",
"round-rect-radius": "2",
"shadow-color": "~ RedCColor",
"size": "30, 22",
"style-3D-in": "false",
"style-3D-out": "false",
"style-no-draw": "false",
"style-no-frame": "false",
"style-no-text": "false",
"style-round-rect": "true",
"style-shadow-text": "false",
"text-alignment": "right",
"text-inset": "5, 0",
"text-rotation": "0",
"text-shadow-offset": "1, 1",
"title": "99",
"transparent": "false",
"value-precision": "2",
"wants-focus": "false",
"wheel-inc-value": "0.1"
}
},
"CTextButton": {
"attributes": {
"autosize": "right top ",
"class": "CTextButton",
"control-tag": "Start",
"default-value": "0.5",
"font": "control",
"frame-color": "label",
"frame-color-highlighted": "label",
"frame-width": "-1",
"gradient": "Default TextButton Gradient",
"gradient-highlighted": "Default TextButton Gradient Highlighted",
"icon-position": "left",
"icon-text-margin": "0",
"kick-style": "true",
"max-value": "1",
"min-value": "0",
"mouse-enabled": "true",
"opacity": "1",
"origin": "284, 11",
"round-radius": "3",
"size": "70, 18",
"text-alignment": "center",
"text-color": "label",
"text-color-highlighted": "textedit.font",
"title": "New Game",
"transparent": "false",
"wants-focus": "true",
"wheel-inc-value": "0.1"
}
},
"CViewContainer": {
"attributes": {
"autosize": "left right top bottom ",
"background-color": "label",
"background-color-draw-style": "stroked",
"class": "CViewContainer",
"custom-view-name": "MinefieldView",
"mouse-enabled": "true",
"opacity": "1",
"origin": "10, 40",
"size": "344, 344",
"sub-controller": "MinefieldController",
"transparent": "false",
"wants-focus": "false"
},
"children": {
"CViewContainer": {
"attributes": {
"autosize": "left right top bottom ",
"background-color": "lost.back",
"background-color-draw-style": "filled and stroked",
"class": "CViewContainer",
"custom-view-name": "LostView",
"mouse-enabled": "false",
"opacity": "0",
"origin": "2, 2",
"size": "338, 339",
"transparent": "false",
"wants-focus": "false"
},
"children": {
"CTextLabel": {
"attributes": {
"autosize": "left right top bottom ",
"back-color": "~ TransparentCColor",
"background-offset": "0, 0",
"class": "CTextLabel",
"default-value": "0.5",
"font": "lost",
"font-antialias": "true",
"font-color": "lost.font",
"frame-color": "~ TransparentCColor",
"frame-width": "1",
"max-value": "1",
"min-value": "0",
"mouse-enabled": "false",
"opacity": "1",
"origin": "0, 0",
"round-rect-radius": "6",
"shadow-color": "label",
"size": "339, 339",
"style-3D-in": "false",
"style-3D-out": "false",
"style-no-draw": "false",
"style-no-frame": "false",
"style-no-text": "false",
"style-round-rect": "false",
"style-shadow-text": "true",
"text-alignment": "center",
"text-inset": "5, 0",
"text-rotation": "0",
"text-shadow-offset": "1, 1",
"title": "EXPLODED",
"transparent": "false",
"value-precision": "2",
"wants-focus": "false",
"wheel-inc-value": "0.1"
}
}
}
},
"CViewContainer": {
"attributes": {
"autosize": "left right top bottom ",
"background-color": "lost.back",
"background-color-draw-style": "filled and stroked",
"class": "CViewContainer",
"custom-view-name": "WonView",
"mouse-enabled": "false",
"opacity": "0",
"origin": "2, 2",
"size": "338, 339",
"transparent": "false",
"wants-focus": "false"
},
"children": {
"CTextLabel": {
"attributes": {
"autosize": "left right top bottom ",
"back-color": "lost.back",
"background-offset": "0, 0",
"class": "CTextLabel",
"default-value": "0.5",
"font": "lost",
"font-antialias": "true",
"font-color": "lost.font",
"frame-color": "~ TransparentCColor",
"frame-width": "1",
"max-value": "1",
"min-value": "0",
"mouse-enabled": "true",
"opacity": "0",
"origin": "0, 0",
"round-rect-radius": "6",
"shadow-color": "label",
"size": "338, 339",
"style-3D-in": "false",
"style-3D-out": "false",
"style-no-draw": "false",
"style-no-frame": "false",
"style-no-text": "false",
"style-round-rect": "false",
"style-shadow-text": "true",
"text-alignment": "center",
"text-inset": "5, 0",
"text-rotation": "0",
"text-shadow-offset": "1, 1",
"title": "FIELD CLEANED",
"transparent": "true",
"value-precision": "2",
"wants-focus": "false",
"wheel-inc-value": "0.1"
}
}
}
}
}
},
"CTextLabel": {
"attributes": {
"back-color": "label",
"background-offset": "0, 0",
"class": "CTextLabel",
"control-tag": "Time",
"default-value": "0.5",
"font": "lcd",
"font-antialias": "true",
"font-color": "lcd.font",
"frame-color": "textedit.frame",
"frame-width": "-1",
"max-value": "1",
"min-value": "0",
"mouse-enabled": "true",
"opacity": "1",
"origin": "110, 9",
"round-rect-radius": "2",
"shadow-color": "~ RedCColor",
"size": "40, 22",
"style-3D-in": "false",
"style-3D-out": "false",
"style-no-draw": "false",
"style-no-frame": "false",
"style-no-text": "false",
"style-round-rect": "true",
"style-shadow-text": "false",
"text-alignment": "right",
"text-inset": "5, 0",
"text-rotation": "0",
"text-shadow-offset": "1, 1",
"title": "000",
"transparent": "false",
"value-precision": "2",
"wants-focus": "false",
"wheel-inc-value": "0.1"
}
},
"CTextLabel": {
"attributes": {
"back-color": "~ BlackCColor",
"background-offset": "0, 0",
"class": "CTextLabel",
"default-value": "0.5",
"font": "control",
"font-antialias": "true",
"font-color": "label",
"frame-color": "~ BlackCColor",
"frame-width": "1",
"max-value": "1",
"min-value": "0",
"mouse-enabled": "true",
"opacity": "1",
"origin": "80, 10",
"round-rect-radius": "6",
"shadow-color": "~ RedCColor",
"size": "30, 20",
"style-3D-in": "false",
"style-3D-out": "false",
"style-no-draw": "false",
"style-no-frame": "false",
"style-no-text": "false",
"style-round-rect": "false",
"style-shadow-text": "false",
"text-alignment": "left",
"text-inset": "0, 0",
"text-rotation": "0",
"text-shadow-offset": "1, 1",
"title": "Time :",
"transparent": "true",
"value-precision": "2",
"wants-focus": "false",
"wheel-inc-value": "0.1"
}
},
"CViewContainer": {
"attributes": {
"autosize": "left right top bottom ",
"background-color": "lost.back",
"background-color-draw-style": "filled and stroked",
"class": "CViewContainer",
"custom-view-name": "MainView",
"mouse-enabled": "false",
"opacity": "0",
"origin": "0, 0",
"size": "365, 395",
"sub-controller": "NewHighScoreViewController",
"transparent": "false",
"wants-focus": "false"
},
"children": {
"CMultiLineTextLabel": {
"attributes": {
"auto-height": "false",
"back-color": "card.closed.frame",
"background-offset": "0, 0",
"class": "CMultiLineTextLabel",
"default-value": "0.5",
"font": "highscore",
"font-antialias": "true",
"font-color": "textedit.font",
"frame-color": "card.closed.frame",
"frame-width": "1",
"line-layout": "wrap",
"max-value": "1",
"min-value": "0",
"mouse-enabled": "true",
"opacity": "1",
"origin": "40, 80",
"round-rect-radius": "3",
"shadow-color": "lcd.font",
"size": "285, 56.3965",
"style-3D-in": "false",
"style-3D-out": "false",
"style-no-draw": "false",
"style-no-frame": "false",
"style-no-text": "false",
"style-round-rect": "true",
"style-shadow-text": "false",
"text-alignment": "center",
"text-inset": "0, 5",
"text-rotation": "0",
"text-shadow-offset": "1, 1",
"title": "You have a new HighScore!\\n\\nPlease enter your name:",
"transparent": "false",
"value-precision": "2",
"wants-focus": "false",
"wheel-inc-value": "0.1"
}
},
"CTextEdit": {
"attributes": {
"back-color": "card.closed.frame",
"background-offset": "0, 0",
"class": "CTextEdit",
"control-tag": "NewHighScoreName",
"default-value": "0.5",
"font": "highscore",
"font-antialias": "true",
"font-color": "textedit.font",
"frame-color": "card.closed.frame",
"frame-width": "1",
"immediate-text-change": "false",
"max-value": "1",
"min-value": "0",
"mouse-enabled": "true",
"opacity": "1",
"origin": "41, 143",
"placeholder-title": "Name",
"round-rect-radius": "3",
"secure-style": "false",
"shadow-color": "lcd.font",
"size": "285, 20",
"style-3D-in": "false",
"style-3D-out": "false",
"style-doubleclick": "false",
"style-no-draw": "false",
"style-no-frame": "false",
"style-no-text": "false",
"style-round-rect": "true",
"style-shadow-text": "false",
"text-alignment": "center",
"text-inset": "0, 0",
"text-rotation": "0",
"text-shadow-offset": "1, 1",
"transparent": "false",
"value-precision": "2",
"wants-focus": "true",
"wheel-inc-value": "0.1"
}
},
"CTextButton": {
"attributes": {
"class": "CTextButton",
"control-tag": "NewHighScoreOK",
"default-value": "0.5",
"font": "control",
"frame-color": "label",
"frame-color-highlighted": "label",
"frame-width": "-1",
"gradient": "Default TextButton Gradient",
"gradient-highlighted": "Default TextButton Gradient Highlighted",
"icon-position": "left",
"icon-text-margin": "0",
"kick-style": "false",
"max-value": "1",
"min-value": "0",
"mouse-enabled": "false",
"opacity": "1",
"origin": "133, 176",
"round-radius": "3",
"size": "100, 18",
"text-alignment": "center",
"text-color": "label",
"text-color-highlighted": "textedit.font",
"title": "OK",
"transparent": "false",
"wants-focus": "true",
"wheel-inc-value": "0.1"
}
}
}
},
"CViewContainer": {
"attributes": {
"autosize": "left right top bottom ",
"background-color": "background",
"background-color-draw-style": "filled and stroked",
"class": "CViewContainer",
"mouse-enabled": "false",
"opacity": "0",
"origin": "15, 45",
"size": "335, 335",
"sub-controller": "HighScoreViewController",
"transparent": "false",
"wants-focus": "false"
},
"children": {
"CScrollView": {
"attributes": {
"auto-drag-scrolling": "false",
"auto-hide-scrollbars": "false",
"background-color": "~ BlackCColor",
"background-color-draw-style": "filled and stroked",
"bordered": "true",
"class": "CScrollView",
"container-size": "315, 259.091",
"custom-view-name": "DataBrowser",
"follow-focus-view": "false",
"horizontal-scrollbar": "false",
"mouse-enabled": "true",
"opacity": "1",
"origin": "10, 10",
"overlay-scrollbars": "false",
"scrollbar-background-color": "#ffffffc8",
"scrollbar-frame-color": "~ BlackCColor",
"scrollbar-scroller-color": "~ BlueCColor",
"scrollbar-width": "16",
"size": "315, 285",
"sub-controller": "DataBrowserController",
"transparent": "true",
"vertical-scrollbar": "false",
"wants-focus": "false"
}
},
"CTextButton": {
"attributes": {
"class": "CTextButton",
"control-tag": "CloseHighscoreView",
"default-value": "0.5",
"font": "control",
"frame-color": "label",
"frame-color-highlighted": "label",
"frame-width": "-1",
"gradient": "Default TextButton Gradient",
"gradient-highlighted": "Default TextButton Gradient Highlighted",
"icon-position": "left",
"icon-text-margin": "0",
"kick-style": "false",
"max-value": "1",
"min-value": "0",
"mouse-enabled": "true",
"opacity": "1",
"origin": "135, 305",
"round-radius": "3",
"size": "70, 18",
"text-alignment": "center",
"text-color": "label",
"text-color-highlighted": "textedit.font",
"title": "Close",
"transparent": "false",
"wants-focus": "true",
"wheel-inc-value": "0.1"
}
}
}
}
}
}
}
}
}

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