Skip to content

Commit

Permalink
Merge branch 'develop' into memory-leak-detector-macos
Browse files Browse the repository at this point in the history
  • Loading branch information
scheffle committed Oct 15, 2023
2 parents 10ae888 + 4e2c80b commit 5f21559
Show file tree
Hide file tree
Showing 32 changed files with 1,101 additions and 216 deletions.
54 changes: 54 additions & 0 deletions vstgui/contrib/evbutton.h
Original file line number Diff line number Diff line change
@@ -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 "../lib/iexternalview.h"
#include "../lib/cstring.h"
#include <memory>

//------------------------------------------------------------------------
namespace VSTGUI {
namespace ExternalView {

//------------------------------------------------------------------------
class Button : public ControlViewAdapter
{
public:
enum class Type
{
Checkbox,
Push,
Radio,
OnOff
};

Button (Type type, const UTF8String& title);
~Button () noexcept;

private:
bool platformViewTypeSupported (PlatformViewType type) override;
bool attach (void* parent, PlatformViewType parentViewType) override;
bool remove () override;

void setViewSize (IntRect frame, IntRect visible) override;
void setContentScaleFactor (double scaleFactor) override;

void setMouseEnabled (bool state) override;

void takeFocus () override;
void looseFocus () override;

void setTookFocusCallback (const TookFocusCallback& callback) override;

bool setValue (double value) override;
bool setEditCallbacks (const EditCallbacks& callbacks) override;

struct Impl;
std::unique_ptr<Impl> impl;
};

//------------------------------------------------------------------------
} // ExternalView
} // VSTGUI
232 changes: 232 additions & 0 deletions vstgui/contrib/evbutton_macos.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
// This file is part of VSTGUI. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE

#import "evbutton.h"
#import "externalview_nsview.h"
#import "../lib/platform/mac/macstring.h"

