aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile34
-rw-r--r--lv2_ui.h372
-rw-r--r--lvz/AEffEditor.hpp30
l---------lvz/AudioEffect.hpp1
-rw-r--r--lvz/audioeffectx.h40
-rw-r--r--lvz/gendata.cpp100
-rw-r--r--lvz/gui_wrapper.cpp211
-rw-r--r--lvz/wrapper.cpp47
-rw-r--r--src/mdaSpecMeter.cpp482
-rw-r--r--src/mdaSpecMeter.h19
-rw-r--r--src/mdaSpecMeterGUI.cpp390
-rw-r--r--src/mdaSpecMeterGUI.h36
-rw-r--r--src/mdaspecmeter.cpp416
-rw-r--r--vstgui/TODO19
-rw-r--r--vstgui/vstcontrols.cpp3651
-rw-r--r--vstgui/vstcontrols.h994
-rw-r--r--vstgui/vstgui.cpp3996
-rw-r--r--vstgui/vstgui.h1105
-rw-r--r--vstgui/vstkeycode.h104
19 files changed, 11376 insertions, 671 deletions
diff --git a/Makefile b/Makefile
index 7a12f90..1627fd2 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
-#CFLAGS = -O0 -g -ansi -pedantic -Wall -Wextra -Wshadow -Woverloaded-virtual -Wno-unused
-CFLAGS += -fPIC -DPIC -Ilvz -I. -DPLUGIN_URI_PREFIX=\"http://drobilla.net/ns/dev/mda-lv2/\"
+#CFLAGS = -O0 -g -ansi -Wall -Wextra -Wno-unused # -pedantic -Woverloaded-virtual
+CFLAGS += -fPIC -DPIC -Ilvz -Ivstgui -I. -DURI_PREFIX=\"http://drobilla.net/ns/dev/mda-lv2/\"
SYSTEMNAME = $(shell uname -s)
@@ -16,8 +16,10 @@ SYSTEM_INSTALL_DIR = /usr/lib/lv2/
LOCAL_INSTALL_DIR = /usr/local/lib/lv2/
endif
+BUILD_GUI = ! `pkg-config --exists gtk+-2.0`
+GUI_CFLAGS = $(CFLAGS) -Ivstgui `pkg-config --cflags gtk+-2.0 libpng`
-all: lvz/gendata libs data
+all: lvz/gendata libs data gui_libs
bundle:
mkdir -p ./mda.lv2
@@ -58,9 +60,16 @@ libs: bundle \
mda.lv2/mdaTracker.so \
mda.lv2/mdaTransient.so \
mda.lv2/mdaVocInput.so \
- mda.lv2/mdaVocoder.so
+ mda.lv2/mdaVocoder.so \
+ mda.lv2/mdaSpecMeter.so
-data: libs lvz/gendata
+pixmaps:
+ cp src/mdaSpecMeter.png mda.lv2
+
+gui_libs: bundle pixmaps \
+ mda.lv2/mdaSpecMeterGUI.so
+
+data: libs gui_libs lvz/gendata
cd ./mda.lv2 && ../lvz/gendata ./*.so > manifest.ttl
install:
@@ -73,6 +82,7 @@ install:
install -d $(INSTALL_DIR)/mda.lv2; \
install -m 644 ./mda.lv2/*.ttl $(INSTALL_DIR)/mda.lv2; \
install -m 755 ./mda.lv2/*.so $(INSTALL_DIR)/mda.lv2; \
+ install -m 755 ./mda.lv2/*.png $(INSTALL_DIR)/mda.lv2; \
fi
install-user:
@@ -94,12 +104,24 @@ src/%.cpp: src/%.h lvz/audioeffectx.h
lvz/gendata: lvz/gendata.cpp lvz/audioeffectx.h
$(CXX) $(CFLAGS) -ldl $< -o $@
+mda.lv2/%GUI.so: src/%GUI.cpp src/%.cpp lvz/gui_wrapper.cpp vstgui/vstgui.cpp vstgui/vstgui.h vstgui/vstcontrols.cpp vstgui/vstcontrols.h
+ if [ $(BUILD_GUI) ]; then \
+ $(CXX) $(SHARED_LDFLAGS) $(GUI_CFLAGS) \
+ -DUI_CLASS=`echo $@ | sed 's/mda.lv2\///' | sed 's/\..*//'` \
+ -DPLUGIN_CLASS=`echo $@ | sed 's/mda.lv2\///' | sed 's/\..*//' | sed 's/GUI//'` \
+ -DUI_HEADER=\"`echo $@ | sed 's/^mda.lv2/src/' | sed 's/\(.*\)\..*/\1/' | sed 's/$$/\.h/'`\" \
+ -DPLUGIN_HEADER=\"`echo $@ | sed 's/^mda.lv2/src/' | sed 's/\(.*\)\..*/\1/' | sed 's/$$/\.h/' | sed 's/GUI//'`\" \
+ -DUI_URI_SUFFIX=\"`echo $@ | sed 's/mda.lv2\///' | sed 's/^mda//' | sed 's/\..*//'`\" \
+ -DPLUGIN_URI_SUFFIX=\"`echo $@ | sed 's/mda.lv2\///' | sed 's/^mda//' | sed 's/\..*//' | sed 's/GUI//'`\" \
+ $^ -o $@; \
+ fi
+
mda.lv2/%.so: src/%.cpp lvz/wrapper.cpp
$(CXX) $(SHARED_LDFLAGS) $(CFLAGS) \
-DPLUGIN_CLASS=`echo $@ | sed 's/mda.lv2\///' | sed 's/\..*//'` \
-DPLUGIN_URI_SUFFIX=\"`echo $@ | sed 's/mda.lv2\///' | sed 's/^mda//' | sed 's/\..*//'`\" \
-DPLUGIN_HEADER=\"`echo $@ | sed 's/^mda.lv2/src/' | sed 's/\(.*\)\..*/\1/' | sed 's/$$/\.h/'`\" \
- $< lvz/wrapper.cpp -o $@
+ $^ -o $@
clean:
rm -f `find -name '*.o'`
diff --git a/lv2_ui.h b/lv2_ui.h
new file mode 100644
index 0000000..4be2c24
--- /dev/null
+++ b/lv2_ui.h
@@ -0,0 +1,372 @@
+/************************************************************************
+ *
+ * In-process UI extension for LV2
+ *
+ * Copyright (C) 2006-2008 Lars Luthman <lars.luthman@gmail.com>
+ *
+ * Based on lv2.h, which was
+ *
+ * Copyright (C) 2000-2002 Richard W.E. Furse, Paul Barton-Davis,
+ * Stefan Westerfeld
+ * Copyright (C) 2006 Steve Harris, Dave Robillard.
+ *
+ * This header is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License,
+ * or (at your option) any later version.
+ *
+ * This header 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA.
+ *
+ ***********************************************************************/
+
+/** @file
+ This extension defines an interface that can be used in LV2 plugins and
+ hosts to create UIs for plugins. The UIs are plugins that reside in
+ shared object files in an LV2 bundle and are referenced in the RDF data
+ using the triples (Turtle shown)
+<pre>
+ @@prefix uiext: <http://lv2plug.in/ns/extensions/ui#> .
+ <http://my.plugin> uiext:ui <http://my.pluginui> .
+ <http://my.plugin> a uiext:GtkUI .
+ <http://my.pluginui> uiext:binary <myui.so> .
+</pre>
+ where <http://my.plugin> is the URI of the plugin, <http://my.pluginui> is
+ the URI of the plugin UI and <myui.so> is the relative URI to the shared
+ object file. While it is possible to have the plugin UI and the plugin in
+ the same shared object file it is probably a good idea to keep them
+ separate so that hosts that don't want UIs don't have to load the UI code.
+ A UI MUST specify its class in the RDF data, in this case uiext:GtkUI. The
+ class defines what type the UI is, e.g. what graphics toolkit it uses.
+ There are no UI classes defined in this extension, those are specified
+ separately (and anyone can define their own).
+
+ (Note: the prefix above is used throughout this file for the same URI)
+
+ It's entirely possible to have multiple UIs for the same plugin, or to have
+ the UI for a plugin in a different bundle from the actual plugin - this
+ way people other than the plugin author can write plugin UIs independently
+ without editing the original plugin bundle.
+
+ Note that the process that loads the shared object file containing the UI
+ code and the process that loads the shared object file containing the
+ actual plugin implementation does not have to be the same. There are many
+ valid reasons for having the plugin and the UI in different processes, or
+ even on different machines. This means that you can _not_ use singletons
+ and global variables and expect them to refer to the same objects in the
+ UI and the actual plugin. The function callback interface defined in this
+ header is all you can expect to work.
+
+ Since the LV2 specification itself allows for extensions that may add
+ new types of data and configuration parameters that plugin authors may
+ want to control with a UI, this extension allows for meta-extensions that
+ can extend the interface between the UI and the host. These extensions
+ mirror the extensions used for plugins - there are required and optional
+ "features" that you declare in the RDF data for the UI as
+<pre>
+ <http://my.pluginui> uiext:requiredFeature <http://my.feature> .
+ <http://my.pluginui> uiext:optionalFeature <http://my.feature> .
+</pre>
+ These predicates have the same semantics as lv2:requiredFeature and
+ lv2:optionalFeature - if a UI is declaring a feature as required, the
+ host is NOT allowed to load it unless it supports that feature, and if it
+ does support a feature (required or optional) it MUST pass that feature's
+ URI and any additional data (specified by the meta-extension that defines
+ the feature) in a LV2_Feature struct (as defined in lv2.h) to the UI's
+ instantiate() function.
+
+ These features may be used to specify how to pass data between the UI
+ and the plugin port buffers - see LV2UI_Write_Function for details.
+
+ There are four features defined in this extension that hosts may want to
+ implement:
+
+<pre>
+ uiext:makeResident
+</pre>
+ If this feature is required by a UI the host MUST NEVER unload the shared
+ library containing the UI implementation during the lifetime of the host
+ process (e.g. never calling dlclose() on Linux). This feature may be
+ needed by e.g. a Gtk UI that registers its own Glib types using
+ g_type_register_static() - if it gets unloaded and then loaded again the
+ type registration will break, since there is no way to unregister the
+ types when the library is unloaded. The data pointer in the LV2_Feature
+ for this feature should always be set to NULL.
+
+<pre>
+ uiext:makeSONameResident
+</pre>
+ This feature is ELF specific - it should only be used by UIs that
+ use the ELF file format for the UI shared object files (e.g. on Linux).
+ If it is required by an UI the UI should also list a number of SO names
+ (shared object names) for libraries that the UI shared object
+ depends on and that may not be unloaded during the lifetime of the host
+ process, using the predicate @c uiext:residentSONames, like this:
+<pre>
+ <http://my.pluginui> uiext:residentSONames "libgtkmm-2.4.so.1", "libfoo.so.0"
+</pre>
+ The host MUST then make sure that the shared libraries with the given ELF
+ SO names are not unloaded when the plugin UI is, but stay loaded during
+ the entire lifetime of the host process. On Linux this can be accomplished
+ by calling dlopen() on the shared library file with that SO name and never
+ calling a matching dlclose(). However, if a plugin UI requires the
+ @c uiext:makeSONameResident feature, it MUST ALWAYS be safe for the host to
+ just never unload the shared object containing the UI implementation, i.e.
+ act as if the UI required the @c uiext:makeResident feature instead. Thus
+ the host only needs to find the shared library files corresponding to the
+ given SO names if it wants to save RAM by unloading the UI shared object
+ file when it is no longer needed. The data pointer for the LV2_Feature for
+ this feature should always be set to NULL.
+
+<pre>
+ uiext:noUserResize
+</pre>
+ If an UI requires this feature it indicates that it does not make sense
+ to let the user resize the main widget, and the host should prevent that.
+ This feature may not make sense for all UI types. The data pointer for the
+ LV2_Feature for this feature should always be set to NULL.
+
+<pre>
+ uiext:fixedSize
+</pre>
+ If an UI requires this feature it indicates the same thing as
+ uiext:noUserResize, and additionally it means that the UI will not resize
+ the main widget on its own - it will always remain the same size (e.g. a
+ pixmap based GUI). This feature may not make sense for all UI types.
+ The data pointer for the LV2_Feature for this feature should always be set
+ to NULL.
+
+
+ UIs written to this specification do not need to be threadsafe - the
+ functions defined below may only be called in the same thread as the UI
+ main loop is running in.
+
+ Note that this UI extension is NOT a lv2:Feature. There is no way for a
+ plugin to know whether the host that loads it supports UIs or not, and
+ the plugin must ALWAYS work without the UI (although it may be rather
+ useless unless it has been configured using the UI in a previous session).
+
+ A UI does not have to be a graphical widget, it could just as well be a
+ server listening for OSC input or an interface to some sort of hardware
+ device, depending on the RDF class of the UI.
+*/
+
+#ifndef LV2_UI_H
+#define LV2_UI_H
+
+#include <lv2.h>
+
+#define LV2_UI_URI "http://lv2plug.in/ns/extensions/ui"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** A pointer to some widget or other type of UI handle.
+ The actual type is defined by the type URI of the UI.
+ All the functionality provided by this extension is toolkit
+ independent, the host only needs to pass the necessary callbacks and
+ display the widget, if possible. Plugins may have several UIs, in various
+ toolkits. */
+typedef void* LV2UI_Widget;
+
+
+/** This handle indicates a particular instance of a UI.
+ It is valid to compare this to NULL (0 for C++) but otherwise the
+ host MUST not attempt to interpret it. The UI plugin may use it to
+ reference internal instance data. */
+typedef void* LV2UI_Handle;
+
+
+/** This handle indicates a particular plugin instance, provided by the host.
+ It is valid to compare this to NULL (0 for C++) but otherwise the
+ UI plugin MUST not attempt to interpret it. The host may use it to
+ reference internal plugin instance data. */
+typedef void* LV2UI_Controller;
+
+
+/** This is the type of the host-provided function that the UI can use to
+ send data to a plugin's input ports. The @c buffer parameter must point
+ to a block of data, @c buffer_size bytes large. The contents of this buffer
+ and what the host should do with it depends on the value of the @c format
+ parameter.
+
+ The @c format parameter should either be 0 or a numeric ID for a "Transfer
+ mechanism". Transfer mechanisms are Features and may be defined in
+ meta-extensions. They specify how to translate the data buffers passed
+ to this function to input data for the plugin ports. If a UI wishes to
+ write data to an input port, it must list a transfer mechanism Feature
+ for that port's class as an optional or required feature (depending on
+ whether the UI will work without being able to write to that port or not).
+ The only exception is when the UI wants to write single float values to
+ input ports of the class lv2:ControlPort, in which case @c buffer_size
+ should always be 4, the buffer should always contain a single IEEE-754
+ float, and @c format should be 0.
+
+ The numeric IDs for the transfer mechanisms are provided by a
+ URI-to-integer mapping function provided by the host, using the URI Map
+ feature <http://lv2plug.in/ns/ext/uri-map> with the map URI
+ "http://lv2plug.in/ns/extensions/ui". Thus a UI that requires transfer
+ mechanism features also requires the URI Map feature, but this is
+ implicit - the UI does not have to list the URI map feature as a required
+ or optional feature in it's RDF data.
+
+ An UI MUST NOT pass a @c format parameter value (except 0) that has not
+ been returned by the host-provided URI mapping function for a
+ host-supported transfer mechanism feature URI.
+
+ The UI MUST NOT try to write to a port for which there is no specified
+ transfer mechanism, or to an output port. The UI is responsible for
+ allocating the buffer and deallocating it after the call.
+*/
+typedef void (*LV2UI_Write_Function)(LV2UI_Controller controller,
+ uint32_t port_index,
+ uint32_t buffer_size,
+ uint32_t format,
+ const void* buffer);
+
+
+/** This struct contains the implementation of an UI. A pointer to an
+ object of this type is returned by the lv2ui_descriptor() function.
+*/
+typedef struct _LV2UI_Descriptor {
+
+ /** The URI for this UI (not for the plugin it controls). */
+ const char* URI;
+
+ /** Create a new UI object and return a handle to it. This function works
+ similarly to the instantiate() member in LV2_Descriptor.
+
+ @param descriptor The descriptor for the UI that you want to instantiate.
+ @param plugin_uri The URI of the plugin that this UI will control.
+ @param bundle_path The path to the bundle containing the RDF data file
+ that references this shared object file, including the
+ trailing '/'.
+ @param write_function A function provided by the host that the UI can
+ use to send data to the plugin's input ports.
+ @param controller A handle for the plugin instance that should be passed
+ as the first parameter of @c write_function.
+ @param widget A pointer to an LV2UI_Widget. The UI will write a
+ widget pointer to this location (what type of widget
+ depends on the RDF class of the UI) that will be the
+ main UI widget.
+ @param features An array of LV2_Feature pointers. The host must pass
+ all feature URIs that it and the UI supports and any
+ additional data, just like in the LV2 plugin
+ instantiate() function. Note that UI features and plugin
+ features are NOT necessarily the same, they just share
+ the same data structure - this will probably not be the
+ same array as the one the plugin host passes to a
+ plugin.
+ */
+ LV2UI_Handle (*instantiate)(const struct _LV2UI_Descriptor* descriptor,
+ const char* plugin_uri,
+ const char* bundle_path,
+ LV2UI_Write_Function write_function,
+ LV2UI_Controller controller,
+ LV2UI_Widget* widget,
+ const LV2_Feature* const* features);
+
+
+ /** Destroy the UI object and the associated widget. The host must not try
+ to access the widget after calling this function.
+ */
+ void (*cleanup)(LV2UI_Handle ui);
+
+ /** Tell the UI that something interesting has happened at a plugin port.
+ What is interesting and how it is written to the buffer passed to this
+ function is defined by the @c format parameter, which has the same
+ meaning as in LV2UI_Write_Function. The only exception is ports of the
+ class lv2:ControlPort, for which this function should be called
+ when the port value changes (it does not have to be called for every
+ single change if the host's UI thread has problems keeping up with
+ the thread the plugin is running in), @c buffer_size should be 4 and the
+ buffer should contain a single IEEE-754 float. In this case the @c format
+ parameter should be 0.
+
+ By default, the host should only call this function for input ports of
+ the lv2:ControlPort class. However, the default setting can be modified
+ by using the following URIs in the UI's RDF data:
+ <pre>
+ uiext:portNotification
+ uiext:noPortNotification
+ uiext:plugin
+ uiext:portIndex
+ </pre>
+ For example, if you want the UI with uri
+ <code><http://my.pluginui></code> for the plugin with URI
+ <code><http://my.plugin></code> to get notified when the value of the
+ output control port with index 4 changes, you would use the following
+ in the RDF for your UI:
+ <pre>
+ <http://my.pluginui> uiext:portNotification [ uiext:plugin <http://my.plugin> ;
+ uiext:portIndex 4 ] .
+ </pre>
+ and similarly with <code>uiext:noPortNotification</code> if you wanted
+ to prevent notifications for a port for which it would be on by default
+ otherwise. The UI is not allowed to request notifications for ports of
+ types for which no transfer mechanism is specified, if it does it should
+ be considered broken and the host should not load it.
+
+ The @c buffer is only valid during the time of this function call, so if
+ the UI wants to keep it for later use it has to copy the contents to an
+ internal buffer.
+
+ This member may be set to NULL if the UI is not interested in any
+ port events.
+ */
+ void (*port_event)(LV2UI_Handle ui,
+ uint32_t port_index,
+ uint32_t buffer_size,
+ uint32_t format,
+ const void* buffer);
+
+ /** Returns a data structure associated with an extension URI, for example
+ a struct containing additional function pointers. Avoid returning
+ function pointers directly since standard C++ has no valid way of
+ casting a void* to a function pointer. This member may be set to NULL
+ if the UI is not interested in supporting any extensions. This is similar
+ to the extension_data() member in LV2_Descriptor.
+ */
+ const void* (*extension_data)(const char* uri);
+
+} LV2UI_Descriptor;
+
+
+
+/** A plugin UI programmer must include a function called "lv2ui_descriptor"
+ with the following function prototype within the shared object
+ file. This function will have C-style linkage (if you are using
+ C++ this is taken care of by the 'extern "C"' clause at the top of
+ the file). This function will be accessed by the UI host using the
+ @c dlsym() function and called to get a LV2UI_UIDescriptor for the
+ wanted plugin.
+
+ Just like lv2_descriptor(), this function takes an index parameter. The
+ index should only be used for enumeration and not as any sort of ID number -
+ the host should just iterate from 0 and upwards until the function returns
+ NULL or a descriptor with an URI matching the one the host is looking for.
+*/
+const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index);
+
+
+/** This is the type of the lv2ui_descriptor() function. */
+typedef const LV2UI_Descriptor* (*LV2UI_DescriptorFunction)(uint32_t index);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
diff --git a/lvz/AEffEditor.hpp b/lvz/AEffEditor.hpp
new file mode 100644
index 0000000..2d5152c
--- /dev/null
+++ b/lvz/AEffEditor.hpp
@@ -0,0 +1,30 @@
+#ifndef __LVZ_AUDIOEFFECT_HPP
+#define __LVZ_AUDIOEFFECT_HPP
+
+class AudioEffect;
+
+class AEffEditor {
+public:
+ AEffEditor (AudioEffect* eff)
+ : effect(eff)
+ , URI("NULL")
+ , pluginURI("NULL")
+ {}
+
+ virtual bool open(void* ptr) { return true; }
+
+ virtual void idle() {}
+
+ virtual const char* getURI() { return URI; }
+ virtual void setURI(const char* u) { URI = u; }
+
+ virtual const char* getPluginURI() { return pluginURI; }
+ virtual void setPluginURI(const char* u) { pluginURI = u; }
+
+protected:
+ AudioEffect* effect;
+ const char* URI;
+ const char* pluginURI;
+};
+
+#endif // __LVZ_AUDIOEFFECT_HPP
diff --git a/lvz/AudioEffect.hpp b/lvz/AudioEffect.hpp
new file mode 120000
index 0000000..df90333
--- /dev/null
+++ b/lvz/AudioEffect.hpp
@@ -0,0 +1 @@
+audioeffectx.h \ No newline at end of file
diff --git a/lvz/audioeffectx.h b/lvz/audioeffectx.h
index 288d1cd..a1f975a 100644
--- a/lvz/audioeffectx.h
+++ b/lvz/audioeffectx.h
@@ -22,10 +22,29 @@
#include <stdint.h>
#include <string.h>
+// Some plugins seem to use these names...
+#ifndef VstInt32
+# define VstInt32 LvzInt32
+# define VstInt16 LvzInt16
+#endif
+#define VstEvents LvzEvents
+#define VstMidiEvent LvzMidiEvent
+#define VstPinProperty LvzPinProperty
+
typedef int16_t LvzInt16;
typedef int32_t LvzInt32;
typedef int (*audioMasterCallback)(int, int ver, int, int, int, int);
+class AEffEditor;
+
+struct VstFileSelect {
+ int reserved;
+ char* returnPath;
+ size_t sizeReturnPath;
+ char** returnMultiplePaths;
+ long nbReturnPath;
+};
+
enum LvzPinFlags {
kLvzPinIsActive = 1<<0,
kLvzPinIsStereo = 1<<1
@@ -59,9 +78,16 @@ struct LvzEvents {
class AudioEffect {
public:
+ AudioEffect() : editor(NULL) {}
virtual ~AudioEffect() {}
+
+ void setEditor(AEffEditor* e) { editor = e; }
+ virtual void masterIdle() {}
+protected:
+ AEffEditor* editor;
};
+
class AudioEffectX : public AudioEffect {
public:
AudioEffectX(audioMasterCallback audioMaster, LvzInt32 progs, LvzInt32 params)
@@ -91,10 +117,11 @@ public:
virtual void getParameterName(LvzInt32 index, char *label) = 0;
virtual bool getProductString(char* text) = 0;
- virtual void canMono() {}
- virtual void canProcessReplacing() {}
- virtual void isSynth() {}
- virtual void wantEvents() {}
+ virtual bool canHostDo(const char* act) { return false; }
+ virtual void canMono() {}
+ virtual void canProcessReplacing() {}
+ virtual void isSynth() {}
+ virtual void wantEvents() {}
virtual void setBlockSize(LvzInt32 size) {}
virtual void setNumInputs(LvzInt32 num) { numInputs = num; }
@@ -104,6 +131,11 @@ public:
virtual void setURI(const char* uri) { URI = uri; }
virtual void setUniqueID(const char* id) { uniqueID = id; }
virtual void suspend() {}
+ virtual void beginEdit(VstInt32 index) {}
+ virtual void endEdit(VstInt32 index) {}
+
+ virtual bool openFileSelector (VstFileSelect* sel) { return false; }
+ virtual bool closeFileSelector (VstFileSelect* sel) { return false; }
protected:
const char* URI;
diff --git a/lvz/gendata.cpp b/lvz/gendata.cpp
index 7f1d501..bf9c9ab 100644
--- a/lvz/gendata.cpp
+++ b/lvz/gendata.cpp
@@ -17,12 +17,14 @@
*/
#include <list>
+#include <map>
#include <string>
#include <cassert>
#include <iostream>
#include <fstream>
#include <dlfcn.h>
#include "audioeffectx.h"
+#include "AEffEditor.hpp"
using namespace std;
@@ -34,13 +36,16 @@ char name_buf[MAX_NAME_LENGTH];
struct Record {
- Record(const string& u, const string& n) : uri(u), base_name(n) {}
- string uri;
+ Record(const string& n) : base_name(n) {}
string base_name;
+ typedef list<string> UIs;
+ UIs uis;
};
-typedef std::list<Record> Manifest;
+typedef std::map<string, Record> Manifest;
Manifest manifest;
+typedef std::map<string, Record> GUIManifest;
+GUIManifest gui_manifest;
string
@@ -85,8 +90,8 @@ symbolify(const char* name)
void
write_plugin(AudioEffectX* effect, const string& lib_file_name)
{
- string base_name = lib_file_name.substr(0, lib_file_name.find_last_of("."));
- string data_file_name = base_name + ".ttl";
+ const string base_name = lib_file_name.substr(0, lib_file_name.find_last_of("."));
+ const string data_file_name = base_name + ".ttl";
fstream os(data_file_name.c_str(), ios::out);
effect->getProductString(name_buf);
@@ -141,7 +146,33 @@ write_plugin(AudioEffectX* effect, const string& lib_file_name)
os.close();
- manifest.push_back(Record(effect->getURI(), base_name));
+ Manifest::iterator i = manifest.find(effect->getURI());
+ if (i != manifest.end()) {
+ i->second.base_name = base_name;
+ } else {
+ manifest.insert(std::make_pair(effect->getURI(), Record(base_name)));
+ }
+}
+
+
+void
+write_gui(AEffEditor* gui, const string& lib_file_name)
+{
+ const string base_name = lib_file_name.substr(0, lib_file_name.find_last_of("."));
+ assert(gui_manifest.find(gui->getURI()) == gui_manifest.end());
+ gui_manifest.insert(std::make_pair(gui->getURI(), Record(base_name)));
+ Manifest::iterator plugin_record = manifest.find(lib_file_name);
+ if (plugin_record != manifest.end()) {
+ plugin_record->second.uis.push_back(gui->getPluginURI());
+ }
+ Manifest::iterator i = manifest.find(gui->getPluginURI());
+ if (i != manifest.end()) {
+ i->second.uis.push_back(gui->getURI());
+ } else {
+ Record r("ERRNOBASE");
+ r.uis.push_back(gui->getURI());
+ manifest.insert(std::make_pair(gui->getPluginURI(), r));
+ }
}
@@ -149,11 +180,23 @@ void
write_manifest(ostream& os)
{
os << "@prefix : <http://lv2plug.in/ns/lv2core#> ." << endl;
- os << "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> ." << endl << endl;
+ os << "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> ." << endl;
+ os << "@prefix uiext: <http://lv2plug.in/ns/extensions/ui#> ." << endl << endl;
for (Manifest::iterator i = manifest.begin(); i != manifest.end(); ++i) {
- os << "<" << i->uri << "> a :Plugin ;" << endl;
- os << "\trdfs:seeAlso <" << i->base_name << ".ttl> ;" << endl;
- os << "\t:binary <" << i->base_name << ".so> ." << endl << endl;
+ Record& r = i->second;
+ os << "<" << i->first << "> a :Plugin ;" << endl;
+ os << "\trdfs:seeAlso <" << r.base_name << ".ttl> ;" << endl;
+ os << "\t:binary <" << r.base_name << ".so> ";
+ for (Record::UIs::iterator j = r.uis.begin(); j != r.uis.end(); ++j)
+ os << ";" << endl << "\tuiext:ui <" << *j << "> ";
+ os << "." << endl << endl;
+ }
+
+ for (GUIManifest::iterator i = gui_manifest.begin(); i != gui_manifest.end(); ++i) {
+ Record& r = i->second;
+ os << "<" << i->first << "> a uiext:GtkUI ;" << endl;
+ os << "\trdfs:seeAlso <" << r.base_name << ".ttl> ;" << endl;
+ os << "\tuiext:binary <" << r.base_name << ".so> ." << endl << endl;
}
}
@@ -171,33 +214,42 @@ main(int argc, char** argv)
}
typedef AudioEffectX* (*new_effect_func)();
+ typedef AEffEditor* (*new_gui_func)();
typedef AudioEffectX* (*plugin_uri_func)();
- new_effect_func constructor = NULL;
- AudioEffectX* effect = NULL;
+ new_effect_func constructor = NULL;
+ new_gui_func gui_constructor = NULL;
+ AudioEffectX* effect = NULL;
+ AEffEditor* gui = NULL;
for (int i = 1; i < argc; ++i) {
- void* handle = dlopen(argv[i], RTLD_NOW);
+ void* handle = dlopen(argv[i], RTLD_LAZY);
if (handle == NULL) {
- cerr << "ERROR: " << argv[i] << " is not a shared library, ignoring" << endl;
+ cerr << "ERROR: " << argv[i] << ": " << dlerror() << " (ignoring)" << endl;
continue;
}
- constructor = (new_effect_func)dlsym(handle, "lvz_new_audioeffectx");
- if (constructor == NULL) {
- dlclose(handle);
- cerr << "ERROR: " << argv[i] << " is not an LVZ plugin library, ignoring" << endl;
- continue;
- }
-
- effect = constructor();
string lib_path = argv[i];
size_t last_slash = lib_path.find_last_of("/");
if (last_slash != string::npos)
lib_path = lib_path.substr(last_slash + 1);
- write_plugin(effect, lib_path);
-
+ constructor = (new_effect_func)dlsym(handle, "lvz_new_audioeffectx");
+ if (constructor != NULL) {
+ effect = constructor();
+ write_plugin(effect, lib_path);
+ }
+
+ gui_constructor = (new_gui_func)dlsym(handle, "lvz_new_aeffeditor");
+ if (gui_constructor != NULL) {
+ gui = gui_constructor();
+ write_gui(gui, lib_path);
+ }
+
+ if (constructor == NULL && gui_constructor == NULL) {
+ cerr << "ERROR: " << argv[i] << ": not an LVZ plugin library, ignoring" << endl;
+ }
+
dlclose(handle);
}
diff --git a/lvz/gui_wrapper.cpp b/lvz/gui_wrapper.cpp
new file mode 100644
index 0000000..ca2b894
--- /dev/null
+++ b/lvz/gui_wrapper.cpp
@@ -0,0 +1,211 @@
+/* LVZ - A C++ interface for writing LV2 plugins.
+ * Copyright (C) 2008 Dave Robillard <http://drobilla.net>
+ *
+ * This library 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 of the License, or (at your option)
+ * any later version.
+ *
+ * This library 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 St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef UI_CLASS
+#error "This file requires UI_CLASS to be defined"
+#endif
+#ifndef URI_PREFIX
+#error "This file requires URI_PREFIX to be defined"
+#endif
+#ifndef UI_URI_SUFFIX
+#error "This file requires UI_URI_SUFFIX to be defined"
+#endif
+
+#include <stdlib.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <cassert>
+#include "AEffEditor.hpp"
+#include "lv2_ui.h"
+#include UI_HEADER
+#include PLUGIN_HEADER
+
+extern "C" {
+
+/* UI */
+
+typedef struct {
+ bool stolen;
+ UI_CLASS* ui;
+ GtkSocket* socket;
+ Window x_window;
+ AudioEffectX* effect;
+} MDAPluginUI;
+
+
+static gboolean
+mda_ui_idle(void* data)
+{
+ MDAPluginUI* ui = (MDAPluginUI*)data;
+ if (!ui->stolen) {
+ //gtk_socket_add_id(GTK_SOCKET(ui->socket), ui->x_window);
+ ui->x_window = (Window)gtk_socket_get_id(GTK_SOCKET(ui->socket));
+ bool success = ui->ui->open((void*)ui->x_window);
+ if (!success)
+ fprintf(stderr, "FAILED TO OPEN GUI\n");
+ ui->ui->getFrame()->draw();
+ ui->stolen = true;
+ }
+
+ ui->ui->idle();
+ return true;
+}
+
+
+static LV2UI_Handle
+mda_ui_instantiate(const struct _LV2UI_Descriptor* descriptor,
+ const char* plugin_uri,
+ const char* bundle_path,
+ LV2UI_Write_Function write_function,
+ LV2UI_Controller controller,
+ LV2UI_Widget* widget,
+ const LV2_Feature* const* features)
+{
+ /* Some extensions need to be defined for this to work. Hosts must:
+ * 1) Pass a pointer to the plugin (VST is crap and has no UI separation)
+ * 2) Call idle on the UI periodically (VST is crap and uses polling)
+ *
+ * Thoughts:
+ *
+ * 1) This wrapper could be written explicitly in GTK and just get at
+ * the idle handler that way. Less burden on the host...
+ *
+ * 2) A better idea is to have a 'get plugin extension data' feature
+ * the UI (or anything else) can use to ask for any URI-identified
+ * piece of extension data (failing in this case if plugin is remote)
+ */
+
+ MDAPluginUI* ui = (MDAPluginUI*)malloc(sizeof(MDAPluginUI));
+ ui->effect = NULL;
+
+ typedef struct { const void* (*extension_data)(const char* uri); } LV2_ExtensionData;
+
+ typedef const void* (*extension_data_func)(const char* uri);
+ typedef const AudioEffectX* (*get_effect_func)(LV2_Handle instance);
+
+ LV2_Handle instance = NULL;
+ get_effect_func get_effect = NULL;
+
+
+ if (features != NULL) {
+ const LV2_Feature* feature = features[0];
+ for (size_t i = 0; (feature = features[i]) != NULL; ++i) {
+ if (!strcmp(feature->URI, "http://lv2plug.in/ns/ext/dev/plugin-instance")) {
+ instance = (LV2_Handle)feature->data;
+ } else if (!strcmp(feature->URI, "http://lv2plug.in/ns/ext/dev/extension-data")) {
+ LV2_ExtensionData* ext_data = (LV2_ExtensionData*)feature->data;
+ extension_data_func func = (extension_data_func)feature->data;
+ get_effect = (get_effect_func)ext_data->extension_data(
+ "http://lv2plug.in/ns/ext/dev/vstgui");
+ }
+ }
+ }
+
+ if (instance && get_effect) {
+ ui->effect = (AudioEffectX*)get_effect(instance);
+ } else {
+ fprintf(stderr, "Host does not support required features, aborting.\n");
+ return NULL;
+ }
+
+ ui->ui = new UI_CLASS(ui->effect);
+ ui->ui->setBundlePath(bundle_path);
+ ui->stolen = false;
+
+ ui->socket = GTK_SOCKET(gtk_socket_new());
+ gtk_widget_show_all(GTK_WIDGET(ui->socket));
+
+ *widget = ui->socket;
+ g_timeout_add(30, mda_ui_idle, ui);
+
+ return ui;
+}
+
+
+static void
+mda_ui_cleanup(LV2UI_Handle instance)
+{
+ g_idle_remove_by_data(instance);
+}
+
+
+static void
+mda_ui_port_event(LV2UI_Handle ui,
+ uint32_t port_index,
+ uint32_t buffer_size,
+ uint32_t format,
+ const void* buffer)
+{
+ // VST UIs seem to not use this at all, it's all polling
+ // The shit the proprietary people come up (and get away) with...
+}
+
+
+static const void*
+mda_ui_extension_data(const char* uri)
+{
+ return NULL;
+}
+
+
+/* Library */
+
+static LV2UI_Descriptor *mda_ui_descriptor = NULL;
+
+static void
+init_ui_descriptor()
+{
+ mda_ui_descriptor = (LV2UI_Descriptor*)malloc(sizeof(LV2UI_Descriptor));
+
+ mda_ui_descriptor->URI = URI_PREFIX UI_URI_SUFFIX;
+ mda_ui_descriptor->instantiate = mda_ui_instantiate;
+ mda_ui_descriptor->cleanup = mda_ui_cleanup;
+ mda_ui_descriptor->port_event = mda_ui_port_event;
+ mda_ui_descriptor->extension_data = mda_ui_extension_data;
+}
+
+
+LV2_SYMBOL_EXPORT
+const LV2UI_Descriptor*
+lv2ui_descriptor(uint32_t index)
+{
+ if (!mda_ui_descriptor)
+ init_ui_descriptor();
+
+ switch (index) {
+ case 0:
+ return mda_ui_descriptor;
+ default:
+ return NULL;
+ }
+}
+
+
+LV2_SYMBOL_EXPORT
+AEffEditor*
+lvz_new_aeffeditor(AudioEffect* effect)
+{
+ UI_CLASS* ui = new UI_CLASS(effect);
+ ui->setURI(URI_PREFIX UI_URI_SUFFIX);
+ ui->setPluginURI(URI_PREFIX PLUGIN_URI_SUFFIX);
+ return ui;
+}
+
+
+} // extern "C"
+
diff --git a/lvz/wrapper.cpp b/lvz/wrapper.cpp
index 4ab99df..82a6989 100644
--- a/lvz/wrapper.cpp
+++ b/lvz/wrapper.cpp
@@ -19,8 +19,8 @@
#ifndef PLUGIN_CLASS
#error "This file requires PLUGIN_CLASS to be defined"
#endif
-#ifndef PLUGIN_URI_PREFIX
-#error "This file requires PLUGIN_URI_PREFIX to be defined"
+#ifndef URI_PREFIX
+#error "This file requires URI_PREFIX to be defined"
#endif
#ifndef PLUGIN_URI_SUFFIX
#error "This file requires PLUGIN_URI_SUFFIX to be defined"
@@ -74,6 +74,7 @@ mda_connect_port(LV2_Handle instance, uint32_t port, void* data)
static int
master_callback(int, int ver, int, int, int, int)
{
+ return 0;
}
@@ -84,7 +85,7 @@ mda_instantiate(const LV2_Descriptor* descriptor,
const LV2_Feature*const* features)
{
PLUGIN_CLASS* effect = new PLUGIN_CLASS(master_callback);
- effect->setURI(PLUGIN_URI_PREFIX PLUGIN_URI_SUFFIX);
+ effect->setURI(URI_PREFIX PLUGIN_URI_SUFFIX);
effect->setSampleRate(rate);
uint32_t num_params = effect->getNumParameters();
@@ -97,7 +98,7 @@ mda_instantiate(const LV2_Descriptor* descriptor,
if (num_params > 0) {
plugin->controls = (float*)malloc(sizeof(float) * num_params);
plugin->control_buffers = (float**)malloc(sizeof(float*) * num_params);
- for (int32_t i = 0; i < num_params; ++i) {
+ for (uint32_t i = 0; i < num_params; ++i) {
plugin->controls[i] = effect->getParameter(i);
plugin->control_buffers[i] = NULL;
}
@@ -108,7 +109,7 @@ mda_instantiate(const LV2_Descriptor* descriptor,
if (num_inputs > 0) {
plugin->inputs = (float**)malloc(sizeof(float*) * num_inputs);
- for (int32_t i = 0; i < num_inputs; ++i)
+ for (uint32_t i = 0; i < num_inputs; ++i)
plugin->inputs[i] = NULL;
} else {
plugin->inputs = NULL;
@@ -116,7 +117,7 @@ mda_instantiate(const LV2_Descriptor* descriptor,
if (num_outputs > 0) {
plugin->outputs = (float**)malloc(sizeof(float*) * num_outputs);
- for (int32_t i = 0; i < num_outputs; ++i)
+ for (uint32_t i = 0; i < num_outputs; ++i)
plugin->outputs[i] = NULL;
} else {
plugin->outputs = NULL;
@@ -141,6 +142,26 @@ mda_run(LV2_Handle instance, uint32_t sample_count)
plugin->effect->processReplacing(plugin->inputs, plugin->outputs, sample_count);
}
+
+
+static const AudioEffectX*
+mda_get_audioeffectx(LV2_Handle instance)
+{
+ MDAPlugin* plugin = (MDAPlugin*)instance;
+ return plugin->effect;
+}
+
+
+static const void*
+mda_extension_data(const char* uri)
+{
+ if (!strcmp(uri, "http://lv2plug.in/ns/ext/dev/vstgui")) {
+ // FIXME: shouldn't return function pointers directly
+ return (const void*)mda_get_audioeffectx;
+ } else {
+ return NULL;
+ }
+}
static void
@@ -160,13 +181,14 @@ init_descriptor()
{
mda_descriptor = (LV2_Descriptor*)malloc(sizeof(LV2_Descriptor));
- mda_descriptor->URI = PLUGIN_URI_PREFIX PLUGIN_URI_SUFFIX;
- mda_descriptor->activate = NULL;
- mda_descriptor->cleanup = mda_cleanup;
- mda_descriptor->connect_port = mda_connect_port;
- mda_descriptor->deactivate = mda_deactivate;
+ mda_descriptor->URI = URI_PREFIX PLUGIN_URI_SUFFIX;
mda_descriptor->instantiate = mda_instantiate;
+ mda_descriptor->connect_port = mda_connect_port;
+ mda_descriptor->activate = NULL;
mda_descriptor->run = mda_run;
+ mda_descriptor->deactivate = mda_deactivate;
+ mda_descriptor->cleanup = mda_cleanup;
+ mda_descriptor->extension_data = mda_extension_data;
}
@@ -191,9 +213,10 @@ AudioEffectX*
lvz_new_audioeffectx()
{
PLUGIN_CLASS* effect = new PLUGIN_CLASS(master_callback);
- effect->setURI(PLUGIN_URI_PREFIX PLUGIN_URI_SUFFIX);
+ effect->setURI(URI_PREFIX PLUGIN_URI_SUFFIX);
return effect;
}
} // extern "C"
+
diff --git a/src/mdaSpecMeter.cpp b/src/mdaSpecMeter.cpp
new file mode 100644
index 0000000..7aae786
--- /dev/null
+++ b/src/mdaSpecMeter.cpp
@@ -0,0 +1,482 @@
+//
+// Plug-in: "MDA SpecMeter"
+//
+// Copyright(c)2002 Paul Kellett (maxim digital audio)
+//
+
+
+#include <stdio.h>
+#include <string.h>
+#include <float.h>
+#include <math.h>
+
+#include "mdaSpecMeter.h"
+//#include "mdaSpecMeterGUI.h"
+//#include "AEffEditor.hpp"
+
+AudioEffect *
+createEffectInstance (audioMasterCallback audioMaster)
+{
+ return new mdaSpecMeter (audioMaster);
+}
+
+mdaSpecMeterProgram::mdaSpecMeterProgram ()
+{
+ param[_PARAM0] = 1.0;
+ strcpy (name, "MDA SpecMeter");
+}
+
+
+mdaSpecMeter::mdaSpecMeter (audioMasterCallback audioMaster):AudioEffectX (audioMaster, 1,
+ NPARAMS)
+{
+ //editor = new mdaSpecMeterGUI(this);
+
+ programs = new mdaSpecMeterProgram[numPrograms];
+ if (programs) {
+ setProgram (0);
+ }
+
+ setNumInputs (2);
+ setNumOutputs (2);
+ DECLARE_LVZ_DEPRECATED (canMono) ();
+ setUniqueID ("mdaSpecMeter");
+ canProcessReplacing ();
+
+ //initialise...
+ K = counter = 0;
+ kmax = 2048;
+ topband = 11;
+ iK = 1.0f / (float) kmax;
+ den = 1.0e-8f;
+
+ //buffer = new float[44100];
+
+ suspend ();
+}
+
+bool
+mdaSpecMeter::getProductString (char *text)
+{
+ strcpy (text, "MDA SpecMeter");
+ return true;
+}
+
+bool
+mdaSpecMeter::getVendorString (char *text)
+{
+ strcpy (text, "mda");
+ return true;
+}
+
+bool
+mdaSpecMeter::getEffectName (char *name)
+{
+ strcpy (name, "SpecMeter");
+ return true;
+}
+
+void
+mdaSpecMeter::suspend ()
+{
+ Lpeak = Rpeak = Lrms = Rrms = Corr = 0.0f;
+ lpeak = rpeak = lrms = rrms = corr = 0.0f;
+ Lhold = Rhold = 0.0f;
+ Lmin = Rmin = 0.0000001f;
+ for (long i = 0; i < 16; i++) {
+ band[0][i] = band[1][i] = 0.0f;
+ for (long j = 0; j < 6; j++)
+ lpp[j][i] = rpp[j][i] = 0.0f;
+ }
+
+ //memset(buffer, 0, size * sizeof (float));
+}
+
+void
+mdaSpecMeter::setSampleRate (float rate)
+{
+ AudioEffectX::setSampleRate (rate);
+ if (rate > 64000) {
+ topband = 12;
+ kmax = 4096;
+ } else {
+ topband = 11;
+ kmax = 2048;
+ }
+ iK = 1.0f / (float) kmax;
+}
+
+
+mdaSpecMeter::~mdaSpecMeter ()
+{
+ //if(buffer) delete [] buffer;
+ if (programs)
+ delete[]programs;
+}
+
+
+void
+mdaSpecMeter::setProgramName (char *name)
+{
+ strcpy (programs[curProgram].name, name);
+}
+
+void
+mdaSpecMeter::getProgramName (char *name)
+{
+ strcpy (name, programs[curProgram].name);
+}
+
+float
+mdaSpecMeter::getParameter (LvzInt32 index)
+{
+ return param[index];
+}
+
+void
+mdaSpecMeter::setProgram (LvzInt32 program)
+{
+ mdaSpecMeterProgram *p = &programs[program];
+ curProgram = program;
+ setProgramName (p->name);
+ for (long i = 0; i < NPARAMS; i++)
+ setParameter (i, p->param[i]);
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+
+void
+mdaSpecMeter::setParameter (LvzInt32 index, float value)
+{
+ mdaSpecMeterProgram *p = &programs[curProgram];
+ param[index] = p->param[index] = value;
+
+ switch (index) {
+ case _PARAM0:
+ gain = (float) pow (10.0f, 2.0f * param[index] - 1.0f);
+ break;
+
+ default:
+ break;
+ }
+
+ //if(editor) editor->postUpdate();
+}
+
+
+void
+mdaSpecMeter::getParameterName (LvzInt32 index, char *label)
+{
+ switch (index) {
+ case _PARAM0:
+ strcpy (label, "Gain");
+ break;
+ default:
+ strcpy (label, "");
+ }
+}
+
+
+void
+mdaSpecMeter::getParameterDisplay (LvzInt32 index, char *text)
+{
+ char string[16];
+
+ switch (index) {
+ case _PARAM0:
+ sprintf (string, "%.1f", 40.0f * param[index] - 20.0f);
+ break;
+ default:
+ sprintf (string, "%.0f", 0.0f * param[index]);
+ }
+ string[8] = 0;
+ strcpy (text, (char *) string);
+}
+
+
+void
+mdaSpecMeter::getParameterLabel (LvzInt32 index, char *label)
+{
+ switch (index) {
+ case _PARAM0:
+ strcpy (label, "Gain");
+ break;
+ default:
+ strcpy (label, "");
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+
+void
+mdaSpecMeter::process (float **inputs, float **outputs, LvzInt32 sampleFrames)
+{
+ float *in1 = inputs[0];
+ float *in2 = inputs[1];
+ float *out1 = outputs[0];
+ float *out2 = outputs[1];
+
+ den = -den;
+ float l, r, p, q, iN = iK;
+ long k = K, j0 = topband, mask, j;
+
+ while (--sampleFrames >= 0) {
+ l = *in1++;
+ r = *in2++;
+ *out1++ += l;
+ *out2++ += r;
+
+ l += den; //anti-denormal
+ r += den;
+
+ lrms += l * l; //RMS integrate
+ rrms += r * r;
+
+ p = (float) fabs (l);
+ if (p > lpeak)
+ lpeak = p; //peak detect
+ q = (float) fabs (r);
+ if (q > rpeak)
+ rpeak = q;
+ /*
+ if(p > 1.0e-8f && p < lmin) lmin = p; //'trough' detect
+ if(q > 1.0e-8f && q < rmin) rmin = q;
+ */
+ if ((l * r) > 0.0f)
+ corr += iN; //measure correlation
+
+ j = j0;
+ mask = k << 1;
+
+ do { //polyphase filter bank
+ p = lpp[0][j] + 0.208f * l;
+ lpp[0][j] = lpp[1][j];
+ lpp[1][j] = l - 0.208f * p;
+
+ q = lpp[2][j] + lpp[4][j] * 0.682f;
+ lpp[2][j] = lpp[3][j];
+ lpp[3][j] = lpp[4][j] - 0.682f * q;
+ lpp[4][j] = l;
+ lpp[5][j] += (float) fabs (p - q); //top octave
+ l = p + q; //lower octaves
+
+ p = rpp[0][j] + 0.208f * r;
+ rpp[0][j] = rpp[1][j];
+ rpp[1][j] = r - 0.208f * p;
+
+ q = rpp[2][j] + rpp[4][j] * 0.682f;
+ rpp[2][j] = rpp[3][j];
+ rpp[3][j] = rpp[4][j] - 0.682f * q;
+ rpp[4][j] = r;
+ rpp[5][j] += (float) fabs (p - q); //top octave
+ r = p + q; //lower octaves
+
+ j--;
+ mask >>= 1;
+ } while (mask & 1);
+
+ if (++k == kmax) {
+ k = 0;
+ counter++; //editor waits for this to change
+
+ if (lpeak == 0.0f)
+ Lpeak = Lrms = 0.0f;
+ else { ///add limits here!
+ if (lpeak > 2.0f)
+ lpeak = 2.0f;
+ if (lpeak >= Lpeak) {
+ Lpeak = lpeak;
+ Lhold = 2.0f * Lpeak;
+ } else {
+ Lhold *= 0.95f;
+ if (Lhold < Lpeak)
+ Lpeak = Lhold;
+ }
+ Lmin = lmin;
+ lmin *= 1.01f;
+ Lrms += 0.2f * (iN * lrms - Lrms);
+ }
+
+ if (rpeak == 0.0f)
+ Rpeak = Rrms = 0.0f;
+ else {
+ if (rpeak > 2.0f)
+ rpeak = 2.0f;
+ if (rpeak >= Rpeak) {
+ Rpeak = rpeak;
+ Rhold = 2.0f * Rpeak;
+ } else {
+ Rhold *= 0.95f;
+ if (Rhold < Rpeak)
+ Rpeak = Rhold;
+ }
+ Rmin = rmin;
+ rmin *= 1.01f;
+ Rrms += 0.2f * (iN * rrms - Rrms);
+ }
+
+ rpeak = lpeak = lrms = rrms = 0.0f;
+ Corr += 0.1f * (corr - Corr); //correlation
+ corr = SILENCE;
+
+ float dec = 0.08f;
+ for (j = 0; j < 13; j++) { //spectrum output
+ band[0][j] += dec * (iN * lpp[5][j] - band[0][j]);
+ if (band[0][j] > 2.0f)
+ band[0][j] = 2.0f;
+ else if (band[0][j] < 0.014f)
+ band[0][j] = 0.014f;
+
+ band[1][j] += dec * (iN * rpp[5][j] - band[1][j]);
+ if (band[1][j] > 2.0f)
+ band[1][j] = 2.0f;
+ else if (band[1][j] < 0.014f)
+ band[1][j] = 0.014f;
+
+ rpp[5][j] = lpp[5][j] = SILENCE;
+ dec = dec * 1.1f;
+ }
+ }
+ }
+
+ K = k;
+}
+
+//////////////////////////////////////////////////////////////////////////////////
+
+void
+mdaSpecMeter::processReplacing (float **inputs, float **outputs,
+ LvzInt32 sampleFrames)
+{
+ float *in1 = inputs[0];
+ float *in2 = inputs[1];
+ float *out1 = outputs[0];
+ float *out2 = outputs[1];
+
+ den = -den;
+ float l, r, p, q, iN = iK;
+ long k = K, j0 = topband, mask, j;
+
+ while (--sampleFrames >= 0) {
+ l = *in1++;
+ r = *in2++;
+ *out1++ = l;
+ *out2++ = r;
+
+ l += den; //anti-denormal
+ r += den;
+
+ lrms += l * l; //RMS integrate
+ rrms += r * r;
+
+ p = (float) fabs (l);
+ if (p > lpeak)
+ lpeak = p; //peak detect
+ q = (float) fabs (r);
+ if (q > rpeak)
+ rpeak = q;
+ /*
+ if(p > 1.0e-8f && p < lmin) lmin = p; //'trough' detect
+ if(q > 1.0e-8f && q < rmin) rmin = q;
+ */
+ if ((l * r) > 0.0f)
+ corr += iN; //measure correlation
+
+ j = j0;
+ mask = k << 1;
+
+ do { //polyphase filter bank
+ p = lpp[0][j] + 0.208f * l;
+ lpp[0][j] = lpp[1][j];
+ lpp[1][j] = l - 0.208f * p;
+
+ q = lpp[2][j] + lpp[4][j] * 0.682f;
+ lpp[2][j] = lpp[3][j];
+ lpp[3][j] = lpp[4][j] - 0.682f * q;
+ lpp[4][j] = l;
+ lpp[5][j] += (float) fabs (p - q); //top octave
+ l = p + q; //lower octaves
+
+ p = rpp[0][j] + 0.208f * r;
+ rpp[0][j] = rpp[1][j];
+ rpp[1][j] = r - 0.208f * p;
+
+ q = rpp[2][j] + rpp[4][j] * 0.682f;
+ rpp[2][j] = rpp[3][j];
+ rpp[3][j] = rpp[4][j] - 0.682f * q;
+ rpp[4][j] = r;
+ rpp[5][j] += (float) fabs (p - q); //top octave
+ r = p + q; //lower octaves
+
+ j--;
+ mask >>= 1;
+ } while (mask & 1);
+
+ if (++k == kmax) {
+ k = 0;
+ //counter++; //editor waits for this to change
+
+ if (lpeak == 0.0f)
+ Lpeak = Lrms = 0.0f;
+ else { ///add limits here!
+ if (lpeak > 2.0f)
+ lpeak = 2.0f;
+ if (lpeak >= Lpeak) {
+ Lpeak = lpeak;
+ Lhold = 2.0f * Lpeak;
+ } else {
+ Lhold *= 0.95f;
+ if (Lhold < Lpeak)
+ Lpeak = Lhold;
+ }
+ Lmin = lmin;
+ lmin *= 1.01f;
+ Lrms += 0.2f * (iN * lrms - Lrms);
+ }
+
+ if (rpeak == 0.0f)
+ Rpeak = Rrms = 0.0f;
+ else {
+ if (rpeak > 2.0f)
+ rpeak = 2.0f;
+ if (rpeak >= Rpeak) {
+ Rpeak = rpeak;
+ Rhold = 2.0f * Rpeak;
+ } else {
+ Rhold *= 0.95f;
+ if (Rhold < Rpeak)
+ Rpeak = Rhold;
+ }
+ Rmin = rmin;
+ rmin *= 1.01f;
+ Rrms += 0.2f * (iN * rrms - Rrms);
+ }
+
+ rpeak = lpeak = lrms = rrms = 0.0f;
+ Corr += 0.1f * (corr - Corr); //correlation
+ corr = SILENCE;
+
+ float dec = 0.08f;
+ for (j = 0; j < 13; j++) { //spectrum output
+ band[0][j] += dec * (iN * lpp[5][j] - band[0][j]);
+ if (band[0][j] > 2.0f)
+ band[0][j] = 2.0f;
+ else if (band[0][j] < 0.014f)
+ band[0][j] = 0.014f;
+
+ band[1][j] += dec * (iN * rpp[5][j] - band[1][j]);
+ if (band[1][j] > 2.0f)
+ band[1][j] = 2.0f;
+ else if (band[1][j] < 0.014f)
+ band[1][j] = 0.014f;
+
+ rpp[5][j] = lpp[5][j] = SILENCE;
+ dec = dec * 1.1f;
+ }
+
+ counter++; //editor waits for this to change
+ }
+ }
+
+ K = k;
+}
diff --git a/src/mdaSpecMeter.h b/src/mdaSpecMeter.h
index 31573ed..5ce88ee 100644
--- a/src/mdaSpecMeter.h
+++ b/src/mdaSpecMeter.h
@@ -1,21 +1,18 @@
-//see associated .cpp file for copyright and other info
+//
+// Plug-in: "MDA SpecMeter"
+//
+// Copyright(c)1999-2000 Paul Kellett (maxim digital audio)
+// Copyright (C) 2008 Dave Robillard
+//
#include "audioeffectx.h"
#include <string.h>
-#define NPROGS 4 //can hide decay settings in programs! fast...slow...peak hold
#define SILENCE 0.00000001f
-
-
-enum
-{
- _PARAM0, //peak decay
- _PARAM1, //RMS speed
- _PARAM2, //spectrum speed
- _PARAM3, //peak reset?
-
+enum {
+ _PARAM0, // gain
NPARAMS
};
diff --git a/src/mdaSpecMeterGUI.cpp b/src/mdaSpecMeterGUI.cpp
index 08bc5a3..d36622d 100644
--- a/src/mdaSpecMeterGUI.cpp
+++ b/src/mdaSpecMeterGUI.cpp
@@ -1,179 +1,211 @@
-#include "mdaSpecMeterGUI.h"
-#include "mdaSpecMeter.h"
-
-#include <math.h>
-
-
-mdaSpecMeterGUI::mdaSpecMeterGUI(AudioEffect *effect) : AEffGUIEditor(effect)
-{
- background = new CBitmap(128);
-
- rect.left = 0;
- rect.top = 0;
- rect.right = (LvzInt16)background->getWidth();
- rect.bottom = (LvzInt16)background->getHeight();
-}
-
-
-mdaSpecMeterGUI::~mdaSpecMeterGUI()
-{
- delete background;
-}
-
-
-bool mdaSpecMeterGUI::open(void *ptr)
-{
- AEffGUIEditor::open(ptr);
-
- CPoint offs(0, 0);
- CRect size(0, 0, background->getWidth(), background->getHeight());
- frame = new CFrame(size, ptr, this);
-
- size.offset(0, 0);
- draw = new CDraw(size, 0.0f, background);
- frame->addView(draw);
-
- return true;
-}
-
-
-void mdaSpecMeterGUI::close()
-{
- delete frame;
- frame = 0;
-}
-
-
-void mdaSpecMeterGUI::idle()
-{
- long xnow = ((mdaSpecMeter *)effect)->counter;
- if(xnow != xtimer)
- {
- xtimer = xnow;
-
- //if(draw) temp = draw->temp;
- //if(label) label->setLabel(xtimer);
-
- if(draw) //copy data from effect (this can't be the best way!)
- {
- draw->Lpeak = ((mdaSpecMeter *)effect)->Lpeak;
- draw->Lmin = ((mdaSpecMeter *)effect)->Lmin;
- draw->Lrms = ((mdaSpecMeter *)effect)->Lrms;
- draw->Rpeak = ((mdaSpecMeter *)effect)->Rpeak;
- draw->Rmin = ((mdaSpecMeter *)effect)->Rmin;
- draw->Rrms = ((mdaSpecMeter *)effect)->Rrms;
- draw->Corr = ((mdaSpecMeter *)effect)->Corr;
- for(long i=0; i<13; i++)
- {
- draw->band[0][i] = ((mdaSpecMeter *)effect)->band[0][i];
- draw->band[1][i] = ((mdaSpecMeter *)effect)->band[1][i];
- }
- draw->setDirty(true); //trigger redraw
- }
- }
-
- AEffGUIEditor::idle();
-}
-
-
-CDraw::CDraw(CRect &size, float value, CBitmap *background) : CControl(size)
-{
- bitmap = background;
-
- Lpeak = Lmin = Lrms = Rpeak = Rmin = Rrms = Corr = 0.0f;
- for(long i=0; i<16; i++) band[0][i] = band[1][i] = 0.0f;
-
- setValue(value);
-}
-
-CDraw::~CDraw()
-{
-
-}
-
-void CDraw::draw(CDrawContext *pContext)
-{
- long r, p;
- CRect block;
- CRect rect(0, 0, bitmap->getWidth(), bitmap->getHeight());
-
- bitmap->draw(pContext, rect);
-/*
- pContext->setFillColor(kGreenCColor);
-
- p = x2pix(Lmin);
- block(p - 3, 10, p - 1, 18);
- pContext->fillRect(block);
-
- p = x2pix(Rmin);
- block(p - 3, 18, p - 1, 26);
- pContext->fillRect(block);
-*/
- pContext->setFillColor(kBlackCColor);
-
- r = x22pix(Lrms); if(r > 454) r = 454;
- p = x2pix(Lpeak); if(p > 454) p = 454;
- block = CRect(r - 1, 10, p - 1, 18);
- pContext->fillRect(block);
- block = CRect(p - 1, 10, 478, 18);
- if(p < 454) pContext->fillRect(block);
-
- r = x22pix(Rrms); if(r > 454) r = 454;
- p = x2pix(Rpeak); if(p > 454) p = 454;
- block = CRect(r - 1, 18, p - 1, 26);
- pContext->fillRect(block);
- block = CRect(p - 1, 18, 478, 26);
- if(p < 454) pContext->fillRect(block);
-
- //block(x2pix(Rpeak), 18, 478, 26);
- //buf->fillRect(block);
-
- block = CRect(235, 42, 244, 134 - (long)(90 * Corr));
- pContext->fillRect(block);
-
- long i, x1=2, x2=256; //octave bands
- float dB;
- for(i=0; i<13; i++)
- {
- dB = band[0][i];
- block = CRect(x1, 42, x1+18, 49 - (long)(20.0 * log(dB)));
- pContext->fillRect(block);
- x1 += 17;
-
- dB = band[1][i];
- block = CRect(x2, 42, x2+18, 49 - (long)(20.0 * log(dB)));
- pContext->fillRect(block);
- x2 += 17;
- }
-}
-
-
-long CDraw::x2pix(float x)
-{
- float dB = x;
- long p = 478;
-
- if(x > 0.00000005f) dB = 8.6858896f * (float)log(x); else dB = -146.0f;
- if(dB < -20.0)
- p = 293 + (long)(2.0f * dB);
- else
- p = 453 + (long)(10.0f * dB);
-
- return p;
-}
-
-
-long CDraw::x22pix(float x) //power version for squared summed
-{
- float dB = x;
- long p = 478;
-
- if(x > 0.00000005f) dB = 4.3429448f * (float)log(x); else dB = -146.0f;
- if(dB < -20.0)
- p = 293 + (long)(2.0f * dB);
- else
- if(dB < 0.0f) p = 453 + (long)(10.0f * dB);
-
- return p;
-}
-
+#include "mdaSpecMeterGUI.h"
+#include "mdaSpecMeter.h"
+#include "mdaSpecMeter.xpm"
+#include <X11/Xlib.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <gtk/gtk.h>
+
+#include <math.h>
+
+mdaSpecMeterGUI::mdaSpecMeterGUI(AudioEffect * effect)
+ : AEffGUIEditor(effect)
+ , background(NULL)
+{
+}
+
+
+mdaSpecMeterGUI::~mdaSpecMeterGUI()
+{
+ delete background;
+}
+
+
+bool
+mdaSpecMeterGUI::open(void *ptr)
+{
+ if (background == NULL) {
+ background = new CBitmap(*this, "mdaSpecMeter.png");
+ rect.right = (LvzInt16) background->getWidth();
+ rect.bottom = (LvzInt16) background->getHeight();
+ }
+
+ AEffGUIEditor::open(ptr);
+
+ CPoint offs(0, 0);
+ CRect size(0, 0, background->getWidth(), background->getHeight());
+ frame = new CFrame(size, ptr, this);
+
+ size.offset(0, 0);
+ draw = new CDraw(size, 0.0f, background);
+ frame->addView(draw);
+
+ return true;
+}
+
+
+void
+mdaSpecMeterGUI::close()
+{
+ delete frame;
+ frame = 0;
+}
+
+
+void
+mdaSpecMeterGUI::idle()
+{
+ long xnow = ((mdaSpecMeter *) effect)->counter;
+ if (xnow != xtimer) {
+ xtimer = xnow;
+
+ if (draw) { // copy data from effect (this can't be the best way!)
+ draw->Lpeak = ((mdaSpecMeter *) effect)->Lpeak;
+ draw->Lmin = ((mdaSpecMeter *) effect)->Lmin;
+ draw->Lrms = ((mdaSpecMeter *) effect)->Lrms;
+ draw->Rpeak = ((mdaSpecMeter *) effect)->Rpeak;
+ draw->Rmin = ((mdaSpecMeter *) effect)->Rmin;
+ draw->Rrms = ((mdaSpecMeter *) effect)->Rrms;
+ draw->Corr = ((mdaSpecMeter *) effect)->Corr;
+ for (long i = 0; i < 13; i++) {
+ draw->band[0][i] = ((mdaSpecMeter *) effect)->band[0][i];
+ draw->band[1][i] = ((mdaSpecMeter *) effect)->band[1][i];
+ }
+ draw->setDirty(true); // trigger redraw
+ }
+ }
+
+ AEffGUIEditor::idle();
+}
+
+
+CDraw::CDraw(CRect & size, float value, CBitmap * background):
+ CControl(size)
+{
+ bitmap = background;
+
+ Lpeak = Lmin = Lrms = Rpeak = Rmin = Rrms = Corr = 0.0f;
+ for (long i = 0; i < 16; i++)
+ band[0][i] = band[1][i] = 0.0f;
+
+ setValue(value);
+}
+
+CDraw::~CDraw()
+{
+}
+
+void
+CDraw::draw(CDrawContext * pContext)
+{
+ long r, p;
+ CRect block;
+ CRect rect(0, 0, bitmap->getWidth(), bitmap->getHeight());
+
+ bitmap->draw(pContext, rect);
+
+ /*
+ pContext->setFillColor(kGreenCColor);
+
+ p = x2pix(Lmin);
+ block(p - 3, 10, p - 1, 18);
+ pContext->fillRect(block);
+
+ p = x2pix(Rmin);
+ block(p - 3, 18, p - 1, 26);
+ pContext->fillRect(block);
+ */
+
+ pContext->setFillColor(kBlackCColor);
+
+ r = x22pix(Lrms);
+ if (r > 454)
+ r = 454;
+
+ p = x2pix(Lpeak);
+ if (p > 454)
+ p = 454;
+
+ block = CRect(r - 1, 10, p - 1, 18);
+ pContext->fillRect(block);
+
+ block = CRect(p - 1, 10, 478, 18);
+ if (p < 454)
+ pContext->fillRect(block);
+
+ r = x22pix(Rrms);
+ if (r > 454)
+ r = 454;
+
+ p = x2pix(Rpeak);
+ if (p > 454)
+ p = 454;
+
+ block = CRect(r - 1, 18, p - 1, 26);
+ pContext->fillRect(block);
+
+ block = CRect(p - 1, 18, 478, 26);
+ if (p < 454)
+ pContext->fillRect(block);
+
+ //block(x2pix(Rpeak), 18, 478, 26);
+ //buf->fillRect(block);
+
+ block = CRect(235, 42, 244, 134 - (long)(90 * Corr));
+ pContext->fillRect(block);
+
+ long i, x1 = 2, x2 = 256; // octave bands
+ for (i = 0; i < 13; i++) {
+ float dB = band[0][i];
+ block = CRect(x1, 42, x1 + 18, 49 - (long)(20.0 * log(dB)));
+ pContext->fillRect(block);
+ x1 += 17;
+
+ dB = band[1][i];
+ block = CRect(x2, 42, x2 + 18, 49 - (long)(20.0 * log(dB)));
+ pContext->fillRect(block);
+ x2 += 17;
+ }
+}
+
+
+long
+CDraw::x2pix(float x)
+{
+ float dB = x;
+ long p = 478;
+
+ if (x > 0.00000005f)
+ dB = 8.6858896f * (float)log(x);
+ else
+ dB = -146.0f;
+
+ if (dB < -20.0)
+ p = 293 + (long)(2.0f * dB);
+ else
+ p = 453 + (long)(10.0f * dB);
+
+ return p;
+}
+
+
+long
+CDraw::x22pix(float x) // power version for squared summed
+{
+ float dB = x;
+ long p = 478;
+
+ if (x > 0.00000005f)
+ dB = 4.3429448f * (float)log(x);
+ else
+ dB = -146.0f;
+
+ if (dB < -20.0)
+ p = 293 + (long)(2.0f * dB);
+ else if (dB < 0.0f)
+ p = 453 + (long)(10.0f * dB);
+
+ return p;
+}
+
diff --git a/src/mdaSpecMeterGUI.h b/src/mdaSpecMeterGUI.h
index b4541f1..263a20b 100644
--- a/src/mdaSpecMeterGUI.h
+++ b/src/mdaSpecMeterGUI.h
@@ -1,45 +1,43 @@
#ifndef _mdaSpecMeterGUI_h_
#define _mdaSpecMeterGUI_h_
-#include "lvzgui.h"
+#include "vstgui.h"
-//a drawing control
class CDraw : public CControl
{
public:
- CDraw(CRect &size, float x, CBitmap *background);
- ~CDraw();
+ CDraw(CRect& size, float x, CBitmap* background);
+ ~CDraw();
- void draw(CDrawContext *pContext);
+ void draw(CDrawContext* pContext);
long x2pix(float x);
long x22pix(float x);
- float Lpeak, Lrms, Lmin, Rpeak, Rrms, Rmin, Corr;
- float band[2][16];
- long temp;
+ float Lpeak, Lrms, Lmin, Rpeak, Rrms, Rmin, Corr;
+ float band[2][16];
protected:
- CBitmap *bitmap;
+ CBitmap* bitmap;
};
class mdaSpecMeterGUI : public AEffGUIEditor
{
public:
- mdaSpecMeterGUI(AudioEffect *effect);
- ~mdaSpecMeterGUI();
-
- bool open(void *ptr);
- void idle();
- void close();
+ mdaSpecMeterGUI(AudioEffect* effect);
+ ~mdaSpecMeterGUI();
+
+ bool open(void* ptr);
+ void idle();
+ void close();
private:
- CDraw *draw;
- CBitmap *background;
- long xtimer;
+ CDraw* draw;
+ CBitmap* background;
+ long xtimer;
};
-#endif //_mdaSpecMeterGUI_h_
+#endif // _mdaSpecMeterGUI_h_
diff --git a/src/mdaspecmeter.cpp b/src/mdaspecmeter.cpp
deleted file mode 100644
index 475a7c5..0000000
--- a/src/mdaspecmeter.cpp
+++ /dev/null
@@ -1,416 +0,0 @@
-//
-// Plug-in: "MDA Template" v1.0
-//
-// Copyright(c)2002 Paul Kellett (maxim digital audio)
-//
-
-
-#include <stdio.h>
-#include <string.h>
-#include <float.h>
-#include <math.h>
-
-#include "mdaSpecMeter.h"
-#include "mdaSpecMeterGUI.h"
-//#include "AEffEditor.hpp"
-
-AudioEffect *createEffectInstance(audioMasterCallback audioMaster)
-{
- return new mdaSpecMeter(audioMaster);
-}
-
-mdaSpecMeterProgram::mdaSpecMeterProgram()
-{
- param[_PARAM0] = 0.5;
- param[_PARAM1] = 0.5;
- param[_PARAM2] = 0.75;
- strcpy (name, "default");
-}
-
-
-mdaSpecMeter::mdaSpecMeter(audioMasterCallback audioMaster) : AudioEffectX(audioMaster, 1, NPARAMS)
-{
- editor = new mdaSpecMeterGUI(this);
-
- programs = new mdaSpecMeterProgram[numPrograms];
- if(programs)
- {
- setProgram(0);
- }
-
- setNumInputs(2);
- setNumOutputs(2);
- DECLARE_LVZ_DEPRECATED(canMono) ();
- setUniqueID("mdaSpecMeter");
- canProcessReplacing();
-
- //initialise...
- K = counter = 0;
- kmax = 2048;
- topband = 11;
- iK = 1.0f / (float)kmax;
- den = 1.0e-8f;
-
- //buffer = new float[44100];
-
- suspend();
-}
-
-bool mdaSpecMeter::getProductString(char* text) { strcpy(text, "MDA SpecMeter"); return true; }
-bool mdaSpecMeter::getVendorString(char* text) { strcpy(text, "mda"); return true; }
-bool mdaSpecMeter::getEffectName(char* name) { strcpy(name, "SpecMeter"); return true; }
-
-void mdaSpecMeter::suspend()
-{
- Lpeak = Rpeak = Lrms = Rrms = Corr = 0.0f;
- lpeak = rpeak = lrms = rrms = corr = 0.0f;
- Lhold = Rhold = 0.0f;
- Lmin = Rmin = 0.0000001f;
- for(long i=0; i<16; i++)
- {
- band[0][i] = band[1][i] = 0.0f;
- for(long j=0; j<6; j++) lpp[j][i] = rpp[j][i] = 0.0f;
- }
-
- //memset(buffer, 0, size * sizeof (float));
-}
-
-void mdaSpecMeter::setSampleRate(float sampleRate)
-{
- AudioEffectX::setSampleRate(sampleRate);
- if(sampleRate > 64000) { topband = 12; kmax = 4096; }
- else { topband = 11; kmax = 2048; }
- iK = 1.0f / (float)kmax;
-}
-
-
-mdaSpecMeter::~mdaSpecMeter()
-{
- //if(buffer) delete [] buffer;
- if(programs) delete [] programs;
-}
-
-
-void mdaSpecMeter::setProgramName(char *name) { strcpy(programs[curProgram].name, name); }
-void mdaSpecMeter::getProgramName(char *name) { strcpy(name, programs[curProgram].name); }
-float mdaSpecMeter::getParameter(LvzInt32 index) { return param[index]; }
-
-void mdaSpecMeter::setProgram(LvzInt32 program)
-{
- mdaSpecMeterProgram *p = &programs[program];
- curProgram = program;
- setProgramName(p->name);
- for(long i=0; i<NPARAMS; i++) setParameter(i, p->param[i]);
-}
-
-//////////////////////////////////////////////////////////////////////////////////
-
-void mdaSpecMeter::setParameter(LvzInt32 index, float value)
-{
- mdaSpecMeterProgram *p = &programs[curProgram];
- param[index] = p->param[index] = value;
-
- switch(index)
- {
- case _PARAM0: gain = (float)pow(10.0f, 2.0f * param[index] - 1.0f); break;
-
- default: break;
- }
-
- //if(editor) editor->postUpdate();
-}
-
-
-void mdaSpecMeter::getParameterName(LvzInt32 index, char *label)
-{
- switch (index)
- {
- case _PARAM0: strcpy (label, ""); break;
- default : strcpy (label, "");
- }
-}
-
-
-void mdaSpecMeter::getParameterDisplay(LvzInt32 index, char *text)
-{
- char string[16];
-
- switch (index)
- {
- case _PARAM0: sprintf(string, "%.1f", 40.0f * param[index] - 20.0f); break;
- case _PARAM1: strcpy (string, ""); break;
- default : sprintf(string, "%.0f", 100.0f * param[index]);
- }
- string[8] = 0;
- strcpy(text, (char *)string);
-}
-
-
-void mdaSpecMeter::getParameterLabel(LvzInt32 index, char *label)
-{
- switch (index)
- {
- case _PARAM0: strcpy(label, ""); break;
- default : strcpy(label, "");
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////////
-
-void mdaSpecMeter::process (float **inputs, float **outputs, LvzInt32 sampleFrames)
-{
- float *in1 = inputs[0];
- float *in2 = inputs[1];
- float *out1 = outputs[0];
- float *out2 = outputs[1];
-
- den = -den;
- float l, r, p, q, iN = iK;
- long k=K, j0=topband, mask, j;
-
- while(--sampleFrames >= 0)
- {
- l = *in1++;
- r = *in2++;
- *out1++ += l;
- *out2++ += r;
-
- l += den; //anti-denormal
- r += den;
-
- lrms += l * l; //RMS integrate
- rrms += r * r;
-
- p = (float)fabs(l); if(p > lpeak) lpeak = p; //peak detect
- q = (float)fabs(r); if(q > rpeak) rpeak = q;
-/*
- if(p > 1.0e-8f && p < lmin) lmin = p; //'trough' detect
- if(q > 1.0e-8f && q < rmin) rmin = q;
-*/
- if((l * r) > 0.0f) corr += iN; //measure correlation
-
- j = j0;
- mask = k << 1;
-
- do //polyphase filter bank
- {
- p = lpp[0][j] + 0.208f * l;
- lpp[0][j] = lpp[1][j];
- lpp[1][j] = l - 0.208f * p;
-
- q = lpp[2][j] + lpp[4][j] * 0.682f;
- lpp[2][j] = lpp[3][j];
- lpp[3][j] = lpp[4][j] - 0.682f * q;
- lpp[4][j] = l;
- lpp[5][j] += (float)fabs(p - q); //top octave
- l = p + q; //lower octaves
-
- p = rpp[0][j] + 0.208f * r;
- rpp[0][j] = rpp[1][j];
- rpp[1][j] = r - 0.208f * p;
-
- q = rpp[2][j] + rpp[4][j] * 0.682f;
- rpp[2][j] = rpp[3][j];
- rpp[3][j] = rpp[4][j] - 0.682f * q;
- rpp[4][j] = r;
- rpp[5][j] += (float)fabs(p - q); //top octave
- r = p + q; //lower octaves
-
- j--;
- mask >>= 1;
- } while(mask & 1);
-
- if(++k == kmax)
- {
- k = 0;
- counter++; //editor waits for this to change
-
- if(lpeak == 0.0f) Lpeak = Lrms = 0.0f; else ///add limits here!
- {
- if(lpeak > 2.0f) lpeak = 2.0f;
- if(lpeak >= Lpeak)
- {
- Lpeak = lpeak;
- Lhold = 2.0f * Lpeak;
- }
- else
- {
- Lhold *= 0.95f;
- if(Lhold < Lpeak) Lpeak = Lhold;
- }
- Lmin = lmin;
- lmin *= 1.01f;
- Lrms += 0.2f * (iN * lrms - Lrms);
- }
-
- if(rpeak == 0.0f) Rpeak = Rrms = 0.0f; else
- {
- if(rpeak > 2.0f) rpeak = 2.0f;
- if(rpeak >= Rpeak)
- {
- Rpeak = rpeak;
- Rhold = 2.0f * Rpeak;
- }
- else
- {
- Rhold *= 0.95f;
- if(Rhold < Rpeak) Rpeak = Rhold;
- }
- Rmin = rmin;
- rmin *= 1.01f;
- Rrms += 0.2f * (iN * rrms - Rrms);
- }
-
- rpeak = lpeak = lrms = rrms = 0.0f;
- Corr += 0.1f * (corr - Corr); //correlation
- corr = SILENCE;
-
- float dec = 0.08f;
- for(j=0; j<13; j++) //spectrum output
- {
- band[0][j] += dec * (iN * lpp[5][j] - band[0][j]);
- if(band[0][j] > 2.0f) band[0][j] = 2.0f;
- else if(band[0][j] < 0.014f) band[0][j] = 0.014f;
-
- band[1][j] += dec * (iN * rpp[5][j] - band[1][j]);
- if(band[1][j] > 2.0f) band[1][j] = 2.0f;
- else if(band[1][j] < 0.014f) band[1][j] = 0.014f;
-
- rpp[5][j] = lpp[5][j] = SILENCE;
- dec = dec * 1.1f;
- }
- }
- }
-
- K = k;
-}
-
-//////////////////////////////////////////////////////////////////////////////////
-
-void mdaSpecMeter::processReplacing (float **inputs, float **outputs, LvzInt32 sampleFrames)
-{
- float *in1 = inputs[0];
- float *in2 = inputs[1];
- float *out1 = outputs[0];
- float *out2 = outputs[1];
-
- den = -den;
- float l, r, p, q, iN = iK;
- long k=K, j0=topband, mask, j;
-
- while(--sampleFrames >= 0)
- {
- l = *in1++;
- r = *in2++;
- *out1++ = l;
- *out2++ = r;
-
- l += den; //anti-denormal
- r += den;
-
- lrms += l * l; //RMS integrate
- rrms += r * r;
-
- p = (float)fabs(l); if(p > lpeak) lpeak = p; //peak detect
- q = (float)fabs(r); if(q > rpeak) rpeak = q;
-/*
- if(p > 1.0e-8f && p < lmin) lmin = p; //'trough' detect
- if(q > 1.0e-8f && q < rmin) rmin = q;
-*/
- if((l * r) > 0.0f) corr += iN; //measure correlation
-
- j = j0;
- mask = k << 1;
-
- do //polyphase filter bank
- {
- p = lpp[0][j] + 0.208f * l;
- lpp[0][j] = lpp[1][j];
- lpp[1][j] = l - 0.208f * p;
-
- q = lpp[2][j] + lpp[4][j] * 0.682f;
- lpp[2][j] = lpp[3][j];
- lpp[3][j] = lpp[4][j] - 0.682f * q;
- lpp[4][j] = l;
- lpp[5][j] += (float)fabs(p - q); //top octave
- l = p + q; //lower octaves
-
- p = rpp[0][j] + 0.208f * r;
- rpp[0][j] = rpp[1][j];
- rpp[1][j] = r - 0.208f * p;
-
- q = rpp[2][j] + rpp[4][j] * 0.682f;
- rpp[2][j] = rpp[3][j];
- rpp[3][j] = rpp[4][j] - 0.682f * q;
- rpp[4][j] = r;
- rpp[5][j] += (float)fabs(p - q); //top octave
- r = p + q; //lower octaves
-
- j--;
- mask >>= 1;
- } while(mask & 1);
-
- if(++k == kmax)
- {
- k = 0;
- counter++; //editor waits for this to change
-
- if(lpeak == 0.0f) Lpeak = Lrms = 0.0f; else ///add limits here!
- {
- if(lpeak > 2.0f) lpeak = 2.0f;
- if(lpeak >= Lpeak)
- {
- Lpeak = lpeak;
- Lhold = 2.0f * Lpeak;
- }
- else
- {
- Lhold *= 0.95f;
- if(Lhold < Lpeak) Lpeak = Lhold;
- }
- Lmin = lmin;
- lmin *= 1.01f;
- Lrms += 0.2f * (iN * lrms - Lrms);
- }
-
- if(rpeak == 0.0f) Rpeak = Rrms = 0.0f; else
- {
- if(rpeak > 2.0f) rpeak = 2.0f;
- if(rpeak >= Rpeak)
- {
- Rpeak = rpeak;
- Rhold = 2.0f * Rpeak;
- }
- else
- {
- Rhold *= 0.95f;
- if(Rhold < Rpeak) Rpeak = Rhold;
- }
- Rmin = rmin;
- rmin *= 1.01f;
- Rrms += 0.2f * (iN * rrms - Rrms);
- }
-
- rpeak = lpeak = lrms = rrms = 0.0f;
- Corr += 0.1f * (corr - Corr); //correlation
- corr = SILENCE;
-
- float dec = 0.08f;
- for(j=0; j<13; j++) //spectrum output
- {
- band[0][j] += dec * (iN * lpp[5][j] - band[0][j]);
- if(band[0][j] > 2.0f) band[0][j] = 2.0f;
- else if(band[0][j] < 0.014f) band[0][j] = 0.014f;
-
- band[1][j] += dec * (iN * rpp[5][j] - band[1][j]);
- if(band[1][j] > 2.0f) band[1][j] = 2.0f;
- else if(band[1][j] < 0.014f) band[1][j] = 0.014f;
-
- rpp[5][j] = lpp[5][j] = SILENCE;
- dec = dec * 1.1f;
- }
- }
- }
-
- K = k;
-}
diff --git a/vstgui/TODO b/vstgui/TODO
new file mode 100644
index 0000000..27096e5
--- /dev/null
+++ b/vstgui/TODO
@@ -0,0 +1,19 @@
+//-----------------------------------------------------------------------------
+// VST Plug-Ins SDK Linux ONLY Port
+// VSTGUIL: Graphical User Interface Framework for VST plugins on LINUX:
+//
+// Version: 0.1
+// Author: kRAkEn/gORe
+// Date: 2007/01/21
+//-----------------------------------------------------------------------------
+
+Todo List:
+
+- Fix multiple CParamDisplay objects not showed correctly (only the first is shown)
+- Update other controls from a single control->update (), usually params displays not updating while mouse drag
+- Fix fonts names and sizes (actually only fixed and courier)
+- COffscreenContext not working (add an internal GC different from the frame GC)
+- Fix COffscreenContext CopyFrom
+- Turn back on CViewContainer::bOffscreenDraw (actually turned off to see something)
+- Keep out MOTIF defines (now that IS the default)
+- Make CBitmap work on every kind of GC (not pFrame only)
diff --git a/vstgui/vstcontrols.cpp b/vstgui/vstcontrols.cpp
new file mode 100644
index 0000000..0b0800c
--- /dev/null
+++ b/vstgui/vstcontrols.cpp
@@ -0,0 +1,3651 @@
+/* ----------------------------------------------------------------------------
+ * VSTGUI for X11/LV2/PNG
+ * Author: Dave Robillard
+ * Released under the revised BSD license, as below
+ * ----------------------------------------------------------------------------
+ *
+ * Based on:
+ * ----------------------------------------------------------------------------
+ * VSTGUIL: Graphical User Interface Framework for VST plugins on LINUX
+ * Version: 0.1, Date: 2007/01/21
+ * Author: kRAkEn/gORe
+ *
+ * Which was based on:
+ * ----------------------------------------------------------------------------
+ * VSTGUI: Graphical User Interface Framework for VST plugins
+ * Version 3.0 $Date: 2005/08/12 12:45:00 $
+ * ----------------------------------------------------------------------------
+ * VSTGUI LICENSE
+ * 2004, Steinberg Media Technologies, All Rights Reserved
+ * ----------------------------------------------------------------------------
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Steinberg Media Technologies nor the names of
+ * its contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ * ----------------------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+
+#ifndef __vstcontrols__
+#include "vstcontrols.h"
+#endif
+
+#include "vstkeycode.h"
+
+namespace VSTGUI {
+
+// some external variables (vstgui.cpp)
+extern long gStandardFontSize [];
+extern const char *gStandardFontName [];
+
+//------------------------------------------------------------------------
+// CControl
+//------------------------------------------------------------------------
+/*! @class CControl
+This object manages the tag identification and the value of a control object.
+
+Note:
+Since version 2.1, when an object uses the transparency for its background and draws on it (tranparency area)
+or the transparency area changes during different draws (CMovieBitmap ,...), the background will be false (not updated),
+you have to rewrite the draw function in order to redraw the background and then call the draw of the object.
+*/
+CControl::CControl (const CRect &size, CControlListener *listener, long tag,
+ CBitmap *pBackground)
+: CView (size),
+ listener (listener), tag (tag), oldValue (1), defaultValue (0.5f),
+ value (0), vmin (0), vmax (1.f), wheelInc (0.1f), lastTicks (-1)
+{
+ delta = 500;
+
+ if (delta < 250)
+ delta = 250;
+
+ setTransparency (false);
+ setMouseEnabled (true);
+ backOffset (0 ,0);
+
+ setBackground (pBackground);
+}
+
+//------------------------------------------------------------------------
+CControl::~CControl ()
+{
+}
+
+//------------------------------------------------------------------------
+void CControl::beginEdit ()
+{
+ // begin of edit parameter
+ getFrame ()->setFocusView(this);
+ getFrame ()->beginEdit (tag);
+}
+
+//------------------------------------------------------------------------
+void CControl::endEdit ()
+{
+ // end of edit parameter
+ getFrame ()->endEdit (tag);
+}
+
+//------------------------------------------------------------------------
+bool CControl::isDirty () const
+{
+ if (oldValue != value || CView::isDirty ())
+ return true;
+ return false;
+}
+
+//------------------------------------------------------------------------
+void CControl::setDirty (const bool val)
+{
+ CView::setDirty (val);
+ if (val)
+ {
+ if (value != -1.f)
+ oldValue = -1.f;
+ else
+ oldValue = 0.f;
+ }
+ else
+ oldValue = value;
+}
+
+//------------------------------------------------------------------------
+void CControl::setBackOffset (CPoint &offset)
+{
+ backOffset = offset;
+}
+
+//-----------------------------------------------------------------------------
+void CControl::copyBackOffset ()
+{
+ backOffset (size.left, size.top);
+}
+
+//------------------------------------------------------------------------
+void CControl::bounceValue ()
+{
+ if (value > vmax)
+ value = vmax;
+ else if (value < vmin)
+ value = vmin;
+}
+
+//-----------------------------------------------------------------------------
+bool CControl::checkDefaultValue (CDrawContext *pContext, long button)
+{
+ if (button == (kControl|kLButton))
+ {
+ // begin of edit parameter
+ beginEdit ();
+
+ value = getDefaultValue ();
+ if (isDirty () && listener)
+ listener->valueChanged (pContext, this);
+
+ // end of edit parameter
+ endEdit ();
+ return true;
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+bool CControl::isDoubleClick ()
+{
+ long ticks = getFrame ()->getTicks ();
+ if (lastTicks <= 0)
+ {
+ lastTicks = ticks;
+ return false;
+ }
+
+ if (lastTicks + delta > ticks)
+ lastTicks = 0;
+ else
+ {
+ lastTicks = ticks;
+ return false;
+ }
+ return true;
+}
+
+//------------------------------------------------------------------------
+// COnOffButton
+//------------------------------------------------------------------------
+/*! @class COnOffButton
+Define a button with 2 positions.
+The pixmap includes the 2 subpixmaps (i.e the rectangle used for the display of this button is half-height of the pixmap).
+When its value changes, the listener is called.
+*/
+COnOffButton::COnOffButton (const CRect &size, CControlListener *listener, long tag,
+ CBitmap *background, long style)
+: CControl (size, listener, tag, background)
+, style (style)
+{}
+
+//------------------------------------------------------------------------
+COnOffButton::~COnOffButton ()
+{}
+
+//------------------------------------------------------------------------
+void COnOffButton::draw (CDrawContext *pContext)
+{
+// DBG ("COnOffButton::draw");
+
+ CCoord off;
+
+ if (value && pBackground)
+ off = pBackground->getHeight () / 2;
+ else
+ off = 0;
+
+ if (pBackground)
+ {
+ if (bTransparencyEnabled)
+ pBackground->drawTransparent (pContext, size, CPoint (0, off));
+ else
+ pBackground->draw (pContext, size, CPoint (0, off));
+ }
+ setDirty (false);
+}
+
+//------------------------------------------------------------------------
+void COnOffButton::mouse (CDrawContext *pContext, CPoint &where, long button)
+{
+ if (!bMouseEnabled)
+ return;
+
+ if (button == -1) button = pContext->getMouseButtons ();
+ if (!(button & kLButton))
+ return;
+
+ if (listener && (button & (kAlt | kShift | kControl | kApple)))
+ {
+ if (listener->controlModifierClicked (pContext, this, button) != 0)
+ return;
+ }
+
+ value = ((long)value) ? 0.f : 1.f;
+
+ if (listener && style == kPostListenerUpdate)
+ {
+ // begin of edit parameter
+ beginEdit ();
+
+ listener->valueChanged (pContext, this);
+
+ // end of edit parameter
+ endEdit ();
+ }
+
+ doIdleStuff ();
+
+ if (listener && style == kPreListenerUpdate)
+ {
+ // begin of edit parameter
+ beginEdit ();
+
+ listener->valueChanged (pContext, this);
+
+ // end of edit parameter
+ endEdit ();
+ }
+}
+
+
+//------------------------------------------------------------------------
+// CKnob
+//------------------------------------------------------------------------
+/*! @class CKnob
+Define a knob with a given background and foreground handle.
+The handle describes a circle over the background (between -45deg and +225deg).
+By clicking Alt+Left Mouse the default value is used.
+By clicking Alt+Left Mouse the value changes with a vertical move (version 2.1)
+*/
+CKnob::CKnob (const CRect &size, CControlListener *listener, long tag,
+ CBitmap *background, CBitmap *handle, const CPoint &offset)
+: CControl (size, listener, tag, background), offset (offset), pHandle (handle)
+{
+ if (pHandle)
+ {
+ pHandle->remember ();
+ inset = (long)((float)pHandle->getWidth () / 2.f + 2.5f);
+ }
+ else
+ inset = 3;
+
+ colorShadowHandle = kGreyCColor;
+ colorHandle = kWhiteCColor;
+ radius = (float)(size.right - size.left) / 2.f;
+
+ rangeAngle = 1.f;
+ setStartAngle ((float)(5.f * kPI / 4.f));
+ setRangeAngle ((float)(-3.f * kPI / 2.f));
+ zoomFactor = 1.5f;
+
+ setWantsFocus (true);
+}
+
+//------------------------------------------------------------------------
+CKnob::~CKnob ()
+{
+ if (pHandle)
+ pHandle->forget ();
+}
+
+//------------------------------------------------------------------------
+void CKnob::draw (CDrawContext *pContext)
+{
+// DBG ("CKnob::draw");
+
+ if (pBackground)
+ {
+ if (bTransparencyEnabled)
+ pBackground->drawTransparent (pContext, size, offset);
+ else
+ pBackground->draw (pContext, size, offset);
+ }
+ drawHandle (pContext);
+ setDirty (false);
+}
+
+//------------------------------------------------------------------------
+void CKnob::drawHandle (CDrawContext *pContext)
+{
+ CPoint where;
+ valueToPoint (where);
+
+ if (pHandle)
+ {
+ long width = (long)pHandle->getWidth ();
+ long height = (long)pHandle->getHeight ();
+ where.offset (size.left - width / 2, size.top - height / 2);
+
+ CRect handleSize (0, 0, width, height);
+ handleSize.offset (where.h, where.v);
+ pHandle->drawTransparent (pContext, handleSize);
+ }
+ else
+ {
+ CPoint origin (size.width () / 2, size.height () / 2);
+
+ where.offset (size.left - 1, size.top);
+ origin.offset (size.left - 1, size.top);
+ pContext->setFrameColor (colorShadowHandle);
+ pContext->moveTo (where);
+ pContext->lineTo (origin);
+
+ where.offset (1, -1);
+ origin.offset (1, -1);
+ pContext->setFrameColor (colorHandle);
+ pContext->moveTo (where);
+ pContext->lineTo (origin);
+ }
+}
+
+//------------------------------------------------------------------------
+void CKnob::mouse (CDrawContext *pContext, CPoint &where, long button)
+{
+ if (!bMouseEnabled)
+ return;
+
+ if (button == -1) button = pContext->getMouseButtons ();
+ if (!(button & kLButton))
+ return;
+
+ if (listener && button & (kAlt | kShift | kControl | kApple))
+ {
+ if (listener->controlModifierClicked (pContext, this, button) != 0)
+ return;
+ }
+
+ // check if default value wanted
+ if (checkDefaultValue (pContext, button))
+ return;
+
+ float old = oldValue;
+ CPoint firstPoint;
+ bool modeLinear = false;
+ float fEntryState = value;
+ float middle = (vmax - vmin) * 0.5f;
+ float range = 200.f;
+ float coef = (vmax - vmin) / range;
+ long oldButton = button;
+
+ long mode = kCircularMode;
+ long newMode = getFrame ()->getKnobMode ();
+ if (kLinearMode == newMode)
+ {
+ if (!(button & kAlt))
+ mode = newMode;
+ }
+ else if (button & kAlt)
+ mode = kLinearMode;
+
+ if (mode == kLinearMode && (button & kLButton))
+ {
+ if (button & kShift)
+ range *= zoomFactor;
+ firstPoint = where;
+ modeLinear = true;
+ coef = (vmax - vmin) / range;
+ }
+ else
+ {
+ CPoint where2 (where);
+ where2.offset (-size.left, -size.top);
+ old = valueFromPoint (where2);
+ }
+
+ CPoint oldWhere (-1, -1);
+
+ // begin of edit parameter
+ beginEdit ();
+ do
+ {
+ button = pContext->getMouseButtons ();
+ if (where != oldWhere)
+ {
+ oldWhere = where;
+ if (modeLinear)
+ {
+ CCoord diff = (firstPoint.v - where.v) + (where.h - firstPoint.h);
+ if (button != oldButton)
+ {
+ range = 200.f;
+ if (button & kShift)
+ range *= zoomFactor;
+
+ float coef2 = (vmax - vmin) / range;
+ fEntryState += diff * (coef - coef2);
+ coef = coef2;
+ oldButton = button;
+ }
+ value = fEntryState + diff * coef;
+ bounceValue ();
+ }
+ else
+ {
+ where.offset (-size.left, -size.top);
+ value = valueFromPoint (where);
+ if (old - value > middle)
+ value = vmax;
+ else if (value - old > middle)
+ value = vmin;
+ else
+ old = value;
+ }
+ if (isDirty () && listener)
+ listener->valueChanged (pContext, this);
+ }
+ getMouseLocation (pContext, where);
+ doIdleStuff ();
+
+ } while (button & kLButton);
+
+ // end of edit parameter
+ endEdit ();
+}
+
+//------------------------------------------------------------------------
+bool CKnob::onWheel (CDrawContext *pContext, const CPoint &where, float distance)
+{
+ if (!bMouseEnabled)
+ return false;
+
+ long buttons = pContext->getMouseButtons ();
+ if (buttons & kShift)
+ value += 0.1f * distance * wheelInc;
+ else
+ value += distance * wheelInc;
+ bounceValue ();
+
+ if (isDirty () && listener)
+ {
+ // begin of edit parameter
+ beginEdit ();
+
+ listener->valueChanged (pContext, this);
+
+ // end of edit parameter
+ endEdit ();
+ }
+ return true;
+}
+
+//------------------------------------------------------------------------
+long CKnob::onKeyDown (VstKeyCode& keyCode)
+{
+ switch (keyCode.virt)
+ {
+ case VKEY_UP :
+ case VKEY_RIGHT :
+ case VKEY_DOWN :
+ case VKEY_LEFT :
+ {
+ float distance = 1.f;
+ if (keyCode.virt == VKEY_DOWN || keyCode.virt == VKEY_LEFT)
+ distance = -distance;
+
+ if (keyCode.modifier & MODIFIER_SHIFT)
+ value += 0.1f * distance * wheelInc;
+ else
+ value += distance * wheelInc;
+ bounceValue ();
+
+ if (isDirty () && listener)
+ {
+ // begin of edit parameter
+ beginEdit ();
+
+ listener->valueChanged (0, this);
+
+ // end of edit parameter
+ endEdit ();
+ }
+ } return 1;
+ }
+ return -1;
+}
+
+//------------------------------------------------------------------------
+void CKnob::setStartAngle (float val)
+{
+ startAngle = val;
+ compute ();
+}
+
+//------------------------------------------------------------------------
+void CKnob::setRangeAngle (float val)
+{
+ rangeAngle = val;
+ compute ();
+}
+
+//------------------------------------------------------------------------
+void CKnob::compute ()
+{
+ aCoef = (vmax - vmin) / rangeAngle;
+ bCoef = vmin - aCoef * startAngle;
+ halfAngle = ((float)k2PI - fabsf (rangeAngle)) * 0.5f;
+ setDirty ();
+}
+
+//------------------------------------------------------------------------
+void CKnob::valueToPoint (CPoint &point) const
+{
+ float alpha = (value - bCoef) / aCoef;
+ point.h = (long)(radius + cosf (alpha) * (radius - inset) + 0.5f);
+ point.v = (long)(radius - sinf (alpha) * (radius - inset) + 0.5f);
+}
+
+//------------------------------------------------------------------------
+float CKnob::valueFromPoint (CPoint &point) const
+{
+ float v;
+ float alpha = (float)atan2 (radius - point.v, point.h - radius);
+ if (alpha < 0.f)
+ alpha += (float)k2PI;
+
+ float alpha2 = alpha - startAngle;
+ if (rangeAngle < 0)
+ {
+ alpha2 -= rangeAngle;
+ float alpha3 = alpha2;
+ if (alpha3 < 0.f)
+ alpha3 += (float)k2PI;
+ else if (alpha3 > k2PI)
+ alpha3 -= (float)k2PI;
+ if (alpha3 > halfAngle - rangeAngle)
+ v = vmax;
+ else if (alpha3 > -rangeAngle)
+ v = vmin;
+ else
+ {
+ if (alpha2 > halfAngle - rangeAngle)
+ alpha2 -= (float)k2PI;
+ else if (alpha2 < -halfAngle)
+ alpha2 += (float)k2PI;
+ v = aCoef * alpha2 + vmax;
+ }
+ }
+ else
+ {
+ float alpha3 = alpha2;
+ if (alpha3 < 0.f)
+ alpha3 += (float)k2PI;
+ else if (alpha3 > k2PI)
+ alpha3 -= (float)k2PI;
+ if (alpha3 > rangeAngle + halfAngle)
+ v = vmin;
+ else if (alpha3 > rangeAngle)
+ v = vmax;
+ else
+ {
+ if (alpha2 > rangeAngle + halfAngle)
+ alpha2 -= (float)k2PI;
+ else if (alpha2 < -halfAngle)
+ alpha2 += (float)k2PI;
+ v = aCoef * alpha2 + vmin;
+ }
+ }
+
+ return v;
+}
+
+//------------------------------------------------------------------------
+void CKnob::setColorShadowHandle (CColor color)
+{
+ colorShadowHandle = color;
+ setDirty ();
+}
+
+//------------------------------------------------------------------------
+void CKnob::setColorHandle (CColor color)
+{
+ colorHandle = color;
+ setDirty ();
+}
+
+//------------------------------------------------------------------------
+void CKnob::setHandleBitmap (CBitmap *bitmap)
+{
+ if (pHandle)
+ {
+ pHandle->forget ();
+ pHandle = 0;
+ }
+
+ if (bitmap)
+ {
+ pHandle = bitmap;
+ pHandle->remember ();
+ inset = (long)((float)pHandle->getWidth () / 2.f + 2.5f);
+ }
+}
+
+
+//------------------------------------------------------------------------
+// CParamDisplay
+//------------------------------------------------------------------------
+/*! @class CParamDisplay
+Define a rectangle view where a text-value can be displayed with a given font and color.
+The user can specify its convert function (from float to char) by default the string format is "%2.2f".
+The text-value is centered in the given rect.
+*/
+CParamDisplay::CParamDisplay (const CRect &size, CBitmap *background, const long style)
+: CControl (size, 0, 0, background), stringConvert (0), stringConvert2 (0), string2FloatConvert (0),
+ horiTxtAlign (kCenterText), style (style), bTextTransparencyEnabled (true)
+{
+ backOffset (0, 0);
+
+ fontID = kNormalFont;
+ txtFace = kNormalFace;
+ fontColor = kWhiteCColor;
+ backColor = kBlackCColor;
+ frameColor = kBlackCColor;
+ shadowColor = kRedCColor;
+ userData = 0;
+ if (style & kNoDrawStyle)
+ setDirty (false);
+}
+
+//------------------------------------------------------------------------
+CParamDisplay::~CParamDisplay ()
+{}
+
+//------------------------------------------------------------------------
+void CParamDisplay::setStyle (long val)
+{
+ if (style != val)
+ {
+ style = val;
+ setDirty ();
+ }
+}
+
+//------------------------------------------------------------------------
+void CParamDisplay::draw (CDrawContext *pContext)
+{
+// DBG ("CParamDisplay::draw");
+
+ char string[256];
+ string[0] = 0;
+
+ if (stringConvert2)
+ stringConvert2 (value, string, userData);
+ else if (stringConvert)
+ stringConvert (value, string);
+ else
+ sprintf (string, "%2.2f", value);
+
+ drawText (pContext, string);
+}
+
+//------------------------------------------------------------------------
+void CParamDisplay::drawText (CDrawContext *pContext, char *string, CBitmap *newBack)
+{
+ setDirty (false);
+
+ if (style & kNoDrawStyle)
+ return;
+
+ // draw the background
+ if (newBack)
+ {
+ if (bTransparencyEnabled)
+ newBack->drawTransparent (pContext, size, backOffset);
+ else
+ newBack->draw (pContext, size, backOffset);
+ }
+ else if (pBackground)
+ {
+ if (bTransparencyEnabled)
+ pBackground->drawTransparent (pContext, size, backOffset);
+ else
+ pBackground->draw (pContext, size, backOffset);
+ }
+ else
+ {
+ if (!bTransparencyEnabled)
+ {
+ pContext->setFillColor (backColor);
+ pContext->fillRect (size);
+
+ if (!(style & (k3DIn|k3DOut|kNoFrame)))
+ {
+ pContext->setFrameColor (frameColor);
+ pContext->drawRect (size);
+ }
+ }
+ }
+ // draw the frame for the 3D effect
+ if (style & (k3DIn|k3DOut))
+ {
+ if (style & k3DIn)
+ pContext->setFrameColor (backColor);
+ else
+ pContext->setFrameColor (frameColor);
+ CPoint p;
+ pContext->moveTo (p (size.left, size.bottom));
+ pContext->lineTo (p (size.left, size.top));
+ pContext->lineTo (p (size.right + 1, size.top));
+
+ if (style & k3DIn)
+ pContext->setFrameColor (frameColor);
+ else
+ pContext->setFrameColor (backColor);
+ pContext->moveTo (p (size.right, size.top + 1));
+ pContext->lineTo (p (size.right, size.bottom));
+ pContext->lineTo (p (size.left, size.bottom));
+ }
+
+ if (!(style & kNoTextStyle) && string)
+ {
+ CRect oldClip;
+ pContext->getClipRect (oldClip);
+ CRect newClip (size);
+ newClip.bound (oldClip);
+ pContext->setClipRect (newClip);
+ pContext->setFont (fontID, 0, txtFace);
+
+ // draw darker text (as shadow)
+ if (style & kShadowText)
+ {
+ CRect newSize (size);
+ newSize.offset (1, 1);
+ pContext->setFontColor (shadowColor);
+ pContext->drawString (string, newSize, !bTextTransparencyEnabled, horiTxtAlign);
+ }
+ pContext->setFontColor (fontColor);
+ pContext->drawString (string, size, !bTextTransparencyEnabled, horiTxtAlign);
+ pContext->setClipRect (oldClip);
+ }
+}
+
+//------------------------------------------------------------------------
+void CParamDisplay::setFont (CFont newFontID)
+{
+ // to force the redraw
+ if (fontID != newFontID)
+ setDirty ();
+ fontID = newFontID;
+}
+
+//------------------------------------------------------------------------
+void CParamDisplay::setTxtFace (CTxtFace newTxtFace)
+{
+ // to force the redraw
+ if (txtFace != newTxtFace)
+ setDirty ();
+ txtFace = newTxtFace;
+}
+
+//------------------------------------------------------------------------
+void CParamDisplay::setFontColor (CColor color)
+{
+ // to force the redraw
+ if (fontColor != color)
+ setDirty ();
+ fontColor = color;
+}
+
+//------------------------------------------------------------------------
+void CParamDisplay::setBackColor (CColor color)
+{
+ // to force the redraw
+ if (backColor != color)
+ setDirty ();
+ backColor = color;
+}
+
+//------------------------------------------------------------------------
+void CParamDisplay::setFrameColor (CColor color)
+{
+ // to force the redraw
+ if (frameColor != color)
+ setDirty ();
+ frameColor = color;
+}
+
+//------------------------------------------------------------------------
+void CParamDisplay::setShadowColor (CColor color)
+{
+ // to force the redraw
+ if (shadowColor != color)
+ setDirty ();
+ shadowColor = color;
+}
+
+//------------------------------------------------------------------------
+void CParamDisplay::setHoriAlign (CHoriTxtAlign hAlign)
+{
+ // to force the redraw
+ if (horiTxtAlign != hAlign)
+ setDirty ();
+ horiTxtAlign = hAlign;
+}
+
+//------------------------------------------------------------------------
+void CParamDisplay::setStringConvert (void (*convert) (float value, char *string))
+{
+ stringConvert = convert;
+}
+
+//------------------------------------------------------------------------
+void CParamDisplay::setStringConvert (void (*convert) (float value, char *string,
+ void *userDta), void *userData_)
+{
+ stringConvert2 = convert;
+ userData = userData_;
+}
+
+//------------------------------------------------------------------------
+void CParamDisplay::setString2FloatConvert (void (*convert) (char *string, float &output))
+{
+ string2FloatConvert = convert;
+}
+
+//------------------------------------------------------------------------
+// CTextLabel
+//------------------------------------------------------------------------
+/*! @class CTextLabel
+*/
+CTextLabel::CTextLabel (const CRect& size, const char* txt, CBitmap* background, const long style)
+: CParamDisplay (size, background, style)
+, text (0)
+{
+ setText (txt);
+}
+
+//------------------------------------------------------------------------
+CTextLabel::~CTextLabel ()
+{
+ freeText ();
+}
+
+//------------------------------------------------------------------------
+void CTextLabel::freeText ()
+{
+ if (text)
+ free (text);
+ text = 0;
+}
+
+//------------------------------------------------------------------------
+void CTextLabel::setText (const char* txt)
+{
+ freeText ();
+ if (txt)
+ {
+ text = (char*)malloc (strlen (txt)+1);
+ strcpy (text, txt);
+ }
+}
+
+//------------------------------------------------------------------------
+const char* CTextLabel::getText () const
+{
+ return text;
+}
+
+//------------------------------------------------------------------------
+void CTextLabel::draw (CDrawContext *pContext)
+{
+// DBG ("CTextLabel::draw");
+
+ drawText (pContext, text);
+ setDirty (false);
+}
+
+
+//------------------------------------------------------------------------
+// CTextEdit
+//------------------------------------------------------------------------
+/*! @class CTextEdit
+Define a rectangle view where a text-value can be displayed and edited with a given font and color.
+The user can specify its convert function (from char to char). The text-value is centered in the given rect.
+A pixmap can be used as background.
+*/
+CTextEdit::CTextEdit (const CRect &size, CControlListener *listener, long tag,
+ const char *txt, CBitmap *background, const long style)
+: CParamDisplay (size, background, style), platformFontColor (0), platformControl (0),
+ platformFont (0), editConvert (0), editConvert2 (0)
+{
+ this->listener = listener;
+ this->tag = tag;
+
+ if (txt)
+ strcpy (text, txt);
+ else
+ strcpy (text, "");
+ setWantsFocus (true);
+}
+
+//------------------------------------------------------------------------
+CTextEdit::~CTextEdit ()
+{}
+
+//------------------------------------------------------------------------
+void CTextEdit::setText (char *txt)
+{
+ if (txt)
+ {
+ if (strcmp (text, txt))
+ {
+ strcpy (text, txt);
+
+ // to force the redraw
+ setDirty ();
+ }
+ }
+ else
+ {
+ if (strcmp (text, ""))
+ {
+ strcpy (text, "");
+
+ // to force the redraw
+ setDirty ();
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+void CTextEdit::getText (char *txt) const
+{
+ if (txt)
+ strcpy (txt, text);
+}
+
+//------------------------------------------------------------------------
+void CTextEdit::draw (CDrawContext *pContext)
+{
+// DBG ("CTextEdit::draw");
+
+ if (platformControl)
+ {
+ setDirty (false);
+ return;
+ }
+
+ char string[256];
+ string[0] = 0;
+
+ if (editConvert2)
+ editConvert2 (text, string, userData);
+ else if (editConvert)
+ editConvert (text, string);
+ // Allow to display strings through the stringConvert
+ // callbacks inherited from CParamDisplay
+ else if (stringConvert2)
+ {
+ string[0] = 0;
+ stringConvert2 (value, string, userData);
+ strcpy(text, string);
+ }
+ else if (stringConvert)
+ {
+ string[0] = 0;
+ stringConvert (value, string);
+ strcpy(text, string);
+ }
+ else
+ sprintf (string, "%s", text);
+
+ drawText (pContext, string);
+ setDirty (false);
+}
+
+//------------------------------------------------------------------------
+void CTextEdit::mouse (CDrawContext *pContext, CPoint &where, long button)
+{
+ if (!bMouseEnabled)
+ return;
+
+ if (button == -1) button = pContext->getMouseButtons ();
+
+ if (listener && button & (kAlt | kShift | kControl | kApple))
+ {
+ if (listener->controlModifierClicked (pContext, this, button) != 0)
+ return;
+ }
+
+ if (button & kLButton)
+ {
+ if (getFrame ()->getFocusView () != this)
+ {
+ if (style & kDoubleClickStyle)
+ if (!isDoubleClick ())
+ return;
+
+ beginEdit();
+ takeFocus (pContext);
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+// #include <Xm/Text.h>
+extern XFontStruct *gFontStructs[];
+
+//------------------------------------------------------------------------
+void CTextEdit::takeFocus (CDrawContext *pContext)
+{
+ bWasReturnPressed = false;
+
+/*
+ // we have to add the Text to the parent !!
+ Dimension posX, posY;
+ Widget widget = (Widget)(getFrame ()->getSystemWindow ());
+ XtVaGetValues (widget, XmNx, &posX, XmNy, &posY, 0);
+
+ Arg args[20];
+ int n = 0;
+ XtSetArg (args[n], XmNx, size.left + posX); n++;
+ XtSetArg (args[n], XmNy, size.top + posY); n++;
+ XtSetArg (args[n], XmNwidth, size.width () + 1); n++;
+ XtSetArg (args[n], XmNheight, size.height () + 2); n++;
+
+ XtSetArg (args[n], XmNvalue, text); n++;
+
+ XtSetArg (args[n], XmNshadowType, XmSHADOW_IN); n++;
+ XtSetArg (args[n], XmNshadowThickness, 0); n++;
+ XtSetArg (args[n], XmNcursorPositionVisible, true); n++;
+
+ XtSetArg (args[n], XmNmarginWidth, 0); n++;
+ XtSetArg (args[n], XmNmarginHeight, 0); n++;
+ XtSetArg (args[n], XmNresizeHeight, True); n++;
+ XtSetArg (args[n], XmNborderWidth, 0); n++;
+ XtSetArg (args[n], XmNeditMode, XmSINGLE_LINE_EDIT); n++;
+
+ // get/set the current font
+ XmFontList fl = 0;
+ XFontStruct* fs = gFontStructs [fontID];
+ if (fs)
+ {
+ XmFontListEntry entry = XmFontListEntryCreate (XmFONTLIST_DEFAULT_TAG, XmFONT_IS_FONT, fs);
+ XmFontList fl = XmFontListAppendEntry (0, entry);
+ XtSetArg (args[n], XmNfontList, fl); n++;
+ }
+
+ platformControl = XmCreateText (XtParent (widget), "Text", args, n);
+ XtManageChild ((Widget)platformControl);
+ if (fl)
+ XmFontListFree (fl);
+ XmTextSetSelection ((Widget)platformControl, 0, strlen (text), 0);
+ XmTextSetHighlight ((Widget)platformControl, 0, strlen (text), XmHIGHLIGHT_SELECTED);
+*/
+}
+
+//------------------------------------------------------------------------
+void CTextEdit::looseFocus (CDrawContext *pContext)
+{
+ // Call this yet to avoid recursive call
+ endEdit();
+ if (getFrame ()->getFocusView () == this)
+ getFrame ()->setFocusView (0);
+
+ if (platformControl == 0)
+ return;
+
+/*
+ char oldText[256];
+ strcpy (oldText, text);
+
+ char *pNewText = XmTextGetString ((Widget)platformControl);
+ strcpy (text, pNewText);
+ XtFree (pNewText);
+
+ XtUnmanageChild ((Widget)platformControl);
+ XtDestroyWidget ((Widget)platformControl);
+
+ CPoint origOffset;
+ bool resetContextOffset = false;
+ if (!pContext)
+ {
+ // create a local context
+ pContext = getFrame ()->createDrawContext ();
+ if (getParentView ())
+ {
+ resetContextOffset = true;
+ origOffset.x = pContext->offset.x;
+ origOffset.y = pContext->offset.y;
+ CView *view= getParentView ();
+ CRect rect2;
+ view->getViewSize (rect2);
+ CPoint offset;
+ view->localToFrame (offset);
+ rect2.offset (offset.x, offset.y);
+ pContext->offset.h = rect2.left;
+ pContext->offset.v = rect2.top;
+ }
+ }
+ else
+ pContext->remember ();
+
+ // update dependency
+ bool change = false;
+ if (strcmp (oldText, text))
+ {
+ change = true;
+ if (listener)
+ listener->valueChanged (pContext, this);
+ }
+
+ platformControl = 0;
+ if (resetContextOffset)
+ {
+ pContext->offset.x = origOffset.x;
+ pContext->offset.y = origOffset.y;
+ }
+ pContext->forget ();
+
+ if (change)
+ doIdleStuff ();
+
+ CView* receiver = pParentView ? pParentView : pParentFrame;
+ if (receiver)
+ receiver->notify (this, "LooseFocus");
+*/
+}
+
+//------------------------------------------------------------------------
+void CTextEdit::setTextEditConvert (void (*convert) (char *input, char *string))
+{
+ editConvert = convert;
+}
+
+//------------------------------------------------------------------------
+void CTextEdit::setTextEditConvert (void (*convert) (char *input, char *string,
+ void *userDta), void *userData)
+{
+ editConvert2 = convert;
+ this->userData = userData;
+}
+
+//------------------------------------------------------------------------
+// COptionMenuScheme
+//------------------------------------------------------------------------
+/*! @class COptionMenuScheme
+Used to define the appearance (font color, background color...) of a popup-menu.
+To define the scheme of a menu, use the appropriate setScheme method (see COptionMenu).
+@section coptionmenuscheme_new_in_3_0 New since 3.0
+You can also use the global variable gOptionMenuScheme to use one scheme on all menus.
+@section coptionmenuscheme_note Note
+If you want to use it on Mac OS X, you must set the macro MAC_ENABLE_MENU_SCHEME (needs Mac OS X 10.3 or higher)
+*/
+COptionMenuScheme* gOptionMenuScheme = 0;
+
+//------------------------------------------------------------------------
+COptionMenuScheme::COptionMenuScheme ()
+{
+ backgroundColor = kGreyCColor;
+ selectionColor = kBlueCColor;
+ textColor = kBlackCColor;
+ hiliteTextColor = kWhiteCColor;
+ disableTextColor = kWhiteCColor;
+
+ font = kNormalFontSmall;
+}
+
+//------------------------------------------------------------------------
+COptionMenuScheme::~COptionMenuScheme ()
+{
+}
+
+//------------------------------------------------------------------------
+void COptionMenuScheme::getItemSize (const char* text, CDrawContext* pContext, CPoint& size)
+{
+ if (!strcmp (text, kMenuSeparator)) // separator
+ {
+ // was: size.h = size.v = 6;
+ size.h = 6;
+ size.v = 18;
+ // separators must have same height, otherwise we have problems
+ // in multi-column menus :(
+ }
+ else
+ {
+ pContext->setFont (font);
+ size.h = pContext->getStringWidth (text) + 18;
+ size.v = 18;
+ }
+}
+
+//------------------------------------------------------------------------
+void COptionMenuScheme::drawItemBack (CDrawContext* pContext, const CRect& rect, bool hilite)
+{
+ if (hilite)
+ pContext->setFillColor (selectionColor);
+ else
+ pContext->setFillColor (backgroundColor);
+ pContext->fillRect (rect);
+}
+
+//------------------------------------------------------------------------
+void COptionMenuScheme::drawItem (const char* text, long itemId, long state, CDrawContext* pContext, const CRect& rect)
+{
+ bool hilite = (state & kSelected) != 0;
+
+ drawItemBack (pContext, rect, hilite);
+
+ if (!strcmp (text, kMenuSeparator))
+ {
+ CCoord y = rect.top + rect.height () / 2;
+
+ const CColor bc = { 0, 0, 0, 150};
+ const CColor wc = { 255, 255, 255, 150};
+
+ pContext->setFrameColor (bc);
+ pContext->moveTo (CPoint (rect.left + 2, y - 1));
+ pContext->lineTo (CPoint (rect.right - 2, y - 1));
+ pContext->setFrameColor (wc);
+ pContext->moveTo (CPoint (rect.left + 2, y));
+ pContext->lineTo (CPoint (rect.right - 2, y));
+ return;
+ }
+
+ CRect r;
+ if (state & kChecked)
+ {
+ r (6, 4, 14, 12);
+ r.offset (rect.left, rect.top);
+ if (hilite)
+ pContext->setFillColor (hiliteTextColor);
+ else
+ pContext->setFillColor (textColor);
+ pContext->fillEllipse (r);
+ }
+
+ r = rect;
+ r.left += 18;
+ pContext->setFont (font);
+ if (state & kDisabled)
+ pContext->setFontColor (disableTextColor);
+ else
+ {
+ if (hilite)
+ pContext->setFontColor (hiliteTextColor);
+ else
+ pContext->setFontColor (textColor);
+ }
+
+ // this needs to be done right, without changing the text pointer in anyway ;-)
+ char *ptr = (char*)strstr (text, "\t");
+ if (ptr)
+ {
+ char modifier[32];
+ strcpy (modifier, ptr + 1);
+ *ptr = 0;
+ pContext->drawString (text, r, false, kLeftText);
+
+ *ptr = '\t';
+ r.left = r.right - 50;
+ pContext->drawString (modifier, r, false, kLeftText);
+ }
+ else
+ pContext->drawString (text, r, false, kLeftText);
+}
+
+
+//------------------------------------------------------------------------
+// COptionMenu
+//------------------------------------------------------------------------
+/*! @class COptionMenu
+Define a rectangle view where a text-value can be displayed with a given font and color.
+The text-value is centered in the given rect.
+A pixmap can be used as background, a second pixmap can be used when the option menu is popuped.
+There are 2 styles with or without a shadowed text. When a mouse click occurs, a popup menu is displayed.
+*/
+COptionMenu::COptionMenu (const CRect &size, CControlListener *listener, long tag,
+ CBitmap *background, CBitmap *bgWhenClick, const long style)
+: CParamDisplay (size, background, style), bgWhenClick (bgWhenClick), nbItemsPerColumn (-1),
+ prefixNumbers (0), scheme (0)
+{
+ this->listener = listener;
+ this->tag = tag;
+
+ nbEntries = 0;
+ nbSubMenus = 0;
+ currentIndex = -1;
+ lastButton = kRButton;
+ platformControl = 0;
+ lastResult = -1;
+ lastMenu = 0;
+
+ if (bgWhenClick)
+ bgWhenClick->remember ();
+
+ nbSubMenuAllocated = nbAllocated = 0;
+
+ check = 0;
+ entry = 0;
+ submenuEntry = 0;
+}
+
+//------------------------------------------------------------------------
+COptionMenu::~COptionMenu ()
+{
+ removeAllEntry ();
+
+ if (bgWhenClick)
+ bgWhenClick->forget ();
+}
+
+//------------------------------------------------------------------------
+void COptionMenu::setPrefixNumbers (long preCount)
+{
+ prefixNumbers = preCount;
+}
+
+//-----------------------------------------------------------------------------
+bool COptionMenu::allocateSubMenu (long nb)
+{
+ long newAllocated = nbSubMenuAllocated + nb;
+
+ if (submenuEntry)
+ submenuEntry = (COptionMenu**)realloc (submenuEntry, newAllocated * sizeof (COptionMenu*));
+ else
+ submenuEntry = (COptionMenu**)malloc (newAllocated * sizeof (COptionMenu*));
+
+ long i;
+ for (i = nbSubMenuAllocated; i < newAllocated; i++)
+ submenuEntry[i] = 0;
+
+ nbSubMenuAllocated = newAllocated;
+
+ return true;
+}
+
+//------------------------------------------------------------------------
+bool COptionMenu::allocateMenu (long nb)
+{
+ long newAllocated = nbAllocated + nb;
+
+ if (check)
+ check = (bool*)realloc (check, newAllocated * sizeof (bool));
+ else
+ check = (bool*)malloc (newAllocated * sizeof (bool));
+ if (!check)
+ return false;
+
+ if (entry)
+ entry = (char**)realloc (entry, newAllocated * sizeof (char*));
+ else
+ entry = (char**)malloc (newAllocated * sizeof (char*));
+ if (!entry)
+ {
+ free (check);
+ return false;
+ }
+
+ long i;
+ for (i = nbAllocated; i < newAllocated; i++)
+ {
+ check[i] = false;
+ entry[i] = 0;
+ }
+
+ nbAllocated = newAllocated;
+
+ return true;
+}
+
+//------------------------------------------------------------------------
+COptionMenu* COptionMenu::getSubMenu (long idx) const
+{
+ if (submenuEntry && idx < nbSubMenus)
+ return submenuEntry[idx];
+ return 0;
+}
+
+//------------------------------------------------------------------------
+bool COptionMenu::addEntry (COptionMenu *subMenu, char *txt)
+{
+ if (nbEntries >= MAX_ENTRY || !subMenu || !txt)
+ return false;
+
+ if (nbEntries >= nbAllocated)
+ if (!allocateMenu (32))
+ return false;
+
+ entry[nbEntries] = (char*)malloc (256);
+ switch (prefixNumbers)
+ {
+ case 2:
+ sprintf (entry[nbEntries], "-M%1d %s", (int)(nbEntries + 1), txt);
+ break;
+
+ case 3:
+ sprintf (entry[nbEntries], "-M%02d %s", (int)(nbEntries + 1), txt);
+ break;
+
+ case 4:
+ sprintf (entry[nbEntries], "-M%03d %s", (int)(nbEntries + 1), txt);
+ break;
+
+ default:
+ sprintf (entry[nbEntries], "-M%s", txt);
+ }
+
+
+ if (nbSubMenus >= nbSubMenuAllocated)
+ if (!allocateSubMenu (10))
+ return false;
+
+ submenuEntry[nbSubMenus++] = subMenu;
+ subMenu->remember ();
+
+ nbEntries++;
+
+ if (currentIndex < 0)
+ currentIndex = 0;
+
+ return true;
+}
+
+//------------------------------------------------------------------------
+bool COptionMenu::addEntry (char *txt, long index)
+{
+ if (nbEntries >= MAX_ENTRY)
+ return false;
+
+ if (nbEntries >= nbAllocated)
+ if (!allocateMenu (32))
+ return false;
+
+ entry[nbEntries] = (char*)malloc (256);
+
+ long pos = nbEntries;
+
+ // switch the entries for the insert
+ if (index >= 0)
+ {
+ for (long i = nbEntries; i > index; i--)
+ strcpy (entry[i], entry[i - 1]);
+ if (index >= nbEntries)
+ pos = nbEntries;
+ else
+ pos = index;
+ if (currentIndex >= index)
+ currentIndex++;
+ }
+
+ *entry[pos] = 0;
+ if (txt)
+ {
+ switch (prefixNumbers)
+ {
+ case 2:
+ sprintf (entry[pos], "%1d %s", (int)(index + 1), txt);
+ break;
+
+ case 3:
+ sprintf (entry[pos], "%02d %s", (int)(index + 1), txt);
+ break;
+
+ case 4:
+ sprintf (entry[pos], "%03d %s", (int)(index + 1), txt);
+ break;
+
+ default:
+ strncpy (entry[pos], txt, 256);
+ }
+ }
+
+ nbEntries++;
+
+ if (currentIndex < 0)
+ currentIndex = 0;
+
+ return true;
+}
+
+//------------------------------------------------------------------------
+long COptionMenu::getCurrent (char *txt, bool countSeparator) const
+{
+ if (currentIndex < 0)
+ return -1;
+
+ long result = 0;
+
+ if (countSeparator)
+ {
+ if (txt)
+ strcpy (txt, entry[currentIndex]);
+ result = currentIndex;
+ }
+ else
+ {
+ for (long i = 0; i < currentIndex; i++)
+ {
+ if (strcmp (entry[i], kMenuSeparator) && strncmp (entry[i], kMenuTitle, 2))
+ result++;
+ }
+ if (txt)
+ strcpy (txt, entry[currentIndex]);
+ }
+ return result;
+}
+
+//------------------------------------------------------------------------
+bool COptionMenu::setCurrent (long index, bool countSeparator)
+{
+ if (index < 0 || index >= nbEntries)
+ return false;
+
+ if (countSeparator)
+ {
+ if (!strcmp (entry[index], kMenuSeparator) && strncmp (entry[index], kMenuTitle, 2))
+ return false;
+
+ currentIndex = index;
+ }
+ else
+ {
+ long newCurrent = 0;
+ long i = 0;
+ while (i <= index && newCurrent < nbEntries)
+ {
+ if (strcmp (entry[newCurrent], kMenuSeparator) && strncmp (entry[newCurrent], kMenuTitle, 2))
+ i++;
+ newCurrent++;
+ }
+ currentIndex = newCurrent - 1;
+ }
+ if (style & (kMultipleCheckStyle & ~kCheckStyle))
+ check[currentIndex] = !check[currentIndex];
+
+ // to force the redraw
+ setDirty ();
+
+ return true;
+}
+
+//------------------------------------------------------------------------
+bool COptionMenu::getEntry (long index, char *txt) const
+{
+ if (index < 0 || index >= nbEntries)
+ return false;
+
+ if (txt)
+ strcpy (txt, entry[index]);
+ return true;
+}
+
+//------------------------------------------------------------------------
+bool COptionMenu::setEntry (long index, char *txt)
+{
+ if (index < 0 || index >= nbEntries)
+ return false;
+
+ if (txt)
+ strcpy (entry[index], txt);
+ return true;
+}
+
+//------------------------------------------------------------------------
+bool COptionMenu::removeEntry (long index)
+{
+ if (index < 0 || index >= nbEntries)
+ return false;
+
+ nbEntries--;
+
+ // switch the entries
+ for (long i = index; i < nbEntries; i++)
+ {
+ strcpy (entry[i], entry[i + 1]);
+ check[i] = check [i + 1];
+ }
+
+ if (currentIndex >= index)
+ currentIndex--;
+
+ // delete the last one
+ free (entry[nbEntries]);
+ entry[nbEntries] = 0;
+ check[nbEntries] = false;
+
+ if (nbEntries == 0)
+ currentIndex = -1;
+ return true;
+}
+
+//------------------------------------------------------------------------
+bool COptionMenu::removeAllEntry ()
+{
+ long i;
+ for (i = 0; i < nbEntries; i++)
+ {
+ free (entry[i]);
+ entry[i] = 0;
+ check[i] = false;
+ }
+
+ nbEntries = 0;
+ currentIndex = -1;
+
+ for (i = 0; i < nbSubMenus; i++)
+ {
+ submenuEntry[i]->forget ();
+ submenuEntry[i] = 0;
+ }
+ nbSubMenus = 0;
+
+ if (check)
+ free (check);
+ check = 0;
+ if (entry)
+ free (entry);
+ entry = 0;
+ if (submenuEntry)
+ free (submenuEntry);
+ submenuEntry = 0;
+ nbAllocated = 0;
+ nbSubMenuAllocated = 0;
+
+ return true;
+}
+
+//------------------------------------------------------------------------
+long COptionMenu::getIndex (char *txt) const
+{
+ if (!txt)
+ return -1;
+
+ // search entries
+ for (long i = 0; i < nbEntries; i++)
+ if (!strcmp (entry[i], txt))
+ return i;
+
+ // not found
+ return -1;
+}
+
+//------------------------------------------------------------------------
+bool COptionMenu::checkEntry (long index, bool state)
+{
+ if (index < 0 || index >= nbEntries)
+ return false;
+
+ check[index] = state;
+
+ return true;
+}
+
+//------------------------------------------------------------------------
+bool COptionMenu::checkEntryAlone (long index)
+{
+ if (index < 0 || index >= nbEntries)
+ return false;
+ for (long i = 0; i < nbEntries; i++)
+ check[i] = false;
+ check[index] = true;
+
+ return true;
+}
+
+//------------------------------------------------------------------------
+bool COptionMenu::isCheckEntry (long index) const
+{
+ if (index < 0 || index >= nbEntries)
+ return false;
+
+ return check[index];
+}
+
+//------------------------------------------------------------------------
+void COptionMenu::draw (CDrawContext *pContext)
+{
+// DBG ("COptionMenu::draw");
+
+ if (currentIndex >= 0 && nbEntries)
+ drawText (pContext, entry[currentIndex] + prefixNumbers);
+ else
+ drawText (pContext, NULL);
+}
+
+//------------------------------------------------------------------------
+void COptionMenu::mouse (CDrawContext *pContext, CPoint &where, long button)
+{
+ if (!bMouseEnabled || !getFrame () || !pContext)
+ return;
+
+ lastButton = (button != -1) ? button : pContext->getMouseButtons ();
+
+ if (listener && button & (kAlt | kShift | kControl | kApple))
+ {
+ if (listener->controlModifierClicked (pContext, this, button) != 0)
+ return;
+ }
+
+ if (lastButton & (kLButton|kRButton|kApple))
+ {
+ if (bgWhenClick)
+ {
+ char string[256];
+ if (currentIndex >= 0)
+ sprintf (string, "%s", entry[currentIndex]);
+ else
+ string[0] = 0;
+
+ drawText (pContext, string, bgWhenClick);
+ }
+
+ beginEdit();
+ takeFocus (pContext);
+ }
+}
+
+//------------------------------------------------------------------------
+/*
+#include <Xm/RowColumn.h>
+#include <Xm/ToggleB.h>
+#include <Xm/PushB.h>
+#include <Xm/SeparatoG.h>
+
+static void _unmapCallback (Widget item, XtPointer clientData, XtPointer callData);
+static void _activateCallback (Widget item, XtPointer clientData, XtPointer callData);
+
+//------------------------------------------------------------------------
+static void _unmapCallback (Widget item, XtPointer clientData, XtPointer callData)
+{
+ COptionMenu *optionMenu= (COptionMenu*)clientData;
+ optionMenu->looseFocus ();
+}
+
+//------------------------------------------------------------------------
+static void _activateCallback (Widget item, XtPointer clientData, XtPointer callData)
+{
+ COptionMenu *optionMenu= (COptionMenu*)clientData;
+ optionMenu->setCurrentSelected ((void*)item);
+}
+*/
+
+//------------------------------------------------------------------------
+COptionMenu *COptionMenu::getLastItemMenu (long &idxInMenu) const
+{
+ idxInMenu = lastMenu ? (long)lastMenu->getValue (): -1;
+ return lastMenu;
+}
+
+//------------------------------------------------------------------------
+COptionMenu *COptionMenu::getItemMenu (long idx, long &idxInMenu, long &offsetIdx)
+{
+ COptionMenu *menu = 0;
+ for (long i = 0; i < nbSubMenus; i++)
+ {
+ menu = submenuEntry[i]->getItemMenu (idx, idxInMenu, offsetIdx);
+ if (menu)
+ break;
+ }
+ return menu;
+}
+
+//------------------------------------------------------------------------
+void COptionMenu::removeItems ()
+{
+ for (long i = 0; i < nbSubMenus; i++)
+ submenuEntry[i]->removeItems ();
+}
+
+//------------------------------------------------------------------------
+void *COptionMenu::appendItems (long &offsetIdx)
+{
+ //bool multipleCheck = style & (kMultipleCheckStyle & ~kCheckStyle);
+ return NULL;
+}
+
+//------------------------------------------------------------------------
+void COptionMenu::setValue (float val)
+{
+ if ((long)val < 0 || (long)val >= nbEntries)
+ return;
+
+ currentIndex = (long)val;
+ if (style & (kMultipleCheckStyle & ~kCheckStyle))
+ check[currentIndex] = !check[currentIndex];
+ CParamDisplay::setValue (val);
+
+ // to force the redraw
+ setDirty ();
+}
+
+//------------------------------------------------------------------------
+void COptionMenu::takeFocus (CDrawContext *pContext)
+{
+ if (!getFrame ())
+ return;
+
+/*
+
+ bool multipleCheck = style & (kMultipleCheckStyle & ~kCheckStyle);
+ lastResult = -1;
+ lastMenu = 0;
+
+ Arg args[10];
+ int n = 0;
+
+ // get the position of the pParent
+ CRect rect;
+ getFrame ()->getSize (&rect);
+
+ if (pContext)
+ {
+ rect.left += pContext->offset.h;
+ rect.top += pContext->offset.v;
+ }
+
+ // create a popup menu
+ int offset;
+ if (style & kPopupStyle)
+ offset = (int)(rect.top + size.top);
+ else
+ offset = (int)(rect.top + size.bottom);
+
+ XtSetArg (args[n], XmNx, rect.left + size.left); n++;
+ XtSetArg (args[n], XmNy, offset); n++;
+ XtSetArg (args[n], XmNmenuHistory, currentIndex); n++;
+ XtSetArg (args[n], XmNtraversalOn, true); n++;
+
+ platformControl = (void*)XmCreatePopupMenu ((Widget)(getFrame ()->getSystemWindow ()),
+ "popup", args, n);
+
+ XtAddCallback ((Widget)platformControl, XmNunmapCallback, _unmapCallback, this);
+
+ // insert the menu items
+ for (long i = 0; i < nbEntries; i++)
+ {
+ if (!strcmp (entry[i], kMenuSeparator))
+ {
+ itemWidget[i] = (void*)XtCreateManagedWidget ("separator",
+ xmSeparatorGadgetClass, (Widget)platformControl, 0, 0);
+ }
+ else
+ {
+ if (multipleCheck)
+ {
+ itemWidget[i] = (void*)XtVaCreateManagedWidget (entry[i],
+ xmToggleButtonWidgetClass, (Widget)platformControl,
+ XmNset, check[i], XmNvisibleWhenOff, false, 0);
+ XtAddCallback ((Widget)itemWidget[i], XmNvalueChangedCallback, _activateCallback, this);
+ }
+ else if (style & kCheckStyle)
+ {
+ itemWidget[i] = (void*)XtVaCreateManagedWidget (entry[i],
+ xmToggleButtonWidgetClass, (Widget)platformControl,
+ XmNset, (i == currentIndex) ? true : false, XmNvisibleWhenOff, false, 0);
+ XtAddCallback ((Widget)itemWidget[i], XmNvalueChangedCallback, _activateCallback, this);
+ }
+ else
+ {
+ itemWidget[i] = (void*)XtVaCreateManagedWidget (entry[i],
+ xmPushButtonWidgetClass, (Widget)platformControl, 0);
+ XtAddCallback ((Widget)itemWidget[i], XmNactivateCallback, _activateCallback, this);
+ }
+ }
+ }
+
+ XtManageChild ((Widget)platformControl);
+ getFrame ()->setFocusView (0);
+ endEdit();
+*/
+}
+
+//------------------------------------------------------------------------
+void COptionMenu::looseFocus (CDrawContext *pContext)
+{
+ if (platformControl == 0)
+ return;
+
+/*
+ for (long i = 0; i < nbEntries; i++)
+ if (itemWidget[i])
+ XtDestroyWidget ((Widget)itemWidget[i]);
+
+ if (platformControl)
+ {
+ XtUnmanageChild ((Widget)platformControl);
+ XtDestroyWidget ((Widget)platformControl);
+ }
+*/
+ platformControl = 0;
+}
+
+//------------------------------------------------------------------------
+void COptionMenu::setCurrentSelected (void *itemSelected)
+{
+ // retrieve the current index
+ if (itemSelected != 0)
+ {
+ for (long i = 0; i < nbEntries; i++)
+ if (itemWidget[i] == itemSelected)
+ {
+ currentIndex = i;
+ break;
+ }
+ }
+
+ // update dependency
+ CDrawContext *pContext = new CDrawContext (getFrame (), (void*)getFrame ()->getGC (), (void*)getFrame ()->getBackBuffer ());
+
+ setValue (currentIndex);
+
+ if (listener)
+ listener->valueChanged (pContext, this);
+ delete pContext;
+}
+
+
+//------------------------------------------------------------------------
+// CAnimKnob
+//------------------------------------------------------------------------
+/*! @class CAnimKnob
+Such as a CKnob control object, but there is a unique pixmap which contains different views (subpixmaps) of this knob.
+According to the value, a specific subpixmap is displayed. The different subpixmaps are stacked in the pixmap object.
+*/
+CAnimKnob::CAnimKnob (const CRect &size, CControlListener *listener, long tag,
+ CBitmap *background, CPoint &offset)
+: CKnob (size, listener, tag, background, 0, offset), bInverseBitmap (false)
+{
+ heightOfOneImage = size.height ();
+ subPixmaps = (short)(background->getHeight () / heightOfOneImage);
+ inset = 0;
+}
+
+//------------------------------------------------------------------------
+CAnimKnob::CAnimKnob (const CRect &size, CControlListener *listener, long tag,
+ long subPixmaps, // number of subPixmaps
+ CCoord heightOfOneImage, // height of one image in pixel
+ CBitmap *background, CPoint &offset)
+: CKnob (size, listener, tag, background, 0, offset),
+ subPixmaps (subPixmaps), heightOfOneImage (heightOfOneImage), bInverseBitmap (false)
+{
+ inset = 0;
+}
+
+//------------------------------------------------------------------------
+CAnimKnob::~CAnimKnob ()
+{}
+
+//-----------------------------------------------------------------------------------------------
+bool CAnimKnob::isDirty () const
+{
+ if (!bDirty)
+ {
+ CPoint p;
+ valueToPoint (p);
+ if (p == lastDrawnPoint)
+ return false;
+ }
+ return CKnob::isDirty ();
+}
+
+//------------------------------------------------------------------------
+void CAnimKnob::draw (CDrawContext *pContext)
+{
+// DBG ("CAnimKnob::draw");
+
+ CPoint where (0, 0);
+ if (value >= 0.f)
+ {
+ CCoord tmp = heightOfOneImage * (subPixmaps - 1);
+ if (bInverseBitmap)
+ where.v = (long)((1 - value) * (float)tmp);
+ else
+ where.v = (long)(value * (float)tmp);
+ for (CCoord realY = 0; realY <= tmp; realY += heightOfOneImage)
+ {
+ if (where.v < realY)
+ {
+ where.v = realY - heightOfOneImage;
+ if (where.v < 0)
+ where.v = 0;
+ break;
+ }
+ }
+ }
+
+ if (pBackground)
+ {
+ if (bTransparencyEnabled)
+ pBackground->drawTransparent (pContext, size, where);
+ else
+ pBackground->draw (pContext, size, where);
+ }
+ valueToPoint (lastDrawnPoint);
+ setDirty (false);
+}
+
+//------------------------------------------------------------------------
+// CVerticalSwitch
+//------------------------------------------------------------------------
+/*! @class CVerticalSwitch
+Define a switch with a given number of positions, the current position is defined by the position
+of the last click on this object (the object is divided in its height by the number of position).
+Each position has its subpixmap, each subpixmap is stacked in the given handle pixmap.
+By clicking Alt+Left Mouse the default value is used.
+*/
+CVerticalSwitch::CVerticalSwitch (const CRect &size, CControlListener *listener, long tag,
+ CBitmap *background, CPoint &offset)
+: CControl (size, listener, tag, background), offset (offset)
+{
+ heightOfOneImage = size.height ();
+ subPixmaps = (long)(background->getHeight () / heightOfOneImage);
+ iMaxPositions = subPixmaps;
+
+ setDefaultValue (0.f);
+}
+
+//------------------------------------------------------------------------
+CVerticalSwitch::CVerticalSwitch (const CRect &size, CControlListener *listener, long tag,
+ long subPixmaps, // number of subPixmaps
+ CCoord heightOfOneImage, // height of one image in pixel
+ long iMaxPositions,
+ CBitmap *background, CPoint &offset)
+: CControl (size, listener, tag, background), offset (offset),
+ subPixmaps (subPixmaps), heightOfOneImage (heightOfOneImage),
+ iMaxPositions (iMaxPositions)
+{
+ setDefaultValue (0.f);
+}
+
+//------------------------------------------------------------------------
+CVerticalSwitch::~CVerticalSwitch ()
+{}
+
+//------------------------------------------------------------------------
+void CVerticalSwitch::draw (CDrawContext *pContext)
+{
+// DBG ("CVerticalSwitch::draw");
+
+ if (pBackground)
+ {
+ // source position in bitmap
+ CPoint where (0, heightOfOneImage * ((long)(value * (iMaxPositions - 1) + 0.5f)));
+
+ if (bTransparencyEnabled)
+ pBackground->drawTransparent (pContext, size, where);
+ else
+ pBackground->draw (pContext, size, where);
+ }
+ setDirty (false);
+}
+
+//------------------------------------------------------------------------
+void CVerticalSwitch::mouse (CDrawContext *pContext, CPoint &where, long button)
+{
+ if (!bMouseEnabled)
+ return;
+
+ if (button == -1) button = pContext->getMouseButtons ();
+ if (!(button & kLButton))
+ return;
+
+ if (listener && button & (kAlt | kShift | kControl | kApple))
+ {
+ if (listener->controlModifierClicked (pContext, this, button) != 0)
+ return;
+ }
+
+ // check if default value wanted
+ if (checkDefaultValue (pContext, button))
+ return;
+
+ double coef = (double)heightOfOneImage / (double)iMaxPositions;
+
+ // begin of edit parameter
+ beginEdit ();
+ do
+ {
+ value = (long)((where.v - size.top) / coef) / (float)(iMaxPositions - 1);
+ if (value > 1.f)
+ value = 1.f;
+ else if (value < 0.f)
+ value = 0.f;
+
+ if (isDirty () && listener)
+ listener->valueChanged (pContext, this);
+
+ getMouseLocation (pContext, where);
+
+ doIdleStuff ();
+ }
+ while (pContext->getMouseButtons () == button);
+
+ // end of edit parameter
+ endEdit ();
+}
+
+
+//------------------------------------------------------------------------
+// CHorizontalSwitch
+//------------------------------------------------------------------------
+/*! @class CHorizontalSwitch
+Same as the CVerticalSwitch but horizontal.
+*/
+CHorizontalSwitch::CHorizontalSwitch (const CRect &size, CControlListener *listener, long tag,
+ CBitmap *background, CPoint &offset)
+: CControl (size, listener, tag, background), offset (offset)
+{
+ heightOfOneImage = size.width ();
+ subPixmaps = (long)(background->getWidth () / heightOfOneImage);
+ iMaxPositions = subPixmaps;
+
+ setDefaultValue (0.f);
+}
+
+//------------------------------------------------------------------------
+CHorizontalSwitch::CHorizontalSwitch (const CRect &size, CControlListener *listener, long tag,
+ long subPixmaps, // number of subPixmaps
+ CCoord heightOfOneImage, // height of one image in pixel
+ long iMaxPositions,
+ CBitmap *background, CPoint &offset)
+: CControl (size, listener, tag, background), offset (offset),
+ subPixmaps (subPixmaps),
+ iMaxPositions (iMaxPositions),
+ heightOfOneImage (heightOfOneImage)
+{
+ setDefaultValue (0.f);
+}
+
+//------------------------------------------------------------------------
+CHorizontalSwitch::~CHorizontalSwitch ()
+{}
+
+//------------------------------------------------------------------------
+void CHorizontalSwitch::draw (CDrawContext *pContext)
+{
+// DBG ("CHorizontalSwitch::draw");
+
+ if (pBackground)
+ {
+ // source position in bitmap
+ CPoint where (0, heightOfOneImage * ((long)(value * (iMaxPositions - 1) + 0.5f)));
+
+ if (bTransparencyEnabled)
+ pBackground->drawTransparent (pContext, size, where);
+ else
+ pBackground->draw (pContext, size, where);
+ }
+ setDirty (false);
+}
+
+//------------------------------------------------------------------------
+void CHorizontalSwitch::mouse (CDrawContext *pContext, CPoint &where, long button)
+{
+ if (!bMouseEnabled)
+ return;
+
+ if (button == -1) button = pContext->getMouseButtons ();
+
+ if (listener && button & (kAlt | kShift | kControl | kApple))
+ {
+ if (listener->controlModifierClicked (pContext, this, button) != 0)
+ return;
+ }
+
+ if (!(button & kLButton))
+ return;
+
+ // check if default value wanted
+ if (checkDefaultValue (pContext, button))
+ return;
+
+ double coef = (double)pBackground->getWidth () / (double)iMaxPositions;
+
+ // begin of edit parameter
+ beginEdit ();
+ do
+ {
+ value = (long)((where.h - size.left) / coef) / (float)(iMaxPositions - 1);
+ if (value > 1.f)
+ value = 1.f;
+ else if (value < 0.f)
+ value = 0.f;
+
+ if (isDirty () && listener)
+ listener->valueChanged (pContext, this);
+
+ getMouseLocation (pContext, where);
+
+ doIdleStuff ();
+ }
+ while (pContext->getMouseButtons () == button);
+
+ // end of edit parameter
+ endEdit ();
+}
+
+
+//------------------------------------------------------------------------
+// CRockerSwitch
+//------------------------------------------------------------------------
+/*! @class CRockerSwitch
+Define a rocker switch with 3 states using 3 subpixmaps.
+One click on its leftside, then the first subpixmap is displayed.
+One click on its rightside, then the third subpixmap is displayed.
+When the mouse button is relaxed, the second subpixmap is framed.
+*/
+CRockerSwitch::CRockerSwitch (const CRect &size, CControlListener *listener, long tag, // identifier tag (ID)
+ CBitmap *background, CPoint &offset, const long style)
+: CControl (size, listener, tag, background), offset (offset), style (style)
+{
+ heightOfOneImage = size.width ();
+}
+
+//------------------------------------------------------------------------
+CRockerSwitch::CRockerSwitch (const CRect &size, CControlListener *listener, long tag, // identifier tag (ID)
+ CCoord heightOfOneImage, // height of one image in pixel
+ CBitmap *background, CPoint &offset, const long style)
+: CControl (size, listener, tag, background), offset (offset),
+ heightOfOneImage (heightOfOneImage), style (style)
+{}
+
+//------------------------------------------------------------------------
+CRockerSwitch::~CRockerSwitch ()
+{}
+
+//------------------------------------------------------------------------
+void CRockerSwitch::draw (CDrawContext *pContext)
+{
+// DBG ("CRockerSwitch::draw");
+
+ CPoint where (offset.h, offset.v);
+
+ if (value == 1.f)
+ where.v += 2 * heightOfOneImage;
+ else if (value == 0.f)
+ where.v += heightOfOneImage;
+
+ if (pBackground)
+ {
+ if (bTransparencyEnabled)
+ pBackground->drawTransparent (pContext, size, where);
+ else
+ pBackground->draw (pContext, size, where);
+ }
+ setDirty (false);
+}
+
+//------------------------------------------------------------------------
+void CRockerSwitch::mouse (CDrawContext *pContext, CPoint &where, long button)
+{
+ if (!bMouseEnabled)
+ return;
+
+ if (button == -1) button = pContext->getMouseButtons ();
+
+ if (listener && button & (kAlt | kShift | kControl | kApple))
+ {
+ if (listener->controlModifierClicked (pContext, this, button) != 0)
+ return;
+ }
+
+ if (!(button & kLButton))
+ return;
+
+ float fEntryState = value;
+
+ CCoord width_2 = size.width () / 2;
+ CCoord height_2 = size.height () / 2;
+
+ // begin of edit parameter
+ beginEdit ();
+
+ if (button)
+ {
+ do
+ {
+ if (style & kHorizontal)
+ {
+ if (where.h >= size.left && where.v >= size.top &&
+ where.h <= (size.left + width_2) && where.v <= size.bottom)
+ value = -1.0f;
+ else if (where.h >= (size.left + width_2) && where.v >= size.top &&
+ where.h <= size.right && where.v <= size.bottom)
+ value = 1.0f;
+ else
+ value = fEntryState;
+ }
+ else
+ {
+ if (where.h >= size.left && where.v >= size.top &&
+ where.h <= size.right && where.v <= (size.top + height_2))
+ value = -1.0f;
+ else if (where.h >= size.left && where.v >= (size.top + height_2) &&
+ where.h <= size.right && where.v <= size.bottom)
+ value = 1.0f;
+ else
+ value = fEntryState;
+ }
+
+ if (isDirty () && listener)
+ listener->valueChanged (pContext, this);
+
+ getMouseLocation (pContext, where);
+
+ doIdleStuff ();
+ }
+ while (pContext->getMouseButtons ());
+ }
+ else
+ {
+ if (where.h >= size.left && where.v >= size.top &&
+ where.h <= (size.left + width_2) && where.v <= size.bottom)
+ value = -1.0f;
+ else if (where.h >= (size.left + width_2) && where.v >= size.top &&
+ where.h <= size.right && where.v <= size.bottom)
+ value = 1.0f;
+
+ if (listener)
+ listener->valueChanged (pContext, this);
+ }
+
+ value = 0.f; // set button to UNSELECTED state
+ if (listener)
+ listener->valueChanged (pContext, this);
+
+ // end of edit parameter
+ endEdit ();
+}
+
+//------------------------------------------------------------------------
+bool CRockerSwitch::onWheel (CDrawContext *pContext, const CPoint &where, float distance)
+{
+ if (!bMouseEnabled)
+ return false;
+
+ if (distance > 0)
+ value = -1.0f;
+ else
+ value = 1.0f;
+
+ // begin of edit parameter
+ beginEdit ();
+
+ if (isDirty () && listener)
+ listener->valueChanged (pContext, this);
+
+ value = 0.0f; // set button to UNSELECTED state
+ if (listener)
+ listener->valueChanged (pContext, this);
+
+ // end of edit parameter
+ endEdit ();
+
+ return true;
+}
+
+
+//------------------------------------------------------------------------
+// CMovieBitmap
+//------------------------------------------------------------------------
+/*! @class CMovieBitmap
+A movie pixmap allows to display different subpixmaps according to its current value.
+*/
+CMovieBitmap::CMovieBitmap (const CRect &size, CControlListener *listener, long tag,
+ CBitmap *background, CPoint &offset)
+ : CControl (size, listener, tag, background), offset (offset),
+ subPixmaps (subPixmaps), heightOfOneImage (heightOfOneImage)
+{
+ heightOfOneImage = size.height ();
+ subPixmaps = (long)(background->getHeight () / heightOfOneImage);
+}
+
+//------------------------------------------------------------------------
+CMovieBitmap::CMovieBitmap (const CRect &size, CControlListener *listener, long tag,
+ long subPixmaps, // number of subPixmaps
+ CCoord heightOfOneImage, // height of one image in pixel
+ CBitmap *background, CPoint &offset)
+ : CControl (size, listener, tag, background), offset (offset),
+ subPixmaps (subPixmaps), heightOfOneImage (heightOfOneImage)
+{}
+
+//------------------------------------------------------------------------
+CMovieBitmap::~CMovieBitmap ()
+{}
+
+//------------------------------------------------------------------------
+void CMovieBitmap::draw (CDrawContext *pContext)
+{
+ // DBG ("CMovieBitmap::draw");
+
+ CPoint where (offset.h, offset.v);
+
+ if (value > 1.0f)
+ value = 1.0f;
+
+ if (value > 0.0f)
+ where.v += heightOfOneImage * (int)(value * (subPixmaps - 1) + 0.5);
+
+ if (pBackground)
+ {
+ if (bTransparencyEnabled)
+ pBackground->drawTransparent (pContext, size, where);
+ else
+ pBackground->draw (pContext, size, where);
+ }
+ setDirty (false);
+}
+
+
+//------------------------------------------------------------------------
+// CMovieButton
+//------------------------------------------------------------------------
+/*! @class CMovieButton
+A movie button is a bi-states button with 2 subpixmaps. These subpixmaps are stacked in the pixmap.
+*/
+CMovieButton::CMovieButton (const CRect &size, CControlListener *listener, long tag, // identifier tag (ID)
+ CBitmap *background, CPoint &offset)
+: CControl (size, listener, tag, background), offset (offset), buttonState (value)
+{
+ heightOfOneImage = size.height ();
+}
+
+//------------------------------------------------------------------------
+CMovieButton::CMovieButton (const CRect &size, CControlListener *listener, long tag,
+ CCoord heightOfOneImage, // height of one image in pixel
+ CBitmap *background, CPoint &offset)
+ : CControl (size, listener, tag, background), offset (offset),
+ heightOfOneImage (heightOfOneImage), buttonState (value)
+{}
+
+//------------------------------------------------------------------------
+CMovieButton::~CMovieButton ()
+{}
+
+//------------------------------------------------------------------------
+void CMovieButton::draw (CDrawContext *pContext)
+{
+ // DBG ("CMovieButton::draw");
+
+ CPoint where;
+
+ where.h = 0;
+
+ bounceValue ();
+
+ if (value)
+ where.v = heightOfOneImage;
+ else
+ where.v = 0;
+
+ if (pBackground)
+ {
+ if (bTransparencyEnabled)
+ pBackground->drawTransparent (pContext, size, where);
+ else
+ pBackground->draw (pContext, size, where);
+ }
+ buttonState = value;
+
+ setDirty (false);
+}
+
+//------------------------------------------------------------------------
+void CMovieButton::mouse (CDrawContext *pContext, CPoint &where, long button)
+{
+ if (!bMouseEnabled)
+ return;
+
+ if (button == -1) button = pContext->getMouseButtons ();
+
+ if (listener && button & (kAlt | kShift | kControl | kApple))
+ {
+ if (listener->controlModifierClicked (pContext, this, button) != 0)
+ return;
+ }
+
+ if (!(button & kLButton))
+ return;
+
+ // this simulates a real windows button
+ float fEntryState = value;
+
+ // begin of edit parameter
+ beginEdit ();
+
+ if (pContext->getMouseButtons ())
+ {
+ do
+ {
+ if (where.h >= size.left &&
+ where.v >= size.top &&
+ where.h <= size.right &&
+ where.v <= size.bottom)
+ value = !fEntryState;
+ else
+ value = fEntryState;
+
+ if (isDirty () && listener)
+ listener->valueChanged (pContext, this);
+
+ getMouseLocation (pContext, where);
+
+ doIdleStuff ();
+ }
+ while (pContext->getMouseButtons () == button);
+ }
+ else
+ {
+ value = !value;
+ if (listener)
+ listener->valueChanged (pContext, this);
+ }
+
+ // end of edit parameter
+ endEdit ();
+
+ buttonState = value;
+}
+
+
+//------------------------------------------------------------------------
+// CAutoAnimation
+//------------------------------------------------------------------------
+/*! @class CAutoAnimation
+An auto-animation control contains a given number of subpixmap which can be displayed in loop.
+Two functions allows to get the previous or the next subpixmap (these functions increase or decrease the current value of this control).
+*/
+// displays bitmaps within a (child-) window
+CAutoAnimation::CAutoAnimation (const CRect &size, CControlListener *listener, long tag,
+ CBitmap *background, CPoint &offset)
+: CControl (size, listener, tag, background), offset (offset), bWindowOpened (false)
+{
+ heightOfOneImage = size.height ();
+ subPixmaps = (long)(background->getHeight () / heightOfOneImage);
+
+ totalHeightOfBitmap = heightOfOneImage * subPixmaps;
+}
+
+//------------------------------------------------------------------------
+CAutoAnimation::CAutoAnimation (const CRect &size, CControlListener *listener, long tag,
+ long subPixmaps, // number of subPixmaps...
+ CCoord heightOfOneImage, // height of one image in pixel
+ CBitmap *background, CPoint &offset)
+ : CControl (size, listener, tag, background), offset (offset),
+ subPixmaps (subPixmaps), heightOfOneImage (heightOfOneImage),
+ bWindowOpened (false)
+{
+ totalHeightOfBitmap = heightOfOneImage * subPixmaps;
+}
+
+//------------------------------------------------------------------------
+CAutoAnimation::~CAutoAnimation ()
+{}
+
+//------------------------------------------------------------------------
+void CAutoAnimation::draw (CDrawContext *pContext)
+{
+ // DBG ("CAutoAnimation::draw");
+
+ if (isWindowOpened ())
+ {
+ CPoint where;
+ where.v = (long)value + offset.v;
+ where.h = offset.h;
+
+ if (pBackground)
+ {
+ if (bTransparencyEnabled)
+ pBackground->drawTransparent (pContext, size, where);
+ else
+ pBackground->draw (pContext, size, where);
+ }
+ }
+ setDirty (false);
+}
+
+//------------------------------------------------------------------------
+void CAutoAnimation::mouse (CDrawContext *pContext, CPoint &where, long button)
+{
+ if (!bMouseEnabled)
+ return;
+
+ if (button == -1) button = pContext->getMouseButtons ();
+
+ if (listener && button & (kAlt | kShift | kControl | kApple))
+ {
+ if (listener->controlModifierClicked (pContext, this, button) != 0)
+ return;
+ }
+
+ if (!(button & kLButton))
+ return;
+
+ if (!isWindowOpened ())
+ {
+ value = 0;
+ openWindow ();
+ setDirty (); // force to redraw
+ if (listener)
+ listener->valueChanged (pContext, this);
+ }
+ else
+ {
+ // stop info animation
+ value = 0; // draw first pic of bitmap
+ setDirty ();
+ closeWindow ();
+ }
+}
+
+//------------------------------------------------------------------------
+void CAutoAnimation::openWindow ()
+{
+ bWindowOpened = true;
+}
+
+//------------------------------------------------------------------------
+void CAutoAnimation::closeWindow ()
+{
+ bWindowOpened = false;
+}
+
+//------------------------------------------------------------------------
+void CAutoAnimation::nextPixmap ()
+{
+ value += heightOfOneImage;
+ if (value >= (totalHeightOfBitmap - heightOfOneImage))
+ value = 0;
+}
+
+//------------------------------------------------------------------------
+void CAutoAnimation::previousPixmap ()
+{
+ value -= heightOfOneImage;
+ if (value < 0.f)
+ value = (float)(totalHeightOfBitmap - heightOfOneImage - 1);
+}
+
+
+//------------------------------------------------------------------------
+// CSlider
+//------------------------------------------------------------------------
+/*! @class CSlider
+Define a slider with a given background and handle.
+The range of variation of the handle should be defined.
+By default the handler is drawn with transparency (white color).
+By clicking Alt+Left Mouse the default value is used.
+*/
+CSlider::CSlider (const CRect &rect, CControlListener *listener, long tag,
+ long iMinPos, // min position in pixel
+ long iMaxPos, // max position in pixel
+ CBitmap *handle, // bitmap of slider
+ CBitmap *background, // bitmap of background
+ CPoint &offset, // offset in the background
+ const long style) // style (kBottom,kRight,kTop,kLeft,kHorizontal,kVertical)
+ : CControl (rect, listener, tag, background), offset (offset), pHandle (handle),
+ pOScreen (0), style (style), bFreeClick (true)
+{
+ setDrawTransparentHandle (true);
+
+ if (pHandle)
+ {
+ pHandle->remember ();
+ widthOfSlider = pHandle->getWidth ();
+ heightOfSlider = pHandle->getHeight ();
+ }
+ else
+ {
+ widthOfSlider = 1;
+ heightOfSlider = 1;
+ }
+
+ widthControl = size.width ();
+ heightControl = size.height ();
+
+ if (style & kHorizontal)
+ {
+ minPos = iMinPos - size.left;
+ rangeHandle = iMaxPos - iMinPos;
+ CPoint p (0, 0);
+ setOffsetHandle (p);
+ }
+ else
+ {
+ minPos = iMinPos - size.top;
+ rangeHandle = iMaxPos - iMinPos;
+ CPoint p (0, 0);
+ setOffsetHandle (p);
+ }
+
+ zoomFactor = 10.f;
+
+ setWantsFocus (true);
+}
+
+//------------------------------------------------------------------------
+CSlider::CSlider (const CRect &rect, CControlListener *listener, long tag,
+ CPoint &offsetHandle, // handle offset
+ long _rangeHandle, // size of handle range
+ CBitmap *handle, // bitmap of slider
+ CBitmap *background, // bitmap of background
+ CPoint &offset, // offset in the background
+ const long style) // style (kBottom,kRight,kTop,kLeft,kHorizontal,kVertical)
+: CControl (rect, listener, tag, background), offset (offset), pHandle (handle),
+ pOScreen (0), style (style), minPos (0), bFreeClick (true)
+{
+ setDrawTransparentHandle (true);
+
+ if (pHandle)
+ {
+ pHandle->remember ();
+ widthOfSlider = pHandle->getWidth ();
+ heightOfSlider = pHandle->getHeight ();
+ }
+ else
+ {
+ widthOfSlider = 1;
+ heightOfSlider = 1;
+ }
+
+ widthControl = size.width ();
+ heightControl = size.height ();
+ if (style & kHorizontal)
+ rangeHandle = _rangeHandle - widthOfSlider;
+ else
+ rangeHandle = _rangeHandle - heightOfSlider;
+
+ setOffsetHandle (offsetHandle);
+
+ zoomFactor = 10.f;
+
+ setWantsFocus (true);
+}
+
+//------------------------------------------------------------------------
+CSlider::~CSlider ()
+{
+ if (pHandle)
+ pHandle->forget ();
+}
+
+//------------------------------------------------------------------------
+void CSlider::setOffsetHandle (CPoint &val)
+{
+ offsetHandle = val;
+
+ if (style & kHorizontal)
+ {
+ minTmp = offsetHandle.h + minPos;
+ maxTmp = minTmp + rangeHandle + widthOfSlider;
+ }
+ else
+ {
+ minTmp = offsetHandle.v + minPos;
+ maxTmp = minTmp + rangeHandle + heightOfSlider;
+ }
+}
+
+//-----------------------------------------------------------------------------
+bool CSlider::attached (CView *parent)
+{
+ if (pOScreen)
+ delete pOScreen;
+
+ pOScreen = 0; // @TODO - faking offscreen
+// pOScreen = new COffscreenContext (getFrame (), widthControl, heightControl, kBlackCColor);
+
+ return CControl::attached (parent);
+}
+
+//-----------------------------------------------------------------------------
+bool CSlider::removed (CView *parent)
+{
+ if (pOScreen)
+ {
+ delete pOScreen;
+ pOScreen = 0;
+ }
+ return CControl::removed (parent);
+}
+
+//------------------------------------------------------------------------
+void CSlider::draw (CDrawContext *pContext)
+{
+ // DBG ("CSlider::draw");
+
+ CDrawContext* drawContext = pOScreen ? pOScreen : pContext;
+
+ if (pOScreen && bTransparencyEnabled)
+ pOScreen->copyTo (pContext, size);
+
+ float fValue;
+ if (style & kLeft || style & kTop)
+ fValue = value;
+ else
+ fValue = 1.f - value;
+
+ // (re)draw background
+ CRect rect (0, 0, widthControl, heightControl);
+ if (!pOScreen)
+ rect.offset (size.left, size.top);
+ if (pBackground)
+ {
+ if (bTransparencyEnabled)
+ pBackground->drawTransparent (drawContext, rect, offset);
+ else
+ pBackground->draw (drawContext, rect, offset);
+ }
+
+ // calc new coords of slider
+ CRect rectNew;
+ if (style & kHorizontal)
+ {
+ rectNew.top = offsetHandle.v;
+ rectNew.bottom = rectNew.top + heightOfSlider;
+
+ rectNew.left = offsetHandle.h + (int)(fValue * rangeHandle);
+ rectNew.left = (rectNew.left < minTmp) ? minTmp : rectNew.left;
+
+ rectNew.right = rectNew.left + widthOfSlider;
+ rectNew.right = (rectNew.right > maxTmp) ? maxTmp : rectNew.right;
+ }
+ else
+ {
+ rectNew.left = offsetHandle.h;
+ rectNew.right = rectNew.left + widthOfSlider;
+
+ rectNew.top = offsetHandle.v + (int)(fValue * rangeHandle);
+ rectNew.top = (rectNew.top < minTmp) ? minTmp : rectNew.top;
+
+ rectNew.bottom = rectNew.top + heightOfSlider;
+ rectNew.bottom = (rectNew.bottom > maxTmp) ? maxTmp : rectNew.bottom;
+ }
+ if (!pOScreen)
+ rectNew.offset (size.left, size.top);
+
+ // draw slider at new position
+ if (pHandle)
+ {
+ if (bDrawTransparentEnabled)
+ pHandle->drawTransparent (drawContext, rectNew);
+ else
+ pHandle->draw (drawContext, rectNew);
+ }
+
+ if (pOScreen)
+ pOScreen->copyFrom (pContext, size);
+
+ setDirty (false);
+}
+
+//------------------------------------------------------------------------
+void CSlider::mouse (CDrawContext *pContext, CPoint &where, long button)
+{
+ if (!bMouseEnabled)
+ return;
+
+ if (button == -1) button = pContext->getMouseButtons ();
+
+ if (listener && button & (kAlt | kShift | kControl | kApple))
+ {
+ if (listener->controlModifierClicked (pContext, this, button) != 0)
+ return;
+ }
+
+ // check if default value wanted
+ if (checkDefaultValue (pContext, button))
+ return;
+
+ // allow left mousebutton only
+ if (!(button & kLButton))
+ return;
+
+ CCoord delta;
+ if (style & kHorizontal)
+ delta = size.left + offsetHandle.h;
+ else
+ delta = size.top + offsetHandle.v;
+ if (!bFreeClick)
+ {
+ float fValue;
+ if (style & kLeft || style & kTop)
+ fValue = value;
+ else
+ fValue = 1.f - value;
+ CCoord actualPos;
+ CRect rect;
+
+ if (style & kHorizontal)
+ {
+ actualPos = offsetHandle.h + (int)(fValue * rangeHandle) + size.left;
+
+ rect.left = actualPos;
+ rect.top = size.top + offsetHandle.v;
+ rect.right = rect.left + widthOfSlider;
+ rect.bottom = rect.top + heightOfSlider;
+
+ if (!where.isInside (rect))
+ return;
+ else
+ delta += where.h - actualPos;
+ }
+ else
+ {
+ actualPos = offsetHandle.v + (int)(fValue * rangeHandle) + size.top;
+
+ rect.left = size.left + offsetHandle.h;
+ rect.top = actualPos;
+ rect.right = rect.left + widthOfSlider;
+ rect.bottom = rect.top + heightOfSlider;
+
+ if (!where.isInside (rect))
+ return;
+ else
+ delta += where.v - actualPos;
+ }
+ }
+ else
+ {
+ if (style & kHorizontal)
+ delta += widthOfSlider / 2 - 1;
+ else
+ delta += heightOfSlider / 2 - 1;
+ }
+
+ float oldVal = value;
+ long oldButton = button;
+
+ // begin of edit parameter
+ beginEdit ();
+
+ while (1)
+ {
+ button = pContext->getMouseButtons ();
+ if (!(button & kLButton))
+ break;
+
+ if ((oldButton != button) && (button & kShift))
+ {
+ oldVal = value;
+ oldButton = button;
+ }
+ else if (!(button & kShift))
+ oldVal = value;
+
+ if (style & kHorizontal)
+ value = (float)(where.h - delta) / (float)rangeHandle;
+ else
+ value = (float)(where.v - delta) / (float)rangeHandle;
+
+ if (style & kRight || style & kBottom)
+ value = 1.f - value;
+
+ if (button & kShift)
+ value = oldVal + ((value - oldVal) / zoomFactor);
+ bounceValue ();
+
+ if (isDirty () && listener)
+ listener->valueChanged (pContext, this);
+
+ getMouseLocation (pContext, where);
+
+ doIdleStuff ();
+ }
+
+ // end of edit parameter
+ endEdit ();
+}
+
+//------------------------------------------------------------------------
+bool CSlider::onWheel (CDrawContext *pContext, const CPoint &where, float distance)
+{
+ if (!bMouseEnabled)
+ return false;
+
+ long buttons = pContext->getMouseButtons ();
+ if (buttons & kShift)
+ value += 0.1f * distance * wheelInc;
+ else
+ value += distance * wheelInc;
+ bounceValue ();
+
+ if (isDirty () && listener)
+ {
+ // begin of edit parameter
+ beginEdit ();
+
+ listener->valueChanged (pContext, this);
+
+ // end of edit parameter
+ endEdit ();
+ }
+
+ return true;
+}
+
+//------------------------------------------------------------------------
+long CSlider::onKeyDown (VstKeyCode& keyCode)
+{
+ switch (keyCode.virt)
+ {
+ case VKEY_UP :
+ case VKEY_RIGHT :
+ case VKEY_DOWN :
+ case VKEY_LEFT :
+ {
+ float distance = 1.f;
+ if (keyCode.virt == VKEY_DOWN || keyCode.virt == VKEY_LEFT)
+ distance = -distance;
+
+ if (keyCode.modifier & MODIFIER_SHIFT)
+ value += 0.1f * distance * wheelInc;
+ else
+ value += distance * wheelInc;
+ bounceValue ();
+
+ if (isDirty () && listener)
+ {
+ // begin of edit parameter
+ beginEdit ();
+
+ listener->valueChanged (0, this);
+
+ // end of edit parameter
+ endEdit ();
+ }
+ } return 1;
+ }
+ return -1;
+}
+
+//------------------------------------------------------------------------
+void CSlider::setHandle (CBitmap *_pHandle)
+{
+ if (pHandle)
+ pHandle->forget ();
+ pHandle = _pHandle;
+ if (pHandle)
+ {
+ pHandle->remember ();
+ widthOfSlider = pHandle->getWidth ();
+ heightOfSlider = pHandle->getHeight ();
+ }
+}
+
+
+//------------------------------------------------------------------------
+// CVerticalSlider
+//------------------------------------------------------------------------
+/*! @class CVerticalSlider
+This is the vertical slider. See CSlider.
+*/
+CVerticalSlider::CVerticalSlider (const CRect &rect, CControlListener *listener, long tag,
+ long iMinPos, // min position in pixel
+ long iMaxPos, // max position in pixel
+ CBitmap *handle, // bitmap of slider
+ CBitmap *background, // bitmap of background
+ CPoint &offset, // offset in the background
+ const long style) // style (kLeft, kRight)
+ : CSlider (rect, listener, tag, iMinPos, iMaxPos, handle, background, offset, style|kVertical)
+{}
+
+//------------------------------------------------------------------------
+CVerticalSlider::CVerticalSlider (const CRect &rect, CControlListener *listener, long tag,
+ CPoint &offsetHandle, // handle offset
+ long rangeHandle, // size of handle range
+ CBitmap *handle, // bitmap of slider
+ CBitmap *background, // bitmap of background
+ CPoint &offset, // offset in the background
+ const long style) // style (kLeft, kRight)
+: CSlider (rect, listener, tag, offsetHandle, rangeHandle, handle, background, offset, style|kVertical)
+{}
+
+
+//------------------------------------------------------------------------
+// CHorizontalSlider
+//------------------------------------------------------------------------
+/*! @class CHorizontalSlider
+This is the horizontal slider. See CSlider.
+*/
+CHorizontalSlider::CHorizontalSlider (const CRect &rect, CControlListener *listener, long tag,
+ long iMinPos, // min Y position in pixel
+ long iMaxPos, // max Y position in pixel
+ CBitmap *handle, // bitmap of slider
+ CBitmap *background, // bitmap of background
+ CPoint &offset, // offset in the background
+ const long style) // style (kLeft, kRight)
+ : CSlider (rect, listener, tag, iMinPos, iMaxPos, handle, background, offset, style|kHorizontal)
+{}
+
+//------------------------------------------------------------------------
+CHorizontalSlider::CHorizontalSlider (const CRect &rect, CControlListener *listener, long tag,
+ CPoint &offsetHandle, // handle offset
+ long rangeHandle, // size of handle range
+ CBitmap *handle, // bitmap of slider
+ CBitmap *background, // bitmap of background
+ CPoint &offset, // offset in the background
+ const long style) // style (kLeft, kRight)
+: CSlider (rect, listener, tag, offsetHandle, rangeHandle, handle, background, offset, style|kHorizontal)
+{}
+
+
+//------------------------------------------------------------------------
+// CSpecialDigit
+//------------------------------------------------------------------------
+/*! @class CSpecialDigit
+Can be used to display a counter with maximum 7 digits.
+All digit have the same size and are stacked in height in the pixmap.
+*/
+CSpecialDigit::CSpecialDigit (const CRect &size,
+ CControlListener *listener,
+ long tag, // tag identifier
+ long dwPos, // actual value
+ long iNumbers, // amount of numbers (max 7)
+ long *xpos, // array of all XPOS
+ long *ypos, // array of all YPOS
+ long width, // width of ONE number
+ long height, // height of ONE number
+ CBitmap *background) // bitmap numbers
+ : CControl (size, listener, tag, background),
+ iNumbers (iNumbers), width (width), height (height)
+{
+ setValue ((float)dwPos); // actual value
+
+ if (iNumbers > 7)
+ iNumbers = 7;
+
+ if (xpos == NULL)
+ {
+ // automatically init xpos/ypos if not provided by caller
+ const int numw = (const int)background->getWidth();
+ int x = (int)size.left;
+ for (long i = 0; i < iNumbers; i++)
+ {
+ this->xpos[i] = x;
+ this->ypos[i] = (long)size.top;
+ x += numw;
+ }
+ }
+ else
+ {
+ // store coordinates of x/y pos of each digit
+ for (long i = 0; i < iNumbers; i++)
+ {
+ this->xpos[i] = xpos[i];
+ this->ypos[i] = ypos[i];
+ }
+ }
+
+ setMax ((float)pow (10., (double)iNumbers) - 1.0f);
+ setMin (0.0f);
+}
+
+//------------------------------------------------------------------------
+CSpecialDigit::~CSpecialDigit ()
+{}
+
+//------------------------------------------------------------------------
+void CSpecialDigit::draw (CDrawContext *pContext)
+{
+// DBG ("CSpecialDigit::draw");
+
+ CPoint where;
+ CRect rectDest;
+ long i, j;
+ long dwValue;
+ long one_digit[16];
+
+ if ((long)value >= getMax ())
+ dwValue = (long)getMax ();
+ else if ((long)value < getMin ())
+ dwValue = (long)getMin ();
+ else
+ dwValue = (long)value;
+
+ for (i = 0, j = ((long)getMax () + 1) / 10; i < iNumbers; i++, j /= 10)
+ {
+ one_digit[i] = dwValue / j;
+ dwValue -= (one_digit[i] * j);
+ }
+
+ where.h = 0;
+ for (i = 0; i < iNumbers; i++)
+ {
+ j = one_digit[i];
+ if (j > 9)
+ j = 9;
+
+ rectDest.left = xpos[i];
+ rectDest.top = ypos[i];
+
+ rectDest.right = rectDest.left + width;
+ rectDest.bottom = rectDest.top + height;
+
+ // where = src from bitmap
+ where.v = j * height;
+ if (pBackground)
+ {
+ if (bTransparencyEnabled)
+ pBackground->drawTransparent (pContext, rectDest, where);
+ else
+ pBackground->draw (pContext, rectDest, where);
+ }
+ }
+
+ setDirty (false);
+}
+
+//------------------------------------------------------------------------
+float CSpecialDigit::getNormValue () const
+{
+ float fTemp;
+ fTemp = value / getMax ();
+ if (fTemp > 1.0f)
+ fTemp = 1.0f;
+ else if (fTemp < 0.0f)
+ fTemp = 0.0f;
+
+ return fTemp;
+}
+
+
+//------------------------------------------------------------------------
+// CKickButton
+//------------------------------------------------------------------------
+/*! @class CKickButton
+Define a button with 2 states using 2 subpixmaps.
+One click on it, then the second subpixmap is displayed.
+When the mouse button is relaxed, the first subpixmap is framed.
+*/
+CKickButton::CKickButton (const CRect &size, CControlListener *listener, long tag,
+ CBitmap *background, CPoint &offset)
+: CControl (size, listener, tag, background), offset (offset)
+{
+ heightOfOneImage = size.height ();
+}
+
+//------------------------------------------------------------------------
+CKickButton::CKickButton (const CRect &size, CControlListener *listener, long tag,
+ CCoord heightOfOneImage, // height of one image in pixel
+ CBitmap *background, CPoint &offset)
+: CControl (size, listener, tag, background), offset (offset),
+ heightOfOneImage (heightOfOneImage)
+{}
+
+//------------------------------------------------------------------------
+CKickButton::~CKickButton ()
+{}
+
+//------------------------------------------------------------------------
+void CKickButton::draw (CDrawContext *pContext)
+{
+ // DBG ("CKickButton::draw");
+
+ CPoint where (offset.h, offset.v);
+
+ bounceValue ();
+
+ if (value)
+ where.v += heightOfOneImage;
+
+ if (pBackground)
+ {
+ if (bTransparencyEnabled)
+ pBackground->drawTransparent (pContext, size, where);
+ else
+ pBackground->draw (pContext, size, where);
+ }
+ setDirty (false);
+}
+
+//------------------------------------------------------------------------
+void CKickButton::mouse (CDrawContext *pContext, CPoint &where, long button)
+{
+ if (!bMouseEnabled)
+ return;
+
+ if (button == -1) button = pContext->getMouseButtons ();
+
+ if (listener && button & (kAlt | kShift | kControl | kApple))
+ {
+ if (listener->controlModifierClicked (pContext, this, button) != 0)
+ return;
+ }
+
+ if (!(button & kLButton))
+ return;
+
+ // this simulates a real windows button
+ float fEntryState = value;
+
+ // begin of edit parameter
+ beginEdit ();
+
+ if (pContext->getMouseButtons () == kLButton)
+ {
+ do
+ {
+ if (where.h >= size.left && where.v >= size.top &&
+ where.h <= size.right && where.v <= size.bottom)
+ value = !fEntryState;
+ else
+ value = fEntryState;
+
+ if (isDirty () && listener)
+ listener->valueChanged (pContext, this);
+
+ getMouseLocation (pContext, where);
+
+ doIdleStuff ();
+ }
+ while (pContext->getMouseButtons () == kLButton);
+ }
+ else
+ {
+ value = !value;
+ if (listener)
+ listener->valueChanged (pContext, this);
+ }
+
+ value = 0.0f; // set button to UNSELECTED state
+ if (listener)
+ listener->valueChanged (pContext, this);
+
+ // end of edit parameter
+ endEdit ();
+}
+
+
+//------------------------------------------------------------------------
+// CSplashScreen
+//------------------------------------------------------------------------
+/*! @class CSplashScreen
+One click on its activated region and its pixmap is displayed, in this state the other control can not be used,
+an another click on the displayed area reinstalls the normal frame.
+This can be used to display a help view over the other views.
+*/
+// one click draw its pixmap, an another click redraw its parent
+CSplashScreen::CSplashScreen (const CRect &size, CControlListener *listener, long tag,
+ CBitmap *background,
+ CRect &toDisplay,
+ CPoint &offset)
+: CControl (size, listener, tag, background),
+ toDisplay (toDisplay), offset (offset), bitmapTransparency (255)
+{}
+
+//------------------------------------------------------------------------
+CSplashScreen::~CSplashScreen ()
+{}
+
+//------------------------------------------------------------------------
+void CSplashScreen::setBitmapTransparency (unsigned char transparency)
+{
+ bitmapTransparency = transparency;
+ setTransparency (bitmapTransparency != 255);
+}
+
+//------------------------------------------------------------------------
+void CSplashScreen::draw (CDrawContext *pContext)
+{
+ // DBG ("CSplashScreen::draw");
+
+ if (value && pBackground)
+ {
+ if (bTransparencyEnabled)
+ {
+ if (bitmapTransparency)
+ pBackground->drawAlphaBlend (pContext, toDisplay, offset, bitmapTransparency);
+ else
+ pBackground->drawTransparent (pContext, toDisplay, offset);
+ }
+ else
+ pBackground->draw (pContext, toDisplay, offset);
+ }
+ setDirty (false);
+}
+
+//------------------------------------------------------------------------
+bool CSplashScreen::hitTest (const CPoint& where, const long buttons)
+{
+ bool result = CView::hitTest (where, buttons);
+ if (result && !(buttons & kLButton))
+ return false;
+ return result;
+}
+
+//------------------------------------------------------------------------
+void CSplashScreen::mouse (CDrawContext *pContext, CPoint &where, long button)
+{
+ if (!bMouseEnabled)
+ return;
+
+ if (button == -1) button = pContext->getMouseButtons ();
+
+ if (listener && button & (kAlt | kShift | kControl | kApple))
+ {
+ if (listener->controlModifierClicked (pContext, this, button) != 0)
+ return;
+ }
+
+ if (!(button & kLButton))
+ return;
+
+ value = !value;
+ if (value)
+ {
+ if (getFrame () && getFrame ()->setModalView (this))
+ {
+ keepSize = size;
+ size = toDisplay;
+ mouseableArea = size;
+// draw (pContext);
+ if (listener)
+ listener->valueChanged (pContext, this);
+ }
+ setDirty ();
+ }
+ else
+ {
+ size = keepSize;
+ mouseableArea = size;
+ if (listener)
+ listener->valueChanged (pContext, this);
+ if (getFrame ())
+ {
+ getFrame ()->setDirty (true);
+ getFrame ()->setModalView (NULL);
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+void CSplashScreen::unSplash ()
+{
+ setDirty ();
+ value = 0.f;
+
+ size = keepSize;
+ if (getFrame ())
+ {
+ if (getFrame ()->getModalView () == this)
+ {
+ getFrame ()->setModalView (NULL);
+ getFrame ()->redraw ();
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+// CVuMeter
+//------------------------------------------------------------------------
+CVuMeter::CVuMeter (const CRect &size, CBitmap *onBitmap, CBitmap *offBitmap,
+ long nbLed, const long style)
+ : CControl (size, 0, 0),
+ onBitmap (onBitmap), offBitmap (offBitmap), pOScreen (0),
+ nbLed (nbLed), style (style)
+{
+ bUseOffscreen = false;
+
+ setDecreaseStepValue (0.1f);
+
+ if (onBitmap)
+ onBitmap->remember ();
+ if (offBitmap)
+ offBitmap->remember ();
+
+ rectOn (size.left, size.top, size.right, size.bottom);
+ rectOff (size.left, size.top, size.right, size.bottom);
+}
+
+//------------------------------------------------------------------------
+CVuMeter::~CVuMeter ()
+{
+ if (onBitmap)
+ onBitmap->forget ();
+ if (offBitmap)
+ offBitmap->forget ();
+}
+
+//------------------------------------------------------------------------
+void CVuMeter::setDirty (const bool val)
+{
+ CView::setDirty (val);
+}
+
+//-----------------------------------------------------------------------------
+bool CVuMeter::attached (CView *parent)
+{
+ if (pOScreen)
+ delete pOScreen;
+/*
+ if (bUseOffscreen)
+ {
+ pOScreen = new COffscreenContext (getFrame (), (long)size.width (), (long)size.height (), kBlackCColor);
+ rectOn (0, 0, size.width (), size.height ());
+ rectOff (0, 0, size.width (), size.height ());
+ }
+ else
+*/
+ {
+ rectOn (size.left, size.top, size.right, size.bottom);
+ rectOff (size.left, size.top, size.right, size.bottom);
+ }
+
+ return CControl::attached (parent);
+}
+
+//------------------------------------------------------------------------
+void CVuMeter::setUseOffscreen (bool val)
+{
+// bUseOffscreen = val; // @TODO - faking offscreen
+ bUseOffscreen = false;
+}
+
+//-----------------------------------------------------------------------------
+bool CVuMeter::removed (CView *parent)
+{
+ if (pOScreen)
+ {
+ delete pOScreen;
+ pOScreen = 0;
+ }
+ return CControl::removed (parent);
+}
+
+//------------------------------------------------------------------------
+void CVuMeter::draw (CDrawContext *_pContext)
+{
+ // DBG ("CVuMeter::draw");
+
+ if (!onBitmap)
+ return;
+
+ CPoint pointOn;
+ CPoint pointOff;
+ CDrawContext *pContext = _pContext;
+
+ bounceValue ();
+
+ float newValue = oldValue - decreaseValue;
+ if (newValue < value)
+ newValue = value;
+ oldValue = newValue;
+
+/*
+ if (bUseOffscreen)
+ {
+ if (!pOScreen)
+ {
+ pOScreen = new COffscreenContext (getFrame (), (long)size.width (), (long)size.height (), kBlackCColor);
+ rectOn (0, 0, size.width (), size.height ());
+ rectOff (0, 0, size.width (), size.height ());
+ }
+ pContext = pOScreen;
+ }
+*/
+
+ if (style & kHorizontal)
+ {
+ CCoord tmp = (long)(((long)(nbLed * newValue + 0.5f) / (float)nbLed) * onBitmap->getWidth ());
+ pointOff (tmp, 0);
+ if (!bUseOffscreen)
+ tmp += size.left;
+
+ rectOff.left = tmp;
+ rectOn.right = tmp;
+ }
+ else
+ {
+ CCoord tmp = (long)(((long)(nbLed * (getMax () - newValue) + 0.5f) / (float)nbLed) * onBitmap->getHeight ());
+ pointOn (0, tmp);
+ if (!bUseOffscreen)
+ tmp += size.top;
+
+ rectOff.bottom = tmp;
+ rectOn.top = tmp;
+ }
+
+ if (offBitmap)
+ {
+ if (bTransparencyEnabled)
+ offBitmap->drawTransparent (pContext, rectOff, pointOff);
+ else
+ offBitmap->draw (pContext, rectOff, pointOff);
+ }
+
+ if (bTransparencyEnabled)
+ onBitmap->drawTransparent (pContext, rectOn, pointOn);
+ else
+ onBitmap->draw (pContext, rectOn, pointOn);
+
+ if (pOScreen)
+ pOScreen->copyFrom (_pContext, size);
+
+ setDirty (false);
+}
+
+} // namespace VSTGUI
+
+//------------------------------------------------------------------------
+// END.
+//------------------------------------------------------------------------
diff --git a/vstgui/vstcontrols.h b/vstgui/vstcontrols.h
new file mode 100644
index 0000000..0505f82
--- /dev/null
+++ b/vstgui/vstcontrols.h
@@ -0,0 +1,994 @@
+/* ----------------------------------------------------------------------------
+ * VSTGUI for X11/LV2/PNG
+ * Author: Dave Robillard
+ * Released under the revised BSD license, as below
+ * ----------------------------------------------------------------------------
+ *
+ * Based on:
+ * ----------------------------------------------------------------------------
+ * VSTGUIL: Graphical User Interface Framework for VST plugins on LINUX
+ * Version: 0.1, Date: 2007/01/21
+ * Author: kRAkEn/gORe
+ *
+ * Which was based on:
+ * ----------------------------------------------------------------------------
+ * VSTGUI: Graphical User Interface Framework for VST plugins
+ * Version 3.0 $Date: 2005/08/12 12:45:00 $
+ * ----------------------------------------------------------------------------
+ * VSTGUI LICENSE
+ * 2004, Steinberg Media Technologies, All Rights Reserved
+ * ----------------------------------------------------------------------------
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Steinberg Media Technologies nor the names of
+ * its contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ * ----------------------------------------------------------------------------
+ */
+
+#ifndef __vstcontrols__
+#define __vstcontrols__
+
+#ifndef __vstgui__
+#include "vstgui.h"
+#endif
+
+//------------------
+// defines
+//------------------
+#ifndef kPI
+#define kPI 3.14159265358979323846
+#endif
+
+#ifndef k2PI
+#define k2PI 6.28318530717958647692
+#endif
+
+#ifndef kPI_2
+#define kPI_2 1.57079632679489661923f
+#endif
+
+#ifndef kPI_4
+#define kPI_4 0.78539816339744830962
+#endif
+
+#ifndef kE
+#define kE 2.7182818284590452354
+#endif
+
+#ifndef kLN2
+#define kLN2 0.69314718055994530942
+#endif
+
+#ifndef kSQRT2
+#define kSQRT2 1.41421356237309504880
+#endif
+
+//------------------
+// CControlEnum type
+//------------------
+enum CControlEnum
+{
+ kHorizontal = 1 << 0,
+ kVertical = 1 << 1,
+ kShadowText = 1 << 2,
+ kLeft = 1 << 3,
+ kRight = 1 << 4,
+ kTop = 1 << 5,
+ kBottom = 1 << 6,
+ k3DIn = 1 << 7,
+ k3DOut = 1 << 8,
+ kPopupStyle = 1 << 9,
+ kCheckStyle = 1 << 10,
+ kMultipleCheckStyle,
+ kNoTextStyle = 1 << 11,
+ kNoDrawStyle = 1 << 12,
+ kDoubleClickStyle = 1 << 13,
+ kNoFrame = 1 << 14
+};
+
+//---------------------------
+// Some defines for Menu item
+//---------------------------
+#define kMenuTitle "-T"
+#define kMenuSeparator "-"
+#define kMenuDisable "-G"
+#define kMenuSubMenu "-M"
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+class CControlListener
+{
+public:
+ virtual ~CControlListener () {}
+
+ virtual void valueChanged (VSTGUI::CDrawContext *pContext, VSTGUI::CControl *pControl) = 0;
+ virtual long controlModifierClicked (VSTGUI::CDrawContext *pContext, VSTGUI::CControl *pControl, long button) { return 0; } // return 1 if you want the control to not handle it, otherwise 0
+};
+
+class AudioEffectX;
+
+//-----------------------------------------------------------------------------
+namespace VSTGUI {
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// CControl Declaration
+//! base class of all VSTGUI controls
+//-----------------------------------------------------------------------------
+class CControl : public CView
+{
+public:
+ CControl (const CRect &size, CControlListener *listener = 0, long tag = 0,
+ CBitmap *pBackground = 0);
+ virtual ~CControl ();
+
+ virtual void draw (CDrawContext *pContext) = 0;
+ virtual void doIdleStuff () { if (pParentFrame) pParentFrame->doIdleStuff (); }
+
+ virtual void setValue (float val) { value = val; }
+ virtual float getValue () const { return value; };
+
+ virtual void setMin (float val) { vmin = val; }
+ virtual float getMin () const { return vmin; }
+ virtual void setMax (float val) { vmax = val; }
+ virtual float getMax () const { return vmax; }
+
+ virtual void setOldValue (float val) { oldValue = val; }
+ virtual float getOldValue (void) const { return oldValue; }
+ virtual void setDefaultValue (float val) { defaultValue = val; }
+ virtual float getDefaultValue (void) const { return defaultValue; }
+
+ virtual void setTag (long val) { tag = val; }
+ virtual long getTag () const { return tag; }
+
+ virtual bool isDirty () const;
+ virtual void setDirty (const bool val = true);
+
+ virtual void beginEdit ();
+ virtual void endEdit ();
+
+ virtual void setBackOffset (CPoint &offset);
+ virtual void copyBackOffset ();
+
+ virtual void setWheelInc (float val) { wheelInc = val; }
+ virtual float getWheelInc () const { return wheelInc; }
+
+ virtual void bounceValue ();
+ virtual bool checkDefaultValue (CDrawContext *pContext, long button);
+
+ CControlListener* getListener () const { return listener; }
+ void setListener (CControlListener* l) { listener = l; }
+ bool isDoubleClick ();
+
+ CLASS_METHODS(CControl, CView)
+
+protected:
+ CControlListener *listener;
+ long tag;
+ float oldValue;
+ float defaultValue;
+ float value;
+ float vmin;
+ float vmax;
+ float wheelInc;
+
+ long lastTicks;
+ long delta;
+
+ CPoint backOffset;
+};
+
+
+//-----------------------------------------------------------------------------
+// COnOffButton Declaration
+//! a button control with 2 states
+//-----------------------------------------------------------------------------
+class COnOffButton : public CControl
+{
+public:
+ COnOffButton (const CRect &size, CControlListener *listener, long tag,
+ CBitmap *background, long style = kPreListenerUpdate);
+ virtual ~COnOffButton ();
+
+ virtual void draw (CDrawContext*);
+ virtual void mouse (CDrawContext *pContext, CPoint &where, long button = -1);
+
+ virtual long getStyle () const { return style; }
+ virtual void setStyle (long newStyle) { style = newStyle; }
+
+ enum {
+ kPreListenerUpdate, ///< listener will be called after doIdleStuff was called
+ kPostListenerUpdate ///< listener will be called before doIdleStuff is called
+ };
+
+ CLASS_METHODS(COnOffButton, CControl)
+protected:
+ long style;
+};
+
+
+//-----------------------------------------------------------------------------
+// CParamDisplay Declaration
+//! a parameter display control
+//-----------------------------------------------------------------------------
+class CParamDisplay : public CControl
+{
+public:
+ CParamDisplay (const CRect &size, CBitmap *background = 0, const long style = 0);
+ virtual ~CParamDisplay ();
+
+ virtual void setFont (CFont fontID);
+ CFont getFont () const { return fontID; }
+
+ virtual void setFontColor (CColor color);
+ CColor getFontColor () const { return fontColor; }
+
+ virtual void setBackColor (CColor color);
+ CColor getBackColor () const { return backColor; }
+
+ virtual void setFrameColor (CColor color);
+ CColor getFrameColor () const { return frameColor; }
+
+ virtual void setShadowColor (CColor color);
+ CColor getShadowColor () const { return shadowColor; }
+
+ virtual void setHoriAlign (CHoriTxtAlign hAlign);
+
+ virtual void setStringConvert (void (*convert) (float value, char *string));
+ virtual void setStringConvert (void (*convert) (float value, char *string, void *userDta),
+ void *userData);
+ virtual void setString2FloatConvert (void (*convert) (char *string, float &output));
+
+ virtual void setStyle (long val);
+ long getStyle () const { return style; }
+
+ virtual void setTxtFace (CTxtFace val);
+ CTxtFace getTxtFace () const { return txtFace; }
+
+ virtual void draw (CDrawContext *pContext);
+
+ virtual void setTextTransparency (bool val) { bTextTransparencyEnabled = val; }
+ bool getTextTransparency () const { return bTextTransparencyEnabled; }
+
+ CLASS_METHODS(CParamDisplay, CControl)
+
+protected:
+ void drawText (CDrawContext *pContext, char *string, CBitmap *newBack = 0);
+
+ void (*stringConvert) (float value, char *string);
+ void (*stringConvert2) (float value, char *string, void *userData);
+ void (*string2FloatConvert) (char *string, float &output);
+ void *userData;
+
+ CHoriTxtAlign horiTxtAlign;
+ long style;
+
+ CFont fontID;
+ CTxtFace txtFace;
+ CColor fontColor;
+ CColor backColor;
+ CColor frameColor;
+ CColor shadowColor;
+ bool bTextTransparencyEnabled;
+};
+
+
+//-----------------------------------------------------------------------------
+// CLabel Declaration
+//! a text label
+//-----------------------------------------------------------------------------
+class CTextLabel : public CParamDisplay
+{
+public:
+ CTextLabel (const CRect& size, const char* txt = 0, CBitmap* background = 0, const long style = 0);
+ ~CTextLabel ();
+
+ virtual void setText (const char* txt);
+ virtual const char* getText () const;
+
+ virtual void draw (CDrawContext *pContext);
+
+ CLASS_METHODS(CTextLabel, CParamDisplay)
+
+protected:
+ void freeText ();
+ char* text;
+};
+
+//-----------------------------------------------------------------------------
+// CTextEdit Declaration
+//! a text edit control
+//-----------------------------------------------------------------------------
+class CTextEdit : public CParamDisplay
+{
+public:
+ CTextEdit (const CRect &size, CControlListener *listener, long tag, const char *txt = 0,
+ CBitmap *background = 0, const long style = 0);
+ virtual ~CTextEdit ();
+
+ virtual void setText (char *txt);
+ virtual void getText (char *txt) const;
+
+ virtual void draw (CDrawContext *pContext);
+ virtual void mouse (CDrawContext *pContext, CPoint &where, long button = -1);
+
+ virtual void setTextEditConvert (void (*editConvert) (char *input, char *string));
+ virtual void setTextEditConvert (void (*editConvert2) (char *input, char *string,
+ void *userDta), void *userData);
+
+ virtual void takeFocus (CDrawContext *pContext = 0);
+ virtual void looseFocus (CDrawContext *pContext = 0);
+
+ void *platformFontColor;
+ void *platformControl;
+ bool bWasReturnPressed;
+
+ CLASS_METHODS(CTextEdit, CParamDisplay)
+
+protected:
+ void *platformFont;
+ char text[256];
+
+ void (*editConvert) (char *input, char *string);
+ void (*editConvert2) (char *input, char *string, void *userData);
+};
+
+
+//-----------------------------------------------------------------------------
+// COptionMenuScheme Declaration
+//-----------------------------------------------------------------------------
+class COptionMenuScheme : public CReferenceCounter
+{
+public:
+ COptionMenuScheme ();
+ virtual ~COptionMenuScheme ();
+
+ enum { kChecked = 0x01, kDisabled = 0x02, kSelected = 0x04, kSubMenu = 0x08, kTitle = 0x10 };
+
+ virtual void getItemSize (const char* text, CDrawContext* pContext, CPoint& size);
+ virtual void drawItem (const char* text, long itemId, long state, CDrawContext* pContext, const CRect& rect);
+
+ void setColors (CColor back, CColor select, CColor text, CColor htext, CColor dtext)
+ { backgroundColor = back; selectionColor = select; textColor = text;
+ hiliteTextColor = htext; disableTextColor = dtext;}
+
+ void setFont (CFont f) { font = f; }
+protected:
+
+ CColor backgroundColor;
+ CColor selectionColor;
+ CColor textColor;
+ CColor hiliteTextColor;
+ CColor disableTextColor;
+ CFont font;
+
+ virtual void drawItemBack (CDrawContext* pContext, const CRect& rect, bool hilite);
+};
+
+//-----------------------------------------------------------------------------
+extern COptionMenuScheme* gOptionMenuScheme;
+
+//-----------------------------------------------------------------------------
+// COptionMenu Declaration
+//! a popup menu control
+//-----------------------------------------------------------------------------
+class COptionMenu : public CParamDisplay
+{
+public:
+ COptionMenu (const CRect &size, CControlListener *listener, long tag,
+ CBitmap *background = 0, CBitmap *bgWhenClick = 0,
+ const long style = 0);
+ virtual ~COptionMenu ();
+
+ enum { MAX_ENTRY = 1024 };
+
+ virtual void setValue (float val);
+ virtual bool addEntry (COptionMenu *subMenu, char *txt);
+ virtual bool addEntry (char *txt, long index = -1);
+ virtual long getCurrent (char *txt = 0, bool countSeparator = true) const;
+ virtual bool setCurrent (long index, bool countSeparator = true);
+ virtual bool getEntry (long index, char *txt) const;
+ virtual bool setEntry (long index, char *txt);
+ virtual bool removeEntry (long index);
+ virtual bool removeAllEntry ();
+ virtual long getNbEntries () const { return nbEntries; }
+ virtual long getIndex (char *txt) const;
+
+ virtual bool checkEntry (long index, bool state);
+ virtual bool checkEntryAlone (long index);
+ virtual bool isCheckEntry (long index) const;
+
+ virtual void draw (CDrawContext *pContext);
+ virtual void mouse (CDrawContext *pContext, CPoint &where, long button = -1);
+
+ virtual void takeFocus (CDrawContext *pContext = 0);
+ virtual void looseFocus (CDrawContext *pContext = 0);
+
+ virtual void setNbItemsPerColumn (long val) { nbItemsPerColumn = val; }
+ virtual long getNbItemsPerColumn () const { return nbItemsPerColumn; }
+
+ void setCurrentSelected (void *itemSelected);
+
+ long getLastResult () const { return lastResult; }
+ COptionMenu *getLastItemMenu (long &idxInMenu) const;
+
+ void setScheme (COptionMenuScheme* s) { scheme = s; }
+ virtual COptionMenuScheme* getScheme () const { return scheme; }
+
+ virtual void setPrefixNumbers (long preCount);
+
+ COptionMenu* getSubMenu (long idx) const;
+
+ CLASS_METHODS(COptionMenu, CParamDisplay)
+
+protected:
+ COptionMenu *getItemMenu (long idx, long &idxInMenu, long &offsetIdx);
+ void removeItems ();
+ void *appendItems (long &offsetIdx);
+
+ void *platformControl;
+
+ bool allocateMenu (long nb);
+ bool allocateSubMenu (long nb);
+
+ char **entry;
+ COptionMenu **submenuEntry;
+ bool *check;
+
+ void *itemWidget[MAX_ENTRY];
+
+ long nbEntries;
+ long nbSubMenus;
+ long currentIndex;
+ CBitmap *bgWhenClick;
+ long lastButton;
+ long nbItemsPerColumn;
+ long nbAllocated;
+ long nbSubMenuAllocated;
+ long lastResult;
+ long prefixNumbers;
+ COptionMenu *lastMenu;
+ COptionMenuScheme* scheme;
+};
+
+
+//-----------------------------------------------------------------------------
+// CKnob Declaration
+//! a knob control
+//-----------------------------------------------------------------------------
+class CKnob : public CControl
+{
+public:
+ CKnob (const CRect &size, CControlListener *listener, long tag,
+ CBitmap *background, CBitmap *handle, const CPoint &offset);
+ virtual ~CKnob ();
+
+ virtual void draw (CDrawContext *pContext);
+ virtual void mouse (CDrawContext *pContext, CPoint &where, long button = -1);
+ virtual bool onWheel (CDrawContext *pContext, const CPoint &where, float distance);
+ virtual long onKeyDown (VstKeyCode& keyCode);
+
+ virtual void drawHandle (CDrawContext *pContext);
+
+ virtual void setStartAngle (float val);
+ virtual float getStartAngle () const { return startAngle; }
+
+ virtual void setRangeAngle (float val);
+ virtual float getRangeAngle () const { return rangeAngle; }
+
+ virtual void valueToPoint (CPoint &point) const;
+ virtual float valueFromPoint (CPoint &point) const;
+
+ virtual void setInsetValue (long val) { inset = val; }
+
+ virtual void setColorShadowHandle (CColor color);
+ virtual void setColorHandle (CColor color);
+
+ virtual void setHandleBitmap (CBitmap *bitmap);
+
+ virtual void setZoomFactor (float val) { zoomFactor = val; }
+ virtual float getZoomFactor () const { return zoomFactor; }
+
+ CLASS_METHODS(CKnob, CControl)
+
+protected:
+ void compute ();
+
+ CPoint offset;
+ CColor colorHandle, colorShadowHandle;
+
+ CBitmap *pHandle;
+ long inset;
+ float startAngle, rangeAngle, halfAngle;
+ float aCoef, bCoef;
+ float radius;
+ float zoomFactor;
+};
+
+//-----------------------------------------------------------------------------
+// CAnimKnob Declaration
+//! a bitmap knob control
+//-----------------------------------------------------------------------------
+class CAnimKnob : public CKnob
+{
+public:
+ CAnimKnob (const CRect &size, CControlListener *listener, long tag,
+ CBitmap *background, CPoint &offset);
+ CAnimKnob (const CRect &size, CControlListener *listener, long tag,
+ long subPixmaps, // number of subPixmaps
+ CCoord heightOfOneImage, // pixel
+ CBitmap *background, CPoint &offset);
+ virtual ~CAnimKnob ();
+
+ virtual bool isDirty () const;
+
+ virtual void draw (CDrawContext* pContext);
+
+ void setInverseBitmap (bool val) { bInverseBitmap = val; }
+
+ CLASS_METHODS(CAnimKnob, CKnob)
+
+protected:
+ long subPixmaps; // number of subPixmaps
+ CCoord heightOfOneImage;
+ bool bInverseBitmap;
+ CPoint lastDrawnPoint;
+};
+
+//-----------------------------------------------------------------------------
+// CVerticalSwitch Declaration
+//! a vertical switch control
+//-----------------------------------------------------------------------------
+class CVerticalSwitch : public CControl
+{
+public:
+ CVerticalSwitch (const CRect &size, CControlListener *listener, long tag,
+ CBitmap *background, CPoint &offset);
+ CVerticalSwitch (const CRect &size, CControlListener *listener, long tag,
+ long subPixmaps, // number of subPixmaps
+ CCoord heightOfOneImage, // pixel
+ long iMaxPositions,
+ CBitmap *background, CPoint &offset);
+ virtual ~CVerticalSwitch ();
+
+ virtual void draw (CDrawContext*);
+ virtual void mouse (CDrawContext *pContext, CPoint &where, long button = -1);
+
+ CLASS_METHODS(CVerticalSwitch, CControl)
+
+protected:
+ CPoint offset;
+ long subPixmaps; // number of subPixmaps
+ CCoord heightOfOneImage;
+ long iMaxPositions;
+};
+
+
+//-----------------------------------------------------------------------------
+// CHorizontalSwitch Declaration
+//! a horizontal switch control
+//-----------------------------------------------------------------------------
+class CHorizontalSwitch : public CControl
+{
+public:
+ CHorizontalSwitch (const CRect &size, CControlListener *listener, long tag,
+ CBitmap *background, CPoint &offset);
+ CHorizontalSwitch (const CRect &size, CControlListener *listener, long tag,
+ long subPixmaps, // number of subPixmaps
+ CCoord heightOfOneImage, // pixel
+ long iMaxPositions,
+ CBitmap *background, CPoint &offset);
+ virtual ~CHorizontalSwitch ();
+
+ virtual void draw (CDrawContext*);
+ virtual void mouse (CDrawContext *pContext, CPoint &where, long button = -1);
+
+ CLASS_METHODS(CHorizontalSwitch, CControl)
+
+protected:
+ CPoint offset;
+ long subPixmaps; // number of subPixmaps
+ long iMaxPositions;
+ CCoord heightOfOneImage;
+};
+
+
+//-----------------------------------------------------------------------------
+// CRockerSwitch Declaration
+//! a switch control with 3 sub bitmaps
+//-----------------------------------------------------------------------------
+class CRockerSwitch : public CControl
+{
+public:
+ CRockerSwitch (const CRect &size, CControlListener *listener, long tag,
+ CBitmap *background, CPoint &offset, const long style = kHorizontal);
+ CRockerSwitch (const CRect &size, CControlListener *listener, long tag,
+ CCoord heightOfOneImage, // pixel
+ CBitmap *background, CPoint &offset, const long style = kHorizontal);
+ virtual ~CRockerSwitch ();
+
+ virtual void draw (CDrawContext*);
+ virtual void mouse (CDrawContext *pContext, CPoint &where, long button = -1);
+ virtual bool onWheel (CDrawContext *pContext, const CPoint &where, float distance);
+
+ CLASS_METHODS(CRockerSwitch, CControl)
+
+protected:
+ CPoint offset;
+ CCoord heightOfOneImage;
+ long style;
+};
+
+
+//-----------------------------------------------------------------------------
+// CMovieBitmap Declaration
+//! a bitmap control that displays different bitmaps according to its current value
+//-----------------------------------------------------------------------------
+class CMovieBitmap : public CControl
+{
+public:
+ CMovieBitmap (const CRect &size, CControlListener *listener, long tag,
+ CBitmap *background, CPoint &offset);
+ CMovieBitmap (const CRect &size, CControlListener *listener, long tag,
+ long subPixmaps, // number of subPixmaps
+ CCoord heightOfOneImage, // pixel
+ CBitmap *background, CPoint &offset);
+ virtual ~CMovieBitmap ();
+
+ virtual void draw (CDrawContext*);
+
+ CLASS_METHODS(CMovieBitmap, CControl)
+
+protected:
+ CPoint offset;
+ long subPixmaps; // number of subPixmaps
+ CCoord heightOfOneImage;
+};
+
+
+//-----------------------------------------------------------------------------
+// CMovieButton Declaration
+//! a bi-states button with 2 subbitmaps
+//-----------------------------------------------------------------------------
+class CMovieButton : public CControl
+{
+public:
+ CMovieButton (const CRect &size, CControlListener *listener, long tag,
+ CBitmap *background, CPoint &offset);
+ CMovieButton (const CRect &size, CControlListener *listener, long tag,
+ CCoord heightOfOneImage, // pixel
+ CBitmap *background, CPoint &offset);
+ virtual ~CMovieButton ();
+
+ virtual void draw (CDrawContext*);
+ virtual void mouse (CDrawContext *pContext, CPoint &where, long button = -1);
+
+ CLASS_METHODS(CMovieButton, CControl)
+
+protected:
+ CPoint offset;
+ CCoord heightOfOneImage;
+ float buttonState;
+};
+
+
+//-----------------------------------------------------------------------------
+// CAutoAnimation Declaration
+//!
+//-----------------------------------------------------------------------------
+class CAutoAnimation : public CControl
+{
+public:
+ CAutoAnimation (const CRect &size, CControlListener *listener, long tag,
+ CBitmap *background, CPoint &offset);
+ CAutoAnimation (const CRect &size, CControlListener *listener, long tag,
+ long subPixmaps, // number of subPixmaps...
+ CCoord heightOfOneImage, // pixel
+ CBitmap *background, CPoint &offset);
+ virtual ~CAutoAnimation ();
+
+ virtual void draw (CDrawContext*);
+ virtual void mouse (CDrawContext *pContext, CPoint &where, long button = -1);
+
+ virtual void openWindow (void);
+ virtual void closeWindow (void);
+
+ virtual void nextPixmap (void);
+ virtual void previousPixmap (void);
+
+ bool isWindowOpened () const { return bWindowOpened; }
+
+ CLASS_METHODS(CAutoAnimation, CControl)
+
+protected:
+ CPoint offset;
+
+ long subPixmaps;
+ CCoord heightOfOneImage;
+ CCoord totalHeightOfBitmap;
+
+ bool bWindowOpened;
+};
+
+
+//-----------------------------------------------------------------------------
+// CSlider Declaration
+//! a slider control
+//-----------------------------------------------------------------------------
+class CSlider : public CControl
+{
+public:
+ CSlider (const CRect &size, CControlListener *listener, long tag,
+ long iMinPos, // min position in pixel
+ long iMaxPos, // max position in pixel
+ CBitmap *handle, // handle bitmap
+ CBitmap *background, // background bitmap
+ CPoint &offset, // offset in the background
+ const long style = kLeft|kHorizontal); // style (kBottom,kRight,kTop,kLeft,kHorizontal,kVertical)
+
+ CSlider (const CRect &rect, CControlListener *listener, long tag,
+ CPoint &offsetHandle, // handle offset
+ long rangeHandle, // size of handle range
+ CBitmap *handle, // handle bitmap
+ CBitmap *background, // background bitmap
+ CPoint &offset, // offset in the background
+ const long style = kLeft|kHorizontal); // style (kBottom,kRight,kTop,kLeft,kHorizontal,kVertical)
+
+ virtual ~CSlider ();
+
+ virtual bool attached (CView *parent);
+ virtual bool removed (CView *parent);
+ virtual void draw (CDrawContext*);
+ virtual void mouse (CDrawContext *pContext, CPoint &where, long button = -1);
+ virtual bool onWheel (CDrawContext *pContext, const CPoint &where, float distance);
+ virtual long onKeyDown (VstKeyCode& keyCode);
+
+ virtual void setDrawTransparentHandle (bool val) { bDrawTransparentEnabled = val; }
+ virtual void setFreeClick (bool val) { bFreeClick = val; }
+ virtual bool getFreeClick () const { return bFreeClick; }
+ virtual void setOffsetHandle (CPoint &val);
+
+ virtual void setHandle (CBitmap* pHandle);
+ virtual CBitmap *getHandle () const { return pHandle; }
+
+ virtual void setZoomFactor (float val) { zoomFactor = val; }
+ virtual float getZoomFactor () const { return zoomFactor; }
+
+ CLASS_METHODS(CSlider, CControl)
+
+protected:
+ CPoint offset;
+ CPoint offsetHandle;
+
+ CBitmap *pHandle;
+ COffscreenContext *pOScreen;
+
+ long style;
+
+ CCoord widthOfSlider; // size of the handle-slider
+ CCoord heightOfSlider;
+ CCoord rangeHandle;
+ CCoord minTmp;
+ CCoord maxTmp;
+ CCoord minPos;
+ CCoord widthControl;
+ CCoord heightControl;
+ float zoomFactor;
+
+ bool bDrawTransparentEnabled;
+ bool bFreeClick;
+};
+
+//-----------------------------------------------------------------------------
+// CVerticalSlider Declaration
+//! a vertical slider control
+//-----------------------------------------------------------------------------
+class CVerticalSlider : public CSlider
+{
+public:
+ CVerticalSlider (const CRect &size, CControlListener *listener, long tag,
+ long iMinPos, // min Y position in pixel
+ long iMaxPos, // max Y position in pixel
+ CBitmap *handle, // bitmap slider
+ CBitmap *background, // bitmap background
+ CPoint &offset, // offset in the background
+ const long style = kBottom); // style (kBottom, kTop))
+
+ CVerticalSlider (const CRect &rect, CControlListener *listener, long tag,
+ CPoint &offsetHandle, // handle offset
+ long rangeHandle, // size of handle range
+ CBitmap *handle, // bitmap of slider
+ CBitmap *background, // bitmap of background
+ CPoint &offset, // offset in the background
+ const long style = kBottom); // style (kBottom, kTop)
+};
+
+//-----------------------------------------------------------------------------
+// CHorizontalSlider Declaration
+//! a horizontal slider control
+//-----------------------------------------------------------------------------
+class CHorizontalSlider : public CSlider
+{
+public:
+ CHorizontalSlider (const CRect &size, CControlListener *listener, long tag,
+ long iMinPos, // min X position in pixel
+ long iMaxPos, // max X position in pixel
+ CBitmap *handle, // bitmap slider
+ CBitmap *background, // bitmap background
+ CPoint &offset, // offset in the background
+ const long style = kRight); // style (kRight, kLeft)
+
+ CHorizontalSlider (const CRect &rect, CControlListener *listener, long tag,
+ CPoint &offsetHandle, // handle offset
+ long rangeHandle, // size of handle range
+ CBitmap *handle, // bitmap of slider
+ CBitmap *background, // bitmap of background
+ CPoint &offset, // offset in the background
+ const long style = kRight); // style (kRight, kLeft)
+};
+
+
+//-----------------------------------------------------------------------------
+// CSpecialDigit Declaration
+//! special display with custom numbers (0...9)
+//-----------------------------------------------------------------------------
+class CSpecialDigit : public CControl
+{
+public:
+ CSpecialDigit (const CRect &size, CControlListener *listener, long tag, // tag identifier
+ long dwPos, // actual value
+ long iNumbers, // amount of numbers (max 7)
+ long *xpos, // array of all XPOS
+ long *ypos, // array of all YPOS
+ long width, // width of ONE number
+ long height, // height of ONE number
+ CBitmap *background); // bitmap numbers
+ virtual ~CSpecialDigit ();
+
+ virtual void draw (CDrawContext*);
+
+ virtual float getNormValue (void) const;
+
+ CLASS_METHODS(CSpecialDigit, CControl)
+
+protected:
+ long iNumbers; // amount of numbers
+ long xpos[7]; // array of all XPOS, max 7 possible
+ long ypos[7]; // array of all YPOS, max 7 possible
+ long width; // width of ONE number
+ long height; // height of ONE number
+};
+
+
+//-----------------------------------------------------------------------------
+// CKickButton Declaration
+//!
+//-----------------------------------------------------------------------------
+class CKickButton : public CControl
+{
+public:
+ CKickButton (const CRect &size, CControlListener *listener, long tag,
+ CBitmap *background, CPoint &offset);
+ CKickButton (const CRect &size, CControlListener *listener, long tag,
+ CCoord heightOfOneImage, // pixel
+ CBitmap *background, CPoint &offset);
+ virtual ~CKickButton ();
+
+ virtual void draw (CDrawContext*);
+ virtual void mouse (CDrawContext *pContext, CPoint &where, long button = -1);
+
+ CLASS_METHODS(CKickButton, CControl)
+
+protected:
+ CPoint offset;
+ CCoord heightOfOneImage;
+};
+
+
+//-----------------------------------------------------------------------------
+// CSplashScreen Declaration
+//!
+//-----------------------------------------------------------------------------
+class CSplashScreen : public CControl
+{
+public:
+ CSplashScreen (const CRect &size, CControlListener *listener, long tag,
+ CBitmap *background,
+ CRect &toDisplay,
+ CPoint &offset);
+ virtual ~CSplashScreen ();
+
+ virtual void draw (CDrawContext*);
+ virtual bool hitTest (const CPoint& where, const long buttons = -1);
+ virtual void mouse (CDrawContext *pContext, CPoint &where, long button = -1);
+ virtual void unSplash ();
+
+ void setBitmapTransparency (unsigned char transparency);
+
+ CLASS_METHODS(CSplashScreen, CControl)
+
+protected:
+ CRect toDisplay;
+ CRect keepSize;
+ CPoint offset;
+ unsigned char bitmapTransparency;
+};
+
+
+//-----------------------------------------------------------------------------
+// CVuMeter Declaration
+//!
+//-----------------------------------------------------------------------------
+class CVuMeter : public CControl
+{
+public:
+ CVuMeter (const CRect& size, CBitmap *onBitmap, CBitmap *offBitmap,
+ long nbLed, const long style = kVertical);
+ virtual ~CVuMeter ();
+
+ virtual void setDecreaseStepValue (float value) { decreaseValue = value; }
+
+ virtual bool attached (CView *parent);
+ virtual bool removed (CView *parent);
+ virtual void draw (CDrawContext *pContext);
+ virtual void setDirty (const bool val = true);
+
+ void setUseOffscreen (bool val = true);
+ bool getUseOffscreen () const { return bUseOffscreen; }
+
+ CLASS_METHODS(CVuMeter, CControl)
+
+protected:
+ CBitmap *onBitmap;
+ CBitmap *offBitmap;
+ COffscreenContext *pOScreen;
+
+ long nbLed;
+ long style;
+ float decreaseValue;
+ bool bUseOffscreen;
+
+ CRect rectOn;
+ CRect rectOff;
+};
+
+
+#if !PLUGGUI
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+class CFileSelector
+{
+public:
+ CFileSelector (AudioEffectX* effect);
+ virtual ~CFileSelector ();
+
+ long run (VstFileSelect *vstFileSelect);
+
+protected:
+ AudioEffectX* effect;
+ VstFileSelect *vstFileSelect;
+};
+#endif
+
+} // namespace VSTGUI
+
+#endif // __vstcontrol__
diff --git a/vstgui/vstgui.cpp b/vstgui/vstgui.cpp
new file mode 100644
index 0000000..ab52007
--- /dev/null
+++ b/vstgui/vstgui.cpp
@@ -0,0 +1,3996 @@
+/* ----------------------------------------------------------------------------
+ * VSTGUI for X11/LV2/PNG
+ * Author: Dave Robillard
+ * Released under the revised BSD license, as below
+ * ----------------------------------------------------------------------------
+ *
+ * Based on:
+ * ----------------------------------------------------------------------------
+ * VSTGUIL: Graphical User Interface Framework for VST plugins on LINUX
+ * Version: 0.1, Date: 2007/01/21
+ * Author: kRAkEn/gORe
+ *
+ * Which was based on:
+ * ----------------------------------------------------------------------------
+ * VSTGUI: Graphical User Interface Framework for VST plugins
+ * Version 3.0 $Date: 2005/08/12 12:45:00 $
+ * ----------------------------------------------------------------------------
+ * VSTGUI LICENSE
+ * 2004, Steinberg Media Technologies, All Rights Reserved
+ * ----------------------------------------------------------------------------
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Steinberg Media Technologies nor the names of
+ * its contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ * ----------------------------------------------------------------------------
+ */
+
+#include <cstdio>
+#include <cstdlib>
+#include <cmath>
+#include <iostream>
+#include <string.h>
+
+#include "vstgui.h"
+#include "audioeffectx.h"
+#include "vstkeycode.h"
+
+//-----------------------------------------------------------------------------
+// Some defines
+//-----------------------------------------------------------------------------
+#ifdef DEBUG
+ #define DBG(x) std::cout << x << std::endl;
+ #define assertfalse assert (false);
+#else
+ #define DBG(x)
+ #define assertfalse
+#endif
+
+#define USE_ALPHA_BLEND 0
+#define USE_CLIPPING_DRAWRECT 1
+#define NEW_UPDATE_MECHANISM 1
+
+
+//-----------------------------------------------------------------------------
+// our global display
+Display* display = 0;
+
+
+//-----------------------------------------------------------------------------
+// AEffGUIEditor Implementation
+//-----------------------------------------------------------------------------
+#define kIdleRate 100 // host idle rate in ms
+#define kIdleRate2 50
+#define kIdleRateMin 4 // minimum time between 2 idles in ms
+
+//-----------------------------------------------------------------------------
+VstInt32 AEffGUIEditor::knobMode = kCircularMode;
+
+//-----------------------------------------------------------------------------
+AEffGUIEditor::AEffGUIEditor (AudioEffect* effect)
+: AEffEditor (effect),
+ lLastTicks (0),
+ inIdleStuff (false),
+ bundlePath(NULL),
+ frame (0)
+{
+ rect.left = rect.top = rect.right = rect.bottom = 0;
+ lLastTicks = getTicks ();
+
+ effect->setEditor (this);
+}
+
+//-----------------------------------------------------------------------------
+AEffGUIEditor::~AEffGUIEditor ()
+{
+}
+
+//-----------------------------------------------------------------------------
+void AEffGUIEditor::setParameter (VstInt32 index, float value)
+{}
+
+//-----------------------------------------------------------------------------
+void AEffGUIEditor::beginEdit (VstInt32 index)
+{
+ ((AudioEffectX*)effect)->beginEdit (index);
+}
+
+//-----------------------------------------------------------------------------
+void AEffGUIEditor::endEdit (VstInt32 index)
+{
+ ((AudioEffectX*)effect)->endEdit (index);
+}
+
+//-----------------------------------------------------------------------------
+#if VST_2_1_EXTENSIONS
+long AEffGUIEditor::onKeyDown (VstKeyCode& keyCode)
+{
+ return frame && frame->onKeyDown (keyCode) == 1 ? 1 : 0;
+}
+
+//-----------------------------------------------------------------------------
+long AEffGUIEditor::onKeyUp (VstKeyCode& keyCode)
+{
+ return frame && frame->onKeyUp (keyCode) == 1 ? 1 : 0;
+}
+
+//-----------------------------------------------------------------------------
+long AEffGUIEditor::setKnobMode (VstInt32 val)
+{
+ knobMode = val;
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+bool AEffGUIEditor::onWheel (float distance)
+{
+/*
+ if (frame)
+ {
+ CDrawContext context (frame, NULL, systemWindow);
+ CPoint where;
+ context.getMouseLocation (where);
+ return frame->onWheel (&context, where, distance);
+ }
+*/
+ return false;
+}
+#endif
+
+//-----------------------------------------------------------------------------
+long AEffGUIEditor::getRect (ERect **ppErect)
+{
+ *ppErect = &rect;
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+void AEffGUIEditor::idle ()
+{
+ if (inIdleStuff)
+ return;
+
+ AEffEditor::idle ();
+ if (frame)
+ frame->idle ();
+}
+
+//-----------------------------------------------------------------------------
+void AEffGUIEditor::wait (unsigned int ms)
+{
+ usleep (ms * 1000);
+}
+
+//-----------------------------------------------------------------------------
+unsigned int AEffGUIEditor::getTicks ()
+{
+ return _getTicks ();
+}
+
+//-----------------------------------------------------------------------------
+void AEffGUIEditor::doIdleStuff ()
+{
+ // get the current time
+ unsigned int currentTicks = getTicks ();
+
+ // YG TEST idle ();
+ if (currentTicks < lLastTicks)
+ {
+ wait (kIdleRateMin);
+
+ currentTicks += kIdleRateMin;
+ if (currentTicks < lLastTicks - kIdleRate2)
+ return;
+ }
+
+ idle ();
+
+ // save the next time
+ lLastTicks = currentTicks + kIdleRate;
+
+ inIdleStuff = true;
+
+ if (effect)
+ effect->masterIdle ();
+
+ inIdleStuff = false;
+}
+
+void AEffGUIEditor::update ()
+{
+ if (frame)
+ frame->invalidate (CRect (0, 0, rect.right, rect.bottom));
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+
+//---For Debugging------------------------
+#if DEBUG
+long gNbCBitmap = 0;
+long gNbCView = 0;
+long gNbCDrawContext = 0;
+long gNbCOffscreenContext = 0;
+long gBitmapAllocation = 0;
+long gNbDC = 0;
+#include <stdarg.h>
+void DebugPrint (const char *format, ...);
+void DebugPrint (const char *format, ...)
+{
+ char string[300];
+ va_list marker;
+ va_start (marker, format);
+ vsprintf (string, format, marker);
+ if (!strcmp(string, ""))
+ strcpy (string, "Empty string\n");
+ fprintf (stderr, string);
+}
+#endif
+//---End For Debugging------------------------
+
+#include <assert.h>
+#include <time.h>
+#include <stdlib.h>
+#include <math.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#define XDRAWPARAM display, (Window)pWindow, (GC) pSystemContext
+#define XWINPARAM display, (Window)pFrame->getWindow()
+#define XGCPARAM display, (GC) pSystemContext
+
+// #define XDRAWPARAM display, (Window)pWindow, (GC)pSystemContext
+// #define XWINPARAM display, (Window)pWindow
+// #define XGCPARAM display, (GC)pSystemContext
+
+// init the static variable about font
+bool gFontInit = false;
+XFontStruct *gFontStructs[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+struct SFontTable { const char* name; const char* string; };
+
+static SFontTable gFontTable[] = {
+ {"SystemFont", "-*-fixed-*-*-*--12-*-*-*-*-*-*-*"}, // kSystemFont
+ {"NormalFontVeryBig", "-*-fixed-*-*-*--18-*-*-*-*-*-*-*"}, // kNormalFontVeryBig
+ {"NormalFontBig", "-*-fixed-*-*-*--18-*-*-*-*-*-*-*"}, // kNormalFontBig
+ {"NormalFont", "-*-fixed-*-*-*--12-*-*-*-*-*-*-*"}, // kNormalFont
+ {"NormalFontSmall", "-*-courier-*-*-*--10-*-*-*-*-*-*-*"}, // kNormalFontSmall
+ {"NormalFontSmaller", "-*-courier-*-*-*--9-*-*-*-*-*-*-*"}, // kNormalFontSmaller
+ {"NormalFontVerySmall", "-*-courier-*-*-*--8-*-*-*-*-*-*-*"}, // kNormalFontVerySmall
+ {"SymbolFont", "-*-fixed-*-*-*--12-*-*-*-*-*-*-*"} // kSymbolFont
+};
+
+long gStandardFontSize[] = { 12, 18, 18, 12, 10, 9, 8, 13 };
+
+// declaration of different local functions
+static long convertPoint2Angle (CPoint &pm, CPoint &pt);
+
+// stuff for color
+long CDrawContext::nbNewColor = 0;
+
+//-----------------------------------------------------------------------------
+bool CRect::pointInside (const CPoint& where) const
+{
+ return where.h >= left && where.h < right && where.v >= top && where.v < bottom;
+}
+
+//-----------------------------------------------------------------------------
+bool CRect::isEmpty () const
+{
+ if (right <= left)
+ return true;
+ if (bottom <= top)
+ return true;
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+void CRect::bound (const CRect& rect)
+{
+ if (left < rect.left)
+ left = rect.left;
+ if (top < rect.top)
+ top = rect.top;
+ if (right > rect.right)
+ right = rect.right;
+ if (bottom > rect.bottom)
+ bottom = rect.bottom;
+ if (bottom < top)
+ bottom = top;
+ if (right < left)
+ right = left;
+}
+
+namespace VSTGUI {
+
+CColor kTransparentCColor = {255, 255, 255, 0};
+CColor kBlackCColor = { 0, 0, 0, 255};
+CColor kWhiteCColor = {255, 255, 255, 255};
+CColor kGreyCColor = {127, 127, 127, 255};
+CColor kRedCColor = {255, 0, 0, 255};
+CColor kGreenCColor = { 0, 255, 0, 255};
+CColor kBlueCColor = { 0, 0, 255, 255};
+CColor kYellowCColor = {255, 255, 0, 255};
+CColor kMagentaCColor = {255, 0, 255, 255};
+CColor kCyanCColor = { 0, 255, 255, 255};
+
+#define kDragDelay 0
+
+//-----------------------------------------------------------------------------
+// CDrawContext Implementation
+//-----------------------------------------------------------------------------
+/**
+ * CDrawContext constructor.
+ * @param inFrame the parent CFrame
+ * @param inSystemContext the platform system context, can be NULL
+ * @param inWindow the platform window object
+ */
+CDrawContext::CDrawContext (CFrame *inFrame, void *inSystemContext, void *inWindow)
+: pSystemContext (inSystemContext)
+, pWindow (inWindow)
+, pFrame (inFrame)
+, fontSize (-1)
+, fontStyle (0)
+, fontId (kNumStandardFonts)
+, frameWidth (0)
+, lineStyle (kLineOnOffDash)
+, drawMode (kAntialias)
+{
+#if DEBUG
+ gNbCDrawContext++;
+#endif
+
+ // initialize values
+ if (pFrame)
+ pFrame->getViewSize (clipRect);
+ else
+ clipRect (0, 0, 1000, 1000);
+
+ const CColor notInitalized = {0, 0, 0, 0};
+ frameColor = notInitalized;
+ fillColor = notInitalized;
+ fontColor = notInitalized;
+
+ // offsets use by offscreen
+ offset (0, 0);
+ offsetScreen (0, 0);
+
+ // set the current font
+ if (pSystemContext)
+ {
+ // set the default values
+ setFont (kNormalFont);
+ setFrameColor (kWhiteCColor);
+ setLineStyle (kLineSolid);
+ setLineWidth (1);
+ setFont (kSystemFont);
+ setDrawMode (kCopyMode);
+ }
+}
+
+//-----------------------------------------------------------------------------
+CDrawContext::~CDrawContext ()
+{
+#if DEBUG
+ gNbCDrawContext--;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+void CDrawContext::setLineStyle (CLineStyle style)
+{
+ if (lineStyle == style)
+ return;
+
+ lineStyle = style;
+
+ long line_width;
+ long line_style;
+ if (frameWidth == 1)
+ line_width = 0;
+ else
+ line_width = frameWidth;
+
+ switch (lineStyle)
+ {
+ case kLineOnOffDash:
+ line_style = LineOnOffDash;
+ break;
+ default:
+ line_style = LineSolid;
+ break;
+ }
+
+ XSetLineAttributes (XGCPARAM, line_width, line_style, CapNotLast, JoinRound);
+}
+
+//-----------------------------------------------------------------------------
+void CDrawContext::setLineWidth (CCoord width)
+{
+ if (frameWidth == width)
+ return;
+
+ frameWidth = width;
+
+ setLineStyle (lineStyle);
+}
+
+//-----------------------------------------------------------------------------
+void CDrawContext::setDrawMode (CDrawMode mode)
+{
+ if (drawMode == mode)
+ return;
+
+ drawMode = mode;
+
+ long iMode = 0;
+ switch (drawMode)
+ {
+ case kXorMode :
+ iMode = GXinvert;
+ break;
+ case kOrMode :
+ iMode = GXor;
+ break;
+ default:
+ iMode = GXcopy;
+ }
+
+ ((XGCValues*)pSystemContext)->function = iMode;
+
+ XChangeGC (XGCPARAM, GCFunction, (XGCValues*)pSystemContext);
+}
+
+//------------------------------------------------------------------------------
+void CDrawContext::setClipRect (const CRect &clip)
+{
+ CRect _clip (clip);
+ _clip.offset (offset.h, offset.v);
+
+ if (clipRect == _clip)
+ return;
+
+ clipRect = _clip;
+
+ XRectangle r;
+ r.x = 0;
+ r.y = 0;
+ r.width = clipRect.right - clipRect.left + 1;
+ r.height = clipRect.bottom - clipRect.top + 1;
+
+ XSetClipRectangles (XGCPARAM, clipRect.left, clipRect.top, &r, 1, Unsorted);
+}
+
+//------------------------------------------------------------------------------
+void CDrawContext::resetClipRect ()
+{
+ CRect newClip;
+ if (pFrame)
+ pFrame->getViewSize (newClip);
+ else
+ newClip (0, 0, 1000, 1000);
+
+ setClipRect (newClip);
+
+ clipRect = newClip;
+}
+
+//-----------------------------------------------------------------------------
+void CDrawContext::moveTo (const CPoint &_point)
+{
+ CPoint point (_point);
+ point.offset (offset.h, offset.v);
+
+ penLoc = point;
+}
+
+//-----------------------------------------------------------------------------
+void CDrawContext::lineTo (const CPoint& _point)
+{
+ CPoint point (_point);
+ point.offset (offset.h, offset.v);
+
+ CPoint start (penLoc);
+ CPoint end (point);
+ if (start.h == end.h)
+ {
+ if (start.v < -5)
+ start.v = -5;
+ else if (start.v > 10000)
+ start.v = 10000;
+
+ if (end.v < -5)
+ end.v = -5;
+ else if (end.v > 10000)
+ end.v = 10000;
+ }
+ if (start.v == end.v)
+ {
+ if (start.h < -5)
+ start.h = -5;
+ else if (start.h > 10000)
+ start.h = 10000;
+
+ if (end.h < -5)
+ end.h = -5;
+ else if (end.h > 10000)
+ end.h = 10000;
+ }
+
+ XDrawLine (XDRAWPARAM, start.h, start.v, end.h, end.v);
+
+ // keep trace of the new position
+ penLoc = point;
+}
+
+//-----------------------------------------------------------------------------
+void CDrawContext::drawLines (const CPoint* points, const long& numLines)
+{
+ // default implementation, when no platform optimized code is implemented
+ for (long i = 0; i < numLines * 2; i+=2)
+ {
+ moveTo (points[i]);
+ lineTo (points[i+1]);
+ }
+}
+
+//-----------------------------------------------------------------------------
+void CDrawContext::drawPolygon (const CPoint *pPoints, long numberOfPoints, const CDrawStyle drawStyle)
+{
+ if (drawStyle == kDrawFilled || drawStyle == kDrawFilledAndStroked)
+ fillPolygon (pPoints, numberOfPoints);
+ if (drawStyle == kDrawStroked || drawStyle == kDrawFilledAndStroked)
+ polyLine (pPoints, numberOfPoints);
+}
+
+//-----------------------------------------------------------------------------
+void CDrawContext::polyLine (const CPoint *pPoints, long numberOfPoints)
+{
+ XPoint* pt = (XPoint*)malloc (numberOfPoints * sizeof (XPoint));
+ if (!pt)
+ return;
+ for (long i = 0; i < numberOfPoints; i++)
+ {
+ pt[i].x = (short)pPoints[i].h + offset.h;
+ pt[i].y = (short)pPoints[i].v + offset.v;
+ }
+
+ XDrawLines (XDRAWPARAM, pt, numberOfPoints, CoordModeOrigin);
+
+ free (pt);
+}
+
+//-----------------------------------------------------------------------------
+void CDrawContext::fillPolygon (const CPoint *pPoints, long numberOfPoints)
+{
+ // convert the points
+ XPoint* pt = (XPoint*)malloc (numberOfPoints * sizeof (XPoint));
+ if (!pt)
+ return;
+ for (long i = 0; i < numberOfPoints; i++)
+ {
+ pt[i].x = (short)pPoints[i].h + offset.h;
+ pt[i].y = (short)pPoints[i].v + offset.v;
+ }
+
+ XFillPolygon (XDRAWPARAM, pt, numberOfPoints, Convex, CoordModeOrigin);
+
+ free (pt);
+}
+
+//-----------------------------------------------------------------------------
+void CDrawContext::drawRect (const CRect &_rect, const CDrawStyle drawStyle)
+{
+ CRect rect (_rect);
+ rect.offset (offset.h, offset.v);
+
+ XDrawRectangle (XDRAWPARAM, rect.left, rect.top, rect.width (), rect.height ());
+}
+
+//-----------------------------------------------------------------------------
+void CDrawContext::fillRect (const CRect &_rect)
+{
+ CRect rect (_rect);
+ rect.offset (offset.h, offset.v);
+
+ // Don't draw boundary
+ XFillRectangle (XDRAWPARAM, rect.left + 1, rect.top + 1, rect.width () - 1, rect.height () - 1);
+}
+
+//-----------------------------------------------------------------------------
+void CDrawContext::drawEllipse (const CRect &_rect, const CDrawStyle drawStyle)
+{
+ CPoint point (_rect.left + (_rect.right - _rect.left) / 2, _rect.top);
+ drawArc (_rect, point, point);
+}
+
+//-----------------------------------------------------------------------------
+void CDrawContext::fillEllipse (const CRect &_rect)
+{
+ CRect rect (_rect);
+ rect.offset (offset.h, offset.v);
+
+ // Don't draw boundary
+ CPoint point (_rect.left + ((_rect.right - _rect.left) / 2), _rect.top);
+ fillArc (_rect, point, point);
+}
+
+//-----------------------------------------------------------------------------
+void CDrawContext::drawPoint (const CPoint &_point, CColor color)
+{
+ CPoint point (_point);
+
+ CColor oldframecolor = frameColor;
+ setFrameColor (color);
+
+ XDrawPoint (XDRAWPARAM, point.h, point.v);
+
+ setFrameColor (oldframecolor);
+}
+
+//-----------------------------------------------------------------------------
+CColor CDrawContext::getPoint (const CPoint& _point)
+{
+// CPoint point (_point);
+// point.offset (offset.h, offset.v);
+
+ assertfalse // not implemented !
+
+ CColor color = kBlackCColor;
+ return color;
+}
+
+//-----------------------------------------------------------------------------
+void CDrawContext::floodFill (const CPoint& _start)
+{
+// CPoint start (_start);
+// start.offset (offset.h, offset.v);
+
+ assertfalse // not implemented !
+}
+
+//-----------------------------------------------------------------------------
+void CDrawContext::drawArc (const CRect &_rect, const float _startAngle, const float _endAngle, const CDrawStyle drawStyle) // in degree
+{
+ CRect rect (_rect);
+ rect.offset (offset.h, offset.v);
+
+ XDrawArc (XDRAWPARAM, rect.left, rect.top, rect.width (), rect.height (),
+ (int) _startAngle * 64, (int) _endAngle * 64);
+}
+
+//-----------------------------------------------------------------------------
+void CDrawContext::drawArc (const CRect &_rect, const CPoint &_point1, const CPoint &_point2)
+{
+ CRect rect (_rect);
+ rect.offset (offset.h, offset.v);
+ CPoint point1 (_point1);
+ point1.offset (offset.h, offset.v);
+ CPoint point2 (_point2);
+ point2.offset (offset.h, offset.v);
+
+ int angle1, angle2;
+ if ((point1.v == point2.v) && (point1.h == point2.h))
+ {
+ angle1 = 0;
+ angle2 = 23040; // 360 * 64
+ }
+ else
+ {
+ CPoint pm ((rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2);
+ angle1 = convertPoint2Angle (pm, point1);
+ angle2 = convertPoint2Angle (pm, point2) - angle1;
+ if (angle2 < 0)
+ angle2 += 23040; // 360 * 64
+ }
+
+ XDrawArc (XDRAWPARAM, rect.left, rect.top, rect.width (), rect.height (),
+ angle1, angle2);
+}
+
+//-----------------------------------------------------------------------------
+void CDrawContext::fillArc (const CRect &_rect, const CPoint &_point1, const CPoint &_point2)
+{
+ CRect rect (_rect);
+ rect.offset (offset.h, offset.v);
+ CPoint point1 (_point1);
+ point1.offset (offset.h, offset.v);
+ CPoint point2 (_point2);
+ point2.offset (offset.h, offset.v);
+
+ // Don't draw boundary
+ int angle1, angle2;
+ if ((point1.v == point2.v) && (point1.h == point2.h))
+ {
+ angle1 = 0;
+ angle2 = 23040; // 360 * 64
+ }
+ else
+ {
+ CPoint pm ((rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2);
+ angle1 = convertPoint2Angle (pm, point1);
+ angle2 = convertPoint2Angle (pm, point2);
+ }
+
+ XFillArc (XDRAWPARAM, rect.left, rect.top, rect.width (), rect.height (),
+ angle1, angle2);
+}
+
+//-----------------------------------------------------------------------------
+void CDrawContext::setFontColor (const CColor color)
+{
+ fontColor = color;
+
+ setFrameColor (fontColor);
+}
+
+//-----------------------------------------------------------------------------
+void CDrawContext::setFrameColor (const CColor color)
+{
+ if (frameColor == color)
+ return;
+
+ frameColor = color;
+
+ XSetForeground (XGCPARAM, getIndexColor (frameColor));
+}
+
+//-----------------------------------------------------------------------------
+void CDrawContext::setFillColor (const CColor color)
+{
+ if (fillColor == color)
+ return;
+
+ fillColor = color;
+
+ // set the background for the text
+ //XSetBackground (XGCPARAM, getIndexColor (fillColor));
+ XSetBackground (display, pFrame->getGC(), getIndexColor (fillColor));
+
+ // set the foreground for the fill
+ setFrameColor (fillColor);
+}
+
+//-----------------------------------------------------------------------------
+void CDrawContext::setFont (CFont fontID, const long size, long style)
+{
+ if (fontID < 0 || fontID >= kNumStandardFonts)
+ fontID = kSystemFont;
+
+ if (fontId == fontID && fontSize == (size != 0 ? size : gStandardFontSize[fontID]) && fontStyle == style)
+ return;
+
+ fontStyle = style;
+ fontId = fontID;
+ if (size != 0)
+ fontSize = size;
+ else
+ fontSize = gStandardFontSize[fontID];
+
+ if (gFontStructs[fontID] != NULL)
+ XSetFont (display, pFrame->getGC(), gFontStructs[fontID]->fid);
+ else
+ fprintf(stderr, "ERROR: Font not defined\n");
+
+ // keep trace of the current font
+ pFontInfoStruct = gFontStructs[fontID];
+
+#ifdef DEBUG
+// if (!pFontInfoStruct) assert (false); // fonts have invalid pointers !
+#endif
+}
+
+//------------------------------------------------------------------------------
+CCoord CDrawContext::getStringWidth (const char *pStr)
+{
+ CCoord result = 0;
+
+ result = (long) XTextWidth (pFontInfoStruct, pStr, strlen (pStr));
+
+ return result;
+}
+
+//-----------------------------------------------------------------------------
+void CDrawContext::drawString (const char *string, const CRect &_rect,
+ const short opaque, const CHoriTxtAlign hAlign)
+{
+ if (!string)
+ return;
+
+ CRect rect (_rect);
+ rect.offset (offset.h, offset.v);
+
+ int width;
+ int fontHeight = pFontInfoStruct->ascent + pFontInfoStruct->descent;
+ int xPos;
+ int yPos;
+ int rectHeight = rect.height ();
+
+ if (rectHeight >= fontHeight)
+ yPos = rect.bottom - (rectHeight - fontHeight) / 2;
+ else
+ yPos = rect.bottom;
+ yPos -= pFontInfoStruct->descent;
+
+ switch (hAlign)
+ {
+ case kCenterText:
+ width = XTextWidth (pFontInfoStruct, string, strlen (string));
+ xPos = (rect.right + rect.left - width) / 2;
+ break;
+
+ case kRightText:
+ width = XTextWidth (pFontInfoStruct, string, strlen (string));
+ xPos = rect.right - width;
+ break;
+
+ default: // left adjust
+ xPos = rect.left + 1;
+ }
+
+ if (opaque)
+ XDrawImageString (XDRAWPARAM, xPos, yPos, string, strlen (string));
+ else
+ XDrawString (XDRAWPARAM, xPos, yPos, string, strlen (string));
+}
+
+//-----------------------------------------------------------------------------
+long CDrawContext::getMouseButtons ()
+{
+ long buttons = 0;
+
+ Window root, child;
+ int rootX, rootY, childX, childY;
+ unsigned int mask;
+
+ XQueryPointer (XWINPARAM,
+ &root,
+ &child,
+ &rootX,
+ &rootY,
+ &childX,
+ &childY,
+ &mask);
+
+ if (mask & Button1Mask)
+ buttons |= kLButton;
+ if (mask & Button2Mask)
+ buttons |= kMButton;
+ if (mask & Button3Mask)
+ buttons |= kRButton;
+
+ if (mask & ShiftMask)
+ buttons |= kShift;
+ if (mask & ControlMask)
+ buttons |= kControl;
+ if (mask & Mod1Mask)
+ buttons |= kAlt;
+
+ return buttons;
+}
+
+//-----------------------------------------------------------------------------
+void CDrawContext::getMouseLocation (CPoint &point)
+{
+ Window root, child;
+ int rootX, rootY, childX, childY;
+ unsigned int mask;
+
+ XQueryPointer (XWINPARAM,
+ &root,
+ &child,
+ &rootX,
+ &rootY,
+ &childX,
+ &childY,
+ &mask);
+
+ point (childX, childY);
+
+ point.offset (-offsetScreen.h, -offsetScreen.v);
+}
+
+//-----------------------------------------------------------------------------
+bool CDrawContext::waitDoubleClick ()
+{
+ bool doubleClick = false;
+
+ long currentTime = _getTicks ();
+ long clickTime = currentTime + 200; // XtGetMultiClickTime (display);
+
+ XEvent e;
+ while (currentTime < clickTime)
+ {
+ if (XCheckTypedEvent (display, ButtonPress, &e))
+ {
+ doubleClick = true;
+ break;
+ }
+
+ currentTime = _getTicks ();
+ }
+
+ return doubleClick;
+}
+
+//-----------------------------------------------------------------------------
+bool CDrawContext::waitDrag ()
+{
+ if (!pFrame)
+ return false;
+
+ CPoint mouseLoc;
+ getMouseLocation (mouseLoc);
+ CRect observe (mouseLoc.h - 2, mouseLoc.v - 2, mouseLoc.h + 2, mouseLoc.v + 2);
+
+ long currentTime = pFrame->getTicks ();
+ bool wasOutside = false;
+
+ while (((getMouseButtons () & ~(kMButton|kRButton)) & kLButton) != 0)
+ {
+ pFrame->doIdleStuff ();
+ if (!wasOutside)
+ {
+ getMouseLocation (mouseLoc);
+ if (!observe.pointInside (mouseLoc))
+ {
+ if (kDragDelay <= 0)
+ return true;
+ wasOutside = true;
+ }
+ }
+
+ if (wasOutside && (pFrame->getTicks () - currentTime > kDragDelay))
+ return true;
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+void CDrawContext::forget ()
+{
+ CReferenceCounter::forget ();
+}
+
+//-----------------------------------------------------------------------------
+long CDrawContext::getIndexColor (CColor color)
+{
+ XColor xcol;
+ xcol.red = color.red << 8;
+ xcol.green = color.green << 8;
+ xcol.blue = color.blue << 8;
+ xcol.flags = (DoRed | DoGreen | DoBlue);
+ XAllocColor (display, XDefaultColormap (display, 0), &xcol);
+ return xcol.pixel;
+}
+
+//-----------------------------------------------------------------------------
+Colormap CDrawContext::getColormap ()
+{
+ if (pFrame)
+ return pFrame->getColormap ();
+ else
+ return None;
+}
+
+//-----------------------------------------------------------------------------
+Visual* CDrawContext::getVisual ()
+{
+ if (pFrame)
+ return pFrame->getVisual ();
+ else
+ return None;
+}
+
+//-----------------------------------------------------------------------------
+unsigned int CDrawContext::getDepth ()
+{
+ if (pFrame)
+ return pFrame->getDepth ();
+ else
+ return None;
+}
+
+
+//-----------------------------------------------------------------------------
+// COffscreenContext Implementation
+//-----------------------------------------------------------------------------
+COffscreenContext::COffscreenContext (CDrawContext *pContext, CBitmap *pBitmapBg, bool drawInBitmap)
+: CDrawContext (pContext->pFrame, NULL, NULL)
+, pBitmap (0)
+, pBitmapBg (pBitmapBg)
+, height (20)
+, width (20)
+{
+ std::cout << "COffscreenContext::COffscreenContext with bitmap" << std::endl;
+
+ if (pBitmapBg)
+ {
+ height = pBitmapBg->getHeight ();
+ width = pBitmapBg->getWidth ();
+
+ clipRect (0, 0, width, height);
+ }
+
+#if DEBUG
+ gNbCOffscreenContext++;
+ gBitmapAllocation += (long)height * (long)width;
+#endif
+
+ bDestroyPixmap = false;
+
+// Window root = RootWindow (display, DefaultScreen (display));
+
+ // if no bitmap handle => create one
+ if (! pWindow)
+ {
+ pWindow = (void*) XCreatePixmap (display, pFrame->getWindow(), width, height, pFrame->getDepth ());
+ bDestroyPixmap = true;
+ }
+
+ // set the current font
+ if (pSystemContext)
+ setFont (kNormalFont);
+
+ if (!drawInBitmap)
+ {
+ // draw bitmap to Offscreen
+ CRect r (0, 0, width, height);
+ if (pBitmapBg)
+ pBitmapBg->draw (this, r);
+ else
+ {
+ setFillColor (kBlackCColor);
+ fillRect (r);
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+COffscreenContext::COffscreenContext (CFrame *pFrame, long width, long height, const CColor backgroundColor)
+: CDrawContext (pFrame, NULL, NULL)
+, pBitmap (0)
+, pBitmapBg (0)
+, height (height)
+, width (width)
+, backgroundColor (backgroundColor)
+{
+ std::cout << "COffscreenContext::COffscreenContext without bitmap" << std::endl;
+
+ clipRect (0, 0, width, height);
+
+#if DEBUG
+ gNbCOffscreenContext++;
+ gBitmapAllocation += height * width;
+#endif
+
+ bDestroyPixmap = true;
+
+ pWindow = (void*) XCreatePixmap (display,
+ pFrame->getWindow(),
+ width,
+ height,
+ pFrame->getDepth ());
+
+/*
+ // clear the pixmap
+ XGCValues values;
+ values.foreground = getIndexColor (backgroundColor);
+ GC gc = XCreateGC (display, (Window)pWindow, GCForeground, &values);
+ XFillRectangle (display, (Window)pWindow, gc, 0, 0, width, height);
+ XFreeGC (display, gc);
+*/
+
+ XGCValues values;
+ values.foreground = getIndexColor (backgroundColor);
+ pSystemContext = XCreateGC (display, (Window)pWindow, GCForeground, &values);
+ XFillRectangle (display, (Window)pWindow, (GC) pSystemContext, 0, 0, width, height);
+
+ // set the current font
+ if (pSystemContext)
+ setFont (kNormalFont);
+}
+
+//-----------------------------------------------------------------------------
+COffscreenContext::~COffscreenContext ()
+{
+#if DEBUG
+ gNbCOffscreenContext--;
+ gBitmapAllocation -= (long)height * (long)width;
+#endif
+
+ if (pBitmap)
+ pBitmap->forget ();
+
+ if (bDestroyPixmap && pWindow)
+ XFreePixmap (display, (Pixmap)pWindow);
+
+ if (pSystemContext)
+ XFreeGC (display, (GC) pSystemContext);
+}
+
+//-----------------------------------------------------------------------------
+void COffscreenContext::copyTo (CDrawContext* pContext, CRect& srcRect, CPoint destOffset)
+{
+ std::cout << "COffscreenContext::copyTo" << std::endl;
+
+ XCopyArea (display,
+ (Drawable) pContext->pWindow,
+ (Drawable) pWindow,
+ (GC) pSystemContext,
+ srcRect.left,
+ srcRect.top,
+ srcRect.width (),
+ srcRect.height (),
+ destOffset.h,
+ destOffset.v);
+}
+
+//-----------------------------------------------------------------------------
+void COffscreenContext::copyFrom (CDrawContext *pContext, CRect destRect, CPoint srcOffset)
+{
+ //std::cout << "COffscreenContext::copyFrom ";
+
+ XCopyArea (display,
+ (Drawable) pContext->pWindow,
+ (Drawable) pWindow,
+ (GC) pSystemContext,
+ srcOffset.h,
+ srcOffset.v,
+ destRect.width(),
+ destRect.height(),
+ destRect.left,
+ destRect.top);
+
+ pContext->setFrameColor (kRedCColor);
+ pContext->drawRect (destRect);
+}
+
+
+//-----------------------------------------------------------------------------
+class CAttributeListEntry
+{
+public:
+ CAttributeListEntry (long size, CViewAttributeID id)
+ : nextEntry (0)
+ , pointer (0)
+ , sizeOfPointer (size)
+ , id (id)
+ {
+ pointer = malloc (size);
+ }
+
+ ~CAttributeListEntry ()
+ {
+ if (pointer)
+ free (pointer);
+ }
+
+ CViewAttributeID getID () const { return id; }
+ long getSize () const { return sizeOfPointer; }
+ void* getPointer () const { return pointer; }
+ CAttributeListEntry* getNext () const { return nextEntry; }
+
+ void setNext (CAttributeListEntry* entry) { nextEntry = entry; }
+
+protected:
+ CAttributeListEntry () : nextEntry (0), pointer (0), sizeOfPointer (0), id (0) {}
+
+ CAttributeListEntry* nextEntry;
+ void* pointer;
+ long sizeOfPointer;
+ CViewAttributeID id;
+};
+
+//-----------------------------------------------------------------------------
+const char* kMsgCheckIfViewContainer = "kMsgCheckIfViewContainer";
+
+//-----------------------------------------------------------------------------
+// CView
+//-----------------------------------------------------------------------------
+/*! @class CView
+base class of all view objects
+*/
+//-----------------------------------------------------------------------------
+CView::CView (const CRect& size)
+: size (size)
+, mouseableArea (size)
+, pParentFrame (0)
+, pParentView (0)
+, bDirty (false)
+, bMouseEnabled (true)
+, bTransparencyEnabled (false)
+, bWantsFocus (false)
+, bVisible (true)
+, pBackground (0)
+, pAttributeList (0)
+{
+#if DEBUG
+ gNbCView++;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+CView::~CView ()
+{
+ if (pBackground)
+ pBackground->forget ();
+
+ if (pAttributeList)
+ {
+ CAttributeListEntry* entry = pAttributeList;
+ while (entry)
+ {
+ CAttributeListEntry* nextEntry = entry->getNext ();
+ delete entry;
+ entry = nextEntry;
+ }
+ }
+#if DEBUG
+ gNbCView--;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+void CView::getMouseLocation (CDrawContext* context, CPoint &point)
+{
+ if (context)
+ {
+ if (pParentView && pParentView->notify (this, kMsgCheckIfViewContainer) == kMessageNotified)
+ {
+ CCoord save[4];
+ ((CViewContainer*)pParentView)->modifyDrawContext (save, context);
+ pParentView->getMouseLocation (context, point);
+ ((CViewContainer*)pParentView)->restoreDrawContext (context, save);
+ }
+ else
+ context->getMouseLocation (point);
+ }
+}
+
+//-----------------------------------------------------------------------------
+CPoint& CView::frameToLocal (CPoint& point) const
+{
+ if (pParentView && pParentView->isTypeOf ("CViewContainer"))
+ return pParentView->frameToLocal (point);
+ return point;
+}
+
+//-----------------------------------------------------------------------------
+CPoint& CView::localToFrame (CPoint& point) const
+{
+ if (pParentView && pParentView->isTypeOf ("CViewContainer"))
+ return pParentView->localToFrame (point);
+ return point;
+}
+
+//-----------------------------------------------------------------------------
+void CView::redraw ()
+{
+ if (pParentFrame)
+ pParentFrame->draw (this);
+}
+
+//-----------------------------------------------------------------------------
+void CView::redrawRect (CDrawContext* context, const CRect& rect)
+{
+ if (pParentView)
+ pParentView->redrawRect (context, rect);
+ else if (pParentFrame)
+ pParentFrame->drawRect (context, rect);
+}
+
+//-----------------------------------------------------------------------------
+void CView::draw (CDrawContext *pContext)
+{
+ if (pBackground)
+ {
+ if (bTransparencyEnabled)
+ pBackground->drawTransparent (pContext, size);
+ else
+ pBackground->draw (pContext, size);
+ }
+ setDirty (false);
+}
+
+//-----------------------------------------------------------------------------
+void CView::mouse (CDrawContext *pContext, CPoint &where, long buttons)
+{}
+
+//-----------------------------------------------------------------------------
+bool CView::onWheel (CDrawContext *pContext, const CPoint &where, float distance)
+{
+ return false;
+}
+
+//------------------------------------------------------------------------
+bool CView::onWheel (CDrawContext *pContext, const CPoint &where, const CMouseWheelAxis axis, float distance)
+{
+ return onWheel (pContext, where, distance);
+}
+
+//------------------------------------------------------------------------
+void CView::update (CDrawContext *pContext)
+{
+ if (isDirty ())
+ {
+#if NEW_UPDATE_MECHANISM
+ if (pContext)
+ redrawRect (pContext, size);
+ else
+ redraw ();
+#else
+ #if USE_ALPHA_BLEND
+ if (pContext)
+ {
+ if (bTransparencyEnabled)
+ getFrame ()->drawRect (pContext, size);
+ else
+ draw (pContext);
+ }
+ #else
+ if (pContext)
+ draw (pContext);
+ #endif
+ else
+ redraw ();
+#endif
+ setDirty (false);
+ }
+}
+
+//------------------------------------------------------------------------------
+long CView::onKeyDown (VstKeyCode& keyCode)
+{
+ return -1;
+}
+
+//------------------------------------------------------------------------------
+long CView::onKeyUp (VstKeyCode& keyCode)
+{
+ return -1;
+}
+
+//------------------------------------------------------------------------------
+long CView::notify (CView* sender, const char* message)
+{
+ return kMessageUnknown;
+}
+
+//------------------------------------------------------------------------------
+void CView::looseFocus (CDrawContext *pContext)
+{}
+
+//------------------------------------------------------------------------------
+void CView::takeFocus (CDrawContext *pContext)
+{}
+
+//------------------------------------------------------------------------------
+void CView::setViewSize (CRect &rect)
+{
+ size = rect;
+ setDirty ();
+}
+
+//-----------------------------------------------------------------------------
+void *CView::getEditor () const
+{
+ return pParentFrame ? pParentFrame->getEditor () : 0;
+}
+
+//-----------------------------------------------------------------------------
+void CView::setBackground (CBitmap *background)
+{
+ if (pBackground)
+ pBackground->forget ();
+ pBackground = background;
+ if (pBackground)
+ pBackground->remember ();
+ setDirty (true);
+}
+
+//-----------------------------------------------------------------------------
+const CViewAttributeID kCViewAttributeReferencePointer = (CViewAttributeID) "cvrp";
+
+//-----------------------------------------------------------------------------
+/**
+ * @param id the ID of the Attribute
+ * @param outSize on return the size of the attribute
+ */
+bool CView::getAttributeSize (const CViewAttributeID id, long& outSize) const
+{
+ if (pAttributeList)
+ {
+ CAttributeListEntry* entry = pAttributeList;
+ while (entry)
+ {
+ if (entry->getID () == id)
+ break;
+ entry = entry->getNext ();
+ }
+ if (entry)
+ {
+ outSize = entry->getSize ();
+ return true;
+ }
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+/**
+ * @param id the ID of the Attribute
+ * @param inSize the size of the outData pointer
+ * @param outData a pointer where to copy the attribute data
+ * @param outSize the size in bytes which was copied into outData
+ */
+bool CView::getAttribute (const CViewAttributeID id, const long inSize, void* outData, long& outSize) const
+{
+ if (pAttributeList)
+ {
+ CAttributeListEntry* entry = pAttributeList;
+ while (entry)
+ {
+ if (entry->getID () == id)
+ break;
+ entry = entry->getNext ();
+ }
+ if (entry && inSize >= entry->getSize ())
+ {
+ outSize = entry->getSize ();
+ memcpy (outData, entry->getPointer (), outSize);
+ return true;
+ }
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+/**
+ * copies data into the attribute. If it does not exist, creates a new attribute.
+ * @param id the ID of the Attribute
+ * @param inSize the size of the outData pointer
+ * @param inData a pointer to the data
+ */
+bool CView::setAttribute (const CViewAttributeID id, const long inSize, void* inData)
+{
+ CAttributeListEntry* lastEntry = 0;
+ if (pAttributeList)
+ {
+ CAttributeListEntry* entry = pAttributeList;
+ while (entry)
+ {
+ if (entry->getID () == id)
+ break;
+ if (entry->getNext () == 0)
+ lastEntry = entry;
+ entry = entry->getNext ();
+ }
+ if (entry)
+ {
+ if (entry->getSize () >= inSize)
+ {
+ memcpy (entry->getPointer (), inData, inSize);
+ return true;
+ }
+ else
+ return false;
+ }
+ }
+
+ // create a new attribute
+ CAttributeListEntry* newEntry = new CAttributeListEntry (inSize, id);
+ memcpy (newEntry->getPointer (), inData, inSize);
+ if (lastEntry)
+ lastEntry->setNext (newEntry);
+ else if (!pAttributeList)
+ pAttributeList = newEntry;
+ else
+ {
+ delete newEntry;
+ return false;
+ }
+ return true;
+}
+
+#if DEBUG
+//-----------------------------------------------------------------------------
+void CView::dumpInfo ()
+{
+ CRect viewRect = getViewSize (viewRect);
+ DebugPrint ("left:%4d, top:%4d, width:%4d, height:%4d ", viewRect.left, viewRect.top, viewRect.getWidth (), viewRect.getHeight ());
+ if (getMouseEnabled ())
+ DebugPrint ("(Mouse Enabled) ");
+ if (getTransparency ())
+ DebugPrint ("(Transparent) ");
+ CRect mouseRect = getMouseableArea (mouseRect);
+ if (mouseRect != viewRect)
+ DebugPrint (" (Mouseable Area: left:%4d, top:%4d, width:%4d, height:%4d ", mouseRect.left, mouseRect.top, mouseRect.getWidth (), mouseRect.getHeight ());
+}
+#endif
+
+#define FOREACHSUBVIEW for (CCView *pSv = pFirstView; pSv; pSv = pSv->pNext) {CView *pV = pSv->pView;
+#define FOREACHSUBVIEW_REVERSE(reverse) for (CCView *pSv = reverse ? pLastView : pFirstView; pSv; pSv = reverse ? pSv->pPrevious : pSv->pNext) {CView *pV = pSv->pView;
+#define ENDFOR }
+
+//-----------------------------------------------------------------------------
+// CFrame Implementation
+//-----------------------------------------------------------------------------
+/*! @class CFrame
+It creates a platform dependend view object.
+On classic Mac OS it just draws into the provided window.
+On Mac OS X it is a ControlRef.
+On Windows it's a WS_CHILD Window.
+*/
+CFrame::CFrame (const CRect &inSize, void *inSystemWindow, void *inEditor)
+: CViewContainer (inSize, 0, 0)
+, pEditor (inEditor)
+, pModalView (0)
+, pFocusView (0)
+, bFirstDraw (true)
+, bDropActive (false)
+, bUpdatesDisabled (false)
+, pSystemWindow ((Window)inSystemWindow)
+, pFrameContext (0)
+, bAddedWindow (false)
+, defaultCursor (0)
+{
+ setOpenFlag (true);
+
+ pParentFrame = this;
+
+ depth = 0;
+ pVisual = 0;
+ window = 0;
+ gc = 0;
+
+ if (display == NULL)
+ display = XOpenDisplay(NULL);
+
+ initFrame ((void*)pSystemWindow);
+ backBuffer = XdbeAllocateBackBufferName(display, (Window)window, XdbeUndefined);
+
+ XGCValues values;
+ values.foreground = 1;
+ gc = XCreateGC (display, (Window)backBuffer, GCForeground, &values);
+
+ pFrameContext = new CDrawContext (this, gc, (void*)backBuffer);
+}
+
+//-----------------------------------------------------------------------------
+CFrame::~CFrame ()
+{
+ if (pModalView)
+ removeView (pModalView, false);
+
+ setCursor (kCursorDefault);
+
+ setDropActive (false);
+
+ if (pFrameContext)
+ pFrameContext->forget ();
+
+ if (getOpenFlag ())
+ close ();
+
+ if (window)
+ XDestroyWindow (display, (Window) window);
+ window = 0;
+
+ // remove callbacks to avoid undesirable update
+ if (gc)
+ freeGc ();
+}
+
+//-----------------------------------------------------------------------------
+bool CFrame::open ()
+{
+ if (! window)
+ return false;
+
+ XMapRaised (display, window);
+
+ return getOpenFlag ();
+}
+
+//-----------------------------------------------------------------------------
+bool CFrame::close ()
+{
+ if (!window || !getOpenFlag () || !pSystemWindow)
+ return false;
+
+ XUnmapWindow (display, window);
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+bool xerror;
+int errorHandler (Display *dp, XErrorEvent *e)
+{
+ xerror = true;
+ return 0;
+}
+int getProperty (Window handle, Atom atom)
+{
+ int result = 0, userSize;
+ unsigned long bytes, userCount;
+ unsigned char *data;
+ Atom userType;
+ xerror = false;
+ XErrorHandler olderrorhandler = XSetErrorHandler (errorHandler);
+ XGetWindowProperty (display, handle, atom, 0, 1, false, AnyPropertyType,
+ &userType, &userSize, &userCount, &bytes, &data);
+ if (xerror == false && userCount == 1)
+ result = *(int*)data;
+ XSetErrorHandler (olderrorhandler);
+ return result;
+}
+
+void eventProc (XEvent* ev)
+{
+ CFrame* frame = (CFrame*) getProperty (ev->xany.window, XInternAtom (display, "_this", false));
+ if (frame == 0)
+ return;
+
+ switch (ev->type)
+ {
+ case ButtonPress:
+ {
+ CPoint where (ev->xbutton.x, ev->xbutton.y);
+ frame->mouse (frame->createDrawContext(), where);
+ break;
+ }
+
+ case MotionNotify:
+ {
+ CPoint where (ev->xbutton.x, ev->xbutton.y);
+ frame->mouse (frame->createDrawContext(), where);
+ break;
+ }
+
+ case ButtonRelease:
+ {
+ break;
+ }
+
+ case Expose:
+ {
+ CRect rc (ev->xexpose.x, ev->xexpose.y,
+ ev->xexpose.x + ev->xexpose.width, ev->xexpose.y + ev->xexpose.height);
+
+ while (XCheckTypedWindowEvent (display, ev->xexpose.window, Expose, ev))
+ {
+ rc.left = std::min ((int) rc.left, ev->xexpose.x);
+ rc.top = std::min ((int) rc.top, ev->xexpose.y);
+ rc.right = std::max ((int) rc.right, ev->xexpose.x + ev->xexpose.width);
+ rc.bottom = std::max ((int) rc.bottom, ev->xexpose.y + ev->xexpose.height);
+ }
+
+ frame->drawRect (0, rc);
+ break;
+ }
+
+ case EnterNotify:
+ break;
+
+ case LeaveNotify:
+ {
+ XCrossingEvent *xevent = (XCrossingEvent*) ev;
+ if (frame->getFocusView ())
+ {
+ if (xevent->x < 0 || xevent->x >= frame->getWidth ()
+ || xevent->y < 0 || xevent->y >= frame->getHeight ())
+ {
+ // if button pressed => don't defocus
+ if (xevent->state & (Button1Mask | Button2Mask | Button3Mask))
+ break;
+
+ frame->getFocusView ()->looseFocus ();
+ frame->setFocusView (0);
+ }
+ }
+ break;
+ }
+
+ case ConfigureNotify:
+ {
+ frame->draw (); // @XXX - keep out ?
+ break;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+bool CFrame::initFrame (void *systemWin)
+{
+ if (!systemWin)
+ return false;
+
+ // window attributes
+ XSetWindowAttributes swa;
+ swa.override_redirect = false;
+ swa.background_pixmap = None;
+ swa.colormap = 0;
+ swa.event_mask =
+ StructureNotifyMask | ExposureMask | KeyPressMask | KeyReleaseMask |
+ ButtonPressMask | ButtonReleaseMask | FocusChangeMask | PointerMotionMask |
+ EnterWindowMask | LeaveWindowMask | PropertyChangeMask;
+
+ // create child window of host supplied window
+ window = XCreateWindow (display, (Window)systemWin,
+ 0, 0, size.width(), size.height(),
+ 0, CopyFromParent, InputOutput, (Visual*) CopyFromParent,
+ CWEventMask | CWOverrideRedirect | CWColormap | CWBackPixmap | CWEventMask, &swa);
+
+ XGrabButton (display, AnyButton, AnyModifier, window, False,
+ ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask,
+ GrabModeAsync, GrabModeAsync, None, None);
+
+#if 0
+ // remove window caption/frame
+ #define MWM_HINTS_DECORATIONS (1L << 1)
+ #define PROP_MOTIF_WM_HINTS_ELEMENTS 5
+ typedef struct
+ {
+ unsigned long flags;
+ unsigned long functions;
+ unsigned long decorations;
+ long inputMode;
+ unsigned long status;
+ }
+ PropMotifWmHints;
+
+ PropMotifWmHints motif_hints;
+ motif_hints.flags = MWM_HINTS_DECORATIONS;
+ motif_hints.decorations = 0;
+ Atom prop = XInternAtom (display, "_MOTIF_WM_HINTS", True );
+ XChangeProperty (display, window, prop, prop, 32, PropModeReplace,
+ (unsigned char *) &motif_hints, PROP_MOTIF_WM_HINTS_ELEMENTS);
+#endif
+
+ Atom atom;
+ void* data = this;
+ atom = XInternAtom (display, "_this", false);
+ XChangeProperty (display, (Window)window, atom, atom, 32,
+ PropModeReplace, (unsigned char*)&data, 1);
+
+ data = (void*)&eventProc;
+ atom = XInternAtom (display, "_XEventProc", false);
+ XChangeProperty (display, (Window)window, atom, atom, 32,
+ PropModeReplace, (unsigned char*)&data, 1);
+
+ XGCValues values;
+ values.foreground = 1;
+ gc = XCreateGC (display, (Window)window, GCForeground, &values);
+
+ // get the std colormap
+ XWindowAttributes attr;
+ XGetWindowAttributes (display, (Window) window, &attr);
+ colormap = attr.colormap;
+ pVisual = attr.visual;
+ depth = attr.depth;
+
+ // init and load the fonts
+ if (! gFontInit) {
+ for (long i = 0; i < kNumStandardFonts; i++) {
+ DBG (gFontTable[i].string);
+ gFontStructs[i] = XLoadQueryFont (display, gFontTable[i].string);
+ assert (gFontStructs[i] != 0);
+ }
+ gFontInit = true;
+ }
+
+ setDropActive (true);
+ bAddedWindow = true;
+
+ //XReparentWindow (display, window, (Window) systemWin, 0, 0);
+ //XMapRaised (display, window);
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+bool CFrame::setDropActive (bool val)
+{
+ if (!bDropActive && !val)
+ return true;
+
+ bDropActive = val;
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+void CFrame::freeGc ()
+{
+ XFreeGC (display, gc);
+}
+
+//-----------------------------------------------------------------------------
+CDrawContext* CFrame::createDrawContext ()
+{
+ if (pFrameContext)
+ {
+ pFrameContext->remember ();
+ return pFrameContext;
+ }
+
+ pFrameContext = new CDrawContext (this, gc, (void*)window);
+
+ return pFrameContext;
+}
+
+//-----------------------------------------------------------------------------
+void CFrame::draw (CDrawContext *pContext)
+{
+ if (bFirstDraw)
+ bFirstDraw = false;
+
+ bool localContext = false;
+ if (! pContext)
+ {
+ localContext = true;
+ pContext = createDrawContext ();
+ }
+
+ // draw the background and the children
+ CViewContainer::draw (pContext);
+
+ if (localContext)
+ pContext->forget ();
+}
+
+//-----------------------------------------------------------------------------
+void CFrame::drawRect (CDrawContext *pContext, const CRect& updateRect)
+{
+ if (bFirstDraw)
+ bFirstDraw = false;
+
+ bool localContext = false;
+ if (! pContext)
+ {
+ localContext = true;
+ pContext = createDrawContext ();
+ }
+
+#if USE_CLIPPING_DRAWRECT
+ CRect oldClip;
+ pContext->getClipRect (oldClip);
+ CRect newClip (updateRect);
+ newClip.bound (oldClip);
+ pContext->setClipRect (newClip);
+#endif
+
+ // draw the background and the children
+ if (updateRect.getWidth () > 0 && updateRect.getHeight () > 0)
+ CViewContainer::drawRect (pContext, updateRect);
+
+#if USE_CLIPPING_DRAWRECT
+ pContext->setClipRect (oldClip);
+#endif
+
+ if (localContext)
+ pContext->forget ();
+}
+
+//-----------------------------------------------------------------------------
+void CFrame::draw (CView *pView)
+{
+ CView *pViewToDraw = 0;
+
+ // Search it in the view list
+ if (pView && isChild(pView))
+ pViewToDraw = pView;
+
+ CDrawContext *pContext = createDrawContext ();
+ if (pContext)
+ {
+ if (pViewToDraw && pViewToDraw->isVisible())
+ pViewToDraw->draw (pContext);
+ else
+ draw (pContext);
+
+ pContext->forget ();
+ }
+}
+
+//-----------------------------------------------------------------------------
+void CFrame::mouse (CDrawContext *pContext, CPoint &where, long buttons)
+{
+/*
+ XGrabPointer (display,
+ window,
+ False,
+ ButtonPressMask | ButtonReleaseMask |
+ EnterWindowMask | LeaveWindowMask |
+ PointerMotionMask | Button1MotionMask |
+ Button2MotionMask | Button3MotionMask |
+ Button4MotionMask | Button5MotionMask,
+ GrabModeAsync,
+ GrabModeAsync,
+ None,
+ None,
+ CurrentTime);
+*/
+
+ if (!pContext)
+ pContext = pFrameContext;
+
+ if (pFocusView)
+ setFocusView (NULL);
+
+ if (buttons == -1 && pContext)
+ buttons = pContext->getMouseButtons ();
+
+ if (pModalView && pModalView->isVisible())
+ {
+ if (pModalView->hitTest (where, buttons))
+ pModalView->mouse (pContext, where, buttons);
+ }
+ else
+ {
+ CViewContainer::mouse (pContext, where, buttons);
+ }
+
+// XUngrabPointer (display, CurrentTime);
+}
+
+//-----------------------------------------------------------------------------
+long CFrame::onKeyDown (VstKeyCode& keyCode)
+{
+ long result = -1;
+
+ if (pFocusView && pFocusView->isVisible())
+ result = pFocusView->onKeyDown (keyCode);
+
+ if (result == -1 && pModalView && pModalView->isVisible())
+ result = pModalView->onKeyDown (keyCode);
+
+ if (result == -1 && keyCode.virt == VKEY_TAB)
+ result = advanceNextFocusView (pFocusView, (keyCode.modifier & MODIFIER_SHIFT) ? true : false) ? 1 : -1;
+
+ return result;
+}
+
+//-----------------------------------------------------------------------------
+long CFrame::onKeyUp (VstKeyCode& keyCode)
+{
+ long result = -1;
+
+ if (pFocusView && pFocusView->isVisible())
+ result = pFocusView->onKeyUp (keyCode);
+
+ if (result == -1 && pModalView && pModalView->isVisible())
+ result = pModalView->onKeyUp (keyCode);
+
+ return result;
+}
+
+//------------------------------------------------------------------------
+bool CFrame::onWheel (CDrawContext *pContext, const CPoint &where, const CMouseWheelAxis axis, float distance)
+{
+ bool result = false;
+
+ CView *view = pModalView ? pModalView : getViewAt (where);
+ if (view && view->isVisible())
+ {
+ bool localContext = false;
+ if (!pContext)
+ {
+ localContext = true;
+ pContext = createDrawContext ();
+ }
+
+ result = view->onWheel (pContext, where, axis, distance);
+
+ if (localContext)
+ pContext->forget ();
+ }
+ return result;
+}
+
+//-----------------------------------------------------------------------------
+bool CFrame::onWheel (CDrawContext *pContext, const CPoint &where, float distance)
+{
+ return onWheel (pContext, where, kMouseWheelAxisY, distance);
+}
+
+//-----------------------------------------------------------------------------
+void CFrame::update (CDrawContext *pContext)
+{
+ if (!getOpenFlag () || updatesDisabled ())
+ return;
+
+ CDrawContext* dc = pContext;
+
+ if (bDirty)
+ {
+ draw (dc);
+ setDirty (false);
+ }
+ else
+ {
+#if USE_CLIPPING_DRAWRECT
+ CRect oldClipRect;
+ dc->getClipRect (oldClipRect);
+#endif
+#if NEW_UPDATE_MECHANISM
+ if (pModalView && pModalView->isVisible () && pModalView->isDirty ())
+ pModalView->update (dc);
+#endif
+ FOREACHSUBVIEW
+#if USE_CLIPPING_DRAWRECT
+ CRect viewSize (pV->size);
+ viewSize.bound (oldClipRect);
+ dc->setClipRect (viewSize);
+#endif
+ pV->update (dc);
+ ENDFOR
+#if USE_CLIPPING_DRAWRECT
+ dc->setClipRect (oldClipRect);
+#endif
+ }
+}
+
+//-----------------------------------------------------------------------------
+void CFrame::idle ()
+{
+ if (!getOpenFlag ())
+ return;
+
+ // don't do an idle before a draw
+ if (bFirstDraw)
+ return;
+
+ if (!isDirty ())
+ return;
+
+ XdbeBeginIdiom(display);
+ XdbeSwapInfo swap_info;
+ swap_info.swap_window = window;
+ swap_info.swap_action = XdbeUndefined;
+ XdbeSwapBuffers(display, &swap_info, 1);
+
+ CDrawContext *pContext = createDrawContext ();
+
+ update (pContext);
+
+ pContext->forget ();
+
+ XdbeEndIdiom(display);
+}
+
+//-----------------------------------------------------------------------------
+void CFrame::doIdleStuff ()
+{
+ if (pEditor)
+ ((AEffGUIEditor*)pEditor)->doIdleStuff ();
+}
+
+//-----------------------------------------------------------------------------
+unsigned long CFrame::getTicks () const
+{
+ if (pEditor)
+ return ((AEffGUIEditor*)pEditor)->getTicks ();
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+long CFrame::getKnobMode () const
+{
+ return AEffGUIEditor::getKnobMode ();
+}
+
+//-----------------------------------------------------------------------------
+bool CFrame::setPosition (CCoord x, CCoord y)
+{
+ size.left = 0;
+ size.top = 0;
+
+ XWindowChanges attr;
+ attr.x = x;
+ attr.y = y;
+
+ XConfigureWindow (display, window, CWX | CWY, &attr);
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+bool CFrame::getPosition (CCoord &x, CCoord &y) const
+{
+ x = size.left;
+ y = size.top;
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+void CFrame::setViewSize (CRect& inRect)
+{
+ setSize (inRect.width (), inRect.height ());
+}
+
+//-----------------------------------------------------------------------------
+bool CFrame::setSize (CCoord width, CCoord height)
+{
+ if ((width == size.width ()) && (height == size.height ()))
+ return false;
+
+ // set the new size
+ size.right = size.left + width;
+ size.bottom = size.top + height;
+
+ XResizeWindow (display, window, size.width (), size.height ());
+
+ CRect myViewSize (0, 0, size.width (), size.height ());
+ CViewContainer::setViewSize (myViewSize);
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+bool CFrame::getSize (CRect *pRect) const
+{
+// if (!getOpenFlag ())
+// return false;
+
+ pRect->left = 0;
+ pRect->top = 0;
+ pRect->right = size.width () + pRect->left;
+ pRect->bottom = size.height () + pRect->top;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+bool CFrame::getSize (CRect& outSize) const
+{
+ return getSize (&outSize);
+}
+
+//-----------------------------------------------------------------------------
+long CFrame::setModalView (CView *pView)
+{
+ // There's already a modal view so we get out
+ if (pView && pModalView)
+ return 0;
+
+ if (pModalView)
+ removeView (pModalView, false);
+
+ pModalView = pView;
+ if (pModalView)
+ addView (pModalView);
+
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+void CFrame::beginEdit (long index)
+{
+ if (pEditor)
+ ((AEffGUIEditor*)pEditor)->beginEdit (index);
+}
+
+//-----------------------------------------------------------------------------
+void CFrame::endEdit (long index)
+{
+ if (pEditor)
+ ((AEffGUIEditor*)pEditor)->endEdit (index);
+}
+
+//-----------------------------------------------------------------------------
+CView *CFrame::getCurrentView () const
+{
+ if (pModalView)
+ return pModalView;
+
+ return CViewContainer::getCurrentView ();
+}
+
+//-----------------------------------------------------------------------------
+bool CFrame::getCurrentLocation (CPoint &where)
+{
+ // create a local context
+ CDrawContext *pContext = createDrawContext ();
+ if (pContext)
+ {
+ // get the current position
+ pContext->getMouseLocation (where);
+ pContext->forget ();
+ }
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+void CFrame::setCursor (CCursorType type)
+{
+}
+
+//-----------------------------------------------------------------------------
+void CFrame::setFocusView (CView *pView)
+{
+ if (pView && ! pView->isVisible())
+ return;
+
+ CView *pOldFocusView = pFocusView;
+ pFocusView = pView;
+
+ if (pFocusView && pFocusView->wantsFocus ())
+ pFocusView->setDirty ();
+
+ if (pOldFocusView)
+ {
+ pOldFocusView->looseFocus ();
+ if (pOldFocusView->wantsFocus ())
+ pOldFocusView->setDirty ();
+ }
+}
+
+//-----------------------------------------------------------------------------
+bool CFrame::advanceNextFocusView (CView* oldFocus, bool reverse)
+{
+ if (pModalView)
+ return false; // currently not supported, but should be done sometime
+ if (oldFocus == 0)
+ {
+ if (pFocusView == 0)
+ return CViewContainer::advanceNextFocusView (0, reverse);
+ oldFocus = pFocusView;
+ }
+ if (isChild (oldFocus))
+ {
+ if (CViewContainer::advanceNextFocusView (oldFocus, reverse))
+ return true;
+ else
+ {
+ setFocusView (NULL);
+ return false;
+ }
+ }
+ CView* parentView = oldFocus->getParentView ();
+ if (parentView && parentView->isTypeOf ("CViewContainer"))
+ {
+ CView* tempOldFocus = oldFocus;
+ CViewContainer* vc = (CViewContainer*)parentView;
+ while (vc)
+ {
+ if (vc->advanceNextFocusView (tempOldFocus, reverse))
+ return true;
+ else
+ {
+ tempOldFocus = vc;
+ if (vc->getParentView () && vc->getParentView ()->isTypeOf ("CViewContainer"))
+ vc = (CViewContainer*)vc->getParentView ();
+ else
+ vc = 0;
+ }
+ }
+ }
+ return CViewContainer::advanceNextFocusView (oldFocus, reverse);
+}
+
+//-----------------------------------------------------------------------------
+void CFrame::invalidate (const CRect &rect)
+{
+ CRect rectView;
+ FOREACHSUBVIEW
+ if (pV)
+ {
+ pV->getViewSize (rectView);
+ if (rect.rectOverlap (rectView))
+ pV->setDirty (true);
+ }
+ ENDFOR
+
+ XClearArea (display,
+ window,
+ rect.left,
+ rect.top,
+ rect.right - rect.left,
+ rect.bottom - rect.top,
+ true);
+
+ XSync (display, false);
+
+/*
+ XEvent ev;
+ memset (&ev, 0, sizeof (XEvent));
+ ev.xexpose.type = Expose;
+ ev.xexpose.display = display;
+ ev.xexpose.window = (Window) window;
+
+ ev.xexpose.x = rect.left;
+ ev.xexpose.y = rect.top;
+ ev.xexpose.width = rect.right - rect.left;
+ ev.xexpose.height = rect.bottom - rect.top;
+
+ XSendEvent (display, (Window) window, False, 0L, &ev);
+ XFlush (display);
+*/
+}
+
+#if DEBUG
+//-----------------------------------------------------------------------------
+void CFrame::dumpHierarchy ()
+{
+ dumpInfo ();
+ DebugPrint ("\n");
+ CViewContainer::dumpHierarchy ();
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// CCView Implementation
+//-----------------------------------------------------------------------------
+CCView::CCView (CView *pView)
+ : pView (pView), pNext (0), pPrevious (0)
+{
+ if (pView)
+ pView->remember ();
+}
+
+//-----------------------------------------------------------------------------
+CCView::~CCView ()
+{
+ if (pView)
+ pView->forget ();
+}
+
+//-----------------------------------------------------------------------------
+// CViewContainer Implementation
+//-----------------------------------------------------------------------------
+/**
+ * CViewContainer constructor.
+ * @param rect the size of the container
+ * @param pParent the parent CFrame
+ * @param pBackground the background bitmap, can be NULL
+ */
+CViewContainer::CViewContainer (const CRect &rect, CFrame *pParent, CBitmap *pBackground)
+ : CView (rect),
+ pFirstView (0),
+ pLastView (0),
+ mode (kNormalUpdate),
+ pOffscreenContext (0),
+ bDrawInOffscreen (false),
+ currentDragView (0)
+{
+ pParentFrame = pParent;
+
+ backgroundOffset (0, 0);
+
+ setBackground (pBackground);
+ backgroundColor = kBlackCColor;
+
+#if NEW_UPDATE_MECHANISM
+ mode = kOnlyDirtyUpdate;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+CViewContainer::~CViewContainer ()
+{
+ // remove all views
+ removeAll (true);
+
+ if (pOffscreenContext)
+ pOffscreenContext->forget ();
+ pOffscreenContext = 0;
+}
+
+//-----------------------------------------------------------------------------
+/**
+ * @param rect the new size of the container
+ */
+void CViewContainer::setViewSize (CRect &rect)
+{
+ CView::setViewSize (rect);
+
+ if (pOffscreenContext && bDrawInOffscreen)
+ {
+ pOffscreenContext->forget ();
+ pOffscreenContext = new COffscreenContext (pParentFrame, (long)size.width (), (long)size.height (), kBlackCColor);
+ }
+}
+
+//-----------------------------------------------------------------------------
+/**
+ * @param color the new background color of the container
+ */
+void CViewContainer::setBackgroundColor (CColor color)
+{
+ backgroundColor = color;
+ setDirty (true);
+}
+
+//------------------------------------------------------------------------------
+long CViewContainer::notify (CView* sender, const char* message)
+{
+ if (message == kMsgCheckIfViewContainer)
+ return kMessageNotified;
+ return kMessageUnknown;
+}
+
+//-----------------------------------------------------------------------------
+/**
+ * @param pView the view object to add to this container
+ */
+void CViewContainer::addView (CView *pView)
+{
+ if (!pView)
+ return;
+
+ CCView *pSv = new CCView (pView);
+
+ pView->pParentFrame = pParentFrame;
+ pView->pParentView = this;
+
+ CCView *pV = pFirstView;
+ if (!pV)
+ {
+ pLastView = pFirstView = pSv;
+ }
+ else
+ {
+ while (pV->pNext)
+ pV = pV->pNext;
+ pV->pNext = pSv;
+ pSv->pPrevious = pV;
+ pLastView = pSv;
+ }
+ pView->attached (this);
+ pView->setDirty ();
+}
+
+//-----------------------------------------------------------------------------
+/**
+ * @param pView the view object to add to this container
+ * @param mouseableArea the view area in where the view will get mouse events
+ * @param mouseEnabled bool to set if view will get mouse events
+ */
+void CViewContainer::addView (CView *pView, CRect &mouseableArea, bool mouseEnabled)
+{
+ if (!pView)
+ return;
+
+ pView->setMouseEnabled (mouseEnabled);
+ pView->setMouseableArea (mouseableArea);
+
+ addView (pView);
+}
+
+//-----------------------------------------------------------------------------
+/**
+ * @param withForget bool to indicate if the view's reference counter should be decreased after removed from the container
+ */
+void CViewContainer::removeAll (const bool &withForget)
+{
+ CCView *pV = pFirstView;
+ while (pV)
+ {
+ CCView *pNext = pV->pNext;
+ if (pV->pView)
+ {
+ pV->pView->removed (this);
+ if (withForget)
+ pV->pView->forget ();
+ }
+
+ delete pV;
+
+ pV = pNext;
+ }
+ pFirstView = 0;
+ pLastView = 0;
+}
+
+//-----------------------------------------------------------------------------
+/**
+ * @param pView the view which should be removed from the container
+ * @param withForget bool to indicate if the view's reference counter should be decreased after removed from the container
+ */
+void CViewContainer::removeView (CView *pView, const bool &withForget)
+{
+ if (pParentFrame && pParentFrame->getFocusView () == pView)
+ pParentFrame->setFocusView (0);
+ CCView *pV = pFirstView;
+ while (pV)
+ {
+ if (pView == pV->pView)
+ {
+ CCView *pNext = pV->pNext;
+ CCView *pPrevious = pV->pPrevious;
+ if (pV->pView)
+ {
+ pV->pView->removed (this);
+ if (withForget)
+ pV->pView->forget ();
+ }
+ delete pV;
+ if (pPrevious)
+ {
+ pPrevious->pNext = pNext;
+ if (pNext)
+ pNext->pPrevious = pPrevious;
+ else
+ pLastView = pPrevious;
+ }
+ else
+ {
+ pFirstView = pNext;
+ if (pNext)
+ pNext->pPrevious = 0;
+ else
+ pLastView = 0;
+ }
+ break;
+ }
+ else
+ pV = pV->pNext;
+ }
+}
+
+//-----------------------------------------------------------------------------
+/**
+ * @param pView the view which should be checked if it is a child of this container
+ */
+bool CViewContainer::isChild (CView *pView) const
+{
+ bool found = false;
+
+ CCView *pV = pFirstView;
+ while (pV)
+ {
+ if (pView == pV->pView)
+ {
+ found = true;
+ break;
+ }
+ pV = pV->pNext;
+ }
+ return found;
+}
+
+//-----------------------------------------------------------------------------
+long CViewContainer::getNbViews () const
+{
+ long nb = 0;
+ CCView *pV = pFirstView;
+ while (pV)
+ {
+ pV = pV->pNext;
+ nb++;
+ }
+ return nb;
+}
+
+//-----------------------------------------------------------------------------
+/**
+ * @param index the index of the view to return
+ */
+CView *CViewContainer::getView (long index) const
+{
+ long nb = 0;
+ CCView *pV = pFirstView;
+ while (pV)
+ {
+ if (nb == index)
+ return pV->pView;
+ pV = pV->pNext;
+ nb++;
+ }
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+/**
+ * @param pContext the context which to use to draw this container and its subviews
+ */
+void CViewContainer::draw (CDrawContext *pContext)
+{
+ CDrawContext *pC;
+ CCoord save[4];
+
+ if (!pOffscreenContext && bDrawInOffscreen)
+ pOffscreenContext = new COffscreenContext (pParentFrame, (long)size.width (), (long)size.height (), kBlackCColor);
+
+#if USE_ALPHA_BLEND
+ if (pOffscreenContext && bTransparencyEnabled)
+ pOffscreenContext->copyTo (pContext, size);
+#endif
+
+ if (bDrawInOffscreen)
+ pC = pOffscreenContext;
+ else
+ {
+ pC = pContext;
+ modifyDrawContext (save, pContext);
+ }
+
+ CRect r (0, 0, size.width (), size.height ());
+
+#if USE_CLIPPING_DRAWRECT
+ CRect oldClip;
+ pContext->getClipRect (oldClip);
+ CRect oldClip2 (oldClip);
+ if (bDrawInOffscreen && getFrame () != this)
+ oldClip.offset (-oldClip.left, -oldClip.top);
+
+ CRect newClip (r);
+ newClip.bound (oldClip);
+ pC->setClipRect (newClip);
+#endif
+
+ // draw the background
+ if (pBackground)
+ {
+ if (bTransparencyEnabled)
+ pBackground->drawTransparent (pC, r, backgroundOffset);
+ else
+ pBackground->draw (pC, r, backgroundOffset);
+ }
+ else if (!bTransparencyEnabled)
+ {
+ pC->setFillColor (backgroundColor);
+ pC->fillRect (r);
+ }
+
+ // draw each view
+ FOREACHSUBVIEW
+#if USE_CLIPPING_DRAWRECT
+ CRect vSize (pV->size);
+ vSize.bound (oldClip);
+ pC->setClipRect (vSize);
+#endif
+ if (pV->isVisible())
+ pV->draw (pC);
+ ENDFOR
+
+#if USE_CLIPPING_DRAWRECT
+ pC->setClipRect (oldClip2);
+#endif
+
+ // transfert offscreen
+ if (bDrawInOffscreen)
+ ((COffscreenContext*)pC)->copyFrom (pContext, size);
+ else
+ restoreDrawContext (pContext, save);
+
+ setDirty (false);
+}
+
+//-----------------------------------------------------------------------------
+/**
+ * @param pContext the context which to use to draw the background
+ * @param _updateRect the area which to draw
+ */
+void CViewContainer::drawBackgroundRect (CDrawContext *pContext, CRect& _updateRect)
+{
+ if (pBackground)
+ {
+ CRect oldClip;
+ pContext->getClipRect (oldClip);
+ CRect newClip (_updateRect);
+ newClip.bound (oldClip);
+ pContext->setClipRect (newClip);
+ CRect tr (0, 0, pBackground->getWidth (), pBackground->getHeight ());
+ if (bTransparencyEnabled)
+ pBackground->drawTransparent (pContext, tr, backgroundOffset);
+ else
+ pBackground->draw (pContext, tr, backgroundOffset);
+ pContext->setClipRect (oldClip);
+ }
+ else if (!bTransparencyEnabled)
+ {
+ pContext->setFillColor (backgroundColor);
+ pContext->fillRect (_updateRect);
+ }
+}
+
+//-----------------------------------------------------------------------------
+/**
+ * @param pContext the context which to use to draw
+ * @param _updateRect the area which to draw
+ */
+void CViewContainer::drawRect (CDrawContext *pContext, const CRect& _updateRect)
+{
+ CDrawContext *pC;
+ CCoord save[4];
+
+ if (!pOffscreenContext && bDrawInOffscreen)
+ pOffscreenContext = new COffscreenContext (pParentFrame, (long)size.width (), (long)size.height (), kBlackCColor);
+
+#if USE_ALPHA_BLEND
+ if (pOffscreenContext && bTransparencyEnabled)
+ pOffscreenContext->copyTo (pContext, size);
+#endif
+
+ if (bDrawInOffscreen)
+ pC = pOffscreenContext;
+ else
+ {
+ pC = pContext;
+ modifyDrawContext (save, pContext);
+ }
+
+ CRect updateRect (_updateRect);
+ updateRect.bound (size);
+
+ CRect clientRect (updateRect);
+ clientRect.offset (-size.left, -size.top);
+
+#if USE_CLIPPING_DRAWRECT
+ CRect oldClip;
+ pContext->getClipRect (oldClip);
+ CRect oldClip2 (oldClip);
+ if (bDrawInOffscreen && getFrame () != this)
+ oldClip.offset (-oldClip.left, -oldClip.top);
+
+ CRect newClip (clientRect);
+ newClip.bound (oldClip);
+ pC->setClipRect (newClip);
+#endif
+
+ // draw the background
+ drawBackgroundRect (pC, clientRect);
+
+ // draw each view
+ FOREACHSUBVIEW
+ if (pV->isVisible() && pV->checkUpdate (clientRect))
+ {
+#if USE_CLIPPING_DRAWRECT
+ CRect viewSize (pV->size);
+ viewSize.bound (newClip);
+ if (viewSize.getWidth () == 0 || viewSize.getHeight () == 0)
+ continue;
+ pC->setClipRect (viewSize);
+#endif
+
+ bool wasDirty = pV->isDirty ();
+ pV->drawRect (pC, clientRect);
+
+#if DEBUG_FOCUS_DRAWING
+ if (getFrame ()->getFocusView() == pV && pV->wantsFocus ())
+ {
+ pC->setDrawMode (kCopyMode);
+ pC->setFrameColor (kRedCColor);
+ pC->drawRect (pV->size);
+ }
+#endif
+ if (wasDirty && /* pV->size != viewSize &&*/ !isTypeOf ("CScrollContainer"))
+ {
+ pV->setDirty (true);
+ }
+ }
+ ENDFOR
+
+#if USE_CLIPPING_DRAWRECT
+ pC->setClipRect (oldClip2);
+#endif
+
+ // transfer offscreen
+ if (bDrawInOffscreen)
+ ((COffscreenContext*)pC)->copyFrom (pContext, updateRect, CPoint (clientRect.left, clientRect.top));
+ else
+ restoreDrawContext (pContext, save);
+
+#if EVENT_DRAW_FIX
+ if (bDirty && newClip == size)
+#endif
+ setDirty (false);
+}
+
+//-----------------------------------------------------------------------------
+/**
+ * @param context the context which to use to redraw this container
+ * @param rect the area which to redraw
+ */
+void CViewContainer::redrawRect (CDrawContext* context, const CRect& rect)
+{
+ CRect _rect (rect);
+ _rect.offset (size.left, size.top);
+ if (bTransparencyEnabled)
+ {
+ // as this is transparent, we call the parentview to redraw this area.
+ if (pParentView)
+ pParentView->redrawRect (context, _rect);
+ else if (pParentFrame)
+ pParentFrame->drawRect (context, _rect);
+ }
+ else
+ {
+ CCoord save[4];
+ if (pParentView)
+ {
+ CPoint off;
+ pParentView->localToFrame (off);
+ // store
+ save[0] = context->offsetScreen.h;
+ save[1] = context->offsetScreen.v;
+ save[2] = context->offset.h;
+ save[3] = context->offset.v;
+
+ context->offsetScreen.h += off.x;
+ context->offsetScreen.v += off.y;
+ context->offset.h += off.x;
+ context->offset.v += off.y;
+
+ drawRect (context, _rect);
+
+ // restore
+ context->offsetScreen.h = save[0];
+ context->offsetScreen.v = save[1];
+ context->offset.h = save[2];
+ context->offset.v = save[3];
+ }
+ else
+ {
+ drawRect (context, _rect);
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+bool CViewContainer::hitTestSubViews (const CPoint& where, const long buttons)
+{
+ CPoint where2 (where);
+ where2.offset (-size.left, -size.top);
+
+ CCView *pSv = pLastView;
+ while (pSv)
+ {
+ CView *pV = pSv->pView;
+ if (pV && pV->getMouseEnabled () && pV->hitTest (where2, buttons))
+ return true;
+ pSv = pSv->pPrevious;
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+bool CViewContainer::hitTest (const CPoint& where, const long buttons)
+{
+ //return hitTestSubViews (where); would change default behavior
+ return CView::hitTest (where, buttons);
+}
+
+//-----------------------------------------------------------------------------
+void CViewContainer::mouse (CDrawContext *pContext, CPoint &where, long buttons)
+{
+ // convert to relativ pos
+ CPoint where2 (where);
+ where2.offset (-size.left, -size.top);
+
+ if (buttons == -1 && pContext)
+ buttons = pContext->getMouseButtons ();
+
+ CCView *pSv = pLastView;
+ while (pSv)
+ {
+ CView *pV = pSv->pView;
+ if (pV && pV->getMouseEnabled () && pV->hitTest (where2, buttons))
+ {
+ pV->mouse (pContext, where2, buttons);
+ break;
+ }
+ pSv = pSv->pPrevious;
+ }
+}
+
+//-----------------------------------------------------------------------------
+long CViewContainer::onKeyDown (VstKeyCode& keyCode)
+{
+ long result = -1;
+
+ CCView* pSv = pLastView;
+ while (pSv)
+ {
+ long result = pSv->pView->onKeyDown (keyCode);
+ if (result != -1)
+ break;
+
+ pSv = pSv->pPrevious;
+ }
+
+ return result;
+}
+
+//-----------------------------------------------------------------------------
+long CViewContainer::onKeyUp (VstKeyCode& keyCode)
+{
+ long result = -1;
+
+ CCView* pSv = pLastView;
+ while (pSv)
+ {
+ long result = pSv->pView->onKeyUp (keyCode);
+ if (result != -1)
+ break;
+
+ pSv = pSv->pPrevious;
+ }
+
+ return result;
+}
+
+//-----------------------------------------------------------------------------
+bool CViewContainer::onWheel (CDrawContext *pContext, const CPoint &where, const CMouseWheelAxis axis, float distance)
+{
+ bool result = false;
+ CView *view = getViewAt (where);
+ if (view)
+ {
+ // convert to relativ pos
+ CPoint where2 (where);
+ where2.offset (-size.left, -size.top);
+
+ CCoord save[4];
+ modifyDrawContext (save, pContext);
+
+ result = view->onWheel (pContext, where2, axis, distance);
+
+ restoreDrawContext (pContext, save);
+ }
+ return result;
+}
+
+//-----------------------------------------------------------------------------
+bool CViewContainer::onWheel (CDrawContext *pContext, const CPoint &where, float distance)
+{
+ return onWheel (pContext, where, kMouseWheelAxisY, distance);
+}
+
+//-----------------------------------------------------------------------------
+bool CViewContainer::onDrop (CDrawContext* context, CDragContainer* drag, const CPoint& where)
+{
+ if (!pParentFrame)
+ return false;
+
+ bool result = false;
+
+ CCoord save[4];
+ modifyDrawContext (save, context);
+
+ // convert to relativ pos
+ CPoint where2 (where);
+ where2.offset (-size.left, -size.top);
+
+ CView* view = getViewAt (where);
+ if (view != currentDragView)
+ {
+ if (currentDragView)
+ currentDragView->onDragLeave (context, drag, where2);
+ currentDragView = view;
+ }
+ if (currentDragView)
+ {
+ result = currentDragView->onDrop (context, drag, where2);
+ currentDragView->onDragLeave (context, drag, where2);
+ }
+ currentDragView = 0;
+
+ restoreDrawContext (context, save);
+
+ return result;
+}
+
+//-----------------------------------------------------------------------------
+void CViewContainer::onDragEnter (CDrawContext* context, CDragContainer* drag, const CPoint& where)
+{
+ if (!pParentFrame)
+ return;
+
+ CCoord save[4];
+ modifyDrawContext (save, context);
+
+ // convert to relativ pos
+ CPoint where2 (where);
+ where2.offset (-size.left, -size.top);
+
+ if (currentDragView)
+ currentDragView->onDragLeave (context, drag, where2);
+ CView* view = getViewAt (where);
+ currentDragView = view;
+ if (view)
+ view->onDragEnter (context, drag, where2);
+
+ restoreDrawContext (context, save);
+}
+
+//-----------------------------------------------------------------------------
+void CViewContainer::onDragLeave (CDrawContext* context, CDragContainer* drag, const CPoint& where)
+{
+ if (!pParentFrame)
+ return;
+
+ CCoord save[4];
+ modifyDrawContext (save, context);
+
+ // convert to relativ pos
+ CPoint where2 (where);
+ where2.offset (-size.left, -size.top);
+
+ if (currentDragView)
+ currentDragView->onDragLeave (context, drag, where2);
+ currentDragView = 0;
+
+ restoreDrawContext (context, save);
+}
+
+//-----------------------------------------------------------------------------
+void CViewContainer::onDragMove (CDrawContext* context, CDragContainer* drag, const CPoint& where)
+{
+ if (!pParentFrame)
+ return;
+
+ CCoord save[4];
+ modifyDrawContext (save, context);
+
+ // convert to relativ pos
+ CPoint where2 (where);
+ where2.offset (-size.left, -size.top);
+
+ CView* view = getViewAt (where);
+ if (view != currentDragView)
+ {
+ if (currentDragView)
+ currentDragView->onDragLeave (context, drag, where2);
+ if (view)
+ view->onDragEnter (context, drag, where2);
+ currentDragView = view;
+ }
+ else if (currentDragView)
+ currentDragView->onDragMove (context, drag, where2);
+
+ restoreDrawContext (context, save);
+}
+
+//-----------------------------------------------------------------------------
+void CViewContainer::update (CDrawContext *pContext)
+{
+ switch (mode)
+ {
+ //---Normal : redraw all...
+ case kNormalUpdate:
+ if (isDirty ())
+ {
+#if NEW_UPDATE_MECHANISM
+ CRect ur (0, 0, size.width (), size.height ());
+ redrawRect (pContext, ur);
+#else
+ #if USE_ALPHA_BLEND
+ if (bTransparencyEnabled)
+ {
+ CRect updateRect (size);
+ CPoint offset (0,0);
+ localToFrame (offset);
+ updateRect.offset (offset.x, offset.y);
+ getFrame ()->drawRect (pContext, updateRect);
+ }
+ else
+ #endif
+ draw (pContext);
+ #endif
+ setDirty (false);
+ }
+ break;
+
+ //---Redraw only dirty controls-----
+ case kOnlyDirtyUpdate:
+ {
+#if NEW_UPDATE_MECHANISM
+ if (bDirty)
+ {
+ CRect ur (0, 0, size.width (), size.height ());
+ redrawRect (pContext, ur);
+ }
+ else
+ {
+ CRect updateRect (size);
+ updateRect.offset (-size.left, -size.top);
+ FOREACHSUBVIEW
+ if (pV->isDirty () && pV->checkUpdate (updateRect))
+ {
+ if (pV->notify (this, kMsgCheckIfViewContainer))
+ pV->update (pContext);
+ else
+ {
+ CRect drawSize (pV->size);
+ drawSize.bound (updateRect);
+ pV->redrawRect (pContext, drawSize);
+ }
+ }
+ ENDFOR
+ }
+#else
+ #if USE_ALPHA_BLEND
+ if (bTransparencyEnabled)
+ {
+ if (bDirty)
+ {
+ CRect updateRect (size);
+ CPoint offset (0,0);
+ localToFrame (offset);
+ updateRect.offset (offset.x, offset.y);
+ getFrame ()->drawRect (pContext, updateRect);
+ }
+ else
+ {
+ CRect updateRect (size);
+ updateRect.offset (-size.left, -size.top);
+ FOREACHSUBVIEW
+ if (pV->isDirty () && pV->checkUpdate (updateRect))
+ {
+ if (pV->notify (this, kMsgCheckIfViewContainer))
+ {
+ pV->update (pContext);
+ }
+ else
+ {
+ CPoint offset;
+ CRect viewSize (pV->size);
+ pV->localToFrame (offset);
+ viewSize.offset (offset.x, offset.y);
+ getFrame ()->drawRect (pContext, viewSize);
+ }
+ }
+ ENDFOR
+ }
+ setDirty (false);
+ return;
+ }
+ #endif
+ if (bDirty)
+ draw (pContext);
+ else if (bDrawInOffscreen && pOffscreenContext)
+ {
+ bool doCopy = false;
+ if (isDirty ())
+ doCopy = true;
+
+ FOREACHSUBVIEW
+ pV->update (pOffscreenContext);
+ ENDFOR
+
+ // transfert offscreen
+ if (doCopy)
+ pOffscreenContext->copyFrom (pContext, size);
+ }
+ else
+ {
+ long save[4];
+ modifyDrawContext (save, pContext);
+
+ FOREACHSUBVIEW
+ if (pV->isDirty ())
+ {
+ long oldMode = 0;
+ CViewContainer* child = 0;
+ if (pV->notify (this, kMsgCheckIfViewContainer))
+ {
+ child = (CViewContainer*)pV;
+ oldMode = child->getMode ();
+ child->setMode (kNormalUpdate);
+ }
+ CRect viewSize (pV->size);
+ drawBackgroundRect (pContext, viewSize);
+ pV->update (pContext);
+ if (child)
+ child->setMode (oldMode);
+ }
+ ENDFOR
+
+ restoreDrawContext (pContext, save);
+ }
+#endif
+ setDirty (false);
+ break;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+void CViewContainer::looseFocus (CDrawContext *pContext)
+{
+ FOREACHSUBVIEW
+ pV->looseFocus (pContext);
+ ENDFOR
+}
+
+//-----------------------------------------------------------------------------
+void CViewContainer::takeFocus (CDrawContext *pContext)
+{
+ FOREACHSUBVIEW
+ pV->takeFocus (pContext);
+ ENDFOR
+}
+
+//-----------------------------------------------------------------------------
+bool CViewContainer::advanceNextFocusView (CView* oldFocus, bool reverse)
+{
+ bool foundOld = false;
+ FOREACHSUBVIEW_REVERSE(reverse)
+ if (oldFocus && !foundOld)
+ {
+ if (oldFocus == pV)
+ {
+ foundOld = true;
+ continue;
+ }
+ }
+ else
+ {
+ if (pV->wantsFocus ())
+ {
+ getFrame ()->setFocusView (pV);
+ return true;
+ }
+ else if (pV->isTypeOf ("CViewContainer"))
+ {
+ if (((CViewContainer*)pV)->advanceNextFocusView (0, reverse))
+ return true;
+ }
+ }
+ ENDFOR
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+bool CViewContainer::isDirty () const
+{
+ if (bDirty)
+ return true;
+
+ CRect viewSize (size);
+ viewSize.offset (-size.left, -size.top);
+
+ FOREACHSUBVIEW
+ if (pV->isDirty ())
+ {
+ CRect r (pV->size);
+ r.bound (viewSize);
+ if (r.getWidth () > 0 && r.getHeight () > 0)
+ return true;
+ }
+ ENDFOR
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+CView *CViewContainer::getCurrentView () const
+{
+ if (!pParentFrame)
+ return 0;
+
+ // get the current position
+ CPoint where;
+ pParentFrame->getCurrentLocation (where);
+
+ frameToLocal (where);
+
+ CCView *pSv = pLastView;
+ while (pSv)
+ {
+ CView *pV = pSv->pView;
+ if (pV && where.isInside (pV->mouseableArea))
+ return pV;
+ pSv = pSv->pPrevious;
+ }
+
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+CView *CViewContainer::getViewAt (const CPoint& p, bool deep) const
+{
+ if (!pParentFrame)
+ return 0;
+
+ CPoint where (p);
+
+ // convert to relativ pos
+ where.offset (-size.left, -size.top);
+
+ CCView *pSv = pLastView;
+ while (pSv)
+ {
+ CView *pV = pSv->pView;
+ if (pV && where.isInside (pV->mouseableArea))
+ {
+ if (deep)
+ {
+ if (pV->isTypeOf ("CViewContainer"))
+ return ((CViewContainer*)pV)->getViewAt (where, deep);
+ }
+ return pV;
+ }
+ pSv = pSv->pPrevious;
+ }
+
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+CPoint& CViewContainer::frameToLocal (CPoint& point) const
+{
+ point.offset (-size.left, -size.top);
+ if (pParentView && pParentView->isTypeOf ("CViewContainer"))
+ return pParentView->frameToLocal (point);
+ return point;
+}
+
+//-----------------------------------------------------------------------------
+CPoint& CViewContainer::localToFrame (CPoint& point) const
+{
+ point.offset (size.left, size.top);
+ if (pParentView && pParentView->isTypeOf ("CViewContainer"))
+ return pParentView->localToFrame (point);
+ return point;
+}
+
+//-----------------------------------------------------------------------------
+bool CViewContainer::removed (CView* parent)
+{
+ if (pOffscreenContext)
+ pOffscreenContext->forget ();
+ pOffscreenContext = 0;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+bool CViewContainer::attached (CView* view)
+{
+ // create offscreen bitmap
+ if (!pOffscreenContext && bDrawInOffscreen)
+ pOffscreenContext = new COffscreenContext (pParentFrame, (long)size.width (), (long)size.height (), kBlackCColor);
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+void CViewContainer::useOffscreen (bool b)
+{
+ bDrawInOffscreen = b;
+
+ if (!bDrawInOffscreen && pOffscreenContext)
+ {
+ pOffscreenContext->forget ();
+ pOffscreenContext = 0;
+ }
+}
+
+//-----------------------------------------------------------------------------
+void CViewContainer::modifyDrawContext (CCoord save[4], CDrawContext* pContext)
+{
+ // store
+ save[0] = pContext->offsetScreen.h;
+ save[1] = pContext->offsetScreen.v;
+ save[2] = pContext->offset.h;
+ save[3] = pContext->offset.v;
+
+ pContext->offsetScreen.h += size.left;
+ pContext->offsetScreen.v += size.top;
+ pContext->offset.h += size.left;
+ pContext->offset.v += size.top;
+}
+
+//-----------------------------------------------------------------------------
+void CViewContainer::restoreDrawContext (CDrawContext* pContext, CCoord save[4])
+{
+ // restore
+ pContext->offsetScreen.h = save[0];
+ pContext->offsetScreen.v = save[1];
+ pContext->offset.h = save[2];
+ pContext->offset.v = save[3];
+}
+
+#if DEBUG
+static long _debugDumpLevel = 0;
+//-----------------------------------------------------------------------------
+void CViewContainer::dumpInfo ()
+{
+ static const char* modeString[] = { "Normal Update Mode", "Only Dirty Update Mode"};
+ DebugPrint ("CViewContainer: Mode: %s, Offscreen:%s ", modeString[mode], bDrawInOffscreen ? "Yes" : "No");
+ CView::dumpInfo ();
+}
+
+//-----------------------------------------------------------------------------
+void CViewContainer::dumpHierarchy ()
+{
+ _debugDumpLevel++;
+ FOREACHSUBVIEW
+ for (long i = 0; i < _debugDumpLevel; i++)
+ DebugPrint ("\t");
+ pV->dumpInfo ();
+ DebugPrint ("\n");
+ if (pV->isTypeOf ("CViewContainer"))
+ ((CViewContainer*)pV)->dumpHierarchy ();
+ ENDFOR
+ _debugDumpLevel--;
+}
+
+#endif
+
+
+//-----------------------------------------------------------------------------
+// CBitmap Implementation
+//-----------------------------------------------------------------------------
+/*! @class CBitmap
+@section cbitmap_alphablend Alpha Blend and Transparency
+With Version 3.0 of VSTGUI it is possible to use alpha blended bitmaps. This comes free on Mac OS X and with Windows you need to include libpng.
+Per default PNG images will be rendered alpha blended. If you want to use a transparency color with PNG Bitmaps, you need to call setNoAlpha(true) on the bitmap and set the transparency color.
+@section cbitmap_macos Classic Apple Mac OS
+The Bitmaps are PICTs and stored inside the resource fork.
+@section cbitmap_macosx Apple Mac OS X
+The Bitmaps can be of type PNG, JPEG, PICT, BMP and are stored in the Resources folder of the plugin bundle.
+They must be named bmp00100.png (or bmp00100.jpg, etc). The number is the resource id.
+@section cbitmap_windows Microsoft Windows
+The Bitmaps are .bmp files and must be included in the plug (usually using a .rc file).
+It's also possible to use png as of version 3.0 if you define the macro USE_LIBPNG and include the libpng and zlib libraries/sources to your project.
+*/
+CBitmap::CBitmap (AEffGUIEditor& editor, const char* filename)
+ : resourceID (resourceID), width (0), height (0), noAlpha (true)
+{
+#if DEBUG
+ gNbCBitmap++;
+#endif
+
+ bool found = false;
+ long i = 0;
+ long ncolors, cpp;
+
+ pHandle = 0;
+ pMask = 0;
+
+ if (editor.getBundlePath() == NULL) {
+ std::cerr << "ERROR: No bundle path set, unable to load images" << std::endl;
+ } else {
+ std::string path = std::string(editor.getBundlePath()) + filename;
+ if (openPng(path.c_str())) // reads width, height
+ closePng();
+ }
+
+ setTransparentColor (kTransparentCColor);
+
+#if DEBUG
+ gBitmapAllocation += (long)height * (long)width;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+CBitmap::CBitmap (CFrame &frame, CCoord width, CCoord height)
+ : width (width), height (height), noAlpha (true), pMask (0)
+{
+#if DEBUG
+ gNbCBitmap++;
+#endif
+
+ pHandle = (void*) XCreatePixmap (display,
+ frame.getBackBuffer (),
+ width,
+ height,
+ frame.getDepth ());
+
+ setTransparentColor (kTransparentCColor);
+}
+
+//-----------------------------------------------------------------------------
+CBitmap::CBitmap ()
+ : resourceID (0)
+ , width (0)
+ , height (0)
+ , noAlpha (true)
+{
+ pMask = 0;
+ pHandle = 0;
+}
+
+//-----------------------------------------------------------------------------
+CBitmap::~CBitmap ()
+{
+ dispose ();
+}
+
+//-----------------------------------------------------------------------------
+void CBitmap::dispose ()
+{
+#if DEBUG
+ gNbCBitmap--;
+ gBitmapAllocation -= (long)height * (long)width;
+#endif
+
+ if (pHandle)
+ XFreePixmap (display, (Pixmap)pHandle);
+ if (pMask)
+ XFreePixmap (display, (Pixmap)pMask);
+
+ pHandle = 0;
+ pMask = 0;
+
+ width = 0;
+ height = 0;
+
+}
+
+//-----------------------------------------------------------------------------
+void *CBitmap::getHandle () const
+{
+ return pHandle;
+}
+
+//-----------------------------------------------------------------------------
+bool CBitmap::loadFromResource (long resourceID)
+{
+ dispose ();
+ fprintf (stderr, "CBitmap::loadFromResource not implemented\n");
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+bool CBitmap::loadFromPath (const void* platformPath)
+{
+ if (pHandle != NULL) {
+ dispose ();
+ closePng ();
+ }
+
+ bool success = openPng ((char*)platformPath);
+ if (success)
+ closePng ();
+
+ return success;
+}
+
+//-----------------------------------------------------------------------------
+bool CBitmap::isLoaded () const
+{
+ return (pHandle != NULL);
+}
+
+//-----------------------------------------------------------------------------
+void CBitmap::draw (CDrawContext *pContext, CRect &rect, const CPoint &offset)
+{
+ if (!pHandle)
+ {
+ // the first time try to decode the pixmap
+ pHandle = createPixmapFromPng (pContext);
+ if (!pHandle)
+ return;
+ }
+
+ CFrame* frame = pContext->pFrame;
+
+ XCopyArea (display,
+ (Drawable) pHandle,
+ (Drawable) frame->getBackBuffer(),
+ (GC) frame->getGC(),
+ offset.h,
+ offset.v,
+ std::min (rect.width (), getWidth()),
+ std::min (rect.height (), getHeight()),
+ rect.left + pContext->offset.h,
+ rect.top + pContext->offset.v);
+}
+
+//-----------------------------------------------------------------------------
+void CBitmap::drawTransparent (CDrawContext *pContext, CRect &rect, const CPoint &offset)
+{
+ if (!pHandle)
+ {
+ // the first time try to decode the pixmap
+ pHandle = createPixmapFromPng (pContext);
+ if (!pHandle)
+ return;
+ }
+
+ CFrame* frame = pContext->pFrame;
+
+ if (pMask == 0)
+ {
+ // get image from the pixmap
+ XImage* image = XGetImage (display, (Drawable)pHandle,
+ 0, 0, width, height, AllPlanes, ZPixmap);
+ assert (image);
+
+ // create the bitmap mask
+ pMask = (void*) XCreatePixmap (display, (Drawable)frame->getWindow(),
+ width, height, 1);
+ assert (pMask);
+
+ // create a associated GC
+ XGCValues values;
+ values.foreground = 1;
+ GC gc = XCreateGC (display, (Drawable)pMask, GCForeground, &values);
+
+ // clear the mask
+ XFillRectangle (display, (Drawable)pMask, gc, 0, 0, width, height);
+
+ // get the transparent color index
+ int color = pContext->getIndexColor (transparentCColor);
+
+ // inverse the color
+ values.foreground = 0;
+ XChangeGC (display, gc, GCForeground, &values);
+
+ // compute the mask
+ XPoint *points = new XPoint [height * width];
+ int x, y, nbPoints = 0;
+ switch (image->depth)
+ {
+ case 8:
+ for (y = 0; y < height; y++)
+ {
+ char* src = image->data + (y * image->bytes_per_line);
+
+ for (x = 0; x < width; x++)
+ {
+ if (src[x] == color)
+ {
+ points[nbPoints].x = x;
+ points[nbPoints].y = y;
+ nbPoints++;
+ }
+ }
+ }
+ break;
+
+ case 24: {
+ int bytesPerPixel = image->bits_per_pixel >> 3;
+ char *lp = image->data;
+ for (y = 0; y < height; y++)
+ {
+ char* cp = lp;
+ for (x = 0; x < width; x++)
+ {
+ if (*(int*)cp == color)
+ {
+ points[nbPoints].x = x;
+ points[nbPoints].y = y;
+ nbPoints++;
+ }
+ cp += bytesPerPixel;
+ }
+ lp += image->bytes_per_line;
+ }
+ } break;
+
+ default :
+ break;
+ }
+
+ XDrawPoints (display, (Drawable)pMask, gc,
+ points, nbPoints, CoordModeOrigin);
+
+ // free
+ XFreeGC (display, gc);
+ delete []points;
+
+ // delete
+ XDestroyImage (image);
+ }
+
+ // set the new clipmask
+ XGCValues value;
+ value.clip_mask = (Pixmap)pMask;
+ value.clip_x_origin = (rect.left + pContext->offset.h) - offset.h;
+ value.clip_y_origin = (rect.top + pContext->offset.v) - offset.v;
+
+ XChangeGC (display,
+ (GC) /*frame->getGC(),*/ pContext->pSystemContext,
+ GCClipMask | GCClipXOrigin | GCClipYOrigin,
+ &value);
+
+ XCopyArea (display,
+ (Drawable) pHandle,
+ (Drawable) frame->getBackBuffer(),
+ (GC) frame->getGC(),
+ offset.h,
+ offset.v,
+ rect.width (),
+ rect.height (),
+ rect.left + pContext->offset.h,
+ rect.top + pContext->offset.v);
+
+ // unset the clipmask
+ XSetClipMask (display, (GC)frame->getGC(), None);
+}
+
+//-----------------------------------------------------------------------------
+void CBitmap::drawAlphaBlend (CDrawContext *pContext, CRect &rect, const CPoint &offset, unsigned char alpha)
+{
+ std::cout << "CBitmap::drawAlphaBlend (not implemented!)" << std::endl;
+}
+
+//-----------------------------------------------------------------------------
+void CBitmap::setTransparentColor (const CColor color)
+{
+ transparentCColor = color;
+}
+
+//-----------------------------------------------------------------------------
+void CBitmap::setTransparencyMask (CDrawContext* pContext, const CPoint& offset)
+{
+ // todo: implement me!
+}
+
+
+//-----------------------------------------------------------------------------
+bool CBitmap::openPng (const char* path)
+{
+ assert(path);
+
+ FILE* fp = fopen(path, "rb");
+ if (!fp) {
+ fprintf(stderr, "Unable to open file %s\n", path);
+ return false;
+ }
+
+ png_byte header[8];
+ fread(header, 1, 8, fp);
+ if (png_sig_cmp(header, 0, 8)) {
+ fprintf(stderr, "File not recognized as a PNG image");
+ return false;
+ }
+
+ pngRead = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (!pngRead) {
+ fprintf(stderr, "Unable to initialize libpng\n");
+ return false;
+ }
+
+ pngInfo = png_create_info_struct(pngRead);
+ if (!pngInfo) {
+ png_destroy_read_struct(&pngRead, NULL, NULL);
+ return false;
+ }
+
+ png_init_io(pngRead, fp);
+ png_set_sig_bytes(pngRead, 8);
+
+ png_read_info(pngRead, pngInfo);
+
+ width = pngInfo->width;
+ height = pngInfo->height;
+
+ pngFp = fp;
+ pngRead = pngRead;
+ pngPath = path;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+bool CBitmap::closePng ()
+{
+ png_destroy_read_struct(&pngRead, &pngInfo, NULL);
+ fclose(pngFp);
+ pngFp = NULL;
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+void* CBitmap::createPixmapFromPng (CDrawContext *pContext)
+{
+ if (!openPng(pngPath.c_str()))
+ return NULL;
+
+ assert(width > 0 && height > 0);
+
+ png_byte** rows = (png_byte**)malloc(height * sizeof(png_byte*));
+ for (int i = 0; i < height; ++i)
+ rows[i] = (png_byte*)(malloc(pngInfo->width * sizeof(uint32_t)));
+
+ png_read_image(pngRead, rows);
+
+ CFrame* frame = pContext->pFrame;
+
+ Pixmap p = XCreatePixmap(display, frame->getBackBuffer(),
+ pngInfo->width, pngInfo->height, 24);
+
+ XGCValues values;
+ values.foreground = 0xFFFFFFFF;
+
+ // Draw
+ GC gc = XCreateGC (display, p, GCForeground, &values);
+ for (unsigned y = 0; y < pngInfo->height; y++) {
+ for (unsigned x = 0; x < pngInfo->width; ++x) {
+ char r = rows[y][(x*3)];
+ char g = rows[y][(x*3)+1];
+ char b = rows[y][(x*3)+2];
+ uint32_t color = (r << 16) + (g << 8) + b;
+ XSetForeground(display, gc, color);
+ XDrawPoint(display, p, gc, x, y);
+ }
+ }
+ XFreeGC (display, gc);
+
+ closePng();
+
+ return (void*)p;
+}
+
+//-----------------------------------------------------------------------------
+// CDragContainer Implementation
+//-----------------------------------------------------------------------------
+CDragContainer::CDragContainer (void* platformDrag)
+: platformDrag (platformDrag)
+, nbItems (0)
+, iterator (0)
+, lastItem (0)
+{
+}
+
+//-----------------------------------------------------------------------------
+CDragContainer::~CDragContainer ()
+{
+ if (lastItem)
+ {
+ free (lastItem);
+ lastItem = 0;
+ }
+}
+
+//-----------------------------------------------------------------------------
+long CDragContainer::getType (long idx) const
+{
+ // not implemented
+ return kUnknown;
+}
+
+//-----------------------------------------------------------------------------
+void* CDragContainer::first (long& size, long& type)
+{
+ iterator = 0;
+ return next (size, type);
+}
+
+//-----------------------------------------------------------------------------
+void* CDragContainer::next (long& size, long& type)
+{
+ if (lastItem)
+ {
+ free (lastItem);
+ lastItem = 0;
+ }
+ size = 0;
+ type = kUnknown;
+
+ // not implemented
+
+ return NULL;
+}
+
+} // namespace VSTGUI
+
+//-----------------------------------------------------------------------------
+// return a degre value between [0, 360 * 64[
+static long convertPoint2Angle (CPoint &pm, CPoint &pt)
+{
+ long angle;
+ if (pt.h == pm.h)
+ {
+ if (pt.v < pm.v)
+ angle = 5760; // 90 * 64
+ else
+ angle = 17280; // 270 * 64
+ }
+ else if (pt.v == pm.v)
+ {
+ if (pt.h < pm.h)
+ angle = 11520; // 180 * 64
+ else
+ angle = 0;
+ }
+ else
+ {
+ // 3666.9299 = 180 * 64 / pi
+ angle = (long)(3666.9298 * atan ((double)(pm.v - pt.v) / (double)(pt.h - pm.h)));
+
+ if (pt.v < pm.v)
+ {
+ if (pt.h < pm.h)
+ angle += 11520; // 180 * 64
+ }
+ else
+ {
+ if (pt.h < pm.h)
+ angle += 11520; // 180 * 64
+ else
+ angle += 23040; // 360 * 64
+ }
+ }
+ return angle;
+}
+
+
+
+#if !PLUGGUI
+//-----------------------------------------------------------------------------
+// CFileSelector Implementation
+//-----------------------------------------------------------------------------
+#define stringAnyType "Any Type (*.*)"
+#define stringAllTypes "All Types: ("
+#define stringSelect "Select"
+#define stringCancel "Cancel"
+#define stringLookIn "Look in"
+#define kPathMax 1024
+
+namespace VSTGUI {
+
+//-----------------------------------------------------------------------------
+CFileSelector::CFileSelector (AudioEffectX* effect)
+: effect (effect), vstFileSelect (0)
+{}
+
+//-----------------------------------------------------------------------------
+CFileSelector::~CFileSelector ()
+{
+ if (vstFileSelect)
+ {
+ if (effect && effect->canHostDo ("closeFileSelector"))
+ effect->closeFileSelector (vstFileSelect);
+ else
+ {
+ if (vstFileSelect->reserved == 1 && vstFileSelect->returnPath)
+ {
+ delete []vstFileSelect->returnPath;
+ vstFileSelect->returnPath = 0;
+ vstFileSelect->sizeReturnPath = 0;
+ }
+ if (vstFileSelect->returnMultiplePaths)
+ {
+ for (long i = 0; i < vstFileSelect->nbReturnPath; i++)
+ {
+ delete []vstFileSelect->returnMultiplePaths[i];
+ vstFileSelect->returnMultiplePaths[i] = 0;
+ }
+ delete[] vstFileSelect->returnMultiplePaths;
+ vstFileSelect->returnMultiplePaths = 0;
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+long CFileSelector::run (VstFileSelect *vstFileSelect_)
+{
+ vstFileSelect = vstFileSelect_;
+ vstFileSelect->nbReturnPath = 0;
+ vstFileSelect->returnPath[0] = 0;
+
+ if (effect
+ && effect->canHostDo ("openFileSelector")
+ && effect->canHostDo ("closeFileSelector"))
+ {
+ if (effect->openFileSelector (vstFileSelect))
+ return vstFileSelect->nbReturnPath;
+ }
+ return 0;
+}
+
+} // namespace VSTGUI
+
+//-----------------------------------------------------------------------------
+#endif // !PLUGGUI
+//-----------------------------------------------------------------------------
+
diff --git a/vstgui/vstgui.h b/vstgui/vstgui.h
new file mode 100644
index 0000000..2ab0e7d
--- /dev/null
+++ b/vstgui/vstgui.h
@@ -0,0 +1,1105 @@
+/* ----------------------------------------------------------------------------
+ * VSTGUI for X11/LV2/PNG
+ * Author: Dave Robillard
+ * Released under the revised BSD license, as below
+ * ----------------------------------------------------------------------------
+ *
+ * Based on:
+ * ----------------------------------------------------------------------------
+ * VSTGUIL: Graphical User Interface Framework for VST plugins on LINUX
+ * Version: 0.1, Date: 2007/01/21
+ * Author: kRAkEn/gORe
+ *
+ * Which was based on:
+ * ----------------------------------------------------------------------------
+ * VSTGUI: Graphical User Interface Framework for VST plugins
+ * Version 3.0 $Date: 2005/08/12 12:45:00 $
+ * ----------------------------------------------------------------------------
+ * VSTGUI LICENSE
+ * 2004, Steinberg Media Technologies, All Rights Reserved
+ * ----------------------------------------------------------------------------
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the Steinberg Media Technologies nor the names of
+ * its contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ * ----------------------------------------------------------------------------
+ */
+
+#ifndef __vstgui__
+#define __vstgui__
+
+// define global defines
+#define MOTIF 1
+#define PNG 1
+#define DEBUG 1
+
+#include "audioeffectx.h"
+#include <X11/Xlib.h>
+#include <X11/extensions/Xdbe.h>
+#include <png.h>
+#include <string>
+
+// VSTGUI Version
+#define VSTGUI_VERSION_MAJOR 3
+#define VSTGUI_VERSION_MINOR 0
+
+struct ERect {
+ VstInt16 left;
+ VstInt16 top;
+ VstInt16 right;
+ VstInt16 bottom;
+};
+
+//----------------------------------------------------
+//----------------------------------------------------
+namespace VSTGUI {
+
+class CFrame;
+class CDrawContext;
+class COffscreenContext;
+class CControl;
+class CBitmap;
+
+} // namespace VSTGUI
+
+class AudioEffect;
+
+#ifndef __aeffeditor__
+#include "AEffEditor.hpp"
+#endif
+
+//-----------------------------------------------------------------------------
+// AEffGUIEditor Declaration
+//-----------------------------------------------------------------------------
+class AEffGUIEditor : public AEffEditor
+{
+public:
+//-----------------------------------------------------------------------------
+ AEffGUIEditor (AudioEffect* effect);
+ ~AEffGUIEditor ();
+
+ // get the CFrame object
+ VSTGUI::CFrame* getFrame () { return frame; }
+
+ virtual void setParameter (VstInt32 index, float value);
+ virtual void beginEdit (VstInt32 index);
+ virtual void endEdit (VstInt32 index);
+
+ // feedback to application
+ virtual void doIdleStuff ();
+
+ // wait (in ms)
+ void wait (unsigned int ms);
+
+ // get the current time (in ms)
+ unsigned int getTicks ();
+
+ // get version of this VSTGUI
+ static int getVstGuiVersion () { return (VSTGUI_VERSION_MAJOR << 16) + VSTGUI_VERSION_MINOR; }
+
+ // get the knob mode
+ static VstInt32 getKnobMode () { return knobMode; }
+
+ long getRect (ERect** rect);
+ void idle ();
+ void update ();
+
+ void setBundlePath(const char* path) { bundlePath = strdup(path); }
+ const char* getBundlePath() { return bundlePath; }
+
+#if VST_2_1_EXTENSIONS
+ long onKeyDown (VstKeyCode& keyCode);
+ long onKeyUp (VstKeyCode& keyCode);
+ bool onWheel (float distance);
+ long setKnobMode (VstInt32 val);
+#endif
+//-----------------------------------------------------------------------------
+protected:
+ ERect rect;
+ unsigned int lLastTicks;
+ bool inIdleStuff;
+ static VstInt32 knobMode;
+ char* bundlePath;
+ friend class VSTGUI::CFrame;
+ VSTGUI::CFrame* frame;
+};
+
+//----------------------------------------------------
+#include <sys/time.h>
+#include <unistd.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Intrinsic.h>
+
+inline unsigned int _getTicks ()
+{
+ // gettimeofday is not what we need here, checkout API for hw time
+ struct timeval tv;
+ struct timezone tz;
+ gettimeofday (&tv, &tz);
+ return tv.tv_sec * 1000 + tv.tv_usec / 1000;
+}
+
+struct VstKeyCode;
+
+namespace VSTGUI {
+
+struct CPoint;
+
+#define CLASS_METHODS(name, parent) \
+ virtual bool isTypeOf (const char* s) const \
+ { return (!strcmp (s, (#name))) ? true : parent::isTypeOf (s); }\
+
+#ifdef VSTGUI_FLOAT_COORDINATES
+ typedef float CCoord;
+#else
+ typedef long CCoord;
+#endif
+
+//-----------------------------------------------------------------------------
+// Structure CRect
+//-----------------------------------------------------------------------------
+struct CRect
+{
+ CRect (CCoord l = 0, CCoord t = 0, CCoord r = 0, CCoord b = 0)
+ : left (l), top (t), right (r), bottom (b) {}
+ CRect (const CRect& r)
+ : left (r.left), top (r.top), right (r.right), bottom (r.bottom) {}
+ CRect& operator () (CCoord l, CCoord t, CCoord r, CCoord b)
+ {
+ if (l < r)
+ this->left = l, this->right = r;
+ else
+ this->left = r, this->right = l;
+ if (top < bottom)
+ this->top = t, this->bottom = b;
+ else
+ this->top = b, this->bottom = t;
+ return *this;
+ }
+
+ bool operator != (const CRect& other) const
+ { return (left != other.left || right != other.right ||
+ top != other.top || bottom != other.bottom); }
+
+ bool operator == (const CRect& other) const
+ { return (left == other.left && right == other.right &&
+ top == other.top && bottom == other.bottom); }
+
+ inline CCoord width () const { return right - left; }
+ inline CCoord height () const { return bottom - top; }
+
+ inline CCoord getWidth () const { return right - left; }
+ inline CCoord getHeight () const { return bottom - top; }
+
+ inline void setWidth (CCoord w) { right = left + w; }
+ inline void setHeight (CCoord h) { bottom = top + h; }
+
+ CRect &offset (CCoord off_x, CCoord off_y)
+ { left += off_x; right += off_x; top += off_y; bottom += off_y; return *this; }
+
+ CRect &inset (CCoord deltaX, CCoord deltaY)
+ { left += deltaX; right -= deltaX; top += deltaY; bottom -= deltaY;
+ return *this; }
+
+ CRect &moveTo (CCoord dest_x, CCoord dest_y)
+ { CCoord vDiff = dest_y - top; CCoord hDiff = dest_x - left;
+ top += vDiff; bottom += vDiff; left += hDiff; right += hDiff;
+ return *this; }
+
+ bool pointInside (const CPoint& where) const; // Checks if point is inside this rect
+ bool isEmpty () const;
+
+ bool rectOverlap (const CRect& rect) const
+ {
+ if (right < rect.left) return false;
+ if (left > rect.right) return false;
+ if (bottom < rect.top) return false;
+ if (top > rect.bottom) return false;
+ return true;
+ }
+
+ void bound (const CRect& rect);
+
+ union
+ { CCoord left; CCoord x;};
+
+ union
+ { CCoord top; CCoord y;};
+
+ union
+ { CCoord right; CCoord x2;};
+
+ union
+ { CCoord bottom; CCoord y2;};
+};
+
+//-----------------------------------------------------------------------------
+// Structure CPoint
+//-----------------------------------------------------------------------------
+struct CPoint
+{
+ CPoint (CCoord a_h = 0, CCoord a_v = 0) : h (a_h), v (a_v) {}
+ CPoint& operator () (CCoord a_h, CCoord a_v)
+ { this->h = a_h; this->v = a_v; return *this; }
+
+ bool isInside (CRect& r) const
+ { return h >= r.left && h <= r.right && v >= r.top && v <= r.bottom; }
+
+ bool operator != (const CPoint &other) const
+ { return (h != other.h || v != other.v); }
+
+ bool operator == (const CPoint &other) const
+ { return (h == other.h && v == other.v); }
+
+ CPoint &offset (CCoord off_h, CCoord off_v)
+ { this->h += off_h; this->v += off_v; return *this; }
+
+ union
+ { CCoord h; CCoord x;};
+
+ union
+ { CCoord v; CCoord y;};
+};
+
+//-----------------------------------------------------------------------------
+// Structure CColor
+//-----------------------------------------------------------------------------
+struct CColor
+{
+ CColor& operator () (unsigned char red,
+ unsigned char green,
+ unsigned char blue,
+ unsigned char alpha)
+ {
+ this->red = red;
+ this->green = green;
+ this->blue = blue;
+ this->alpha = alpha;
+ return *this;
+ }
+
+ CColor& operator = (const CColor& newColor)
+ {
+ red = newColor.red;
+ green = newColor.green;
+ blue = newColor.blue;
+ alpha = newColor.alpha;
+ return *this;
+ }
+
+ CColor operator ~ ()
+ {
+ CColor c;
+ c.red = ~red;
+ c.green = ~green;
+ c.blue = ~blue;
+ c.alpha = ~alpha;
+ return c;
+ }
+
+ bool operator != (const CColor &other) const
+ { return (red != other.red || green != other.green || blue != other.blue || alpha != other.alpha); }
+
+ bool operator == (const CColor &other) const
+ { return (red == other.red && green == other.green && blue == other.blue && alpha == other.alpha); }
+
+ unsigned char red;
+ unsigned char green;
+ unsigned char blue;
+ unsigned char alpha;
+};
+
+// define some basic colors
+extern CColor kTransparentCColor;
+extern CColor kBlackCColor;
+extern CColor kWhiteCColor;
+extern CColor kGreyCColor;
+extern CColor kRedCColor;
+extern CColor kGreenCColor;
+extern CColor kBlueCColor;
+extern CColor kYellowCColor;
+extern CColor kCyanCColor;
+extern CColor kMagentaCColor;
+
+
+//-----------------------------------------------------------------------------
+// Definitions of special characters in a platform independent way
+
+#define kDegreeSymbol "\xB0"
+#define kInfiniteSymbol "oo"
+#define kCopyrightSymbol "\xA9"
+#define kTrademarkSymbol "\x99"
+#define kRegisteredSymbol "\xAE"
+#define kMicroSymbol "\x85"
+#define kPerthousandSymbol "\x89"
+
+class CDragContainer;
+class CCView;
+class CAttributeListEntry;
+
+//-----------------------------------------------------------------------------
+typedef intptr_t CViewAttributeID;
+//-----------------------------------------------------------------------------
+// Attributes
+// all attributes where the first letter is lowercase are reserved for the vstgui lib
+
+extern const CViewAttributeID kCViewAttributeReferencePointer; // 'cvrp'
+
+//-----------------------------------------------------------------------------
+//-----------
+// Font Type
+//-----------
+enum CFont
+{
+ kSystemFont = 0,
+ kNormalFontVeryBig,
+ kNormalFontBig,
+ kNormalFont,
+ kNormalFontSmall,
+ kNormalFontSmaller,
+ kNormalFontVerySmall,
+ kSymbolFont,
+
+ kNumStandardFonts
+};
+
+//-----------
+// Text Face
+//-----------
+enum CTxtFace
+{
+ kNormalFace = 0,
+ kBoldFace = 1,
+ kItalicFace = 2,
+ kUnderlineFace = 4
+};
+
+//-----------
+// Line Style
+//-----------
+enum CLineStyle
+{
+ kLineSolid = 0,
+ kLineOnOffDash
+};
+
+//-----------
+// Draw Mode
+//-----------
+enum CDrawMode
+{
+ kCopyMode = 0,
+ kOrMode,
+ kXorMode,
+ kAntialias
+};
+
+//----------------------------
+// Text Alignment (Horizontal)
+//----------------------------
+enum CHoriTxtAlign
+{
+ kLeftText = 0,
+ kCenterText,
+ kRightText
+};
+
+//----------------------------
+// Buttons Type (+modifiers)
+//----------------------------
+enum CButton
+{
+ kLButton = 1,
+ kMButton = 2,
+ kRButton = 4,
+ kShift = 8,
+ kControl = 16,
+ kAlt = 32,
+ kApple = 64
+};
+
+//----------------------------
+// Cursor Type
+//----------------------------
+enum CCursorType
+{
+ kCursorDefault = 0,
+ kCursorWait,
+ kCursorHSize,
+ kCursorVSize,
+ kCursorSizeAll,
+ kCursorNESWSize,
+ kCursorNWSESize,
+ kCursorCopy,
+ kCursorNotAllowed,
+ kCursorHand
+};
+
+//----------------------------
+// Knob Mode
+//----------------------------
+enum CKnobMode
+{
+ kCircularMode = 0,
+ kRelativCircularMode,
+ kLinearMode
+};
+
+//----------------------------
+// Draw Style
+//----------------------------
+enum CDrawStyle
+{
+ kDrawStroked = 0,
+ kDrawFilled,
+ kDrawFilledAndStroked
+};
+
+enum CMouseWheelAxis
+{
+ kMouseWheelAxisX = 0,
+ kMouseWheelAxisY
+};
+
+//-----------------------------------------------------------------------------
+// CReferenceCounter Declaration (Reference Counting)
+//-----------------------------------------------------------------------------
+class CReferenceCounter
+{
+public:
+ CReferenceCounter () : nbReference (1) {}
+ virtual ~CReferenceCounter () {}
+
+ virtual void forget () { nbReference--; if (nbReference == 0) delete this; }
+ virtual void remember () { nbReference++; }
+ long getNbReference () const { return nbReference; }
+
+private:
+ long nbReference;
+};
+
+//-----------------------------------------------------------------------------
+// CDrawContext Declaration
+//! A drawing context encapsulates the drawing context of the underlying OS. It implements the drawing functions.
+//-----------------------------------------------------------------------------
+class CDrawContext : public CReferenceCounter
+{
+public:
+ CDrawContext (CFrame *pFrame, void *pSystemContext, void *pWindow = 0);
+ virtual ~CDrawContext ();
+
+ void moveTo (const CPoint &point); ///< move line position to point
+ void lineTo (const CPoint &point); ///< draw a line from current position to point
+ void drawLines (const CPoint* points, const long& numberOfLines); ///< draw multiple lines at once
+
+ void drawPolygon (const CPoint *pPoints, long numberOfPoints, const CDrawStyle drawStyle = kDrawStroked); ///< draw a polygon
+ void polyLine (const CPoint *pPoint, long numberOfPoints); ///< draw a stroked polygon
+ void fillPolygon (const CPoint *pPoint, long numberOfPoints); ///< draw a filled polygon
+
+ void drawRect (const CRect &rect, const CDrawStyle drawStyle = kDrawStroked); ///< draw a stroked rect
+ void fillRect (const CRect &rect); ///< draw a filled rect
+
+ void drawArc (const CRect &rect, const float startAngle1, const float endAngle2, const CDrawStyle drawStyle = kDrawStroked); ///< draw a stroked arc, where the angles are in degree
+ void drawArc (const CRect &rect, const CPoint &point1, const CPoint &point2); ///< draw a stroked arc between point1 and point2
+ void fillArc (const CRect &rect, const CPoint &point1, const CPoint &point2); ///< draw a filled arc between point1 and point2
+
+ void drawEllipse (const CRect &rect, const CDrawStyle drawStyle = kDrawStroked); ///< draw an ellipse
+ void fillEllipse (const CRect &rect); ///< draw a filled ellipse
+
+ void drawPoint (const CPoint &point, CColor color); ///< draw a point
+ CColor getPoint (const CPoint& point); ///< \deprecated
+
+ void floodFill (const CPoint& start); ///< \deprecated
+
+ void setLineStyle (CLineStyle style); ///< set the current line style
+ CLineStyle getLineStyle () const { return lineStyle; } ///< get the current line style
+
+ void setLineWidth (CCoord width); ///< set the current line width
+ CCoord getLineWidth () const { return frameWidth; } ///< get the current line width
+
+ void setDrawMode (CDrawMode mode); ///< set the current draw mode, see CDrawMode
+ CDrawMode getDrawMode () const { return drawMode; } ///< get the current draw mode, see CDrawMode
+
+ void setClipRect (const CRect &clip); ///< set the current clip
+ CRect &getClipRect (CRect &clip) const { clip = clipRect; clip.offset (-offset.h, -offset.v); return clip; } ///< get the current clip
+ void resetClipRect (); ///< reset the clip to the default state
+
+ void setFillColor (const CColor color); ///< set current fill color
+ CColor getFillColor () const { return fillColor; } ///< get current fill color
+
+ void setFrameColor (const CColor color); ///< set current stroke color
+ CColor getFrameColor () const { return frameColor; } ///< get current stroke color
+
+ void setFontColor (const CColor color); ///< set current font color
+ CColor getFontColor () const { return fontColor; } ///< get current font color
+ void setFont (CFont fontID, const long size = 0, long style = 0); ///< set current font
+ CFont getFont () const { return fontId; } ///< get current font
+ long getFontSize () const { return fontSize; } ///< get current font size
+
+ CCoord getStringWidth (const char* pStr); ///< get the width of a string
+
+ void drawString (const char *pString, const CRect &rect, const short opaque = false,
+ const CHoriTxtAlign hAlign = kCenterText); ///< draw a string
+
+ long getMouseButtons (); ///< get current mouse buttons
+ void getMouseLocation (CPoint &point); ///< get current mouse location. should not be used, see CView::getMouseLocation
+ bool waitDoubleClick (); ///< check if another mouse click occurs in the near future
+ bool waitDrag (); ///< check if the mouse will be dragged
+
+#if MOTIF
+ long getIndexColor (CColor color);
+ Colormap getColormap ();
+ Visual *getVisual ();
+ unsigned int getDepth ();
+ static long nbNewColor;
+#endif
+
+ void *getWindow () { return pWindow; }
+ void setWindow (void *ptr) { pWindow = ptr; }
+ void getLoc (CPoint &where) const { where = penLoc; }
+ CFrame* getFrame () const { return pFrame; }
+
+ CPoint offsetScreen;
+ CPoint offset;
+
+ void *getSystemContext () const { return pSystemContext; }
+
+ virtual void forget ();
+
+ //-------------------------------------------
+protected:
+
+ friend class CBitmap;
+ friend class COffscreenContext;
+
+ void *pSystemContext;
+ void *pWindow;
+ CFrame *pFrame;
+
+ long fontSize;
+ long fontStyle;
+ CFont fontId;
+ CColor fontColor;
+ CPoint penLoc;
+
+ CCoord frameWidth;
+ CColor frameColor;
+ CColor fillColor;
+ CLineStyle lineStyle;
+ CDrawMode drawMode;
+ CRect clipRect;
+
+#if MOTIF
+ XFontStruct *pFontInfoStruct;
+#endif
+};
+
+
+//-----------------------------------------------------------------------------
+// COffscreenContext Declaration
+//! A drawing device which uses a pixmap as its drawing surface.
+//-----------------------------------------------------------------------------
+class COffscreenContext : public CDrawContext
+{
+public:
+ COffscreenContext (CDrawContext *pContext, CBitmap *pBitmap, bool drawInBitmap = false);
+ COffscreenContext (CFrame *pFrame, long width, long height, const CColor backgroundColor = kBlackCColor);
+
+ virtual ~COffscreenContext ();
+
+ void copyFrom (CDrawContext *pContext, CRect destRect, CPoint srcOffset = CPoint (0, 0)); ///< copy from offscreen to pContext
+ void copyTo (CDrawContext* pContext, CRect& srcRect, CPoint destOffset = CPoint (0, 0)); ///< copy to offscreen from pContext
+
+ inline CCoord getWidth () const { return width; }
+ inline CCoord getHeight () const { return height; }
+
+ //-------------------------------------------
+protected:
+ CBitmap *pBitmap;
+ CBitmap *pBitmapBg;
+ CCoord height;
+ CCoord width;
+ bool bDestroyPixmap;
+
+ CColor backgroundColor;
+
+#if MOTIF
+ Display *pXdisplay;
+#endif
+};
+
+
+//-----------------------------------------------------------------------------
+// CBitmap Declaration
+//! Encapsulates various platform depended kinds of bitmaps.
+//-----------------------------------------------------------------------------
+class CBitmap : public CReferenceCounter
+{
+public:
+ CBitmap (AEffGUIEditor& editor, const char* img_name); ///< Create from a filename
+ CBitmap (CFrame &frame, CCoord width, CCoord height); ///< Create a pixmap with a given size.
+ virtual ~CBitmap ();
+
+ virtual void draw (CDrawContext *pContext, CRect &rect, const CPoint &offset = CPoint (0, 0)); ///< Draw the pixmap using a given rect as output position and a given offset of its source pixmap.
+ virtual void drawTransparent (CDrawContext *pContext, CRect &rect, const CPoint &offset = CPoint (0, 0));
+ virtual void drawAlphaBlend (CDrawContext *pContext, CRect &rect, const CPoint &offset = CPoint (0, 0), unsigned char alpha = 128); ///< Same as CBitmap::draw except that it uses the alpha value to draw the bitmap alpha blended.
+
+ inline CCoord getWidth () const { return width; }
+ inline CCoord getHeight () const { return height; }
+
+ bool isLoaded () const;
+ void *getHandle () const;
+
+ void setTransparentColor (const CColor color);
+ CColor getTransparentColor () const { return transparentCColor; }
+ void setTransparencyMask (CDrawContext* pContext, const CPoint& offset = CPoint (0, 0));
+
+ void setNoAlpha (bool state) { noAlpha = state; }
+ bool getNoAlpha () const { return noAlpha; }
+
+ //-------------------------------------------
+protected:
+ CBitmap ();
+
+ virtual void dispose ();
+ virtual bool loadFromResource (long resourceID);
+ virtual bool loadFromPath (const void* platformPath); // platformPath is a C string
+
+ long resourceID;
+ CCoord width;
+ CCoord height;
+
+ CColor transparentCColor;
+ bool noAlpha;
+
+#if PNG
+ void *createPixmapFromPng (CDrawContext *pContext);
+ bool openPng (const char* path);
+ bool closePng ();
+ std::string pngPath;
+ png_structp pngRead;
+ png_infop pngInfo;
+ FILE* pngFp;
+#endif
+#if MOTIF
+ void *createPixmapFromXpm (CDrawContext *pContext);
+
+ char **ppDataXpm;
+ void *pHandle;
+ void *pMask;
+#endif
+};
+
+enum {
+ kMessageUnknown = 0,
+ kMessageNotified = 1
+};
+
+//-----------------------------------------------------------------------------
+// CView Declaration
+//-----------------------------------------------------------------------------
+class CView : public CReferenceCounter
+{
+public:
+ CView (const CRect &size);
+ virtual ~CView ();
+
+ virtual void draw (CDrawContext *pContext); ///< called if the view should draw itself
+ virtual void drawRect (CDrawContext *pContext, const CRect& updateRect) { draw (pContext); } ///< called if the view should draw itself
+ virtual bool checkUpdate (CRect& updateRect) const { return updateRect.rectOverlap (size); }
+ virtual void mouse (CDrawContext *pContext, CPoint &where, long buttons = -1); ///< called if a mouse click event occurs
+
+ virtual void setBackground (CBitmap *background); ///< set the background image of this view
+ virtual CBitmap *getBackground () const { return pBackground; } ///< get the background image of this view
+
+ virtual long onKeyDown (VstKeyCode& keyCode); ///< called if a key down event occurs and this view has focus
+ virtual long onKeyUp (VstKeyCode& keyCode); ///< called if a key up event occurs and this view has focus
+
+ virtual bool onWheel (CDrawContext *pContext, const CPoint &where, float distance); ///< called if a mouse wheel event is happening over this view
+ virtual bool onWheel (CDrawContext *pContext, const CPoint &where, const CMouseWheelAxis axis, float distance); ///< called if a mouse wheel event is happening over this view
+
+ virtual bool onDrop (CDrawContext* context, CDragContainer* drag, const CPoint& where) { return false; } ///< called if a drag is dropped onto this view
+ virtual void onDragEnter (CDrawContext* context, CDragContainer* drag, const CPoint& where) {} ///< called if a drag is entering this view
+ virtual void onDragLeave (CDrawContext* context, CDragContainer* drag, const CPoint& where) {} ///< called if a drag is leaving this view
+ virtual void onDragMove (CDrawContext* context, CDragContainer* drag, const CPoint& where) {} ///< called if a drag is current moved over this view
+
+ virtual void looseFocus (CDrawContext *pContext = 0); ///< called if view should loose focus
+ virtual void takeFocus (CDrawContext *pContext = 0); ///< called if view should take focus
+
+ virtual bool isDirty () const { return bDirty; } ///< check if view is dirty
+ virtual void setDirty (const bool val = true) { bDirty = val; } ///< set the view to dirty so that it is redrawn in the next idle. Thread Safe !
+
+ virtual bool isVisible () const { return bVisible; } ///< check if view is dirty
+ virtual void setVisible (const bool val = true) { bVisible = val; } ///< set the view to dirty so that it is redrawn in the next idle. Thread Safe !
+
+ virtual void setMouseEnabled (const bool bEnable = true) { bMouseEnabled = bEnable; } ///< turn on/off mouse usage for this view
+ virtual bool getMouseEnabled () const { return bMouseEnabled; } ///< get the state of wheather this view uses the mouse or not
+
+ virtual void setMouseableArea (const CRect &rect) { mouseableArea = rect; } ///< set the area in which the view reacts to the mouse
+ virtual CRect &getMouseableArea (CRect &rect) const { rect = mouseableArea; return rect;} ///< get the area in which the view reacts to the mouse
+
+ virtual bool hitTest (const CPoint& where, const long buttons = -1) { return where.isInside (mouseableArea); } ///< check if where hits this view
+
+ virtual void setTransparency (bool val) { bTransparencyEnabled = val; } ///< set views transparent state
+ virtual bool getTransparency () const { return bTransparencyEnabled; } ///< is view transparent ?
+
+ CCoord getHeight () const { return size.height (); } ///< get the height of the view
+ CCoord getWidth () const { return size.width (); } ///< get the width of the view
+
+ virtual void setViewSize (CRect &rect); ///< set views size
+ virtual CRect &getViewSize (CRect &rect) const { rect = size; return rect; } ///< returns the current view size
+ virtual const CRect &getViewSize () const { return size; } ///< returns the current view size
+
+ virtual bool removed (CView* parent) { return true; } ///< view is removed from parent view
+ virtual bool attached (CView* view) { return true; } ///< view is attached to a parent view
+
+ virtual void getMouseLocation (CDrawContext* context, CPoint &point); ///< get current mouse location in local view coordinates
+
+ virtual CPoint& frameToLocal (CPoint& point) const; ///< conversion from frame coordinates to local view coordinates
+ virtual CPoint& localToFrame (CPoint& point) const; ///< conversion from local view coordinates to frame coordinates
+
+ bool getAttributeSize (const CViewAttributeID id, long& outSize) const; ///< get the size of an attribute
+ bool getAttribute (const CViewAttributeID id, const long inSize, void* outData, long& outSize) const; ///< get an attribute
+ bool setAttribute (const CViewAttributeID id, const long inSize, void* inData); ///< set an attribute
+
+ CView *getParentView () const { return pParentView; }
+ CFrame *getParent () const { return pParentFrame; }
+ CFrame *getFrame () const { return pParentFrame; }
+ virtual void *getEditor () const;
+
+ virtual long notify (CView* sender, const char* message);
+ void redraw ();
+ virtual void redrawRect (CDrawContext* context, const CRect& rect);
+
+ virtual bool wantsFocus () const { return bWantsFocus; } ///< check if view supports focus
+ virtual void setWantsFocus (bool state) { bWantsFocus = state; } ///< set focus support on/off
+
+#if DEBUG
+ virtual void dumpInfo ();
+#endif
+
+ virtual bool isTypeOf (const char* s) const
+ { return (!strcmp (s, "CView")); }
+
+ virtual void update (CDrawContext *pContext); // don't call this !!!
+
+ //-------------------------------------------
+protected:
+ friend class CControl;
+ friend class CFrame;
+ friend class CViewContainer;
+
+ CRect size;
+ CRect mouseableArea;
+
+ CFrame *pParentFrame;
+ CView *pParentView;
+
+ bool bDirty;
+ bool bMouseEnabled;
+ bool bTransparencyEnabled;
+ bool bWantsFocus;
+ bool bVisible;
+
+ CBitmap* pBackground;
+ CAttributeListEntry* pAttributeList;
+};
+
+// Message to check if View is a CViewContainer
+const extern char* kMsgCheckIfViewContainer;
+
+//-----------------------------------------------------------------------------
+// CViewContainer Declaration
+//! Container Class of CView objects.
+//-----------------------------------------------------------------------------
+class CViewContainer : public CView
+{
+public:
+ CViewContainer (const CRect &size, CFrame *pParent, CBitmap *pBackground = 0);
+ virtual ~CViewContainer ();
+
+ virtual void addView (CView *pView); ///< add a child view
+ virtual void addView (CView *pView, CRect &mouseableArea, bool mouseEnabled = true); ///< add a child view
+ virtual void removeView (CView *pView, const bool &withForget = true); ///< remove a child view
+ virtual void removeAll (const bool &withForget = true); ///< remove all child views
+ virtual bool isChild (CView *pView) const; ///< check if pView is a child view of this container
+ virtual long getNbViews () const; ///< get the number of child views
+ virtual CView *getView (long index) const; ///< get the child view at index
+
+ virtual void setBackgroundColor (const CColor color); ///< set the background color (will only be drawn if this container is not set to transparent and does not have a background bitmap)
+ virtual CColor getBackgroundColor () const { return backgroundColor; } ///< get the background color
+ virtual void setBackgroundOffset (const CPoint &p) { backgroundOffset = p; } ///< set the offset of the background bitmap
+ virtual const CPoint& getBackgroundOffset () const { return backgroundOffset; } ///< get the offset of the background bitmap
+
+ virtual void drawBackgroundRect (CDrawContext *pContext, CRect& _updateRect); ///< draw the background
+
+ enum {
+ kNormalUpdate = 0, ///< this mode redraws the whole container if something is dirty
+ kOnlyDirtyUpdate ///< this mode only redraws the views which are dirty
+ };
+
+ virtual void setMode (long val) { mode = val; } ///< set the update mode
+ virtual long getMode () const { return mode; } ///< get the update mode
+
+ virtual void useOffscreen (bool b); ///< turn on/off using an offscreen
+
+ virtual CView *getCurrentView () const; ///< get the current view under the mouse
+ virtual CView *getViewAt (const CPoint& where, bool deep = false) const; ///< get the view at point where
+
+ void modifyDrawContext (CCoord save[4], CDrawContext* pContext);
+ void restoreDrawContext (CDrawContext* pContext, CCoord save[4]);
+
+ // CView
+ virtual void draw (CDrawContext *pContext);
+ virtual void drawRect (CDrawContext *pContext, const CRect& updateRect);
+ virtual void mouse (CDrawContext *pContext, CPoint &where, long buttons = -1);
+ virtual bool onWheel (CDrawContext *pContext, const CPoint &where, float distance);
+ virtual bool onWheel (CDrawContext *pContext, const CPoint &where, const CMouseWheelAxis axis, float distance);
+ virtual void update (CDrawContext *pContext);
+ virtual bool hitTest (const CPoint& where, const long buttons = -1);
+ virtual long onKeyDown (VstKeyCode& keyCode);
+ virtual long onKeyUp (VstKeyCode& keyCode);
+ virtual long notify (CView* sender, const char* message);
+
+ virtual bool onDrop (CDrawContext* context, CDragContainer* drag, const CPoint& where);
+ virtual void onDragEnter (CDrawContext* context, CDragContainer* drag, const CPoint& where);
+ virtual void onDragLeave (CDrawContext* context, CDragContainer* drag, const CPoint& where);
+ virtual void onDragMove (CDrawContext* context, CDragContainer* drag, const CPoint& where);
+
+ virtual void looseFocus (CDrawContext *pContext = 0);
+ virtual void takeFocus (CDrawContext *pContext = 0);
+ virtual bool advanceNextFocusView (CView* oldFocus, bool reverse = false);
+
+ virtual bool isDirty () const;
+
+ virtual void setViewSize (CRect &rect);
+
+ virtual bool removed (CView* parent);
+ virtual bool attached (CView* view);
+
+ virtual CPoint& frameToLocal (CPoint& point) const;
+ virtual CPoint& localToFrame (CPoint& point) const;
+
+ virtual void redrawRect (CDrawContext* context, const CRect& rect);
+
+ CLASS_METHODS(CViewContainer, CView)
+
+#if DEBUG
+ virtual void dumpInfo ();
+ virtual void dumpHierarchy ();
+#endif
+
+ //-------------------------------------------
+protected:
+ bool hitTestSubViews (const CPoint& where, const long buttons = -1);
+
+ CCView *pFirstView;
+ CCView *pLastView;
+ long mode;
+ COffscreenContext *pOffscreenContext;
+ CColor backgroundColor;
+ CPoint backgroundOffset;
+ bool bDrawInOffscreen;
+
+ CView* currentDragView;
+};
+
+//-----------------------------------------------------------------------------
+// CFrame Declaration
+//! The CFrame is the parent container of all views.
+//-----------------------------------------------------------------------------
+class CFrame : public CViewContainer
+{
+public:
+ CFrame (const CRect &size, void *pSystemWindow, void *pEditor);
+
+ virtual ~CFrame ();
+
+ virtual bool open ();
+ virtual bool close ();
+ virtual bool isOpen () const { return bOpenFlag; }
+
+ virtual void idle ();
+ virtual void doIdleStuff ();
+
+ virtual unsigned long getTicks () const; ///< get the current time (in ms)
+ virtual long getKnobMode () const; ///< get hosts knob mode
+
+ virtual bool setPosition (CCoord x, CCoord y);
+ virtual bool getPosition (CCoord &x, CCoord &y) const;
+
+ virtual bool setSize (CCoord width, CCoord height);
+ virtual bool getSize (CRect *pSize) const;
+ virtual bool getSize (CRect &pSize) const;
+
+ virtual long setModalView (CView *pView);
+ virtual CView *getModalView () const { return pModalView; }
+
+ virtual void beginEdit (long index);
+ virtual void endEdit (long index);
+
+ virtual bool getCurrentLocation (CPoint &where);
+ virtual void setCursor (CCursorType type);
+
+ virtual void setFocusView (CView *pView);
+ virtual CView *getFocusView () const { return pFocusView; }
+ virtual bool advanceNextFocusView (CView* oldFocus, bool reverse = false);
+
+ virtual bool setDropActive (bool val);
+ virtual bool isDropActive () const { return bDropActive; };
+
+ CDrawContext* createDrawContext ();
+
+ virtual void setOpenFlag (bool val) { bOpenFlag = val;};
+ virtual bool getOpenFlag () const { return bOpenFlag; };
+
+ virtual void invalidate (const CRect &rect);
+
+ virtual bool updatesDisabled () const { return bUpdatesDisabled; }
+ virtual bool updatesDisabled (bool state) { bool before = bUpdatesDisabled; bUpdatesDisabled = state; return before; }
+
+ void *getSystemWindow () const { return (void*)pSystemWindow; }
+ void *getParentSystemWindow () const { return (void*)pSystemWindow; }
+ void setParentSystemWindow (void *val) { pSystemWindow = (XdbeBackBuffer)val; }
+
+ // CView
+ virtual void draw (CDrawContext *pContext);
+ virtual void drawRect (CDrawContext *pContext, const CRect& updateRect);
+ virtual void draw (CView *pView = 0);
+ virtual void mouse (CDrawContext *pContext, CPoint &where, long buttons = -1);
+ virtual bool onWheel (CDrawContext *pContext, const CPoint &where, float distance);
+ virtual bool onWheel (CDrawContext *pContext, const CPoint &where, const CMouseWheelAxis axis, float distance);
+ virtual long onKeyDown (VstKeyCode& keyCode);
+ virtual long onKeyUp (VstKeyCode& keyCode);
+ virtual void update (CDrawContext *pContext);
+ virtual void setViewSize (CRect& inRect);
+ virtual CView *getCurrentView () const;
+
+ virtual void *getEditor () const { return pEditor; }
+
+#if MOTIF
+ Colormap getColormap () const { return colormap; }
+ Visual *getVisual () const { return pVisual; }
+ unsigned int getDepth () const { return depth; }
+ Window getWindow () const { return window; }
+ Drawable getBackBuffer () const { return backBuffer; }
+ void freeGc ();
+
+ Region region;
+
+ GC gc;
+ GC getGC () const { return gc; }
+#endif
+
+#if DEBUG
+ virtual void dumpHierarchy ();
+#endif
+
+ CLASS_METHODS(CFrame, CViewContainer)
+
+ //-------------------------------------------
+protected:
+ bool initFrame (void *pSystemWin);
+
+ void *pEditor;
+
+ CView *pModalView;
+ CView *pFocusView;
+
+ bool bFirstDraw;
+ bool bOpenFlag;
+ bool bDropActive;
+ bool bUpdatesDisabled;
+
+#if MOTIF
+ Colormap colormap;
+ Visual *pVisual;
+ Window window;
+ unsigned int depth;
+ XdbeBackBuffer backBuffer;
+ Window pSystemWindow;
+#endif
+
+ //-------------------------------------------
+private:
+ CDrawContext *pFrameContext;
+ bool bAddedWindow;
+ void *defaultCursor;
+};
+
+//-----------------------------------------------------------------------------
+// CDragContainer Declaration
+//-----------------------------------------------------------------------------
+class CDragContainer : public CReferenceCounter
+{
+public:
+ CDragContainer (void* platformDrag);
+ ~CDragContainer ();
+
+ void* first (long& size, long& type); ///< returns pointer on a char array if type is known
+ void* next (long& size, long& type); ///< returns pointer on a char array if type is known
+
+ long getType (long idx) const;
+ long getCount () const { return nbItems; }
+
+ enum {
+ kFile = 0,
+ kText,
+
+ kUnknown = -1
+ };
+
+protected:
+ void* platformDrag;
+ long nbItems;
+
+ long iterator;
+ void* lastItem;
+};
+
+//-----------------------------------------------------------------------------
+// CCView Declaration
+//-----------------------------------------------------------------------------
+class CCView
+{
+public:
+ CCView (CView *pView);
+ ~CCView ();
+
+ CView *pView;
+ CCView *pNext;
+ CCView *pPrevious;
+};
+
+} // namespace VSTGUI
+
+// include the control objects
+#ifndef __vstcontrols__
+#include "vstcontrols.h"
+#endif
+
+#ifndef USE_NAMESPACE
+using namespace VSTGUI;
+#endif
+
+#endif // __vstgui__
diff --git a/vstgui/vstkeycode.h b/vstgui/vstkeycode.h
new file mode 100644
index 0000000..1eba98c
--- /dev/null
+++ b/vstgui/vstkeycode.h
@@ -0,0 +1,104 @@
+/* ----------------------------------------------------------------------------
+ * VSTGUI for X11/LV2/PNG
+ * Author: Dave Robillard
+ * Released under the revised BSD license, as below
+ * ----------------------------------------------------------------------------
+ *
+ * Based on:
+ * ----------------------------------------------------------------------------
+ * VST Plug-Ins SDK Linux ONLY Port
+ * VSTGUIL: Graphical User Interface Framework for VST plugins on LINUX
+ * Version: 0.1, Date: 2007/01/21
+ * Author: kRAkEn/gORe
+ * ----------------------------------------------------------------------------
+ */
+
+#ifndef __vstkeycode__
+#define __vstkeycode__
+
+
+/** Structure and enum used for keyUp/keyDown */
+struct VstKeyCode
+{
+ long character;
+ unsigned char virt; ///< see enum VstVirtualKey
+ unsigned char modifier; ///< see enum VstModifierKey
+};
+
+
+/** Used by member virt of VstKeyCode */
+enum VstVirtualKey
+{
+ VKEY_BACK = 1,
+ VKEY_TAB,
+ VKEY_CLEAR,
+ VKEY_RETURN,
+ VKEY_PAUSE,
+ VKEY_ESCAPE,
+ VKEY_SPACE,
+ VKEY_NEXT,
+ VKEY_END,
+ VKEY_HOME,
+
+ VKEY_LEFT,
+ VKEY_UP,
+ VKEY_RIGHT,
+ VKEY_DOWN,
+ VKEY_PAGEUP,
+ VKEY_PAGEDOWN,
+
+ VKEY_SELECT,
+ VKEY_PRINT,
+ VKEY_ENTER,
+ VKEY_SNAPSHOT,
+ VKEY_INSERT,
+ VKEY_DELETE,
+ VKEY_HELP,
+ VKEY_NUMPAD0,
+ VKEY_NUMPAD1,
+ VKEY_NUMPAD2,
+ VKEY_NUMPAD3,
+ VKEY_NUMPAD4,
+ VKEY_NUMPAD5,
+ VKEY_NUMPAD6,
+ VKEY_NUMPAD7,
+ VKEY_NUMPAD8,
+ VKEY_NUMPAD9,
+ VKEY_MULTIPLY,
+ VKEY_ADD,
+ VKEY_SEPARATOR,
+ VKEY_SUBTRACT,
+ VKEY_DECIMAL,
+ VKEY_DIVIDE,
+ VKEY_F1,
+ VKEY_F2,
+ VKEY_F3,
+ VKEY_F4,
+ VKEY_F5,
+ VKEY_F6,
+ VKEY_F7,
+ VKEY_F8,
+ VKEY_F9,
+ VKEY_F10,
+ VKEY_F11,
+ VKEY_F12,
+ VKEY_NUMLOCK,
+ VKEY_SCROLL,
+
+ VKEY_SHIFT,
+ VKEY_CONTROL,
+ VKEY_ALT,
+
+ VKEY_EQUALS
+};
+
+/** Used by member modifier of VstKeyCode */
+enum VstModifierKey
+{
+ MODIFIER_SHIFT = 1<<0, ///< Shift
+ MODIFIER_ALTERNATE = 1<<1, ///< Alt
+ MODIFIER_COMMAND = 1<<2, ///< Control on Mac
+ MODIFIER_CONTROL = 1<<3 ///< Ctrl on PC, Apple on Mac
+};
+
+#endif