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