//------------------------------------------------------------------------
namespace VSTGUI {
namespace ExternalView {

//------------------------------------------------------------------------
struct ButtonDelegate : RuntimeObjCClass<ButtonDelegate>
{
using ActionCallback = std::function<void ()>;

static constexpr const auto ActionCallbackVarName = "ActionCallback";

static id allocAndInit (ActionCallback&& actionCallback)
{
id obj = Base::alloc ();
initWithCallbacks (obj, std::move (actionCallback));
return obj;
}

static Class CreateClass ()
{
return ObjCClassBuilder ()
.init ("ButtonDelegate", [NSObject class])
.addMethod (@selector (onAction:), onAction)
.addIvar<ActionCallback> (ActionCallbackVarName)
.finalize ();
}

static id initWithCallbacks (id self, ActionCallback&& actionCallback)
{
if ((self = makeInstance (self).callSuper<id (), id> (@selector (init))))
{
auto instance = makeInstance (self);
if (auto var = instance.getVariable<ActionCallback> (ActionCallbackVarName))
var->set (actionCallback);
}
return self;
}

static void onAction (id self, SEL cmd, id sender)
{
if (auto var = makeInstance (self).getVariable<ActionCallback> (ActionCallbackVarName))
{
const auto& callback = var->get ();
if (callback)
callback ();
}
}
};

//------------------------------------------------------------------------
struct Button::Impl : ExternalNSViewBase<NSButton>,
IControlViewExtension
{
using Base::Base;

id delegate {nil};
EditCallbacks callbacks {};

#if !__has_feature(objc_arc)
~Impl () noexcept
{
if (delegate)
[delegate release];
}
#endif

bool setValue (double value) override
{
if (value < 0.5)
view.state = NSControlStateValueOff;
else if (value == 0.5)
view.state = NSControlStateValueMixed;
else
view.state = NSControlStateValueOn;
return true;
}

bool setEditCallbacks (const EditCallbacks& editCallbacks) override
{
callbacks = editCallbacks;
return true;
}
};

//------------------------------------------------------------------------
Button::Button (Type type, const UTF8String& inTitle)
{
NSString* title = fromUTF8String<NSString*> (inTitle);
ButtonDelegate::ActionCallback actionCallback = [this] () {
double value = 0.;
switch (impl->view.state)
{
case NSControlStateValueOn:
value = 1.;
break;
case NSControlStateValueOff:
value = 0.;
break;
case NSControlStateValueMixed:
value = 0.5;
break;
}
if (impl->callbacks.beginEdit)
impl->callbacks.beginEdit ();
if (impl->callbacks.performEdit)
impl->callbacks.performEdit (value);
if (impl->callbacks.endEdit)
impl->callbacks.endEdit ();
};
NSButton* button = {};
switch (type)
{
case Type::Checkbox:
{
button = [NSButton checkboxWithTitle:title target:nullptr action:nullptr];
break;
}
case Type::Push:
{
button = [NSButton buttonWithTitle:title target:nullptr action:nullptr];
[button setButtonType:NSButtonTypeMomentaryLight];
actionCallback = [this] () {
if (impl->callbacks.beginEdit)
impl->callbacks.beginEdit ();
if (impl->callbacks.performEdit)
impl->callbacks.performEdit (1.);
if (impl->callbacks.endEdit)
impl->callbacks.endEdit ();
if (impl->callbacks.beginEdit)
impl->callbacks.beginEdit ();
if (impl->callbacks.performEdit)
impl->callbacks.performEdit (0.);
if (impl->callbacks.endEdit)
impl->callbacks.endEdit ();
};
break;
}
case Type::OnOff:
{
button = [NSButton buttonWithTitle:title target:nullptr action:nullptr];
[button setButtonType:NSButtonTypePushOnPushOff];
break;
}
case Type::Radio:
{
button = [NSButton radioButtonWithTitle:title target:nullptr action:nullptr];
break;
}
}
[button sizeToFit];
impl = std::make_unique<Impl> (button);
impl->delegate = ButtonDelegate::allocAndInit (std::move (actionCallback));
impl->view.target = impl->delegate;
impl->view.action = @selector (onAction:);
[impl->container addSubview:impl->view];
[button retain];
}

//------------------------------------------------------------------------
Button::~Button () noexcept = default;

//------------------------------------------------------------------------
bool Button::platformViewTypeSupported (PlatformViewType type)
{
return impl->platformViewTypeSupported (type);
}

//------------------------------------------------------------------------
bool Button::attach (void* parent, PlatformViewType parentViewType)
{
return impl->attach (parent, parentViewType);
}

//------------------------------------------------------------------------
bool Button::remove () { return impl->remove (); }

//------------------------------------------------------------------------
void Button::setViewSize (IntRect frame, IntRect visible)
{
static constexpr const NSControlSize controlSizes[] = {NSControlSizeRegular, NSControlSizeSmall,
NSControlSizeMini};
for (auto i = 0; i < std::size (controlSizes); i++)
{
impl->view.controlSize = controlSizes[i];
auto size = [impl->view sizeThatFits:NSMakeSize (frame.size.width, frame.size.height)];
if (size.height <= frame.size.height)
break;
}
impl->setViewSize (frame, visible);
}

//------------------------------------------------------------------------
void Button::setContentScaleFactor (double scaleFactor)
{
impl->setContentScaleFactor (scaleFactor);
}

//------------------------------------------------------------------------
void Button::setMouseEnabled (bool state) { impl->setMouseEnabled (state); }

//------------------------------------------------------------------------
void Button::takeFocus () { impl->takeFocus (); }

//------------------------------------------------------------------------
void Button::looseFocus () { impl->looseFocus (); }

//------------------------------------------------------------------------
void Button::setTookFocusCallback (const TookFocusCallback& callback)
{
impl->setTookFocusCallback (callback);
}

//------------------------------------------------------------------------
bool Button::setValue (double value) { return impl->setValue (value); }

//------------------------------------------------------------------------
bool Button::setEditCallbacks (const EditCallbacks& callbacks)
{
return impl->setEditCallbacks (callbacks);
}

//------------------------------------------------------------------------
} // ExternalView
} // VSTGUI
Loading

0 comments on commit 5f21559

Please sign in to comment.