summaryrefslogtreecommitdiff
path: root/libs/surfaces/maschine2/m2_button.h
diff options
context:
space:
mode:
Diffstat (limited to 'libs/surfaces/maschine2/m2_button.h')
-rw-r--r--libs/surfaces/maschine2/m2_button.h220
1 files changed, 220 insertions, 0 deletions
diff --git a/libs/surfaces/maschine2/m2_button.h b/libs/surfaces/maschine2/m2_button.h
new file mode 100644
index 0000000000..cfe26b12d0
--- /dev/null
+++ b/libs/surfaces/maschine2/m2_button.h
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2016 Robin Gareus <robin@gareus.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _ardour_surfaces_m2button_h_
+#define _ardour_surfaces_m2button_h_
+
+#include <stdint.h>
+#include "gtkmm2ext/colors.h"
+#include "pbd/signals.h"
+
+namespace ArdourSurface {
+
+class M2ButtonInterface
+{
+ public:
+ M2ButtonInterface () {}
+ virtual ~M2ButtonInterface () {}
+
+ /* user API */
+ PBD::Signal1<void, bool> changed;
+ PBD::Signal0<void> pressed;
+ PBD::Signal0<void> released;
+
+ virtual void set_blinking (bool) {}
+ virtual void set_color (uint32_t rgba) {}
+
+ virtual bool is_pressed () const { return false; }
+ virtual bool active () const { return is_pressed (); }
+
+ virtual void ignore_release () {}
+
+ // TODO allow to suspend *next* release signal
+ // e.g. press + hold "grid", move encoder -> release "grid" -> noop
+
+ /* internal API - called from device thread */
+ virtual bool set_active (bool a) { return false; }
+ virtual uint8_t lightness (float) const { return 0; }
+ virtual uint32_t color (float) const { return 0; }
+};
+
+class M2Button : public M2ButtonInterface
+{
+ public:
+ M2Button ()
+ : M2ButtonInterface ()
+ , _pressed (false)
+ , _blink (false)
+ , _ignore_release (false)
+ , _lightness (0)
+ , _rgba (0)
+ {}
+
+ /* user API */
+ void set_blinking (bool en) {
+ _blink = en;
+ }
+
+ virtual void set_color (uint32_t rgba) {
+ _rgba = rgba;
+ /* 7 bit color */
+ const uint8_t r = ((rgba >> 24) & 0xff) >> 1;
+ const uint8_t g = ((rgba >> 16) & 0xff) >> 1;
+ const uint8_t b = ((rgba >> 8) & 0xff) >> 1;
+ _lightness = std::max (r, std::max (g, b));
+ }
+
+ bool is_pressed () const { return _pressed; }
+
+ void ignore_release () {
+ if (_pressed) {
+ _ignore_release = true;
+ }
+ }
+
+ /* internal API - called from device thread */
+ virtual bool set_active (bool a) {
+ if (a == _pressed) {
+ return false;
+ }
+ _pressed = a;
+
+ if (a) {
+ pressed (); /* EMIT SIGNAL */
+ } else {
+ if (_ignore_release) {
+ _ignore_release = false;
+ } else {
+ released (); /* EMIT SIGNAL */
+ }
+ }
+ changed (a); /* EMIT SIGNAL */
+ return true;
+ }
+
+ uint8_t lightness (float blink) const {
+ if (_blink && blink >= 0.f && blink <= 1.f) {
+ return (uint8_t) floorf(blink * _lightness);
+ }
+ return _lightness;
+ }
+
+ uint32_t color (float blink) const {
+ if (_blink && blink >= 0.f && blink <= 1.f) {
+ Gtkmm2ext::HSV hsv (_rgba);
+ Gtkmm2ext::HSV s (hsv.shade (blink));
+ return s.color();
+ }
+ return _rgba;
+ }
+
+ protected:
+ bool _pressed;
+ bool _blink;
+ bool _ignore_release;
+ uint8_t _lightness;
+ uint32_t _rgba;
+};
+
+class M2StatelessButton : public M2Button
+{
+ public:
+ M2StatelessButton () : M2Button () {}
+
+ bool set_active (bool a) {
+ if (a == _pressed) {
+ return false;
+ }
+ if (a) {
+ set_color (0xffffffff);
+ } else {
+ set_color (0x000000ff);
+ }
+ return M2Button::set_active (a);
+ }
+};
+
+class M2ToggleButton : public M2Button
+{
+ public:
+ M2ToggleButton ()
+ : M2Button ()
+ , _active (false)
+ {
+ changed.connect_same_thread (changed_connection, boost::bind (&M2ToggleButton::change_event, this, _1));
+ }
+
+ PBD::Signal1<void, bool> toggled;
+ bool active () const { return _active; }
+
+ protected:
+ void change_event (bool down) {
+ if (down) { return; }
+ _active = !_active;
+ set_color (_active ? 0xffffffff : 0x000000ff);
+ toggled (_active);
+ }
+
+ PBD::ScopedConnection changed_connection;
+ bool _active;
+};
+
+class M2ToggleHoldButton : public M2Button
+{
+ public:
+ M2ToggleHoldButton ()
+ : M2Button ()
+ , _active (false)
+ , _active_on_release (false)
+ {
+ changed.connect_same_thread (changed_connection, boost::bind (&M2ToggleHoldButton::change_event, this, _1));
+ }
+
+ PBD::Signal1<void, bool> toggled;
+ bool active () const { return _active; }
+ void unset_active_on_release () { if (is_pressed ()) { _active_on_release = false; } }
+
+ protected:
+ void change_event (bool down) {
+ if (down) {
+ if (_active) {
+ _active_on_release = false;
+ return;
+ }
+ _active = true;
+ _active_on_release = true;
+ } else {
+ if (_active == _active_on_release) {
+ return;
+ }
+ _active = _active_on_release;
+ }
+
+ set_color (_active ? 0xffffffff : 0x000000ff);
+ toggled (_active);
+ }
+
+ PBD::ScopedConnection changed_connection;
+ bool _active;
+ bool _active_on_release;
+};
+
+
+} /* namespace */
+#endif /* _ardour_surfaces_m2button_h_ */
+