Initial release
@@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
echo `pwd`
|
||||
mkdir -p "$1"
|
||||
|
||||
rm -f "$1/editoruidesc.h"
|
||||
echo -n "constexpr auto editorUIDesc = R\"====(" >> "$1/editoruidesc.h"
|
||||
cat uidescriptioneditor.uidesc >> "$1/editoruidesc.h"
|
||||
echo ")====\";" >> "$1/editoruidesc.h"
|
||||
|
||||
echo -n "constexpr auto editorUILightDesc = R\"====(" >> "$1/editoruidesc.h"
|
||||
cat uidescriptioneditor_res_light.uidesc >> "$1/editoruidesc.h"
|
||||
echo ")====\";" >> "$1/editoruidesc.h"
|
||||
|
||||
echo -n "constexpr auto editorUIDarkDesc = R\"====(" >> "$1/editoruidesc.h"
|
||||
cat uidescriptioneditor_res_dark.uidesc >> "$1/editoruidesc.h"
|
||||
echo ")====\";" >> "$1/editoruidesc.h"
|
||||
|
||||
@@ -0,0 +1,328 @@
|
||||
// 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
|
||||
|
||||
/*
|
||||
|
||||
TODO:
|
||||
Musts:
|
||||
- fix TODOs
|
||||
- finish documentation
|
||||
|
||||
Nice To Have:
|
||||
- grid handling improvements (like custom magnetic lines)
|
||||
- more custom attribute editing
|
||||
- view z-index editing via drag&drop
|
||||
- editing of uidescription variables
|
||||
|
||||
Known Bugs:
|
||||
- sometimes the attribute editor is not editable (dont know why yet)
|
||||
- setting autosize of template seems not to work
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
@page page_uidescription_editor Inline UI Editor for VST3 (WYSIWYG)
|
||||
|
||||
@tableofcontents
|
||||
|
||||
@section ui_editor_intro Introduction
|
||||
|
||||
VSTGUI 4.1 includes a new VST3 inline UI editor which makes UI design easier than before.
|
||||
|
||||
It automatically supports the following VST3 features:
|
||||
- IParameterFinder (find parameter under mouse)
|
||||
- IContextMenu (show host context menu on right click for an automatable parameter) [VST3.5 SDK required]
|
||||
|
||||
@note You need at least VST SDK 3.1, any earlier version will not work.
|
||||
@note The new editor is compatible to the old one included in VSTGUI 4.0
|
||||
|
||||
<hr/>
|
||||
|
||||
@section ui_editor_preparation Preparation
|
||||
|
||||
Before using the inline UI editor, you must make sure that you use the Steinberg::Vst::EditController class as a base
|
||||
of your own edit controller and that you have used the Steinberg::Vst::Parameter class or any subclass of it for your
|
||||
parameters.<br>
|
||||
Otherwise the inline UI editor won't work properly.
|
||||
|
||||
Next you have to add two files to your project:
|
||||
- vstgui/vstgui_uidescription.cpp
|
||||
- vstgui/plugin-bindings/vst3editor.cpp
|
||||
|
||||
After that you have to alter your project settings to add a preprocessor definition to your debug build:
|
||||
- VSTGUI_LIVE_EDITING=1
|
||||
|
||||
As last step you have to modify your edit controller class to overwrite the createView() method:
|
||||
@code
|
||||
IPlugView* PLUGIN_API MyEditController::createView (FIDString name)
|
||||
{
|
||||
if (strcmp (name, ViewType::kEditor) == 0)
|
||||
{
|
||||
return new VSTGUI::VST3Editor (this, "view", "myEditor.uidesc");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@endcode
|
||||
|
||||
And make sure to include the vst3editor.h header.
|
||||
|
||||
Now you can build your plug-in and start your preferred VST3 host to start designing your user interface.
|
||||
|
||||
If you now open your plug-in editor you will see a blank editor. To enter the UI editor you have to make a
|
||||
right click on it and choose "Open UIDescription Editor".
|
||||
|
||||
\note Your VST3 host should support live plug-in resizing for optimal experience. As of this writing, not all VST3 hosts support this feature.
|
||||
|
||||
<hr/>
|
||||
|
||||
@section ui_editor_parameter_binding Parameter Binding
|
||||
|
||||
If you've used the Parameter class provided by the VST3 SDK, you will get automatic parameter bindings between the controls of your editor
|
||||
and the parameters in your VST Edit Controller.
|
||||
|
||||
The only thing you need to do is to declare the ids of the parameters as tags in the @ref the_editor_view_palette_globals_tags editor
|
||||
(or use the 'Sync Parameter Tags' command in the Edit Menu of the @ref the_editor_toolbar) and set the tags of your controls to these ids.
|
||||
After you've done this your VST Edit Controller will receive the beginEdit(..)/performEdit(..)/endEdit(..) calls when the user changes the controls and if the host
|
||||
automates the parameter the control will also reflect these changes.
|
||||
|
||||
As an addition you can modify your VST Edit Controller to return specific parameter objects in the getParameterObject(int32 paramID) method for UI only needs, which are not
|
||||
parameters of your VST audio processor. This way you can store view settings like the tab which is open when the user closes the editor so that you can restore it
|
||||
when the user opens the editor again. You can look at the sources of the included 'uidescription test' project how this works.
|
||||
|
||||
<hr/>
|
||||
|
||||
<img src="ui_editor.png" style="float:right"/>
|
||||
|
||||
@section ui_editor_the_editor The Editor
|
||||
|
||||
The Editor has mainly five sections:
|
||||
<ol>
|
||||
<li>@ref the_editor_toolbar @n</li>
|
||||
<li>@ref the_editor_template_editor @n</li>
|
||||
<li>@ref the_editor_view_attribute_editor @n</li>
|
||||
<li>@ref the_editor_template_view_hierarchy @n</li>
|
||||
<li>@ref the_editor_view_palette_globals @n</li>
|
||||
</ol>
|
||||
|
||||
All actions you do here are undoable.
|
||||
|
||||
<div style="clear:both"></div>
|
||||
<hr/>
|
||||
|
||||
@subsection the_editor_toolbar Toolbar
|
||||
|
||||
The toolbar currently contains the two menus "File" and "Edit", the editing checkbox and the grid settings.
|
||||
|
||||
TODO: describe menu items
|
||||
|
||||
The File Menu contains:
|
||||
- Save
|
||||
- Save as...
|
||||
- Close Editor
|
||||
|
||||
The Edit Menu contains:
|
||||
- Undo
|
||||
- Redo
|
||||
- Cut
|
||||
- Copy
|
||||
- Paste
|
||||
- Delete
|
||||
- Size To Fit
|
||||
- Unembed Views
|
||||
- Embed Into
|
||||
- Transform View Type
|
||||
- Add New Template
|
||||
- Delete Template
|
||||
- Duplicate Template
|
||||
- Template Settings...
|
||||
- Focus Settings...
|
||||
- Sync Parameter Tags
|
||||
|
||||
<hr/>
|
||||
|
||||
@subsection the_editor_template_editor Template Editor
|
||||
|
||||
TODO
|
||||
|
||||
<hr/>
|
||||
|
||||
@subsection the_editor_view_attribute_editor View Attribute Editor
|
||||
|
||||
The View Attribute Editor shows the attributes of the selected views. If multiple views are selected
|
||||
it only shows those attributes which applies to all selected views.
|
||||
On the left side are the names of the attributes and on the right side their values. The values are editable.
|
||||
|
||||
You can enter a search term in the search field so that only those attributes are shown which matches the search string.
|
||||
|
||||
<hr/>
|
||||
|
||||
@subsection the_editor_template_view_hierarchy Template Selector + View Hierarchy Browser
|
||||
|
||||
The most left list shows all the templates. You can rename a template with a double click on it.
|
||||
|
||||
If a template is selected, it is shown in the Template Editor and all sub
|
||||
views are listed in the next list. You can select these sub views and if the selected sub view is a container view,
|
||||
its subviews are listed in the next list, etc.
|
||||
|
||||
You can alter the selection of the Template Editor via double click.
|
||||
|
||||
You can move the selected view up and down in the hierarchy order via Command-Up and Command-Down.
|
||||
|
||||
<hr/>
|
||||
|
||||
@subsection the_editor_view_palette_globals View Palette + Global UI Properties Editor
|
||||
|
||||
This section contains five subsections :
|
||||
- @ref the_editor_view_palette_globals_view @n
|
||||
- @ref the_editor_view_palette_globals_tags @n
|
||||
- @ref the_editor_view_palette_globals_colors @n
|
||||
- @ref the_editor_view_palette_globals_bitmaps @n
|
||||
- @ref the_editor_view_palette_globals_fonts @n
|
||||
|
||||
<hr/>
|
||||
|
||||
<img src="ui_editor_views_browser.png" style="display:block; float:right"/>
|
||||
@subsubsection the_editor_view_palette_globals_view Views
|
||||
|
||||
This section shows all views which are registered with UIDescription. You can register your own views,
|
||||
see \ref VSTGUI::IViewCreator.
|
||||
|
||||
To insert a view, select it and drag it into the template editor. While dragging the view over the template editor, the
|
||||
container view will be highlighted which will be the parent of the view if you drop it there.
|
||||
|
||||
<div style="clear:both"></div>
|
||||
<hr/>
|
||||
|
||||
<img src="ui_editor_tags_browser.png" style="float:right"/>
|
||||
@subsubsection the_editor_view_palette_globals_tags Tags
|
||||
|
||||
Here you define Tags for your controls. The left column describes the name of the Tag and the right column is the
|
||||
numerical value of the tag as used in VSTGUI::CControl.
|
||||
|
||||
With the + button you add a new tag and with the - button you remove the selected tag.
|
||||
|
||||
<div style="clear:both"></div>
|
||||
<hr/>
|
||||
|
||||
<img src="ui_editor_colors_browser.png" style="float:right"/>
|
||||
@subsubsection the_editor_view_palette_globals_colors Colors
|
||||
|
||||
TODO: New Screenshot
|
||||
|
||||
Here you define custom colors.
|
||||
|
||||
With the + button you add a new color and with the - button you remove the selected color.
|
||||
|
||||
<div style="clear:both"></div>
|
||||
<hr/>
|
||||
|
||||
<img src="ui_editor_bitmaps_browser.png" style="float:right"/>
|
||||
@subsubsection the_editor_view_palette_globals_bitmaps Bitmaps
|
||||
|
||||
TODO: New Screenshot
|
||||
|
||||
Here you define your bitmaps.
|
||||
|
||||
The path is the path to the bitmap.
|
||||
- On Mac OS X this is the filename of the bitmap inside the Resources directory of the plug-in bundle.
|
||||
- On Windows this is the resource name as described in the .rc file of your plug-in.
|
||||
|
||||
The Nine Part Tiled checkbox indicates if this is a VSTGUI::CNinePartTiledBitmap. And the l/t/r/b values describes its offsets.
|
||||
|
||||
With the + button you add a new bitmap and with the - button you remove the selected bitmap.
|
||||
|
||||
<div style="clear:both"></div>
|
||||
<hr/>
|
||||
|
||||
<img src="ui_editor_fonts_browser.png" style="float:right"/>
|
||||
@subsubsection the_editor_view_palette_globals_fonts Fonts
|
||||
|
||||
Here you describe your custom fonts.
|
||||
|
||||
- The font menu let you choose a font family installed on your system.
|
||||
- The alt control let you insert alternative font families if the main font is not available. You can insert more than one
|
||||
by using a comma as separator.
|
||||
|
||||
With the + button you add a new font and with the - button you remove the selected font.
|
||||
|
||||
<div style="clear:both"></div>
|
||||
<hr/>
|
||||
|
||||
@section ui_editor_custom_view_creation Creating Custom Views
|
||||
|
||||
If you need to create custom views, you can implement the VSTGUI::VST3EditorDelegate interface in your edit controller class.
|
||||
The createCustomView method will be called if you set the 'custom-view-name' attribute in one of the views.
|
||||
|
||||
Another way to use your own views is to register them at runtime with the UIViewFactory. This method requires more work but has the advantage
|
||||
that the view will be listed like the built-in views and changing attributes work on the fly. See \ref VSTGUI::IViewCreator.
|
||||
|
||||
<hr/>
|
||||
|
||||
@section ui_editor_sub_controllers Sub-Controllers
|
||||
|
||||
Sub-Controllers are useful if you need finer control of your views.
|
||||
You can define sub-controllers for views with the 'sub-controller' attribute.
|
||||
Sub-Controllers will be created via the VSTGUI::VST3EditorDelegate interface.
|
||||
The Sub-Controller object is now owned by the view and will be destroyed when the view is destroyed.
|
||||
|
||||
TODO: describe nested subcontrollers
|
||||
|
||||
The VSTGUI::DelegationController is a helper class if you don't want to control every aspect of the views by forwarding every call to its parent controller.
|
||||
You only overwrite the methods you need in your inherited class.
|
||||
|
||||
If you want to be notified about value changes for controls in your sub-controller but don't want to loose the
|
||||
@ref ui_editor_parameter_binding you can add your sub-controller as dependent of the control:
|
||||
|
||||
@code
|
||||
class MyController : public DelegationController, public CBaseObject
|
||||
{
|
||||
public:
|
||||
MyController (IController* baseController) : DelegationController (baseController), controlView (nullptr) {}
|
||||
~MyController ()
|
||||
{
|
||||
if (controlView)
|
||||
{
|
||||
controlView->unregisterControlListener (this);
|
||||
controlView->forget ();
|
||||
}
|
||||
}
|
||||
|
||||
CView* verifyView (CView* view, const UIAttributes& attributes, IUIDescription* description) override
|
||||
{
|
||||
auto* control = dynamic_cast<CControl*> (view);
|
||||
if (control && control->getTag () == 20)
|
||||
{
|
||||
controlView = control;
|
||||
controlView->registerControlListener (this);
|
||||
controlView->remember ();
|
||||
}
|
||||
return controller->verifyView (view, attributes, description);
|
||||
}
|
||||
|
||||
void valueChanged (CControl* pControl) override
|
||||
{
|
||||
if (pControl == controlView)
|
||||
{
|
||||
// value of the control view changed, do whatever you like
|
||||
}
|
||||
DelegationController::valueChanged (pControl);
|
||||
}
|
||||
|
||||
protected:
|
||||
CControl* controlView;
|
||||
};
|
||||
@endcode
|
||||
|
||||
<hr/>
|
||||
|
||||
@section ui_editor_templates Templates
|
||||
|
||||
Templates are root views where you can group controls in logical entities.
|
||||
You can embed templates into other templates.
|
||||
|
||||
Some views like the VSTGUI::UIViewSwitchContainer shows different templates depending on a control value.
|
||||
|
||||
<hr/>
|
||||
|
||||
*/
|
||||
@@ -0,0 +1,73 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../lib/vstguifwd.h"
|
||||
|
||||
#if VSTGUI_LIVE_EDITING
|
||||
#include "../../lib/cfont.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
class UIAttributes;
|
||||
struct FocusDrawingSettings;
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class IAction
|
||||
{
|
||||
public:
|
||||
virtual ~IAction () {}
|
||||
|
||||
virtual UTF8StringPtr getName () = 0;
|
||||
virtual void perform () = 0;
|
||||
virtual void undo () = 0;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class IActionPerformer
|
||||
{
|
||||
public:
|
||||
virtual ~IActionPerformer () {}
|
||||
virtual void performAction (IAction* action) = 0;
|
||||
|
||||
virtual void performColorChange (UTF8StringPtr colorName, const CColor& newColor, bool remove = false) = 0;
|
||||
virtual void performTagChange (UTF8StringPtr tagName, UTF8StringPtr tagString, bool remove = false) = 0;
|
||||
virtual void performBitmapChange (UTF8StringPtr bitmapName, UTF8StringPtr bitmapPath, bool remove = false) = 0;
|
||||
virtual void performGradientChange (UTF8StringPtr gradientName, CGradient* newGradient, bool remove = false) = 0;
|
||||
virtual void performFontChange (UTF8StringPtr fontName, CFontRef newFont, bool remove = false) = 0;
|
||||
|
||||
virtual void performColorNameChange (UTF8StringPtr oldName, UTF8StringPtr newName) = 0;
|
||||
virtual void performTagNameChange (UTF8StringPtr oldName, UTF8StringPtr newName) = 0;
|
||||
virtual void performFontNameChange (UTF8StringPtr oldName, UTF8StringPtr newName) = 0;
|
||||
virtual void performBitmapNameChange (UTF8StringPtr oldName, UTF8StringPtr newName) = 0;
|
||||
virtual void performGradientNameChange (UTF8StringPtr oldName, UTF8StringPtr newName) = 0;
|
||||
|
||||
virtual void performAlternativeFontChange (UTF8StringPtr fontName, UTF8StringPtr newAlternativeFonts) = 0;
|
||||
|
||||
virtual void performBitmapMultiFrameChange (UTF8StringPtr bitmapName,
|
||||
const CMultiFrameBitmapDescription* desc) = 0;
|
||||
virtual void performBitmapNinePartTiledChange (UTF8StringPtr bitmapName, const CRect* offsets) = 0;
|
||||
virtual void performBitmapFiltersChange (UTF8StringPtr bitmapName, const std::list<SharedPointer<UIAttributes> >& filterDescription) = 0;
|
||||
|
||||
virtual void beginLiveColorChange (UTF8StringPtr colorName) = 0;
|
||||
virtual void performLiveColorChange (UTF8StringPtr colorName, const CColor& newColor) = 0;
|
||||
virtual void endLiveColorChange (UTF8StringPtr colorName) = 0;
|
||||
|
||||
virtual void performTemplateNameChange (UTF8StringPtr oldName, UTF8StringPtr newName) = 0;
|
||||
virtual void performTemplateMinMaxSizeChange (UTF8StringPtr templateName, CPoint minSize, CPoint maxSize) = 0;
|
||||
virtual void performCreateNewTemplate (UTF8StringPtr name, UTF8StringPtr baseViewClassName) = 0;
|
||||
virtual void performDeleteTemplate (UTF8StringPtr name) = 0;
|
||||
virtual void performDuplicateTemplate (UTF8StringPtr name, UTF8StringPtr dupName) = 0;
|
||||
virtual void onTemplateCreation (UTF8StringPtr name, CView* view) = 0;
|
||||
virtual void onTemplateNameChange (UTF8StringPtr oldName, UTF8StringPtr newName) = 0;
|
||||
|
||||
virtual void performChangeFocusDrawingSettings (const FocusDrawingSettings& newSettings) = 0;
|
||||
|
||||
virtual void beginGroupAction (UTF8StringPtr name) = 0;
|
||||
virtual void finishGroupAction () = 0;
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
|
||||
#endif // VSTGUI_LIVE_EDITING
|
||||
@@ -0,0 +1,22 @@
|
||||
// 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 "../../lib/vstguibase.h"
|
||||
|
||||
#if VSTGUI_LIVE_EDITING
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class IGridProcessor : virtual public IReference
|
||||
{
|
||||
public:
|
||||
virtual void process (CPoint& p) = 0;
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
|
||||
#endif // VSTGUI_LIVE_EDITING
|
||||
|
After Width: | Height: | Size: 842 B |
|
After Width: | Height: | Size: 848 B |
|
After Width: | Height: | Size: 838 B |
|
After Width: | Height: | Size: 835 B |
|
After Width: | Height: | Size: 847 B |
|
After Width: | Height: | Size: 851 B |
|
After Width: | Height: | Size: 848 B |
|
After Width: | Height: | Size: 844 B |
|
After Width: | Height: | Size: 855 B |
|
After Width: | Height: | Size: 870 B |
|
After Width: | Height: | Size: 853 B |
|
After Width: | Height: | Size: 844 B |
|
After Width: | Height: | Size: 842 B |
|
After Width: | Height: | Size: 848 B |
|
After Width: | Height: | Size: 839 B |
|
After Width: | Height: | Size: 837 B |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 708 B |
|
After Width: | Height: | Size: 715 B |
|
After Width: | Height: | Size: 691 B |
|
After Width: | Height: | Size: 679 B |
|
After Width: | Height: | Size: 721 B |
|
After Width: | Height: | Size: 751 B |
|
After Width: | Height: | Size: 704 B |
|
After Width: | Height: | Size: 685 B |
|
After Width: | Height: | Size: 686 B |
|
After Width: | Height: | Size: 686 B |
|
After Width: | Height: | Size: 672 B |
|
After Width: | Height: | Size: 668 B |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 770 B |
|
After Width: | Height: | Size: 680 B |
|
After Width: | Height: | Size: 533 B |
|
After Width: | Height: | Size: 947 B |
|
After Width: | Height: | Size: 593 B |
|
After Width: | Height: | Size: 417 B |
|
After Width: | Height: | Size: 258 B |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 613 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 617 B |
|
After Width: | Height: | Size: 675 B |
|
After Width: | Height: | Size: 309 B |
|
After Width: | Height: | Size: 492 B |
|
After Width: | Height: | Size: 398 B |
|
After Width: | Height: | Size: 860 B |
|
After Width: | Height: | Size: 490 B |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
@@ -0,0 +1,623 @@
|
||||
// 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 "iaction.h"
|
||||
|
||||
#if VSTGUI_LIVE_EDITING
|
||||
|
||||
#include "uiselection.h"
|
||||
#include "../iviewfactory.h"
|
||||
#include "../iuidescription.h"
|
||||
#include "../../lib/ccolor.h"
|
||||
#include "../../lib/cgradient.h"
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
namespace VSTGUI {
|
||||
class UIViewFactory;
|
||||
class IUIDescription;
|
||||
class UIDescription;
|
||||
class CViewContainer;
|
||||
class CView;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
class Action : public IAction
|
||||
{
|
||||
public:
|
||||
using Func = std::function<void ()>;
|
||||
Action (const std::string& name, Func&& perform, Func&& undo)
|
||||
: name (name), performAction (std::move (perform)), undoAction (std::move (undo))
|
||||
{
|
||||
}
|
||||
|
||||
UTF8StringPtr getName () override { return name.data (); }
|
||||
|
||||
void perform () override { performAction (); }
|
||||
void undo () override { undoAction (); }
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
Func performAction;
|
||||
Func undoAction;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T>
|
||||
class BaseSelectionOperation : public IAction, protected std::list<T>
|
||||
{
|
||||
public:
|
||||
BaseSelectionOperation (UISelection* selection) : selection (selection) {}
|
||||
|
||||
protected:
|
||||
SharedPointer<UISelection> selection;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
class SizeToFitOperation : public BaseSelectionOperation<std::pair<SharedPointer<CView>, CRect> >
|
||||
{
|
||||
public:
|
||||
SizeToFitOperation (UISelection* selection);
|
||||
~SizeToFitOperation () override = default;
|
||||
|
||||
UTF8StringPtr getName () override;
|
||||
|
||||
void perform () override;
|
||||
void undo () override;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
class UnembedViewOperation : public BaseSelectionOperation<SharedPointer<CView> >
|
||||
{
|
||||
public:
|
||||
UnembedViewOperation (UISelection* selection, const IViewFactory* factory);
|
||||
~UnembedViewOperation () override = default;
|
||||
|
||||
UTF8StringPtr getName () override;
|
||||
|
||||
void perform () override;
|
||||
void undo () override;
|
||||
|
||||
protected:
|
||||
void collectSubviews (CViewContainer* container, bool deep);
|
||||
const IViewFactory* factory;
|
||||
SharedPointer<CViewContainer> containerView;
|
||||
CViewContainer* parent;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
class EmbedViewOperation : public BaseSelectionOperation<std::pair<SharedPointer<CView>, CRect> >
|
||||
{
|
||||
public:
|
||||
EmbedViewOperation (UISelection* selection, CViewContainer* newContainer);
|
||||
~EmbedViewOperation () override = default;
|
||||
|
||||
UTF8StringPtr getName () override;
|
||||
void perform () override;
|
||||
void undo () override;
|
||||
|
||||
protected:
|
||||
SharedPointer<CViewContainer> newContainer;
|
||||
CViewContainer* parent;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
class ViewCopyOperation : public IAction, protected std::list<SharedPointer<CView> >
|
||||
{
|
||||
public:
|
||||
ViewCopyOperation (UISelection* copySelection, UISelection* workingSelection, CViewContainer* parent, const CPoint& offset, IUIDescription* desc);
|
||||
~ViewCopyOperation () override = default;
|
||||
|
||||
UTF8StringPtr getName () override;
|
||||
void perform () override;
|
||||
void undo () override;
|
||||
protected:
|
||||
SharedPointer<CViewContainer> parent;
|
||||
SharedPointer<UISelection> copySelection;
|
||||
SharedPointer<UISelection> workingSelection;
|
||||
std::list<SharedPointer<CView> > oldSelectedViews;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
class ViewSizeChangeOperation : public BaseSelectionOperation<std::pair<SharedPointer<CView>, CRect> >
|
||||
{
|
||||
public:
|
||||
ViewSizeChangeOperation (UISelection* selection, bool sizing, bool autosizingEnabled);
|
||||
~ViewSizeChangeOperation () override = default;
|
||||
|
||||
UTF8StringPtr getName () override;
|
||||
void perform () override;
|
||||
void undo () override;
|
||||
|
||||
bool didChange ();
|
||||
protected:
|
||||
bool first;
|
||||
bool sizing;
|
||||
bool autosizing;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
struct DeleteOperationViewAndNext
|
||||
{
|
||||
DeleteOperationViewAndNext (CView* view, CView* nextView) : view (view), nextView (nextView) {}
|
||||
DeleteOperationViewAndNext (const DeleteOperationViewAndNext& copy) : view (copy.view), nextView (copy.nextView) {}
|
||||
SharedPointer<CView> view;
|
||||
SharedPointer<CView> nextView;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class DeleteOperation : public IAction, protected std::multimap<SharedPointer<CViewContainer>, DeleteOperationViewAndNext>
|
||||
{
|
||||
public:
|
||||
DeleteOperation (UISelection* selection);
|
||||
~DeleteOperation () override = default;
|
||||
|
||||
UTF8StringPtr getName () override;
|
||||
void perform () override;
|
||||
void undo () override;
|
||||
protected:
|
||||
SharedPointer<UISelection> selection;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
class InsertViewOperation : public IAction
|
||||
{
|
||||
public:
|
||||
InsertViewOperation (CViewContainer* parent, CView* view, UISelection* selection);
|
||||
~InsertViewOperation () override = default;
|
||||
|
||||
UTF8StringPtr getName () override;
|
||||
void perform () override;
|
||||
void undo () override;
|
||||
protected:
|
||||
SharedPointer<CViewContainer> parent;
|
||||
SharedPointer<CView> view;
|
||||
SharedPointer<UISelection> selection;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
class TransformViewTypeOperation : public IAction
|
||||
{
|
||||
public:
|
||||
TransformViewTypeOperation (UISelection* selection, CView* view, IdStringPtr viewClassName,
|
||||
UIDescription* desc, const IViewFactory* factory);
|
||||
~TransformViewTypeOperation () override;
|
||||
|
||||
UTF8StringPtr getName () override;
|
||||
|
||||
void exchangeSubViews (CViewContainer* src, CViewContainer* dst);
|
||||
void perform () override;
|
||||
void undo () override;
|
||||
protected:
|
||||
SharedPointer<CView> view;
|
||||
CView* newView;
|
||||
int32_t insertIndex;
|
||||
SharedPointer<CViewContainer> parent;
|
||||
SharedPointer<UISelection> selection;
|
||||
const IViewFactory* factory;
|
||||
SharedPointer<UIDescription> description;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
class AttributeChangeAction : public IAction, protected std::map<SharedPointer<CView>, std::string>
|
||||
{
|
||||
public:
|
||||
AttributeChangeAction (UIDescription* desc, UISelection* selection, const std::string& attrName, const std::string& attrValue);
|
||||
~AttributeChangeAction () override = default;
|
||||
|
||||
UTF8StringPtr getName () override;
|
||||
void perform () override;
|
||||
void undo () override;
|
||||
protected:
|
||||
void updateSelection ();
|
||||
|
||||
UIDescription* desc;
|
||||
SharedPointer<UISelection> selection;
|
||||
std::string attrName;
|
||||
std::string attrValue;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class MultipleAttributeChangeAction : public IAction, public std::vector<std::pair<SharedPointer<CView>, std::string> >
|
||||
{
|
||||
public:
|
||||
MultipleAttributeChangeAction (UIDescription* description, const std::list<CView*>& views, IViewCreator::AttrType attrType, UTF8StringPtr oldValue, UTF8StringPtr newValue);
|
||||
UTF8StringPtr getName () override { return "multiple view attribute changes"; }
|
||||
void perform () override;
|
||||
void undo () override;
|
||||
protected:
|
||||
void setAttributeValue (UTF8StringPtr value);
|
||||
static void collectAllSubViews (CView* view, std::list<CView*>& views);
|
||||
void collectViewsWithAttributeValue (const IViewFactory* viewFactory, IUIDescription* desc,
|
||||
CView* startView, IViewCreator::AttrType type,
|
||||
const std::string& value);
|
||||
|
||||
SharedPointer<UIDescription> description;
|
||||
std::string oldValue;
|
||||
std::string newValue;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class TagChangeAction : public IAction
|
||||
{
|
||||
public:
|
||||
TagChangeAction (UIDescription* description, UTF8StringPtr name, UTF8StringPtr newTagString, bool remove, bool performOrUndo);
|
||||
|
||||
UTF8StringPtr getName () override;
|
||||
void perform () override;
|
||||
void undo () override;
|
||||
|
||||
bool isAddTag () const { return isNewTag; }
|
||||
protected:
|
||||
SharedPointer<UIDescription> description;
|
||||
std::string name;
|
||||
std::string newTag;
|
||||
std::string originalTag;
|
||||
bool remove;
|
||||
bool performOrUndo;
|
||||
bool isNewTag;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class TagNameChangeAction : public IAction
|
||||
{
|
||||
public:
|
||||
TagNameChangeAction (UIDescription* description, UTF8StringPtr oldName, UTF8StringPtr newName, bool performOrUndo);
|
||||
|
||||
UTF8StringPtr getName () override;
|
||||
void perform () override;
|
||||
void undo () override;
|
||||
protected:
|
||||
SharedPointer<UIDescription> description;
|
||||
std::string oldName;
|
||||
std::string newName;
|
||||
bool performOrUndo;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class ColorChangeAction : public IAction
|
||||
{
|
||||
public:
|
||||
ColorChangeAction (UIDescription* description, UTF8StringPtr name, const CColor& color, bool remove, bool performOrUndo);
|
||||
|
||||
UTF8StringPtr getName () override;
|
||||
void perform () override;
|
||||
void undo () override;
|
||||
|
||||
bool isAddColor () const { return isNewColor; }
|
||||
protected:
|
||||
SharedPointer<UIDescription> description;
|
||||
std::string name;
|
||||
CColor newColor;
|
||||
CColor oldColor;
|
||||
bool remove;
|
||||
bool performOrUndo;
|
||||
bool isNewColor;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class ColorNameChangeAction : public IAction
|
||||
{
|
||||
public:
|
||||
ColorNameChangeAction (UIDescription* description, UTF8StringPtr oldName, UTF8StringPtr newName, bool performOrUndo);
|
||||
|
||||
UTF8StringPtr getName () override;
|
||||
void perform () override;
|
||||
void undo () override;
|
||||
protected:
|
||||
SharedPointer<UIDescription> description;
|
||||
std::string oldName;
|
||||
std::string newName;
|
||||
bool performOrUndo;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class BitmapChangeAction : public IAction
|
||||
{
|
||||
public:
|
||||
BitmapChangeAction (UIDescription* description, UTF8StringPtr name, UTF8StringPtr path, bool remove, bool performOrUndo);
|
||||
|
||||
UTF8StringPtr getName () override;
|
||||
void perform () override;
|
||||
void undo () override;
|
||||
|
||||
bool isAddBitmap () const { return isNewBitmap; }
|
||||
protected:
|
||||
SharedPointer<UIDescription> description;
|
||||
std::string name;
|
||||
std::string path;
|
||||
std::string originalPath;
|
||||
bool remove;
|
||||
bool performOrUndo;
|
||||
bool isNewBitmap;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class BitmapNameChangeAction : public IAction
|
||||
{
|
||||
public:
|
||||
BitmapNameChangeAction (UIDescription* description, UTF8StringPtr oldName, UTF8StringPtr newName, bool performOrUndo);
|
||||
|
||||
UTF8StringPtr getName () override;
|
||||
void perform () override;
|
||||
void undo () override;
|
||||
protected:
|
||||
SharedPointer<UIDescription> description;
|
||||
std::string oldName;
|
||||
std::string newName;
|
||||
bool performOrUndo;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class NinePartTiledBitmapChangeAction : public IAction
|
||||
{
|
||||
public:
|
||||
NinePartTiledBitmapChangeAction (UIDescription* description, UTF8StringPtr name, const CRect* rect, bool performOrUndo);
|
||||
~NinePartTiledBitmapChangeAction () override;
|
||||
|
||||
UTF8StringPtr getName () override;
|
||||
void perform () override;
|
||||
void undo () override;
|
||||
protected:
|
||||
SharedPointer<UIDescription> description;
|
||||
std::string name;
|
||||
CRect* oldRect;
|
||||
CRect* newRect;
|
||||
bool performOrUndo;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class MultiFrameBitmapChangeAction : public IAction
|
||||
{
|
||||
public:
|
||||
MultiFrameBitmapChangeAction (UIDescription* description, UTF8StringPtr name,
|
||||
const CMultiFrameBitmapDescription* desc, bool performOrUndo);
|
||||
~MultiFrameBitmapChangeAction () override;
|
||||
|
||||
UTF8StringPtr getName () override;
|
||||
void perform () override;
|
||||
void undo () override;
|
||||
|
||||
protected:
|
||||
SharedPointer<UIDescription> description;
|
||||
std::string name;
|
||||
std::unique_ptr<CMultiFrameBitmapDescription> oldDesc;
|
||||
std::unique_ptr<CMultiFrameBitmapDescription> newDesc;
|
||||
bool performOrUndo;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class BitmapFilterChangeAction : public IAction
|
||||
{
|
||||
public:
|
||||
BitmapFilterChangeAction (UIDescription* description, UTF8StringPtr bitmapName, const std::list<SharedPointer<UIAttributes> >& attributes, bool performOrUndo);
|
||||
~BitmapFilterChangeAction () override = default;
|
||||
|
||||
UTF8StringPtr getName () override;
|
||||
void perform () override;
|
||||
void undo () override;
|
||||
protected:
|
||||
SharedPointer<UIDescription> description;
|
||||
std::string bitmapName;
|
||||
std::list<SharedPointer<UIAttributes> > newAttributes;
|
||||
std::list<SharedPointer<UIAttributes> > oldAttributes;
|
||||
bool performOrUndo;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class GradientChangeAction : public IAction
|
||||
{
|
||||
public:
|
||||
GradientChangeAction (UIDescription* description, UTF8StringPtr name, CGradient* gradient, bool remove, bool performOrUndo);
|
||||
|
||||
UTF8StringPtr getName () override;
|
||||
void perform () override;
|
||||
void undo () override;
|
||||
|
||||
bool isAddGradient () const { return originalGradient == 0; }
|
||||
protected:
|
||||
SharedPointer<UIDescription> description;
|
||||
std::string name;
|
||||
SharedPointer<CGradient> gradient;
|
||||
SharedPointer<CGradient> originalGradient;
|
||||
bool remove;
|
||||
bool performOrUndo;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class GradientNameChangeAction : public IAction
|
||||
{
|
||||
public:
|
||||
GradientNameChangeAction (UIDescription* description, UTF8StringPtr oldName, UTF8StringPtr newName, bool performOrUndo);
|
||||
|
||||
UTF8StringPtr getName () override;
|
||||
void perform () override;
|
||||
void undo () override;
|
||||
protected:
|
||||
SharedPointer<UIDescription> description;
|
||||
std::string oldName;
|
||||
std::string newName;
|
||||
bool performOrUndo;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class FontChangeAction : public IAction
|
||||
{
|
||||
public:
|
||||
FontChangeAction (UIDescription* description, UTF8StringPtr name, CFontRef font, bool remove, bool performOrUndo);
|
||||
|
||||
UTF8StringPtr getName () override;
|
||||
void perform () override;
|
||||
void undo () override;
|
||||
|
||||
bool isAddFont () const { return originalFont == 0; }
|
||||
protected:
|
||||
SharedPointer<UIDescription> description;
|
||||
std::string name;
|
||||
std::string alternativeNames;
|
||||
SharedPointer<CFontDesc> font;
|
||||
SharedPointer<CFontDesc> originalFont;
|
||||
bool remove;
|
||||
bool performOrUndo;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class FontNameChangeAction : public IAction
|
||||
{
|
||||
public:
|
||||
FontNameChangeAction (UIDescription* description, UTF8StringPtr oldName, UTF8StringPtr newName, bool performOrUndo);
|
||||
|
||||
UTF8StringPtr getName () override;
|
||||
void perform () override;
|
||||
void undo () override;
|
||||
protected:
|
||||
SharedPointer<UIDescription> description;
|
||||
std::string oldName;
|
||||
std::string newName;
|
||||
bool performOrUndo;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
class AlternateFontChangeAction : public IAction
|
||||
{
|
||||
public:
|
||||
AlternateFontChangeAction (UIDescription* description, UTF8StringPtr fontName, UTF8StringPtr newAlternateFontNames);
|
||||
UTF8StringPtr getName () override;
|
||||
void perform () override;
|
||||
void undo () override;
|
||||
protected:
|
||||
SharedPointer<UIDescription> description;
|
||||
std::string fontName;
|
||||
std::string newAlternateFontNames;
|
||||
std::string oldAlternateFontNames;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
class HierarchyMoveViewOperation : public IAction
|
||||
{
|
||||
public:
|
||||
HierarchyMoveViewOperation (CView* view, UISelection* selection, int32_t dir);
|
||||
~HierarchyMoveViewOperation () override = default;
|
||||
|
||||
UTF8StringPtr getName () override;
|
||||
void perform () override;
|
||||
void undo () override;
|
||||
protected:
|
||||
SharedPointer<CView> view;
|
||||
SharedPointer<CViewContainer> parent;
|
||||
SharedPointer<UISelection> selection;
|
||||
int32_t dir;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
class TemplateNameChangeAction : public IAction
|
||||
{
|
||||
public:
|
||||
TemplateNameChangeAction (UIDescription* description, IActionPerformer* actionPerformer, UTF8StringPtr oldName, UTF8StringPtr newName);
|
||||
|
||||
UTF8StringPtr getName () override;
|
||||
void perform () override;
|
||||
void undo () override;
|
||||
protected:
|
||||
SharedPointer<UIDescription> description;
|
||||
IActionPerformer* actionPerformer;
|
||||
std::string oldName;
|
||||
std::string newName;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
class CreateNewTemplateAction : public IAction
|
||||
{
|
||||
public:
|
||||
CreateNewTemplateAction (UIDescription* description, IActionPerformer* actionPerformer, UTF8StringPtr name, UTF8StringPtr baseViewClassName);
|
||||
|
||||
UTF8StringPtr getName () override;
|
||||
void perform () override;
|
||||
void undo () override;
|
||||
protected:
|
||||
SharedPointer<UIDescription> description;
|
||||
IActionPerformer* actionPerformer;
|
||||
SharedPointer<CView> view;
|
||||
std::string name;
|
||||
std::string baseViewClassName;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
class DuplicateTemplateAction : public IAction
|
||||
{
|
||||
public:
|
||||
DuplicateTemplateAction (UIDescription* description, IActionPerformer* actionPerformer, UTF8StringPtr name, UTF8StringPtr dupName);
|
||||
|
||||
UTF8StringPtr getName () override;
|
||||
void perform () override;
|
||||
void undo () override;
|
||||
protected:
|
||||
SharedPointer<UIDescription> description;
|
||||
IActionPerformer* actionPerformer;
|
||||
SharedPointer<CView> view;
|
||||
std::string name;
|
||||
std::string dupName;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
class DeleteTemplateAction : public IAction
|
||||
{
|
||||
public:
|
||||
DeleteTemplateAction (UIDescription* description, IActionPerformer* actionPerformer, CView* view, UTF8StringPtr name);
|
||||
|
||||
UTF8StringPtr getName () override;
|
||||
void perform () override;
|
||||
void undo () override;
|
||||
protected:
|
||||
SharedPointer<UIDescription> description;
|
||||
IActionPerformer* actionPerformer;
|
||||
SharedPointer<CView> view;
|
||||
SharedPointer<UIAttributes> attributes;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
class ChangeFocusDrawingAction : public IAction
|
||||
{
|
||||
public:
|
||||
ChangeFocusDrawingAction (UIDescription* description, const FocusDrawingSettings& newSettings);
|
||||
|
||||
UTF8StringPtr getName () override;
|
||||
void perform () override;
|
||||
void undo () override;
|
||||
protected:
|
||||
SharedPointer<UIDescription> description;
|
||||
FocusDrawingSettings oldSettings;
|
||||
FocusDrawingSettings newSettings;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
class ChangeTemplateMinMaxAction : public IAction
|
||||
{
|
||||
public:
|
||||
ChangeTemplateMinMaxAction (UIDescription* description, UTF8StringPtr templateName, CPoint minSize, CPoint maxSize);
|
||||
|
||||
UTF8StringPtr getName () override;
|
||||
void perform () override;
|
||||
void undo () override;
|
||||
private:
|
||||
void setMinMaxSize (CPoint minimum, CPoint maximum);
|
||||
|
||||
SharedPointer<UIDescription> description;
|
||||
std::string templateName;
|
||||
CPoint minSize;
|
||||
CPoint maxSize;
|
||||
CPoint oldMinSize;
|
||||
CPoint oldMaxSize;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
} // VSTGUI
|
||||
|
||||
#endif // VSTGUI_LIVE_EDITING
|
||||
@@ -0,0 +1,99 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../uidescription.h"
|
||||
|
||||
#if VSTGUI_LIVE_EDITING
|
||||
|
||||
#include "uiselection.h"
|
||||
#include "../delegationcontroller.h"
|
||||
#include "../iviewcreator.h"
|
||||
#include "../iviewfactory.h"
|
||||
#include "../uidescriptionlistener.h"
|
||||
#include "uiundomanager.h"
|
||||
#include "../../lib/controls/ctextedit.h"
|
||||
#include "../../lib/iviewlistener.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
class CRowColumnView;
|
||||
|
||||
namespace UIAttributeControllers {
|
||||
class Controller;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class UIAttributesController : public NonAtomicReferenceCounted,
|
||||
public DelegationController,
|
||||
public UIDescriptionListenerAdapter,
|
||||
public UISelectionListenerAdapter,
|
||||
public IUIUndoManagerListener,
|
||||
public ViewListenerAdapter
|
||||
{
|
||||
public:
|
||||
UIAttributesController (IController* baseController, UISelection* selection, UIUndoManager* undoManager, UIDescription* description);
|
||||
~UIAttributesController () override;
|
||||
|
||||
void beginLiveAttributeChange (const std::string& name, const std::string& currentValue);
|
||||
void endLiveAttributeChange ();
|
||||
void performAttributeChange (const std::string& name, const std::string& value);
|
||||
protected:
|
||||
using StringList = std::list<std::string>;
|
||||
|
||||
CView* createViewForAttribute (const std::string& attrName);
|
||||
void rebuildAttributesView ();
|
||||
void validateAttributeViews ();
|
||||
CView* createValueViewForAttributeType (const IViewFactory* viewFactory, CView* view,
|
||||
const std::string& attrName,
|
||||
IViewCreator::AttrType attrType);
|
||||
void getConsolidatedAttributeNames (StringList& result, const std::string& filter);
|
||||
|
||||
void valueChanged (CControl* pControl) override;
|
||||
CView* verifyView (CView* view, const UIAttributes& attributes, const IUIDescription* description) override;
|
||||
IController* createSubController (IdStringPtr name, const IUIDescription* description) override;
|
||||
IControlListener* getControlListener (UTF8StringPtr name) override;
|
||||
|
||||
void onUIDescTagChanged (UIDescription* desc) override;
|
||||
void onUIDescColorChanged (UIDescription* desc) override;
|
||||
void onUIDescFontChanged (UIDescription* desc) override;
|
||||
void onUIDescBitmapChanged (UIDescription* desc) override;
|
||||
void onUIDescTemplateChanged (UIDescription* desc) override;
|
||||
void onUIDescGradientChanged (UIDescription* desc) override;
|
||||
|
||||
void selectionDidChange (UISelection* selection) override;
|
||||
void selectionViewsDidChange (UISelection* selection) override;
|
||||
|
||||
void onUndoManagerChange () override;
|
||||
|
||||
void viewWillDelete (CView* view) override;
|
||||
|
||||
SharedPointer<UISelection> selection;
|
||||
SharedPointer<UIUndoManager> undoManager;
|
||||
SharedPointer<UIDescription> editDescription;
|
||||
IAction* liveAction;
|
||||
|
||||
using UIAttributeControllerList = std::list<UIAttributeControllers::Controller*>;
|
||||
UIAttributeControllerList attributeControllers;
|
||||
|
||||
enum {
|
||||
kSearchFieldTag = 100,
|
||||
kViewNameTag = 101
|
||||
};
|
||||
|
||||
SharedPointer<CTextEdit> searchField;
|
||||
CTextLabel* viewNameLabel;
|
||||
CRowColumnView* attributeView;
|
||||
CColor attributeNameColor {kBlackCColor};
|
||||
|
||||
std::string filterString;
|
||||
|
||||
const std::string* currentAttributeName;
|
||||
|
||||
bool rebuildRequested{false};
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
|
||||
#endif // VSTGUI_LIVE_EDITING
|
||||
@@ -0,0 +1,304 @@
|
||||
// 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 "../iuidescription.h"
|
||||
|
||||
#if VSTGUI_LIVE_EDITING
|
||||
|
||||
#include "../uiattributes.h"
|
||||
#include "../uidescriptionlistener.h"
|
||||
#include "../../lib/cdatabrowser.h"
|
||||
#include "../../lib/genericstringlistdatabrowsersource.h"
|
||||
#include "../../lib/controls/csearchtextedit.h"
|
||||
#include "../../lib/controls/cscrollbar.h"
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class UIBaseDataSource : public GenericStringListDataBrowserSource, public IControlListener, public UIDescriptionListenerAdapter
|
||||
{
|
||||
public:
|
||||
using StringVector = GenericStringListDataBrowserSource::StringVector;
|
||||
|
||||
UIBaseDataSource (UIDescription* description, IActionPerformer* actionPerformer, GenericStringListDataBrowserSourceSelectionChanged* delegate = nullptr)
|
||||
: GenericStringListDataBrowserSource (0, delegate) , description (description), actionPerformer (actionPerformer)
|
||||
{
|
||||
description->registerListener (this);
|
||||
textInset.x = 4;
|
||||
}
|
||||
|
||||
~UIBaseDataSource () override
|
||||
{
|
||||
description->unregisterListener (this);
|
||||
}
|
||||
|
||||
void setSearchFieldControl (CSearchTextEdit* searchControl)
|
||||
{
|
||||
searchField = searchControl;
|
||||
searchField->setListener (this);
|
||||
}
|
||||
|
||||
virtual bool add ()
|
||||
{
|
||||
if (dataBrowser && actionPerformer)
|
||||
{
|
||||
std::string newName (filterString.empty () ? "New" : filterString.data ());
|
||||
if (createUniqueName (newName))
|
||||
{
|
||||
addItem (newName.data ());
|
||||
int32_t row = selectName (newName.data ());
|
||||
if (row != -1)
|
||||
{
|
||||
dbOnMouseDown (CPoint (0, 0), CButtonState (kLButton|kDoubleClick), row, 0, dataBrowser);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool remove ()
|
||||
{
|
||||
if (dataBrowser && actionPerformer)
|
||||
{
|
||||
int32_t selectedRow = dataBrowser->getSelectedRow ();
|
||||
if (selectedRow != CDataBrowser::kNoSelection)
|
||||
{
|
||||
removeItem (names.at (static_cast<uint32_t> (selectedRow)).data ());
|
||||
dbSelectionChanged (dataBrowser);
|
||||
dataBrowser->setSelectedRow (selectedRow);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void setFilter (const UTF8String& filter)
|
||||
{
|
||||
if (filterString != filter)
|
||||
{
|
||||
filterString = filter;
|
||||
int32_t selectedRow = dataBrowser ? dataBrowser->getSelectedRow () : CDataBrowser::kNoSelection;
|
||||
std::string selectedName;
|
||||
if (selectedRow != CDataBrowser::kNoSelection)
|
||||
selectedName = names.at (static_cast<uint32_t> (selectedRow));
|
||||
update ();
|
||||
if (selectedRow != CDataBrowser::kNoSelection)
|
||||
selectName (selectedName.data ());
|
||||
}
|
||||
}
|
||||
|
||||
virtual int32_t selectName (UTF8StringPtr name)
|
||||
{
|
||||
int32_t index = 0;
|
||||
for (auto& it : names)
|
||||
{
|
||||
if (it == name)
|
||||
{
|
||||
dataBrowser->setSelectedRow (index, true);
|
||||
if (delegate)
|
||||
delegate->dbSelectionChanged (index, this);
|
||||
return index;
|
||||
}
|
||||
++index;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
protected:
|
||||
virtual void getNames (std::list<const std::string*>& names) = 0;
|
||||
virtual bool addItem (UTF8StringPtr name) = 0;
|
||||
virtual bool removeItem (UTF8StringPtr name) = 0;
|
||||
virtual bool performNameChange (UTF8StringPtr oldName, UTF8StringPtr newName) = 0;
|
||||
virtual UTF8StringPtr getDefaultsName () = 0;
|
||||
|
||||
virtual void update ()
|
||||
{
|
||||
if (textEditControl)
|
||||
textEditControl->looseFocus ();
|
||||
names.clear ();
|
||||
std::list<const std::string*> tmpNames;
|
||||
getNames (tmpNames);
|
||||
|
||||
std::string filter = filterString.getString ();
|
||||
std::transform (filter.begin (), filter.end (), filter.begin (), ::tolower);
|
||||
|
||||
for (auto& name : tmpNames)
|
||||
{
|
||||
if (!filter.empty ())
|
||||
{
|
||||
std::string tmp (*name);
|
||||
std::transform (tmp.begin (), tmp.end (), tmp.begin (), ::tolower);
|
||||
if (tmp.find (filter) == std::string::npos)
|
||||
continue;
|
||||
}
|
||||
if (name->find ("~ ") == 0)
|
||||
continue; // don't show static items
|
||||
names.emplace_back (UTF8String (*name));
|
||||
}
|
||||
bool vsbIsVisible = false;
|
||||
if (dataBrowser)
|
||||
{
|
||||
if (auto vsb = dataBrowser->getVerticalScrollbar ())
|
||||
vsbIsVisible = vsb->isVisible ();
|
||||
}
|
||||
setStringList (&names);
|
||||
if (dataBrowser)
|
||||
{
|
||||
if (auto vsb = dataBrowser->getVerticalScrollbar ())
|
||||
{
|
||||
if (vsb->isVisible() != vsbIsVisible)
|
||||
dataBrowser->recalculateLayout ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void beforeUIDescSave (UIDescription* desc) override
|
||||
{
|
||||
saveDefaults ();
|
||||
};
|
||||
|
||||
void onUIDescriptionUpdate ()
|
||||
{
|
||||
int32_t selectedRow = dataBrowser ? dataBrowser->getSelectedRow () : CDataBrowser::kNoSelection;
|
||||
std::string selectedName;
|
||||
if (selectedRow != CDataBrowser::kNoSelection)
|
||||
selectedName = names.at (static_cast<uint32_t> (selectedRow));
|
||||
update ();
|
||||
if (selectedRow != CDataBrowser::kNoSelection)
|
||||
selectName (selectedName.data ());
|
||||
}
|
||||
|
||||
virtual void saveDefaults ()
|
||||
{
|
||||
UTF8StringPtr name = getDefaultsName ();
|
||||
if (name)
|
||||
{
|
||||
auto attributes = description->getCustomAttributes (name, true);
|
||||
if (attributes)
|
||||
{
|
||||
attributes->setAttribute ("FilterString", filterString.getString ());
|
||||
if (dataBrowser)
|
||||
{
|
||||
int32_t selectedRow = dataBrowser->getSelectedRow ();
|
||||
attributes->setIntegerAttribute ("SelectedRow", selectedRow);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void loadDefaults ()
|
||||
{
|
||||
UTF8StringPtr name = getDefaultsName ();
|
||||
if (name)
|
||||
{
|
||||
auto attributes = description->getCustomAttributes (name, true);
|
||||
if (attributes)
|
||||
{
|
||||
const std::string* str = attributes->getAttributeValue ("FilterString");
|
||||
if (str)
|
||||
setFilter (str->data ());
|
||||
if (dataBrowser)
|
||||
{
|
||||
int32_t selectedRow;
|
||||
if (attributes->getIntegerAttribute("SelectedRow", selectedRow))
|
||||
dataBrowser->setSelectedRow (selectedRow, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dbAttached (CDataBrowser* browser) override
|
||||
{
|
||||
GenericStringListDataBrowserSource::dbAttached (browser);
|
||||
update ();
|
||||
loadDefaults ();
|
||||
if (searchField)
|
||||
searchField->setText (filterString);
|
||||
}
|
||||
|
||||
void dbRemoved (CDataBrowser* browser) override
|
||||
{
|
||||
saveDefaults ();
|
||||
GenericStringListDataBrowserSource::dbRemoved (browser);
|
||||
}
|
||||
|
||||
void valueChanged (CControl* control) override
|
||||
{
|
||||
CTextEdit* edit = dynamic_cast<CTextEdit*>(control);
|
||||
if (edit)
|
||||
setFilter (edit->getText ());
|
||||
}
|
||||
|
||||
bool createUniqueName (std::string& name, int32_t count = 0)
|
||||
{
|
||||
std::stringstream str;
|
||||
str << name;
|
||||
if (count)
|
||||
{
|
||||
str << ' ';
|
||||
str << count;
|
||||
}
|
||||
for (auto& it : names)
|
||||
{
|
||||
if (it == str.str ())
|
||||
return createUniqueName (name, count+1);
|
||||
}
|
||||
name = str.str ();
|
||||
return true;
|
||||
}
|
||||
|
||||
CMouseEventResult dbOnMouseDown (const CPoint& where, const CButtonState& buttons, int32_t row, int32_t column, CDataBrowser* browser) override
|
||||
{
|
||||
if (buttons.isLeftButton () && buttons.isDoubleClick ())
|
||||
{
|
||||
browser->beginTextEdit (CDataBrowser::Cell (row, column), names.at (static_cast<uint32_t> (row)).data ());
|
||||
}
|
||||
return kMouseDownEventHandledButDontNeedMovedOrUpEvents;
|
||||
}
|
||||
|
||||
void dbCellTextChanged (int32_t _row, int32_t column, UTF8StringPtr newText, CDataBrowser* browser) override
|
||||
{
|
||||
textEditControl = nullptr;
|
||||
if (_row < 0 || _row >= static_cast<int32_t> (names.size ()))
|
||||
return;
|
||||
auto row = static_cast<size_t> (_row);
|
||||
for (auto& name : names)
|
||||
{
|
||||
if (name == newText)
|
||||
return;
|
||||
}
|
||||
auto& currentName = names.at (row);
|
||||
if (performNameChange (currentName.data (), newText))
|
||||
{
|
||||
if (selectName (newText) == -1 && row < names.size ())
|
||||
selectName (names.at (row).data ());
|
||||
}
|
||||
}
|
||||
|
||||
void dbCellSetupTextEdit (int32_t row, int32_t column, CTextEdit* control, CDataBrowser* browser) override
|
||||
{
|
||||
textEditControl = control;
|
||||
textEditControl->setBackColor (kWhiteCColor);
|
||||
textEditControl->setFontColor (fontColor);
|
||||
textEditControl->setFont (drawFont);
|
||||
textEditControl->setHoriAlign (textAlignment);
|
||||
textEditControl->setTextInset (textInset);
|
||||
}
|
||||
|
||||
SharedPointer<UIDescription> description;
|
||||
SharedPointer<CSearchTextEdit> searchField;
|
||||
SharedPointer<CTextEdit> textEditControl;
|
||||
IActionPerformer* actionPerformer;
|
||||
|
||||
StringVector names;
|
||||
UTF8String filterString;
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
|
||||
#endif // VSTGUI_LIVE_EDITING
|
||||
@@ -0,0 +1,64 @@
|
||||
// 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 "../uidescription.h"
|
||||
|
||||
#if VSTGUI_LIVE_EDITING
|
||||
|
||||
#include "uiselection.h"
|
||||
#include "uiundomanager.h"
|
||||
#include "iaction.h"
|
||||
#include "../delegationcontroller.h"
|
||||
#include "../../lib/cdatabrowser.h"
|
||||
#include "../../lib/genericstringlistdatabrowsersource.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
class UIBitmapsDataSource;
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class UIBitmapsController : public NonAtomicReferenceCounted,
|
||||
public DelegationController,
|
||||
public GenericStringListDataBrowserSourceSelectionChanged
|
||||
{
|
||||
public:
|
||||
UIBitmapsController (IController* baseController, UIDescription* description,
|
||||
IActionPerformer* actionPerformer, UIUndoManager* undoManager);
|
||||
~UIBitmapsController () override;
|
||||
|
||||
protected:
|
||||
CView* createView (const UIAttributes& attributes, const IUIDescription* description) override;
|
||||
CView* verifyView (CView* view, const UIAttributes& attributes, const IUIDescription* description) override;
|
||||
IControlListener* getControlListener (UTF8StringPtr name) override;
|
||||
void valueChanged (CControl* pControl) override;
|
||||
|
||||
void dbSelectionChanged (int32_t selectedRow, GenericStringListDataBrowserSource* source) override;
|
||||
void dbRowDoubleClick (int32_t row, GenericStringListDataBrowserSource* source) override;
|
||||
|
||||
void showSettingsDialog ();
|
||||
|
||||
static bool valueToString (float value, char utf8String[256], void* userData);
|
||||
static bool stringToValue (UTF8StringPtr txt, float& result, void* userData);
|
||||
|
||||
SharedPointer<UIDescription> editDescription;
|
||||
IActionPerformer* actionPerformer {nullptr};
|
||||
UIUndoManager* undoManager {nullptr};
|
||||
UIBitmapsDataSource* dataSource {nullptr};
|
||||
SharedPointer<CView> bitmapView;
|
||||
SharedPointer<CTextEdit> bitmapPathEdit;
|
||||
SharedPointer<CControl> settingButton;
|
||||
|
||||
enum {
|
||||
kAddTag = 0,
|
||||
kRemoveTag,
|
||||
kSearchTag,
|
||||
kBitmapPathTag,
|
||||
kSettingsTag
|
||||
};
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
|
||||
#endif // VSTGUI_LIVE_EDITING
|
||||
@@ -0,0 +1,155 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#include "uicolor.h"
|
||||
|
||||
#if VSTGUI_LIVE_EDITING
|
||||
|
||||
#include "../../lib/coffscreencontext.h"
|
||||
#include "../../lib/controls/coptionmenu.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
UIColor& UIColor::operator= (const CColor& c)
|
||||
{
|
||||
red = c.red; green = c.green; blue = c.blue; alpha = c.alpha;
|
||||
r = red; g = green; b = blue;
|
||||
updateHSL (kTo);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColor::updateHSL (HSLUpdateDirection direction)
|
||||
{
|
||||
if (direction == kTo)
|
||||
toHSL (hue, saturation, lightness);
|
||||
else
|
||||
{
|
||||
fromHSL (hue, saturation, lightness);
|
||||
r = red; g = green; b = blue;
|
||||
}
|
||||
editChange ();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColor::setHue (double h)
|
||||
{
|
||||
if (hue != h)
|
||||
{
|
||||
hue = h;
|
||||
updateHSL (kFrom);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColor::setSaturation (double s)
|
||||
{
|
||||
if (saturation != s)
|
||||
{
|
||||
saturation = s;
|
||||
updateHSL (kFrom);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColor::setLightness (double l)
|
||||
{
|
||||
if (lightness != l)
|
||||
{
|
||||
lightness = l;
|
||||
updateHSL (kFrom);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColor::setRed (double nr)
|
||||
{
|
||||
if (r != nr)
|
||||
{
|
||||
r = nr;
|
||||
red = static_cast<uint8_t> (nr);
|
||||
updateHSL (kTo);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColor::setGreen (double ng)
|
||||
{
|
||||
if (g != ng)
|
||||
{
|
||||
g = ng;
|
||||
green = static_cast<uint8_t> (ng);
|
||||
updateHSL (kTo);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColor::setBlue (double nb)
|
||||
{
|
||||
if (b != nb)
|
||||
{
|
||||
b = nb;
|
||||
blue = static_cast<uint8_t> (nb);
|
||||
updateHSL (kTo);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColor::setAlpha (double na)
|
||||
{
|
||||
alpha = static_cast<uint8_t> (na);
|
||||
editChange ();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColor::beginEdit ()
|
||||
{
|
||||
forEachListener ([this] (IUIColorListener* l) { l->uiColorBeginEditing (this); });
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColor::endEdit ()
|
||||
{
|
||||
forEachListener ([this] (IUIColorListener* l) { l->uiColorEndEditing (this); });
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColor::editChange ()
|
||||
{
|
||||
forEachListener ([this] (IUIColorListener* l) { l->uiColorChanged (this); });
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
SharedPointer<CBitmap> createColorIcon (CColor color, CPoint colorIconSize)
|
||||
{
|
||||
if (auto context = COffscreenContext::create (colorIconSize))
|
||||
{
|
||||
context->beginDraw ();
|
||||
context->setFillColor (color);
|
||||
context->drawRect (CRect (0, 0, colorIconSize.x, colorIconSize.y), kDrawFilled);
|
||||
context->endDraw ();
|
||||
return context->getBitmap ();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
SharedPointer<COptionMenu> createCSSColorMenu (const std::function<void (CColor)>& callback,
|
||||
CPoint colorIconSize)
|
||||
{
|
||||
auto cssColorMenu = makeOwned<COptionMenu> ();
|
||||
auto cssColors = getCSSNamedColors ();
|
||||
std::for_each (cssColors.begin (), cssColors.end (), [&] (const auto& el) {
|
||||
auto item = new CCommandMenuItem ({std::string (el.name.data (), el.name.size ())});
|
||||
item->setActions ([callback, el] (auto item) { callback (el.color); });
|
||||
item->setIcon (createColorIcon (el.color, colorIconSize));
|
||||
cssColorMenu->addEntry (item);
|
||||
});
|
||||
return cssColorMenu;
|
||||
}
|
||||
|
||||
} // VSTGUI
|
||||
|
||||
#endif // VSTGUI_LIVE_EDITING
|
||||
@@ -0,0 +1,95 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../lib/vstguibase.h"
|
||||
|
||||
#if VSTGUI_LIVE_EDITING
|
||||
|
||||
#include "../../lib/ccolor.h"
|
||||
#include "../../lib/dispatchlist.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
class UIColor;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
SharedPointer<COptionMenu> createCSSColorMenu (const std::function<void (CColor)>& callback,
|
||||
CPoint colorIconSize = {15., 15.});
|
||||
SharedPointer<CBitmap> createColorIcon (CColor color, CPoint colorIconSize = {15., 15.});
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class IUIColorListener
|
||||
{
|
||||
public:
|
||||
virtual ~IUIColorListener () noexcept = default;
|
||||
|
||||
virtual void uiColorChanged (UIColor* c) = 0;
|
||||
virtual void uiColorBeginEditing (UIColor* c) = 0;
|
||||
virtual void uiColorEndEditing (UIColor* c) = 0;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class UIColorListenerAdapter : public IUIColorListener
|
||||
{
|
||||
public:
|
||||
void uiColorChanged (UIColor* c) override {}
|
||||
void uiColorBeginEditing (UIColor* c) override {}
|
||||
void uiColorEndEditing (UIColor* c) override {}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class UIColor : public NonAtomicReferenceCounted,
|
||||
protected ListenerProvider<UIColor, IUIColorListener>,
|
||||
protected CColor
|
||||
{
|
||||
public:
|
||||
UIColor () : CColor (kTransparentCColor), hue (0), saturation (0), lightness (0) {}
|
||||
|
||||
UIColor& operator= (const CColor& c);
|
||||
const CColor& base () const { return *this; }
|
||||
|
||||
double getRed () const { return r; }
|
||||
double getGreen () const { return g; }
|
||||
double getBlue () const { return b; }
|
||||
double getAlpha () const { return alpha; }
|
||||
|
||||
double getHue () const { return hue; }
|
||||
double getSaturation () const { return saturation; }
|
||||
double getLightness () const { return lightness; }
|
||||
|
||||
void setHue (double h);
|
||||
void setSaturation (double s);
|
||||
void setLightness (double l);
|
||||
|
||||
void setRed (double nr);
|
||||
void setGreen (double ng);
|
||||
void setBlue (double nb);
|
||||
void setAlpha (double na);
|
||||
|
||||
void beginEdit ();
|
||||
void endEdit ();
|
||||
|
||||
using ListenerProvider<UIColor, IUIColorListener>::registerListener;
|
||||
using ListenerProvider<UIColor, IUIColorListener>::unregisterListener;
|
||||
using CColor::operator==;
|
||||
using CColor::operator!=;
|
||||
private:
|
||||
enum HSLUpdateDirection
|
||||
{
|
||||
kFrom,
|
||||
kTo
|
||||
};
|
||||
|
||||
void updateHSL (HSLUpdateDirection direction);
|
||||
void editChange ();
|
||||
|
||||
double hue, saturation, lightness;
|
||||
double r, g, b;
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
|
||||
#endif // VSTGUI_LIVE_EDITING
|
||||
@@ -0,0 +1,313 @@
|
||||
// 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 "uicolorchoosercontroller.h"
|
||||
|
||||
#if VSTGUI_LIVE_EDITING
|
||||
|
||||
#include "uicolorslider.h"
|
||||
#include "../uiattributes.h"
|
||||
#include "../iuidescription.h"
|
||||
#include "../../lib/dragging.h"
|
||||
#include <sstream>
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class UIColorChooserDropTarget : public NonAtomicReferenceCounted, public DropTargetAdapter
|
||||
{
|
||||
public:
|
||||
UIColorChooserDropTarget (UIColor* color) : color (color) {}
|
||||
DragOperation onDragEnter (DragEventData eventData) override
|
||||
{
|
||||
for (const auto& item : eventData.drag)
|
||||
{
|
||||
if (item.type != IDataPackage::kText)
|
||||
continue;
|
||||
std::string_view text (static_cast<const char*> (item.data), item.dataSize);
|
||||
if (CColor::isColorRepresentation (text))
|
||||
{
|
||||
CColor dragColor;
|
||||
if (dragColor.fromString (text) && *color != dragColor)
|
||||
{
|
||||
colorString = text;
|
||||
return DragOperation::Copy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return DragOperation::None;
|
||||
}
|
||||
DragOperation onDragMove (DragEventData eventData) override
|
||||
{
|
||||
return colorString.empty () ? DragOperation::None : DragOperation::Copy;
|
||||
}
|
||||
void onDragLeave (DragEventData eventData) override { colorString.clear (); }
|
||||
bool onDrop (DragEventData eventData) override
|
||||
{
|
||||
if (!colorString.empty ())
|
||||
{
|
||||
CColor dragColor;
|
||||
if (dragColor.fromString (colorString))
|
||||
{
|
||||
color->beginEdit ();
|
||||
*color = dragColor;
|
||||
color->endEdit ();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
UIColor* color;
|
||||
std::string colorString;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
UIColorChooserController::UIColorChooserController (IController* baseController, UIColor* color)
|
||||
: DelegationController (baseController)
|
||||
, color (color)
|
||||
{
|
||||
color->registerListener (this);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
UIColorChooserController::~UIColorChooserController ()
|
||||
{
|
||||
color->unregisterListener (this);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColorChooserController::updateColorSlider (CControl* control)
|
||||
{
|
||||
float value = 0.f;
|
||||
switch (control->getTag ())
|
||||
{
|
||||
case kHueTag:
|
||||
{
|
||||
value = (float)color->getHue ();
|
||||
break;
|
||||
}
|
||||
case kSaturationTag:
|
||||
{
|
||||
value = (float)color->getSaturation ();
|
||||
break;
|
||||
}
|
||||
case kLightnessTag:
|
||||
{
|
||||
value = (float)color->getLightness ();
|
||||
break;
|
||||
}
|
||||
case kRedTag:
|
||||
{
|
||||
value = (float)color->getRed ();
|
||||
break;
|
||||
}
|
||||
case kGreenTag:
|
||||
{
|
||||
value = (float)color->getGreen ();
|
||||
break;
|
||||
}
|
||||
case kBlueTag:
|
||||
{
|
||||
value = (float)color->getBlue ();
|
||||
break;
|
||||
}
|
||||
case kAlphaTag:
|
||||
{
|
||||
value = (float)color->getAlpha ();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
control->setValue (value);
|
||||
control->invalid ();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColorChooserController::updateColorSliders ()
|
||||
{
|
||||
for (auto& control : controls)
|
||||
updateColorSlider (control);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColorChooserController::uiColorChanged (UIColor* c)
|
||||
{
|
||||
updateColorSliders ();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool UIColorChooserController::valueToString (float value, char utf8String[256], CParamDisplay::ValueToStringUserData* userData)
|
||||
{
|
||||
auto* display = static_cast<CParamDisplay*>(userData);
|
||||
std::stringstream str;
|
||||
switch (display->getTag ())
|
||||
{
|
||||
case kSaturationTag:
|
||||
case kLightnessTag:
|
||||
{
|
||||
str << (uint32_t)(value * 100);
|
||||
str << " %";
|
||||
break;
|
||||
}
|
||||
case kHueTag:
|
||||
{
|
||||
str << (uint32_t)value;
|
||||
str << kDegreeSymbol;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
str << (uint32_t)value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
strncpy (utf8String, str.str ().c_str (), 255);
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool UIColorChooserController::stringToValue (UTF8StringPtr txt, float& result, CTextEdit::StringToValueUserData* userData)
|
||||
{
|
||||
std::locale origLocale;
|
||||
std::locale::global (std::locale::classic ());
|
||||
|
||||
char* endptr = nullptr;
|
||||
result = (float)strtod (txt, &endptr);
|
||||
|
||||
std::locale::global (origLocale);
|
||||
if (endptr != txt)
|
||||
{
|
||||
auto* display = static_cast<CParamDisplay*>(userData);
|
||||
switch (display->getTag ())
|
||||
{
|
||||
case kSaturationTag:
|
||||
case kLightnessTag:
|
||||
{
|
||||
result /= 100.f;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
CView* UIColorChooserController::createView (const UIAttributes& attributes, const IUIDescription* description)
|
||||
{
|
||||
const std::string* name = attributes.getAttributeValue (IUIDescription::kCustomViewName);
|
||||
if (name)
|
||||
{
|
||||
if (*name == "UIColorSlider")
|
||||
{
|
||||
const std::string* controlTagStr = attributes.getAttributeValue ("control-tag");
|
||||
int32_t tag = controlTagStr ? description->getTagForName (controlTagStr->c_str ()) : -1;
|
||||
if (tag != -1)
|
||||
{
|
||||
return new UIColorSlider (color, tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return DelegationController::createView (attributes, description);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
CView* UIColorChooserController::verifyView (CView* view, const UIAttributes& attributes, const IUIDescription* description)
|
||||
{
|
||||
auto* control = dynamic_cast<CControl*>(view);
|
||||
if (control && control->getTag () >= 0)
|
||||
{
|
||||
controls.emplace_back (control);
|
||||
auto* textEdit = dynamic_cast<CTextEdit*> (control);
|
||||
if (textEdit)
|
||||
{
|
||||
textEdit->setValueToStringFunction (valueToString);
|
||||
textEdit->setStringToValueFunction (stringToValue);
|
||||
}
|
||||
updateColorSlider (control);
|
||||
}
|
||||
else if (auto container = view->asViewContainer ())
|
||||
{
|
||||
container->setDropTarget (makeOwned<UIColorChooserDropTarget> (color));
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
IControlListener* UIColorChooserController::getControlListener (UTF8StringPtr name)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColorChooserController::controlBeginEdit (CControl* pControl)
|
||||
{
|
||||
if (pControl->getTag () >= kHueTag && pControl->getTag () <= kAlphaTag)
|
||||
{
|
||||
color->beginEdit ();
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColorChooserController::controlEndEdit (CControl* pControl)
|
||||
{
|
||||
if (pControl->getTag () >= kHueTag && pControl->getTag () <= kAlphaTag)
|
||||
{
|
||||
color->endEdit ();
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColorChooserController::valueChanged (CControl* pControl)
|
||||
{
|
||||
switch (pControl->getTag ())
|
||||
{
|
||||
case kHueTag:
|
||||
{
|
||||
color->setHue (pControl->getValue ());
|
||||
break;
|
||||
}
|
||||
case kSaturationTag:
|
||||
{
|
||||
color->setSaturation (pControl->getValue ());
|
||||
break;
|
||||
}
|
||||
case kLightnessTag:
|
||||
{
|
||||
color->setLightness (pControl->getValue ());
|
||||
break;
|
||||
}
|
||||
case kRedTag:
|
||||
{
|
||||
color->setRed (pControl->getValue ());
|
||||
break;
|
||||
}
|
||||
case kGreenTag:
|
||||
{
|
||||
color->setGreen (pControl->getValue ());
|
||||
break;
|
||||
}
|
||||
case kBlueTag:
|
||||
{
|
||||
color->setBlue (pControl->getValue ());
|
||||
break;
|
||||
}
|
||||
case kAlphaTag:
|
||||
{
|
||||
color->setAlpha (pControl->getValue ());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // VSTGUI
|
||||
|
||||
#endif // VSTGUI_LIVE_EDITING
|
||||
@@ -0,0 +1,61 @@
|
||||
// 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 "../../lib/vstguibase.h"
|
||||
|
||||
#if VSTGUI_LIVE_EDITING
|
||||
|
||||
#include "uicolor.h"
|
||||
#include "../delegationcontroller.h"
|
||||
#include "../../lib/controls/ctextedit.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
class UIColor;
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class UIColorChooserController : public NonAtomicReferenceCounted,
|
||||
public DelegationController,
|
||||
public UIColorListenerAdapter
|
||||
{
|
||||
public:
|
||||
UIColorChooserController (IController* baseController, UIColor* color);
|
||||
~UIColorChooserController () override;
|
||||
|
||||
protected:
|
||||
CView* createView (const UIAttributes& attributes, const IUIDescription* description) override;
|
||||
CView* verifyView (CView* view, const UIAttributes& attributes, const IUIDescription* description) override;
|
||||
IControlListener* getControlListener (UTF8StringPtr name) override;
|
||||
void valueChanged (CControl* pControl) override;
|
||||
void controlBeginEdit (CControl* pControl) override;
|
||||
void controlEndEdit (CControl* pControl) override;
|
||||
|
||||
void updateColorSlider (CControl* control);
|
||||
void updateColorSliders ();
|
||||
|
||||
void uiColorChanged (UIColor* c) override;
|
||||
|
||||
static bool valueToString (float value, char utf8String[256], CParamDisplay::ValueToStringUserData* userData);
|
||||
static bool stringToValue (UTF8StringPtr txt, float& result, CTextEdit::StringToValueUserData* userData);
|
||||
|
||||
SharedPointer<UIColor> color;
|
||||
using ControlList = std::list<SharedPointer<CControl>>;
|
||||
ControlList controls;
|
||||
|
||||
enum {
|
||||
kHueTag = 0,
|
||||
kSaturationTag,
|
||||
kLightnessTag,
|
||||
kRedTag,
|
||||
kGreenTag,
|
||||
kBlueTag,
|
||||
kAlphaTag,
|
||||
kNumTags
|
||||
};
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
|
||||
#endif // VSTGUI_LIVE_EDITING
|
||||
@@ -0,0 +1,505 @@
|
||||
// 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 "uicolorscontroller.h"
|
||||
|
||||
#if VSTGUI_LIVE_EDITING
|
||||
|
||||
#include "uicolor.h"
|
||||
#include "uicolorchoosercontroller.h"
|
||||
#include "uieditcontroller.h"
|
||||
#include "uibasedatasource.h"
|
||||
#include "../../lib/ccolor.h"
|
||||
#include "../../lib/cdropsource.h"
|
||||
#include "../../lib/coffscreencontext.h"
|
||||
#include "../../lib/dragging.h"
|
||||
#include "../../lib/optional.h"
|
||||
#include "../../lib/idatapackage.h"
|
||||
#include "../../lib/controls/coptionmenu.h"
|
||||
#include "../../lib/controls/csearchtextedit.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class UIColorsDataSource : public UIBaseDataSource, public UIColorListenerAdapter
|
||||
{
|
||||
public:
|
||||
UIColorsDataSource (UIDescription* description, IActionPerformer* actionPerformer, UIColor* color);
|
||||
~UIColorsDataSource () override;
|
||||
|
||||
protected:
|
||||
void onUIDescColorChanged (UIDescription* desc) override;
|
||||
void update () override;
|
||||
void getNames (std::list<const std::string*>& names) override;
|
||||
bool addItem (UTF8StringPtr name) override;
|
||||
bool removeItem (UTF8StringPtr name) override;
|
||||
bool performNameChange (UTF8StringPtr oldName, UTF8StringPtr newName) override;
|
||||
UTF8StringPtr getDefaultsName () override { return "UIColorsDataSource"; }
|
||||
|
||||
void dbDrawCell (CDrawContext* context, const CRect& size, int32_t row, int32_t column, int32_t flags, CDataBrowser* browser) override;
|
||||
void dbCellSetupTextEdit (int32_t row, int32_t column, CTextEdit* control, CDataBrowser* browser) override;
|
||||
void dbSelectionChanged (CDataBrowser* browser) override;
|
||||
|
||||
void dbOnDragEnterBrowser (IDataPackage* drag, CDataBrowser* browser) override;
|
||||
void dbOnDragExitBrowser (IDataPackage* drag, CDataBrowser* browser) override;
|
||||
DragOperation dbOnDragEnterCell (int32_t row, int32_t column, const CPoint& where, IDataPackage* drag, CDataBrowser* browser) override;
|
||||
DragOperation dbOnDragMoveInCell (int32_t row, int32_t column, const CPoint& where, IDataPackage* drag, CDataBrowser* browser) override;
|
||||
void dbOnDragExitCell (int32_t row, int32_t column, IDataPackage* drag, CDataBrowser* browser) override;
|
||||
bool dbOnDropInCell (int32_t row, int32_t column, const CPoint& where, IDataPackage* drag, CDataBrowser* browser) override;
|
||||
CMouseEventResult dbOnMouseDown (const CPoint& where, const CButtonState& buttons, int32_t row, int32_t column, CDataBrowser* browser) override;
|
||||
CMouseEventResult dbOnMouseMoved (const CPoint& where, const CButtonState& buttons, int32_t row, int32_t column, CDataBrowser* browser) override;
|
||||
CMouseEventResult dbOnMouseUp (const CPoint& where, const CButtonState& buttons, int32_t row,
|
||||
int32_t column, CDataBrowser* browser) override;
|
||||
|
||||
CCoord getColorIconWith ();
|
||||
|
||||
void uiColorChanged (UIColor* c) override;
|
||||
void uiColorBeginEditing (UIColor* c) override;
|
||||
void uiColorEndEditing (UIColor* c) override;
|
||||
|
||||
SharedPointer<UIColor> color;
|
||||
bool editing;
|
||||
Optional<CColor> dragColor;
|
||||
int32_t dragRow;
|
||||
DragStartMouseObserver dragStartMouseObserver;
|
||||
bool allowDrag {false};
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
UIColorsDataSource::UIColorsDataSource (UIDescription* description, IActionPerformer* actionPerformer, UIColor* color)
|
||||
: UIBaseDataSource (description, actionPerformer)
|
||||
, color (color)
|
||||
, editing (false)
|
||||
, dragRow (-1)
|
||||
{
|
||||
color->registerListener (this);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
UIColorsDataSource::~UIColorsDataSource ()
|
||||
{
|
||||
color->unregisterListener (this);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColorsDataSource::onUIDescColorChanged (UIDescription* desc)
|
||||
{
|
||||
onUIDescriptionUpdate ();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColorsDataSource::uiColorChanged (UIColor* c)
|
||||
{
|
||||
if (editing)
|
||||
{
|
||||
int32_t selectedRow = dataBrowser->getSelectedRow ();
|
||||
if (selectedRow != CDataBrowser::kNoSelection)
|
||||
{
|
||||
actionPerformer->performLiveColorChange (
|
||||
names.at (static_cast<uint32_t> (selectedRow)).data (), color->base ());
|
||||
dataBrowser->setSelectedRow (selectedRow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColorsDataSource::uiColorBeginEditing (UIColor* c)
|
||||
{
|
||||
int32_t selectedRow = dataBrowser->getSelectedRow ();
|
||||
if (selectedRow != CDataBrowser::kNoSelection)
|
||||
{
|
||||
actionPerformer->beginLiveColorChange (
|
||||
names.at (static_cast<uint32_t> (selectedRow)).data ());
|
||||
editing = true;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColorsDataSource::uiColorEndEditing (UIColor* c)
|
||||
{
|
||||
int32_t selectedRow = dataBrowser->getSelectedRow ();
|
||||
if (selectedRow != CDataBrowser::kNoSelection)
|
||||
{
|
||||
actionPerformer->endLiveColorChange (
|
||||
names.at (static_cast<uint32_t> (selectedRow)).data ());
|
||||
editing = false;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColorsDataSource::getNames (std::list<const std::string*>& names)
|
||||
{
|
||||
description->collectColorNames (names);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool UIColorsDataSource::addItem (UTF8StringPtr name)
|
||||
{
|
||||
actionPerformer->performColorChange (name, kWhiteCColor);
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool UIColorsDataSource::removeItem (UTF8StringPtr name)
|
||||
{
|
||||
actionPerformer->performColorChange (name, kWhiteCColor, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColorsDataSource::update ()
|
||||
{
|
||||
UIBaseDataSource::update ();
|
||||
if (dataBrowser)
|
||||
{
|
||||
dbSelectionChanged (dataBrowser);
|
||||
dataBrowser->invalid ();
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColorsDataSource::dbSelectionChanged (CDataBrowser* browser)
|
||||
{
|
||||
int32_t selectedRow = dataBrowser->getSelectedRow ();
|
||||
if (selectedRow != CDataBrowser::kNoSelection)
|
||||
{
|
||||
CColor c;
|
||||
if (description->getColor (names.at (static_cast<uint32_t> (selectedRow)).data (), c))
|
||||
{
|
||||
if (c != color->base ())
|
||||
{
|
||||
*color = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
CCoord UIColorsDataSource::getColorIconWith ()
|
||||
{
|
||||
return dataBrowser ? dbGetRowHeight (dataBrowser) : 0.;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColorsDataSource::dbDrawCell (CDrawContext* context, const CRect& size, int32_t row, int32_t column, int32_t flags, CDataBrowser* browser)
|
||||
{
|
||||
GenericStringListDataBrowserSource::drawRowBackground (context, size, row, flags, browser);
|
||||
CRect r (size);
|
||||
r.right -= getColorIconWith ();
|
||||
GenericStringListDataBrowserSource::drawRowString (context, r, row, flags, browser);
|
||||
CColor cellColor;
|
||||
if (description->getColor (names.at (static_cast<uint32_t> (row)).data (), cellColor))
|
||||
{
|
||||
context->setFillColor (cellColor);
|
||||
context->setFrameColor (dragRow == row ? kRedCColor : kBlackCColor);
|
||||
context->setLineWidth (context->getHairlineSize ());
|
||||
context->setLineStyle (kLineSolid);
|
||||
context->setDrawMode (kAliasing);
|
||||
r = size;
|
||||
r.left = r.right - getColorIconWith ();
|
||||
r.inset (2, 2);
|
||||
context->drawRect (r, kDrawFilledAndStroked);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColorsDataSource::dbCellSetupTextEdit (int32_t row, int32_t column, CTextEdit* control, CDataBrowser* browser)
|
||||
{
|
||||
UIBaseDataSource::dbCellSetupTextEdit(row, column, control, browser);
|
||||
CRect r (control->getViewSize ());
|
||||
r.right -= getColorIconWith ();
|
||||
control->setViewSize (r);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
CMouseEventResult UIColorsDataSource::dbOnMouseDown (const CPoint& where,
|
||||
const CButtonState& buttons, int32_t row,
|
||||
int32_t column, CDataBrowser* browser)
|
||||
{
|
||||
auto r = browser->getCellBounds ({row, column});
|
||||
r.left = r.right - getColorIconWith ();
|
||||
r.inset (2, 2);
|
||||
if (r.pointInside (where))
|
||||
{
|
||||
allowDrag = true;
|
||||
dragStartMouseObserver.init (where);
|
||||
}
|
||||
UIBaseDataSource::dbOnMouseDown (where, buttons, row, column, browser);
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
CMouseEventResult UIColorsDataSource::dbOnMouseMoved (const CPoint& where,
|
||||
const CButtonState& buttons, int32_t row,
|
||||
int32_t column, CDataBrowser* browser)
|
||||
{
|
||||
if (row < 0 || column < 0)
|
||||
return UIBaseDataSource::dbOnMouseMoved (where, buttons, row, column, browser);
|
||||
|
||||
auto r = browser->getCellBounds ({row, column});
|
||||
r.left = r.right - getColorIconWith ();
|
||||
r.inset (2, 2);
|
||||
if (allowDrag)
|
||||
{
|
||||
if (buttons.isLeftButton ())
|
||||
{
|
||||
if (dragStartMouseObserver.shouldStartDrag (where))
|
||||
{
|
||||
CColor cellColor;
|
||||
if (description->getColor (names.at (static_cast<uint32_t> (row)).data (), cellColor))
|
||||
{
|
||||
auto colorStr = cellColor.toString ();
|
||||
auto dropSource = CDropSource::create (
|
||||
colorStr.data (), static_cast<uint32_t> (colorStr.length () + 1),
|
||||
CDropSource::kText);
|
||||
SharedPointer<CBitmap> dragBitmap;
|
||||
if (auto offscreen = COffscreenContext::create (r.getSize ()))
|
||||
{
|
||||
offscreen->beginDraw ();
|
||||
offscreen->setFillColor (cellColor);
|
||||
offscreen->drawRect (CRect (0, 0, r.getWidth(), r.getHeight()), kDrawFilled);
|
||||
offscreen->endDraw();
|
||||
dragBitmap = offscreen->getBitmap ();
|
||||
}
|
||||
|
||||
auto df = makeOwned<DragCallbackFunctions> ();
|
||||
df->endedFunc = [browser, Self = shared (this)] (IDraggingSession*, CPoint,
|
||||
DragOperation) {
|
||||
browser->getFrame ()->setCursor (kCursorDefault);
|
||||
Self->allowDrag = false;
|
||||
};
|
||||
browser->doDrag (DragDescription (dropSource, -r.getSize () / 2., dragBitmap), df);
|
||||
}
|
||||
}
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
}
|
||||
if (r.pointInside (where))
|
||||
browser->getFrame ()->setCursor (kCursorMovableObject);
|
||||
else
|
||||
browser->getFrame ()->setCursor (kCursorDefault);
|
||||
return UIBaseDataSource::dbOnMouseMoved (where, buttons, row, column, browser);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
CMouseEventResult UIColorsDataSource::dbOnMouseUp (const CPoint& where, const CButtonState& buttons,
|
||||
int32_t row, int32_t column,
|
||||
CDataBrowser* browser)
|
||||
{
|
||||
allowDrag = false;
|
||||
return UIBaseDataSource::dbOnMouseUp (where, buttons, row, column, browser);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool UIColorsDataSource::performNameChange (UTF8StringPtr oldName, UTF8StringPtr newName)
|
||||
{
|
||||
actionPerformer->performColorNameChange (oldName, newName);
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColorsDataSource::dbOnDragEnterBrowser (IDataPackage* drag, CDataBrowser* browser)
|
||||
{
|
||||
for (const auto& item : drag)
|
||||
{
|
||||
if (item.type != IDataPackage::kText)
|
||||
continue;
|
||||
std::string_view text (static_cast<const char*> (item.data), item.dataSize);
|
||||
if (CColor::isColorRepresentation (text))
|
||||
{
|
||||
CColor c;
|
||||
c.fromString (text);
|
||||
dragColor = Optional<CColor> (c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColorsDataSource::dbOnDragExitBrowser (IDataPackage* drag, CDataBrowser* browser)
|
||||
{
|
||||
dragColor = {};
|
||||
dragRow = -1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
DragOperation UIColorsDataSource::dbOnDragEnterCell (int32_t row, int32_t column, const CPoint& where, IDataPackage* drag, CDataBrowser* browser)
|
||||
{
|
||||
if (dragColor && row >= 0)
|
||||
{
|
||||
CColor cellColor;
|
||||
if (description->getColor (names.at (static_cast<uint32_t> (row)).data (), cellColor) &&
|
||||
cellColor != *dragColor)
|
||||
{
|
||||
dragRow = row;
|
||||
browser->invalidateRow (dragRow);
|
||||
return DragOperation::Copy;
|
||||
}
|
||||
else
|
||||
dragRow = -1;
|
||||
}
|
||||
return DragOperation::None;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
DragOperation UIColorsDataSource::dbOnDragMoveInCell (int32_t row, int32_t column, const CPoint& where, IDataPackage* drag, CDataBrowser* browser)
|
||||
{
|
||||
return (dragColor && (dragRow >= 0 || row == -1)) ? DragOperation::Copy : DragOperation::None;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColorsDataSource::dbOnDragExitCell (int32_t row, int32_t column, IDataPackage* drag, CDataBrowser* browser)
|
||||
{
|
||||
if (dragColor)
|
||||
{
|
||||
if (dragRow >= 0)
|
||||
browser->invalidateRow (dragRow);
|
||||
dragRow = -1;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool UIColorsDataSource::dbOnDropInCell (int32_t row, int32_t column, const CPoint& where, IDataPackage* drag, CDataBrowser* browser)
|
||||
{
|
||||
if (dragColor)
|
||||
{
|
||||
if (row >= 0)
|
||||
{
|
||||
CColor cellColor;
|
||||
if (description->getColor (names.at (static_cast<uint32_t> (row)).data (), cellColor))
|
||||
{
|
||||
if (cellColor != *dragColor)
|
||||
{
|
||||
actionPerformer->performColorChange (names[static_cast<uint32_t> (row)].data (), *dragColor);
|
||||
selectName (names[static_cast<uint32_t> (row)].data ());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string newName (filterString.empty () ? "New" : filterString.data ());
|
||||
if (createUniqueName (newName))
|
||||
{
|
||||
actionPerformer->performColorChange (newName.data (), *dragColor);
|
||||
selectName (newName.data ());
|
||||
}
|
||||
}
|
||||
dragColor = {};
|
||||
dragRow = -1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
UIColorsController::UIColorsController (IController* baseController, UIDescription* description, IActionPerformer* actionPerformer)
|
||||
: DelegationController (baseController)
|
||||
, editDescription (description)
|
||||
, actionPerformer (actionPerformer)
|
||||
, dataSource (nullptr)
|
||||
, color (makeOwned<UIColor> ())
|
||||
{
|
||||
dataSource = new UIColorsDataSource (editDescription, actionPerformer, color);
|
||||
UIEditController::setupDataSource (dataSource);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
UIColorsController::~UIColorsController ()
|
||||
{
|
||||
dataSource->forget ();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
CView* UIColorsController::createView (const UIAttributes& attributes, const IUIDescription* description)
|
||||
{
|
||||
const std::string* name = attributes.getAttributeValue (IUIDescription::kCustomViewName);
|
||||
if (name)
|
||||
{
|
||||
if (*name == "ColorsBrowser")
|
||||
{
|
||||
CDataBrowser* dataBrowser = new CDataBrowser (CRect (0, 0, 0, 0), dataSource, CDataBrowser::kDrawRowLines|CScrollView::kHorizontalScrollbar|CScrollView::kVerticalScrollbar);
|
||||
return dataBrowser;
|
||||
}
|
||||
}
|
||||
return DelegationController::createView (attributes, description);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
CView* UIColorsController::verifyView (CView* view, const UIAttributes& attributes, const IUIDescription* description)
|
||||
{
|
||||
auto searchField = dynamic_cast<CSearchTextEdit*>(view);
|
||||
if (searchField && searchField->getTag () == kSearchTag)
|
||||
{
|
||||
dataSource->setSearchFieldControl (searchField);
|
||||
return searchField;
|
||||
}
|
||||
return controller->verifyView (view, attributes, description);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
IControlListener* UIColorsController::getControlListener (UTF8StringPtr name)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColorsController::valueChanged (CControl* pControl)
|
||||
{
|
||||
switch (pControl->getTag ())
|
||||
{
|
||||
case kAddTag:
|
||||
{
|
||||
if (pControl->getValue () == pControl->getMax ())
|
||||
{
|
||||
dataSource->add ();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kRemoveTag:
|
||||
{
|
||||
if (pControl->getValue () == pControl->getMax ())
|
||||
{
|
||||
dataSource->remove ();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
IController* UIColorsController::createSubController (IdStringPtr name, const IUIDescription* description)
|
||||
{
|
||||
if (std::strcmp (name, "ColorChooserController") == 0)
|
||||
return new UIColorChooserController (this, color);
|
||||
return controller->createSubController (name, description);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColorsController::appendContextMenuItems (COptionMenu& contextMenu, CView* view,
|
||||
const CPoint& where)
|
||||
{
|
||||
auto item = new CCommandMenuItem ({"Add Color"});
|
||||
item->setActions ([this] (auto) { dataSource->add (); });
|
||||
contextMenu.addEntry (item);
|
||||
item = new CCommandMenuItem ({"Remove Color"});
|
||||
item->setActions ([this] (auto) { dataSource->remove (); });
|
||||
contextMenu.addEntry (item);
|
||||
contextMenu.addSeparator ();
|
||||
|
||||
auto cssColorMenu = createCSSColorMenu ([this] (auto newColor) {
|
||||
if (color)
|
||||
{
|
||||
color->beginEdit ();
|
||||
*color = newColor;
|
||||
color->endEdit ();
|
||||
}
|
||||
});
|
||||
contextMenu.addEntry (cssColorMenu, "Set to CSS Color");
|
||||
}
|
||||
|
||||
} // VSTGUI
|
||||
|
||||
#endif // VSTGUI_LIVE_EDITING
|
||||
@@ -0,0 +1,53 @@
|
||||
// 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 "../uidescription.h"
|
||||
|
||||
#if VSTGUI_LIVE_EDITING
|
||||
|
||||
#include "../delegationcontroller.h"
|
||||
#include "uiselection.h"
|
||||
#include "uiundomanager.h"
|
||||
#include "iaction.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
class UIColorsDataSource;
|
||||
class UIColor;
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class UIColorsController : public NonAtomicReferenceCounted,
|
||||
public DelegationController,
|
||||
public IContextMenuController2
|
||||
{
|
||||
public:
|
||||
UIColorsController (IController* baseController, UIDescription* description, IActionPerformer* actionPerformer);
|
||||
~UIColorsController () override;
|
||||
|
||||
protected:
|
||||
CView* createView (const UIAttributes& attributes, const IUIDescription* description) override;
|
||||
CView* verifyView (CView* view, const UIAttributes& attributes, const IUIDescription* description) override;
|
||||
IControlListener* getControlListener (UTF8StringPtr name) override;
|
||||
void valueChanged (CControl* pControl) override;
|
||||
IController* createSubController (IdStringPtr name, const IUIDescription* description) override;
|
||||
|
||||
void appendContextMenuItems (COptionMenu& contextMenu, CView* view,
|
||||
const CPoint& where) override;
|
||||
|
||||
SharedPointer<UIDescription> editDescription;
|
||||
IActionPerformer* actionPerformer;
|
||||
UIColorsDataSource* dataSource;
|
||||
SharedPointer<UIColor> color;
|
||||
|
||||
enum {
|
||||
kAddTag = 0,
|
||||
kRemoveTag,
|
||||
kSearchTag
|
||||
};
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
|
||||
#endif // VSTGUI_LIVE_EDITING
|
||||
@@ -0,0 +1,167 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#include "uicolorslider.h"
|
||||
|
||||
#if VSTGUI_LIVE_EDITING
|
||||
|
||||
#include "../../lib/coffscreencontext.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
UIColorSlider::UIColorSlider (UIColor* color, int32_t style)
|
||||
: CSlider (CRect (0, 0, 0, 0), nullptr, 0, 0, 0, nullptr, nullptr)
|
||||
, color (color)
|
||||
, style (style)
|
||||
{
|
||||
color->registerListener (this);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
UIColorSlider::~UIColorSlider ()
|
||||
{
|
||||
color->unregisterListener (this);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColorSlider::draw (CDrawContext* context)
|
||||
{
|
||||
if (getHandle () == nullptr)
|
||||
updateHandle (context);
|
||||
if (getBackground () == nullptr)
|
||||
updateBackground (context);
|
||||
CSlider::draw (context);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColorSlider::setViewSize (const CRect& rect, bool invalid)
|
||||
{
|
||||
bool widthDifferent = rect.getWidth () != getWidth ();
|
||||
bool heightDifferent = rect.getHeight () != getHeight ();
|
||||
CSlider::setViewSize (rect, invalid);
|
||||
if (widthDifferent)
|
||||
setBackground (nullptr);
|
||||
if (heightDifferent)
|
||||
setHandle (nullptr);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColorSlider::uiColorChanged (UIColor* c)
|
||||
{
|
||||
setBackground (nullptr);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColorSlider::updateBackground (CDrawContext* context)
|
||||
{
|
||||
double scaleFactor = context->getScaleFactor ();
|
||||
if (auto offscreen = COffscreenContext::create ({getWidth (), getHeight ()}, scaleFactor))
|
||||
{
|
||||
const int32_t kNumPoints = (style <= kLightness) ? 360 : 256;
|
||||
CCoord width = std::floor (getWidth () + 0.5);
|
||||
offscreen->beginDraw ();
|
||||
offscreen->setDrawMode (kAliasing);
|
||||
CCoord minWidth = 1. / scaleFactor;
|
||||
CCoord widthPerColor = width / static_cast<double> (kNumPoints - 1);
|
||||
CRect r;
|
||||
r.setHeight (getHeight ());
|
||||
r.setWidth (widthPerColor < minWidth ? minWidth : (std::floor (widthPerColor * scaleFactor + 0.5) / scaleFactor));
|
||||
r.offset (-r.getWidth (), 0);
|
||||
offscreen->setLineWidth (minWidth);
|
||||
|
||||
auto maxLines = static_cast<size_t> (std::ceil (widthPerColor / minWidth));
|
||||
CDrawContext::LineList lines;
|
||||
lines.reserve (maxLines);
|
||||
|
||||
for (int32_t i = 0; i < kNumPoints; i++)
|
||||
{
|
||||
CCoord x = std::floor (widthPerColor * i * scaleFactor + 0.5) / scaleFactor;
|
||||
if (x > r.right || i == kNumPoints -1)
|
||||
{
|
||||
CColor c = color->base ();
|
||||
switch (style)
|
||||
{
|
||||
case kRed:
|
||||
{
|
||||
c.red = (uint8_t)i;
|
||||
break;
|
||||
}
|
||||
case kGreen:
|
||||
{
|
||||
c.green = (uint8_t)i;
|
||||
break;
|
||||
}
|
||||
case kBlue:
|
||||
{
|
||||
c.blue = (uint8_t)i;
|
||||
break;
|
||||
}
|
||||
case kAlpha:
|
||||
{
|
||||
c.alpha = (uint8_t)i;
|
||||
break;
|
||||
}
|
||||
case kHue:
|
||||
{
|
||||
double hue = (static_cast<double> (i) / static_cast<double> (kNumPoints)) * 360.;
|
||||
c.fromHSL (hue, color->getSaturation (), color->getLightness ());
|
||||
break;
|
||||
}
|
||||
case kSaturation:
|
||||
{
|
||||
double sat = (static_cast<double> (i) / static_cast<double> (kNumPoints));
|
||||
c.fromHSL (color->getHue (), sat, color->getLightness ());
|
||||
break;
|
||||
}
|
||||
case kLightness:
|
||||
{
|
||||
double light = (static_cast<double> (i) / static_cast<double> (kNumPoints));
|
||||
c.fromHSL (color->getHue (), color->getSaturation (), light);
|
||||
break;
|
||||
}
|
||||
}
|
||||
offscreen->setFrameColor (c);
|
||||
CCoord next = r.left + widthPerColor;
|
||||
while (r.left < next)
|
||||
{
|
||||
lines.emplace_back (r.getTopLeft (), r.getBottomLeft ());
|
||||
r.offset (minWidth, 0);
|
||||
}
|
||||
if (!lines.empty ())
|
||||
{
|
||||
offscreen->drawLines (lines);
|
||||
lines.clear ();
|
||||
}
|
||||
}
|
||||
}
|
||||
offscreen->drawLine (r.getTopLeft (), r.getBottomLeft ());
|
||||
offscreen->endDraw ();
|
||||
setBackground (offscreen->getBitmap ());
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColorSlider::updateHandle (CDrawContext* context)
|
||||
{
|
||||
if (auto offscreen = COffscreenContext::create ({7., getHeight ()}, context->getScaleFactor ()))
|
||||
{
|
||||
auto lineWidth = 1.;
|
||||
offscreen->beginDraw ();
|
||||
offscreen->setFrameColor (kBlackCColor);
|
||||
offscreen->setLineWidth (lineWidth);
|
||||
offscreen->setDrawMode (kAliasing);
|
||||
CRect r (0, 0, 7, getHeight ());
|
||||
offscreen->drawRect (r, kDrawStroked);
|
||||
r.inset (lineWidth, lineWidth);
|
||||
offscreen->setFrameColor (kWhiteCColor);
|
||||
offscreen->drawRect (r, kDrawStroked);
|
||||
offscreen->endDraw ();
|
||||
setHandle (offscreen->getBitmap ());
|
||||
}
|
||||
}
|
||||
|
||||
} // VSTGUI
|
||||
|
||||
#endif // VSTGUI_LIVE_EDITING
|
||||
@@ -0,0 +1,51 @@
|
||||
// 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 "../../lib/vstguibase.h"
|
||||
|
||||
#if VSTGUI_LIVE_EDITING
|
||||
|
||||
#include "uicolor.h"
|
||||
#include "../../lib/controls/cslider.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
class UIColor;
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class UIColorSlider : public CSlider, public UIColorListenerAdapter
|
||||
{
|
||||
public:
|
||||
enum {
|
||||
kHue,
|
||||
kSaturation,
|
||||
kLightness,
|
||||
kRed,
|
||||
kGreen,
|
||||
kBlue,
|
||||
kAlpha
|
||||
};
|
||||
UIColorSlider (UIColor* color, int32_t style);
|
||||
~UIColorSlider () override;
|
||||
|
||||
protected:
|
||||
void draw (CDrawContext* context) override;
|
||||
void setViewSize (const CRect& rect, bool invalid = true) override;
|
||||
void uiColorChanged (UIColor* c) override;
|
||||
void updateBackground (CDrawContext* context);
|
||||
void updateHandle (CDrawContext* context);
|
||||
|
||||
SharedPointer<UIColor> color;
|
||||
int32_t style;
|
||||
};
|
||||
|
||||
|
||||
} // VSTGUI
|
||||
|
||||
#endif // VSTGUI_LIVE_EDITING
|
||||
@@ -0,0 +1,142 @@
|
||||
// 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 "uicrosslines.h"
|
||||
|
||||
#if VSTGUI_LIVE_EDITING
|
||||
|
||||
#include "../../lib/cviewcontainer.h"
|
||||
#include "../../lib/cdrawcontext.h"
|
||||
#include "uiselection.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
UICrossLines::UICrossLines (CViewContainer* view, int32_t style, const CColor& background, const CColor& foreground)
|
||||
: UIOverlayView (view)
|
||||
, style (style)
|
||||
, background (background)
|
||||
, foreground (foreground)
|
||||
{
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
UICrossLines::~UICrossLines ()
|
||||
{
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UICrossLines::update (UISelection* selection)
|
||||
{
|
||||
invalid ();
|
||||
|
||||
CPoint p;
|
||||
currentRect = selection->getBounds ();
|
||||
localToFrame (p);
|
||||
currentRect.offset (-p.x, -p.y);
|
||||
|
||||
invalid ();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UICrossLines::update (const CPoint& point)
|
||||
{
|
||||
invalid ();
|
||||
|
||||
currentRect.left = point.x-1;
|
||||
currentRect.top = point.y-1;
|
||||
currentRect.setWidth (1);
|
||||
currentRect.setHeight (1);
|
||||
getTargetView ()->getTransform ().transform (currentRect);
|
||||
CPoint p;
|
||||
getParentView ()->frameToLocal (p);
|
||||
currentRect.offset (p.x, p.y);
|
||||
getTargetView ()->localToFrame (p);
|
||||
currentRect.offset (p.x, p.y);
|
||||
|
||||
invalid ();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UICrossLines::update (const CRect& rect)
|
||||
{
|
||||
invalid ();
|
||||
currentRect = rect;
|
||||
getTargetView ()->getTransform ().transform (currentRect);
|
||||
CPoint p;
|
||||
getParentView ()->frameToLocal (p);
|
||||
currentRect.offset (p.x, p.y);
|
||||
getTargetView ()->localToFrame (p);
|
||||
currentRect.offset (p.x, p.y);
|
||||
invalid ();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UICrossLines::invalid ()
|
||||
{
|
||||
if (style == kLassoStyle)
|
||||
{
|
||||
auto r = currentRect;
|
||||
r.makeIntegral ();
|
||||
if (!r.isEmpty ())
|
||||
invalidRect (r);
|
||||
return;
|
||||
}
|
||||
CRect frameRect = getViewSize ();
|
||||
invalidRect (CRect (currentRect.left-3, frameRect.top, currentRect.left+3, frameRect.bottom));
|
||||
invalidRect (CRect (frameRect.left, currentRect.top-3, frameRect.right, currentRect.top+3));
|
||||
if (style == kSelectionStyle)
|
||||
{
|
||||
invalidRect (CRect (currentRect.right-3, frameRect.top, currentRect.right+3, frameRect.bottom));
|
||||
invalidRect (CRect (frameRect.left, currentRect.bottom-3, frameRect.right, currentRect.bottom+3));
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UICrossLines::drawLines (CDrawContext* pContext, const CRect& size, const CRect& selectionSize)
|
||||
{
|
||||
pContext->drawLine (CPoint (size.left, selectionSize.top), CPoint (size.right, selectionSize.top));
|
||||
pContext->drawLine (CPoint (selectionSize.left, size.top), CPoint (selectionSize.left, size.bottom));
|
||||
if (style == kSelectionStyle)
|
||||
{
|
||||
pContext->drawLine (CPoint (size.left, selectionSize.bottom - 1), CPoint (size.right, selectionSize.bottom - 1));
|
||||
pContext->drawLine (CPoint (selectionSize.right-1, size.top), CPoint (selectionSize.right-1, size.bottom));
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UICrossLines::draw (CDrawContext* pContext)
|
||||
{
|
||||
CRect size = getViewSize ();
|
||||
|
||||
pContext->setDrawMode (kAliasing);
|
||||
pContext->setLineStyle (kLineSolid);
|
||||
pContext->setFrameColor (background);
|
||||
pContext->setLineWidth (1);
|
||||
|
||||
if (style == kLassoStyle)
|
||||
{
|
||||
auto r = currentRect;
|
||||
r.makeIntegral ();
|
||||
if (r.isEmpty ())
|
||||
return;
|
||||
pContext->setFillColor (foreground);
|
||||
pContext->drawRect (r, kDrawFilledAndStroked);
|
||||
return;
|
||||
}
|
||||
|
||||
CRect selectionSize (currentRect);
|
||||
drawLines (pContext, size, selectionSize);
|
||||
|
||||
static const CCoord dashLength [] = {3,3};
|
||||
static const CLineStyle lineStyle (CLineStyle::kLineCapButt, CLineStyle::kLineJoinMiter, 0, 2, dashLength);
|
||||
|
||||
pContext->setLineStyle (lineStyle);
|
||||
pContext->setFrameColor (foreground);
|
||||
drawLines (pContext, size, selectionSize);
|
||||
}
|
||||
|
||||
} // VSTGUI
|
||||
|
||||
#endif // VSTGUI_LIVE_EDITING
|
||||
@@ -0,0 +1,53 @@
|
||||
// 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 "../../lib/vstguifwd.h"
|
||||
|
||||
#if VSTGUI_LIVE_EDITING
|
||||
|
||||
#include "uioverlayview.h"
|
||||
#include "../../lib/crect.h"
|
||||
#include "../../lib/ccolor.h"
|
||||
#include "../../lib/cview.h"
|
||||
#include "../../lib/iviewlistener.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
class UISelection;
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class UICrossLines : public UIOverlayView
|
||||
{
|
||||
public:
|
||||
enum {
|
||||
kSelectionStyle,
|
||||
kDragStyle,
|
||||
kLassoStyle,
|
||||
};
|
||||
|
||||
UICrossLines (CViewContainer* view, int32_t style, const CColor& background = kWhiteCColor, const CColor& foreground = kBlackCColor);
|
||||
~UICrossLines () override;
|
||||
|
||||
int32_t getStyle () const { return style; }
|
||||
|
||||
void update (UISelection* selection);
|
||||
void update (const CPoint& point);
|
||||
void update (const CRect& rect);
|
||||
void invalid () override;
|
||||
void draw (CDrawContext* pContext) override;
|
||||
protected:
|
||||
void drawLines (CDrawContext* pContext, const CRect& size, const CRect& selectionSize);
|
||||
|
||||
CViewContainer* editView;
|
||||
CRect currentRect;
|
||||
int32_t style;
|
||||
|
||||
CColor background;
|
||||
CColor foreground;
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
|
||||
#endif // VSTGUI_LIVE_EDITING
|
||||
@@ -0,0 +1,435 @@
|
||||
{
|
||||
"vstgui-ui-description": {
|
||||
"version": "1",
|
||||
"variables": {},
|
||||
"bitmaps": {
|
||||
"attach-bottom": {
|
||||
"path": "resources/darkmode-attach-bottom.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAABemlDQ1BJQ0MgUHJvZmlsZQAAKJF9kE0rRFEYx38zQ95GCgvJ4uZtNcQosVEzk1AW06C8be7ceVNm3O5cIRsLZasosfG24BOwsVDWSilSsvMFiI10PWeGxkt56jnP7zznOf/O+YPbp5vmbFEHpDO2FRkIauMTk1rJI2VU46WGet3ImoFweBiJr/ozXm9wqXrdprT+nv8bFbF41gBXqXCfYVq28KBw04JtKlZ6tZY8SnhFcTLPm4qjeT7OzYxGQsJnwpqR0mPC98I+I2Wlwa30m6PfZpLfOD07b3y+R/3EG8+MjUhtlGwgS4QBgmgM0U+IbjrplbWbNvy0yw47vmiry6E5c8maSaZsLSBOxLWhjNHu0/wdfplRvv72q9Cb24OeF/CsF3rRLThdg7q7Qq95F6pW4eTC1C091/JIuhMJeDqCygmouYLyqWyiy5//kTcIxQ+O89wCJRvwvu44b/uO834gl8Wj80zeo08tDm9hdBmGL2F7B1pFu2r6AwBYZxv39p/KAAAAOGVYSWZNTQAqAAAACAABh2kABAAAAAEAAAAaAAAAAAACoAIABAAAAAEAAAAMoAMABAAAAAEAAAAMAAAAADDE2GcAAABSSURBVCgVY2SAgv///2sBmWEwPhq9ipGR8RpIjAlNAsYVBTJAmDgAtK0BhLGpxmUDNrVgsVENOIMGSYIRRwzDIu01kloQcxULmgCMi64QJs4AAP8EEk3v5pcSAAAAAElFTkSuQmCC"
|
||||
}
|
||||
},
|
||||
"attach-bottom#2.0x": {
|
||||
"path": "resources/darkmode-attach-bottom#2.0x.png",
|
||||
"scale-factor": "2",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAABe2lDQ1BJQ0MgUHJvZmlsZQAAKJF9kMsrRFEcxz8zyGuksLCwuHmtxmuU2CgzialZaIzy2ty581Jm3O5cIRsLZasosfFa8BewsVDWSilSsvMPEBvp+p0ZGo/yq9/5fc7v/M63c77g9uqmOVvcCemMbYWH/Nr4xKRW+kg5NXiopUM3subAyEgIia/6M15vcKl63aa0/p7/G5WxeNYAV5lwv2FatvCwcNOCbSpWenWWPEp4RXEyz5uKo3k+zs1EwgHhM2HNSOkx4Xthr5Gy0uBW+s3RbzPJb5yenTc+36N+4olnxkalNko2kCXMEH40ggwSoIcu+mTtoQ0f7bLDji/a6nJgzlyyZpIpWxsQJ+JaMGO0ezVfp09mlK+//Sr05vag9wWK1gu96BacrkH9XaHXvAvVq3ByYeqWnmsVSboTCXg6gqoJqL2CiqlsotuX/5HHDyUPjvPcAqUb8L7uOG/7jvN+IJfFo/NM3qNPLQ5vIbIMoUvY3oFW0a6e/gArFWcwZrsc/wAAAGxlWElmTU0AKgAAAAgABAEaAAUAAAABAAAAPgEbAAUAAAABAAAARgEoAAMAAAABAAIAAIdpAAQAAAABAAAATgAAAAAAAACQAAAAAQAAAJAAAAABAAKgAgAEAAAAAQAAABigAwAEAAAAAQAAABgAAAAAiB+cqwAAAAlwSFlzAAAWJQAAFiUBSVIk8AAAAGBJREFUSA1jYBgI8P///61ATCrYis2tTNgEB0wM6CWQz7C6lCqOgoUZKYbRPIhGLSAYHaNBNBpEBEOAoILRVDQCgoiFoB9RFWxD5RLJg9ZUsPqEWjS45qN5MiXSj+QrAwArzZ6BCJI6MQAAAABJRU5ErkJggg=="
|
||||
}
|
||||
},
|
||||
"attach-bottom-non": {
|
||||
"path": "resources/darkmode-attach-bottom-non.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAABemlDQ1BJQ0MgUHJvZmlsZQAAKJF9kMsrRFEcxz8GeaewsLC4eW6GxiiRUmYSU7PQoLw2d+681Dxud66QjYWyVZTYeC34C9hYKGulFCnZ+QeIjXT9jqHxKL/6nd/n/M7vfDvnCy63bprJIg+k0rYVGvJpE5NTWskDZdRQQR9tupE1B0ZGgkh81Z/xck2BqlftSuvv+b9REYlmDSgoFe43TMsWHhZumrdNxUqvzpJHCS8rjud4Q3E4x0cfM2Mhv/CpsGYk9IjwnbDbSFgpcCn95vC3mfg3TiXnjM/3qJ9URtPjo1IbJRvIEmIIHxoBBvHTTSe9snbTjpcO2WFHF2x12Z8xF63ZeMLWBsSJqBZIGx1uzevxyozy9bdf+V5mF3qeoXAt3wtvwskq1N/me807UL0Cx+embukfrUJJVywGj4dQNQm1l1A+nY11eXM/qvRB8b3jPLVAyTq8rTnO657jvO3LZfHoLJ3z6FOLgxsYW4LgBWxtQ6toV8+8A2p4Z09tJazIAAAAOGVYSWZNTQAqAAAACAABh2kABAAAAAEAAAAaAAAAAAACoAIABAAAAAEAAAAMoAMABAAAAAEAAAAMAAAAADDE2GcAAABUSURBVCgVY2SAgv///2sBmWEwPhq9ipGR8RpIjAlNAsYVBTJAmDgAtC0LhIlTTRdV+JyEy9N0cRgJluDzAyNQElsMwyLtNZo9q1jQBGBcdIUwcQYAXowfsZtf8X8AAAAASUVORK5CYII="
|
||||
}
|
||||
},
|
||||
"attach-bottom-non#2.0x": {
|
||||
"path": "resources/darkmode-attach-bottom-non#2.0x.png",
|
||||
"scale-factor": "2",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAABfWlDQ1BJQ0MgUHJvZmlsZQAAKJF9kE1LAlEUhl+1sA9DqBYtCoayVio2gdQmUAkTXIgZZLUZx1EDHS8zExVtWgRthYKoTV+L+gW1aRG0DoKgCKJdf6CoTch0rmNoBR049zz33HNf7n0Bu1dirNgSAEqqoSWjYWEuPS84X9CObrgoByRZZ6FEIg6K7/ozPu5h4/XOx7X+nv8bnVlFlwFbG/GkzDSDeJp4aMVgnLler0aPIt7gnLd4h3PG4rPaTCoZIb4kFuSClCV+IvbKBa0E2Lm+J9M0k2/iUnFZrr+H/8SlqLMzVAcp+6EjiSjCEBDDFCIIYhQTtAbhgwg/7WAoqwa/HCmzNW0pXzCEEDmhCDFV9nsFMSDSDPf1t1+NXvkQGH8HHJVGL7MLXGwBfY+NnucAcG8C59dM0qRay0Fpz+WA11OgKw303AIdC3puTLR+5AoDrc+m+TYMOLeBasU0P49Ms3pMl8mjK9XyqK6FkwcgtQ7Eb4C9fWCEtN2LXwRoZx3VyNkVAAAAbGVYSWZNTQAqAAAACAAEARoABQAAAAEAAAA+ARsABQAAAAEAAABGASgAAwAAAAEAAgAAh2kABAAAAAEAAABOAAAAAAAAAJAAAAABAAAAkAAAAAEAAqACAAQAAAABAAAAGKADAAQAAAABAAAAGAAAAACIH5yrAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAX0lEQVRIDWNgGAjw////rUBMKtiKza1M2AQHTAzoJZDPsLqUKo6ChRkphrGQohiodhuJ6keVD7UQGJTJlOY5eTQfDLV0Smv3Dsp8QJ9kCvU6rD6hFg2u+Wiek2mdLhgAPDm+kdjh42AAAAAASUVORK5CYII="
|
||||
}
|
||||
},
|
||||
"attach-left": {
|
||||
"path": "resources/darkmode-attach-left.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAABemlDQ1BJQ0MgUHJvZmlsZQAAKJF9kE0rRFEYx39myGCksJiFxc3baohRYqNmJqEsNChvmzvXvKiZcbtzhWwslK2ixMbbgk/AxkJZK6VIyc4XIDaarufM0HgpTz3n+Z3nPOffOX9w+XXTTJV2QDpjW5GBkDYxOaWVP1FBLV58eHQjawZHRoaR+Ko/4+2WElVv2pTW3/N/o2o2ljWgxCPcZ5iWLTwo3LRom4qVXr0ljxJeVZwo8JbiaIFP8jNjkbDwubBmJPVZ4Qdhv5G00uBS+s3RbzOJb5xOLRif71E/8cYy46NSGyUbyBJhgBAaQ/QTpptOemXtpo0A7bLDji3Z6nJ43ly25hJJWwuKEzFtKGO0+7VAR0BmlK+//Sr25veh5xXcG8VedBvO1sF3X+w170HNGpxemrql51tuSVc8Ds/HUD0JdddQOZ2NdwUKP/KGoOzRcV5aoHwTchuO837gOLlDuSweXWQKHn1qcXQHYyswfAU7u9Aq2jUzH+XeZw7fiuiiAAAAOGVYSWZNTQAqAAAACAABh2kABAAAAAEAAAAaAAAAAAACoAIABAAAAAEAAAAMoAMABAAAAAEAAAAMAAAAADDE2GcAAABbSURBVCgVY/j//78WCDMQCZiA6sKgmCgtLESpAiqCuYJoDTBXgJxEEoDZIAq0soGATlGg/GuybXjNyMiI1waYC8i2gYDzwdKrQCTM0wQ1AJ18DaYBrJOgDqgCAGuzFkaMpOVFAAAAAElFTkSuQmCC"
|
||||
}
|
||||
},
|
||||
"attach-left#2.0x": {
|
||||
"path": "resources/darkmode-attach-left#2.0x.png",
|
||||
"scale-factor": "2",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAABemlDQ1BJQ0MgUHJvZmlsZQAAKJF9kE0rRFEYx39myGCksJiFxc3baohRYqNmJqEsNChvmzvXvKiZcbtzhWwslK2ixMbbgk/AxkJZK6VIyc4XIDaarufM0HgpTz3n+Z3nPOffOX9w+XXTTJV2QDpjW5GBkDYxOaWVP1FBLV58eHQjawZHRoaR+Ko/4+2WElVv2pTW3/N/o2o2ljWgxCPcZ5iWLTwo3LRom4qVXr0ljxJeVZwo8JbiaIFP8jNjkbDwubBmJPVZ4Qdhv5G00uBS+s3RbzOJb5xOLRif71E/8cYy46NSGyUbyBJhgBAaQ/QTpptOemXtpo0A7bLDji3Z6nJ43ly25hJJWwuKEzFtKGO0+7VAR0BmlK+//Sr25veh5xXcG8VedBvO1sF3X+w170HNGpxemrql51tuSVc8Ds/HUD0JdddQOZ2NdwUKP/KGoOzRcV5aoHwTchuO837gOLlDuSweXWQKHn1qcXQHYyswfAU7u9Aq2jUzH+XeZw7fiuiiAAAAbGVYSWZNTQAqAAAACAAEARoABQAAAAEAAAA+ARsABQAAAAEAAABGASgAAwAAAAEAAgAAh2kABAAAAAEAAABOAAAAAAAAAJAAAAABAAAAkAAAAAEAAqACAAQAAAABAAAAGKADAAQAAAABAAAAGAAAAACIH5yrAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAeElEQVRIDWNgoAf4////VhCmmV1Aw8GAFhYw0cJQZDOHpgXA8EaNU2gU/Ef2GiVsZPOGZhAh+36Y+QAa+7A4IpdGKRFoHkTg+IA5FTlyKGEjm0dzH4xaQDCqWAiqIE/BNhRtyLGOIkEFztCPZFgcoIYZFYKGbkYAAIpwh08jMZ6/AAAAAElFTkSuQmCC"
|
||||
}
|
||||
},
|
||||
"attach-left-non": {
|
||||
"path": "resources/darkmode-attach-left-non.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAABemlDQ1BJQ0MgUHJvZmlsZQAAKJF9kMsrRFEcxz8GeY0UioXFzWs1xNDERplJTM1Cg/La3LnmoeZxu3OFbCyUraLExmvBX8DGQlkrpUjJzj9AbKTrdwyNR/nV7/w+53d+59s5X3B5dNNMFnVAKm1b4UG/Nj4xqZU8UEY1buro1o2s2T88HELiq/6Ml2sKVL1qU1p/z/+Niplo1oCCUuE+w7Rs4SHhpnnbVKz0ai15lPCy4niONxRHcnz0MTMaDgifCmtGQp8RvhP2GAkrBS6l3xz5NhP/xqnknPH5HvUTdzQ9NiK1UbKBLGEG8aMRZIAAPjrpldVHG17aZYcdXbDV5UDGXLRm4wlb6xcnolowbbR7NG+HV2aUr7/9yvcyu9DzDIVr+V5kE05Wof4232vegaoVOD43dUv/aBVKumIxeDyEygmouYTyqWysy5v7kdsPxfeO89QCJevwtuY4r3uO87Yvl8Wjs3TOo08tDm5gdAlCF7C1Da2iXTX9Dj1uZzmkSEPbAAAAOGVYSWZNTQAqAAAACAABh2kABAAAAAEAAAAaAAAAAAACoAIABAAAAAEAAAAMoAMABAAAAAEAAAAMAAAAADDE2GcAAABnSURBVCgVY/j//78WCDMQCZiA6sKgmCgtLESpAiqCuYJoDTBXgJxEEoBpEAVamQXTCWKj84FyoiB5mAaYWoI0I9CkBpAqRkZGMA1iYwMwdSTbQEoorQLZTLQGoJOvwTSAdWJzNzYxADa+IgdSZ4xsAAAAAElFTkSuQmCC"
|
||||
}
|
||||
},
|
||||
"attach-left-non#2.0x": {
|
||||
"path": "resources/darkmode-attach-left-non#2.0x.png",
|
||||
"scale-factor": "2",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAABemlDQ1BJQ0MgUHJvZmlsZQAAKJF9kE0rRFEYx39myGCksJiFxc3baohRYqNmJqEsNChvmzvXvKiZcbtzhWwslK2ixMbbgk/AxkJZK6VIyc4XIDaarufM0HgpTz3n+Z3nPOffOX9w+XXTTJV2QDpjW5GBkDYxOaWVP1FBLV58eHQjawZHRoaR+Ko/4+2WElVv2pTW3/N/o2o2ljWgxCPcZ5iWLTwo3LRom4qVXr0ljxJeVZwo8JbiaIFP8jNjkbDwubBmJPVZ4Qdhv5G00uBS+s3RbzOJb5xOLRif71E/8cYy46NSGyUbyBJhgBAaQ/QTpptOemXtpo0A7bLDji3Z6nJ43ly25hJJWwuKEzFtKGO0+7VAR0BmlK+//Sr25veh5xXcG8VedBvO1sF3X+w170HNGpxemrql51tuSVc8Ds/HUD0JdddQOZ2NdwUKP/KGoOzRcV5aoHwTchuO837gOLlDuSweXWQKHn1qcXQHYyswfAU7u9Aq2jUzH+XeZw7fiuiiAAAAbGVYSWZNTQAqAAAACAAEARoABQAAAAEAAAA+ARsABQAAAAEAAABGASgAAwAAAAEAAgAAh2kABAAAAAEAAABOAAAAAAAAAJAAAAABAAAAkAAAAAEAAqACAAQAAAABAAAAGKADAAQAAAABAAAAGAAAAACIH5yrAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAf0lEQVRIDWNgoAf4////VhCmmV1Aw8GAFhYw0cJQZDOHpgXA8EaNU2gU/Ef2GiVsZPOGZhAh+36Y+QAa+6A4wsjVSHKE5FH00jyIwPEBchIIIEcOJWyIaRDzaO6DUQsIRhULQRXkKdiGog051lEkqMAZ+pEMiwPUMKNC0NDNCAAQpGZH4WLCKQAAAABJRU5ErkJggg=="
|
||||
}
|
||||
},
|
||||
"attach-right": {
|
||||
"path": "resources/darkmode-attach-right.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAABemlDQ1BJQ0MgUHJvZmlsZQAAKJF9kE0rRFEYx39myGCksJiFxc3baohRYqNmJqEsNChvmzvXvKiZcbtzhWwslK2ixMbbgk/AxkJZK6VIyc4XIDaarufM0HgpTz3n+Z3nPOffOX9w+XXTTJV2QDpjW5GBkDYxOaWVP1FBLV58eHQjawZHRoaR+Ko/4+2WElVv2pTW3/N/o2o2ljWgxCPcZ5iWLTwo3LRom4qVXr0ljxJeVZwo8JbiaIFP8jNjkbDwubBmJPVZ4Qdhv5G00uBS+s3RbzOJb5xOLRif71E/8cYy46NSGyUbyBJhgBAaQ/QTpptOemXtpo0A7bLDji3Z6nJ43ly25hJJWwuKEzFtKGO0+7VAR0BmlK+//Sr25veh5xXcG8VedBvO1sF3X+w170HNGpxemrql51tuSVc8Ds/HUD0JdddQOZ2NdwUKP/KGoOzRcV5aoHwTchuO837gOLlDuSweXWQKHn1qcXQHYyswfAU7u9Aq2jUzH+XeZw7fiuiiAAAAOGVYSWZNTQAqAAAACAABh2kABAAAAAEAAAAaAAAAAAACoAIABAAAAAEAAAAMoAMABAAAAAEAAAAMAAAAADDE2GcAAABhSURBVCgVY2QgEvz//18LpJSFSPUgZWEgggmkE6YbJEAIMAEVgHSCdRNSDJIHaSAJwPwgCnRWAwGdokD512Tb8JqRkRGvDTAXkGXDKgJuR5FmATrlGooIAQ4jAXm4NCxyAUjGGL/6AlMxAAAAAElFTkSuQmCC"
|
||||
}
|
||||
},
|
||||
"attach-right#2.0x": {
|
||||
"path": "resources/darkmode-attach-right#2.0x.png",
|
||||
"scale-factor": "2",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAABemlDQ1BJQ0MgUHJvZmlsZQAAKJF9kE0rRFEYx39myGCksJiFxc3baohRYqNmJqEsNChvmzvXvKiZcbtzhWwslK2ixMbbgk/AxkJZK6VIyc4XIDaarufM0HgpTz3n+Z3nPOffOX9w+XXTTJV2QDpjW5GBkDYxOaWVP1FBLV58eHQjawZHRoaR+Ko/4+2WElVv2pTW3/N/o2o2ljWgxCPcZ5iWLTwo3LRom4qVXr0ljxJeVZwo8JbiaIFP8jNjkbDwubBmJPVZ4Qdhv5G00uBS+s3RbzOJb5xOLRif71E/8cYy46NSGyUbyBJhgBAaQ/QTpptOemXtpo0A7bLDji3Z6nJ43ly25hJJWwuKEzFtKGO0+7VAR0BmlK+//Sr25veh5xXcG8VedBvO1sF3X+w170HNGpxemrql51tuSVc8Ds/HUD0JdddQOZ2NdwUKP/KGoOzRcV5aoHwTchuO837gOLlDuSweXWQKHn1qcXQHYyswfAU7u9Aq2jUzH+XeZw7fiuiiAAAAbGVYSWZNTQAqAAAACAAEARoABQAAAAEAAAA+ARsABQAAAAEAAABGASgAAwAAAAEAAgAAh2kABAAAAAEAAABOAAAAAAAAAJAAAAABAAAAkAAAAAEAAqACAAQAAAABAAAAGKADAAQAAAABAAAAGAAAAACIH5yrAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAhUlEQVRIDWNgGGrg////jEC8HYi3gtzOSG0PgCwAmvkPbDgjIyMTtS1AN4/2FqCHGboLKOWDIgQlzCg1EN082gcRpS4mpH+Y+QAYQVuBmCIADLItyMFG8yAaTabIwY2VTfM4oLkFLFB/bQfS4DIcqz8pEBytcAgGHiwOCCokUQHN4hTDHQCb93SDqQqZfAAAAABJRU5ErkJggg=="
|
||||
}
|
||||
},
|
||||
"attach-right-non": {
|
||||
"path": "resources/darkmode-attach-right-non.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAABemlDQ1BJQ0MgUHJvZmlsZQAAKJF9kE0rRFEYx39myGCksJiFxc3baohRYqNmJqEsNChvmzvXvKiZcbtzhWwslK2ixMbbgk/AxkJZK6VIyc4XIDaarufM0HgpTz3n+Z3nPOffOX9w+XXTTJV2QDpjW5GBkDYxOaWVP1FBLV58eHQjawZHRoaR+Ko/4+2WElVv2pTW3/N/o2o2ljWgxCPcZ5iWLTwo3LRom4qVXr0ljxJeVZwo8JbiaIFP8jNjkbDwubBmJPVZ4Qdhv5G00uBS+s3RbzOJb5xOLRif71E/8cYy46NSGyUbyBJhgBAaQ/QTpptOemXtpo0A7bLDji3Z6nJ43ly25hJJWwuKEzFtKGO0+7VAR0BmlK+//Sr25veh5xXcG8VedBvO1sF3X+w170HNGpxemrql51tuSVc8Ds/HUD0JdddQOZ2NdwUKP/KGoOzRcV5aoHwTchuO837gOLlDuSweXWQKHn1qcXQHYyswfAU7u9Aq2jUzH+XeZw7fiuiiAAAAOGVYSWZNTQAqAAAACAABh2kABAAAAAEAAAAaAAAAAAACoAIABAAAAAEAAAAMoAMABAAAAAEAAAAMAAAAADDE2GcAAAB0SURBVCgVlZLRDcAgCESLcQWX6EAdwik6TwfqOpZHwk+DQe9D8LhDjMqxiDHGibQu6pFdLAWnuyEyFBXgNHcmpo5hC25oOlZ3J/l/r7VG3Q2uTaNopxuViFgkj+C67RN4hyfqOOOqjvLOihEvERlxegf7Gh8T0SSA9KXNDAAAAABJRU5ErkJggg=="
|
||||
}
|
||||
},
|
||||
"attach-right-non#2.0x": {
|
||||
"path": "resources/darkmode-attach-right-non#2.0x.png",
|
||||
"scale-factor": "2",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAABemlDQ1BJQ0MgUHJvZmlsZQAAKJF9kE0rRFEYx39myGCksJiFxc3baohRYqNmJqEsNChvmzvXvKiZcbtzhWwslK2ixMbbgk/AxkJZK6VIyc4XIDaarufM0HgpTz3n+Z3nPOffOX9w+XXTTJV2QDpjW5GBkDYxOaWVP1FBLV58eHQjawZHRoaR+Ko/4+2WElVv2pTW3/N/o2o2ljWgxCPcZ5iWLTwo3LRom4qVXr0ljxJeVZwo8JbiaIFP8jNjkbDwubBmJPVZ4Qdhv5G00uBS+s3RbzOJb5xOLRif71E/8cYy46NSGyUbyBJhgBAaQ/QTpptOemXtpo0A7bLDji3Z6nJ43ly25hJJWwuKEzFtKGO0+7VAR0BmlK+//Sr25veh5xXcG8VedBvO1sF3X+w170HNGpxemrql51tuSVc8Ds/HUD0JdddQOZ2NdwUKP/KGoOzRcV5aoHwTchuO837gOLlDuSweXWQKHn1qcXQHYyswfAU7u9Aq2jUzH+XeZw7fiuiiAAAAbGVYSWZNTQAqAAAACAAEARoABQAAAAEAAAA+ARsABQAAAAEAAABGASgAAwAAAAEAAgAAh2kABAAAAAEAAABOAAAAAAAAAJAAAAABAAAAkAAAAAEAAqACAAQAAAABAAAAGKADAAQAAAABAAAAGAAAAACIH5yrAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAo0lEQVRIDe1V2wqAIAx10f9/TeHfZdvwiC0s8PJQKMh017PNlXNfWyEE4u1574KdeicgAdjnoc6JaOkdwPobH8DWzCJovUtDLjVrdWj9jS9RK+I3+59lwA2SCZSlU4j0+Y7pVOGTnG022Am1JQpRCJrr5rz8DB3wQJU/nynKU6S2B0XFWsHwAGtE5pnqN7wWaclu/nBKlUl89CAxOh2G9fSG7wR611938FxGawAAAABJRU5ErkJggg=="
|
||||
}
|
||||
},
|
||||
"attach-top": {
|
||||
"path": "resources/darkmode-attach-top.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAABemlDQ1BJQ0MgUHJvZmlsZQAAKJF9kE0rRFEYx39myGCksJiFxc3baohRYqNmJqEsNChvmzvXvKiZcbtzhWwslK2ixMbbgk/AxkJZK6VIyc4XIDaarufM0HgpTz3n+Z3nPOffOX9w+XXTTJV2QDpjW5GBkDYxOaWVP1FBLV58eHQjawZHRoaR+Ko/4+2WElVv2pTW3/N/o2o2ljWgxCPcZ5iWLTwo3LRom4qVXr0ljxJeVZwo8JbiaIFP8jNjkbDwubBmJPVZ4Qdhv5G00uBS+s3RbzOJb5xOLRif71E/8cYy46NSGyUbyBJhgBAaQ/QTpptOemXtpo0A7bLDji3Z6nJ43ly25hJJWwuKEzFtKGO0+7VAR0BmlK+//Sr25veh5xXcG8VedBvO1sF3X+w170HNGpxemrql51tuSVc8Ds/HUD0JdddQOZ2NdwUKP/KGoOzRcV5aoHwTchuO837gOLlDuSweXWQKHn1qcXQHYyswfAU7u9Aq2jUzH+XeZw7fiuiiAAAAOGVYSWZNTQAqAAAACAABh2kABAAAAAEAAAAaAAAAAAACoAIABAAAAAEAAAAMoAMABAAAAAEAAAAMAAAAADDE2GcAAABQSURBVCgVY/z//78WAwNDGBATA1Yx4VAlChQHYeIA0NYGEMamGpcN2NSCxUY14AwaJAlGGBstxmGR9hoqv4qRkfEaiM0C04BGwxSiCTMwAABfmxJNSdqiHAAAAABJRU5ErkJggg=="
|
||||
}
|
||||
},
|
||||
"attach-top#2.0x": {
|
||||
"path": "resources/darkmode-attach-top#2.0x.png",
|
||||
"scale-factor": "2",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAABemlDQ1BJQ0MgUHJvZmlsZQAAKJF9kE0rRFEYx39myGCksJiFxc3baohRYqNmJqEsNChvmzvXvKiZcbtzhWwslK2ixMbbgk/AxkJZK6VIyc4XIDaarufM0HgpTz3n+Z3nPOffOX9w+XXTTJV2QDpjW5GBkDYxOaWVP1FBLV58eHQjawZHRoaR+Ko/4+2WElVv2pTW3/N/o2o2ljWgxCPcZ5iWLTwo3LRom4qVXr0ljxJeVZwo8JbiaIFP8jNjkbDwubBmJPVZ4Qdhv5G00uBS+s3RbzOJb5xOLRif71E/8cYy46NSGyUbyBJhgBAaQ/QTpptOemXtpo0A7bLDji3Z6nJ43ly25hJJWwuKEzFtKGO0+7VAR0BmlK+//Sr25veh5xXcG8VedBvO1sF3X+w170HNGpxemrql51tuSVc8Ds/HUD0JdddQOZ2NdwUKP/KGoOzRcV5aoHwTchuO837gOLlDuSweXWQKHn1qcXQHYyswfAU7u9Aq2jUzH+XeZw7fiuiiAAAAbGVYSWZNTQAqAAAACAAEARoABQAAAAEAAAA+ARsABQAAAAEAAABGASgAAwAAAAEAAgAAh2kABAAAAAEAAABOAAAAAAAAAJAAAAABAAAAkAAAAAEAAqACAAQAAAABAAAAGKADAAQAAAABAAAAGAAAAACIH5yrAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAYklEQVRIDWNgoAf4////ViCmNtgKcjsTPTxAtB1AL4J8CnYZ0ZpIUQgLQ1L00DyIRi0gGB2jQTQaRARDgKCC0VQ0AoKIhaAfURVsQ+WSyYPWXLD6hVgaa01H82RKph+J1wYAx2yegcfTuFsAAAAASUVORK5CYII="
|
||||
}
|
||||
},
|
||||
"attach-top-non": {
|
||||
"path": "resources/darkmode-attach-top-non.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAABemlDQ1BJQ0MgUHJvZmlsZQAAKJF9kE0rRFEYx39myGCksJiFxc3baohRYqNmJqEsNChvmzvXvKiZcbtzhWwslK2ixMbbgk/AxkJZK6VIyc4XIDaarufM0HgpTz3n+Z3nPOffOX9w+XXTTJV2QDpjW5GBkDYxOaWVP1FBLV58eHQjawZHRoaR+Ko/4+2WElVv2pTW3/N/o2o2ljWgxCPcZ5iWLTwo3LRom4qVXr0ljxJeVZwo8JbiaIFP8jNjkbDwubBmJPVZ4Qdhv5G00uBS+s3RbzOJb5xOLRif71E/8cYy46NSGyUbyBJhgBAaQ/QTpptOemXtpo0A7bLDji3Z6nJ43ly25hJJWwuKEzFtKGO0+7VAR0BmlK+//Sr25veh5xXcG8VedBvO1sF3X+w170HNGpxemrql51tuSVc8Ds/HUD0JdddQOZ2NdwUKP/KGoOzRcV5aoHwTchuO837gOLlDuSweXWQKHn1qcXQHYyswfAU7u9Aq2jUzH+XeZw7fiuiiAAAAOGVYSWZNTQAqAAAACAABh2kABAAAAAEAAAAaAAAAAAACoAIABAAAAAEAAAAMoAMABAAAAAEAAAAMAAAAADDE2GcAAABUSURBVCgVY/z//78WAwNDGBATA1Yx4VAlChQHYeIA0NYsECZONV1U4XMSLk/TxWEkWILPD4wwc4CKkGMcFmmvofKrGBkZr4HYLDANaDRMIZowAwMAvxQfsUl4T10AAAAASUVORK5CYII="
|
||||
}
|
||||
},
|
||||
"attach-top-non#2.0x": {
|
||||
"path": "resources/darkmode-attach-top-non#2.0x.png",
|
||||
"scale-factor": "2",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAABemlDQ1BJQ0MgUHJvZmlsZQAAKJF9kE0rRFEYx39myGCksJiFxc3baohRYqNmJqEsNChvmzvXvKiZcbtzhWwslK2ixMbbgk/AxkJZK6VIyc4XIDaarufM0HgpTz3n+Z3nPOffOX9w+XXTTJV2QDpjW5GBkDYxOaWVP1FBLV58eHQjawZHRoaR+Ko/4+2WElVv2pTW3/N/o2o2ljWgxCPcZ5iWLTwo3LRom4qVXr0ljxJeVZwo8JbiaIFP8jNjkbDwubBmJPVZ4Qdhv5G00uBS+s3RbzOJb5xOLRif71E/8cYy46NSGyUbyBJhgBAaQ/QTpptOemXtpo0A7bLDji3Z6nJ43ly25hJJWwuKEzFtKGO0+7VAR0BmlK+//Sr25veh5xXcG8VedBvO1sF3X+w170HNGpxemrql51tuSVc8Ds/HUD0JdddQOZ2NdwUKP/KGoOzRcV5aoHwTchuO837gOLlDuSweXWQKHn1qcXQHYyswfAU7u9Aq2jUzH+XeZw7fiuiiAAAAbGVYSWZNTQAqAAAACAAEARoABQAAAAEAAAA+ARsABQAAAAEAAABGASgAAwAAAAEAAgAAh2kABAAAAAEAAABOAAAAAAAAAJAAAAABAAAAkAAAAAEAAqACAAQAAAABAAAAGKADAAQAAAABAAAAGAAAAACIH5yrAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAYklEQVRIDWNgoAf4////ViCmNtgKcjsTPTxAtB1AL4J8CnYZ0ZpIUQgLQ1L0sJCiGKh2G4nqR5UPtRAYlMmU5jl5NB8MtXRKa/cOynwwMMkUGhSw+oVYGmtNR/OcTOt0wQAA19i+kSjGD58AAAAASUVORK5CYII="
|
||||
}
|
||||
},
|
||||
"segment-bitmaps": {
|
||||
"path": "resources/segment-bitmaps.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAMJJREFUOBFjYBhowAhywP///02AlBUQywDxEyB+D8SCePjHGBkZzwDlGVhABBBYMabPmghhAg2cmbYu3cQkCMafeebMOqAGOB9oYT5QDmwAE1SRFEwxqXyYAc/QDCCaDwuDWKABAUAMC4PXQLYoHv4GoJcWA+XhYSCYPisd5kezmWkz1509exbONzY2XjcLEQZmaf//HwRpBgGYF4ZDGDAwwOPZDJgS1p1lRAqD/8br0tORwmjmzEEYBmTnBUhkUkACABwiWK9EDJAuAAAAAElFTkSuQmCC"
|
||||
}
|
||||
},
|
||||
"segment-bitmaps#2.0x": {
|
||||
"path": "resources/segment-bitmaps#2.0x.png",
|
||||
"scale-factor": "2",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAa5JREFUWAntV8FKxDAQ3YrIXhSRxZu3RcRre/MX9juaH9Cv0B9Iv0dv7VVUvHlSRKRexEt8r5uENJts2EVR2A4Mk8lLpukkeZ2ORoNsegYykwCl1BjtPehE2x2NfcG20A/t78Jy3Kr4K+a0WZZ96jid2XYcBj2FFtoeaOwN9hb6qP0pLMetiteYwzjRBfDNi0xUl7ALomR5xU5RFOcLIDpkXXc43jCII8MXGPai1YYIZcCCXuPE8303hTNr1/4kdwHcU5NWfxz9/VCn05fCGducGztty7b+qOFmgKedBy4m7zFA96dwxuYzeuJmoAXCUxqTOwDUmKRwxuYzeuLywBGQHHoG5YEye8o3Y/B7KMcfQ9fBbzCvwS15grXiZsB2LmmoJRihFL4w3T0DZLipqEToHs9kKbt73jRNEM/zvMOrMA/MSqWeEf/BX4G7AMOE/hjjp+55Ch94wGSyZ90tGHhg4IGOB0B2wXsOjpnzQBbhATXnASEiPCLlwANDPfD/64FDcCQ/GIW23DMKV85i4kfKctQDrIytuAXJGL38Ik60NQUkKZqVzK/8mCDuhss3dLWpMq08Wq0AAAAASUVORK5CYII="
|
||||
}
|
||||
},
|
||||
"segment-colors": {
|
||||
"path": "resources/segment-colors.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAjVJREFUOBGtk8tOU1EUhr/TC5dCKqBUSosXYkWbkJgwlBfQkRgHOBMn4gBNfA4diBMY6AM4AOMTqAOdNMZEKTcTG8ALrYLa0lrOZfufHggEnelKvnNZl/+svfY+8I9m/a3+QreJxm2yfVsMpWyXFPVcL/X8MF3OwfzIQUf2pBkpbzPV5pDw1UMYWnBpwy2uszZ+lPTs/prQ/pfYoJn83sRMLUyiEgVb0bAEWvE4hJPoxJ4xvJzcX7MncNOMVE8xsd4KpRbYaIZ6GJok0IFDN9tE+aTawoTh3qVdkUDgkYkwwBRZcM/BSnsgsCWBmNpP8Yt2Cqp5J+bE8rRhtLH8YAZnVFojwU/FTogeeP8CTv+A3nKdJItyPhcroii2ElA9q4e3QrZhrlMyhs+iIBbEM3HN6PJQDIuMSIrDolPEx/zSoIO4r7wtbFEWJcjkSZ6/D1c/wrRcH0RFVIUr/NRvuwLM5bD86KbQoKx5Tf4VF6s1lgciZK5o+18rtCY2RCCU2xOwFvKKFLG+aG0FTX6RwbpNj+tRCofJDErAP0JxsS6+ahA15nnjnxPfwnccrKVxyGtNS/TbDinXIeZ5VEMWmzGlHVOeT1r0ccN62pDcEZCP0OPZKKsP/MJufbnDNTQbfzIW5ZAE1Ju2w9+hSesuT/wS34IOgmedvNVbna53Oe55xTbjNbyeznNFXVSarSJdjFhj3N5Jb9wU/tNGy0ciacfJphx36Lh+pj7HyaUddz7Zr/b+t/0GPUPe9o1DLvIAAAAASUVORK5CYII="
|
||||
}
|
||||
},
|
||||
"segment-colors#2.0x": {
|
||||
"path": "resources/segment-colors#2.0x.png",
|
||||
"scale-factor": "2",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAABaJJREFUWAntl0tvlUUcxp/3tKenl9MLpxdsoW0ajaGBRD6AidFFF0LwA9SYgLKEuHRp/AY2xk0DbiBujIlEjOLCFTExMTEGjCYmlFYuBUqhLS09t/H3zDkv5fQidcWGCc+Zeeedmef5P/+ZeYv0ojxnB5L/wz8xEEbyZb3TU9REW0XD+ZKG9pSr6lLlZpfKs+DHbpW/eUOF2d2uuysB42Oh0F7RFIST1Op7LCFCXaCzWtUelRFRFuQRnaqcB6fGNLj4LCGZZw0YPBCOMOhKEjRZotGCgCqym4Jk9SmaFZQFuYjqZE6Vq8u6/vaz1t9RQOZwyHcdCmeLGX27lNVghZHrTZJF0KdV2pW6f0118hZVEVFVK2hTdZD6YtDvZ4Iu53cSsqOAaqemID7uiavN0mJLLWoLsAOGBXiBVECdWO2qWICatcrb5RPS0qdeZ7uyvYB3wxESe5zEaiFXixoxMWrXZYijE7iQEL3tz9WiVh7yDpATG0X3gbfBwxNB09umY6uAj0IB8mn1Mq8PFNAPqW1fpnYaXD+mzlZrDrQgwNE7cpO3RfK7TH4ALOIeWJgO+ngPjYayVUCvpiAfjOR7GWsMSCukIApgxiKuZNiEdoJ/kNeIfRK6VKJnHtwBt4CFWMD9IURM0Wgonr9RzodRrWsG4HcdDsIueo0bHD+c3ce7fY+kV5ekA49LGtcjvaw1jRB5olkGpsQPaTOI93gGvPD6aKKvPCgWttdTpU/HYgAel47vpN0D2A+EqgfXpbay1M0dEJDv3Pse2Ksi5DMMYoBuA6s2+QpII2KSSsf4+QzEslnABG6ScAAJQSnuBa/hPWEUiO8PiMn/K8tSx1pVw6ht1V+8/BNgkxaArbONaSTpwqUJOncQsJe1TMziDUIcgMUYY2BUmrmMAAIcWXrMdvmFzp+Boze5LfdgL+ZovKDbcfFhGk8KJj5V1sIdDnZ/HO9uNlpE2nYQXsP7jOjNGd77gMZPwHb7hQeZ0JNd/Oy2qdyfuZuoOEAjlsYUNFs9gzN1xYlrL2pW22CQ24QdPvCrDo58KR2+Jc6NYga851LXPcXcKVINfnZK66VRQHLnJjP6a6S2zvmr14kj9FFggyVXVKj+ptfX1nW1O6uDRxE5xKuZ+pA0A+l0x5CaUmST7ChAt+eI9rUn0SZeySHZby6UhGh1TflwTeOlknr5Ei5muBjG6TZZG0gPgKd4qk3zO0deM3NOhJmWTQ7cvcToo7UZ3kQWQOSJjxS2J/8oF+Y1Wi7rpTKXDwJWM4nuZTPq20+IjpIbMgqxYZtF1PYPHBulUYDmL2D5VE2Aib2CV8L6ZF6tYUGDEBcq/BFS5f4nr6Uk0RIu9PXD7ohNwq3JZ9GXROMd5JiKgmOj4N9Tpek05+jeeZPFjRavVM51cgOyBfVB3EPUBdARqhyYEPlWLaKZpQqs1Qt847v2sy8xX2b5WJ9Lvo9XJQ+1sskBOpOFU2zTt4h8kK8Yz4tqCUvqhrQrIkTrcyFEtyuQrwOL6OpmfuqC1/fJc0rsyCqZz+k0rYbS6IBfZaZJ+P2TSmz7QiS33UYHpHlEtFJnfVqB0+6P0hp7YQ0RMVJHa1hQGn1eJ5PP4/1M50bZKsDvMj9c5Cr9IhtW1A6Z7faGa0eEn1shbqaOQ/kpEapdeISIutUbxB0M6NDZ5BN9Fyds+tmagvqAbFg9DVnoqIYTIBK3I8TWO/d21bUd8Eb0CatYCCJy7Yjz8at1nqH7Q562LTsKKGXmVtgB7/cXh76GdBoM2gFb7xQ4vUaaAotwGnJ8InM+Hm3kvIztR7aPPFWzfQrSt9R/t9y82BbCQWw/Z7X+y9e5z9RFeCiP8Z5xGoo1nOPzeCh587/JPddB7LpMLvWOcAyPsSEnqId7KtV9PpbgBn1z1Jf4f8KF/WOV2V0v+mLg83bgX3khaaTW0kY7AAAAAElFTkSuQmCC"
|
||||
}
|
||||
},
|
||||
"segment-fonts": {
|
||||
"path": "resources/darkmode-segment-fonts.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAEKADAAQAAAABAAAAEAAAAAA0VXHyAAACI0lEQVQ4EaWTz2saURDH1yaW1YZF2lDstoQllFqkSMzNWhBCKQvm0EOoufTgrZT+AQEvXgo9FPGWa069ehIPomApGCXFHzcRPQimoRu1+Ksaa+z3u22X7CF46MBn38zse/Nm5r0nCP8plmvWr8Jv/8slxiGYAOomWTFZf4wbGG6BzUwms+tyue5ks1kGGIFfYKlw903wtt/va7VarQR9D9wF/LdU1jDjWSwWSy0g0+l04fF4DuHzAHHZaqbPnfbr9fo5A1BSqdQpfK/AOuAcQ0wGvDfBWigUWhdF0dLr9fSJPp/vHpRtwACmMq42kcFsYCORSOxVKpWLRqOx4Xa7BQQTnE6nlEwmT/D/G5iBBTAJIz8Au91u9xjjRywqTiYTvYxWq8UFB0ABRhZXM2CD7qfT6R1ZlpVgMHimqqpgs9ncDodDkCRJGAwG83w+X8a8c3ABDGH6rG8HdWej0eg76M/Bfjgc/jyfz/UsqtXqFL43QAZGFtD143kYiURe4+xzsF8ABTwGB81mUw8wm80Wfr//CD42lBnrwt1vg6ftdvtToVB4D30LSMAB1Hg8fqJHwCeXy7Xg48UyToRHx+ap4/H4K8aXQAH0c5cn4EOn09FjjEajn7BZhgJE1rFaLpdlu93+CPV/wQ6XgUBgCD8fDukWi0UNR5rRNE2xWq29UqnkhF/2er3fLVD0y4ORKVPvgx/gX5f5Knk7mSXn8FWegjMw/A1MAdd6VZHdawAAAABJRU5ErkJggg=="
|
||||
}
|
||||
},
|
||||
"segment-fonts#2.0x": {
|
||||
"path": "resources/darkmode-segment-fonts#2.0x.png",
|
||||
"scale-factor": "2",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAHhlWElmTU0AKgAAAAgABAEaAAUAAAABAAAAPgEbAAUAAAABAAAARgEoAAMAAAABAAIAAIdpAAQAAAABAAAATgAAAAAAAACQAAAAAQAAAJAAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQAAACCgAwAEAAAAAQAAACAAAAAAfgvaUgAAAAlwSFlzAAAWJQAAFiUBSVIk8AAABL1JREFUWAntll1I3XUYxz26fGfL2OZJTY4vm0NUbA2JkvJieJEQEsMLiRDxQkeGwYzYTZHTIMoLr8SLIPUqUhJThJY4GFm+IpuiSVvznYNuR+fr8eX0+Z7Of3rO8bW0bnrgw+/9+T2/53l+v//fx+d/+Y89YPob+/uy5hQEusotSruLDcojid+RZv81+TmK0/ASREMYOEBGyADVDy06zVFE83VybfzawsJCTXt7ewH1JHge5JkTFW2gzd9tbGy860Dm5uYWaN+CNAiFox6KJYcXbXAFKicnJ7W/U8rLy3voy4UIODEv6GRmuFZcXNy5tbVl7O8YGRlR3CsgFYLhRESxvwQ3e3t715/tTmVzc9ORk5PzE2Nvw3k49jBIoZIsIz4+/pu1tbWd+zvrnZ2da4x/DDJSxh6r+KNNyZfb1tbWrxN7ysrKisNsNn/LnKsgY4/NC1Kk5FN8bzxBFPOZmRlPGxxNTU1W5lyHWJDRB8phrDQMMFdVVcWeQerq6qytra1eytPT08/RKUOVrArDYfQzbX+RIsU1j6vXNz8/P0X9O7i/tLTk5YXKysphxt6DKDjwSh5kocZ1rc5mZmZGEuNLPT09v9LugttdXV1KPDfJzs5OoCMJdBsOFQY3BR4NKbDAtb6+vha73f6E+k3IhryMjIz2jY0NNy/ofSgoKLjL+DsgI/b1wn4e0JjcfxaiExISroyOjsq9i6Dnd7ajo+O34WF1bYvJZPIpLCx8lZ5E0Np/ZICy31xbW5saGBgYVlZW9pC2YZgU22pqap7iAqrbkpKS4pecnPwKPbq6CuGeB93vf0ALLfDG9PT0h2FhYWaS8H5wcPC0v7//PP0m7v45m82WFBcXZ8FAuraFW2LLysr6hJ4fYAL0uT60yOIXICM/P/9zHh57S0vLj7RvwFsgFwvlwpd4aNUtEWhgmNzyNaSD/h/29AJjXqLki4XcwcHBO+vr64r5Z6DN40FfPXERlGzfLy8ve9rgqK6ufsBYHux5JXezSn1G8kXx9iePj48P0SdlYgZmXUxRKgt/7u7uXqV0E0IQQ0cKmME9Rq6Zexmg5Itobm6+TLzP4OJfaCuOj2EZFE+huhWGKioq7hAqqtsSGRnpU1JS8jo9FpBOJe6BouRLgvf52/mdWD6i/gHoJFLiKZqvsVuEyysMAwMDW4x9CtLp5YWdHlBdsT8NUaWlpRfJfEt/f/892nK7DXRqT1HfLAzV19ffwwK38cTERBMPVhqdFpBu7bFzX5rbd1sPx2W4zhevn+Rb5vn9gvZV0JjXQvrkVo1pTu3U1JSXF/hxlfEfQSporjzh1GUolBK5UoNR4eHhUTExMRfGxsYe8dnV4kXQL/duYuhQEk5wXZ96TkpLS9PJLRAN2kN7ac9nSSEl/ouLi3mrq6sv8p7H+Pn5nQoJCVm0Wq0pDQ0Nt4uKihRLT9E6J7Ozs2/isQt8LR9SJvv6+pqMyUFBQVs8Yi8HBASE8GBZQ0NDv3Kt8zEmKS5KMD0+ujLnXW1l+YSLx5Q6pachWmt4L4J6LMSD6nK1vCcdD+APUD5Jl/rthgFOD9ChBVJmxEhulxHOyZS7hcFYaxiigwhDhwyW4dIhXUJtJa/nYej6l+VPyIg6s/NvuCYAAAAASUVORK5CYII="
|
||||
}
|
||||
},
|
||||
"segment-gradients": {
|
||||
"path": "resources/segment-gradients.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAP9JREFUOBHVUk0SgTEMTcvKzoexNmNwACuXchaXsnIAjL8DWFnYab2XNMWMnZU3k6ZNk5ekqcjfI7CDnPMcagGZQTqQCPmGBOMdsoWsQwibdvFaXEbD1X7SCGU3beQw7kL35NpuRM59kdOgaOyPA7mth0vEbjwTMytiypJDgLgFOuGQy/l1oTFO0GEgwfuQ30jUUC7UgYuCrdZeY4qW8tGKIDAPJTVGeML4eC/LYr0CzaqMpRLulbSFd2MLZGW8s9MBcILEvgkrX7e2MJjZa+/mh0tOpBJwNOIPyD3h7/LxiE5o46wEnKuWzEQ1kEYHE7P8WFqyv6Bd/fSRnP+P9RNWYmAXVDwH+gAAAABJRU5ErkJggg=="
|
||||
}
|
||||
},
|
||||
"segment-gradients#2.0x": {
|
||||
"path": "resources/segment-gradients#2.0x.png",
|
||||
"scale-factor": "2",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAstJREFUWAntllFuE0EMhmc3EUpSCYlQyh363KtxCq6GeOwhQkjaSkgIZXfxZ/vfnXThBSF4aCzNjscz9m//nk22lItcGHjpDDQiYBiGlemvbVzn/Mrm1sbfkN6C/LDxZGPP3DTNd5vLkkcK4Lc27nLe2lzv2/KP5WSeBxv3Nj7lPEuAyu9277cfv75dl/31pjAf36zKl3cbn3c3m3LYrszO3sr0dfnWbkp5XFv4qxhHWz+kbW829h5tfbBxvCpPn7cfDGeX44xiMVCGJjrTDIPp1oc+ZnPKvaE0AzqWFPTWjAykN8MS5lPnME7BMlgudY/pObTPpFs0Z2Ak1LeJvshMIriBpDvrUx3e7CQVGGC51CfQl1QPANUjrIkVI+x92/oZPxBBXfUswy3ogQ3R5AH8GPdqxB2ViHBOt5JYdH3EztZwlrjeKgHWiXAAQM2ttcIdwlQ/ZwmMge1Ut2idCeie7gXuQjVVlHulZmddV87x3mCw6Sy2lFkC2HX50AGPBIKd6H20hX3PBXBRDBNiwwHt4QkRzA3upscsAeKo79wFjUVXVZ3e7HlVopsjngj2HJztEljn0p9plkBUGC3jgHyY2eM+UHa0ylRVJdq9FXia+J458qb8RmYJ1P5qBcC8ilTMvYiyMzmAkc7sZMmFQxRIrGsdu+NzloAqBuT84gUD4RmgY0wUOaLP1lVCI3Qov0gg+q5XUOdZe8/NICzNUTlJZSJseBJ4py5mMFUyS4A96Fbw5yxEWyZ2xjeSfgtYDARRnsP4KlbgqHUCNO+kN4BXF6Hqmo3YDxs4o7AQoIxigUs4McA/Y16U8wT4vz4ITAzUb0UNKGamywb6sxbU778n6BnztwyWS80AHwv3Cjz1eypL1deJeBRlKwrA8Xb4bujTmm8CsFw8JTT7Irqx6dbGP/kgsS8ivgn8d4yZBP7LJ5mDXx4XBl40Az8BicVNWXOzqGcAAAAASUVORK5CYII="
|
||||
}
|
||||
},
|
||||
"segment-tags": {
|
||||
"path": "resources/darkmode-segment-tags.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAEKADAAQAAAABAAAAEAAAAAA0VXHyAAABNklEQVQ4Ea1TQWrCQBR1bM2qlEDFlYgn6Mpt6K6FrLr0BLlJyCoXyAm8gisxZNF1T1BcBbEQSjdJBH1P54+DRrPxw+P//Pfen0+GUZ3mcNB+Ap41/Yf8D1T62yRlqlNB8wB4TZLkje0gCJZI38AauBiCngmaR8A0iqJFWZY7gjV7mqOmMUgMgWkYhl80SrBmj5zWNA7h2p8QZrb5bEhGDUDtRUziOJ7Z5jRNd4QEOWrgnIi7KwXy0Pf9d8dp3O4gI0cNteJ7lALZretaru3Q9jzPoo+l1rhC2Btw2IMQNzI15mB7wA3PdequA7ZKqe31s46M1hidvUGBv7xpG6A1hejMz0Bjlef5HPmjqqoX3H1PRMw4uYb5V2tWwtmPqY8m38EY4HXaw/HZ4dp8lT8AB7RuC0177AGp/5TKaLLwaQAAAABJRU5ErkJggg=="
|
||||
}
|
||||
},
|
||||
"segment-tags#2.0x": {
|
||||
"path": "resources/darkmode-segment-tags#2.0x.png",
|
||||
"scale-factor": "2",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAHhlWElmTU0AKgAAAAgABAEaAAUAAAABAAAAPgEbAAUAAAABAAAARgEoAAMAAAABAAIAAIdpAAQAAAABAAAATgAAAAAAAACQAAAAAQAAAJAAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQAAACCgAwAEAAAAAQAAACAAAAAAfgvaUgAAAAlwSFlzAAAWJQAAFiUBSVIk8AAAAclJREFUWAntl71KA0EUhdefiFgoqFhZLRZBLC3FBxCLNHkLH8ZS8gjxNSytwmK6PIAEESt3CVnPt8xIdGZ0sgxokQOHO7lz99w7d8jMbpb9MdZa5F/XM5vitiES74Yz2TmOWGzEBpo4km+JB2IudsVjkWJIXokUUItRWKYDNvmhlM/Ei8lk0idLnuf3Mg9iIU5FW4iGaUByVslqr8W7oijK2oAxPjNnO8IzSfA9+WA0Gtncnxafsg1ECkxWRFRyW0XqIpZKnrqIVslTFsFfjX28Er17bpOF7MJ2oIEWmtHYV+SleCuhuS9JWZb1cDhsWFWVL6TmWTSMFprROFHkzXg8fvUqy0lyxTRkHAIaaIloOmCvfdiVsyvs+SaX8RkNTkw0HXCm+7Aj55Fvwvp6vV6mlTc/Gf8CtNB0ECoAPydfEJ1OJ+v3m5M4GLMwgZY3V2gLePanuQXtqGFQKzgRJZsgaFXAqgOrDvzbDnCLzRL8za0EWmg6CHWAt9oXJ7q9Ay00HYQKeFPkkxPd3oEWmg5C3wXcXqfiubG8THgvE/lDoO2snOSPxj7LfkGoAG4v7m8+QrC8ToW6pSkv2HPazsqnxvIJt8L/6sAHQeuLQvkgaVQAAAAASUVORK5CYII="
|
||||
}
|
||||
},
|
||||
"segment-views": {
|
||||
"path": "resources/darkmode-segment-views.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAEKADAAQAAAABAAAAEAAAAAA0VXHyAAABcklEQVQ4EcVRPU/CUBR9rbJgTai7gwkrbGjThI2li0xOrJDoj5ABwl9gM8yO9A9QTQClu4OGCd1smvBRAimt55iWBWxiHLzJ6b2955z73ssV4o8hJfiPwF1GvIm8SNBuKQ4sAnf5fP7DNM2Hbrf7yJq9iNt76BnI22w2+9ZsNm3HcYZhGK6AOFbskYPmlVqAnu8ooRnUarXZZDKZBUEQm3YyOWqq1eqcHrhLnHDV6XQ+1+u1PxqN3Far5Q8Gg9DzvO0A1v1+PyRn27ZLLT30HuKzUBTlJZVKFQuFQgYQrut6lmVt8H6FJ5TL5bmmaQe6rqfxm2GPHqQFB+yEqqppwzAEbiTq9bqQJOl4RxQ15J8I9mVZpjlJIhIHJDoj8v8H8CKn2Om43W4Pp9Opjd1t4v01Go24jPOGGmrpoTd6ieA2DOAea3zv9XqW7/vjeABr9shRE2n3bhCcOAFugOdcLresVCpL1E/ANaACv4oLqM+THF/58+6PHzr4cwAAAABJRU5ErkJggg=="
|
||||
}
|
||||
},
|
||||
"segment-views#2.0x": {
|
||||
"path": "resources/darkmode-segment-views#2.0x.png",
|
||||
"scale-factor": "2",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAHhlWElmTU0AKgAAAAgABAEaAAUAAAABAAAAPgEbAAUAAAABAAAARgEoAAMAAAABAAIAAIdpAAQAAAABAAAATgAAAAAAAACQAAAAAQAAAJAAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQAAACCgAwAEAAAAAQAAACAAAAAAfgvaUgAAAAlwSFlzAAAWJQAAFiUBSVIk8AAAAtRJREFUWAntVk1rGlEUldBFV0K77LqB0uLSlau0u9J/4M4ioQ2SECjBbbtqEBela0ErSAqNO3eCiZjEWYxEF+lCoRmVIgiN9QO16us5w7xhYq2JmkIDXji8O+/de86d+2bejM22tFvagceoexc4M/AeI+f+qd0H+2tAAQSxurraJOQ1xizwCrgH3IjdActz4DPQAyg88vv9aq1WywghOgT9nZ0dlWtGDGOZw1xyzGxPkLELfAf0u11bW/uWy+VSw+GwCtGJxjVVVVOIPZd5Bge5yDnVHmD1DaAAZov39vbS3W43P1FxyiRyTmOxWHpsi8hNDWpdshe4GgK6sNvtrpTLZQX8bPGi1tE0TSGn5De0qGnaITzh8Xi6DodDL8LpdIqjoyPR6cxfA3MzmYwgF/nJTQ36ADVNi8MTzWZTDAaDYT6f/xEIBH5xjtje3halUolrV3aDMcViUWxtbem5zA8Gg31ykpsaBu8+RtM+whPtdvvCqtBqtbrJZPJifX1dPt0iGo2Ker0uRqORGUqfc5FIRJIL5jCXHGYgHGpQC6CmaXoB/X7/zBps9avV6k88VC3rFsXjcUFYW8wYxlpzrT41oDp7AZJEbtHm5ubAIBI4AwayxTLub+PCBUjiRCKht7vRaMipa43jBayYmzCj0+vxsLPZ7Hb7jJmXw+cu4DLN/FfLApYdWHbgv+nAV77J+JOxK4pygI9Lef43e3ImOLWTk5MDahgRuqaMvgvnA9AB9CPW5/Od4qOSxvnamnTG8iPE2CusValU0hsbG3nJa2hQi5p/GKt7CaQBXQBjOxwOZ/AZVa1i0wpgbCgUyjDXwnMI3wPIDsCdbg+x/A7QAL0Yl8tVzWaz/DHVxgvA3Pnx8XGKMTIeI39O3wLkmttWkPkM+ASYW4R/AP3uCoWC8Hq91jtlTAR4CjD3Rm3SFsmtOoSSB7h2ixet7BEI9oEvAP3bab8BN+PtjUyt5m8AAAAASUVORK5CYII="
|
||||
}
|
||||
},
|
||||
"text-align-center": {
|
||||
"path": "resources/text-align-center-white.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAAA4AAAAHCAYAAAA4R3wZAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAADqADAAQAAAABAAAABwAAAACw4FuLAAAAMUlEQVQYGWP8DwQMZAAWoB5GMvQxgDTCALE2gy1C1kiSzSCNxNoEcxmYptiPpNrKCAAssQcY3RRi6QAAAABJRU5ErkJggg=="
|
||||
}
|
||||
},
|
||||
"text-align-center-white": {
|
||||
"path": "resources/text-align-center-white.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAAA4AAAAHCAYAAAA4R3wZAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAADqADAAQAAAABAAAABwAAAACw4FuLAAAAMUlEQVQYGWP8DwQMZAAWoB5GMvQxgDTCALE2gy1C1kiSzSCNxNoEcxmYptiPpNrKCAAssQcY3RRi6QAAAABJRU5ErkJggg=="
|
||||
}
|
||||
},
|
||||
"text-align-left": {
|
||||
"path": "resources/text-align-left-white.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAAA4AAAAHCAYAAAA4R3wZAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAADqADAAQAAAABAAAABwAAAACw4FuLAAAAJklEQVQYGWP8DwQMZAAWoB5GMvQxgDSSYiPcErrZCPcVXW0E+xMAOLUHGEXVaqUAAAAASUVORK5CYII="
|
||||
}
|
||||
},
|
||||
"text-align-left-white": {
|
||||
"path": "resources/text-align-left-white.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAAA4AAAAHCAYAAAA4R3wZAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAADqADAAQAAAABAAAABwAAAACw4FuLAAAAJklEQVQYGWP8DwQMZAAWoB5GMvQxgDSSYiPcErrZCPcVXW0E+xMAOLUHGEXVaqUAAAAASUVORK5CYII="
|
||||
}
|
||||
},
|
||||
"text-align-right": {
|
||||
"path": "resources/text-align-right-white.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAAA4AAAAHCAYAAAA4R3wZAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAADqADAAQAAAABAAAABwAAAACw4FuLAAAALElEQVQYGWP8DwQMZAAWoB5GMvQxgDQiA6JtR9dItO0gjUTbguw0qviRJJsBI8sHFsAi5+AAAAAASUVORK5CYII="
|
||||
}
|
||||
},
|
||||
"text-align-right-white": {
|
||||
"path": "resources/text-align-right-white.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAAA4AAAAHCAYAAAA4R3wZAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAADqADAAQAAAABAAAABwAAAACw4FuLAAAALElEQVQYGWP8DwQMZAAWoB5GMvQxgDQiA6JtR9dItO0gjUTbguw0qviRJJsBI8sHFsAi5+AAAAAASUVORK5CYII="
|
||||
}
|
||||
}
|
||||
},
|
||||
"fonts": {
|
||||
"autosize.font": {
|
||||
"font-name": "Arial",
|
||||
"size": "8"
|
||||
},
|
||||
"colorchooser.font": {
|
||||
"font-name": "Arial",
|
||||
"size": "10"
|
||||
},
|
||||
"control.font": {
|
||||
"font-name": "Arial",
|
||||
"size": "11"
|
||||
},
|
||||
"control.small.font": {
|
||||
"font-name": "Arial",
|
||||
"size": "10"
|
||||
},
|
||||
"db.font": {
|
||||
"font-name": "Arial",
|
||||
"size": "11"
|
||||
},
|
||||
"scripteditor.font": {
|
||||
"alternative-font-names": "Hack,Consolas,Menlo",
|
||||
"font-name": "Hack",
|
||||
"size": "12"
|
||||
},
|
||||
"title.font": {
|
||||
"bold": "true",
|
||||
"font-name": "Arial",
|
||||
"size": "13"
|
||||
}
|
||||
},
|
||||
"colors": {
|
||||
"background": "#1f1f1fff",
|
||||
"checkmark.color": "#999999ff",
|
||||
"checkmark.color.header": "#999999ff",
|
||||
"checkmark.fill": "#67676711",
|
||||
"control.back": "#1d1d1dff",
|
||||
"control.font": "#d6d6d6ff",
|
||||
"control.frame": "#c2c2c23d",
|
||||
"control.value": "#676767ff",
|
||||
"db.background": "#1f1f1fff",
|
||||
"db.drag.indicator": "#df0000ff",
|
||||
"db.font": "#d4d4d4ff",
|
||||
"db.row.alternate.back": "#ffffff08",
|
||||
"db.row.back": "#f3f3f305",
|
||||
"db.row.line": "#333333ff",
|
||||
"db.selection": "#117bffad",
|
||||
"editView.backgrund": "#1f1f1fff",
|
||||
"editView.crosslines.background": "#ffffff96",
|
||||
"editView.crosslines.foreground": "#00000096",
|
||||
"editView.lasso.fill": "#0000d814",
|
||||
"editView.lasso.frame": "#ffffffdc",
|
||||
"editView.view.highlight": "#ffffff5a",
|
||||
"editView.view.selection": "#ff0000c8",
|
||||
"focus": "#4c9bffff",
|
||||
"gradient.editor.back": "#ffffff0a",
|
||||
"groupframe": "#ffffff05",
|
||||
"header.text": "#d4d4d4ff",
|
||||
"menu.selected": "#0f79ffff",
|
||||
"scrollbar.background": "#1a1a1aff",
|
||||
"scrollbar.frame": "#9b9b9b1e",
|
||||
"scrollbar.scroller": "#595959ff",
|
||||
"shading.light.bottom": "#292929ff",
|
||||
"shading.light.frame": "#2e2e2eff",
|
||||
"textbutton.text": "#d5d5d5ff",
|
||||
"textbutton.text.highlighted": "#d4d4d4ff",
|
||||
"warning.background": "#ff0000ff",
|
||||
"warning.font": "#ffffffff",
|
||||
"warning.frame": "#9b0000ff"
|
||||
},
|
||||
"gradients": {
|
||||
"Default TextButton Gradient": [
|
||||
{
|
||||
"rgba": "#3f3f3fff",
|
||||
"start": "0"
|
||||
},
|
||||
{
|
||||
"rgba": "#212121ff",
|
||||
"start": "1"
|
||||
}
|
||||
],
|
||||
"Default TextButton Gradient 2": [
|
||||
{
|
||||
"rgba": "#dcdcdcff",
|
||||
"start": "0"
|
||||
},
|
||||
{
|
||||
"rgba": "#b4b4b4ff",
|
||||
"start": "1"
|
||||
}
|
||||
],
|
||||
"Default TextButton Gradient Highlighted": [
|
||||
{
|
||||
"rgba": "#595959ff",
|
||||
"start": "0"
|
||||
},
|
||||
{
|
||||
"rgba": "#545454ff",
|
||||
"start": "1"
|
||||
}
|
||||
],
|
||||
"Default TextButton Gradient Highlighted 2": [
|
||||
{
|
||||
"rgba": "#b4b4b4ff",
|
||||
"start": "0"
|
||||
},
|
||||
{
|
||||
"rgba": "#646464ff",
|
||||
"start": "1"
|
||||
}
|
||||
],
|
||||
"GradientView": [
|
||||
{
|
||||
"rgba": "#282828ff",
|
||||
"start": "0"
|
||||
},
|
||||
{
|
||||
"rgba": "#202020ff",
|
||||
"start": "1"
|
||||
}
|
||||
],
|
||||
"Toolbar": [
|
||||
{
|
||||
"rgba": "#3e3f41ff",
|
||||
"start": "0"
|
||||
},
|
||||
{
|
||||
"rgba": "#2b2b2cff",
|
||||
"start": "0.5"
|
||||
},
|
||||
{
|
||||
"rgba": "#323334ff",
|
||||
"start": "1"
|
||||
}
|
||||
],
|
||||
"Transparent": [
|
||||
{
|
||||
"rgba": "#ffffff00",
|
||||
"start": "0"
|
||||
},
|
||||
{
|
||||
"rgba": "#ffffff00",
|
||||
"start": "1"
|
||||
}
|
||||
],
|
||||
"shading.light": [
|
||||
{
|
||||
"rgba": "#262626ff",
|
||||
"start": "0"
|
||||
},
|
||||
{
|
||||
"rgba": "#292929ff",
|
||||
"start": "0.5"
|
||||
},
|
||||
{
|
||||
"rgba": "#2b2b2bff",
|
||||
"start": "1"
|
||||
}
|
||||
],
|
||||
"tabswitch.selected": [
|
||||
{
|
||||
"rgba": "#008dc7ff",
|
||||
"start": "0"
|
||||
},
|
||||
{
|
||||
"rgba": "#00469eff",
|
||||
"start": "0.689999997615814208984375"
|
||||
},
|
||||
{
|
||||
"rgba": "#005bccff",
|
||||
"start": "1"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,416 @@
|
||||
{
|
||||
"vstgui-ui-description": {
|
||||
"version": "1",
|
||||
"variables": {},
|
||||
"bitmaps": {
|
||||
"attach-bottom": {
|
||||
"path": "resources/attach-bottom.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAABe2lDQ1BJQ0MgUHJvZmlsZQAAKJF9kE0rRFEYx38zXjNkwcLC4jaG1RCjvGyUmYSaxTRGedvcueZFmXG7c4VsLJTtFCU23hZ8AjYWylopRUrKVyA20vUcQ+OlPHXO+Z3nPM+/5/zB7ddNc7a0HTJZ24oOBrWx8Qmt4gEX5XjQ8OpGzuyPRMJIfJ0/4+VaqiWuWpXW3/d/wzOdyBngqhTuM0zLFh4SblqwTcVKr96SoYRXFKcKvKE4XuCjj5pYNCR8KqwZaX1a+E7Yb6StDLiVvi/+rSb1jTOz88bnPOon1Yns6IicXlmN5IgySFC8GGaAEF100Ct7F60EaJMbdmLRVs2hOXPJmkmlba1fnEhow1mjza8F2ju6Qfn6269ibm4Xep6hJF/MxTfhZA0abos53w7UrsLxualb+keqRJY7mYTHQ6gZh7pLqJrMJTsDhR9VB6Hs3nGemqFiHd7yjvO65zhv+9IsHp1lCx59anFwA7FlCF/A1ja0iHbt1Dv7WWccXX/QZQAAAExJREFUKBVjZEAALSAzDMFFYa0C8q6BRJhQhBEcUSAThIkGDUCVIIwBcNmAoRAmMKoBFhL4aEagJLYYhkXaazTNq1jQBGBcdIUwcQYAOGIGVqwWW9EAAAAASUVORK5CYII="
|
||||
}
|
||||
},
|
||||
"attach-bottom#2.0x": {
|
||||
"path": "resources/attach-bottom#2.0x.png",
|
||||
"scale-factor": "2",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAABe2lDQ1BJQ0MgUHJvZmlsZQAAKJF9kE0rRFEYx38zXjNkwcLC4jaG1RCjvGyUmYSaxTRGedvcueZFmXG7c4VsLJTtFCU23hZ8AjYWylopRUrKVyA20vUcQ+OlPHXO+Z3nPM+/5/zB7ddNc7a0HTJZ24oOBrWx8Qmt4gEX5XjQ8OpGzuyPRMJIfJ0/4+VaqiWuWpXW3/d/wzOdyBngqhTuM0zLFh4SblqwTcVKr96SoYRXFKcKvKE4XuCjj5pYNCR8KqwZaX1a+E7Yb6StDLiVvi/+rSb1jTOz88bnPOon1Yns6IicXlmN5IgySFC8GGaAEF100Ct7F60EaJMbdmLRVs2hOXPJmkmlba1fnEhow1mjza8F2ju6Qfn6269ibm4Xep6hJF/MxTfhZA0abos53w7UrsLxualb+keqRJY7mYTHQ6gZh7pLqJrMJTsDhR9VB6Hs3nGemqFiHd7yjvO65zhv+9IsHp1lCx59anFwA7FlCF/A1ja0iHbt1Dv7WWccXX/QZQAAAAlwSFlzAAAWJQAAFiUBSVIk8AAAAFxJREFUSA1jYBggsBVo738SMUgPBmDCEBlgAZArsbqUWu6CBRvR5tE8iEYtIBgXo0E0GkQEQ4CggtFUNAKCiIWgH1EVbEPlEs8jpw6GVT64aHDNR/NkSrwfyVQJAEutJvm+lAwhAAAAAElFTkSuQmCC"
|
||||
}
|
||||
},
|
||||
"attach-bottom-non": {
|
||||
"path": "resources/attach-bottom-non.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAABe2lDQ1BJQ0MgUHJvZmlsZQAAKJF9kE0rRFEYx38zXjNkwcLC4jaG1RCjvGyUmYSaxTRGedvcueZFmXG7c4VsLJTtFCU23hZ8AjYWylopRUrKVyA20vUcQ+OlPHXO+Z3nPM+/5/zB7ddNc7a0HTJZ24oOBrWx8Qmt4gEX5XjQ8OpGzuyPRMJIfJ0/4+VaqiWuWpXW3/d/wzOdyBngqhTuM0zLFh4SblqwTcVKr96SoYRXFKcKvKE4XuCjj5pYNCR8KqwZaX1a+E7Yb6StDLiVvi/+rSb1jTOz88bnPOon1Yns6IicXlmN5IgySFC8GGaAEF100Ct7F60EaJMbdmLRVs2hOXPJmkmlba1fnEhow1mjza8F2ju6Qfn6269ibm4Xep6hJF/MxTfhZA0abos53w7UrsLxualb+keqRJY7mYTHQ6gZh7pLqJrMJTsDhR9VB6Hs3nGemqFiHd7yjvO65zhv+9IsHp1lCx59anFwA7FlCF/A1ja0iHbt1Dv7WWccXX/QZQAAAFFJREFUKBVjZEAALSAzDMFFYa0C8q6BRJhQhBEcUSAThIkGWUCVIDyIAE4n4fL0IHI7zCk4/cAIVKEFxOgxDIu01zAToPQqFjQBGBddIUycAQBFoQfGFfwscAAAAABJRU5ErkJggg=="
|
||||
}
|
||||
},
|
||||
"attach-bottom-non#2.0x": {
|
||||
"path": "resources/attach-bottom-non#2.0x.png",
|
||||
"scale-factor": "2",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAABe2lDQ1BJQ0MgUHJvZmlsZQAAKJF9kE0rRFEYx38zXjNkwcLC4jaG1RCjvGyUmYSaxTRGedvcueZFmXG7c4VsLJTtFCU23hZ8AjYWylopRUrKVyA20vUcQ+OlPHXO+Z3nPM+/5/zB7ddNc7a0HTJZ24oOBrWx8Qmt4gEX5XjQ8OpGzuyPRMJIfJ0/4+VaqiWuWpXW3/d/wzOdyBngqhTuM0zLFh4SblqwTcVKr96SoYRXFKcKvKE4XuCjj5pYNCR8KqwZaX1a+E7Yb6StDLiVvi/+rSb1jTOz88bnPOon1Yns6IicXlmN5IgySFC8GGaAEF100Ct7F60EaJMbdmLRVs2hOXPJmkmlba1fnEhow1mjza8F2ju6Qfn6269ibm4Xep6hJF/MxTfhZA0abos53w7UrsLxualb+keqRJY7mYTHQ6gZh7pLqJrMJTsDhR9VB6Hs3nGemqFiHd7yjvO65zhv+9IsHp1lCx59anFwA7FlCF/A1ja0iHbt1Dv7WWccXX/QZQAAAAlwSFlzAAAWJQAAFiUBSVIk8AAAAFtJREFUSA1jYBggsBVo738SMUgPBmDCEBlgAZArsbqUWu6CBRvR5rEQrRKicBuJ6keVD8EQGHzJlOY5eTQfDMF0SmsnD758QLdkCvI6rDKhFg2u+Wiek2mdKBgAxS8vISbuf78AAAAASUVORK5CYII="
|
||||
}
|
||||
},
|
||||
"attach-left": {
|
||||
"path": "resources/attach-left.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAABe2lDQ1BJQ0MgUHJvZmlsZQAAKJF9kE0rRFEYx38zXjNkwcLC4jaG1RCjvGyUmYSaxTRGedvcueZFmXG7c4VsLJTtFCU23hZ8AjYWylopRUrKVyA20vUcQ+OlPHXO+Z3nPM+/5/zB7ddNc7a0HTJZ24oOBrWx8Qmt4gEX5XjQ8OpGzuyPRMJIfJ0/4+VaqiWuWpXW3/d/wzOdyBngqhTuM0zLFh4SblqwTcVKr96SoYRXFKcKvKE4XuCjj5pYNCR8KqwZaX1a+E7Yb6StDLiVvi/+rSb1jTOz88bnPOon1Yns6IicXlmN5IgySFC8GGaAEF100Ct7F60EaJMbdmLRVs2hOXPJmkmlba1fnEhow1mjza8F2ju6Qfn6269ibm4Xep6hJF/MxTfhZA0abos53w7UrsLxualb+keqRJY7mYTHQ6gZh7pLqJrMJTsDhR9VB6Hs3nGemqFiHd7yjvO65zhv+9IsHp1lCx59anFwA7FlCF/A1ja0iHbt1Dv7WWccXX/QZQAAAFVJREFUKBVjYGBg0IJiIEUYMAGVhEExYdVAFSxEqYIoArmEJA0glzCAnEQSgDlJFKirgYBOkJrXZNvwmggbwC4g2wYCzgdLrwKRME8To+EaTBFJSQMAN4EG9R7vAZUAAAAASUVORK5CYII="
|
||||
}
|
||||
},
|
||||
"attach-left#2.0x": {
|
||||
"path": "resources/attach-left#2.0x.png",
|
||||
"scale-factor": "2",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAABe2lDQ1BJQ0MgUHJvZmlsZQAAKJF9kE0rRFEYx38zXjNkwcLC4jaG1RCjvGyUmYSaxTRGedvcueZFmXG7c4VsLJTtFCU23hZ8AjYWylopRUrKVyA20vUcQ+OlPHXO+Z3nPM+/5/zB7ddNc7a0HTJZ24oOBrWx8Qmt4gEX5XjQ8OpGzuyPRMJIfJ0/4+VaqiWuWpXW3/d/wzOdyBngqhTuM0zLFh4SblqwTcVKr96SoYRXFKcKvKE4XuCjj5pYNCR8KqwZaX1a+E7Yb6StDLiVvi/+rSb1jTOz88bnPOon1Yns6IicXlmN5IgySFC8GGaAEF100Ct7F60EaJMbdmLRVs2hOXPJmkmlba1fnEhow1mjza8F2ju6Qfn6269ibm4Xep6hJF/MxTfhZA0abos53w7UrsLxualb+keqRJY7mYTHQ6gZh7pLqJrMJTsDhR9VB6Hs3nGemqFiHd7yjvO65zhv+9IsHp1lCx59anFwA7FlCF/A1ja0iHbt1Dv7WWccXX/QZQAAAAlwSFlzAAAWJQAAFiUBSVIk8AAAAG1JREFUSA1jYKAT2Aq0B4RpBv4DTQZhqgMmqpuIZuCQtQAjTqkdB3DzhmwQwaN6+PkAFPuwCCKXRikRaB5EsMiAuRbGp5SGm0dzH4xaQDCuWAiqIE/BNnRt8FhHl6CUP/QjGRYHGGFGadDQTT8ADI8htST/kYAAAAAASUVORK5CYII="
|
||||
}
|
||||
},
|
||||
"attach-left-non": {
|
||||
"path": "resources/attach-left-non.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAABe2lDQ1BJQ0MgUHJvZmlsZQAAKJF9kE0rRFEYx38zXjNkwcLC4jaG1RCjvGyUmYSaxTRGedvcueZFmXG7c4VsLJTtFCU23hZ8AjYWylopRUrKVyA20vUcQ+OlPHXO+Z3nPM+/5/zB7ddNc7a0HTJZ24oOBrWx8Qmt4gEX5XjQ8OpGzuyPRMJIfJ0/4+VaqiWuWpXW3/d/wzOdyBngqhTuM0zLFh4SblqwTcVKr96SoYRXFKcKvKE4XuCjj5pYNCR8KqwZaX1a+E7Yb6StDLiVvi/+rSb1jTOz88bnPOon1Yns6IicXlmN5IgySFC8GGaAEF100Ct7F60EaJMbdmLRVs2hOXPJmkmlba1fnEhow1mjza8F2ju6Qfn6269ibm4Xep6hJF/MxTfhZA0abos53w7UrsLxualb+keqRJY7mYTHQ6gZh7pLqJrMJTsDhR9VB6Hs3nGemqFiHd7yjvO65zhv+9IsHp1lCx59anFwA7FlCF/A1ja0iHbt1Dv7WWccXX/QZQAAAGNJREFUKBVjYGBg0IJiIEUYMAGVhEExYdVAFSxEqYIoArmEJA0glzCAnEQSgGkQBerKQtIJYqPzQWpIt4ERqKkBpBMIGsAkbgIsD3MSbmVoMqQE6yqQXlI0XINZpgVkgDBRAAApoAbC0f2dZgAAAABJRU5ErkJggg=="
|
||||
}
|
||||
},
|
||||
"attach-left-non#2.0x": {
|
||||
"path": "resources/attach-left-non#2.0x.png",
|
||||
"scale-factor": "2",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAABe2lDQ1BJQ0MgUHJvZmlsZQAAKJF9kE0rRFEYx38zXjNkwcLC4jaG1RCjvGyUmYSaxTRGedvcueZFmXG7c4VsLJTtFCU23hZ8AjYWylopRUrKVyA20vUcQ+OlPHXO+Z3nPM+/5/zB7ddNc7a0HTJZ24oOBrWx8Qmt4gEX5XjQ8OpGzuyPRMJIfJ0/4+VaqiWuWpXW3/d/wzOdyBngqhTuM0zLFh4SblqwTcVKr96SoYRXFKcKvKE4XuCjj5pYNCR8KqwZaX1a+E7Yb6StDLiVvi/+rSb1jTOz88bnPOon1Yns6IicXlmN5IgySFC8GGaAEF100Ct7F60EaJMbdmLRVs2hOXPJmkmlba1fnEhow1mjza8F2ju6Qfn6269ibm4Xep6hJF/MxTfhZA0abos53w7UrsLxualb+keqRJY7mYTHQ6gZh7pLqJrMJTsDhR9VB6Hs3nGemqFiHd7yjvO65zhv+9IsHp1lCx59anFwA7FlCF/A1ja0iHbt1Dv7WWccXX/QZQAAAAlwSFlzAAAWJQAAFiUBSVIk8AAAAHJJREFUSA1jYKAT2Aq0B4RpBv4DTQZhqgMmqpuIZuCQtQAjTqkdB3DzhmwQwaN6+PkAFPugCMKWq2FyhORR9NI8iGCRAU9WMAEKabh5NPfBqAUEo4qFoAryFGxD1waPdXQJSvlDP5JhcYARZpQGDd30AwDfmxiVG1IHGAAAAABJRU5ErkJggg=="
|
||||
}
|
||||
},
|
||||
"attach-right": {
|
||||
"path": "resources/attach-right.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAABe2lDQ1BJQ0MgUHJvZmlsZQAAKJF9kE0rRFEYx38zXjNkwcLC4jaG1RCjvGyUmYSaxTRGedvcueZFmXG7c4VsLJTtFCU23hZ8AjYWylopRUrKVyA20vUcQ+OlPHXO+Z3nPM+/5/zB7ddNc7a0HTJZ24oOBrWx8Qmt4gEX5XjQ8OpGzuyPRMJIfJ0/4+VaqiWuWpXW3/d/wzOdyBngqhTuM0zLFh4SblqwTcVKr96SoYRXFKcKvKE4XuCjj5pYNCR8KqwZaX1a+E7Yb6StDLiVvi/+rSb1jTOz88bnPOon1Yns6IicXlmN5IgySFC8GGaAEF100Ct7F60EaJMbdmLRVs2hOXPJmkmlba1fnEhow1mjza8F2ju6Qfn6269ibm4Xep6hJF/MxTfhZA0abos53w7UrsLxualb+keqRJY7mYTHQ6gZh7pLqJrMJTsDhR9VB6Hs3nGemqFiHd7yjvO65zhv+9IsHp1lCx59anFwA7FlCF/A1ja0iHbt1Dv7WWccXX/QZQAAAFlJREFUKBVjZCAeaIGUshCvniEMpJYJiEE6wbpBAoQASANIJ1g3IcUgeZAGkgDMD6JAXQ0EdILUvCbbhtdE2AB2AVk2rCLgdhRpkKevoYgQ4DASkEeWBkcuADSkBssJFLVJAAAAAElFTkSuQmCC"
|
||||
}
|
||||
},
|
||||
"attach-right#2.0x": {
|
||||
"path": "resources/attach-right#2.0x.png",
|
||||
"scale-factor": "2",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAABe2lDQ1BJQ0MgUHJvZmlsZQAAKJF9kE0rRFEYx38zXjNkwcLC4jaG1RCjvGyUmYSaxTRGedvcueZFmXG7c4VsLJTtFCU23hZ8AjYWylopRUrKVyA20vUcQ+OlPHXO+Z3nPM+/5/zB7ddNc7a0HTJZ24oOBrWx8Qmt4gEX5XjQ8OpGzuyPRMJIfJ0/4+VaqiWuWpXW3/d/wzOdyBngqhTuM0zLFh4SblqwTcVKr96SoYRXFKcKvKE4XuCjj5pYNCR8KqwZaX1a+E7Yb6StDLiVvi/+rSb1jTOz88bnPOon1Yns6IicXlmN5IgySFC8GGaAEF100Ct7F60EaJMbdmLRVs2hOXPJmkmlba1fnEhow1mjza8F2ju6Qfn6269ibm4Xep6hJF/MxTfhZA0abos53w7UrsLxualb+keqRJY7mYTHQ6gZh7pLqJrMJTsDhR9VB6Hs3nGemqFiHd7yjvO65zhv+9IsHp1lCx59anFwA7FlCF/A1ja0iHbt1Dv7WWccXX/QZQAAAAlwSFlzAAAWJQAAFiUBSVIk8AAAAHBJREFUSA1jYBiCgBHo5u1AvJVWbgdZ8B+KGZhoZQvMXLpYQN8wg3mNAnoYxgEFoUFYK11SEbIzQLkPlknIpbcgG0hzH4AsQ0lWyLaTyUYxj+Y+GLWAYDSxQFWAKoh/BFUPEgXDLBXB4oDaoUu/OAUAtDAjvkuSH9QAAAAASUVORK5CYII="
|
||||
}
|
||||
},
|
||||
"attach-right-non": {
|
||||
"path": "resources/attach-right-non.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAABe2lDQ1BJQ0MgUHJvZmlsZQAAKJF9kE0rRFEYx38zXjNkwcLC4jaG1RCjvGyUmYSaxTRGedvcueZFmXG7c4VsLJTtFCU23hZ8AjYWylopRUrKVyA20vUcQ+OlPHXO+Z3nPM+/5/zB7ddNc7a0HTJZ24oOBrWx8Qmt4gEX5XjQ8OpGzuyPRMJIfJ0/4+VaqiWuWpXW3/d/wzOdyBngqhTuM0zLFh4SblqwTcVKr96SoYRXFKcKvKE4XuCjj5pYNCR8KqwZaX1a+E7Yb6StDLiVvi/+rSb1jTOz88bnPOon1Yns6IicXlmN5IgySFC8GGaAEF100Ct7F60EaJMbdmLRVs2hOXPJmkmlba1fnEhow1mjza8F2ju6Qfn6269ibm4Xep6hJF/MxTfhZA0abos53w7UrsLxualb+keqRJY7mYTHQ6gZh7pLqJrMJTsDhR9VB6Hs3nGemqFiHd7yjvO65zhv+9IsHp1lCx59anFwA7FlCF/A1ja0iHbt1Dv7WWccXX/QZQAAAGhJREFUKBWVkYEJwCAMBFW6gks4kEN0CufpQJ3HXECQgBofDCb/h4ox+FWIPv58qGSTLEilGZwEAKn0KYwPcKUBZKHeiWRvezL3J0SBGqSoaV0X9ceV1jHj8A+fmW1bgH+bMCZv8KoQ7CbDBpgiEQGeAAAAAElFTkSuQmCC"
|
||||
}
|
||||
},
|
||||
"attach-right-non#2.0x": {
|
||||
"path": "resources/attach-right-non#2.0x.png",
|
||||
"scale-factor": "2",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAABe2lDQ1BJQ0MgUHJvZmlsZQAAKJF9kE0rRFEYx38zXjNkwcLC4jaG1RCjvGyUmYSaxTRGedvcueZFmXG7c4VsLJTtFCU23hZ8AjYWylopRUrKVyA20vUcQ+OlPHXO+Z3nPM+/5/zB7ddNc7a0HTJZ24oOBrWx8Qmt4gEX5XjQ8OpGzuyPRMJIfJ0/4+VaqiWuWpXW3/d/wzOdyBngqhTuM0zLFh4SblqwTcVKr96SoYRXFKcKvKE4XuCjj5pYNCR8KqwZaX1a+E7Yb6StDLiVvi/+rSb1jTOz88bnPOon1Yns6IicXlmN5IgySFC8GGaAEF100Ct7F60EaJMbdmLRVs2hOXPJmkmlba1fnEhow1mjza8F2ju6Qfn6269ibm4Xep6hJF/MxTfhZA0abos53w7UrsLxualb+keqRJY7mYTHQ6gZh7pLqJrMJTsDhR9VB6Hs3nGemqFiHd7yjvO65zhv+9IsHp1lCx59anFwA7FlCF/A1ja0iHbt1Dv7WWccXX/QZQAAAAlwSFlzAAAWJQAAFiUBSVIk8AAAAI5JREFUSA3tU4sKgCAMXNH/f03R31UOvZwDCzRHSYJuXrnnjeiDa3Axr24vrWJnB3vYNLbyArsmDmxrhtQqZIc9qKjG/VMTFskweAJ5SPQUgmkYoKvvszSoM2ADvCD9zZ8Skzr+AQYJnBJanWi5ktjTGZSbzbz8HWQKE+EpqEzPLcLv1jpjEXrwdNHtenoAsJ0goBUDUhwAAAAASUVORK5CYII="
|
||||
}
|
||||
},
|
||||
"attach-top": {
|
||||
"path": "resources/attach-top.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAABe2lDQ1BJQ0MgUHJvZmlsZQAAKJF9kE0rRFEYx38zXjNkwcLC4jaG1RCjvGyUmYSaxTRGedvcueZFmXG7c4VsLJTtFCU23hZ8AjYWylopRUrKVyA20vUcQ+OlPHXO+Z3nPM+/5/zB7ddNc7a0HTJZ24oOBrWx8Qmt4gEX5XjQ8OpGzuyPRMJIfJ0/4+VaqiWuWpXW3/d/wzOdyBngqhTuM0zLFh4SblqwTcVKr96SoYRXFKcKvKE4XuCjj5pYNCR8KqwZaX1a+E7Yb6StDLiVvi/+rSb1jTOz88bnPOon1Yns6IicXlmN5IgySFC8GGaAEF100Ct7F60EaJMbdmLRVs2hOXPJmkmlba1fnEhow1mjza8F2ju6Qfn6269ibm4Xep6hJF/MxTfhZA0abos53w7UrsLxualb+keqRJY7mYTHQ6gZh7pLqJrMJTsDhR9VB6Hs3nGemqFiHd7yjvO65zhv+9IsHp1lCx59anFwA7FlCF/A1ja0iHbt1Dv7WWccXX/QZQAAAEpJREFUKBVjZGBg0ALiMCAmBqxiwqFKFCgOwkSDBqBKEMYAuGzAUAgTGNUACwl8NCOSJHKMwyLtNVR+FZC+BmKzQAXQKZhCdHEGAJ6oBlZB+FTeAAAAAElFTkSuQmCC"
|
||||
}
|
||||
},
|
||||
"attach-top#2.0x": {
|
||||
"path": "resources/attach-top#2.0x.png",
|
||||
"scale-factor": "2",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAABe2lDQ1BJQ0MgUHJvZmlsZQAAKJF9kE0rRFEYx38zXjNkwcLC4jaG1RCjvGyUmYSaxTRGedvcueZFmXG7c4VsLJTtFCU23hZ8AjYWylopRUrKVyA20vUcQ+OlPHXO+Z3nPM+/5/zB7ddNc7a0HTJZ24oOBrWx8Qmt4gEX5XjQ8OpGzuyPRMJIfJ0/4+VaqiWuWpXW3/d/wzOdyBngqhTuM0zLFh4SblqwTcVKr96SoYRXFKcKvKE4XuCjj5pYNCR8KqwZaX1a+E7Yb6StDLiVvi/+rSb1jTOz88bnPOon1Yns6IicXlmN5IgySFC8GGaAEF100Ct7F60EaJMbdmLRVs2hOXPJmkmlba1fnEhow1mjza8F2ju6Qfn6269ibm4Xep6hJF/MxTfhZA0abos53w7UrsLxualb+keqRJY7mYTHQ6gZh7pLqJrMJTsDhR9VB6Hs3nGemqFiHd7yjvO65zhv+9IsHp1lCx59anFwA7FlCF/A1ja0iHbt1Dv7WWccXX/QZQAAAAlwSFlzAAAWJQAAFiUBSVIk8AAAAFZJREFUSA1jYKAT2Aq05z+VMchMBiYQMZgAyFVgl9HKUbBgJNp8mgfRqAUE42I0iEaDiGAIEFQwmopGQBCxEPQjqoJtqFzyeeTU0VhrOponU/L9SKROALKRJvkYGlxKAAAAAElFTkSuQmCC"
|
||||
}
|
||||
},
|
||||
"attach-top-non": {
|
||||
"path": "resources/attach-top-non.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAABe2lDQ1BJQ0MgUHJvZmlsZQAAKJF9kE0rRFEYx38zXjNkwcLC4jaG1RCjvGyUmYSaxTRGedvcueZFmXG7c4VsLJTtFCU23hZ8AjYWylopRUrKVyA20vUcQ+OlPHXO+Z3nPM+/5/zB7ddNc7a0HTJZ24oOBrWx8Qmt4gEX5XjQ8OpGzuyPRMJIfJ0/4+VaqiWuWpXW3/d/wzOdyBngqhTuM0zLFh4SblqwTcVKr96SoYRXFKcKvKE4XuCjj5pYNCR8KqwZaX1a+E7Yb6StDLiVvi/+rSb1jTOz88bnPOon1Yns6IicXlmN5IgySFC8GGaAEF100Ct7F60EaJMbdmLRVs2hOXPJmkmlba1fnEhow1mjza8F2ju6Qfn6269ibm4Xep6hJF/MxTfhZA0abos53w7UrsLxualb+keqRJY7mYTHQ6gZh7pLqJrMJTsDhR9VB6Hs3nGemqFiHd7yjvO65zhv+9IsHp1lCx59anFwA7FlCF/A1ja0iHbt1Dv7WWccXX/QZQAAAE9JREFUKBVjZGBg0ALiMCAmBqxiwqFKFCgOwkSDLKBKEB5EAKeTcHl6ELkd5hScfmCEqQDSWkAMi3FYpL2Gyq8C0tdAbBaoADoFU4guzgAAq+cHxnkz0rUAAAAASUVORK5CYII="
|
||||
}
|
||||
},
|
||||
"attach-top-non#2.0x": {
|
||||
"path": "resources/attach-top-non#2.0x.png",
|
||||
"scale-factor": "2",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAABe2lDQ1BJQ0MgUHJvZmlsZQAAKJF9kE0rRFEYx38zXjNkwcLC4jaG1RCjvGyUmYSaxTRGedvcueZFmXG7c4VsLJTtFCU23hZ8AjYWylopRUrKVyA20vUcQ+OlPHXO+Z3nPM+/5/zB7ddNc7a0HTJZ24oOBrWx8Qmt4gEX5XjQ8OpGzuyPRMJIfJ0/4+VaqiWuWpXW3/d/wzOdyBngqhTuM0zLFh4SblqwTcVKr96SoYRXFKcKvKE4XuCjj5pYNCR8KqwZaX1a+E7Yb6StDLiVvi/+rSb1jTOz88bnPOon1Yns6IicXlmN5IgySFC8GGaAEF100Ct7F60EaJMbdmLRVs2hOXPJmkmlba1fnEhow1mjza8F2ju6Qfn6269ibm4Xep6hJF/MxTfhZA0abos53w7UrsLxualb+keqRJY7mYTHQ6gZh7pLqJrMJTsDhR9VB6Hs3nGemqFiHd7yjvO65zhv+9IsHp1lCx59anFwA7FlCF/A1ja0iHbt1Dv7WWccXX/QZQAAAAlwSFlzAAAWJQAAFiUBSVIk8AAAAFpJREFUSA1jYKAT2Aq05z+VMchMBiYQMZgAyFVgl9HKUbBgJNp8FqJVQhRuI1H9qPIhGAKDL5nSPCeP5oMhmE5p7eTBlw8GLJmCggJWuRBLY63paJ6TaZ0oGAAsIi8huR6YpQAAAABJRU5ErkJggg=="
|
||||
}
|
||||
},
|
||||
"segment-bitmaps": {
|
||||
"path": "resources/segment-bitmaps.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAMJJREFUOBFjYBhowAhywP///02AlBUQywDxEyB+D8SCePjHGBkZzwDlGVhABBBYMabPmghhAg2cmbYu3cQkCMafeebMOqAGOB9oYT5QDmwAE1SRFEwxqXyYAc/QDCCaDwuDWKABAUAMC4PXQLYoHv4GoJcWA+XhYSCYPisd5kezmWkz1509exbONzY2XjcLEQZmaf//HwRpBgGYF4ZDGDAwwOPZDJgS1p1lRAqD/8br0tORwmjmzEEYBmTnBUhkUkACABwiWK9EDJAuAAAAAElFTkSuQmCC"
|
||||
}
|
||||
},
|
||||
"segment-bitmaps#2.0x": {
|
||||
"path": "resources/segment-bitmaps#2.0x.png",
|
||||
"scale-factor": "2",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAa5JREFUWAntV8FKxDAQ3YrIXhSRxZu3RcRre/MX9juaH9Cv0B9Iv0dv7VVUvHlSRKRexEt8r5uENJts2EVR2A4Mk8lLpukkeZ2ORoNsegYykwCl1BjtPehE2x2NfcG20A/t78Jy3Kr4K+a0WZZ96jid2XYcBj2FFtoeaOwN9hb6qP0pLMetiteYwzjRBfDNi0xUl7ALomR5xU5RFOcLIDpkXXc43jCII8MXGPai1YYIZcCCXuPE8303hTNr1/4kdwHcU5NWfxz9/VCn05fCGducGztty7b+qOFmgKedBy4m7zFA96dwxuYzeuJmoAXCUxqTOwDUmKRwxuYzeuLywBGQHHoG5YEye8o3Y/B7KMcfQ9fBbzCvwS15grXiZsB2LmmoJRihFL4w3T0DZLipqEToHs9kKbt73jRNEM/zvMOrMA/MSqWeEf/BX4G7AMOE/hjjp+55Ch94wGSyZ90tGHhg4IGOB0B2wXsOjpnzQBbhATXnASEiPCLlwANDPfD/64FDcCQ/GIW23DMKV85i4kfKctQDrIytuAXJGL38Ik60NQUkKZqVzK/8mCDuhss3dLWpMq08Wq0AAAAASUVORK5CYII="
|
||||
}
|
||||
},
|
||||
"segment-colors": {
|
||||
"path": "resources/segment-colors.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAjVJREFUOBGtk8tOU1EUhr/TC5dCKqBUSosXYkWbkJgwlBfQkRgHOBMn4gBNfA4diBMY6AM4AOMTqAOdNMZEKTcTG8ALrYLa0lrOZfufHggEnelKvnNZl/+svfY+8I9m/a3+QreJxm2yfVsMpWyXFPVcL/X8MF3OwfzIQUf2pBkpbzPV5pDw1UMYWnBpwy2uszZ+lPTs/prQ/pfYoJn83sRMLUyiEgVb0bAEWvE4hJPoxJ4xvJzcX7MncNOMVE8xsd4KpRbYaIZ6GJok0IFDN9tE+aTawoTh3qVdkUDgkYkwwBRZcM/BSnsgsCWBmNpP8Yt2Cqp5J+bE8rRhtLH8YAZnVFojwU/FTogeeP8CTv+A3nKdJItyPhcroii2ElA9q4e3QrZhrlMyhs+iIBbEM3HN6PJQDIuMSIrDolPEx/zSoIO4r7wtbFEWJcjkSZ6/D1c/wrRcH0RFVIUr/NRvuwLM5bD86KbQoKx5Tf4VF6s1lgciZK5o+18rtCY2RCCU2xOwFvKKFLG+aG0FTX6RwbpNj+tRCofJDErAP0JxsS6+ahA15nnjnxPfwnccrKVxyGtNS/TbDinXIeZ5VEMWmzGlHVOeT1r0ccN62pDcEZCP0OPZKKsP/MJufbnDNTQbfzIW5ZAE1Ju2w9+hSesuT/wS34IOgmedvNVbna53Oe55xTbjNbyeznNFXVSarSJdjFhj3N5Jb9wU/tNGy0ciacfJphx36Lh+pj7HyaUddz7Zr/b+t/0GPUPe9o1DLvIAAAAASUVORK5CYII="
|
||||
}
|
||||
},
|
||||
"segment-colors#2.0x": {
|
||||
"path": "resources/segment-colors#2.0x.png",
|
||||
"scale-factor": "2",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAABaJJREFUWAntl0tvlUUcxp/3tKenl9MLpxdsoW0ajaGBRD6AidFFF0LwA9SYgLKEuHRp/AY2xk0DbiBujIlEjOLCFTExMTEGjCYmlFYuBUqhLS09t/H3zDkv5fQidcWGCc+Zeeedmef5P/+ZeYv0ojxnB5L/wz8xEEbyZb3TU9REW0XD+ZKG9pSr6lLlZpfKs+DHbpW/eUOF2d2uuysB42Oh0F7RFIST1Op7LCFCXaCzWtUelRFRFuQRnaqcB6fGNLj4LCGZZw0YPBCOMOhKEjRZotGCgCqym4Jk9SmaFZQFuYjqZE6Vq8u6/vaz1t9RQOZwyHcdCmeLGX27lNVghZHrTZJF0KdV2pW6f0118hZVEVFVK2hTdZD6YtDvZ4Iu53cSsqOAaqemID7uiavN0mJLLWoLsAOGBXiBVECdWO2qWICatcrb5RPS0qdeZ7uyvYB3wxESe5zEaiFXixoxMWrXZYijE7iQEL3tz9WiVh7yDpATG0X3gbfBwxNB09umY6uAj0IB8mn1Mq8PFNAPqW1fpnYaXD+mzlZrDrQgwNE7cpO3RfK7TH4ALOIeWJgO+ngPjYayVUCvpiAfjOR7GWsMSCukIApgxiKuZNiEdoJ/kNeIfRK6VKJnHtwBt4CFWMD9IURM0Wgonr9RzodRrWsG4HcdDsIueo0bHD+c3ce7fY+kV5ekA49LGtcjvaw1jRB5olkGpsQPaTOI93gGvPD6aKKvPCgWttdTpU/HYgAel47vpN0D2A+EqgfXpbay1M0dEJDv3Pse2Ksi5DMMYoBuA6s2+QpII2KSSsf4+QzEslnABG6ScAAJQSnuBa/hPWEUiO8PiMn/K8tSx1pVw6ht1V+8/BNgkxaArbONaSTpwqUJOncQsJe1TMziDUIcgMUYY2BUmrmMAAIcWXrMdvmFzp+Boze5LfdgL+ZovKDbcfFhGk8KJj5V1sIdDnZ/HO9uNlpE2nYQXsP7jOjNGd77gMZPwHb7hQeZ0JNd/Oy2qdyfuZuoOEAjlsYUNFs9gzN1xYlrL2pW22CQ24QdPvCrDo58KR2+Jc6NYga851LXPcXcKVINfnZK66VRQHLnJjP6a6S2zvmr14kj9FFggyVXVKj+ptfX1nW1O6uDRxE5xKuZ+pA0A+l0x5CaUmST7ChAt+eI9rUn0SZeySHZby6UhGh1TflwTeOlknr5Ei5muBjG6TZZG0gPgKd4qk3zO0deM3NOhJmWTQ7cvcToo7UZ3kQWQOSJjxS2J/8oF+Y1Wi7rpTKXDwJWM4nuZTPq20+IjpIbMgqxYZtF1PYPHBulUYDmL2D5VE2Aib2CV8L6ZF6tYUGDEBcq/BFS5f4nr6Uk0RIu9PXD7ohNwq3JZ9GXROMd5JiKgmOj4N9Tpek05+jeeZPFjRavVM51cgOyBfVB3EPUBdARqhyYEPlWLaKZpQqs1Qt847v2sy8xX2b5WJ9Lvo9XJQ+1sskBOpOFU2zTt4h8kK8Yz4tqCUvqhrQrIkTrcyFEtyuQrwOL6OpmfuqC1/fJc0rsyCqZz+k0rYbS6IBfZaZJ+P2TSmz7QiS33UYHpHlEtFJnfVqB0+6P0hp7YQ0RMVJHa1hQGn1eJ5PP4/1M50bZKsDvMj9c5Cr9IhtW1A6Z7faGa0eEn1shbqaOQ/kpEapdeISIutUbxB0M6NDZ5BN9Fyds+tmagvqAbFg9DVnoqIYTIBK3I8TWO/d21bUd8Eb0CatYCCJy7Yjz8at1nqH7Q562LTsKKGXmVtgB7/cXh76GdBoM2gFb7xQ4vUaaAotwGnJ8InM+Hm3kvIztR7aPPFWzfQrSt9R/t9y82BbCQWw/Z7X+y9e5z9RFeCiP8Z5xGoo1nOPzeCh587/JPddB7LpMLvWOcAyPsSEnqId7KtV9PpbgBn1z1Jf4f8KF/WOV2V0v+mLg83bgX3khaaTW0kY7AAAAAElFTkSuQmCC"
|
||||
}
|
||||
},
|
||||
"segment-fonts": {
|
||||
"path": "resources/segment-fonts.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAi5JREFUOBGlkkFrGlEQx982SwxBlhCsppscZHPopYTSSlxKDjEEMSB4EIr1C1iweC/5FKLYg3hQ8KoXayBokUQiGiIGPEgpHooGKZrWGiVG6fY/xgiLJZc++PH+M87MzoyPsf883L/yFUXh4V+e8gf3DbjlOI606jxRWTCQTD5KljKZjKvRaOxCi2ARzJ25Aoggnw68icVih6lU6iP0SyBMO4N85CBIC3bq9fqRRqNRLBaLMh6PP8G3BZYeSb1vH0F64AoEAm0EK0Qul7uC7y3QAVXXKgPBNKe23+/rut0u5/V6YTIWj8ef4XoFaDRa8PyhyoDm3A4Gg/FCoXBaKpUmHSBaqdVql/jNNo2ZfXgmEERaAPpqtbopy3LRZDKdW61WuBhLJpNbuGiZq2CWNxNwUvur2Wz2Nc/zo3Q6vZDP578/FPD7/azdbu8iZgOol4m2qH1a0J7H4/nSbDY/QO8DF3ZxYjQaJ6NEo9EhfO+BCCa7eOiAvr7SarXWh8PhgiiKX2F/AxVBENI+nw+SsVAotDgajWTINXBfAJWoCL08fTgcPrDb7XnoH+AatEDF4XBc4E2wYrHI8Dr34JMAvReekqkSFRDK5fJzp9N5Dv0L3E5pSJKUwWgwGYtEIk9x0d+pBTyHKst4si96vZ6MJW2azeaszWY7w49UhI4+kUi8Q9xBp9MxDgaDnwaD4TPsY7fbXaECND9VEwDp34CS7wCdyXi4afsUQ51dARrv5i+W1Q7Fh0TQdgAAAABJRU5ErkJggg=="
|
||||
}
|
||||
},
|
||||
"segment-fonts#2.0x": {
|
||||
"path": "resources/segment-fonts#2.0x.png",
|
||||
"scale-factor": "2",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAABRVJREFUWAntl39I1Gccx88mV7gUDXfdbnZWVOaYols5uWaTGDFGrBz+SmWcOv/TINgf0l85xvbPNsYg/9AQRlBGi/bHZoa1pehmEkNFhiTY5o9yxzm1pGmbfvd6X9/zut3UO2nbP/vAi+/3+3me5/N8ns/zeT7PncXyv/zHEYiKdH7DMNYxJho2mM9Fng9FVFTUHzwjEhmKVDQmDhwQD5p8Arw49wAn5FDYotWELebqtXInuNxud0NbW9s7vL8AcmYtC2JYmIID0eCEsu7u7k6GGTU1Nff4fh+yYCNEtKgwp37UzZxgD89PTp48aciBmJgYY3R09Ca6EnDAPxMFDK8DO+RPTk5+b7PZfA7Iifr6etTGB5ABMRGtKtzOGN4Au+HEuXPnftfEflJSUozZ2dlrtL0JNniy2yCDEA+5CwsLnx84cGBpcr8Tly5dmqe9FuSkEjUsCddT7avv6HV0dKSPjY1Z4uL0GZCGhgYrE7+IJgkUrbBsr9rJNGTF6CZwNDc3bz1+/Lilurqaz4BcvnzZwsnIRbML1PfJJCMO6Ogp+V4fGhqqT0hIWLx79+4vAwMDIdvAkaSb0QAuiINVF4ijKwtG/Mnnrqur+6G8vPwOui9goKCgIMSJ4eHhQdrehiRYNQoreogBtetYJc7Pzz939uzZ3UePHr3Bdw9craysnOcZJCRjCgpVRhto69YuOKDE2gr5TP71vn37png/AUfAjVPfZGZmBkXB6XQa09PTnbS/BTqSK0Zh2QgwUG06TongvHDhwp6KiopB3mfhHnitVust9p3XgIyMjFiuXLmSjeZ50Ni1OcBAObAR7P39/Rm9vb0JRUVFt029HJPh6cOHD9+Pj9c9FJBTp049Rb14CY0urRhzMYEOj72t5J32T5aTzp8//3JqaupvjY2NyV6v10qI07h2o55BtmzZMulyuWJbWlqWzFIrLF1dXbn79+//FuUtUNR0bYcn8hg2Qe7MzMyHycnJD9vb29v4fhfegGwT5cJHfX19c1gOygUSlCajCV6ByI4kA5R826Hk9OnT7dnZ2bpy3wNNvgN064ldoGT7Mi8vL8gBOTQ4ODhMmxuWPZIhSUjnx5MvicqXxt7/iMFhkwmeXpM7PJWY31VVVSkKQXLx4sVtKNLBDuHdDzigyqfVHens7Gym5i+Mj49/yvdrEHTT8a2tSoRDc3NzrRkZGUFRsNvtBjlzg/Z8UDUNybmQCOCpkk+1XMm3t7CwcMzhcGj1Hgj6zWf+/nuAfmT9+vU3/3o/TExMWEjOvbSrMK18JPFOq9He++q+x+P5jB8dC62trV+hKwT9FAupbOj8ESthwn6OZFAUsrKyDApWC/0OgSKoOZYW7nsxFTLu/7W7nf3LIfvnDx48qP3/FbTS5X5264h5Nm/e3Hvs2DFeA9LT02O5fv26C40KkwM0x5ITfk+0NzGgMCljk86cObOzrKzsZ8I8jU7neLnJ/TaUhGPFxcX3eQZJU1OTJt0KKkyaQ3P58sGfFDJiLS0tdRP2Zymx27hyo2G2trY2nRvwKj+7FukTJGbkNHYdK381NjZ2J4Xpdk5OTtrU1NTSnx7qxCI3aSYF7GlsejhZH2uMjPk6YUjhV9lV8unI2MxvhX3MRNswZyYer4/EHOuPnkK8HXaA3nX0FD3ZUCL/BDrGsjWLrYd+B3wRQKkBMqandAq7nJCRv/3rZUZBCxAaq4UIvw1FTtsjG7Il9C17IVFF/+/Kn1SYGQ/x3P+kAAAAAElFTkSuQmCC"
|
||||
}
|
||||
},
|
||||
"segment-gradients": {
|
||||
"path": "resources/segment-gradients.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAP9JREFUOBHVUk0SgTEMTcvKzoexNmNwACuXchaXsnIAjL8DWFnYab2XNMWMnZU3k6ZNk5ekqcjfI7CDnPMcagGZQTqQCPmGBOMdsoWsQwibdvFaXEbD1X7SCGU3beQw7kL35NpuRM59kdOgaOyPA7mth0vEbjwTMytiypJDgLgFOuGQy/l1oTFO0GEgwfuQ30jUUC7UgYuCrdZeY4qW8tGKIDAPJTVGeML4eC/LYr0CzaqMpRLulbSFd2MLZGW8s9MBcILEvgkrX7e2MJjZa+/mh0tOpBJwNOIPyD3h7/LxiE5o46wEnKuWzEQ1kEYHE7P8WFqyv6Bd/fSRnP+P9RNWYmAXVDwH+gAAAABJRU5ErkJggg=="
|
||||
}
|
||||
},
|
||||
"segment-gradients#2.0x": {
|
||||
"path": "resources/segment-gradients#2.0x.png",
|
||||
"scale-factor": "2",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAstJREFUWAntllFuE0EMhmc3EUpSCYlQyh363KtxCq6GeOwhQkjaSkgIZXfxZ/vfnXThBSF4aCzNjscz9m//nk22lItcGHjpDDQiYBiGlemvbVzn/Mrm1sbfkN6C/LDxZGPP3DTNd5vLkkcK4Lc27nLe2lzv2/KP5WSeBxv3Nj7lPEuAyu9277cfv75dl/31pjAf36zKl3cbn3c3m3LYrszO3sr0dfnWbkp5XFv4qxhHWz+kbW829h5tfbBxvCpPn7cfDGeX44xiMVCGJjrTDIPp1oc+ZnPKvaE0AzqWFPTWjAykN8MS5lPnME7BMlgudY/pObTPpFs0Z2Ak1LeJvshMIriBpDvrUx3e7CQVGGC51CfQl1QPANUjrIkVI+x92/oZPxBBXfUswy3ogQ3R5AH8GPdqxB2ViHBOt5JYdH3EztZwlrjeKgHWiXAAQM2ttcIdwlQ/ZwmMge1Ut2idCeie7gXuQjVVlHulZmddV87x3mCw6Sy2lFkC2HX50AGPBIKd6H20hX3PBXBRDBNiwwHt4QkRzA3upscsAeKo79wFjUVXVZ3e7HlVopsjngj2HJztEljn0p9plkBUGC3jgHyY2eM+UHa0ylRVJdq9FXia+J458qb8RmYJ1P5qBcC8ilTMvYiyMzmAkc7sZMmFQxRIrGsdu+NzloAqBuT84gUD4RmgY0wUOaLP1lVCI3Qov0gg+q5XUOdZe8/NICzNUTlJZSJseBJ4py5mMFUyS4A96Fbw5yxEWyZ2xjeSfgtYDARRnsP4KlbgqHUCNO+kN4BXF6Hqmo3YDxs4o7AQoIxigUs4McA/Y16U8wT4vz4ITAzUb0UNKGamywb6sxbU778n6BnztwyWS80AHwv3Cjz1eypL1deJeBRlKwrA8Xb4bujTmm8CsFw8JTT7Irqx6dbGP/kgsS8ivgn8d4yZBP7LJ5mDXx4XBl40Az8BicVNWXOzqGcAAAAASUVORK5CYII="
|
||||
}
|
||||
},
|
||||
"segment-tags": {
|
||||
"path": "resources/segment-tags.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAUVJREFUOBGtk7FLw0AUxnuxGgIiBaVTKVmzOLmbSYcsjv5l+Rv8BzKUDKbQobNLtiCXTRSKCAEtOb8v3h2naZvFg4/37n2/9+7oNWK0YymlTlA+hc60/Y74IYT41HsbhM10opun2F6WZXnNchRFS4Qn6GXXEDLdYjM0h+6llI9xHCuKOWva4+36CyabZwTrul6zEVQn5qzR00x/CIwpdAdw5Tb/GbIiQ7Z3BRSvqqp6cJuzLFOUO4QMWTPAMwniLM/zm6IonNLvlB4ZssYZmwRx4vu+ebaunCSJY/+kmpkYw73BGE90ZIx9UTP2YHfAvp6D9X8dsG3bdnvwOJiasZx7g03TNK9DAzSzMZz9MVCQYRgu0jS9DYLg3PO8YwMx4uQvNL+RIWs8+zHhz3GB4hwKIT6nOxzbEa/Nr/IZkniNwduCG17fcpi2nJTv0OcAAAAASUVORK5CYII="
|
||||
}
|
||||
},
|
||||
"segment-tags#2.0x": {
|
||||
"path": "resources/segment-tags#2.0x.png",
|
||||
"scale-factor": "2",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAdZJREFUWAntl7FKA0EQhnMiIZVFELFImUqsxDJcrMXWt7DJk8QihVwRSKudz2AXS/EJLEREJJWG4Pr9yV6I3G2ylyyY4gZ+Ztmd+f+5ndxlt1L5Z4uK6htjdsjZBTULUXxZTKIo+tGErxUqwIpXIa+DBji0Qq/4F/ABxkWK8C5gQXwfkWPQ6na7l/hKp9O5wz2AJ/AOChVB/HKTOKiBBrgAN/1+/5ssI2isObumGMWqVZubiCxhKp4MBoOpMOxzrzksASowTBEQeYmnhQQtoqh40CLWFQ9WBAVUgfp4DnJ7noq5/EI7xCEuvb5+RnAdxOAaIn1Y5j+2dNxut81wOJwijuPMuuKUKw7LpW+Hn5HQBFdJknySkUsu8dQ0dsWJQ1yg6acuJmNOQM9FqnnfAmZ0pidOxn5GcAvcEu18Mm37qhak+eISp5+6sow5A/cpwaZeXOKEJ2PLPpfL1jJEKyacXM6FFYTBlssCyh0od2Brd0D/gJNgL/uMK/e47tqBMeI6Yoey6XE9j8xVwIjg57yENefEJc6M5d4L+OM4IPIInFpfx+s2VMTUQj25xB/lubC84f+YqwBdu/aALiHyOk65doulXFPP1Uo9uS4rIwrQFa607dqBX76xCWEB3lZIAAAAAElFTkSuQmCC"
|
||||
}
|
||||
},
|
||||
"segment-views": {
|
||||
"path": "resources/segment-views.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAYBJREFUOBHFUj1PwlAUfbWEaJxwoJODMSGMTHZxdFDTGNgZHJUQ/oEb/R+ubuCCoxgTagkrCSpbO7BYYiXE0FLPadoosWVx8CUn7/aej9f7WiH+uKQ0fxAE2+DOIv5WkqRZknYlACY+HwLnvu8fG4bxCqOkquq+LMt36F8Dj2gF2L8XjHvAFUwvlmX16/V6L5vNfkJBYcC60Wj0yEHzTC09YQKKIzSX0+nUbTabbj6fD02x+edOTtd1F9oPeujdgCA3HA7fNE3bKhaL3mAw8FutliiXywInh6hUKqLdbgtyhULBg3aTHnoFUk5N03yIT+J8tVpt1u123x3HWRKs2YtmD9+QHnp/BcRB3G3bDhRFSRwpDuAIqQsniMlkksqTWBuw1hmR/x/AS9zFNx2PRqNetVrt44/z8XbhxeHHWblActRQSw+94SQoMsAJcLNYLKxOp3NfKpXGcQBr9shRE2kziXcEcge4BJ48z5u7rjtHbQAXQC7RlNaEQQUO0nj2vwD/OiglPWLWTQAAAABJRU5ErkJggg=="
|
||||
}
|
||||
},
|
||||
"segment-views#2.0x": {
|
||||
"path": "resources/segment-views#2.0x.png",
|
||||
"scale-factor": "2",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAxxJREFUWAntVj1Im0EYVhERQaEdHNwEwVAdkt2pXSQ4qLiIi9ipncxQkjUpCnXS4q624lCI0dVBEkOQBg1JEOxkqq1UMTGxUTF/vT7PJSefyWeIPwULeeG5u9w97/O+997l+76amqr9jxUQQrwApoDdAj5w7p/uBQGeA28BPyAtl8slCfUb/VfgDfDsUZKBUD1gBr4AKYD25+joKGC1Wn1NTU2XhM1m8x0fHwe4Jhl5Ln3oW3/nZODUBUwBvwBpqVTq++Lioru9vf0QgkIPXFtaWnKDu6/80FODWl1lEwGhDXgH+AFpLO/W1pa3t7c3rBew3JzZbA5tb297i46I2ozRdiMZTPQBOUBaMpn8OTEx4Wd5ywWpZI0ak5OTfmoqffSM1XedBH5scPHs7Owqm81yKDKZjFhZWRH9/f2ioaFBt+TlEqDPwMCAWF1dlVrUpDZjcAzb0Cbg4szIyIjo7u7OLSwsxCORSIZztJOTEzE9PS2MRmPZRGpra4XJZBIzMzMiGo3mndHu7e2lqUltxijYsjaBWU5itwntroaHh6/W1tYS8Xhc3W4RDAbF+Pi4aG1tvU6GY4vFIkKhkBIX9KEvNbSajFEgzZYk0NPTs6slq3Fzc7Ow2+2/canOtUe0ubkpCB4XjWvkkEsf5a/tGePOCWgF1BGhxPnLAjU8A7KqxFqu3vjBCShRj8cjNzI6Oqq7U8Ur7osTqAPhXoZbLv3m5+fv5a+c7p2AEnhoX02gWoFqBZ5MBb7x/7y+vt7idDo9nZ2dPx76/y72NxgMBy6Xy8MYhTUZU47xTG0EPgKX8vmKJhaLhfBS8eKlcg5SyeOWLyGa3pqao6/D4fCenp6GJTnfMAZjNcrg2gaTLcBrwAsouwiHw77BwcEA3/dK/LYEyBkaGgrs7Oz4IHChRNDzo2cMUBXQhi4dg9gBvAcOAGnpdPoQR+TGER0UJ4AS76PEbnIUHz0/Th1AR2mECmfgXAe8Aj4D10eEbwC5u7m5OZFIJLQ7JecT8BJ43EsOQb0jwrS0DbRjQGUlrrAAt9IQyAAsA06ObyU+9YW/y30KUvnazC4AAAAASUVORK5CYII="
|
||||
}
|
||||
},
|
||||
"text-align-center": {
|
||||
"path": "resources/text-align-center.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAAA4AAAAHCAYAAAA4R3wZAAAAAXNSR0IArs4c6QAAADpJREFUGBmdj0EKADAMwhT2/y+7duDdWSg9xVQC0Oz3UKo4HKtIRgkj4jK1cenI5M98a+PrmPazbXteMysTA3aVaLcAAAAASUVORK5CYII="
|
||||
}
|
||||
},
|
||||
"text-align-center-white": {
|
||||
"path": "resources/text-align-center-white.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAAA4AAAAHCAYAAAA4R3wZAAAAAXNSR0IArs4c6QAAADFJREFUGBlj/A8EDGQAFqAeRjL0MYA0wgCxNoMtQtZIks0gjcTaBHMZmKbYj6TayggALLEHGN0UYukAAAAASUVORK5CYII="
|
||||
}
|
||||
},
|
||||
"text-align-left": {
|
||||
"path": "resources/text-align-left.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAAA4AAAAHCAYAAAA4R3wZAAAAAXNSR0IArs4c6QAAAC1JREFUGBljZGBg+A/EJAPG///J0sfACLSKaJ1AS0DqwYA+NsJsA9H0sxHmTwBPOxL3pHFqkwAAAABJRU5ErkJggg=="
|
||||
}
|
||||
},
|
||||
"text-align-left-white": {
|
||||
"path": "resources/text-align-left-white.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAAA4AAAAHCAYAAAA4R3wZAAAAAXNSR0IArs4c6QAAACZJREFUGBlj/A8EDGQAFqAeRjL0MYA0kmIj3BK62Qj3FV1tBPsTADi1BxhF1WqlAAAAAElFTkSuQmCC"
|
||||
}
|
||||
},
|
||||
"text-align-right": {
|
||||
"path": "resources/text-align-right.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAAA4AAAAHCAYAAAA4R3wZAAAAAXNSR0IArs4c6QAAADFJREFUGBljZGBg+A/EJAPG///J0sfAgmwVIyMj0aaQbSMj0EaibUFxHcV+JMV/IJsBYs4NB7DUPhAAAAAASUVORK5CYII="
|
||||
}
|
||||
},
|
||||
"text-align-right-white": {
|
||||
"path": "resources/text-align-right-white.png",
|
||||
"data": {
|
||||
"encoding": "base64",
|
||||
"data": "iVBORw0KGgoAAAANSUhEUgAAAA4AAAAHCAYAAAA4R3wZAAAAAXNSR0IArs4c6QAAACxJREFUGBlj/A8EDGQAFqAeRjL0MYA0IgOibUfXSLTtII1E24LsNKr4kSSbASPLBxbAIufgAAAAAElFTkSuQmCC"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fonts": {
|
||||
"autosize.font": {
|
||||
"font-name": "Arial",
|
||||
"size": "8"
|
||||
},
|
||||
"colorchooser.font": {
|
||||
"font-name": "Arial",
|
||||
"size": "10"
|
||||
},
|
||||
"control.font": {
|
||||
"font-name": "Arial",
|
||||
"size": "11"
|
||||
},
|
||||
"control.small.font": {
|
||||
"font-name": "Arial",
|
||||
"size": "10"
|
||||
},
|
||||
"db.font": {
|
||||
"font-name": "Arial",
|
||||
"size": "11"
|
||||
},
|
||||
"scripteditor.font": {
|
||||
"alternative-font-names": "Hack,Consolas,Menlo",
|
||||
"font-name": "Hack",
|
||||
"size": "12"
|
||||
},
|
||||
"title.font": {
|
||||
"bold": "true",
|
||||
"font-name": "Arial",
|
||||
"size": "13"
|
||||
}
|
||||
},
|
||||
"colors": {
|
||||
"background": "#edededff",
|
||||
"background.high": "#d5d5d5ff",
|
||||
"checkmark.color": "#010000ff",
|
||||
"checkmark.color.header": "#ffffffff",
|
||||
"checkmark.fill": "#00000011",
|
||||
"control.back": "#f7f7f7ff",
|
||||
"control.font": "#000000ff",
|
||||
"control.frame": "#0000003d",
|
||||
"control.value": "#676767ff",
|
||||
"db.background": "#fafafaff",
|
||||
"db.drag.indicator": "#df0000ff",
|
||||
"db.font": "#000000ff",
|
||||
"db.row.alternate.back": "#bcc9d919",
|
||||
"db.row.back": "#f3f3f319",
|
||||
"db.row.line": "#d5d5d5ff",
|
||||
"db.selection": "#81b9ffff",
|
||||
"editView.backgrund": "#f2f2f2ff",
|
||||
"editView.crosslines.background": "#ffffff96",
|
||||
"editView.crosslines.foreground": "#00000096",
|
||||
"editView.lasso.fill": "#0000d814",
|
||||
"editView.lasso.frame": "#ffffffdc",
|
||||
"editView.view.highlight": "#ffffff5a",
|
||||
"editView.view.selection": "#ff0000c8",
|
||||
"focus": "#b4d5ffff",
|
||||
"gradient.editor.back": "#ffffff46",
|
||||
"groupframe": "#00000008",
|
||||
"header.text": "#ffffffff",
|
||||
"menu.selected": "#0f79ffff",
|
||||
"scrollbar.background": "#fafafaff",
|
||||
"scrollbar.frame": "#9b9b9b1e",
|
||||
"scrollbar.scroller": "#909090ff",
|
||||
"shading.light.bottom": "#bfbfbfff",
|
||||
"shading.light.frame": "#a6a6a6ff",
|
||||
"textbutton.text": "#000000ff",
|
||||
"textbutton.text.highlighted": "#ffffffff",
|
||||
"warning.background": "#ff0000ff",
|
||||
"warning.font": "#000000ff",
|
||||
"warning.frame": "#930000ff"
|
||||
},
|
||||
"gradients": {
|
||||
"Default TextButton Gradient": [
|
||||
{
|
||||
"rgba": "#dcdcdcff",
|
||||
"start": "0"
|
||||
},
|
||||
{
|
||||
"rgba": "#b4b4b4ff",
|
||||
"start": "1"
|
||||
}
|
||||
],
|
||||
"Default TextButton Gradient Highlighted": [
|
||||
{
|
||||
"rgba": "#b4b4b4ff",
|
||||
"start": "0"
|
||||
},
|
||||
{
|
||||
"rgba": "#646464ff",
|
||||
"start": "1"
|
||||
}
|
||||
],
|
||||
"GradientView": [
|
||||
{
|
||||
"rgba": "#cdcdcdff",
|
||||
"start": "0"
|
||||
},
|
||||
{
|
||||
"rgba": "#d2d2d2ff",
|
||||
"start": "1"
|
||||
}
|
||||
],
|
||||
"Toolbar": [
|
||||
{
|
||||
"rgba": "#525964ff",
|
||||
"start": "0"
|
||||
},
|
||||
{
|
||||
"rgba": "#3f444bff",
|
||||
"start": "0.5"
|
||||
},
|
||||
{
|
||||
"rgba": "#464d54ff",
|
||||
"start": "1"
|
||||
}
|
||||
],
|
||||
"Transparent": [
|
||||
{
|
||||
"rgba": "#ffffff00",
|
||||
"start": "0"
|
||||
},
|
||||
{
|
||||
"rgba": "#ffffff00",
|
||||
"start": "1"
|
||||
}
|
||||
],
|
||||
"shading.light": [
|
||||
{
|
||||
"rgba": "#edededff",
|
||||
"start": "0"
|
||||
},
|
||||
{
|
||||
"rgba": "#cacacaff",
|
||||
"start": "0.5"
|
||||
},
|
||||
{
|
||||
"rgba": "#bfbfbfff",
|
||||
"start": "1"
|
||||
}
|
||||
],
|
||||
"tabswitch.selected": [
|
||||
{
|
||||
"rgba": "#32c3ffff",
|
||||
"start": "0"
|
||||
},
|
||||
{
|
||||
"rgba": "#0f79ffff",
|
||||
"start": "0.689999997615814208984375"
|
||||
},
|
||||
{
|
||||
"rgba": "#3991ffff",
|
||||
"start": "1"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,335 @@
|
||||
// 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 "uidialogcontroller.h"
|
||||
|
||||
#if VSTGUI_LIVE_EDITING
|
||||
|
||||
#include "uieditcontroller.h"
|
||||
#include "../uiattributes.h"
|
||||
#include "../../lib/coffscreencontext.h"
|
||||
#include "../../lib/cbitmapfilter.h"
|
||||
#include "../../lib/clayeredviewcontainer.h"
|
||||
#include "../../lib/cshadowviewcontainer.h"
|
||||
#include "../../lib/events.h"
|
||||
#include "../../lib/controls/ctextlabel.h"
|
||||
#include "../../lib/controls/cbuttons.h"
|
||||
#include "../../lib/animation/animations.h"
|
||||
#include "../../lib/animation/animator.h"
|
||||
#include "../../lib/animation/timingfunctions.h"
|
||||
#include <cmath>
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
UIDialogController::UIDialogController (IController* baseController, CFrame* frame)
|
||||
: DelegationController (baseController)
|
||||
, frame (frame)
|
||||
{
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIDialogController::run (UTF8StringPtr _templateName, UTF8StringPtr _dialogTitle,
|
||||
UTF8StringPtr _button1, UTF8StringPtr _button2,
|
||||
const SharedPointer<IDialogController>& _dialogController,
|
||||
UIDescription* _description, bool _resizable)
|
||||
{
|
||||
collectOpenGLViews (frame);
|
||||
|
||||
templateName = _templateName;
|
||||
dialogTitle = _dialogTitle;
|
||||
dialogButton1 = _button1;
|
||||
dialogButton2 = _button2 != nullptr ? _button2 : "";
|
||||
dialogController = _dialogController;
|
||||
dialogDescription = _description;
|
||||
resizable = _resizable;
|
||||
CView* view = UIEditController::getEditorDescription ()->createView ("dialog", this);
|
||||
if (view)
|
||||
{
|
||||
auto* layeredView = dynamic_cast<CLayeredViewContainer*>(view);
|
||||
if (layeredView)
|
||||
layeredView->setZIndex (std::numeric_limits<uint32_t>::max () - 1);
|
||||
|
||||
CRect size = view->getViewSize ();
|
||||
size.right += sizeDiff.x;
|
||||
size.bottom += sizeDiff.y;
|
||||
CRect frameSize = frame->getViewSize ();
|
||||
frame->getTransform ().inverse ().transform (frameSize);
|
||||
size.centerInside (frameSize);
|
||||
size.makeIntegral ();
|
||||
view->setViewSize (size);
|
||||
view->setMouseableArea (size);
|
||||
view->setAlphaValue (0.f);
|
||||
|
||||
modalSession = frame->beginModalViewSession (view);
|
||||
frame->registerKeyboardHook (this);
|
||||
frame->registerViewListener (this);
|
||||
view->registerViewListener (this);
|
||||
if (button1)
|
||||
frame->setFocusView (button1);
|
||||
setOpenGLViewsVisible (false);
|
||||
if (dialogController)
|
||||
dialogController->onDialogShow (this);
|
||||
|
||||
using namespace Animation;
|
||||
view->addAnimation (
|
||||
"AlphaAnimation", new AlphaValueAnimation (1.f),
|
||||
new CubicBezierTimingFunction (CubicBezierTimingFunction::easyInOut (160)));
|
||||
|
||||
if (resizable)
|
||||
{
|
||||
if (customViewEmbedder)
|
||||
customViewEmbedder->setAutosizeFlags (kAutosizeAll);
|
||||
view->setAutosizeFlags (kAutosizeAll);
|
||||
view->setViewSize (frameSize);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
forget ();
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIDialogController::close ()
|
||||
{
|
||||
frame->unregisterKeyboardHook (this);
|
||||
frame->unregisterViewListener (this);
|
||||
if (button1)
|
||||
button1->setListener (nullptr);
|
||||
if (button2)
|
||||
button2->setListener (nullptr);
|
||||
setOpenGLViewsVisible (true);
|
||||
|
||||
if (modalSession)
|
||||
{
|
||||
if (auto dialog = frame->getModalView ())
|
||||
dialog->unregisterViewListener (this);
|
||||
frame->endModalViewSession (*modalSession);
|
||||
modalSession = {};
|
||||
}
|
||||
forget ();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIDialogController::viewSizeChanged (CView* view, const CRect& oldSize)
|
||||
{
|
||||
if (view == frame && !resizable)
|
||||
{
|
||||
CView* dialog = frame->getModalView ();
|
||||
CRect viewSize = dialog->getViewSize ();
|
||||
CRect frameSize = frame->getViewSize ();
|
||||
frame->getTransform ().inverse ().transform (frameSize);
|
||||
viewSize.centerInside (frameSize);
|
||||
dialog->setViewSize (viewSize);
|
||||
dialog->setMouseableArea (viewSize);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIDialogController::viewRemoved (CView* view)
|
||||
{
|
||||
if (view != frame)
|
||||
{
|
||||
view->unregisterViewListener (this);
|
||||
close ();
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIDialogController::valueChanged (CControl* control)
|
||||
{
|
||||
if (control->getValue () == control->getMax ())
|
||||
{
|
||||
switch (control->getTag ())
|
||||
{
|
||||
case kButton1Tag:
|
||||
{
|
||||
if (dialogController)
|
||||
dialogController->onDialogButton1Clicked (this);
|
||||
break;
|
||||
}
|
||||
case kButton2Tag:
|
||||
{
|
||||
if (dialogController)
|
||||
dialogController->onDialogButton2Clicked (this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
CView* modalView = frame->getModalView ();
|
||||
using namespace Animation;
|
||||
modalView->addAnimation (
|
||||
"AlphaAnimation", new AlphaValueAnimation (0.f),
|
||||
new CubicBezierTimingFunction (CubicBezierTimingFunction::easyInOut (160)),
|
||||
[this] (CView*, const IdStringPtr, IAnimationTarget*) { close (); });
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
IControlListener* UIDialogController::getControlListener (UTF8StringPtr controlTagName)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
CView* UIDialogController::verifyView (CView* view, const UIAttributes& attributes,
|
||||
const IUIDescription* description)
|
||||
{
|
||||
if (auto control = dynamic_cast<CControl*> (view))
|
||||
{
|
||||
if (control->getTag () == kButton1Tag)
|
||||
{
|
||||
auto* button = dynamic_cast<CTextButton*>(control);
|
||||
if (button)
|
||||
{
|
||||
button1 = button;
|
||||
button->setTitle (dialogButton1.c_str ());
|
||||
layoutButtons ();
|
||||
}
|
||||
}
|
||||
else if (control->getTag () == kButton2Tag)
|
||||
{
|
||||
auto* button = dynamic_cast<CTextButton*>(control);
|
||||
if (button)
|
||||
{
|
||||
button2 = button;
|
||||
if (dialogButton2.empty ())
|
||||
{
|
||||
button->setVisible (false);
|
||||
}
|
||||
else
|
||||
{
|
||||
button->setTitle (dialogButton2.c_str ());
|
||||
}
|
||||
layoutButtons ();
|
||||
}
|
||||
}
|
||||
else if (control->getTag () == kTitleTag)
|
||||
{
|
||||
auto* label = dynamic_cast<CTextLabel*>(control);
|
||||
if (label)
|
||||
{
|
||||
label->setText (dialogTitle.c_str ());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (auto name = attributes.getAttributeValue (IUIDescription::kCustomViewName))
|
||||
{
|
||||
if (*name == "view" && view)
|
||||
{
|
||||
auto controller = dialogController.cast<IController> ();
|
||||
if (auto subView = dialogDescription->createView (templateName.c_str (), controller))
|
||||
{
|
||||
subView->setAttribute (kCViewControllerAttribute, controller);
|
||||
sizeDiff.x = subView->getWidth () - view->getWidth ();
|
||||
sizeDiff.y = subView->getHeight () - view->getHeight ();
|
||||
CRect size = view->getViewSize ();
|
||||
size.setWidth (subView->getWidth ());
|
||||
size.setHeight (subView->getHeight ());
|
||||
view->setViewSize (size);
|
||||
view->setMouseableArea (size);
|
||||
if (auto container = view->asViewContainer ())
|
||||
container->addView (subView);
|
||||
if (controller)
|
||||
dialogController->remember ();
|
||||
customViewEmbedder = view;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (auto shadowViewContainer = dynamic_cast<CShadowViewContainer*> (view))
|
||||
{
|
||||
if (resizable)
|
||||
{
|
||||
auto container = new CViewContainer (view->getViewSize ());
|
||||
container->setAutosizeFlags (view->getAutosizeFlags ());
|
||||
while (shadowViewContainer->hasChildren ())
|
||||
{
|
||||
auto child = shared (shadowViewContainer->getView (0));
|
||||
shadowViewContainer->removeView (child, false);
|
||||
container->addView (child);
|
||||
}
|
||||
view->forget ();
|
||||
view = container;
|
||||
}
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIDialogController::layoutButtons ()
|
||||
{
|
||||
if (button1 && button2)
|
||||
{
|
||||
CRect b1r1 = button1->getViewSize ();
|
||||
CRect b2r1 = button2->getViewSize ();
|
||||
CCoord margin = b1r1.left - b2r1.right;
|
||||
button1->sizeToFit ();
|
||||
button2->sizeToFit ();
|
||||
CRect b1r2 = button1->getViewSize ();
|
||||
CRect b2r2 = button2->getViewSize ();
|
||||
|
||||
b1r2.offset (b1r1.getWidth () - b1r2.getWidth (), b1r1.getHeight () - b1r2.getHeight ());
|
||||
button1->setViewSize (b1r2);
|
||||
button1->setMouseableArea (b1r2);
|
||||
|
||||
b2r2.offset (b2r1.getWidth () - b2r2.getWidth (), b2r1.getHeight () - b2r2.getHeight ());
|
||||
b2r2.offset ((b1r2.left - margin) - b2r2.right, 0);
|
||||
button2->setViewSize (b2r2);
|
||||
button2->setMouseableArea (b2r2);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIDialogController::onKeyboardEvent (KeyboardEvent& event, CFrame* inFrame)
|
||||
{
|
||||
auto guard = shared (this);
|
||||
if (auto focusView = shared (inFrame->getFocusView ()))
|
||||
{
|
||||
focusView->dispatchEvent (event);
|
||||
if (event.consumed)
|
||||
return;
|
||||
}
|
||||
if (event.type != EventType::KeyUp)
|
||||
{
|
||||
if (event.virt == VirtualKey::Return && event.modifiers.empty ())
|
||||
{
|
||||
button1->setValue (button1->getMax ());
|
||||
button1->valueChanged ();
|
||||
event.consumed = true;
|
||||
}
|
||||
else if (event.virt == VirtualKey::Escape && event.modifiers.empty () && button2->isVisible ())
|
||||
{
|
||||
button2->setValue (button2->getMax ());
|
||||
button2->valueChanged ();
|
||||
event.consumed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIDialogController::collectOpenGLViews (CViewContainer* container)
|
||||
{
|
||||
#if VSTGUI_OPENGL_SUPPORT
|
||||
container->forEachChild ([this] (CView* view) {
|
||||
auto openGLView = dynamic_cast<COpenGLView*> (view);
|
||||
if (openGLView && openGLView->isVisible ())
|
||||
openglViews.emplace_back (openGLView);
|
||||
else if (auto childContainer = view->asViewContainer ())
|
||||
collectOpenGLViews (childContainer);
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIDialogController::setOpenGLViewsVisible (bool state)
|
||||
{
|
||||
#if VSTGUI_OPENGL_SUPPORT
|
||||
for (auto& v : openglViews)
|
||||
v->setVisible (state);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // VSTGUI
|
||||
|
||||
#endif // VSTGUI_LIVE_EDITING
|
||||
@@ -0,0 +1,87 @@
|
||||
// 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 "../uidescription.h"
|
||||
|
||||
#if VSTGUI_LIVE_EDITING
|
||||
|
||||
#include "../delegationcontroller.h"
|
||||
#include "../../lib/cframe.h"
|
||||
#include "../../lib/iviewlistener.h"
|
||||
#include "../../lib/copenglview.h"
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
class UIDialogController;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
class IDialogController : public virtual IReference
|
||||
{
|
||||
public:
|
||||
virtual void onDialogButton1Clicked (UIDialogController*) = 0;
|
||||
virtual void onDialogButton2Clicked (UIDialogController*) = 0;
|
||||
virtual void onDialogShow (UIDialogController*) = 0;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class UIDialogController : public NonAtomicReferenceCounted,
|
||||
public DelegationController,
|
||||
public IKeyboardHook,
|
||||
public ViewListenerAdapter
|
||||
{
|
||||
public:
|
||||
UIDialogController (IController* baseController, CFrame* frame);
|
||||
~UIDialogController () override = default;
|
||||
|
||||
void run (UTF8StringPtr templateName, UTF8StringPtr dialogTitle, UTF8StringPtr button1,
|
||||
UTF8StringPtr button2, const SharedPointer<IDialogController>& controller,
|
||||
UIDescription* description, bool resizable = false);
|
||||
|
||||
protected:
|
||||
void valueChanged (CControl* pControl) override;
|
||||
IControlListener* getControlListener (UTF8StringPtr controlTagName) override;
|
||||
CView* verifyView (CView* view, const UIAttributes& attributes, const IUIDescription* description) override;
|
||||
|
||||
void viewSizeChanged (CView* view, const CRect& oldSize) override;
|
||||
void viewRemoved (CView* view) override;
|
||||
|
||||
void close ();
|
||||
void layoutButtons ();
|
||||
void collectOpenGLViews (CViewContainer* container);
|
||||
void setOpenGLViewsVisible (bool state);
|
||||
|
||||
void onKeyboardEvent (KeyboardEvent& event, CFrame* frame) override;
|
||||
|
||||
CFrame* frame;
|
||||
Optional<ModalViewSessionID> modalSession;
|
||||
SharedPointer<IDialogController> dialogController;
|
||||
UIDescription* dialogDescription;
|
||||
SharedPointer<CControl> button1;
|
||||
SharedPointer<CControl> button2;
|
||||
CView* customViewEmbedder {nullptr};
|
||||
CPoint sizeDiff;
|
||||
std::string templateName;
|
||||
std::string dialogTitle;
|
||||
std::string dialogButton1;
|
||||
std::string dialogButton2;
|
||||
bool resizable {false};
|
||||
|
||||
#if VSTGUI_OPENGL_SUPPORT
|
||||
std::list<SharedPointer<COpenGLView> > openglViews;
|
||||
#endif
|
||||
|
||||
enum {
|
||||
kButton1Tag,
|
||||
kButton2Tag,
|
||||
kTitleTag
|
||||
};
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
|
||||
#endif // VSTGUI_LIVE_EDITING
|
||||
@@ -0,0 +1,207 @@
|
||||
// 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 "../uidescription.h"
|
||||
|
||||
#if VSTGUI_LIVE_EDITING
|
||||
|
||||
#include "../iviewcreator.h"
|
||||
#include "../icontroller.h"
|
||||
#include "../uidescriptionlistener.h"
|
||||
#include "iaction.h"
|
||||
#include "uiundomanager.h"
|
||||
#include "uitemplatecontroller.h"
|
||||
#include "../../lib/csplitview.h"
|
||||
#include "../../lib/cframe.h"
|
||||
#include "../../lib/controls/icommandmenuitemtarget.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace VSTGUI {
|
||||
class UIEditView;
|
||||
class UISelection;
|
||||
class UITemplateController;
|
||||
class UIEditMenuController;
|
||||
class UIGridController;
|
||||
class UIZoomSettingController;
|
||||
class GenericStringListDataBrowserSource;
|
||||
class CCommandMenuItem;
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class UIEditController : public CBaseObject,
|
||||
public IController,
|
||||
public IContextMenuController2,
|
||||
public ISplitViewController,
|
||||
public ISplitViewSeparatorDrawer,
|
||||
public IActionPerformer,
|
||||
public IKeyboardHook,
|
||||
public CommandMenuItemTargetAdapter,
|
||||
public UIDescriptionListenerAdapter,
|
||||
public IUIUndoManagerListener,
|
||||
public IUITemplateControllerListener
|
||||
{
|
||||
public:
|
||||
UIEditController (UIDescription* description);
|
||||
void setDarkTheme (bool state); // must be called before createEditView
|
||||
bool usesDarkTheme () const;
|
||||
CView* createEditView ();
|
||||
UIEditMenuController* getMenuController () const { return menuController; }
|
||||
UIUndoManager* getUndoManager () const { return undoManager; }
|
||||
const std::string& getEditTemplateName () const { return editTemplateName; }
|
||||
SharedPointer<UIAttributes> getSettings ();
|
||||
int32_t getSaveOptions ();
|
||||
|
||||
void onZoomChanged (double zoom);
|
||||
|
||||
void addSelectionToCurrentView (UISelection* selection);
|
||||
|
||||
static SharedPointer<UIDescription> getEditorDescription ();
|
||||
static void setupDataSource (GenericStringListDataBrowserSource* source);
|
||||
static bool std__stringCompare (const std::string* lhs, const std::string* rhs);
|
||||
static const UTF8StringPtr kEncodeBitmapsSettingsKey;
|
||||
static const UTF8StringPtr kWriteWindowsRCFileSettingsKey;
|
||||
protected:
|
||||
~UIEditController () override;
|
||||
|
||||
static void resetScrollViewOffsets (CViewContainer* view);
|
||||
|
||||
int32_t getSplitViewIndex (CSplitView* splitView);
|
||||
void setDirty (bool state);
|
||||
|
||||
void valueChanged (CControl* pControl) override;
|
||||
CView* createView (const UIAttributes& attributes, const IUIDescription* description) override;
|
||||
CView* verifyView (CView* view, const UIAttributes& attributes, const IUIDescription* description) override;
|
||||
IController* createSubController (UTF8StringPtr name, const IUIDescription* description) override;
|
||||
|
||||
CMessageResult notify (CBaseObject* sender, IdStringPtr message) override;
|
||||
|
||||
// IUITemplateControllerListener
|
||||
void onTemplateSelectionChanged () override;
|
||||
|
||||
// IUIUndoManagerListener
|
||||
void onUndoManagerChange () override;
|
||||
|
||||
// IContextMenuController2
|
||||
void appendContextMenuItems (COptionMenu& contextMenu, CView* view, const CPoint& where) override;
|
||||
|
||||
// ISplitViewController
|
||||
bool getSplitViewSizeConstraint (int32_t index, CCoord& minSize, CCoord& maxSize, CSplitView* splitView) override;
|
||||
ISplitViewSeparatorDrawer* getSplitViewSeparatorDrawer (CSplitView* splitView) override;
|
||||
bool storeViewSize (int32_t index, const CCoord& size, CSplitView* splitView) override;
|
||||
bool restoreViewSize (int32_t index, CCoord& size, CSplitView* splitView) override;
|
||||
|
||||
// ISplitViewSeparatorDrawer
|
||||
void drawSplitViewSeparator (CDrawContext* context, const CRect& size, int32_t flags, int32_t index, CSplitView* splitView) override;
|
||||
|
||||
// IActionPerformer
|
||||
void performAction (IAction* action) override;
|
||||
void performColorChange (UTF8StringPtr colorName, const CColor& newColor, bool remove = false) override;
|
||||
void performTagChange (UTF8StringPtr tagName, UTF8StringPtr tagString, bool remove = false) override;
|
||||
void performBitmapChange (UTF8StringPtr bitmapName, UTF8StringPtr bitmapPath, bool remove = false) override;
|
||||
void performGradientChange (UTF8StringPtr gradientName, CGradient* newGradient, bool remove = false) override;
|
||||
void performFontChange (UTF8StringPtr fontName, CFontRef newFont, bool remove = false) override;
|
||||
void performColorNameChange (UTF8StringPtr oldName, UTF8StringPtr newName) override;
|
||||
void performTagNameChange (UTF8StringPtr oldName, UTF8StringPtr newName) override;
|
||||
void performFontNameChange (UTF8StringPtr oldName, UTF8StringPtr newName) override;
|
||||
void performGradientNameChange (UTF8StringPtr oldName, UTF8StringPtr newName) override;
|
||||
void performBitmapNameChange (UTF8StringPtr oldName, UTF8StringPtr newName) override;
|
||||
void performBitmapMultiFrameChange (UTF8StringPtr bitmapName,
|
||||
const CMultiFrameBitmapDescription* desc) override;
|
||||
void performBitmapNinePartTiledChange (UTF8StringPtr bitmapName, const CRect* offsets) override;
|
||||
void performBitmapFiltersChange (UTF8StringPtr bitmapName, const std::list<SharedPointer<UIAttributes> >& filterDescription) override;
|
||||
void performAlternativeFontChange (UTF8StringPtr fontName, UTF8StringPtr newAlternativeFonts) override;
|
||||
|
||||
void beginLiveColorChange (UTF8StringPtr colorName) override;
|
||||
void performLiveColorChange (UTF8StringPtr colorName, const CColor& newColor) override;
|
||||
void endLiveColorChange (UTF8StringPtr colorName) override;
|
||||
|
||||
void performTemplateNameChange (UTF8StringPtr oldName, UTF8StringPtr newName) override;
|
||||
void performTemplateMinMaxSizeChange (UTF8StringPtr templateName, CPoint minSize, CPoint maxSize) override;
|
||||
void performCreateNewTemplate (UTF8StringPtr name, UTF8StringPtr baseViewClassName) override;
|
||||
void performDeleteTemplate (UTF8StringPtr name) override;
|
||||
void performDuplicateTemplate (UTF8StringPtr name, UTF8StringPtr dupName) override;
|
||||
|
||||
void onTemplateCreation (UTF8StringPtr name, CView* view) override;
|
||||
void onTemplateNameChange (UTF8StringPtr oldName, UTF8StringPtr newName) override;
|
||||
|
||||
void performChangeFocusDrawingSettings (const FocusDrawingSettings& newSettings) override;
|
||||
|
||||
void beginGroupAction (UTF8StringPtr name) override;
|
||||
void finishGroupAction () override;
|
||||
|
||||
// IKeyboardHook
|
||||
void onKeyboardEvent (KeyboardEvent& event, CFrame* frame) override;
|
||||
|
||||
// CommandMenuItemTargetAdapter
|
||||
bool validateCommandMenuItem (CCommandMenuItem* item) override;
|
||||
bool onCommandMenuItemSelected (CCommandMenuItem* item) override;
|
||||
|
||||
SharedPointer<UIDescription> editDescription;
|
||||
SharedPointer<UIDescription> editorDesc;
|
||||
SharedPointer<UISelection> selection;
|
||||
SharedPointer<UIUndoManager> undoManager;
|
||||
SharedPointer<UIGridController> gridController;
|
||||
CView* baseView {nullptr};
|
||||
UIEditView* editView {nullptr};
|
||||
SharedPointer<UITemplateController> templateController;
|
||||
SharedPointer<UIEditMenuController> menuController;
|
||||
SharedPointer<UIZoomSettingController> zoomSettingController;
|
||||
SharedPointer<CControl> enableEditingControl;
|
||||
SharedPointer<CControl> notSavedControl;
|
||||
SharedPointer<CControl> tabSwitchControl;
|
||||
|
||||
std::string editTemplateName;
|
||||
std::list<SharedPointer<CSplitView> > splitViews;
|
||||
|
||||
bool dirty;
|
||||
|
||||
struct Template {
|
||||
std::string name;
|
||||
SharedPointer<CView> view;
|
||||
|
||||
Template (const std::string& n, CView* v) : name (n), view (v) {}
|
||||
Template (const Template& c) : name (c.name), view (c.view) {}
|
||||
bool operator==(const Template& t) { return name == t.name && view == t.view; }
|
||||
bool operator==(const std::string& n) { return name == n; }
|
||||
Template& operator=(const Template& t) { name = t.name; view = t.view; return *this; }
|
||||
Template (Template&& t) noexcept { *this = std::move (t); }
|
||||
Template& operator=(Template&& t) noexcept { name = std::move (t.name); view = std::move (t.view); return *this; }
|
||||
};
|
||||
void updateTemplate (UTF8StringPtr name);
|
||||
void updateTemplate (const std::vector<Template>::const_iterator& it);
|
||||
void onTemplatesChanged ();
|
||||
void getTemplateViews (std::list<CView*>& views) const;
|
||||
|
||||
std::vector<Template> templates;
|
||||
private:
|
||||
void beforeUIDescSave (UIDescription* desc) override;
|
||||
void onUIDescTemplateChanged (UIDescription* desc) override;
|
||||
bool doUIDescTemplateUpdate (UIDescription* desc, UTF8StringPtr name) override;
|
||||
|
||||
void beforeSave ();
|
||||
CMessageResult validateMenuItem (CCommandMenuItem* item);
|
||||
CMessageResult onMenuItemSelection (CCommandMenuItem* item);
|
||||
void doCopy (bool cut = false);
|
||||
void doPaste ();
|
||||
void showTemplateSettings ();
|
||||
void showFocusSettings ();
|
||||
bool doSelectionMove (const UTF8String& commandName, bool useGrid) const;
|
||||
bool doSelectionSize (const UTF8String& commandName, bool useGrid) const;
|
||||
bool doZOrderAction (bool lower);
|
||||
void doSelectAllChildren ();
|
||||
void doSelectParents ();
|
||||
void doSelectViewInHierarchyBrowser (CView* view);
|
||||
void doChangeTheme (bool dark);
|
||||
|
||||
void onUndoManagerChanged ();
|
||||
template<typename NameChangeAction, IViewCreator::AttrType attrType> void performNameChange (UTF8StringPtr oldName, UTF8StringPtr newName, IdStringPtr groupActionName);
|
||||
|
||||
std::string onlyTemplateToUpdateName;
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
|
||||
#endif // VSTGUI_LIVE_EDITING
|
||||
@@ -0,0 +1,806 @@
|
||||
// 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 "uieditmenucontroller.h"
|
||||
|
||||
#if VSTGUI_LIVE_EDITING
|
||||
|
||||
#include "uiactions.h"
|
||||
#include "uieditview.h"
|
||||
#include "uieditcontroller.h"
|
||||
#include "../iviewfactory.h"
|
||||
#include "../uiattributes.h"
|
||||
#include "../../lib/cvstguitimer.h"
|
||||
#include "../../lib/events.h"
|
||||
#include "../../lib/controls/coptionmenu.h"
|
||||
#include "../../lib/controls/ctextlabel.h"
|
||||
#include "../detail/uiviewcreatorattributes.h"
|
||||
#include <cctype>
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
UIEditMenuController::UIEditMenuController (IController* baseController, UISelection* selection, UIUndoManager* undoManager, UIDescription* description, IActionPerformer* actionPerformer)
|
||||
: DelegationController (baseController)
|
||||
, selection (selection)
|
||||
, undoManager (undoManager)
|
||||
, description (description)
|
||||
, actionPerformer (actionPerformer)
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
UIEditMenuController::~UIEditMenuController () noexcept
|
||||
{
|
||||
if (editMenu)
|
||||
editMenu->unregisterViewListener (this);
|
||||
if (fileMenu)
|
||||
fileMenu->unregisterViewListener (this);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
static void addEntriesToMenu (const UIEditing::MenuEntry* entries, COptionMenu* menu, ICommandMenuItemTarget* menuItemTarget, int32_t& index)
|
||||
{
|
||||
while (entries[index].category != nullptr)
|
||||
{
|
||||
if (entries[index].menuFlags & UIEditing::MenuEntry::kSubMenuEnd)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (entries[index].category == UIEditing::kMenuSeparator.category)
|
||||
menu->addSeparator ();
|
||||
else if (entries[index].menuFlags & UIEditing::MenuEntry::kSubMenu)
|
||||
{
|
||||
auto subMenu = makeOwned<COptionMenu> ();
|
||||
if (entries[index].menuFlags & UIEditing::MenuEntry::kSubMenuCheckStyle)
|
||||
subMenu->setStyle (COptionMenu::kMultipleCheckStyle|COptionMenu::kCheckStyle);
|
||||
menu->addEntry (new CMenuItem (entries[index].name, subMenu));
|
||||
index++;
|
||||
addEntriesToMenu(entries, subMenu, menuItemTarget, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
CMenuItem* item = menu->addEntry (new CCommandMenuItem ({entries[index].name, menuItemTarget, entries[index].category, entries[index].name}));
|
||||
if (entries[index].key)
|
||||
{
|
||||
item->setKey (entries[index].key, entries[index].modifier);
|
||||
}
|
||||
else if (entries[index].virtualKey != VirtualKey::None)
|
||||
{
|
||||
item->setVirtualKey (entries[index].virtualKey, entries[index].modifier);
|
||||
}
|
||||
if (entries[index].menuFlags)
|
||||
{
|
||||
if (entries[index].menuFlags & UIEditing::MenuEntry::kMenuItemIsTitle)
|
||||
{
|
||||
item->setIsTitle (true);
|
||||
}
|
||||
}
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIEditMenuController::createFileMenu (COptionMenu* menu)
|
||||
{
|
||||
int32_t index = 0;
|
||||
addEntriesToMenu (UIEditing::fileMenu, menu, this, index);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIEditMenuController::createEditMenu (COptionMenu* menu)
|
||||
{
|
||||
int32_t index = 0;
|
||||
menu->setStyle (menu->getStyle () | COptionMenu::kMultipleCheckStyle);
|
||||
addEntriesToMenu (UIEditing::editMenu, menu, this, index);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool UIEditMenuController::createUniqueTemplateName (std::list<const std::string*>& names, std::string& name)
|
||||
{
|
||||
for (auto& it : names)
|
||||
{
|
||||
if (*it == name)
|
||||
{
|
||||
int32_t count = 0;
|
||||
size_t pos = name.find_last_not_of ("0123456789");
|
||||
if (pos != std::string::npos && pos != name.length () - 1)
|
||||
{
|
||||
std::string numberStr = name.substr (pos);
|
||||
count = static_cast<int32_t> (strtol (numberStr.c_str (), nullptr, 10)) + 1;
|
||||
name.erase (pos+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
count = 1;
|
||||
}
|
||||
while (name.length () && std::isspace (name[name.length ()-1]))
|
||||
name.erase (name.length ()-1);
|
||||
char number[10];
|
||||
snprintf (number, 10, "%d", count);
|
||||
name += ' ';
|
||||
name += number;
|
||||
return createUniqueTemplateName (names, name);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool UIEditMenuController::validateCommandMenuItem (CCommandMenuItem* item)
|
||||
{
|
||||
return validateMenuItem (*item);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool UIEditMenuController::onCommandMenuItemSelected (CCommandMenuItem* item)
|
||||
{
|
||||
return handleCommand (item->getCommandCategory (), item->getCommandName ());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
CMessageResult UIEditMenuController::notify (CBaseObject* sender, IdStringPtr message)
|
||||
{
|
||||
if (message == CVSTGUITimer::kMsgTimer)
|
||||
{
|
||||
editLabel->setTransparency (true);
|
||||
fileLabel->setTransparency (true);
|
||||
highlightTimer = nullptr;
|
||||
}
|
||||
return kMessageUnknown;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool UIEditMenuController::validateMenuItem (CCommandMenuItem& item)
|
||||
{
|
||||
UTF8StringView cmdCategory (item.getCommandCategory ());
|
||||
UTF8StringView cmdName (item.getCommandName ());
|
||||
item.setChecked (false);
|
||||
if (cmdCategory == "Edit")
|
||||
{
|
||||
if (cmdName == "Undo")
|
||||
{
|
||||
if (undoManager->canUndo ())
|
||||
{
|
||||
std::string str ("Undo ");
|
||||
str += undoManager->getUndoName ();
|
||||
item.setTitle (str.c_str ());
|
||||
item.setEnabled (true);
|
||||
}
|
||||
else
|
||||
{
|
||||
item.setTitle ("Undo");
|
||||
item.setEnabled (false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (cmdName == "Redo")
|
||||
{
|
||||
if (undoManager->canRedo ())
|
||||
{
|
||||
std::string str ("Redo ");
|
||||
str += undoManager->getRedoName ();
|
||||
item.setTitle (str.c_str ());
|
||||
item.setEnabled (true);
|
||||
}
|
||||
else
|
||||
{
|
||||
item.setTitle ("Redo");
|
||||
item.setEnabled (false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (cmdName == "Cut")
|
||||
{
|
||||
item.setEnabled (false);
|
||||
}
|
||||
else if (cmdName == "Copy")
|
||||
{
|
||||
item.setEnabled (false);
|
||||
}
|
||||
else if (cmdName == "Paste")
|
||||
{
|
||||
item.setEnabled (false);
|
||||
}
|
||||
else if (cmdName == "Delete")
|
||||
{
|
||||
CView* view = selection->first ();
|
||||
int32_t selectionCount = selection->total ();
|
||||
bool enable = view ? (selectionCount > 1 ? true : dynamic_cast<UIEditView*> (view->getParentView ()) == nullptr) : false;
|
||||
item.setEnabled (enable);
|
||||
return true;
|
||||
}
|
||||
else if (cmdName == "Add New Template")
|
||||
{
|
||||
if (const auto* factory = dynamic_cast<const IViewFactoryEditingSupport*> (
|
||||
description->getViewFactory ()))
|
||||
{
|
||||
auto submenu = makeOwned<COptionMenu> ();
|
||||
auto viewAndDisplayNames =
|
||||
factory->collectRegisteredViewAndDisplayNames ("CViewContainer");
|
||||
viewAndDisplayNames.sort (
|
||||
[] (const auto& lhs, const auto& rhs) { return lhs.second < rhs.second; });
|
||||
for (auto& entry : viewAndDisplayNames)
|
||||
{
|
||||
submenu->addEntry (new CCommandMenuItem (CCommandMenuItem::Desc {
|
||||
entry.second.data (), this, "AddTemplate", entry.first->data ()}));
|
||||
}
|
||||
item.setSubmenu (submenu);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (cmdName == "Delete Template")
|
||||
{
|
||||
item.setSubmenu (nullptr);
|
||||
std::list<const std::string*> templateNames;
|
||||
description->collectTemplateViewNames (templateNames);
|
||||
item.setEnabled (templateNames.empty () == false);
|
||||
if (templateNames.empty () == false)
|
||||
{
|
||||
templateNames.sort (UIEditController::std__stringCompare);
|
||||
auto submenu = makeOwned<COptionMenu> ();
|
||||
item.setSubmenu (submenu);
|
||||
for (auto& name : templateNames)
|
||||
{
|
||||
submenu->addEntry (new CCommandMenuItem (CCommandMenuItem::Desc{name->data (), this, "RemoveTemplate", name->data ()}));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (cmdName == "Duplicate Template")
|
||||
{
|
||||
item.setSubmenu (nullptr);
|
||||
std::list<const std::string*> templateNames;
|
||||
description->collectTemplateViewNames (templateNames);
|
||||
item.setEnabled (templateNames.empty () == false);
|
||||
if (templateNames.empty () == false)
|
||||
{
|
||||
templateNames.sort (UIEditController::std__stringCompare);
|
||||
auto submenu = makeOwned<COptionMenu> ();
|
||||
item.setSubmenu (submenu);
|
||||
for (auto& name : templateNames)
|
||||
{
|
||||
submenu->addEntry (new CCommandMenuItem (CCommandMenuItem::Desc{name->data (), this, "DuplicateTemplate", name->data ()}));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (cmdName == "Embed Into")
|
||||
{
|
||||
item.setSubmenu (nullptr);
|
||||
bool enable = selection->total () > 0;
|
||||
for (auto view : *selection)
|
||||
{
|
||||
if (dynamic_cast<UIEditView*>(view->getParentView()) != nullptr)
|
||||
{
|
||||
enable = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
item.setEnabled (enable);
|
||||
if (enable == false)
|
||||
return true;
|
||||
if (const auto* factory = dynamic_cast<const IViewFactoryEditingSupport*> (
|
||||
description->getViewFactory ()))
|
||||
{
|
||||
auto submenu = makeOwned<COptionMenu> ();
|
||||
item.setSubmenu (submenu);
|
||||
auto viewAndDisplayNames =
|
||||
factory->collectRegisteredViewAndDisplayNames ("CViewContainer");
|
||||
viewAndDisplayNames.sort (
|
||||
[] (const auto& lhs, const auto& rhs) { return lhs.second < rhs.second; });
|
||||
for (auto& entry : viewAndDisplayNames)
|
||||
{
|
||||
submenu->addEntry (new CCommandMenuItem (CCommandMenuItem::Desc {
|
||||
entry.second.data (), this, "Embed", entry.first->data ()}));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (cmdName == "Unembed Views")
|
||||
{
|
||||
bool enabled = false;
|
||||
if (selection->total () == 1)
|
||||
{
|
||||
CViewContainer* container = selection->first ()->asViewContainer ();
|
||||
if (container && container->hasChildren () && dynamic_cast<UIEditView*>(container->getParentView ()) == nullptr)
|
||||
enabled = true;
|
||||
}
|
||||
item.setEnabled (enabled);
|
||||
return true;
|
||||
}
|
||||
else if (cmdName == "Size To Fit")
|
||||
{
|
||||
item.setEnabled (selection->total() > 0 ? true : false);
|
||||
return true;
|
||||
}
|
||||
else if (cmdName == "Transform View Type")
|
||||
{
|
||||
item.setSubmenu (nullptr);
|
||||
auto numViewContainers = 0u;
|
||||
auto numNonViewContainers = 0u;
|
||||
for (auto& entry : *selection)
|
||||
{
|
||||
if (entry->asViewContainer ())
|
||||
++numViewContainers;
|
||||
else
|
||||
++numNonViewContainers;
|
||||
}
|
||||
if (numViewContainers != 0 && numNonViewContainers != 0)
|
||||
{
|
||||
item.setEnabled (false);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (const auto* factory = dynamic_cast<const IViewFactoryEditingSupport*> (
|
||||
description->getViewFactory ()))
|
||||
{
|
||||
auto submenu = makeOwned<COptionMenu> ();
|
||||
item.setSubmenu (submenu);
|
||||
auto viewAndDisplayNames = factory->collectRegisteredViewAndDisplayNames ();
|
||||
viewAndDisplayNames.sort (
|
||||
[] (const auto& lhs, const auto& rhs) { return lhs.second < rhs.second; });
|
||||
for (auto& entry : viewAndDisplayNames)
|
||||
{
|
||||
submenu->addEntry (new CCommandMenuItem (CCommandMenuItem::Desc {
|
||||
entry.second.data (), this, "Transform View Type", entry.first->data ()}));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (cmdName == "Insert Template")
|
||||
{
|
||||
item.setSubmenu (nullptr);
|
||||
item.setEnabled (selection->total () == 1 && selection->first ()->asViewContainer ());
|
||||
if (item.isEnabled () == false)
|
||||
return true;
|
||||
std::list<const std::string*> templateNames;
|
||||
description->collectTemplateViewNames (templateNames);
|
||||
item.setEnabled (templateNames.empty () == false);
|
||||
if (templateNames.empty () == false)
|
||||
{
|
||||
templateNames.sort (UIEditController::std__stringCompare);
|
||||
auto submenu = makeOwned<COptionMenu> ();
|
||||
item.setSubmenu (submenu);
|
||||
for (auto& name : templateNames)
|
||||
{
|
||||
submenu->addEntry (new CCommandMenuItem (CCommandMenuItem::Desc{name->data (), this, "InsertTemplate", name->data ()}));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (cmdCategory == "Selection")
|
||||
{
|
||||
if (cmdName == "Select Children Of Type")
|
||||
{
|
||||
if (const auto* factory = dynamic_cast<const IViewFactoryEditingSupport*> (
|
||||
description->getViewFactory ()))
|
||||
{
|
||||
auto submenu = makeOwned<COptionMenu> ();
|
||||
item.setSubmenu (submenu);
|
||||
auto viewAndDisplayNames = factory->collectRegisteredViewAndDisplayNames ();
|
||||
viewAndDisplayNames.sort (
|
||||
[] (const auto& lhs, const auto& rhs) { return lhs.second < rhs.second; });
|
||||
for (auto& entry : viewAndDisplayNames)
|
||||
{
|
||||
submenu->addEntry (new CCommandMenuItem (
|
||||
CCommandMenuItem::Desc {entry.second.data (), this,
|
||||
"Select Children Of Type", entry.first->data ()}));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (auto obj = dynamic_cast<ICommandMenuItemTarget*> (controller))
|
||||
return obj->validateCommandMenuItem (&item);
|
||||
return false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
CCommandMenuItem* UIEditMenuController::findKeyCommandItem (COptionMenu* menu, const KeyboardEvent& event)
|
||||
{
|
||||
for (auto& item : *menu->getItems ())
|
||||
{
|
||||
COptionMenu* subMenu = item->getSubmenu ();
|
||||
if (subMenu)
|
||||
{
|
||||
CCommandMenuItem* result = findKeyCommandItem (subMenu, event);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
CCommandMenuItem* result = item.cast<CCommandMenuItem>();
|
||||
if (result)
|
||||
{
|
||||
int32_t modifier = 0;
|
||||
if (event.modifiers.has (ModifierKey::Shift))
|
||||
modifier |= kShift;
|
||||
if (event.modifiers.has (ModifierKey::Alt))
|
||||
modifier |= kAlt;
|
||||
if (event.modifiers.has (ModifierKey::Control))
|
||||
modifier |= kControl;
|
||||
if (event.modifiers.has (ModifierKey::Super))
|
||||
modifier |= kApple;
|
||||
if (result->getKeyModifiers () == modifier)
|
||||
{
|
||||
if (event.virt != VirtualKey::None && event.virt == result->getVirtualKey ())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else if (!result->getKeycode ().empty () &&
|
||||
static_cast<char32_t> (result->getKeycode ().getString ()[0]) ==
|
||||
event.character)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool UIEditMenuController::handleCommand (const UTF8StringPtr category, const UTF8StringPtr name)
|
||||
{
|
||||
UTF8StringView cmdCategory (category);
|
||||
UTF8StringView cmdName (name);
|
||||
if (cmdCategory == "Edit")
|
||||
{
|
||||
if (cmdName == "Undo")
|
||||
{
|
||||
if (undoManager->canUndo ())
|
||||
{
|
||||
undoManager->performUndo ();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (cmdName == "Redo")
|
||||
{
|
||||
if (undoManager->canRedo ())
|
||||
{
|
||||
undoManager->performRedo ();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (cmdName == "Delete")
|
||||
{
|
||||
IAction* action = new DeleteOperation (selection);
|
||||
undoManager->pushAndPerform (action);
|
||||
return true;
|
||||
}
|
||||
else if (cmdName == "Unembed Views")
|
||||
{
|
||||
IAction* action = new UnembedViewOperation (selection, description->getViewFactory ());
|
||||
undoManager->pushAndPerform (action);
|
||||
return true;
|
||||
}
|
||||
else if (cmdName == "Size To Fit")
|
||||
{
|
||||
IAction* action = new SizeToFitOperation (selection);
|
||||
undoManager->pushAndPerform (action);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (cmdCategory == "AddTemplate")
|
||||
{
|
||||
std::list<const std::string*> tmp;
|
||||
description->collectTemplateViewNames (tmp);
|
||||
std::string templateName (cmdName);
|
||||
if (createUniqueTemplateName (tmp, templateName))
|
||||
{
|
||||
actionPerformer->performCreateNewTemplate (templateName.c_str (), cmdName);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (cmdCategory == "RemoveTemplate")
|
||||
{
|
||||
actionPerformer->performDeleteTemplate (cmdName);
|
||||
return kMessageNotified;
|
||||
}
|
||||
else if (cmdCategory == "DuplicateTemplate")
|
||||
{
|
||||
std::list<const std::string*> tmp;
|
||||
description->collectTemplateViewNames (tmp);
|
||||
std::string templateName (cmdName);
|
||||
if (createUniqueTemplateName (tmp, templateName))
|
||||
{
|
||||
actionPerformer->performDuplicateTemplate (cmdName, templateName.c_str ());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (cmdCategory == "Embed")
|
||||
{
|
||||
const IViewFactory* viewFactory = description->getViewFactory ();
|
||||
UIAttributes viewAttr;
|
||||
viewAttr.setAttribute (UIViewCreator::kAttrClass, std::string (cmdName));
|
||||
if (auto newContainer = viewFactory->createView (viewAttr, description)->asViewContainer ())
|
||||
{
|
||||
IAction* action = new EmbedViewOperation (selection, newContainer);
|
||||
undoManager->pushAndPerform (action);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (cmdCategory == "Transform View Type")
|
||||
{
|
||||
undoManager->startGroupAction ("Transform View Type");
|
||||
for (auto& entry : *selection)
|
||||
{
|
||||
IAction* action = new TransformViewTypeOperation (
|
||||
selection, entry, cmdName, description, description->getViewFactory ());
|
||||
undoManager->pushAndPerform (action);
|
||||
}
|
||||
undoManager->endGroupAction ();
|
||||
return true;
|
||||
}
|
||||
else if (cmdCategory == "Select Children Of Type")
|
||||
{
|
||||
const auto* viewFactory = description->getViewFactory ();
|
||||
if (!viewFactory)
|
||||
return false;
|
||||
std::vector<CView*> newSelection;
|
||||
for (auto& entry : *selection)
|
||||
{
|
||||
if (auto viewContainer = entry->asViewContainer ())
|
||||
getChildrenOfType (viewContainer, cmdName, newSelection);
|
||||
}
|
||||
selection->clear ();
|
||||
for (auto& view : newSelection)
|
||||
selection->add (view);
|
||||
return true;
|
||||
}
|
||||
else if (cmdCategory == "InsertTemplate")
|
||||
{
|
||||
if (auto parent = selection->first ()->asViewContainer ())
|
||||
{
|
||||
CView* view = description->createView (cmdName, description->getController ());
|
||||
if (view)
|
||||
{
|
||||
undoManager->pushAndPerform (new InsertViewOperation (parent, view, selection));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (auto obj = dynamic_cast<ICommandMenuItemTarget*> (controller))
|
||||
{
|
||||
CCommandMenuItem item (CCommandMenuItem::Desc{"", 0, nullptr, category, name});
|
||||
if (obj->onCommandMenuItemSelected (&item))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool UIEditMenuController::canHandleCommand (const UTF8StringPtr category, const UTF8StringPtr name) const
|
||||
{
|
||||
CCommandMenuItem item (CCommandMenuItem::Desc{"", 0, nullptr, category, name});
|
||||
if (const_cast<UIEditMenuController*> (this)->validateMenuItem (item))
|
||||
{
|
||||
return item.isEnabled ();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIEditMenuController::processKeyCommand (KeyboardEvent& event)
|
||||
{
|
||||
COptionMenu* baseMenu = editMenu;
|
||||
CCommandMenuItem* item = baseMenu ? findKeyCommandItem (baseMenu, event) : nullptr;
|
||||
if (item == nullptr && fileMenu)
|
||||
{
|
||||
baseMenu = fileMenu;
|
||||
item = findKeyCommandItem (baseMenu, event);
|
||||
}
|
||||
if (item && item->getItemTarget ())
|
||||
{
|
||||
item->getItemTarget ()->validateCommandMenuItem (item);
|
||||
if (item->isEnabled ())
|
||||
{
|
||||
CTextLabel* label = nullptr;
|
||||
if (baseMenu)
|
||||
{
|
||||
switch (baseMenu->getTag ())
|
||||
{
|
||||
case kMenuFileTag:
|
||||
{
|
||||
label = fileLabel;
|
||||
break;
|
||||
}
|
||||
case kMenuEditTag:
|
||||
{
|
||||
label = editLabel;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (label)
|
||||
{
|
||||
label->setTransparency (false);
|
||||
}
|
||||
item->getItemTarget ()->onCommandMenuItemSelected (item);
|
||||
if (label)
|
||||
{
|
||||
highlightTimer = makeOwned<CVSTGUITimer> (this, 90u, true);
|
||||
}
|
||||
event.consumed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
static void copyMenuItems (COptionMenu* src, COptionMenu* dst)
|
||||
{
|
||||
auto srcItems = src->getItems ();
|
||||
if (!srcItems)
|
||||
return;
|
||||
for (auto& item : *srcItems)
|
||||
{
|
||||
item->remember ();
|
||||
dst->addEntry (item);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void UIEditMenuController::viewRemoved (CView* view)
|
||||
{
|
||||
if (view == editMenu)
|
||||
{
|
||||
view->unregisterViewListener (this);
|
||||
editMenu = nullptr;
|
||||
}
|
||||
else if (view == fileMenu)
|
||||
{
|
||||
view->unregisterViewListener (this);
|
||||
fileMenu = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
CView* UIEditMenuController::verifyView (CView* view, const UIAttributes& attributes, const IUIDescription*)
|
||||
{
|
||||
COptionMenu* menu = dynamic_cast<COptionMenu*>(view);
|
||||
if (menu)
|
||||
{
|
||||
switch (menu->getTag ())
|
||||
{
|
||||
case kMenuEditTag:
|
||||
{
|
||||
if (editMenu)
|
||||
copyMenuItems (editMenu, menu);
|
||||
else
|
||||
{
|
||||
createEditMenu (menu);
|
||||
menu->registerViewListener (this);
|
||||
}
|
||||
editMenu = menu;
|
||||
break;
|
||||
}
|
||||
case kMenuFileTag:
|
||||
{
|
||||
if (fileMenu)
|
||||
copyMenuItems (fileMenu, menu);
|
||||
else
|
||||
{
|
||||
createFileMenu (menu);
|
||||
menu->registerViewListener (this);
|
||||
}
|
||||
fileMenu = menu;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CTextLabel* label = dynamic_cast<CTextLabel*>(view);
|
||||
if (label)
|
||||
{
|
||||
switch (label->getTag ())
|
||||
{
|
||||
case kMenuEditTag:
|
||||
{
|
||||
editLabel = label;
|
||||
break;
|
||||
}
|
||||
case kMenuFileTag:
|
||||
{
|
||||
fileLabel = label;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIEditMenuController::valueChanged (CControl* control)
|
||||
{
|
||||
switch (control->getTag ())
|
||||
{
|
||||
case kMenuFileTag:
|
||||
{
|
||||
if (fileMenu && control->getValue () == control->getMax ())
|
||||
{
|
||||
CRect r (control->getViewSize ());
|
||||
CPoint p = r.getBottomLeft ();
|
||||
control->localToFrame (p);
|
||||
fileMenu->popup (control->getFrame (), p);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kMenuEditTag:
|
||||
{
|
||||
if (editMenu && control->getValue () == control->getMax ())
|
||||
{
|
||||
CRect r (control->getViewSize ());
|
||||
CPoint p = r.getTopLeft ();
|
||||
control->localToFrame (p);
|
||||
editMenu->popup (control->getFrame (), p);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIEditMenuController::controlBeginEdit (CControl* pControl)
|
||||
{
|
||||
CTextLabel* label = nullptr;
|
||||
switch (pControl->getTag ())
|
||||
{
|
||||
case kMenuFileTag:
|
||||
{
|
||||
fileMenu->cleanupSeparators (true);
|
||||
label = fileLabel;
|
||||
break;
|
||||
}
|
||||
case kMenuEditTag:
|
||||
{
|
||||
editMenu->cleanupSeparators (true);
|
||||
label = editLabel;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (label)
|
||||
label->setTransparency (false);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIEditMenuController::controlEndEdit (CControl* pControl)
|
||||
{
|
||||
CTextLabel* label = nullptr;
|
||||
switch (pControl->getTag ())
|
||||
{
|
||||
case kMenuFileTag:
|
||||
{
|
||||
label = fileLabel;
|
||||
break;
|
||||
}
|
||||
case kMenuEditTag:
|
||||
{
|
||||
label = editLabel;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (label)
|
||||
label->setTransparency (true);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void UIEditMenuController::getChildrenOfType (CViewContainer* container, UTF8StringView type, std::vector<CView*>& result) const
|
||||
{
|
||||
container->forEachChild ([&] (auto view) {
|
||||
if (type == IViewFactory::getViewName (view))
|
||||
result.emplace_back (view);
|
||||
if (auto c = view->asViewContainer ())
|
||||
{
|
||||
getChildrenOfType (c, type, result);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // VSTGUI
|
||||
|
||||
#endif // VSTGUI_LIVE_EDITING
|
||||
@@ -0,0 +1,204 @@
|
||||
// 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 "../uidescription.h"
|
||||
|
||||
#if VSTGUI_LIVE_EDITING
|
||||
|
||||
#include "uiselection.h"
|
||||
#include "uiundomanager.h"
|
||||
#include "../delegationcontroller.h"
|
||||
#include "../../lib/controls/icommandmenuitemtarget.h"
|
||||
#include "../../lib/events.h"
|
||||
#include "../../lib/iviewlistener.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
class IActionPerformer;
|
||||
|
||||
namespace UIEditing {
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
struct MenuEntry {
|
||||
UTF8StringPtr category {nullptr};
|
||||
UTF8StringPtr name {nullptr};
|
||||
UTF8StringPtr key {nullptr};
|
||||
int32_t modifier {0};
|
||||
VirtualKey virtualKey {VirtualKey::None};
|
||||
int32_t menuFlags {0};
|
||||
|
||||
enum {
|
||||
kSubMenu = (1 << 0),
|
||||
kSubMenuEnd = (1 << 1),
|
||||
kSubMenuCheckStyle = (1 << 2),
|
||||
kMenuItemIsTitle = (1 << 3)
|
||||
};
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1910 // Can be removed when dropping VS 2015 Support
|
||||
MenuEntry (UTF8StringPtr s1 = nullptr, UTF8StringPtr s2 = nullptr, UTF8StringPtr s3 = nullptr,
|
||||
int32_t i1 = 0, int32_t i2 = 0, int32_t i3 = 0)
|
||||
: category (s1), name (s2), key (s3), modifier (i1), virtualKey (i2), menuFlags (i3)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
static const MenuEntry kMenuSeparator = { "Separator", 0, 0, 0, VirtualKey::None };
|
||||
static const MenuEntry kSubMenuEnd = { 0, 0 , 0, 0, VirtualKey::None, MenuEntry::kSubMenuEnd };
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
static const MenuEntry editMenu[] = {
|
||||
{"Edit", "Undo", "z", kControl},
|
||||
{"Edit", "Redo", "z", kControl | kShift},
|
||||
kMenuSeparator,
|
||||
{"Edit", "Cut", "x", kControl},
|
||||
{"Edit", "Copy", "c", kControl},
|
||||
{"Edit", "Paste", "v", kControl},
|
||||
{"Edit", "Delete", 0, kControl, VirtualKey::Back},
|
||||
kMenuSeparator,
|
||||
{"Edit", "Selection", 0, 0, VirtualKey::None, MenuEntry::kSubMenu},
|
||||
|
||||
{"Selection", "Move", 0, 0, VirtualKey::None, MenuEntry::kSubMenu},
|
||||
{"", "By Grid", 0, 0, VirtualKey::None, MenuEntry::kMenuItemIsTitle},
|
||||
kMenuSeparator,
|
||||
{"SelectionMoveByGrid", "Move Up", 0, kControl, VirtualKey::Up},
|
||||
{"SelectionMoveByGrid", "Move Down", 0, kControl, VirtualKey::Down},
|
||||
{"SelectionMoveByGrid", "Move Left", 0, kControl, VirtualKey::Left},
|
||||
{"SelectionMoveByGrid", "Move Right", 0, kControl, VirtualKey::Right},
|
||||
kMenuSeparator,
|
||||
{"", "By Pixel", 0, 0, VirtualKey::None, MenuEntry::kMenuItemIsTitle},
|
||||
kMenuSeparator,
|
||||
{"SelectionMoveByPixel", "Move Up", 0, kControl | kShift, VirtualKey::Up},
|
||||
{"SelectionMoveByPixel", "Move Down", 0, kControl | kShift, VirtualKey::Down},
|
||||
{"SelectionMoveByPixel", "Move Left", 0, kControl | kShift, VirtualKey::Left},
|
||||
{"SelectionMoveByPixel", "Move Right", 0, kControl | kShift, VirtualKey::Right},
|
||||
kSubMenuEnd,
|
||||
|
||||
{"Selection", "Size", 0, 0, VirtualKey::None, MenuEntry::kSubMenu},
|
||||
{"", "By Grid", 0, 0, VirtualKey::None, MenuEntry::kMenuItemIsTitle},
|
||||
kMenuSeparator,
|
||||
{"SelectionSizeByGrid", "Increase Size Width", 0, kControl | kAlt, VirtualKey::Right},
|
||||
{"SelectionSizeByGrid", "Increase Size Height", 0, kControl | kAlt, VirtualKey::Down},
|
||||
{"SelectionSizeByGrid", "Decrease Size Width", 0, kControl | kAlt, VirtualKey::Left},
|
||||
{"SelectionSizeByGrid", "Decrease Size Height", 0, kControl | kAlt, VirtualKey::Up},
|
||||
kMenuSeparator,
|
||||
{"", "By Pixel", 0, 0, VirtualKey::None, MenuEntry::kMenuItemIsTitle},
|
||||
kMenuSeparator,
|
||||
{"SelectionSizeByPixel", "Increase Size Width", 0, kControl | kAlt | kShift, VirtualKey::Right},
|
||||
{"SelectionSizeByPixel", "Increase Size Height", 0, kControl | kAlt | kShift, VirtualKey::Down},
|
||||
{"SelectionSizeByPixel", "Decrease Size Width", 0, kControl | kAlt | kShift, VirtualKey::Left},
|
||||
{"SelectionSizeByPixel", "Decrease Size Height", 0, kControl | kAlt | kShift, VirtualKey::Up},
|
||||
kSubMenuEnd,
|
||||
|
||||
{"Selection", "Z-Order", 0, 0, VirtualKey::None, MenuEntry::kSubMenu},
|
||||
{"SelectionZOrder", "Lower", 0, kAlt, VirtualKey::Up},
|
||||
{"SelectionZOrder", "Raise", 0, kAlt, VirtualKey::Down},
|
||||
kSubMenuEnd,
|
||||
kMenuSeparator,
|
||||
{"Selection", "Select Children Of Type", 0, 0, VirtualKey::None},
|
||||
kMenuSeparator,
|
||||
{"Selection", "Select Parent(s)", 0, 0, VirtualKey::None},
|
||||
{"Selection", "Select All Children", 0, 0, VirtualKey::None},
|
||||
kMenuSeparator,
|
||||
{"Selection", "Select View in Hierarchy Browser", 0, 0, VirtualKey::None},
|
||||
|
||||
kSubMenuEnd,
|
||||
kMenuSeparator,
|
||||
{"Zoom", "Zoom", 0, 0, VirtualKey::None, MenuEntry::kSubMenu},
|
||||
{"Zoom", "Zoom In", "=", kControl},
|
||||
{"Zoom", "Zoom Out", "-", kControl},
|
||||
kMenuSeparator,
|
||||
{"Zoom", "Zoom 100%", "0", kControl | kAlt},
|
||||
kSubMenuEnd,
|
||||
|
||||
kMenuSeparator,
|
||||
{"Edit", "Size To Fit", 0, 0, VirtualKey::None},
|
||||
{"Edit", "Unembed Views", 0, 0, VirtualKey::None},
|
||||
{"Edit", "Embed Into", 0, 0, VirtualKey::None},
|
||||
{"Edit", "Transform View Type", 0, 0, VirtualKey::None},
|
||||
{"Edit", "Insert Template", 0, 0, VirtualKey::None},
|
||||
kMenuSeparator,
|
||||
{"Edit", "Add New Template", 0, 0, VirtualKey::None},
|
||||
{"Edit", "Delete Template", 0, 0, VirtualKey::None},
|
||||
{"Edit", "Duplicate Template", 0, 0, VirtualKey::None},
|
||||
kMenuSeparator,
|
||||
{"Edit", "Template Settings...", 0, kControl, VirtualKey::Enter},
|
||||
{"Edit", "Focus Drawing Settings...", 0, 0, VirtualKey::None},
|
||||
kMenuSeparator,
|
||||
{"Edit", "Toggle UI Theme (Dark/Light)", 0, 0, VirtualKey::None},
|
||||
{0}};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
static const MenuEntry fileMenu[] = {
|
||||
{ "File", "Save Options" , 0, 0, VirtualKey::None, MenuEntry::kSubMenu|MenuEntry::kSubMenuCheckStyle },
|
||||
{ "File", "Encode Bitmaps in XML" , 0, 0, VirtualKey::None },
|
||||
{ "File", "Write Windows RC File on Save" , 0, 0, VirtualKey::None },
|
||||
kSubMenuEnd,
|
||||
kMenuSeparator,
|
||||
{0}
|
||||
};
|
||||
|
||||
} // UIEditing
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class UIEditMenuController : public CBaseObject,
|
||||
public DelegationController,
|
||||
public CommandMenuItemTargetAdapter,
|
||||
public ViewListenerAdapter
|
||||
{
|
||||
public:
|
||||
UIEditMenuController (IController* baseController, UISelection* selection, UIUndoManager* undoManager, UIDescription* description, IActionPerformer* actionPerformer);
|
||||
~UIEditMenuController () noexcept override;
|
||||
|
||||
COptionMenu* getFileMenu () const { return fileMenu; }
|
||||
COptionMenu* getEditMenu () const { return editMenu; }
|
||||
|
||||
void processKeyCommand (KeyboardEvent& event);
|
||||
bool handleCommand (const UTF8StringPtr category, const UTF8StringPtr name);
|
||||
bool canHandleCommand (const UTF8StringPtr category, const UTF8StringPtr name) const;
|
||||
|
||||
CMessageResult notify (CBaseObject* sender, IdStringPtr message) override;
|
||||
void valueChanged (CControl* pControl) override;
|
||||
|
||||
static bool createUniqueTemplateName (std::list<const std::string*>& names, std::string& name);
|
||||
protected:
|
||||
bool validateCommandMenuItem (CCommandMenuItem* item) override;
|
||||
bool onCommandMenuItemSelected (CCommandMenuItem* item) override;
|
||||
|
||||
bool validateMenuItem (CCommandMenuItem& item);
|
||||
CCommandMenuItem* findKeyCommandItem (COptionMenu* menu, const KeyboardEvent& event);
|
||||
void createEditMenu (COptionMenu* menu);
|
||||
void createFileMenu (COptionMenu* menu);
|
||||
|
||||
void viewRemoved (CView* view) override;
|
||||
CView* verifyView (CView* view, const UIAttributes& attributes, const IUIDescription* description) override;
|
||||
IControlListener* getControlListener (UTF8StringPtr name) override { return this; }
|
||||
void controlBeginEdit (CControl* pControl) override;
|
||||
void controlEndEdit (CControl* pControl) override;
|
||||
|
||||
void getChildrenOfType (CViewContainer* container, UTF8StringView type, std::vector<CView*>& result) const;
|
||||
|
||||
SharedPointer<UISelection> selection;
|
||||
SharedPointer<UIUndoManager> undoManager;
|
||||
SharedPointer<UIDescription> description;
|
||||
SharedPointer<CVSTGUITimer> highlightTimer;
|
||||
IActionPerformer* actionPerformer;
|
||||
|
||||
SharedPointer<COptionMenu> fileMenu;
|
||||
SharedPointer<COptionMenu> editMenu;
|
||||
SharedPointer<CTextLabel> fileLabel;
|
||||
SharedPointer<CTextLabel> editLabel;
|
||||
|
||||
enum {
|
||||
kMenuFileTag = 100,
|
||||
kMenuEditTag = 101
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
|
||||
#endif // VSTGUI_LIVE_EDITING
|
||||
@@ -0,0 +1,151 @@
|
||||
// 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 "../../lib/cviewcontainer.h"
|
||||
|
||||
#if VSTGUI_LIVE_EDITING
|
||||
|
||||
#include "../../lib/cbitmap.h"
|
||||
#include "../../lib/ccolor.h"
|
||||
#include "../../lib/dragging.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
class UIUndoManager;
|
||||
class UISelection;
|
||||
class UIDescription;
|
||||
class IUIDescription;
|
||||
class UICrossLines;
|
||||
class ViewSizeChangeOperation;
|
||||
class IGridProcessor;
|
||||
namespace UIEditViewInternal {
|
||||
class UIHighlightView;
|
||||
} // UIEditViewInternal
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class UIEditView : public CViewContainer, public IDropTarget
|
||||
{
|
||||
public:
|
||||
UIEditView (const CRect& size, UIDescription* uidescription);
|
||||
~UIEditView () override;
|
||||
|
||||
void enableEditing (bool state);
|
||||
void enableAutosizing (bool state);
|
||||
void setScale (double scale);
|
||||
|
||||
void setEditView (CView* view);
|
||||
CView* getEditView () const;
|
||||
|
||||
void doKeyMove (const CPoint& delta);
|
||||
void doKeySize (const CPoint& delta);
|
||||
|
||||
void setUndoManager (UIUndoManager* manager);
|
||||
UIUndoManager* getUndoManager ();
|
||||
|
||||
void setSelection (UISelection* selection);
|
||||
UISelection* getSelection ();
|
||||
|
||||
void setGridProcessor (IGridProcessor* grid);
|
||||
|
||||
void setupColors (const IUIDescription* description);
|
||||
|
||||
static IdStringPtr kMsgAttached;
|
||||
static IdStringPtr kMsgRemoved;
|
||||
protected:
|
||||
enum class MouseEditMode {
|
||||
NoEditing,
|
||||
DragEditing,
|
||||
SizeEditing,
|
||||
LassoSelection,
|
||||
WaitDrag,
|
||||
WaitLasso,
|
||||
};
|
||||
|
||||
enum class MouseSizeMode {
|
||||
None,
|
||||
BottomRight,
|
||||
BottomLeft,
|
||||
TopRight,
|
||||
TopLeft,
|
||||
Left,
|
||||
Right,
|
||||
Top,
|
||||
Bottom
|
||||
};
|
||||
|
||||
void updateSize ();
|
||||
void invalidSelection ();
|
||||
MouseSizeMode selectionHitTest (const CPoint& where, CView** resultView);
|
||||
bool hitTestSubViews (const CPoint& where, const Event& 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 onMouseExited (CPoint& where, const CButtonState& buttons) override;
|
||||
CMessageResult notify (CBaseObject* sender, IdStringPtr message) override;
|
||||
void onKeyboardEvent (KeyboardEvent& event) override;
|
||||
|
||||
std::vector<CView*> findChildsInArea (CViewContainer* view, CRect r) const;
|
||||
|
||||
void doDragEditingMove (CPoint& where);
|
||||
void doSizeEditingMove (CPoint& where);
|
||||
void onDoubleClickEditing (CView* view);
|
||||
|
||||
void startDrag (CPoint& where);
|
||||
SharedPointer<UISelection> getSelectionOutOfDrag (IDataPackage* drag) const;
|
||||
|
||||
SharedPointer<IDropTarget> getDropTarget () override;
|
||||
bool onDrop (DragEventData data) override;
|
||||
DragOperation onDragEnter (DragEventData data) override;
|
||||
void onDragLeave (DragEventData data) override;
|
||||
DragOperation onDragMove (DragEventData data) override;
|
||||
|
||||
void draw (CDrawContext *pContext) override;
|
||||
void drawRect (CDrawContext *pContext, const CRect& updateRect) override;
|
||||
CView* getViewAt (const CPoint& p, const GetViewOptions& options = GetViewOptions ()) const override;
|
||||
CViewContainer* getContainerAt (const CPoint& p, const GetViewOptions& options = GetViewOptions ().deep ()) const override;
|
||||
bool advanceNextFocusView (CView* oldFocus, bool reverse) override;
|
||||
void onMouseWheelEvent (MouseWheelEvent& event) override;
|
||||
void onZoomGestureEvent (ZoomGestureEvent& event) override;
|
||||
|
||||
void looseFocus () override;
|
||||
void takeFocus () override;
|
||||
bool removed (CView* parent) override;
|
||||
bool attached (CView* parent) override;
|
||||
|
||||
bool editing {true};
|
||||
bool autosizing {true};
|
||||
bool inlineAttrTextEditOpen {false};
|
||||
MouseEditMode mouseEditMode {MouseEditMode::NoEditing};
|
||||
MouseSizeMode mouseSizeMode {MouseSizeMode::None};
|
||||
CPoint mouseStartPoint;
|
||||
|
||||
SharedPointer<UIUndoManager> undoManger;
|
||||
SharedPointer<UISelection> selection;
|
||||
SharedPointer<UISelection> dragSelection;
|
||||
UIDescription* description {nullptr};
|
||||
SharedPointer<IGridProcessor> gridProcessor;
|
||||
|
||||
UIEditViewInternal::UIHighlightView* highlightView {nullptr};
|
||||
CLayeredViewContainer* overlayView {nullptr};
|
||||
UICrossLines* lines {nullptr};
|
||||
ViewSizeChangeOperation* moveSizeOperation {nullptr};
|
||||
SharedPointer<CVSTGUITimer> editTimer;
|
||||
DragStartMouseObserver dragStartMouseObserver;
|
||||
|
||||
CColor crosslineForegroundColor;
|
||||
CColor crosslineBackgroundColor;
|
||||
CColor lassoFillColor;
|
||||
CColor lassoFrameColor;
|
||||
CColor viewHighlightColor;
|
||||
CColor viewSelectionColor;
|
||||
|
||||
struct ViewAddedObserver;
|
||||
std::unique_ptr<ViewAddedObserver> editingViewAddedObserver;
|
||||
void disableExternalViewsOnInlineEditing (bool state);
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
|
||||
#endif // VSTGUI_LIVE_EDITING
|
||||
@@ -0,0 +1,144 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#include "uifocussettingscontroller.h"
|
||||
|
||||
#if VSTGUI_LIVE_EDITING
|
||||
|
||||
#include "uidialogcontroller.h"
|
||||
#include "uieditcontroller.h"
|
||||
#include "uiactions.h"
|
||||
#include "../uiattributes.h"
|
||||
#include "../../lib/controls/ctextedit.h"
|
||||
#include "../../lib/controls/coptionmenu.h"
|
||||
#include <sstream>
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
UIFocusSettingsController::UIFocusSettingsController (UIDescription* description, IActionPerformer* actionPerformer)
|
||||
: editDescription (description)
|
||||
, actionPerformer (actionPerformer)
|
||||
{
|
||||
originalSettings = editDescription->getFocusDrawingSettings ();
|
||||
for (auto& control : controls)
|
||||
control = nullptr;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void UIFocusSettingsController::onDialogButton1Clicked (UIDialogController*)
|
||||
{
|
||||
FocusDrawingSettings fd;
|
||||
|
||||
if (controls[kEnabledTag])
|
||||
fd.enabled =
|
||||
(controls[kEnabledTag]->getValue () == controls[kEnabledTag]->getMax ()) ? true : false;
|
||||
if (controls[kColorTag])
|
||||
{
|
||||
COptionMenu* menu = dynamic_cast<COptionMenu*> (controls[kColorTag]);
|
||||
CMenuItem* item = menu->getCurrent ();
|
||||
if (item)
|
||||
fd.colorName = item->getTitle ();
|
||||
}
|
||||
if (controls[kWidthTag])
|
||||
fd.width = controls[kWidthTag]->getValue ();
|
||||
if (originalSettings != fd)
|
||||
actionPerformer->performChangeFocusDrawingSettings (fd);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void UIFocusSettingsController::onDialogButton2Clicked (UIDialogController*)
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void UIFocusSettingsController::onDialogShow (UIDialogController*)
|
||||
{
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
CView* UIFocusSettingsController::verifyView (CView* view, const UIAttributes& attributes, const IUIDescription* description)
|
||||
{
|
||||
auto* control = dynamic_cast<CControl*>(view);
|
||||
if (control)
|
||||
{
|
||||
switch (control->getTag ())
|
||||
{
|
||||
case kEnabledTag:
|
||||
{
|
||||
control->setValue (originalSettings.enabled ? control->getMax () : control->getMin ());
|
||||
controls[kEnabledTag] = control;
|
||||
break;
|
||||
}
|
||||
case kColorTag:
|
||||
{
|
||||
auto* menu = dynamic_cast<COptionMenu*>(control);
|
||||
if (menu)
|
||||
{
|
||||
controls[kColorTag] = control;
|
||||
std::list<const std::string*> names;
|
||||
editDescription->collectColorNames (names);
|
||||
names.sort (UIEditController::std__stringCompare);
|
||||
int32_t index = 0;
|
||||
for (auto& name : names)
|
||||
{
|
||||
menu->addEntry (new CMenuItem (name->c_str ()));
|
||||
if (originalSettings.colorName == *name)
|
||||
{
|
||||
menu->setValue ((float)index);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kWidthTag:
|
||||
{
|
||||
controls[kWidthTag] = control;
|
||||
auto* edit = dynamic_cast<CTextEdit*>(control);
|
||||
if (edit)
|
||||
{
|
||||
edit->setStringToValueFunction (stringToValue);
|
||||
edit->setValueToStringFunction (valueToString);
|
||||
}
|
||||
control->setValue (static_cast<float> (originalSettings.width));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIFocusSettingsController::valueChanged (CControl* control)
|
||||
{
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool UIFocusSettingsController::valueToString (float value, char utf8String[256], CParamDisplay::ValueToStringUserData* userData)
|
||||
{
|
||||
int32_t intValue = (int32_t)value;
|
||||
std::stringstream str;
|
||||
str << (value == intValue ? intValue : value);
|
||||
std::strcpy (utf8String, str.str ().c_str ());
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool UIFocusSettingsController::stringToValue (UTF8StringPtr txt, float& result, CTextEdit::StringToValueUserData* userData)
|
||||
{
|
||||
if (txt)
|
||||
{
|
||||
float value = UTF8StringView (txt).toFloat ();
|
||||
result = value;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // VSTGUI
|
||||
|
||||
#endif // VSTGUI_LIVE_EDITING
|
||||
@@ -0,0 +1,52 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../uidescription.h"
|
||||
|
||||
#if VSTGUI_LIVE_EDITING
|
||||
|
||||
#include "iaction.h"
|
||||
#include "uidialogcontroller.h"
|
||||
#include "../icontroller.h"
|
||||
#include "../../lib/controls/ctextedit.h"
|
||||
#include <string>
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class UIFocusSettingsController : public NonAtomicReferenceCounted,
|
||||
public IDialogController,
|
||||
public IController
|
||||
{
|
||||
public:
|
||||
UIFocusSettingsController (UIDescription* description, IActionPerformer* actionPerformer);
|
||||
~UIFocusSettingsController () override = default;
|
||||
|
||||
CView* verifyView (CView* view, const UIAttributes& attributes, const IUIDescription* description) override;
|
||||
void valueChanged (CControl* control) override;
|
||||
void onDialogButton1Clicked (UIDialogController*) override;
|
||||
void onDialogButton2Clicked (UIDialogController*) override;
|
||||
void onDialogShow (UIDialogController*) override;
|
||||
protected:
|
||||
static bool valueToString (float value, char utf8String[256], CParamDisplay::ValueToStringUserData* userData);
|
||||
static bool stringToValue (UTF8StringPtr txt, float& result, CTextEdit::StringToValueUserData* userData);
|
||||
|
||||
SharedPointer<UIDescription> editDescription;
|
||||
IActionPerformer* actionPerformer;
|
||||
|
||||
enum {
|
||||
kEnabledTag = 0,
|
||||
kColorTag,
|
||||
kWidthTag,
|
||||
kNumTags
|
||||
};
|
||||
CControl* controls[kNumTags];
|
||||
FocusDrawingSettings originalSettings;
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
|
||||
#endif // VSTGUI_LIVE_EDITING
|
||||
@@ -0,0 +1,364 @@
|
||||
// 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 "uifontscontroller.h"
|
||||
|
||||
#if VSTGUI_LIVE_EDITING
|
||||
|
||||
#include "uieditcontroller.h"
|
||||
#include "uibasedatasource.h"
|
||||
#include "../../lib/controls/ccolorchooser.h"
|
||||
#include "../../lib/controls/coptionmenu.h"
|
||||
#include "../../lib/controls/csearchtextedit.h"
|
||||
#include "../../lib/platform/platformfactory.h"
|
||||
#include <sstream>
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class UIFontsDataSource : public UIBaseDataSource
|
||||
{
|
||||
public:
|
||||
UIFontsDataSource (UIDescription* description, IActionPerformer* actionPerformer, GenericStringListDataBrowserSourceSelectionChanged* delegate);
|
||||
|
||||
protected:
|
||||
void onUIDescFontChanged (UIDescription* desc) override;
|
||||
void getNames (std::list<const std::string*>& names) override;
|
||||
bool addItem (UTF8StringPtr name) override;
|
||||
bool removeItem (UTF8StringPtr name) override;
|
||||
bool performNameChange (UTF8StringPtr oldName, UTF8StringPtr newName) override;
|
||||
UTF8StringPtr getDefaultsName () override { return "UIFontsDataSource"; }
|
||||
|
||||
SharedPointer<CColorChooser> colorChooser;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
UIFontsDataSource::UIFontsDataSource (UIDescription* description, IActionPerformer* actionPerformer, GenericStringListDataBrowserSourceSelectionChanged* delegate)
|
||||
: UIBaseDataSource (description, actionPerformer, delegate)
|
||||
{
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIFontsDataSource::onUIDescFontChanged (UIDescription* desc)
|
||||
{
|
||||
onUIDescriptionUpdate ();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIFontsDataSource::getNames (std::list<const std::string*>& names)
|
||||
{
|
||||
description->collectFontNames (names);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool UIFontsDataSource::addItem (UTF8StringPtr name)
|
||||
{
|
||||
actionPerformer->performFontChange (name, kNormalFont);
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool UIFontsDataSource::removeItem (UTF8StringPtr name)
|
||||
{
|
||||
actionPerformer->performFontChange (name, kNormalFont, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool UIFontsDataSource::performNameChange (UTF8StringPtr oldName, UTF8StringPtr newName)
|
||||
{
|
||||
actionPerformer->performFontNameChange (oldName, newName);
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
UIFontsController::UIFontsController (IController* baseController, UIDescription* description, IActionPerformer* actionPerformer)
|
||||
: DelegationController (baseController)
|
||||
, editDescription (description)
|
||||
, actionPerformer (actionPerformer)
|
||||
, dataSource (nullptr)
|
||||
, fontMenu (nullptr)
|
||||
, altTextEdit (nullptr)
|
||||
, sizeTextEdit (nullptr)
|
||||
, boldControl (nullptr)
|
||||
, italicControl (nullptr)
|
||||
, strikethroughControl (nullptr)
|
||||
, underlineControl (nullptr)
|
||||
{
|
||||
dataSource = new UIFontsDataSource (editDescription, actionPerformer, this);
|
||||
UIEditController::setupDataSource (dataSource);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
UIFontsController::~UIFontsController ()
|
||||
{
|
||||
dataSource->forget ();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
CView* UIFontsController::createView (const UIAttributes& attributes, const IUIDescription* description)
|
||||
{
|
||||
const std::string* name = attributes.getAttributeValue (IUIDescription::kCustomViewName);
|
||||
if (name)
|
||||
{
|
||||
if (*name == "FontsBrowser")
|
||||
{
|
||||
CDataBrowser* dataBrowser = new CDataBrowser (CRect (0, 0, 0, 0), dataSource, CDataBrowser::kDrawRowLines|CScrollView::kHorizontalScrollbar | CScrollView::kVerticalScrollbar);
|
||||
return dataBrowser;
|
||||
}
|
||||
}
|
||||
return DelegationController::createView (attributes, description);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
CView* UIFontsController::verifyView (CView* view, const UIAttributes& attributes, const IUIDescription* description)
|
||||
{
|
||||
auto searchField = dynamic_cast<CSearchTextEdit*>(view);
|
||||
if (searchField && searchField->getTag () == kSearchTag)
|
||||
{
|
||||
dataSource->setSearchFieldControl (searchField);
|
||||
return searchField;
|
||||
}
|
||||
auto* control = dynamic_cast<CControl*>(view);
|
||||
if (control)
|
||||
{
|
||||
switch (control->getTag ())
|
||||
{
|
||||
case kFontMainTag:
|
||||
{
|
||||
fontMenu = dynamic_cast<COptionMenu*> (control);
|
||||
getPlatformFactory ().getAllFontFamilies ([&] (const std::string& name) {
|
||||
fontMenu->addEntry (name.data ());
|
||||
return true;
|
||||
});
|
||||
fontMenu->setStyle (fontMenu->getStyle () | COptionMenu::kNoTextStyle);
|
||||
fontMenu->setMouseEnabled (false);
|
||||
break;
|
||||
}
|
||||
case kFontAltTag:
|
||||
{
|
||||
altTextEdit = dynamic_cast<CTextEdit*>(control);
|
||||
control->setMouseEnabled (false);
|
||||
break;
|
||||
}
|
||||
case kFontSizeTag:
|
||||
{
|
||||
sizeTextEdit = dynamic_cast<CTextEdit*>(control);
|
||||
if (sizeTextEdit)
|
||||
{
|
||||
sizeTextEdit->setValueToStringFunction (valueToString);
|
||||
sizeTextEdit->setStringToValueFunction (stringToValue);
|
||||
}
|
||||
control->setMouseEnabled (false);
|
||||
break;
|
||||
}
|
||||
case kFontStyleBoldTag:
|
||||
{
|
||||
boldControl = control;
|
||||
control->setMouseEnabled (false);
|
||||
break;
|
||||
}
|
||||
case kFontStyleItalicTag:
|
||||
{
|
||||
italicControl = control;
|
||||
control->setMouseEnabled (false);
|
||||
break;
|
||||
}
|
||||
case kFontStyleStrikethroughTag:
|
||||
{
|
||||
strikethroughControl = control;
|
||||
control->setMouseEnabled (false);
|
||||
break;
|
||||
}
|
||||
case kFontStyleUnderlineTag:
|
||||
{
|
||||
underlineControl = control;
|
||||
control->setMouseEnabled (false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return controller->verifyView (view, attributes, description);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
IControlListener* UIFontsController::getControlListener (UTF8StringPtr name)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIFontsController::valueChanged (CControl* pControl)
|
||||
{
|
||||
switch (pControl->getTag ())
|
||||
{
|
||||
case kAddTag:
|
||||
{
|
||||
if (pControl->getValue () == pControl->getMax ())
|
||||
{
|
||||
dataSource->add ();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kRemoveTag:
|
||||
{
|
||||
if (pControl->getValue () == pControl->getMax ())
|
||||
{
|
||||
dataSource->remove ();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kFontMainTag:
|
||||
case kFontSizeTag:
|
||||
case kFontStyleBoldTag:
|
||||
case kFontStyleItalicTag:
|
||||
case kFontStyleStrikethroughTag:
|
||||
case kFontStyleUnderlineTag:
|
||||
{
|
||||
if (fontMenu == nullptr || sizeTextEdit == nullptr || selectedFont.empty ())
|
||||
break;
|
||||
CMenuItem* menuItem = fontMenu->getCurrent ();
|
||||
if (menuItem)
|
||||
{
|
||||
int32_t style = 0;
|
||||
if (boldControl && boldControl->getValue () > 0)
|
||||
style |= kBoldFace;
|
||||
if (italicControl && italicControl->getValue () > 0)
|
||||
style |= kItalicFace;
|
||||
if (underlineControl && underlineControl->getValue () > 0)
|
||||
style |= kUnderlineFace;
|
||||
if (strikethroughControl && strikethroughControl->getValue () > 0)
|
||||
style |= kStrikethroughFace;
|
||||
auto font = makeOwned<CFontDesc> (menuItem->getTitle (), sizeTextEdit->getValue (), style);
|
||||
actionPerformer->performFontChange (selectedFont.data (), font);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kFontAltTag:
|
||||
{
|
||||
actionPerformer->performAlternativeFontChange (selectedFont.data (), altTextEdit->getText ());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIFontsController::dbSelectionChanged (int32_t selectedRow, GenericStringListDataBrowserSource* source)
|
||||
{
|
||||
selectedFont = selectedRow != CDataBrowser::kNoSelection ? dataSource->getStringList ()->at (static_cast<uint32_t> (selectedRow)).data () : "";
|
||||
CFontRef font = editDescription->getFont (selectedFont.data ());
|
||||
if (font)
|
||||
{
|
||||
if (fontMenu && !font->getName ().empty ())
|
||||
{
|
||||
const auto& fontName = font->getName ();
|
||||
CMenuItemList* items = fontMenu->getItems ();
|
||||
int32_t index = 0;
|
||||
for (auto& item : *items)
|
||||
{
|
||||
if (fontName == item->getTitle ())
|
||||
{
|
||||
fontMenu->setValue ((float)index);
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
fontMenu->setStyle (fontMenu->getStyle () & ~COptionMenu::kNoTextStyle);
|
||||
fontMenu->setMouseEnabled (true);
|
||||
}
|
||||
if (sizeTextEdit)
|
||||
{
|
||||
sizeTextEdit->setMouseEnabled (true);
|
||||
std::stringstream str;
|
||||
str << font->getSize ();
|
||||
sizeTextEdit->setText (str.str ().data ());
|
||||
}
|
||||
if (boldControl)
|
||||
{
|
||||
boldControl->setValue (font->getStyle () & kBoldFace ? true : false);
|
||||
boldControl->invalid ();
|
||||
boldControl->setMouseEnabled (true);
|
||||
}
|
||||
if (italicControl)
|
||||
{
|
||||
italicControl->setValue (font->getStyle () & kItalicFace ? true : false);
|
||||
italicControl->invalid ();
|
||||
italicControl->setMouseEnabled (true);
|
||||
}
|
||||
if (underlineControl)
|
||||
{
|
||||
underlineControl->setValue (font->getStyle () & kUnderlineFace ? true : false);
|
||||
underlineControl->invalid ();
|
||||
underlineControl->setMouseEnabled (true);
|
||||
}
|
||||
if (strikethroughControl)
|
||||
{
|
||||
strikethroughControl->setValue (font->getStyle () & kStrikethroughFace ? true : false);
|
||||
strikethroughControl->invalid ();
|
||||
strikethroughControl->setMouseEnabled (true);
|
||||
}
|
||||
if (altTextEdit)
|
||||
{
|
||||
std::string alternativeFonts;
|
||||
editDescription->getAlternativeFontNames (selectedFont.data (), alternativeFonts);
|
||||
altTextEdit->setText (alternativeFonts.data ());
|
||||
altTextEdit->setMouseEnabled (true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fontMenu)
|
||||
{
|
||||
fontMenu->setStyle (fontMenu->getStyle () | COptionMenu::kNoTextStyle);
|
||||
fontMenu->setMouseEnabled (false);
|
||||
}
|
||||
if (boldControl)
|
||||
boldControl->setMouseEnabled (false);
|
||||
if (italicControl)
|
||||
italicControl->setMouseEnabled (false);
|
||||
if (underlineControl)
|
||||
underlineControl->setMouseEnabled (false);
|
||||
if (strikethroughControl)
|
||||
strikethroughControl->setMouseEnabled (false);
|
||||
if (altTextEdit)
|
||||
{
|
||||
altTextEdit->setMouseEnabled (false);
|
||||
altTextEdit->setText (nullptr);
|
||||
}
|
||||
if (sizeTextEdit)
|
||||
{
|
||||
sizeTextEdit->setMouseEnabled (false);
|
||||
sizeTextEdit->setText (nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool UIFontsController::valueToString (float value, char utf8String[256], CParamDisplay::ValueToStringUserData* userData)
|
||||
{
|
||||
auto* edit = static_cast<CTextEdit*> (userData);
|
||||
if (edit && edit->getMouseEnabled () == false)
|
||||
return true;
|
||||
|
||||
int32_t intValue = (int32_t)value;
|
||||
std::stringstream str;
|
||||
str << intValue;
|
||||
std::strcpy (utf8String, str.str ().data ());
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool UIFontsController::stringToValue (UTF8StringPtr txt, float& result, CTextEdit::StringToValueUserData* userData)
|
||||
{
|
||||
int32_t value = txt ? (int32_t)strtol (txt, nullptr, 10) : 0;
|
||||
result = (float)value;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
} // VSTGUI
|
||||
|
||||
#endif // VSTGUI_LIVE_EDITING
|
||||
@@ -0,0 +1,71 @@
|
||||
// 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 "../uidescription.h"
|
||||
|
||||
#if VSTGUI_LIVE_EDITING
|
||||
|
||||
#include "uiselection.h"
|
||||
#include "uiundomanager.h"
|
||||
#include "iaction.h"
|
||||
#include "../delegationcontroller.h"
|
||||
#include "../../lib/cdatabrowser.h"
|
||||
#include "../../lib/genericstringlistdatabrowsersource.h"
|
||||
#include "../../lib/controls/ctextedit.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
class UIFontsDataSource;
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class UIFontsController : public NonAtomicReferenceCounted,
|
||||
public DelegationController,
|
||||
public GenericStringListDataBrowserSourceSelectionChanged
|
||||
{
|
||||
public:
|
||||
UIFontsController (IController* baseController, UIDescription* description, IActionPerformer* actionPerformer);
|
||||
~UIFontsController () override;
|
||||
|
||||
protected:
|
||||
CView* createView (const UIAttributes& attributes, const IUIDescription* description) override;
|
||||
CView* verifyView (CView* view, const UIAttributes& attributes, const IUIDescription* description) override;
|
||||
IControlListener* getControlListener (UTF8StringPtr name) override;
|
||||
void valueChanged (CControl* pControl) override;
|
||||
|
||||
void dbSelectionChanged (int32_t selectedRow, GenericStringListDataBrowserSource* source) override;
|
||||
|
||||
static bool valueToString (float value, char utf8String[256], CParamDisplay::ValueToStringUserData* userData);
|
||||
static bool stringToValue (UTF8StringPtr txt, float& result, CTextEdit::StringToValueUserData* userData);
|
||||
|
||||
SharedPointer<UIDescription> editDescription;
|
||||
IActionPerformer* actionPerformer;
|
||||
UIFontsDataSource* dataSource;
|
||||
|
||||
COptionMenu* fontMenu;
|
||||
CTextEdit* altTextEdit;
|
||||
CTextEdit* sizeTextEdit;
|
||||
CControl* boldControl;
|
||||
CControl* italicControl;
|
||||
CControl* strikethroughControl;
|
||||
CControl* underlineControl;
|
||||
|
||||
std::string selectedFont;
|
||||
|
||||
enum {
|
||||
kAddTag = 0,
|
||||
kRemoveTag,
|
||||
kSearchTag,
|
||||
kFontMainTag,
|
||||
kFontAltTag,
|
||||
kFontSizeTag,
|
||||
kFontStyleBoldTag,
|
||||
kFontStyleItalicTag,
|
||||
kFontStyleStrikethroughTag,
|
||||
kFontStyleUnderlineTag
|
||||
};
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
|
||||
#endif // VSTGUI_LIVE_EDITING
|
||||
@@ -0,0 +1,889 @@
|
||||
// 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 "uigradientscontroller.h"
|
||||
|
||||
#if VSTGUI_LIVE_EDITING
|
||||
|
||||
#include "uibasedatasource.h"
|
||||
#include "iaction.h"
|
||||
#include "uieditcontroller.h"
|
||||
#include "uidialogcontroller.h"
|
||||
#include "uicolorchoosercontroller.h"
|
||||
#include "uicolor.h"
|
||||
#include "../../lib/cgradientview.h"
|
||||
#include "../../lib/ifocusdrawing.h"
|
||||
#include "../../lib/cgraphicspath.h"
|
||||
#include "../../lib/cdrawcontext.h"
|
||||
#include "../../lib/events.h"
|
||||
#include "../../lib/controls/coptionmenu.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
struct IUIColorStopEditViewListener
|
||||
{
|
||||
virtual ~IUIColorStopEditViewListener () noexcept = default;
|
||||
virtual void onChange () = 0;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
class UIColorStopEditView
|
||||
: public CView,
|
||||
protected ListenerProvider<UIColorStopEditView, IUIColorStopEditViewListener>,
|
||||
public IFocusDrawing,
|
||||
public UIColorListenerAdapter
|
||||
{
|
||||
public:
|
||||
UIColorStopEditView (UIColor* editColor);
|
||||
~UIColorStopEditView () override;
|
||||
|
||||
void setGradient (CGradient* gradient);
|
||||
|
||||
void selectNextColorStop ();
|
||||
void selectPrevColorStop ();
|
||||
void setEditColor (CColor color);
|
||||
void setCurrentStartOffset (double startOffset);
|
||||
double getSelectedColorStart () const { return editStartOffset; }
|
||||
const GradientColorStopMap& getColorStopMap () const { return colorStopMap; }
|
||||
|
||||
using ListenerProvider<UIColorStopEditView, IUIColorStopEditViewListener>::registerListener;
|
||||
using ListenerProvider<UIColorStopEditView, IUIColorStopEditViewListener>::unregisterListener;
|
||||
private:
|
||||
void draw (CDrawContext* context) override;
|
||||
bool drawFocusOnTop () override;
|
||||
bool getFocusPath (CGraphicsPath& outPath) override;
|
||||
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;
|
||||
void uiColorChanged (UIColor* c) override;
|
||||
|
||||
double gradientStartPosFromMousePos (const CPoint& where) const;
|
||||
|
||||
void addColorStop (double startOffset);
|
||||
void removeColorStop (double startOffset);
|
||||
|
||||
SharedPointer<UIColor> editColor;
|
||||
SharedPointer<CGradient> gradient;
|
||||
GradientColorStopMap colorStopMap;
|
||||
double editStartOffset;
|
||||
CCoord stopWidth;
|
||||
|
||||
double mouseDownStartPosOffset;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
UIColorStopEditView::UIColorStopEditView (UIColor* editColor)
|
||||
: CView (CRect (0, 0, 0, 0))
|
||||
, editColor (editColor)
|
||||
, editStartOffset (-1.)
|
||||
, mouseDownStartPosOffset (0.)
|
||||
{
|
||||
editColor->registerListener (this);
|
||||
setWantsFocus (true);
|
||||
stopWidth = 12.;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
UIColorStopEditView::~UIColorStopEditView ()
|
||||
{
|
||||
editColor->unregisterListener (this);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColorStopEditView::selectNextColorStop ()
|
||||
{
|
||||
auto pos = colorStopMap.find (getSelectedColorStart ());
|
||||
pos++;
|
||||
if (pos == colorStopMap.end ())
|
||||
{
|
||||
pos = colorStopMap.begin ();
|
||||
}
|
||||
editStartOffset = pos->first;
|
||||
*editColor = pos->second;
|
||||
forEachListener ([] (IUIColorStopEditViewListener* l) { l->onChange (); });
|
||||
invalid ();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColorStopEditView::selectPrevColorStop ()
|
||||
{
|
||||
auto pos = colorStopMap.find (getSelectedColorStart ());
|
||||
if (pos == colorStopMap.begin ())
|
||||
pos = colorStopMap.end ();
|
||||
pos--;
|
||||
editStartOffset = pos->first;
|
||||
*editColor = pos->second;
|
||||
forEachListener ([] (IUIColorStopEditViewListener* l) { l->onChange (); });
|
||||
invalid ();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColorStopEditView::setEditColor (CColor color)
|
||||
{
|
||||
if (editColor)
|
||||
{
|
||||
editColor->beginEdit ();
|
||||
*editColor = color;
|
||||
editColor->endEdit ();
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColorStopEditView::setCurrentStartOffset (double startOffset)
|
||||
{
|
||||
if (startOffset < 0.)
|
||||
startOffset = 0.;
|
||||
else if (startOffset > 1.)
|
||||
startOffset = 1.;
|
||||
auto pos = colorStopMap.find (getSelectedColorStart ());
|
||||
if (pos != colorStopMap.end () && pos->first != startOffset)
|
||||
{
|
||||
CColor color = pos->second;
|
||||
colorStopMap.erase (pos);
|
||||
colorStopMap.emplace (startOffset, color);
|
||||
editStartOffset = startOffset;
|
||||
forEachListener ([] (IUIColorStopEditViewListener* l) { l->onChange (); });
|
||||
invalid ();
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColorStopEditView::addColorStop (double startOffset)
|
||||
{
|
||||
colorStopMap.emplace (startOffset, editColor->base ());
|
||||
editStartOffset = startOffset;
|
||||
forEachListener ([] (IUIColorStopEditViewListener* l) { l->onChange (); });
|
||||
invalid ();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColorStopEditView::removeColorStop (double startOffset)
|
||||
{
|
||||
if (colorStopMap.size () < 3)
|
||||
return;
|
||||
if (getSelectedColorStart () == startOffset)
|
||||
selectNextColorStop ();
|
||||
colorStopMap.erase (startOffset);
|
||||
forEachListener ([] (IUIColorStopEditViewListener* l) { l->onChange (); });
|
||||
invalid ();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColorStopEditView::onKeyboardEvent (KeyboardEvent& event)
|
||||
{
|
||||
if (event.type != EventType::KeyDown)
|
||||
return;
|
||||
switch (event.virt)
|
||||
{
|
||||
case VirtualKey::Left:
|
||||
{
|
||||
if (event.modifiers.empty ())
|
||||
{
|
||||
selectPrevColorStop ();
|
||||
event.consumed = true;
|
||||
}
|
||||
else if (event.modifiers.is (ModifierKey::Alt))
|
||||
{
|
||||
setCurrentStartOffset (editStartOffset - 0.001);
|
||||
event.consumed = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VirtualKey::Right:
|
||||
{
|
||||
if (event.modifiers.empty ())
|
||||
{
|
||||
selectNextColorStop ();
|
||||
event.consumed = true;
|
||||
}
|
||||
else if (event.modifiers.is(ModifierKey::Alt))
|
||||
{
|
||||
setCurrentStartOffset (editStartOffset + 0.001);
|
||||
event.consumed = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VirtualKey::Back:
|
||||
{
|
||||
if (event.modifiers.empty ())
|
||||
{
|
||||
removeColorStop (getSelectedColorStart ());
|
||||
event.consumed = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
double UIColorStopEditView::gradientStartPosFromMousePos (const CPoint& where) const
|
||||
{
|
||||
return (where.x - (getViewSize ().left + (stopWidth / 2.))) / (getWidth () - stopWidth);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
CMouseEventResult UIColorStopEditView::onMouseDown (CPoint& where, const CButtonState& buttons)
|
||||
{
|
||||
if (buttons.isDoubleClick ())
|
||||
{
|
||||
double pos = gradientStartPosFromMousePos (where);
|
||||
if (pos >= 0. && pos <= 1.)
|
||||
{
|
||||
addColorStop (pos);
|
||||
}
|
||||
return kMouseDownEventHandledButDontNeedMovedOrUpEvents;
|
||||
}
|
||||
else if (buttons.isLeftButton ())
|
||||
{
|
||||
getFrame ()->setFocusView (this);
|
||||
double pos = gradientStartPosFromMousePos (where);
|
||||
double range = (stopWidth / getWidth ()) / 2.;
|
||||
for (auto& colorStop : colorStopMap)
|
||||
{
|
||||
if (pos >= colorStop.first - range && pos <= colorStop.first + range)
|
||||
{
|
||||
if (buttons.getModifierState () == kAlt)
|
||||
{
|
||||
removeColorStop (colorStop.first);
|
||||
return kMouseDownEventHandledButDontNeedMovedOrUpEvents;
|
||||
}
|
||||
if (editStartOffset != colorStop.first)
|
||||
{
|
||||
editStartOffset = colorStop.first;
|
||||
*editColor = colorStop.second;
|
||||
forEachListener ([] (IUIColorStopEditViewListener* l) { l->onChange (); });
|
||||
}
|
||||
mouseDownStartPosOffset = pos - editStartOffset;
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
}
|
||||
}
|
||||
return kMouseDownEventHandledButDontNeedMovedOrUpEvents;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
CMouseEventResult UIColorStopEditView::onMouseUp (CPoint& where, const CButtonState& buttons)
|
||||
{
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
CMouseEventResult UIColorStopEditView::onMouseMoved (CPoint& where, const CButtonState& buttons)
|
||||
{
|
||||
if (buttons.isLeftButton ())
|
||||
{
|
||||
double pos = gradientStartPosFromMousePos (where) - mouseDownStartPosOffset;
|
||||
setCurrentStartOffset (pos);
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
return kMouseEventNotHandled;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColorStopEditView::uiColorChanged (UIColor* c)
|
||||
{
|
||||
invalid ();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColorStopEditView::setGradient (CGradient* inGradient)
|
||||
{
|
||||
colorStopMap = inGradient->getColorStops ();
|
||||
auto it = colorStopMap.find (editStartOffset);
|
||||
if (it == colorStopMap.end ())
|
||||
editStartOffset = colorStopMap.begin ()->first;
|
||||
gradient = inGradient;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIColorStopEditView::draw (CDrawContext* context)
|
||||
{
|
||||
CDrawContext::Transform t (*context, CGraphicsTransform ().translate (getViewSize ().left, getViewSize ().top));
|
||||
|
||||
context->setDrawMode (kAliasing);
|
||||
|
||||
SharedPointer<CGraphicsPath> gradientPath = owned (context->createGraphicsPath ());
|
||||
gradientPath->addRect (CRect (stopWidth / 2., 0., getWidth () - stopWidth / 2., getHeight ()));
|
||||
context->fillLinearGradient (gradientPath, *gradient, CPoint (stopWidth / 2., 0), CPoint (getWidth () - stopWidth / 2, 0));
|
||||
|
||||
CCoord width = getWidth () - stopWidth;
|
||||
CCoord height = (getHeight () / 2.);
|
||||
SharedPointer<CGraphicsPath> path = owned (context->createGraphicsPath ());
|
||||
path->beginSubpath (CPoint (stopWidth / 2., 0));
|
||||
path->addLine (CPoint (0, height));
|
||||
path->addLine (CPoint (stopWidth, height));
|
||||
path->closeSubpath ();
|
||||
|
||||
context->setFrameColor (kBlackCColor);
|
||||
context->setLineWidth (1.1);
|
||||
context->setLineStyle (kLineSolid);
|
||||
context->setDrawMode (kAntiAliasing);
|
||||
|
||||
CColor selectedColor;
|
||||
|
||||
context->setGlobalAlpha (0.5f);
|
||||
for (auto& colorStop : colorStopMap)
|
||||
{
|
||||
if (colorStop.first == getSelectedColorStart ())
|
||||
{
|
||||
selectedColor = colorStop.second;
|
||||
}
|
||||
else
|
||||
{
|
||||
CGraphicsTransform offset;
|
||||
offset.translate (colorStop.first * width, getHeight () / 4.);
|
||||
if (colorStop.second.getLuma () < 127)
|
||||
context->setFrameColor (kWhiteCColor);
|
||||
else
|
||||
context->setFrameColor (kBlackCColor);
|
||||
context->drawGraphicsPath (path, CDrawContext::kPathStroked, &offset);
|
||||
}
|
||||
}
|
||||
|
||||
context->setGlobalAlpha (1.f);
|
||||
if (getSelectedColorStart () >= 0.)
|
||||
{
|
||||
CGraphicsTransform offset;
|
||||
offset.translate (getSelectedColorStart () * width, getHeight() / 4.);
|
||||
if (selectedColor.getLuma () < 127)
|
||||
context->setFrameColor (kWhiteCColor);
|
||||
else
|
||||
context->setFrameColor (kBlackCColor);
|
||||
context->setFillColor (selectedColor);
|
||||
context->drawGraphicsPath (path, CDrawContext::kPathFilled, &offset);
|
||||
context->drawGraphicsPath (path, CDrawContext::kPathStroked, &offset);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool UIColorStopEditView::drawFocusOnTop ()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool UIColorStopEditView::getFocusPath (CGraphicsPath& outPath)
|
||||
{
|
||||
CRect r (getViewSize ());
|
||||
r.inset (stopWidth / 2 - 1, -1);
|
||||
outPath.addRect (r);
|
||||
r.inset (2, 2);
|
||||
outPath.addRect (r);
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class UIGradientEditorController : public NonAtomicReferenceCounted,
|
||||
public IDialogController,
|
||||
public UIColorListenerAdapter,
|
||||
public IUIColorStopEditViewListener,
|
||||
public IController
|
||||
{
|
||||
public:
|
||||
UIGradientEditorController (const std::string& gradientName, CGradient* gradient, UIDescription* description, IActionPerformer* actionPerformer);
|
||||
~UIGradientEditorController () override;
|
||||
|
||||
void valueChanged (CControl* pControl) override;
|
||||
CView* verifyView (CView* view, const UIAttributes& attributes, const IUIDescription* description) override;
|
||||
CView* createView (const UIAttributes& attributes, const IUIDescription* description) override;
|
||||
IController* createSubController (UTF8StringPtr name, const IUIDescription* description) override;
|
||||
void onDialogButton1Clicked (UIDialogController*) override;
|
||||
void onDialogButton2Clicked (UIDialogController*) override;
|
||||
void onDialogShow (UIDialogController*) override;
|
||||
protected:
|
||||
enum
|
||||
{
|
||||
kApplyTag = 1,
|
||||
kPositionTag = 2,
|
||||
kFunctionMenuTag = 3,
|
||||
};
|
||||
void uiColorChanged (UIColor* c) override;
|
||||
void onChange () override;
|
||||
void apply ();
|
||||
void updatePositionEdit ();
|
||||
|
||||
SharedPointer<UIDescription> editDescription;
|
||||
SharedPointer<UIColorStopEditView> colorStopEditView;
|
||||
SharedPointer<CGradient> gradient;
|
||||
SharedPointer<UIColor> editColor;
|
||||
CTextEdit* positionEdit {nullptr};
|
||||
IActionPerformer* actionPerformer;
|
||||
std::string gradientName;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
UIGradientEditorController::UIGradientEditorController (const std::string& gradientName, CGradient* gradient, UIDescription* description, IActionPerformer* actionPerformer)
|
||||
: editDescription(description)
|
||||
, gradient (gradient)
|
||||
, editColor (makeOwned<UIColor> ())
|
||||
, actionPerformer(actionPerformer)
|
||||
, gradientName (gradientName)
|
||||
{
|
||||
*editColor = gradient->getColorStops ().begin ()->second;
|
||||
editColor->registerListener (this);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
UIGradientEditorController::~UIGradientEditorController ()
|
||||
{
|
||||
colorStopEditView->unregisterListener (this);
|
||||
editColor->unregisterListener (this);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIGradientEditorController::apply ()
|
||||
{
|
||||
CGradient* g = editDescription->getGradient (gradientName.data ());
|
||||
if (g->getColorStops () != gradient->getColorStops ())
|
||||
actionPerformer->performGradientChange (gradientName.data (), gradient);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIGradientEditorController::updatePositionEdit ()
|
||||
{
|
||||
if (positionEdit && colorStopEditView)
|
||||
positionEdit->setValue (static_cast<float> (colorStopEditView->getSelectedColorStart ()));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIGradientEditorController::uiColorChanged (UIColor* c)
|
||||
{
|
||||
auto colorStopMap = gradient->getColorStops (); // create a copy
|
||||
auto it = colorStopMap.find (colorStopEditView->getSelectedColorStart ());
|
||||
if (it != colorStopMap.end () && it->second != editColor->base ())
|
||||
{
|
||||
it->second = editColor->base ();
|
||||
gradient = CGradient::create (colorStopMap);
|
||||
colorStopEditView->setGradient (gradient);
|
||||
updatePositionEdit ();
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIGradientEditorController::onChange ()
|
||||
{
|
||||
gradient = CGradient::create (colorStopEditView->getColorStopMap ());
|
||||
colorStopEditView->setGradient (gradient);
|
||||
updatePositionEdit ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void UIGradientEditorController::onDialogButton1Clicked (UIDialogController*)
|
||||
{
|
||||
apply ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void UIGradientEditorController::onDialogButton2Clicked (UIDialogController*)
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void UIGradientEditorController::onDialogShow (UIDialogController*)
|
||||
{
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
IController* UIGradientEditorController::createSubController (UTF8StringPtr name, const IUIDescription* description)
|
||||
{
|
||||
if (UTF8StringView (name) == "ColorChooserController")
|
||||
{
|
||||
return new UIColorChooserController (this, editColor);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIGradientEditorController::valueChanged (CControl* pControl)
|
||||
{
|
||||
switch (pControl->getTag ())
|
||||
{
|
||||
case kApplyTag:
|
||||
{
|
||||
if (pControl->getValue () > 0.f)
|
||||
apply ();
|
||||
break;
|
||||
}
|
||||
case kPositionTag:
|
||||
{
|
||||
colorStopEditView->setCurrentStartOffset (pControl->getValue ());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
SharedPointer<COptionMenu> createColorMenu (IUIDescription& desc,
|
||||
const std::function<void (CColor)>& callback)
|
||||
{
|
||||
std::list<const std::string*> names;
|
||||
desc.collectColorNames (names);
|
||||
if (names.empty ())
|
||||
return {};
|
||||
auto menu = makeOwned<COptionMenu> ();
|
||||
std::for_each (names.begin (), names.end (), [&] (const auto& el) {
|
||||
CColor color;
|
||||
if (desc.getColor (el->data (), color))
|
||||
{
|
||||
auto item = new CCommandMenuItem (UTF8String (*el));
|
||||
item->setActions ([callback, color] (auto item) { callback (color); });
|
||||
item->setIcon (createColorIcon (color));
|
||||
menu->addEntry (item);
|
||||
}
|
||||
});
|
||||
return menu;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
CView* UIGradientEditorController::verifyView (CView* view, const UIAttributes& attributes, const IUIDescription* description)
|
||||
{
|
||||
if (auto control = dynamic_cast<CTextEdit*>(view))
|
||||
{
|
||||
if (control->getTag () == kPositionTag)
|
||||
{
|
||||
control->setStringToValueFunction ([] (UTF8StringPtr txt, float& result, CTextEdit*) {
|
||||
UTF8StringView t (txt);
|
||||
result = t.toFloat ();
|
||||
return true;
|
||||
});
|
||||
positionEdit = control;
|
||||
updatePositionEdit ();
|
||||
}
|
||||
}
|
||||
else if (auto menu = dynamic_cast<COptionMenu*> (view))
|
||||
{
|
||||
if (menu->getTag () == kFunctionMenuTag)
|
||||
{
|
||||
auto item = new CCommandMenuItem ({"Select Next Color Stop"});
|
||||
item->setActions ([this] (auto) {
|
||||
if (colorStopEditView)
|
||||
{
|
||||
colorStopEditView->selectNextColorStop ();
|
||||
}
|
||||
});
|
||||
menu->addEntry (item);
|
||||
item = new CCommandMenuItem ({"Select Previous Color Stop"});
|
||||
item->setActions ([this] (auto) {
|
||||
if (colorStopEditView)
|
||||
{
|
||||
colorStopEditView->selectPrevColorStop ();
|
||||
}
|
||||
});
|
||||
menu->addEntry (item);
|
||||
menu->addSeparator ();
|
||||
auto descColorMenu = createColorMenu (*editDescription, [this] (auto color) {
|
||||
if (colorStopEditView)
|
||||
{
|
||||
colorStopEditView->setEditColor (color);
|
||||
}
|
||||
});
|
||||
menu->addEntry (descColorMenu, "Set to Description Color");
|
||||
auto cssColorMenu = createCSSColorMenu ([this] (auto color) {
|
||||
if (colorStopEditView)
|
||||
{
|
||||
colorStopEditView->setEditColor (color);
|
||||
}
|
||||
});
|
||||
menu->addEntry (cssColorMenu, "Set to CSS Color");
|
||||
}
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
CView* UIGradientEditorController::createView (const UIAttributes& attributes, const IUIDescription* description)
|
||||
{
|
||||
const std::string* name = attributes.getAttributeValue (IUIDescription::kCustomViewName);
|
||||
if (name)
|
||||
{
|
||||
if (*name == "ColorStopEditView")
|
||||
{
|
||||
colorStopEditView = new UIColorStopEditView (editColor);
|
||||
colorStopEditView->setGradient (gradient);
|
||||
colorStopEditView->registerListener (this);
|
||||
return colorStopEditView;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class UIGradientsDataSource : public UIBaseDataSource
|
||||
{
|
||||
public:
|
||||
UIGradientsDataSource (UIDescription* description, IActionPerformer* actionPerformer, GenericStringListDataBrowserSourceSelectionChanged* delegate);
|
||||
~UIGradientsDataSource () override = default;
|
||||
|
||||
CGradient* getSelectedGradient ();
|
||||
std::string getSelectedGradientName ();
|
||||
|
||||
protected:
|
||||
void onUIDescGradientChanged (UIDescription* desc) override;
|
||||
void update () override;
|
||||
void getNames (std::list<const std::string*>& names) override;
|
||||
bool addItem (UTF8StringPtr name) override;
|
||||
bool removeItem (UTF8StringPtr name) override;
|
||||
bool performNameChange (UTF8StringPtr oldName, UTF8StringPtr newName) override;
|
||||
UTF8StringPtr getDefaultsName () override { return "UIGradientsDataSource"; }
|
||||
|
||||
void dbDrawCell (CDrawContext* context, const CRect& size, int32_t row, int32_t column, int32_t flags, CDataBrowser* browser) override;
|
||||
void dbCellSetupTextEdit (int32_t row, int32_t column, CTextEdit* control, CDataBrowser* browser) override;
|
||||
CMouseEventResult dbOnMouseDown (const CPoint& where, const CButtonState& buttons, int32_t row, int32_t column, CDataBrowser* browser) override;
|
||||
|
||||
CCoord getGradientIconWidth ();
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
UIGradientsDataSource::UIGradientsDataSource (
|
||||
UIDescription* description, IActionPerformer* actionPerformer,
|
||||
GenericStringListDataBrowserSourceSelectionChanged* delegate)
|
||||
: UIBaseDataSource (description, actionPerformer, delegate)
|
||||
{
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIGradientsDataSource::onUIDescGradientChanged (UIDescription* desc)
|
||||
{
|
||||
onUIDescriptionUpdate ();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
CGradient* UIGradientsDataSource::getSelectedGradient ()
|
||||
{
|
||||
int32_t selectedRow = dataBrowser ? dataBrowser->getSelectedRow() : CDataBrowser::kNoSelection;
|
||||
if (selectedRow != CDataBrowser::kNoSelection && selectedRow < (int32_t)names.size ())
|
||||
return description->getGradient (names.at (static_cast<uint32_t> (selectedRow)).data ());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
std::string UIGradientsDataSource::getSelectedGradientName ()
|
||||
{
|
||||
int32_t selectedRow = dataBrowser ? dataBrowser->getSelectedRow() : CDataBrowser::kNoSelection;
|
||||
if (selectedRow != CDataBrowser::kNoSelection && selectedRow < (int32_t)names.size ())
|
||||
return names[static_cast<uint32_t> (selectedRow)].getString ();
|
||||
return "";
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIGradientsDataSource::getNames (std::list<const std::string*>& names)
|
||||
{
|
||||
description->collectGradientNames (names);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool UIGradientsDataSource::addItem (UTF8StringPtr name)
|
||||
{
|
||||
actionPerformer->performGradientChange (name, CGradient::create (0, 1, kWhiteCColor, kBlackCColor));
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool UIGradientsDataSource::removeItem (UTF8StringPtr name)
|
||||
{
|
||||
actionPerformer->performGradientChange (name, nullptr, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIGradientsDataSource::update ()
|
||||
{
|
||||
UIBaseDataSource::update ();
|
||||
if (dataBrowser)
|
||||
{
|
||||
dbSelectionChanged (dataBrowser);
|
||||
dataBrowser->invalid ();
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
CCoord UIGradientsDataSource::getGradientIconWidth ()
|
||||
{
|
||||
return dataBrowser ? dbGetRowHeight (dataBrowser) * 2. : 0.;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
CMouseEventResult UIGradientsDataSource::dbOnMouseDown (const CPoint& where, const CButtonState& buttons, int32_t row, int32_t column, CDataBrowser* browser)
|
||||
{
|
||||
if (buttons.isDoubleClick () && row >= 0 && row < static_cast<int32_t> (names.size ()))
|
||||
{
|
||||
auto r = browser->getCellBounds ({row, column});
|
||||
r.left = r.right - getGradientIconWidth ();
|
||||
if (r.pointInside (where))
|
||||
{
|
||||
delegate->dbRowDoubleClick (row, this);
|
||||
return kMouseDownEventHandledButDontNeedMovedOrUpEvents;
|
||||
}
|
||||
}
|
||||
return UIBaseDataSource::dbOnMouseDown (where, buttons, row, column, browser);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIGradientsDataSource::dbDrawCell (CDrawContext* context, const CRect& size, int32_t row, int32_t column, int32_t flags, CDataBrowser* browser)
|
||||
{
|
||||
GenericStringListDataBrowserSource::drawRowBackground (context, size, row, flags, browser);
|
||||
CRect r (size);
|
||||
r.right -= getGradientIconWidth ();
|
||||
GenericStringListDataBrowserSource::drawRowString (context, r, row, flags, browser);
|
||||
CGradient* gradient = nullptr;
|
||||
if ((gradient = description->getGradient (names.at (static_cast<uint32_t> (row)).data ())))
|
||||
{
|
||||
context->setFrameColor (kBlackCColor);
|
||||
context->setLineWidth (context->getHairlineSize ());
|
||||
context->setLineStyle (kLineSolid);
|
||||
context->setDrawMode (kAliasing);
|
||||
r = size;
|
||||
r.left = r.right - (getGradientIconWidth ());
|
||||
r.offset (-0.5, -0.5);
|
||||
r.inset (3, 2);
|
||||
SharedPointer<CGraphicsPath> path = owned (context->createGraphicsPath ());
|
||||
path->addRect (r);
|
||||
path->closeSubpath ();
|
||||
context->fillLinearGradient (path, *gradient, r.getTopLeft (), r.getTopRight ());
|
||||
context->drawGraphicsPath (path, CDrawContext::kPathStroked);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIGradientsDataSource::dbCellSetupTextEdit (int32_t row, int32_t column, CTextEdit* control, CDataBrowser* browser)
|
||||
{
|
||||
UIBaseDataSource::dbCellSetupTextEdit(row, column, control, browser);
|
||||
CRect r (control->getViewSize ());
|
||||
r.right -= getGradientIconWidth ();
|
||||
control->setViewSize (r);
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool UIGradientsDataSource::performNameChange (UTF8StringPtr oldName, UTF8StringPtr newName)
|
||||
{
|
||||
actionPerformer->performGradientNameChange (oldName, newName);
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
UIGradientsController::UIGradientsController (IController* baseController, UIDescription* description, IActionPerformer* actionPerformer)
|
||||
: DelegationController (baseController)
|
||||
, editDescription (description)
|
||||
, actionPerformer (actionPerformer)
|
||||
, dataSource (nullptr)
|
||||
{
|
||||
dataSource = new UIGradientsDataSource (editDescription, actionPerformer, this);
|
||||
UIEditController::setupDataSource (dataSource);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
UIGradientsController::~UIGradientsController ()
|
||||
{
|
||||
dataSource->forget ();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
CView* UIGradientsController::createView (const UIAttributes& attributes, const IUIDescription* description)
|
||||
{
|
||||
const std::string* name = attributes.getAttributeValue (IUIDescription::kCustomViewName);
|
||||
if (name)
|
||||
{
|
||||
if (*name == "GradientsBrowser")
|
||||
{
|
||||
CDataBrowser* dataBrowser = new CDataBrowser (CRect (0, 0, 0, 0), dataSource, CDataBrowser::kDrawRowLines|CScrollView::kHorizontalScrollbar|CScrollView::kVerticalScrollbar);
|
||||
return dataBrowser;
|
||||
}
|
||||
}
|
||||
return DelegationController::createView (attributes, description);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
CView* UIGradientsController::verifyView (CView* view, const UIAttributes& attributes, const IUIDescription* description)
|
||||
{
|
||||
CControl* control = dynamic_cast<CControl*> (view);
|
||||
if (control)
|
||||
{
|
||||
auto searchField = dynamic_cast<CSearchTextEdit*> (control);
|
||||
if (searchField && searchField->getTag () == kSearchTag)
|
||||
{
|
||||
dataSource->setSearchFieldControl (searchField);
|
||||
return searchField;
|
||||
}
|
||||
else if (control->getTag () == kEditTag)
|
||||
{
|
||||
editButton = control;
|
||||
editButton->setMouseEnabled (false);
|
||||
}
|
||||
}
|
||||
return controller->verifyView (view, attributes, description);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
IControlListener* UIGradientsController::getControlListener (UTF8StringPtr name)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIGradientsController::valueChanged (CControl* pControl)
|
||||
{
|
||||
switch (pControl->getTag ())
|
||||
{
|
||||
case kAddTag:
|
||||
{
|
||||
if (pControl->getValue () == pControl->getMax ())
|
||||
dataSource->add ();
|
||||
break;
|
||||
}
|
||||
case kRemoveTag:
|
||||
{
|
||||
if (pControl->getValue () == pControl->getMax ())
|
||||
dataSource->remove ();
|
||||
break;
|
||||
}
|
||||
case kEditTag:
|
||||
{
|
||||
if (pControl->getValue () == pControl->getMax ())
|
||||
showEditDialog ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIGradientsController::dbSelectionChanged (int32_t selectedRow, GenericStringListDataBrowserSource* source)
|
||||
{
|
||||
if (dataSource)
|
||||
{
|
||||
CGradient* gradient = dataSource->getSelectedGradient ();
|
||||
if (editButton)
|
||||
editButton->setMouseEnabled (gradient ? true : false);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIGradientsController::dbRowDoubleClick (int32_t row, GenericStringListDataBrowserSource* source)
|
||||
{
|
||||
showEditDialog ();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIGradientsController::showEditDialog ()
|
||||
{
|
||||
UIDialogController* dc = new UIDialogController (this, editButton->getFrame ());
|
||||
auto fsController = makeOwned<UIGradientEditorController> (
|
||||
dataSource->getSelectedGradientName (), dataSource->getSelectedGradient (), editDescription,
|
||||
actionPerformer);
|
||||
dc->run ("gradient.editor", "Gradient Editor", "OK", "Cancel", fsController,
|
||||
UIEditController::getEditorDescription ());
|
||||
}
|
||||
|
||||
} // VSTGUI
|
||||
|
||||
#endif // VSTGUI_LIVE_EDITING
|
||||
@@ -0,0 +1,54 @@
|
||||
// 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 "../uidescription.h"
|
||||
|
||||
#if VSTGUI_LIVE_EDITING
|
||||
|
||||
#include "../delegationcontroller.h"
|
||||
#include "../../lib/cdatabrowser.h"
|
||||
#include "../../lib/genericstringlistdatabrowsersource.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
class UIGradientsDataSource;
|
||||
class IActionPerformer;
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class UIGradientsController : public NonAtomicReferenceCounted,
|
||||
public DelegationController,
|
||||
public GenericStringListDataBrowserSourceSelectionChanged
|
||||
{
|
||||
public:
|
||||
UIGradientsController (IController* baseController, UIDescription* description, IActionPerformer* actionPerformer);
|
||||
~UIGradientsController () override;
|
||||
|
||||
protected:
|
||||
CView* createView (const UIAttributes& attributes, const IUIDescription* description) override;
|
||||
CView* verifyView (CView* view, const UIAttributes& attributes, const IUIDescription* description) override;
|
||||
IControlListener* getControlListener (UTF8StringPtr name) override;
|
||||
void valueChanged (CControl* pControl) override;
|
||||
void dbSelectionChanged (int32_t selectedRow, GenericStringListDataBrowserSource* source) override;
|
||||
void dbRowDoubleClick (int32_t row, GenericStringListDataBrowserSource* source) override;
|
||||
|
||||
void showEditDialog ();
|
||||
|
||||
SharedPointer<UIDescription> editDescription;
|
||||
SharedPointer<CControl> editButton;
|
||||
IActionPerformer* actionPerformer;
|
||||
UIGradientsDataSource* dataSource;
|
||||
|
||||
enum {
|
||||
kAddTag = 0,
|
||||
kRemoveTag,
|
||||
kSearchTag,
|
||||
kEditTag
|
||||
};
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
|
||||
#endif // VSTGUI_LIVE_EDITING
|
||||
@@ -0,0 +1,38 @@
|
||||
// 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 "../../lib/cpoint.h"
|
||||
|
||||
#if VSTGUI_LIVE_EDITING
|
||||
|
||||
#include "igridprocessor.h"
|
||||
#include <cmath>
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class UIGrid : public IGridProcessor, public NonAtomicReferenceCounted
|
||||
{
|
||||
public:
|
||||
UIGrid (const CPoint& size = CPoint (10, 10)) : size (size) {}
|
||||
|
||||
void process (CPoint& p) override
|
||||
{
|
||||
auto x = static_cast<int32_t> (std::round (p.x / size.x));
|
||||
p.x = x * size.x;
|
||||
auto y = static_cast<int32_t> (std::round (p.y / size.y));
|
||||
p.y = y * size.y;
|
||||
}
|
||||
|
||||
virtual void setSize (const CPoint& p) { size = p; }
|
||||
const CPoint& getSize () const { return size; }
|
||||
protected:
|
||||
CPoint size;
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
|
||||
#endif // VSTGUI_LIVE_EDITING
|
||||
@@ -0,0 +1,293 @@
|
||||
// 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 "uigridcontroller.h"
|
||||
|
||||
#if VSTGUI_LIVE_EDITING
|
||||
|
||||
#include "../../lib/algorithm.h"
|
||||
#include "../../lib/controls/coptionmenu.h"
|
||||
#include "../../lib/controls/cstringlist.h"
|
||||
#include "../../lib/platform/platformfactory.h"
|
||||
#include "../uiattributes.h"
|
||||
#include "uieditcontroller.h"
|
||||
#include <array>
|
||||
#include <sstream>
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
UIGridController::UIGridController (IController* baseController, UIDescription* description)
|
||||
: DelegationController (baseController), editDescription (description)
|
||||
{
|
||||
auto attributes = editDescription->getCustomAttributes ("UIGridController", true);
|
||||
if (attributes)
|
||||
attributes->getPointAttribute ("Size", size);
|
||||
loadDefGrids ();
|
||||
if (defGrids.empty ())
|
||||
{
|
||||
defGrids = {{1., 1.}, {5., 5.}, {10., 10.}, {12., 12.}, {15., 15.}};
|
||||
auto it = std::find (defGrids.begin (), defGrids.end (), getSize ());
|
||||
if (it == defGrids.end ())
|
||||
defGrids.emplace_back (getSize ());
|
||||
saveDefGrids ();
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
UIGridController::~UIGridController ()
|
||||
{
|
||||
saveDefGrids ();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIGridController::setSize (const CPoint& p)
|
||||
{
|
||||
UIGrid::setSize (p);
|
||||
if (auto attributes = editDescription->getCustomAttributes ("UIGridController", true))
|
||||
attributes->setPointAttribute ("Size", size);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIGridController::valueChanged (CControl* control)
|
||||
{
|
||||
switch (control->getTag ())
|
||||
{
|
||||
case kGridAddTag:
|
||||
{
|
||||
if (control->getValue () == control->getMin ())
|
||||
break;
|
||||
defGrids.push_back ({2., 2.});
|
||||
gridList->setMax (static_cast<float> (defGrids.size () - 1));
|
||||
gridList->setValue (gridList->getMax ());
|
||||
gridList->valueChanged ();
|
||||
break;
|
||||
}
|
||||
case kGridRemoveTag:
|
||||
{
|
||||
if (control->getValue () == control->getMin ())
|
||||
break;
|
||||
auto index = gridList->getIntValue ();
|
||||
if (index > 0)
|
||||
{
|
||||
auto it = defGrids.begin ();
|
||||
std::advance (it, index);
|
||||
defGrids.erase (it);
|
||||
gridList->setMax (static_cast<float> (defGrids.size () - 1));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kGridXTag:
|
||||
{
|
||||
auto index = gridList->getIntValue ();
|
||||
if (index > 0)
|
||||
{
|
||||
defGrids[index].x = control->getValue ();
|
||||
gridList->invalidRow (index);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kGridYTag:
|
||||
{
|
||||
auto index = gridList->getIntValue ();
|
||||
if (index > 0)
|
||||
{
|
||||
defGrids[index].y = control->getValue ();
|
||||
gridList->invalidRow (index);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kGridListTag:
|
||||
{
|
||||
auto index = gridList->getIntValue ();
|
||||
if (gridXEdit)
|
||||
gridXEdit->setValue (static_cast<float> (defGrids[index].x));
|
||||
if (gridYEdit)
|
||||
gridYEdit->setValue (static_cast<float> (defGrids[index].y));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
CView* UIGridController::verifyView (CView* view, const UIAttributes& attributes,
|
||||
const IUIDescription* description)
|
||||
{
|
||||
if (auto menu = dynamic_cast<COptionMenu*> (view))
|
||||
{
|
||||
if (menu->getTag () == kGridMenuTag)
|
||||
{
|
||||
gridMenu = menu;
|
||||
setupMenu ();
|
||||
}
|
||||
}
|
||||
else if (auto listControl = dynamic_cast<CListControl*> (view))
|
||||
{
|
||||
if (listControl->getTag () == kGridListTag)
|
||||
{
|
||||
if (auto drawer = dynamic_cast<StringListControlDrawer*> (listControl->getDrawer ()))
|
||||
{
|
||||
drawer->setStringProvider ([this] (int32_t row) {
|
||||
return getPlatformFactory ().createString (
|
||||
pointToDisplayString (defGrids[row]));
|
||||
});
|
||||
}
|
||||
gridList = listControl;
|
||||
gridList->setMax (static_cast<float> (defGrids.size () - 1));
|
||||
}
|
||||
}
|
||||
else if (auto textEdit = dynamic_cast<CTextEdit*> (view))
|
||||
{
|
||||
if (textEdit->getTag () == kGridXTag)
|
||||
{
|
||||
gridXEdit = textEdit;
|
||||
setupTextEdit (textEdit);
|
||||
}
|
||||
else if (textEdit->getTag () == kGridYTag)
|
||||
{
|
||||
gridYEdit = textEdit;
|
||||
setupTextEdit (textEdit);
|
||||
}
|
||||
}
|
||||
return DelegationController::verifyView (view, attributes, description);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
IControlListener* UIGridController::getControlListener (UTF8StringPtr name)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIGridController::onDialogButton1Clicked (UIDialogController*)
|
||||
{
|
||||
gridList = nullptr;
|
||||
gridXEdit = nullptr;
|
||||
gridYEdit = nullptr;
|
||||
setupMenu ();
|
||||
saveDefGrids ();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIGridController::onDialogButton2Clicked (UIDialogController*)
|
||||
{
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIGridController::onDialogShow (UIDialogController*)
|
||||
{
|
||||
if (gridList)
|
||||
gridList->valueChanged ();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIGridController::loadDefGrids ()
|
||||
{
|
||||
auto attributes = editDescription->getCustomAttributes ("UIGridController", true);
|
||||
if (!attributes)
|
||||
return;
|
||||
UIAttributes::StringArray strings;
|
||||
if (!attributes->getStringArrayAttribute ("Grids", strings))
|
||||
return;
|
||||
for (auto& str : strings)
|
||||
{
|
||||
auto pos = str.find_first_of ('x');
|
||||
if (pos == std::string::npos)
|
||||
continue;
|
||||
str[pos] = ',';
|
||||
CPoint p;
|
||||
if (UIAttributes::stringToPoint (str, p))
|
||||
defGrids.emplace_back (p);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIGridController::saveDefGrids ()
|
||||
{
|
||||
if (defGrids.empty ())
|
||||
return;
|
||||
auto attributes = editDescription->getCustomAttributes ("UIGridController", true);
|
||||
if (!attributes)
|
||||
return;
|
||||
UIAttributes::StringArray strings;
|
||||
for (auto p : defGrids)
|
||||
{
|
||||
std::string str = UIAttributes::pointToString (p);
|
||||
auto pos = str.find_first_of (',');
|
||||
if (pos == std::string::npos)
|
||||
continue;
|
||||
str[pos] = 'x';
|
||||
strings.emplace_back (str);
|
||||
}
|
||||
attributes->setStringArrayAttribute ("Grids", strings);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
UTF8String UIGridController::pointToDisplayString (const CPoint& p) const
|
||||
{
|
||||
if (p == CPoint (1., 1.))
|
||||
return "Off";
|
||||
auto str = toString (static_cast<int32_t> (p.x));
|
||||
str += "x";
|
||||
str += toString (static_cast<int32_t> (p.y));
|
||||
return str;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIGridController::setupMenu ()
|
||||
{
|
||||
std::sort (defGrids.begin (), defGrids.end (),
|
||||
[] (const CPoint& lhs, const CPoint& rhs) { return lhs.x * lhs.y < rhs.x * rhs.y; });
|
||||
gridMenu->removeAllEntry ();
|
||||
for (auto& p : defGrids)
|
||||
{
|
||||
auto item = new CCommandMenuItem (CCommandMenuItem::Desc {pointToDisplayString (p)});
|
||||
gridMenu->addEntry (item);
|
||||
item->setActions ([this, p] (CCommandMenuItem*) { setSize (p); });
|
||||
}
|
||||
gridMenu->addSeparator ();
|
||||
auto item = new CCommandMenuItem (CCommandMenuItem::Desc {"Setup..."});
|
||||
gridMenu->addEntry (item);
|
||||
item->setActions ([this] (CCommandMenuItem*) {
|
||||
syncMenuValueAndSize ();
|
||||
auto dc = new UIDialogController (this, gridMenu->getFrame ());
|
||||
dc->run ("grid.dialog", "Grid Setup", "Close", nullptr, this,
|
||||
UIEditController::getEditorDescription ());
|
||||
});
|
||||
syncMenuValueAndSize ();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIGridController::syncMenuValueAndSize ()
|
||||
{
|
||||
if (!gridMenu)
|
||||
return;
|
||||
|
||||
auto index = indexOf (defGrids.begin (), defGrids.end (), getSize ());
|
||||
if (!index)
|
||||
{
|
||||
gridMenu->setValue (0.f);
|
||||
setSize (defGrids[0]);
|
||||
return;
|
||||
}
|
||||
gridMenu->setValue (static_cast<float> (*index));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIGridController::setupTextEdit (CTextEdit* te) const
|
||||
{
|
||||
te->setPrecision (0);
|
||||
te->setStringToValueFunction ([] (UTF8StringPtr txt, float& result, CTextEdit* textEdit) {
|
||||
if (auto value = UTF8StringView (txt).toNumber<float> ())
|
||||
{
|
||||
result = *value;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
} // VSTGUI
|
||||
|
||||
#endif // VSTGUI_LIVE_EDITING
|
||||
@@ -0,0 +1,64 @@
|
||||
// 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 "../uidescription.h"
|
||||
|
||||
#if VSTGUI_LIVE_EDITING
|
||||
|
||||
#include "uigrid.h"
|
||||
#include "uidialogcontroller.h"
|
||||
#include "../delegationcontroller.h"
|
||||
#include "../../lib/controls/ctextedit.h"
|
||||
#include <vector>
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class UIGridController : public UIGrid, public DelegationController, public IDialogController
|
||||
{
|
||||
public:
|
||||
UIGridController (IController* baseController, UIDescription* description);
|
||||
~UIGridController () override;
|
||||
|
||||
protected:
|
||||
void valueChanged (CControl* pControl) override;
|
||||
CView* verifyView (CView* view, const UIAttributes& attributes, const IUIDescription* description) override;
|
||||
IControlListener* getControlListener (UTF8StringPtr name) override;
|
||||
void setSize (const CPoint& p) override;
|
||||
|
||||
void onDialogButton1Clicked (UIDialogController*) override;
|
||||
void onDialogButton2Clicked (UIDialogController*) override;
|
||||
void onDialogShow (UIDialogController*) override;
|
||||
|
||||
void syncMenuValueAndSize ();
|
||||
void loadDefGrids ();
|
||||
void saveDefGrids ();
|
||||
UTF8String pointToDisplayString (const CPoint& p) const;
|
||||
void setupTextEdit (CTextEdit* te) const;
|
||||
void setupMenu ();
|
||||
|
||||
SharedPointer<UIDescription> editDescription;
|
||||
SharedPointer<COptionMenu> gridMenu;
|
||||
SharedPointer<CListControl> gridList;
|
||||
SharedPointer<CTextEdit> gridXEdit;
|
||||
SharedPointer<CTextEdit> gridYEdit;
|
||||
|
||||
std::vector<CPoint> defGrids;
|
||||
|
||||
enum {
|
||||
kGridMenuTag,
|
||||
kGridListTag,
|
||||
kGridAddTag,
|
||||
kGridRemoveTag,
|
||||
kGridXTag,
|
||||
kGridYTag
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
|
||||
#endif // VSTGUI_LIVE_EDITING
|
||||
@@ -0,0 +1,55 @@
|
||||
// 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 "uioverlayview.h"
|
||||
|
||||
#if VSTGUI_LIVE_EDITING
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
namespace VSTGUI {
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
UIOverlayView::UIOverlayView (CViewContainer* view)
|
||||
: CView ({}), targetView (view), targetViewParent (view->getParentView ())
|
||||
{
|
||||
setMouseEnabled (false);
|
||||
targetViewParent->registerViewListener (this);
|
||||
targetView->registerViewListener (this);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
UIOverlayView::~UIOverlayView ()
|
||||
{
|
||||
targetViewParent->unregisterViewListener (this);
|
||||
targetView->unregisterViewListener (this);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool UIOverlayView::attached (CView* parent)
|
||||
{
|
||||
auto result = CView::attached (parent);
|
||||
viewSizeChanged (targetViewParent, {});
|
||||
return result;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UIOverlayView::viewSizeChanged (CView* view, const CRect& oldSize)
|
||||
{
|
||||
if (view == targetView)
|
||||
invalid ();
|
||||
CRect r = targetView->getVisibleViewSize ();
|
||||
CPoint p;
|
||||
targetViewParent->localToFrame (p);
|
||||
r.offset (p.x, p.y);
|
||||
if (getViewSize () != r)
|
||||
{
|
||||
setViewSize (r);
|
||||
invalid ();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // VSTGUI
|
||||
|
||||
#endif // VSTGUI_LIVE_EDITING
|
||||
@@ -0,0 +1,37 @@
|
||||
// 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 "../../lib/vstguibase.h"
|
||||
|
||||
#if VSTGUI_LIVE_EDITING
|
||||
|
||||
#include "../../lib/cviewcontainer.h"
|
||||
#include "../../lib/iviewlistener.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
class UIOverlayView : public CView, public ViewListenerAdapter
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
{
|
||||
public:
|
||||
UIOverlayView (CViewContainer* view);
|
||||
~UIOverlayView () override;
|
||||
|
||||
bool attached (CView* parent) override;
|
||||
void viewSizeChanged (CView* view, const CRect& oldSize) override;
|
||||
|
||||
protected:
|
||||
CViewContainer* getTargetView () const { return targetView; }
|
||||
|
||||
private:
|
||||
CViewContainer* targetView;
|
||||
CView* targetViewParent;
|
||||
};
|
||||
|
||||
} // VSTGUI
|
||||
|
||||
#endif // VSTGUI_LIVE_EDITING
|
||||
@@ -0,0 +1,342 @@
|
||||
// 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
|
||||
|
||||
#if VSTGUI_LIVE_EDITING
|
||||
|
||||
#include "uiselection.h"
|
||||
#include "../iviewfactory.h"
|
||||
#include "../uidescription.h"
|
||||
#include "../cstream.h"
|
||||
#include "../uiattributes.h"
|
||||
#include "../../lib/cviewcontainer.h"
|
||||
#include "../../lib/cframe.h"
|
||||
#include "../../lib/ccolor.h"
|
||||
#include "../../lib/coffscreencontext.h"
|
||||
#include "../../lib/clayeredviewcontainer.h"
|
||||
#include "../../lib/cbitmap.h"
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
UISelection::UISelection (int32_t style)
|
||||
: style (style)
|
||||
{
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
UISelection::~UISelection ()
|
||||
{
|
||||
clear ();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
auto UISelection::begin () const -> const_iterator
|
||||
{
|
||||
return viewList.begin ();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
auto UISelection::end () const -> const_iterator
|
||||
{
|
||||
return viewList.end ();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
auto UISelection::rbegin () const -> const_reverse_iterator
|
||||
{
|
||||
return viewList.rbegin ();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
auto UISelection::rend () const -> const_reverse_iterator
|
||||
{
|
||||
return viewList.rend ();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UISelection::setStyle (int32_t _style)
|
||||
{
|
||||
style = _style;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UISelection::add (CView* view)
|
||||
{
|
||||
vstgui_assert (view, "view cannot be nullptr");
|
||||
willChange ();
|
||||
if (style == kSingleSelectionStyle)
|
||||
clear ();
|
||||
viewList.emplace_back (view);
|
||||
didChange ();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UISelection::remove (CView* view)
|
||||
{
|
||||
vstgui_assert (view, "view cannot be nullptr");
|
||||
if (contains (view))
|
||||
{
|
||||
willChange ();
|
||||
viewList.remove (view);
|
||||
didChange ();
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UISelection::setExclusive (CView* view)
|
||||
{
|
||||
vstgui_assert (view, "view cannot be nullptr");
|
||||
if (viewList.size () == 1 && viewList.front () == view)
|
||||
return;
|
||||
UISelection::DeferChange dc (*this);
|
||||
viewList.clear ();
|
||||
add (view);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UISelection::clear ()
|
||||
{
|
||||
willChange ();
|
||||
viewList.clear ();
|
||||
didChange ();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool UISelection::contains (CView* view) const
|
||||
{
|
||||
return std::find (begin (), end (), view) != end ();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool UISelection::containsParent (CView* view) const
|
||||
{
|
||||
CView* parent = view->getParentView ();
|
||||
if (parent)
|
||||
{
|
||||
if (contains (parent))
|
||||
return true;
|
||||
return containsParent (parent);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
int32_t UISelection::total () const
|
||||
{
|
||||
return (int32_t)viewList.size ();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
CView* UISelection::first () const
|
||||
{
|
||||
if (!viewList.empty ())
|
||||
return *begin ();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
CRect UISelection::getBounds () const
|
||||
{
|
||||
CRect result;
|
||||
if (viewList.empty ())
|
||||
return result;
|
||||
const_iterator it = begin ();
|
||||
result = getGlobalViewCoordinates (*it);
|
||||
++it;
|
||||
while (it != end ())
|
||||
{
|
||||
CRect vs = getGlobalViewCoordinates (*it);
|
||||
result.unite (vs);
|
||||
++it;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
CRect UISelection::getGlobalViewCoordinates (CView* view)
|
||||
{
|
||||
CRect result = view->translateToGlobal (view->getViewSize ());
|
||||
if (auto frame = view->getFrame ())
|
||||
return frame->getTransform ().inverse ().transform (result);
|
||||
return result;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UISelection::moveBy (const CPoint& p)
|
||||
{
|
||||
viewsWillChange ();
|
||||
const_iterator it = begin ();
|
||||
while (it != end ())
|
||||
{
|
||||
if (!containsParent ((*it)))
|
||||
{
|
||||
CRect viewRect = (*it)->getViewSize ();
|
||||
viewRect.offset (p.x, p.y);
|
||||
(*it)->setViewSize (viewRect);
|
||||
(*it)->setMouseableArea (viewRect);
|
||||
}
|
||||
it++;
|
||||
}
|
||||
viewsDidChange ();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UISelection::sizeBy (const CRect& r)
|
||||
{
|
||||
viewsWillChange ();
|
||||
for (auto view : *this)
|
||||
{
|
||||
auto viewSize = view->getViewSize ();
|
||||
viewSize.left += r.left;
|
||||
viewSize.top += r.top;
|
||||
viewSize.right += r.right;
|
||||
viewSize.bottom += r.bottom;
|
||||
view->setViewSize (viewSize);
|
||||
view->setMouseableArea (viewSize);
|
||||
}
|
||||
viewsDidChange ();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UISelection::invalidRects () const
|
||||
{
|
||||
const_iterator it = begin ();
|
||||
while (it != end ())
|
||||
{
|
||||
if (!containsParent ((*it)))
|
||||
{
|
||||
(*it)->invalid ();
|
||||
}
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UISelection::willChange ()
|
||||
{
|
||||
if (++inChange == 1)
|
||||
forEachListener ([this] (IUISelectionListener* l) { l->selectionWillChange (this); });
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UISelection::didChange ()
|
||||
{
|
||||
if (--inChange == 0)
|
||||
forEachListener ([this] (IUISelectionListener* l) { l->selectionDidChange (this); });
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UISelection::viewsWillChange ()
|
||||
{
|
||||
if (++inViewsChange == 1)
|
||||
{
|
||||
invalidRects ();
|
||||
forEachListener ([this] (IUISelectionListener* l) { l->selectionViewsWillChange (this); });
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void UISelection::viewsDidChange ()
|
||||
{
|
||||
if (--inViewsChange == 0)
|
||||
{
|
||||
invalidRects ();
|
||||
forEachListener ([this] (IUISelectionListener* l) { l->selectionViewsDidChange (this); });
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool UISelection::store (OutputStream& stream, IUIDescription* uiDescription)
|
||||
{
|
||||
UIDescription* desc = dynamic_cast<UIDescription*>(uiDescription);
|
||||
if (desc)
|
||||
{
|
||||
std::list<CView*> views;
|
||||
for (auto view : *this)
|
||||
{
|
||||
if (!containsParent (view))
|
||||
{
|
||||
views.emplace_back (view);
|
||||
}
|
||||
}
|
||||
|
||||
auto attr = makeOwned<UIAttributes> ();
|
||||
attr->setPointAttribute ("selection-drag-offset", dragOffset);
|
||||
return desc->storeViews (views, stream, attr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool UISelection::restore (InputStream& stream, IUIDescription* uiDescription)
|
||||
{
|
||||
clear ();
|
||||
UIDescription* desc = dynamic_cast<UIDescription*>(uiDescription);
|
||||
if (desc)
|
||||
{
|
||||
UIAttributes* attr = nullptr;
|
||||
if (desc->restoreViews (stream, viewList, &attr))
|
||||
{
|
||||
if (attr)
|
||||
{
|
||||
attr->getPointAttribute ("selection-drag-offset", dragOffset);
|
||||
attr->forget ();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
SharedPointer<CBitmap> createBitmapFromSelection (UISelection* selection, CFrame* frame,
|
||||
CViewContainer* anchorView)
|
||||
{
|
||||
CRect selectionRect = selection->getBounds ();
|
||||
auto scaleFactor = frame->getScaleFactor ();
|
||||
auto bitmap = renderBitmapOffscreen (selectionRect.getSize (), scaleFactor, [&] (auto& context) {
|
||||
CGraphicsTransform tm;
|
||||
CGraphicsTransform invTm;
|
||||
if (anchorView)
|
||||
{
|
||||
tm = anchorView->getTransform ();
|
||||
invTm = tm.inverse ();
|
||||
invTm.transform (selectionRect);
|
||||
tm = tm * CGraphicsTransform ().translate (-selectionRect.left, -selectionRect.top);
|
||||
}
|
||||
double originalZoom = 1.;
|
||||
if (anchorView && anchorView->isAttached ())
|
||||
{
|
||||
// reset frame zoom
|
||||
originalZoom = anchorView->getFrame ()->getZoom ();
|
||||
anchorView->getFrame ()->setZoom (1.);
|
||||
}
|
||||
CDrawContext::Transform tr (context, tm);
|
||||
for (auto view : *selection)
|
||||
{
|
||||
if (!selection->containsParent (view))
|
||||
{
|
||||
CPoint p;
|
||||
p = view->translateToGlobal (p);
|
||||
if (anchorView)
|
||||
invTm.transform (p);
|
||||
CDrawContext::Transform transform (context,
|
||||
CGraphicsTransform ().translate (p.x, p.y));
|
||||
context.setClipRect (view->getViewSize ());
|
||||
view->drawRect (&context, view->getViewSize ());
|
||||
}
|
||||
}
|
||||
if (anchorView && anchorView->isAttached ())
|
||||
{
|
||||
anchorView->getFrame ()->setZoom (originalZoom);
|
||||
}
|
||||
});
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
} // VSTGUI
|
||||
|
||||
#endif // VSTGUI_LIVE_EDITING
|
||||