Browse Source

add SubmarineUtility modules

pull/1639/head
bsp2 6 years ago
parent
commit
f179d15487
40 changed files with 3212 additions and 1 deletions
  1. +2
    -1
      plugins/community/repos/SubmarineFree/src/SubmarineFree.cpp
  2. +7
    -0
      plugins/community/repos/SubmarineUtility/.gitignore
  3. +29
    -0
      plugins/community/repos/SubmarineUtility/LICENSE
  4. +28
    -0
      plugins/community/repos/SubmarineUtility/Makefile
  5. +19
    -0
      plugins/community/repos/SubmarineUtility/README.md
  6. +5
    -0
      plugins/community/repos/SubmarineUtility/make.objects
  7. +7
    -0
      plugins/community/repos/SubmarineUtility/makefile.linux
  8. +7
    -0
      plugins/community/repos/SubmarineUtility/makefile.msvc
  9. +14
    -0
      plugins/community/repos/SubmarineUtility/manual/index.md
  10. +71
    -0
      plugins/community/repos/SubmarineUtility/manual/modbrowser.md
  11. +83
    -0
      plugins/community/repos/SubmarineUtility/manual/wiremanager.md
  12. +17
    -0
      plugins/community/repos/SubmarineUtility/res/Sub1.svg
  13. +15
    -0
      plugins/community/repos/SubmarineUtility/res/Sub2.svg
  14. +28
    -0
      plugins/community/repos/SubmarineUtility/res/colors.svg
  15. +44
    -0
      plugins/community/repos/SubmarineUtility/res/favorite.svg
  16. +35
    -0
      plugins/community/repos/SubmarineUtility/res/hls.svg
  17. +39
    -0
      plugins/community/repos/SubmarineUtility/res/load.svg
  18. +33
    -0
      plugins/community/repos/SubmarineUtility/res/min.svg
  19. +35
    -0
      plugins/community/repos/SubmarineUtility/res/plugin.svg
  20. +34
    -0
      plugins/community/repos/SubmarineUtility/res/tag.svg
  21. +721
    -0
      plugins/community/repos/SubmarineUtility/src/ModBrowser.cpp
  22. +335
    -0
      plugins/community/repos/SubmarineUtility/src/SubControls.cpp
  23. +225
    -0
      plugins/community/repos/SubmarineUtility/src/SubControls.hpp
  24. +14
    -0
      plugins/community/repos/SubmarineUtility/src/SubmarineUtility.cpp
  25. +9
    -0
      plugins/community/repos/SubmarineUtility/src/SubmarineUtility.hpp
  26. +1023
    -0
      plugins/community/repos/SubmarineUtility/src/WireManager.cpp
  27. +2
    -0
      plugins/makefile.common
  28. +2
    -0
      src/plugin_static.cpp
  29. +29
    -0
      vst2_bin/plugins/SubmarineUtility/LICENSE
  30. +19
    -0
      vst2_bin/plugins/SubmarineUtility/README.md
  31. +17
    -0
      vst2_bin/plugins/SubmarineUtility/res/Sub1.svg
  32. +15
    -0
      vst2_bin/plugins/SubmarineUtility/res/Sub2.svg
  33. +28
    -0
      vst2_bin/plugins/SubmarineUtility/res/colors.svg
  34. +44
    -0
      vst2_bin/plugins/SubmarineUtility/res/favorite.svg
  35. +35
    -0
      vst2_bin/plugins/SubmarineUtility/res/hls.svg
  36. +39
    -0
      vst2_bin/plugins/SubmarineUtility/res/load.svg
  37. +33
    -0
      vst2_bin/plugins/SubmarineUtility/res/min.svg
  38. +35
    -0
      vst2_bin/plugins/SubmarineUtility/res/plugin.svg
  39. +34
    -0
      vst2_bin/plugins/SubmarineUtility/res/tag.svg
  40. +1
    -0
      vst2_common_staticlibs.mk

+ 2
- 1
plugins/community/repos/SubmarineFree/src/SubmarineFree.cpp View File

@@ -76,7 +76,8 @@ RACK_PLUGIN_MODEL_DECLARE(SubmarineFree, BP132);
RACK_PLUGIN_INIT(SubmarineFree) {
RACK_PLUGIN_INIT_ID();
RACK_PLUGIN_INIT_VERSION("0.6.8");
// https://github.com/david-c14/SubmarineFree
RACK_PLUGIN_INIT_WEBSITE("https://github.com/david-c14/SubmarineFree");
RACK_PLUGIN_INIT_MANUAL("https://github.com/david-c14/SubmarineFree");

// Add all Models defined throughout the plugin
RACK_PLUGIN_MODEL_ADD(SubmarineFree, AG104);


+ 7
- 0
plugins/community/repos/SubmarineUtility/.gitignore View File

@@ -0,0 +1,7 @@
/build
/dist
/plugin.dylib
/plugin.dll
/plugin.so
.DS_Store
/WK_Custom.tunings

+ 29
- 0
plugins/community/repos/SubmarineUtility/LICENSE View File

@@ -0,0 +1,29 @@
BSD 3-Clause License

Copyright (c) 2018, David O'Rourke
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 copyright holder 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 HOLDER 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.

+ 28
- 0
plugins/community/repos/SubmarineUtility/Makefile View File

@@ -0,0 +1,28 @@
# Must follow the format in the Naming section of https://vcvrack.com/manual/PluginDevelopmentTutorial.html
SLUG = SubmarineUtility

# Must follow the format in the Versioning section of https://vcvrack.com/manual/PluginDevelopmentTutorial.html
VERSION = 0.6.2

# FLAGS will be passed to both the C and C++ compiler
FLAGS +=
CFLAGS +=
CXXFLAGS +=

# Careful about linking to shared libraries, since you can't assume much about the user's environment and library search path.
# Static libraries are fine.
LDFLAGS +=

# Add .cpp and .c files to the build
SOURCES += $(wildcard src/*.cpp)

# Add files to the ZIP package when running `make dist`
# The compiled plugin is automatically added.
DISTRIBUTABLES += $(wildcard LICENSE*) res

# If RACK_DIR is not defined when calling the Makefile, default to two levels above
RACK_DIR ?= ../..

# Include the VCV Rack plugin Makefile framework
include $(RACK_DIR)/plugin.mk


+ 19
- 0
plugins/community/repos/SubmarineUtility/README.md View File

@@ -0,0 +1,19 @@
# SubmarineUtility
Utility Modules for VCVRack

Important note:

These modules rely on knowledge of VCVRack which goes beyond the published API. The ongoing stability of the code is therefore not guaranteed. At least some of the features of these modules rely on code which is expected to change in future versions of VCVRack, and many other parts are likely to change.

Whilst I intend to try to keep these modules up to date with changes, I can make no guarantees that this will even be possible.

**Module Browser will definitely need to be somewhat rewritten for VCVRack v1.0. It is my intention to do so as soon as possible.**

However, these modules are not designed or intended to form any part of your patch behaviour. They are intended purely as workflow tools. If these modules become incompatible with VCVRack in the future, it should be possible to remove them from the patch without affecting the aural content of the patch.

## [Manual](https://github.com/david-c14/SubmarineUtility/blob/master/manual/index.md)

## Licence

This code is licensed under BSD 3-clause and is mostly copyright © 2018 carbon14 (David O'Rourke) 2018
Some parts of this code are inevitably based directly on code by Andrew Belt within VCVRack itself; Copyright © 2016 Andrew Belt.

+ 5
- 0
plugins/community/repos/SubmarineUtility/make.objects View File

@@ -0,0 +1,5 @@
ALL_OBJ= \
src/ModBrowser.o \
src/SubControls.o \
src/SubmarineUtility.o \
src/WireManager.o

+ 7
- 0
plugins/community/repos/SubmarineUtility/makefile.linux View File

@@ -0,0 +1,7 @@
SLUG=SubmarineUtility

include ../../../build_plugin_pre_linux.mk

include make.objects

include ../../../build_plugin_post_linux.mk

+ 7
- 0
plugins/community/repos/SubmarineUtility/makefile.msvc View File

@@ -0,0 +1,7 @@
SLUG=SubmarineUtility

include ../../../build_plugin_pre_msvc.mk

include make.objects

include ../../../build_plugin_post_msvc.mk

+ 14
- 0
plugins/community/repos/SubmarineUtility/manual/index.md View File

@@ -0,0 +1,14 @@
# Submarine Utilities

Important note:

These modules rely on knowledge of VCVRack which goes beyond the published API. The ongoing stability of the code is therefore not guaranteed. At least some of the features of these modules rely on code which is expected to change in future versions of VCVRack, and many other parts are likely to change.

Whilst I intend to try to keep these modules up to date with changes, I can make no guarantees that this will even be possible.

**Module Browser will definitely need to be somewhat rewritten for VCVRack v1.0. It is my intention to do so as soon as possible.**

However, these modules are not designed or intended to form any part of your patch behaviour. They are intended purely as workflow tools. If these modules become incompatible with VCVRack in the future, it should be possible to remove them from the patch without affecting the aural content of the patch.

## [Module Browser](modbrowser.md)
## [Wire Manager](wiremanager.md)

+ 71
- 0
plugins/community/repos/SubmarineUtility/manual/modbrowser.md View File

@@ -0,0 +1,71 @@
# Module Browser

The module browser offers an alternative to the built in module browser within VCVRack. It has some weaknesses compared to the built-in browser
but at the same time offers some distinct advantages. Both browsers can be used at the same time.

## Creating Modules

The first three icons allow you to browse for modules by Author, Tag or from the list of Favorites. Use the icon to select the list you require.

### ![](../res/plugin.svg) Authors.

Select an author to be shown a list of the modules available from that author. To go back either select the Authors icon again, or select
the 'Back' option at the top of the list.

Clicking on a module will cause that module to be added to your patch. The module will be added into empty space as close as possible to the
module browser.

Alternatively you can drag a module from the module browser to anywhere on your patch. The module will be added into empty space as close as possible
to where you tried to drop it.

### ![](../res/tag.svg) Tags

Select a tag to be shown a list of the modules which offer that functionality. To go back either select the Tags icon again, or select
the 'Back' option at the top of the list.

Clicking on a module will cause that module to be added to your patch. The module will be added into empty space as close as possible to the
module browser.

Alternatively you can drag a module from the module browser to anywhere on your patch. The module will be added into empty space as close as possible
to where you tried to drop it.

### ![](../res/favorite.svg) Favorites

The favorites list is loaded from your settings file. As a result it is normally only updated when you quit VCVRack. Favorites changed during a patching session will not show up in the module browser until the next time that you start VCVRack.

Clicking on a module will cause that module to be added to your patch. The module will be added into empty space as close as possible to the
module browser.

Alternatively you can drag a module from the module browser to anywhere on your patch. The module will be added into empty space as close as possible
to where you tried to drop it.

## ![](../res/load.svg) Loading Patches

The Disk icon will open up a dialog box allowing you to select either a patch or a preset file.

### Patch Files

Loading a patch file will cause all the modules in the patch to be imported into your current patch. Everything already in your patch will remain.

The loaded modules will be grouped together in their original arrangement, but placed into your patch somewhere where there is sufficient space for the whole arrangement. All the settings and wiring from your patch will be set-up also. This is an ideal tool for
building a library of signal chains that you pick and choose from to construct more complex patches.

### Preset Files

Loading a preset file will add a new module from into your patch. It will also be configured with the settings of the preset. This can be quicker than manually adding the module and then opening the preset from within the module to configure it.

## Sizing

### ![](../res/min.svg) Minimize

The Minimize icon will shrink the size of the module browser down to 1-HP. All the modules in the patch to the right of the module browser will be move to the left to take up the space.

When the module browser is minimized, a Restore button is visible in the centre of the module. Selecting this will restore the module to its previous size. All modules to the right of the module browser will be moved to the right to make space.

In this way you can keep the module browser in your patch for ready access, without taking up more space than is necessary.

When the module browser is in its open state, a drag handle at the right-hand edge can be used to make the module wider or narrower.

### Zooming

The scrolling list in the module browser is designed to remain readable. If you zoom in, the items in the list will increase in size as you might expect, but if you zoom out to less than 100% the items in the list will remain the same size on the screen to ensure that they remain visible.

+ 83
- 0
plugins/community/repos/SubmarineUtility/manual/wiremanager.md View File

@@ -0,0 +1,83 @@
# Wire Manager

The wire manager offers the ability to choose more colors for the patch cables that you use in your patches. It also has highlighting options
which some users may find useful in tracing wires around the patch.

## ![](../res/colors.svg) Colors

The colors page of the wire manager offers a list of different colored wires. To the left of each wire is a checkbox. When you make a new connection
in VCVRack, a color for that wire is chosen from the list of wires that are checked. The list is cycled, so if you select only Red, Yellow and Green
wires in the wire manager, the first wire you add to your patch will be Red, the next Yellow, the third Green and then back to Red.

If you wish to connect all of the right channel of a stereo signal in Red, you might choose to select only the Red wire in the wire manager, and
then to wire up the entire right channel signal chain. Then change to a Dark Grey wire to wire the left hand signal chain.

Or perhaps you just want all of the wires to be pink to celebrate Valentine's Day.

The top-most checkbox in the list allows you to select / deselect all the colors.

At the top of the list on the right hand side is a plus icon. This will take you to the editing page to create a new wire color which will
be placed an the bottom of the list when you save it.

To the right of each color are some more icons. These allow you to move your colored wires up or down the list to choose the order of them, and
the three dots icon takes you to an editing page where you can change the color of the wire. This editing page also has the option to
delete the wire.

### Editing

On the editing page there are save and cancel buttons, and a delete button (which will offer you a further chance to change your mind).

There are three sliders here to adjust the color of the wire. Although they are not deliberately not labelled, the sliders control the Red, Green and Blue
parts of the color. Each slider has a gradient background accurately showing the colors that will result from moving that slider.

Right-clicking on any slider will return it to it's unedited position.

## ![](../res/hls.svg) Settings.

The settings page currently has two functions.

### Variation

When the variation option is enabled, the color chosen for your wire is randomly varied. You might wish to use all green wires for a patch,
but if this option is enabled, you can have lots of slightly different green wires, emulating a collection of patch cables acquired over a
long and happy period of modular experimentation.

The three sliders allow you to fine tune the type of variation introduced.

H: is the hue or actual color of the wire

L: is the lightness of the wire, from a deep dark red, to a light pale pink for example

S: is the saturation of the wire, how deep the color is. Wires with a low saturation will appear more gray.

### Highlighting

When the highlighting option is selected, an additional transparency is added to the wires in the patch. When you hover over a
module in the patch, only those wires connected to that module will be shown with normal opacity. This may help you to trace pathways
in complex patches. You can quickly point to a module and see where each wire goes.

There are two highlighting options, they differ in what happens when you are not pointing at a module, when you are pointing at empty space in the
rack. *Always On* will still fade all the wires when you are not hovering over any module; *When Hovering* will only fade wires away when you
are pointing at something.

## Sizing

### ![](../res/min.svg) Minimize

The Minimize icon will shrink the size of the module browser down to 1-HP. All the modules in the patch to the right of the module browser will be move to the left to take up the space.

When the module browser is minimized, a Restore button is visible in the centre of the module. Selecting this will restore the module to its previous size. All modules to the right of the module browser will be moved to the right to make space.

In this way you can keep the module browser in your patch for ready access, without taking up more space than is necessary.

## Saving.

Once the wires have been connected in your patch, you do not need to keep the wire manager around. You can minimize it to save space, but if
you remove it from the patch completely, the wires will still retain their colors. Highlighting will not function without the wire
manager in the patch.

The settings that you make are global. They are not saved along with the patch, so your favorite collection of colored wires is available in
every patch that you add wire manager to.

Do not add more than one wire manager to your patch. It will do no harm, but only one of them will be actually selecting the colors and the
other will be wasting CPU.

+ 17
- 0
plugins/community/repos/SubmarineUtility/res/Sub1.svg View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
height="15px"
width="20px">
<g
style="font-size:12px;font-family:'DejaVu Sans';fill:#719fcf"
font-size="12"
id="logo">
<path
id="path4136"
d="M 9.35391,1 A 1.9846094,2.2519786 0 0 0 7.36926,3.25192 1.9846094,2.2519786 0 0 0 7.42806,3.78359 8.1692063,5.1693144 0 0 0 1,8.83071 8.1692063,5.1693144 0 0 0 9.16915,14 8.1692063,5.1693144 0 0 0 16.48278,11.11985 3.0461447,4.2480502 0 0 0 19,12.97641 l 0,-2.35772 A 1.3384576,1.9448905 0 0 1 17.7077,8.67718 1.3384576,1.9448905 0 0 1 19,6.73455 L 19,4.48039 A 3.0461447,4.2480502 0 0 0 16.42587,6.45983 8.1692063,5.1693144 0 0 0 9.16915,3.66141 8.1692063,5.1693144 0 0 0 8.79597,3.67331 1.7538409,2.0472531 0 0 1 9.49235,2.67169 l 0,-1.66609 A 1.9846094,2.2519786 0 0 0 9.35391,1 Z M 6.07684,6.83461 A 1.6615335,1.8425278 0 0 1 7.7384,8.67718 1.6615335,1.8425278 0 0 1 6.07684,10.51975 1.6615335,1.8425278 0 0 1 4.41539,8.67718 1.6615335,1.8425278 0 0 1 6.07684,6.83461 Z M 9.86149,7.2441 A 1.2923038,1.4330772 0 0 1 11.1538,8.67718 1.2923038,1.4330772 0 0 1 9.86149,10.11026 1.2923038,1.4330772 0 0 1 8.56919,8.67718 1.2923038,1.4330772 0 0 1 9.86149,7.2441 Z m 3.00928,0.38892 A 0.92307415,1.0236265 0 0 1 13.79381,8.65675 0.92307415,1.0236265 0 0 1 12.87077,9.68034 0.92307415,1.0236265 0 0 1 11.9476,8.65675 0.92307415,1.0236265 0 0 1 12.87077,7.63302 Z"
inkscape:connector-curvature="0" />
</g>
</svg>

+ 15
- 0
plugins/community/repos/SubmarineUtility/res/Sub2.svg View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
height="20px"
width="15px">
<g
style="font-size:12px;font-family:'DejaVu Sans';fill:#719fcf"
font-size="12"
id="logo">
<path
id="path4136"
d="M 1,10.64609 A 2.2519786,1.9846094 0 0 0 3.25192,12.63074 2.2519786,1.9846094 0 0 0 3.78359,12.57194 5.1693144,8.1692063 0 0 0 8.83071,19 5.1693144,8.1692063 0 0 0 14,10.83085 5.1693144,8.1692063 0 0 0 11.11985,3.51722 4.2480502,3.0461447 0 0 0 12.97641,1 L 10.61869,1 A 1.9448905,1.3384576 0 0 1 8.67718,2.2923 1.9448905,1.3384576 0 0 1 6.73455,1 L 4.48039,1 a 4.2480502,3.0461447 0 0 0 1.97944,2.57413 5.1693144,8.1692063 0 0 0 -2.79842,7.25672 5.1693144,8.1692063 0 0 0 0.0119,0.37318 2.0472531,1.7538409 0 0 1 -1.00162,-0.69638 l -1.66609,0 A 2.2519786,1.9846094 0 0 0 1,10.64609 Z m 5.83461,3.27707 A 1.8425278,1.6615335 0 0 1 8.67718,12.2616 1.8425278,1.6615335 0 0 1 10.51975,13.92316 1.8425278,1.6615335 0 0 1 8.67718,15.58461 1.8425278,1.6615335 0 0 1 6.83461,13.92316 Z M 7.2441,10.13851 A 1.4330772,1.2923038 0 0 1 8.67718,8.8462 1.4330772,1.2923038 0 0 1 10.11026,10.13851 1.4330772,1.2923038 0 0 1 8.67718,11.43081 1.4330772,1.2923038 0 0 1 7.2441,10.13851 Z M 7.63302,7.12923 A 1.0236265,0.92307415 0 0 1 8.65675,6.20619 1.0236265,0.92307415 0 0 1 9.68034,7.12923 1.0236265,0.92307415 0 0 1 8.65675,8.0524 1.0236265,0.92307415 0 0 1 7.63302,7.12923 Z" />
</g>
</svg>

+ 28
- 0
plugins/community/repos/SubmarineUtility/res/colors.svg View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="30px"
height="30px"
version="1.1">
<g
inkscape:label="Background"
inkscape:groupmode="layer"
id="background">
<rect
x="0"
y="0"
width="30"
height="30"
rx="3"
ry="3"
style="fill:#404040;stroke:none;"
id="rect4255" />
</g>
<g>
<circle cx="9" cy="20" r="6" style="fill:#ff0000;" />
<circle cx="21" cy="20" r="6" style="fill:#0000ff;" />
<circle cx="15" cy="9.6" r="6" style="fill:#00ff00;" />
</g>
</svg>

+ 44
- 0
plugins/community/repos/SubmarineUtility/res/favorite.svg View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="30px"
height="30px"
version="1.1">
<g
inkscape:label="Background"
inkscape:groupmode="layer"
id="background">
<rect
x="0"
y="0"
width="30"
height="30"
rx="3"
ry="3"
style="fill:#404040;stroke:none;"
id="rect4255" />
</g>
<g
stroke="#ffffff"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2">
<path d="
M 15 2
L 20.878 7.91
L 28.315 11.6738
L 24.511 19.090
L 23.8168 27.3262
L 15 26
L 6.1832 27.3262
L 5.489 19.090
L 1.6852 11.6738
L 9.122 7.91
z

" />
</g>
</svg>

+ 35
- 0
plugins/community/repos/SubmarineUtility/res/hls.svg View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="30px"
height="30px"
version="1.1">
<g
inkscape:label="Background"
inkscape:groupmode="layer"
id="background">
<rect
x="0"
y="0"
width="30"
height="30"
rx="3"
ry="3"
style="fill:#404040;stroke:none;"
id="rect4255" />
</g>
<g
stroke="#ffffff"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2">
<path d="
M 3 6 h 24 m -20 0 m 0 -4 v 8
M 3 15 h 24 m -6 0 m 0 -4 v 8
M 3 24 h 24 m -13 0 m 0 -4 v 8
" />
</g>
</svg>

+ 39
- 0
plugins/community/repos/SubmarineUtility/res/load.svg View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="30px"
height="30px"
version="1.1">
<g
inkscape:label="Background"
inkscape:groupmode="layer"
id="background">
<rect
x="0"
y="0"
width="30"
height="30"
rx="3"
ry="3"
style="fill:#404040;stroke:none;"
id="rect4255" />
</g>
<g
stroke="#ffffff"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2">
<path d="
M 3 2 l 19 0 l 5 5 l 0 21 l -24 0 l 0 -26
M 8 2 l 0 10 l 13 0 l 0 -10
M 12 5 l 0 4
M 7 28 l 0 -12 l 16 0 l 0 12
M 10 24 l 6 0
M 10 21 l 9 0

" />
</g>
</svg>

+ 33
- 0
plugins/community/repos/SubmarineUtility/res/min.svg View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="30px"
height="30px"
version="1.1">
<g
inkscape:label="Background"
inkscape:groupmode="layer"
id="background">
<rect
x="0"
y="0"
width="30"
height="30"
rx="3"
ry="3"
style="fill:#404040;stroke:none;"
id="rect4255" />
</g>
<g
stroke="#ffffff"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2">
<path d="
M 21 3 l 0 24 l -14 -12 l 14 -12
" />
</g>
</svg>

+ 35
- 0
plugins/community/repos/SubmarineUtility/res/plugin.svg View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="30px"
height="30px"
version="1.1">
<g
inkscape:label="Background"
inkscape:groupmode="layer"
id="background">
<rect
x="0"
y="0"
width="30"
height="30"
rx="3"
ry="3"
style="fill:#404040;stroke:none;"
id="rect4255" />
</g>
<g
stroke="#ffffff"
fill="none"
stroke-linecap="round"
stroke-width="2">
<path d="M 3 27 l 6 -6
M 13 9 l -4 4 a 3 3 0 0 0 8 8 l 4 -4
M 12 8 l 10 10
M 15 11 l 5 -5
M 19 15 l 5 -5
" />
</g>
</svg>

+ 34
- 0
plugins/community/repos/SubmarineUtility/res/tag.svg View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="30px"
height="30px"
version="1.1">
<g
inkscape:label="Background"
inkscape:groupmode="layer"
id="background">
<rect
x="0"
y="0"
width="30"
height="30"
rx="3"
ry="3"
style="fill:#404040;stroke:none;"
id="rect4255" />
</g>
<g
stroke="#ffffff"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2">
<path d="
M 3 3 l 10 0 l 14 14 l -10 10 l -14 -14 z
" />
<circle cx="9" cy="9" r="2.5" />
</g>
</svg>

+ 721
- 0
plugins/community/repos/SubmarineUtility/src/ModBrowser.cpp View File

@@ -0,0 +1,721 @@
#include "SubControls.hpp"
#include <map>
#include <algorithm>
#include "global_pre.hpp"
#include "global_ui.hpp"
#include "app.hpp"
#include "window.hpp"
#include "osdialog.h"
#include "util/common.hpp"

namespace rack_plugin_SubmarineUtility {

struct ModBrowserWidget;

struct ListElement {
ModBrowserWidget *mbw;
virtual void onAction(EventAction &e) { debug ("Not Implemented"); }
virtual std::string GetLabelOne() { return std::string("Label 1"); };
virtual std::string GetLabelTwo() { return std::string("Label 2"); };
};

struct TextButton : SubControls::ButtonBase {
std::string label1;
std::string label2;
std::shared_ptr<ListElement> element;
float label1Width = 0;
float label2Width = 0;
void CalculateSizes(NVGcontext *vg, float zoom) {
nvgFontFaceId(vg, rack::global_ui->window.gGuiFont->handle);
nvgFontSize(vg, 13 * zoom);
float bounds[4];
nvgTextBounds(vg, zoom, box.size.y / 2, label1.c_str(), NULL, bounds);
label1Width = bounds[2] - bounds[0];
nvgTextBounds(vg, zoom, box.size.y / 2, label2.c_str(), NULL, bounds);
label2Width = bounds[2] - bounds[0];
}
void draw (NVGcontext *vg) override {
float zoom = 1.0f / clamp(RACK_PLUGIN_UI_RACKSCENE->zoomWidget->zoom, 0.25f, 1.0f);
//if (label1Width == 0.0f)
CalculateSizes(vg, zoom);
if (RACK_PLUGIN_UI_DRAGGED_WIDGET == this) {
nvgBeginPath(vg);
nvgRect(vg, 0, 0, box.size.x - 2, box.size.y);
nvgFillColor(vg, nvgRGB(0x40, 0x40, 0x40));
nvgFill(vg);
}
nvgFontFaceId(vg, rack::global_ui->window.gGuiFont->handle);
nvgFontSize(vg, 13 * zoom);
// Draw secondary text
nvgFillColor(vg, nvgRGB(0x80, 0x80, 0x80));
nvgTextAlign(vg, NVG_ALIGN_MIDDLE | NVG_ALIGN_RIGHT);
nvgText(vg, box.size.x - zoom, box.size.y / 2, label2.c_str(), NULL);
// If text overlaps, feather out overlap
if (label1Width + label2Width > box.size.x) {
NVGpaint grad;
if (RACK_PLUGIN_UI_DRAGGED_WIDGET == this) {
nvgFillColor(vg, nvgRGB(0x40, 0x40, 0x40));
grad = nvgLinearGradient(vg, label1Width, 0, label1Width + 10, 0, nvgRGBA(0x20, 0x20, 0x20, 0xff), nvgRGBA(0x20, 0x20, 0x20, 0));
}
else {
nvgFillColor(vg, nvgRGB(0, 0, 0));
grad = nvgLinearGradient(vg, label1Width, 0, label1Width + 10, 0, nvgRGBA(0, 0, 0, 0xff), nvgRGBA(0, 0, 0, 0));
}
nvgBeginPath(vg);
nvgRect(vg, box.size.x - label2Width, 0, label1Width - box.size.x + label2Width, box.size.y);
nvgFill(vg);
nvgBeginPath(vg);
nvgRect(vg, label1Width, 0, 10, box.size.y);
nvgFillPaint(vg, grad);
nvgFill(vg);
}
// Draw primary text
nvgFillColor(vg, nvgRGB(0xff, 0xff, 0xff));
nvgTextAlign(vg, NVG_ALIGN_MIDDLE);
nvgText(vg, zoom, box.size.y / 2, label1.c_str(), NULL);
Component::draw(vg);
}
void GetLabels() {
label1 = element->GetLabelOne();
label2 = element->GetLabelTwo();
}
void onAction(EventAction &e) override {
element->onAction(e);
}
};

// Icons


struct MBIconWidget : SubControls::ButtonBase,SVGWidget {
ModBrowserWidget *mbw;
};

struct PluginIcon : MBIconWidget {
int selected = 0;
PluginIcon() {
box.size.x = 30;
box.size.y = 30;
}
void onAction(EventAction &e) override;
};

struct TagIcon : MBIconWidget {
int selected = 0;
TagIcon() {
box.size.x = 30;
box.size.y = 30;
}
void onAction(EventAction &e) override;
};

struct FavIcon : MBIconWidget {
int selected = 0;
FavIcon() {
box.size.x = 30;
box.size.y = 30;
}
void onAction(EventAction &e) override;
};

struct LoadIcon : MBIconWidget {
int selected = 0;
LoadIcon() {
box.size.x = 30;
box.size.y = 30;
}
void onAction(EventAction &e) override;
};

struct MinimizeIcon : MBIconWidget {
MinimizeIcon() {
box.size.x = 30;
box.size.y = 30;
}
void onAction(EventAction &e) override;
};

// Elements

struct ModelElement : ListElement {
Model *model;
std::string GetLabelOne() override {
return model->name;
}
std::string GetLabelTwo() override {
#undef plugin
return model->plugin->slug;
#define plugin "SubmarineUtility"
}
void onAction(EventAction &e) override;
};

struct PluginElement : ListElement {
std::string label;
std::string GetLabelOne() override {
return label;
}
std::string GetLabelTwo() override;
void onAction(EventAction &e) override;
};

struct TagElement : ListElement {
unsigned int tag;
std::string GetLabelOne() override {
return gTagNames[tag];
}
std::string GetLabelTwo() override;
void onAction(EventAction &e) override;
};

struct PluginBackElement : ListElement {
std::string label2;
std::string GetLabelOne() override {
return std::string("\xe2\x86\x90 Back");
}
std::string GetLabelTwo() override {
return label2;
}
void onAction(EventAction &e) override;
};

struct TagBackElement : ListElement {
std::string label2;
std::string GetLabelOne() override {
return std::string("\xe2\x86\x90 Back");
}
std::string GetLabelTwo() override {
return label2;
}
void onAction(EventAction &e) override;
};

struct ModBrowserWidget : SubControls::SizeableModuleWidget {
Widget *scrollContainer;
ScrollWidget *scrollWidget;
PluginIcon *pluginIcon;
TagIcon *tagIcon;
FavIcon *favIcon;
LoadIcon *loadIcon;
MinimizeIcon *minimizeIcon;
float width;
float zoom = 1.0f;
std::list<std::shared_ptr<PluginElement>> pluginList;
std::list<std::shared_ptr<TagElement>> tagList;
std::list<std::shared_ptr<ModelElement>> modelList;
std::string allfilters;
std::string lastPath;
ModBrowserWidget(Module *module) : SubControls::SizeableModuleWidget(module) {
moduleName = "Module Browser";
zoom = clamp(RACK_PLUGIN_UI_RACKSCENE->zoomWidget->zoom, 0.25f, 1.0f);
allfilters.assign(PATCH_FILTERS);
allfilters.append(";");
allfilters.append(PRESET_FILTERS);

pluginIcon = Widget::create<PluginIcon>(Vec(2, 2));
pluginIcon->selected = 1;
pluginIcon->mbw = this;
pluginIcon->setSVG(SVG::load(assetPlugin(plugin, "res/plugin.svg")));
backPanel->addChild(pluginIcon);

tagIcon = Widget::create<TagIcon>(Vec(34, 2));
tagIcon->mbw = this;
tagIcon->setSVG(SVG::load(assetPlugin(plugin, "res/tag.svg")));
backPanel->addChild(tagIcon);

favIcon = Widget::create<FavIcon>(Vec(66, 2));
favIcon->mbw = this;
favIcon->setSVG(SVG::load(assetPlugin(plugin, "res/favorite.svg")));
backPanel->addChild(favIcon);
loadIcon = Widget::create<LoadIcon>(Vec(98, 2));
loadIcon->mbw = this;
loadIcon->setSVG(SVG::load(assetPlugin(plugin, "res/load.svg")));
backPanel->addChild(loadIcon);
minimizeIcon = Widget::create<MinimizeIcon>(Vec(130, 2));
minimizeIcon->mbw = this;
minimizeIcon->setSVG(SVG::load(assetPlugin(plugin, "res/min.svg")));
backPanel->addChild(minimizeIcon);

scrollWidget = Widget::create<ScrollWidget>(Vec(0, 35));
scrollWidget->box.size.x = box.size.x - 20;
scrollWidget->box.size.y = box.size.y - 65;
width = scrollWidget->box.size.x - 20;
backPanel->addChild(scrollWidget);

scrollContainer = scrollWidget->container;
for (unsigned int i = 1; i < NUM_TAGS; i++) {
std::shared_ptr<TagElement> te = std::make_shared<TagElement>();
te->mbw = this;
te->tag = i;
tagList.push_back(te);
}
// Sort Tags (probably already sorted)
tagList.sort([](std::shared_ptr<TagElement> te1, std::shared_ptr<TagElement> te2) { return gTagNames[te1->tag].compare(gTagNames[te2->tag]) < 0; } );

#undef plugin
for (Plugin *plugin : rack::global->plugin.gPlugins) {
for (Model *model : plugin->models) {
std::shared_ptr<ModelElement> me = std::make_shared<ModelElement>();
me->mbw = this;
me->model = model;
modelList.push_back(me);
int found = false;
for (std::shared_ptr<PluginElement> pe : pluginList) {
if (!pe->label.compare(me->model->author)) {
found = true;
break;
}
}
if (!found) {
std::shared_ptr<PluginElement> pe = std::make_shared<PluginElement>();
pe->mbw = this;
pe->label.assign(me->model->author);
pluginList.push_back(pe);
}
}
}
// Sort Plugins/Authors
pluginList.sort([](std::shared_ptr<PluginElement> pe1, std::shared_ptr<PluginElement> pe2) { return stringLowercase(pe1->label).compare(stringLowercase(pe2->label)) < 0; } );
AddPlugins();
}
void ResetIcons() {
pluginIcon->selected = 0;
tagIcon->selected = 0;
favIcon->selected = 0;
}

void onResize() override {
scrollWidget->box.size.x = box.size.x - 20;
SetListWidth();
}

void SetListWidth() {
float width = scrollContainer->parent->box.size.x;
float size = 15.0f / zoom;
if (scrollContainer->children.size() * size > scrollContainer->parent->box.size.y)
width -= 13;
float position = 0;
for (Widget *w : scrollContainer->children) {
w->box.pos.y = position;
w->box.size.x = width;
position += w->box.size.y = size;
}
}
void AddElement(std::shared_ptr<ListElement> le, float y) {
TextButton *tb = Widget::create<TextButton>(Vec(0, y));
tb->element = le;
tb->GetLabels();
tb->box.size.x = width;
tb->box.size.y = 15;
scrollContainer->addChild(tb);
}
void AddPlugins() {
scrollContainer->clearChildren();
unsigned int y = 0;
for (std::shared_ptr<PluginElement> pe : pluginList) {
AddElement(pe, y);
y += 15;
}
SetListWidth();
}
void AddTags() {
scrollContainer->clearChildren();
unsigned int y = 0;
for (std::shared_ptr<TagElement> te : tagList) {
AddElement(te, y);
y += 15;
}
SetListWidth();
}
void AddFavorites() {
scrollContainer->clearChildren();
unsigned int y = 0;
FILE *file = fopen(assetLocal("settings.json").c_str(), "r");
if (!file)
return;
json_error_t error;
json_t *rootJ = json_loadf(file, 0, &error);
if (!rootJ) {
warn("JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text);
fclose(file);
return;
}
json_t *modb = json_object_get(rootJ, "moduleBrowser");
if (modb) {
json_t *favoritesJ = json_object_get(modb, "favorites");
if (favoritesJ) {
size_t i;
json_t *favoriteJ;
json_array_foreach(favoritesJ, i, favoriteJ) {
json_t *pluginJ = json_object_get(favoriteJ, "plugin");
json_t *modelJ = json_object_get(favoriteJ, "model");
if (!pluginJ || !modelJ)
continue;
std::string pluginSlug = json_string_value(pluginJ);
std::string modelSlug = json_string_value(modelJ);
Model *model = pluginGetModel(pluginSlug, modelSlug);
if (!model)
continue;
for (std::shared_ptr<ModelElement> me : modelList) {
if (me->model == model) {
AddElement(me, y);
y += 15;
}
}
}
}
}
json_decref(rootJ);
fclose(file);
SetListWidth();
}
void AddModels(std::string author) {
scrollContainer->clearChildren();
std::shared_ptr<PluginBackElement> pbe = std::make_shared<PluginBackElement>();
pbe->mbw = this;
pbe->label2 = author;
AddElement(pbe, 0);
unsigned int y = 15;
for (std::shared_ptr<ModelElement> me : modelList) {
if (!me->model->author.compare(author)) {
AddElement(me, y);
y += 15;
}
}
SetListWidth();
}
void AddModels(unsigned int tag) {
scrollContainer->clearChildren();
std::shared_ptr<TagBackElement> tbe = std::make_shared<TagBackElement>();
tbe->mbw = this;
tbe->label2 = gTagNames[tag];
AddElement(tbe, 0);
unsigned int y = 15;
for (std::shared_ptr<ModelElement> me : modelList) {
for (ModelTag mt : me->model->tags) {
if (mt == tag) {
AddElement(me, y);
y += 15;
}
}
}
SetListWidth();
}
void Load() {
if (lastPath.empty()) {
if (RACK_PLUGIN_UI_RACKWIDGET->lastPath.empty()) {
lastPath = assetLocal("patches");
systemCreateDirectory(lastPath);
}
else {
lastPath = stringDirectory(RACK_PLUGIN_UI_RACKWIDGET->lastPath);
}
}
osdialog_filters *filters = osdialog_filters_parse(allfilters.c_str());
char *path = osdialog_file(OSDIALOG_OPEN, lastPath.c_str(), NULL, filters);
if (path) {
Load(path);
lastPath = stringDirectory(path);
free(path);
}
osdialog_filters_free(filters);
}
void Load(std::string filename) {
FILE *file = fopen(filename.c_str(), "r");
if (!file) {
debug("Unable to open patch %s", filename.c_str());
return;
}

json_error_t error;
json_t *rootJ = json_loadf(file, 0, &error);
if (rootJ) {
Load(rootJ);
json_decref(rootJ);
}
else {
std::string message = stringf("JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text);
osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, message.c_str());
}
fclose(file);
}
void LoadPreset(json_t *rootJ) {
ModuleWidget *moduleWidget = RACK_PLUGIN_UI_RACKWIDGET->moduleFromJson(rootJ);
if (moduleWidget) {
moduleWidget->box.pos = RACK_PLUGIN_UI_RACKWIDGET->lastMousePos.minus(moduleWidget->box.size.div(2));
RACK_PLUGIN_UI_RACKWIDGET->requestModuleBoxNearest(moduleWidget, moduleWidget->box);
}
}
void Load(json_t *rootJ) {
std::string message;
Rect newBox;
newBox.pos.x = -1;
//load modules
std::map<int, ModuleWidget *> moduleWidgets;
json_t *modulesJ = json_object_get(rootJ, "modules");
if (!modulesJ) {
LoadPreset(rootJ);
return;
}
std::vector<Widget *> existingWidgets;
for (Widget *child : RACK_PLUGIN_UI_RACKWIDGET->moduleContainer->children) {
existingWidgets.push_back(child);
}
size_t moduleId;
json_t *moduleJ;
json_array_foreach(modulesJ, moduleId, moduleJ) {
ModuleWidget *moduleWidget = RACK_PLUGIN_UI_RACKWIDGET->moduleFromJson(moduleJ);
if (moduleWidget) {
json_t *posJ = json_object_get(moduleJ, "pos");
double x, y;
json_unpack(posJ, "[F, F]", &x, &y);
Vec pos = Vec(x,y);
moduleWidget->box.pos = pos.mult(RACK_GRID_SIZE);
moduleWidgets[moduleId] = moduleWidget;
if (newBox.pos.x == -1) {
newBox.pos.x = moduleWidget->box.pos.x;
newBox.pos.y = moduleWidget->box.pos.y;
newBox.size.x = moduleWidget->box.size.x;
newBox.size.y = moduleWidget->box.size.y;
}
else {
Rect mbox = moduleWidget->box;
if (mbox.pos.x < newBox.pos.x) {
newBox.size.x += newBox.pos.x - mbox.pos.x;
newBox.pos.x = mbox.pos.x;
}
if (mbox.pos.y < newBox.pos.y) {
newBox.size.y += newBox.pos.y - mbox.pos.y;
newBox.pos.y = mbox.pos.y;
}
if ((mbox.pos.x + mbox.size.x) > (newBox.pos.x + newBox.size.x)) {
newBox.size.x = mbox.pos.x + mbox.size.x - newBox.pos.x;
}
if ((mbox.pos.y + mbox.size.y) > (newBox.pos.y + newBox.size.y)) {
newBox.size.y = mbox.pos.y + mbox.size.y - newBox.pos.y;
}
}
}
}
//find space for modules and arrange
Rect space = FindSpace(existingWidgets, newBox);
if (space.pos.x == -1) {
// oooh noes!!! couldn't find space for these widgets
warn("Module browser could not find space to load patch");
for (const auto& kvp : moduleWidgets) {
RACK_PLUGIN_UI_RACKWIDGET->deleteModule(kvp.second);
kvp.second->finalizeEvents();
delete kvp.second;
}
return;
}
// Move modules into space
float dx = space.pos.x - newBox.pos.x;
float dy = space.pos.y - newBox.pos.y;
for (const auto& kvp : moduleWidgets) {
kvp.second->box.pos.x += dx;
kvp.second->box.pos.y += dy;
}
//wires
json_t *wiresJ = json_object_get(rootJ, "wires");
if (!wiresJ) return;
size_t wireId;
json_t *wireJ;
json_array_foreach(wiresJ, wireId, wireJ) {
int outputModuleId = json_integer_value(json_object_get(wireJ, "outputModuleId"));
int outputId = json_integer_value(json_object_get(wireJ, "outputId"));
int inputModuleId = json_integer_value(json_object_get(wireJ, "inputModuleId"));
int inputId = json_integer_value(json_object_get(wireJ, "inputId"));
ModuleWidget *outputModuleWidget = moduleWidgets[outputModuleId];
if (!outputModuleWidget) continue;
ModuleWidget *inputModuleWidget = moduleWidgets[inputModuleId];
if (!inputModuleWidget) continue;
Port *outputPort = NULL;
Port *inputPort = NULL;
for (Port *port : outputModuleWidget->outputs) {
if (port->portId == outputId) {
outputPort = port;
break;
}
}
for (Port *port : inputModuleWidget->inputs) {
if (port->portId == inputId) {
inputPort = port;
break;
}
}
if (!outputPort || !inputPort)
continue;
WireWidget *wireWidget = new WireWidget();
wireWidget->fromJson(wireJ);
wireWidget->outputPort = outputPort;
wireWidget->inputPort = inputPort;
wireWidget->updateWire();
RACK_PLUGIN_UI_RACKWIDGET->wireContainer->addChild(wireWidget);
}

}
Rect FindSpace(std::vector<Widget *> existingWidgets, Rect box) {
int x0 = roundf(box.pos.x / RACK_GRID_WIDTH);
int y0 = roundf(box.pos.y / RACK_GRID_HEIGHT);
std::vector<Vec> positions;
for (int y = max(0, y0 - 8); y < y0 + 8; y++) {
for (int x = max(0, x0 - 400); x < x0 + 400; x++) {
positions.push_back(Vec(x * RACK_GRID_WIDTH, y * RACK_GRID_HEIGHT));
}
}
std::sort(positions.begin(), positions.end(), [box](Vec a, Vec b) {
return a.minus(box.pos).norm() < b.minus(box.pos).norm();
});
for (Vec position : positions) {
Rect newBox = box;
newBox.pos = position;
int collide = false;
for (Widget *child : existingWidgets) {
if (newBox.intersects(child->box)) {
collide = true;
break;
}
}
if (!collide) {
return newBox;
}
}
Rect failed;
failed.pos.x = -1;
return failed;
}
void step() override {
float thisZoom = clamp(RACK_PLUGIN_UI_RACKSCENE->zoomWidget->zoom, 0.25f, 1.0f);
if (thisZoom != zoom) {
zoom = thisZoom;
SetListWidth();
}
stabilized = true;
ModuleWidget::step();
}

};

// Icon onAction

void PluginIcon::onAction(EventAction &e) {
mbw->ResetIcons();
mbw->pluginIcon->selected = 1;
mbw->AddPlugins();
}

void TagIcon::onAction(EventAction &e) {
mbw->ResetIcons();
mbw->tagIcon->selected = 1;
mbw->AddTags();
}

void FavIcon::onAction(EventAction &e) {
mbw->pluginIcon->selected = 0;
mbw->favIcon->selected = 1;
mbw->AddFavorites();
}

void LoadIcon::onAction(EventAction &e) {
mbw->Load();
}

void MinimizeIcon::onAction(EventAction &e) {
mbw->Minimize(true);
}

// Element onAction

void PluginElement::onAction(EventAction &e) {
mbw->AddModels(label);
}

std::string PluginElement::GetLabelTwo() {
unsigned int count = 0;
for (std::shared_ptr<ModelElement> me : mbw->modelList) {
if (!label.compare(me->model->author))
count++;
}
return std::to_string(count).append(" Modules");
}

void TagElement::onAction(EventAction &e) {
mbw->AddModels(tag);
}

std::string TagElement::GetLabelTwo() {
unsigned int count = 0;
for (std::shared_ptr<ModelElement> me : mbw->modelList) {
for (ModelTag mt : me->model->tags) {
if (mt == tag) {
count++;
}
}
}
return std::to_string(count).append(" Modules");
}

void ModelElement::onAction(EventAction &e) {
ModuleWidget *moduleWidget = model->createModuleWidget();
if (!moduleWidget)
return;
RACK_PLUGIN_UI_RACKWIDGET->addModule(moduleWidget);
moduleWidget->box.pos = RACK_PLUGIN_UI_RACKWIDGET->lastMousePos.minus(moduleWidget->box.size.div(2));
RACK_PLUGIN_UI_RACKWIDGET->requestModuleBoxNearest(moduleWidget, moduleWidget->box);
}

void PluginBackElement::onAction(EventAction &e) {
mbw->AddPlugins();
}

void TagBackElement::onAction(EventAction &e) {
mbw->AddTags();
}

struct Blank2 : ModuleWidget {
Blank2(Module *module) : ModuleWidget(module) {
box.size = Vec(RACK_GRID_WIDTH * 5, RACK_GRID_HEIGHT * 2);
{
Panel *panel = new LightPanel();
panel->box.size = box.size;
addChild(panel);
}
}
};

struct Blank3 : ModuleWidget {
Blank3(Module *module) : ModuleWidget(module) {
box.size = Vec(RACK_GRID_WIDTH * 5, RACK_GRID_HEIGHT * 3);
{
Panel *panel = new LightPanel();
panel->box.size = box.size;
addChild(panel);
}
}
};

struct Blank5 : ModuleWidget {
Blank5(Module *module) : ModuleWidget(module) {
box.size = Vec(RACK_GRID_WIDTH * 5, RACK_GRID_HEIGHT * 5);
{
Panel *panel = new LightPanel();
panel->box.size = box.size;
addChild(panel);
}
}
};

} // namespace rack_plugin_SubmarineUtility

using namespace rack_plugin_SubmarineUtility;

RACK_PLUGIN_MODEL_INIT(SubmarineUtility, ModBrowser) {
Model *modelModBrowser = Model::create<Module, ModBrowserWidget>("Submarine (Utilities)", "ModBrowser", "Module Browser", UTILITY_TAG);
return modelModBrowser;
}

+ 335
- 0
plugins/community/repos/SubmarineUtility/src/SubControls.cpp View File

@@ -0,0 +1,335 @@
#include "SubControls.hpp"
#include "global_pre.hpp"
#include "global_ui.hpp"
#include "window.hpp"

namespace rack_plugin_SubmarineUtility {

namespace SubControls {

struct RowShift {
Vec position;
int handled = false;
};

struct RowShifter {
std::vector<std::shared_ptr<RowShift>> rows;
Widget *baseWidget;
unsigned int addRow(Vec position) {
// Search for row in existing list
for (std::shared_ptr<RowShift> row : rows) {
if (row->position.y != position.y)
continue; // This is not the row we are looking for
if (row->handled)
return false; // This is the row but it's been done already
if (row->position.x <= position.x)
return false; // This is the row already and covers the same ground
row->position.x = position.x; // We need to move the start point further to the left
return true;
}
std::shared_ptr<RowShift> row = std::make_shared<RowShift>();
row->position.x = position.x;
row->position.y = position.y;
rows.push_back(row);
return true; // We didn't find the row so we added it.
}
unsigned int shift(float delta) {
unsigned moreWork = false;
for (std::shared_ptr<RowShift> row : rows) {
if (row->handled)
continue; // This row has been done already
row->handled = true;
for (Widget *w : RACK_PLUGIN_UI_RACKWIDGET->moduleContainer->children) {
if (baseWidget == w)
continue; // We are not moving the widget that caused this.
if (row->position.x > w->box.pos.x)
continue; // This is to the left of our start position
if (row->position.y != w->box.pos.y) {
if (row->position.y > w->box.pos.y) {
if (row->position.y < w->box.pos.y + w->box.size.y) {
for (float i = 0; i < w->box.size.y; i += RACK_GRID_HEIGHT) {
Vec newRow;
newRow.x = w->box.pos.x;
newRow.y = w->box.pos.y + i;
moreWork |= addRow(newRow); // These are the rows covered by a multi-row widget
}
}
}
continue;
}
if (w->box.size.y > RACK_GRID_HEIGHT) {
for (float i = 0; i < w->box.size.y; i += RACK_GRID_HEIGHT) {
Vec newRow;
newRow.x = w->box.pos.x;
newRow.y = w->box.pos.y + i;
moreWork |= addRow(newRow); // These are the rows covered by a multi row widget
}
}
w->box.pos.x += delta; // This widget should be moved
}
}
return moreWork;
}
void shortShiftRight(float endPoint) {
Widget *widgetToMove = baseWidget;
std::shared_ptr<RowShift> row = rows[0];
for (Widget *w : RACK_PLUGIN_UI_RACKWIDGET->moduleContainer->children) {
if (w->box.pos.y != row->position.y)
continue; // This is not the row we are looking for
if (w->box.pos.x <= row->position.x)
continue; // This is to the left of the region we are looking at
if (w->box.pos.x >= endPoint)
continue; // This is to the right of the region we are looking at
if (w->box.pos.x > widgetToMove->box.pos.x)
widgetToMove = w;
}
if (widgetToMove == baseWidget)
return; // Nothing more to move
float delta = endPoint - widgetToMove->box.pos.x - widgetToMove->box.size.x;
widgetToMove->box.pos.x += delta; // Move this widget as far to the right as we can
endPoint -= widgetToMove->box.size.x; // Adjust our endpoint back to exclude this widget
shortShiftRight(endPoint); // Recurse to move the next widget
}
void shortShiftLeft(float delta, float endPoint) {
std::shared_ptr<RowShift> row = rows[0];
for (Widget *w : RACK_PLUGIN_UI_RACKWIDGET->moduleContainer->children) {
if (w->box.pos.y != row->position.y)
continue; // This is not the row we are looking for
if (w->box.pos.x <= row->position.x)
continue; // This is to the left of the region we are looking at
if (w->box.pos.x >= endPoint)
continue; // This is to the right of the region we are looking at
w->box.pos.x += delta;
}
}
void process(float delta) {
// Test to see if any multi-row items are involved
float endPoint = 0.0f;
std::shared_ptr<RowShift> row = rows[0];
for (Widget *w : RACK_PLUGIN_UI_RACKWIDGET->moduleContainer->children) {
if (w->box.size.y == RACK_GRID_HEIGHT)
continue; // This is a single row widget
if (w->box.pos.y > row->position.y)
continue; // This is below the row
if ((w->box.pos.y + w->box.size.y) > (row->position.y + RACK_GRID_HEIGHT)) { // This is what we are looking for
if ((endPoint == 0.0f) || endPoint > w->box.pos.x) {
endPoint = w->box.pos.x;
}
}
}
if (endPoint > 0.0f) { // There is a multi-row element in the way
if (delta < 0.0f) {
shortShiftLeft(delta, endPoint); // Just shift upto the endPoint
return;
}
// Have we got enough space to shuffle up before the multi-row element
float space = endPoint - baseWidget->box.pos.x - baseWidget->box.size.x;
debug("Space %f", space);
for (Widget *w : RACK_PLUGIN_UI_RACKWIDGET->moduleContainer->children) {
if (w->box.pos.y != row->position.y)
continue; // This is not the row we are looking for
if (w->box.pos.x <= row->position.x)
continue; // This is to the left of the region we are looking at
if (w->box.pos.x >= endPoint)
continue; // This is to the right of the region we are looking at
space -= w->box.size.x;
debug("Space adjusted to %f", space);
}
debug("Space %f delta %f", space, delta);
if (space >= delta) {
shortShiftRight(endPoint); // Just shift upto the endPoint
return;
}
}
while (shift(delta));
}
};

SizeableModuleWidget::SizeableModuleWidget(Module *module) : ModuleWidget(module) {
box.size.x = moduleWidth;
box.size.y = 380;
handle = Widget::create<ModuleDragHandle>(Vec(box.size.x - 10, 175));
handle->smw = this;
addChild(handle);

backPanel = Widget::create<BackPanel>(Vec(10, 15));
backPanel->box.size.x = box.size.x - 20;
backPanel->box.size.y = box.size.y - 30;
addChild(backPanel);

minimizeLogo = Widget::create<SubLogo>(Vec(0,0));
#define plugin "SubmarineUtility"
minimizeLogo->setSVG(SVG::load(assetPlugin(plugin, "res/Sub2.svg")));
minimizeLogo->visible = false;
addChild(minimizeLogo);

maximizeLogo = Widget::create<SubLogo>(Vec(moduleWidth - 20, 365));
maximizeLogo->setSVG(SVG::load(assetPlugin(plugin, "res/Sub1.svg")));
addChild(maximizeLogo);

maximizeButton = Widget::create<MaximizeButton>(Vec(0, 175));
maximizeButton->smw = this;
maximizeButton->visible = false;
addChild(maximizeButton);
}

void SizeableModuleWidget::Resize() {
backPanel->box.size.x = box.size.x - 20;
handle->box.pos.x = box.size.x - 10;
maximizeLogo->box.pos.x = box.size.x - 20;
handle->visible = sizeable;
onResize();
}

void SizeableModuleWidget::draw(NVGcontext *vg) {
nvgBeginPath(vg);
nvgRect(vg,0,0,box.size.x, box.size.y);
nvgFillColor(vg,nvgRGB(0x29, 0x4f, 0x77));
nvgFill(vg);

nvgBeginPath(vg);
nvgMoveTo(vg, 0, 0);
nvgLineTo(vg, box.size.x, 0);
nvgLineTo(vg, box.size.x - 1, 1);
nvgLineTo(vg, 1, 1);
nvgClosePath(vg);
nvgMoveTo(vg, 1, 1);
nvgLineTo(vg, 1, box.size.y - 1);
nvgLineTo(vg, 0, box.size.y);
nvgLineTo(vg, 0, 0);
nvgClosePath(vg);
nvgFillColor(vg, nvgRGB(0x3a, 0x6e, 0xa5));
nvgFill(vg);

nvgBeginPath(vg);
nvgMoveTo(vg, box.size.x, 0);
nvgLineTo(vg, box.size.x, box.size.y);
nvgLineTo(vg, box.size.x - 1, box.size.y - 1);
nvgLineTo(vg, box.size.x -1, 1);
nvgClosePath(vg);
nvgMoveTo(vg, box.size.x, box.size.y);
nvgLineTo(vg, 0, box.size.y);
nvgLineTo(vg, 1, box.size.y - 1);
nvgLineTo(vg, box.size.x - 1, box.size.y - 1);
nvgClosePath(vg);
nvgFillColor(vg, nvgRGB(0x18, 0x2d, 0x44));
nvgFill(vg);

if (moduleWidth > 0) {
nvgFontSize(vg, 14);
nvgFontFaceId(vg, font->handle);
nvgFillColor(vg, nvgRGBA(0x71, 0x9f, 0xcf, 0xff));
nvgTextAlign(vg, NVG_ALIGN_LEFT);
nvgText(vg, 3, 378, "submarine", NULL);
nvgTextAlign(vg, NVG_ALIGN_CENTER);
nvgText(vg, box.size.x / 2, 12, moduleName.c_str(), NULL);
}
else {
nvgSave(vg);
nvgRotate(vg, -M_PI / 2);
nvgFontSize(vg, 14);
nvgFontFaceId(vg, font->handle);
nvgFillColor(vg, nvgRGBA(0x71, 0x9f, 0xcf, 0xff));
nvgTextAlign(vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE);
nvgText(vg, -97.5, 7.5, moduleName.c_str(), NULL);
nvgText(vg, -277.5, 7.5, "submarine", NULL);
nvgRestore(vg);
}
ModuleWidget::draw(vg);
}

void SizeableModuleWidget::ShiftOthers(float delta) {
if (!stabilized)
return;
if (delta == 0.0f)
return;
RowShifter shifter;
shifter.baseWidget = this;
shifter.addRow(this->box.pos);
shifter.process(delta);
}

void SizeableModuleWidget::Minimize(unsigned int minimize) {
float oldSize = box.size.x;
if (minimize) {
if (moduleWidth > 0)
moduleWidth = -moduleWidth;
box.size.x = 15;
backPanel->visible = false;
maximizeButton->visible = true;
maximizeLogo->visible = false;
minimizeLogo->visible = true;
handle->visible = false;
ShiftOthers(box.size.x - oldSize);
}
else {
if (moduleWidth < 0)
moduleWidth = -moduleWidth;
ShiftOthers(moduleWidth - oldSize);
box.size.x = moduleWidth;
backPanel->visible = true;
maximizeButton->visible = false;
maximizeLogo->visible = true;
minimizeLogo->visible = false;
handle->visible = sizeable;
Resize();
}
}

json_t *SizeableModuleWidget::toJson() {
json_t *rootJ = ModuleWidget::toJson();
// moduleWidth
json_object_set_new (rootJ, "width", json_real(moduleWidth));

return rootJ;
}

void SizeableModuleWidget::fromJson(json_t *rootJ) {
ModuleWidget::fromJson(rootJ);

// width
json_t *widthJ = json_object_get(rootJ, "width");
if (widthJ)
moduleWidth = json_number_value(widthJ);
Minimize(moduleWidth < 0);
}

void ModuleDragHandle::onDragStart(EventDragStart &e) {
dragX = RACK_PLUGIN_UI_RACKWIDGET->lastMousePos.x;
originalBox = smw->box;
}

void ModuleDragHandle::onDragMove(EventDragMove &e) {

float newDragX = RACK_PLUGIN_UI_RACKWIDGET->lastMousePos.x;
float deltaX = newDragX - dragX;

Rect newBox = originalBox;
newBox.size.x += deltaX;
newBox.size.x = fmaxf(newBox.size.x, smw->minimumWidth);
newBox.size.x = roundf(newBox.size.x / RACK_GRID_WIDTH) * RACK_GRID_WIDTH;
RACK_PLUGIN_UI_RACKWIDGET->requestModuleBox(smw, newBox);
smw->moduleWidth = smw->box.size.x;
smw->Resize();
}

void ModuleDragHandle::draw(NVGcontext *vg) {
for (float x = 2.0; x <= 8.0; x += 2.0) {
nvgBeginPath(vg);
const float margin = 5.0;
nvgMoveTo(vg, x + 0.5, margin + 0.5);
nvgLineTo(vg, x + 0.5, box.size.y - margin + 0.5);
nvgStrokeWidth(vg, 1.0);
nvgStrokeColor(vg, nvgRGBAf(0.5, 0.5, 0.5, 0.5));
nvgStroke(vg);
}
}

void MaximizeButton::onAction(EventAction &e) {
smw->Minimize(false);
}

} // SubControls

} // namespace rack_plugin_SubmarineUtility

+ 225
- 0
plugins/community/repos/SubmarineUtility/src/SubControls.hpp View File

@@ -0,0 +1,225 @@
#include "SubmarineUtility.hpp"
#undef plugin
#include "global.hpp"
#include "global_pre.hpp"
#include "window.hpp"

namespace rack_plugin_SubmarineUtility {

namespace SubControls {

struct BackPanel : OpaqueWidget {
void draw (NVGcontext *vg) override {
nvgBeginPath(vg);
nvgRect(vg, 0, 0, box.size.x, box.size.y);
nvgFillColor(vg, nvgRGB(0, 0, 0));
nvgFill(vg);
OpaqueWidget::draw(vg);
}
};

struct ButtonBase : Component {
void onDragEnd(EventDragEnd &e) override {
EventAction eAction;
onAction(eAction);
}
};

struct RadioButton : ButtonBase {
std::string label;
int selected = false;
void draw (NVGcontext *vg) override {
nvgStrokeWidth(vg, 1);
nvgFillColor(vg, nvgRGB(0xff, 0xff, 0xff));
if (!label.empty()) {
nvgFontFaceId(vg, rack::global_ui->window.gGuiFont->handle);
nvgFontSize(vg, 13);
nvgTextAlign(vg, NVG_ALIGN_MIDDLE);
nvgText(vg, 21, box.size.y / 2, label.c_str(), NULL);
}
if (selected) {
nvgBeginPath(vg);
nvgCircle(vg, box.size.y / 2 + 1, box.size.y / 2, 5);
nvgFill(vg);
}
nvgBeginPath(vg);
nvgCircle(vg, box.size.y / 2 + 1, box.size.y / 2, 8);
nvgStrokeColor(vg, nvgRGB(0xff, 0xff, 0xff));
nvgStroke(vg);
Component::draw(vg);
}
};

struct CheckButton : ButtonBase {
std::string label;
int selected = false;
void draw (NVGcontext *vg) override {
nvgFillColor(vg, nvgRGB(0xff, 0xff, 0xff));
if (!label.empty()) {
nvgFontFaceId(vg, rack::global_ui->window.gGuiFont->handle);
nvgFontSize(vg, 13);
nvgTextAlign(vg, NVG_ALIGN_MIDDLE);
nvgText(vg, 21, box.size.y / 2, label.c_str(), NULL);
}
nvgStrokeWidth(vg, 1);
nvgStrokeColor(vg, nvgRGB(0xff, 0xff, 0xff));
if (selected) {
nvgBeginPath(vg);
nvgMoveTo(vg, box.size.y / 2 - 4, box.size.y / 2 - 5);
nvgLineTo(vg, box.size.y / 2 + 6, box.size.y / 2 + 5);
nvgMoveTo(vg, box.size.y / 2 - 4, box.size.y / 2 + 5);
nvgLineTo(vg, box.size.y / 2 + 6, box.size.y / 2 - 5);
nvgStroke(vg);
}
nvgBeginPath(vg);
nvgRect(vg, box.size.y / 2 - 7, box.size.y / 2 - 8, 16, 16);
nvgStroke(vg);
Component::draw(vg);
}
};

struct ClickButton : ButtonBase {
std::string label;
void draw (NVGcontext *vg) override {
nvgFillColor(vg, nvgRGB(0xff, 0xff, 0xff));
if (!label.empty()) {
nvgFontFaceId(vg, rack::global_ui->window.gGuiFont->handle);
nvgFontSize(vg, 13);
nvgTextAlign(vg, NVG_ALIGN_MIDDLE | NVG_ALIGN_CENTER);
nvgText(vg, box.size.x / 2, box.size.y / 2, label.c_str(), NULL);
}
nvgBeginPath(vg);
nvgRect(vg, 0.5, 0.5, box.size.x - 1, box.size.y - 1);
nvgStrokeColor(vg, nvgRGB(0xff, 0xff, 0xff));
nvgStrokeWidth(vg, 1);
nvgStroke(vg);
Component::draw(vg);
}
};

struct Label : TransparentWidget {
std::string label;
void draw (NVGcontext *vg) override {
nvgFillColor(vg, nvgRGB(0xff, 0xff, 0xff));
if (!label.empty()) {
nvgFontFaceId(vg, rack::global_ui->window.gGuiFont->handle);
nvgFontSize(vg, 13);
nvgTextAlign(vg, NVG_ALIGN_MIDDLE);
nvgText(vg, 1, box.size.y / 2, label.c_str(), NULL);
}
TransparentWidget::draw(vg);
}
};

struct Slider : Knob {
int transparent = false;
void draw(NVGcontext *vg) override {
Vec minHandlePos;
Vec maxHandlePos;
float width;
float height;
if (box.size.x < box.size.y) {
width = box.size.x;
height = 10;
minHandlePos = Vec(box.size.x / 2, height / 2);
maxHandlePos = Vec(box.size.x / 2, box.size.y - height / 2);
}
else {
width = 10;
height = box.size.y;
minHandlePos = Vec(width / 2, box.size.y / 2);
maxHandlePos = Vec(box.size.x - width / 2, box.size.y / 2);
}
Vec pos = Vec(rescale(value, minValue, maxValue, minHandlePos.x, maxHandlePos.x), rescale(value, minValue, maxValue, minHandlePos.y, maxHandlePos.y));
nvgFillColor(vg, nvgRGB(0, 0, 0));
nvgStrokeColor(vg, nvgRGB(0xff, 0xff, 0xff));
nvgStrokeWidth(vg, 1);
if (!transparent) {
nvgBeginPath(vg);
nvgMoveTo(vg, minHandlePos.x, minHandlePos.y);
nvgLineTo(vg, maxHandlePos.x, maxHandlePos.y);
nvgStroke(vg);
}
nvgBeginPath(vg);
nvgRect(vg, pos.x - width / 2 + 0.5, pos.y - height / 2 + 0.5 , width - 1, height - 1);
if (!transparent) nvgFill(vg);
nvgStroke(vg);
}
};

struct HSlider : Slider {
void onDragMove(EventDragMove &e) override {
e.mouseRel.y = -e.mouseRel.x;
Knob::onDragMove(e);
}
};

struct SubLogo : SVGWidget{};

struct ModuleDragHandle;
struct SizeableModuleWidget;

struct MaximizeButton : ButtonBase {
SizeableModuleWidget *smw;
MaximizeButton() {
box.size.x = 15;
box.size.y = 30;
}
void draw(NVGcontext *vg) override {
nvgBeginPath(vg);
nvgMoveTo(vg, 2, 4);
nvgLineTo(vg, 13, 15);
nvgLineTo(vg, 2, 26);
nvgClosePath(vg);
nvgFillColor(vg, nvgRGB(0x71, 0x9f, 0xcf));
nvgFill(vg);
Component::draw(vg);
}
void onAction(EventAction &e) override;
};

struct SizeableModuleWidget : ModuleWidget {
float moduleWidth = 300.0f;
float minimumWidth = 185.0f;
unsigned int sizeable = true;
unsigned int stabilized = false;
ModuleDragHandle *handle;
BackPanel *backPanel;
SubLogo *minimizeLogo;
SubLogo *maximizeLogo;
MaximizeButton *maximizeButton;
std::shared_ptr<Font> font = Font::load(assetGlobal("res/fonts/DejaVuSans.ttf"));
std::string moduleName;

SizeableModuleWidget(Module *module);
void draw(NVGcontext *vg) override;
void Resize();
void Minimize(unsigned int minimize);
void ShiftOthers(float delta);
json_t *toJson() override;
void fromJson(json_t *rootJ) override;

virtual void onResize() { };
};

struct ModuleDragHandle : VirtualWidget {
SizeableModuleWidget *smw;
float dragX;
Rect originalBox;
ModuleDragHandle() {
box.size = Vec(10, 30);
}
void onMouseDown(EventMouseDown &e) override {
if (e.button == 0) {
e.consumed = true;
e.target = this;
}
}
void draw(NVGcontext *vg) override;
void onDragStart(EventDragStart &e) override;
void onDragMove(EventDragMove &e) override;
};

} // SubControls

} // namespace rack_plugin_SubmarineUtility

+ 14
- 0
plugins/community/repos/SubmarineUtility/src/SubmarineUtility.cpp View File

@@ -0,0 +1,14 @@
#include "SubmarineUtility.hpp"

RACK_PLUGIN_MODEL_DECLARE(SubmarineUtility, ModBrowser);
RACK_PLUGIN_MODEL_DECLARE(SubmarineUtility, WireManager);

RACK_PLUGIN_INIT(SubmarineUtility) {
RACK_PLUGIN_INIT_ID();
RACK_PLUGIN_INIT_VERSION("0.6.2");
RACK_PLUGIN_INIT_WEBSITE("https://github.com/david-c14/SubmarineUtility");
RACK_PLUGIN_INIT_MANUAL("https://github.com/david-c14/SubmarineUtility");

RACK_PLUGIN_MODEL_ADD(SubmarineUtility, ModBrowser);
RACK_PLUGIN_MODEL_ADD(SubmarineUtility, WireManager);
}

+ 9
- 0
plugins/community/repos/SubmarineUtility/src/SubmarineUtility.hpp View File

@@ -0,0 +1,9 @@
#include "rack.hpp"

using namespace rack;

RACK_PLUGIN_DECLARE(SubmarineUtility);

#ifdef USE_VST2
#define plugin "SubmarineUtility"
#endif // USE_VST2

+ 1023
- 0
plugins/community/repos/SubmarineUtility/src/WireManager.cpp
File diff suppressed because it is too large
View File


+ 2
- 0
plugins/makefile.common View File

@@ -74,6 +74,7 @@ bin:
$(call run_make,Southpole-parasites,bin)
$(call run_make,squinkylabs-plug1,bin)
$(call run_make,SubmarineFree,bin)
$(call run_make,SubmarineUtility,bin)
$(call run_make,SynthKit,bin)
$(call run_make,Template,bin)
$(call run_make,Template_shared,bin)
@@ -154,6 +155,7 @@ clean:
$(call run_make,Southpole-parasites,clean)
$(call run_make,squinkylabs-plug1,clean)
$(call run_make,SubmarineFree,clean)
$(call run_make,SubmarineUtility,clean)
$(call run_make,SynthKit,clean)
$(call run_make,Template,clean)
$(call run_make,Template_shared,clean)


+ 2
- 0
src/plugin_static.cpp View File

@@ -115,6 +115,7 @@ extern void init_plugin_Southpole (rack::Plugin *p);
extern void init_plugin_Southpole_parasites (rack::Plugin *p);
extern void init_plugin_squinkylabs_plug1 (rack::Plugin *p);
extern void init_plugin_SubmarineFree (rack::Plugin *p);
extern void init_plugin_SubmarineUtility (rack::Plugin *p);
extern void init_plugin_SynthKit (rack::Plugin *p);
extern void init_plugin_Template (rack::Plugin *p);
extern void init_plugin_TheXOR (rack::Plugin *p);
@@ -220,6 +221,7 @@ void vst2_load_static_rack_plugins(void) {
vst2_load_static_rack_plugin("Southpole_parasites", &init_plugin_Southpole_parasites);
vst2_load_static_rack_plugin("squinkylabs-plug1", &init_plugin_squinkylabs_plug1);
vst2_load_static_rack_plugin("SubmarineFree", &init_plugin_SubmarineFree);
vst2_load_static_rack_plugin("SubmarineUtility", &init_plugin_SubmarineUtility);
vst2_load_static_rack_plugin("SynthKit", &init_plugin_SynthKit);
vst2_load_static_rack_plugin("Template", &init_plugin_Template);
vst2_load_static_rack_plugin("TheXOR", &init_plugin_TheXOR);


+ 29
- 0
vst2_bin/plugins/SubmarineUtility/LICENSE View File

@@ -0,0 +1,29 @@
BSD 3-Clause License

Copyright (c) 2018, David O'Rourke
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 copyright holder 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 HOLDER 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.

+ 19
- 0
vst2_bin/plugins/SubmarineUtility/README.md View File

@@ -0,0 +1,19 @@
# SubmarineUtility
Utility Modules for VCVRack

Important note:

These modules rely on knowledge of VCVRack which goes beyond the published API. The ongoing stability of the code is therefore not guaranteed. At least some of the features of these modules rely on code which is expected to change in future versions of VCVRack, and many other parts are likely to change.

Whilst I intend to try to keep these modules up to date with changes, I can make no guarantees that this will even be possible.

**Module Browser will definitely need to be somewhat rewritten for VCVRack v1.0. It is my intention to do so as soon as possible.**

However, these modules are not designed or intended to form any part of your patch behaviour. They are intended purely as workflow tools. If these modules become incompatible with VCVRack in the future, it should be possible to remove them from the patch without affecting the aural content of the patch.

## [Manual](https://github.com/david-c14/SubmarineUtility/blob/master/manual/index.md)

## Licence

This code is licensed under BSD 3-clause and is mostly copyright © 2018 carbon14 (David O'Rourke) 2018
Some parts of this code are inevitably based directly on code by Andrew Belt within VCVRack itself; Copyright © 2016 Andrew Belt.

+ 17
- 0
vst2_bin/plugins/SubmarineUtility/res/Sub1.svg View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
height="15px"
width="20px">
<g
style="font-size:12px;font-family:'DejaVu Sans';fill:#719fcf"
font-size="12"
id="logo">
<path
id="path4136"
d="M 9.35391,1 A 1.9846094,2.2519786 0 0 0 7.36926,3.25192 1.9846094,2.2519786 0 0 0 7.42806,3.78359 8.1692063,5.1693144 0 0 0 1,8.83071 8.1692063,5.1693144 0 0 0 9.16915,14 8.1692063,5.1693144 0 0 0 16.48278,11.11985 3.0461447,4.2480502 0 0 0 19,12.97641 l 0,-2.35772 A 1.3384576,1.9448905 0 0 1 17.7077,8.67718 1.3384576,1.9448905 0 0 1 19,6.73455 L 19,4.48039 A 3.0461447,4.2480502 0 0 0 16.42587,6.45983 8.1692063,5.1693144 0 0 0 9.16915,3.66141 8.1692063,5.1693144 0 0 0 8.79597,3.67331 1.7538409,2.0472531 0 0 1 9.49235,2.67169 l 0,-1.66609 A 1.9846094,2.2519786 0 0 0 9.35391,1 Z M 6.07684,6.83461 A 1.6615335,1.8425278 0 0 1 7.7384,8.67718 1.6615335,1.8425278 0 0 1 6.07684,10.51975 1.6615335,1.8425278 0 0 1 4.41539,8.67718 1.6615335,1.8425278 0 0 1 6.07684,6.83461 Z M 9.86149,7.2441 A 1.2923038,1.4330772 0 0 1 11.1538,8.67718 1.2923038,1.4330772 0 0 1 9.86149,10.11026 1.2923038,1.4330772 0 0 1 8.56919,8.67718 1.2923038,1.4330772 0 0 1 9.86149,7.2441 Z m 3.00928,0.38892 A 0.92307415,1.0236265 0 0 1 13.79381,8.65675 0.92307415,1.0236265 0 0 1 12.87077,9.68034 0.92307415,1.0236265 0 0 1 11.9476,8.65675 0.92307415,1.0236265 0 0 1 12.87077,7.63302 Z"
inkscape:connector-curvature="0" />
</g>
</svg>

+ 15
- 0
vst2_bin/plugins/SubmarineUtility/res/Sub2.svg View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
height="20px"
width="15px">
<g
style="font-size:12px;font-family:'DejaVu Sans';fill:#719fcf"
font-size="12"
id="logo">
<path
id="path4136"
d="M 1,10.64609 A 2.2519786,1.9846094 0 0 0 3.25192,12.63074 2.2519786,1.9846094 0 0 0 3.78359,12.57194 5.1693144,8.1692063 0 0 0 8.83071,19 5.1693144,8.1692063 0 0 0 14,10.83085 5.1693144,8.1692063 0 0 0 11.11985,3.51722 4.2480502,3.0461447 0 0 0 12.97641,1 L 10.61869,1 A 1.9448905,1.3384576 0 0 1 8.67718,2.2923 1.9448905,1.3384576 0 0 1 6.73455,1 L 4.48039,1 a 4.2480502,3.0461447 0 0 0 1.97944,2.57413 5.1693144,8.1692063 0 0 0 -2.79842,7.25672 5.1693144,8.1692063 0 0 0 0.0119,0.37318 2.0472531,1.7538409 0 0 1 -1.00162,-0.69638 l -1.66609,0 A 2.2519786,1.9846094 0 0 0 1,10.64609 Z m 5.83461,3.27707 A 1.8425278,1.6615335 0 0 1 8.67718,12.2616 1.8425278,1.6615335 0 0 1 10.51975,13.92316 1.8425278,1.6615335 0 0 1 8.67718,15.58461 1.8425278,1.6615335 0 0 1 6.83461,13.92316 Z M 7.2441,10.13851 A 1.4330772,1.2923038 0 0 1 8.67718,8.8462 1.4330772,1.2923038 0 0 1 10.11026,10.13851 1.4330772,1.2923038 0 0 1 8.67718,11.43081 1.4330772,1.2923038 0 0 1 7.2441,10.13851 Z M 7.63302,7.12923 A 1.0236265,0.92307415 0 0 1 8.65675,6.20619 1.0236265,0.92307415 0 0 1 9.68034,7.12923 1.0236265,0.92307415 0 0 1 8.65675,8.0524 1.0236265,0.92307415 0 0 1 7.63302,7.12923 Z" />
</g>
</svg>

+ 28
- 0
vst2_bin/plugins/SubmarineUtility/res/colors.svg View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="30px"
height="30px"
version="1.1">
<g
inkscape:label="Background"
inkscape:groupmode="layer"
id="background">
<rect
x="0"
y="0"
width="30"
height="30"
rx="3"
ry="3"
style="fill:#404040;stroke:none;"
id="rect4255" />
</g>
<g>
<circle cx="9" cy="20" r="6" style="fill:#ff0000;" />
<circle cx="21" cy="20" r="6" style="fill:#0000ff;" />
<circle cx="15" cy="9.6" r="6" style="fill:#00ff00;" />
</g>
</svg>

+ 44
- 0
vst2_bin/plugins/SubmarineUtility/res/favorite.svg View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="30px"
height="30px"
version="1.1">
<g
inkscape:label="Background"
inkscape:groupmode="layer"
id="background">
<rect
x="0"
y="0"
width="30"
height="30"
rx="3"
ry="3"
style="fill:#404040;stroke:none;"
id="rect4255" />
</g>
<g
stroke="#ffffff"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2">
<path d="
M 15 2
L 20.878 7.91
L 28.315 11.6738
L 24.511 19.090
L 23.8168 27.3262
L 15 26
L 6.1832 27.3262
L 5.489 19.090
L 1.6852 11.6738
L 9.122 7.91
z

" />
</g>
</svg>

+ 35
- 0
vst2_bin/plugins/SubmarineUtility/res/hls.svg View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="30px"
height="30px"
version="1.1">
<g
inkscape:label="Background"
inkscape:groupmode="layer"
id="background">
<rect
x="0"
y="0"
width="30"
height="30"
rx="3"
ry="3"
style="fill:#404040;stroke:none;"
id="rect4255" />
</g>
<g
stroke="#ffffff"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2">
<path d="
M 3 6 h 24 m -20 0 m 0 -4 v 8
M 3 15 h 24 m -6 0 m 0 -4 v 8
M 3 24 h 24 m -13 0 m 0 -4 v 8
" />
</g>
</svg>

+ 39
- 0
vst2_bin/plugins/SubmarineUtility/res/load.svg View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="30px"
height="30px"
version="1.1">
<g
inkscape:label="Background"
inkscape:groupmode="layer"
id="background">
<rect
x="0"
y="0"
width="30"
height="30"
rx="3"
ry="3"
style="fill:#404040;stroke:none;"
id="rect4255" />
</g>
<g
stroke="#ffffff"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2">
<path d="
M 3 2 l 19 0 l 5 5 l 0 21 l -24 0 l 0 -26
M 8 2 l 0 10 l 13 0 l 0 -10
M 12 5 l 0 4
M 7 28 l 0 -12 l 16 0 l 0 12
M 10 24 l 6 0
M 10 21 l 9 0

" />
</g>
</svg>

+ 33
- 0
vst2_bin/plugins/SubmarineUtility/res/min.svg View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="30px"
height="30px"
version="1.1">
<g
inkscape:label="Background"
inkscape:groupmode="layer"
id="background">
<rect
x="0"
y="0"
width="30"
height="30"
rx="3"
ry="3"
style="fill:#404040;stroke:none;"
id="rect4255" />
</g>
<g
stroke="#ffffff"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2">
<path d="
M 21 3 l 0 24 l -14 -12 l 14 -12
" />
</g>
</svg>

+ 35
- 0
vst2_bin/plugins/SubmarineUtility/res/plugin.svg View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="30px"
height="30px"
version="1.1">
<g
inkscape:label="Background"
inkscape:groupmode="layer"
id="background">
<rect
x="0"
y="0"
width="30"
height="30"
rx="3"
ry="3"
style="fill:#404040;stroke:none;"
id="rect4255" />
</g>
<g
stroke="#ffffff"
fill="none"
stroke-linecap="round"
stroke-width="2">
<path d="M 3 27 l 6 -6
M 13 9 l -4 4 a 3 3 0 0 0 8 8 l 4 -4
M 12 8 l 10 10
M 15 11 l 5 -5
M 19 15 l 5 -5
" />
</g>
</svg>

+ 34
- 0
vst2_bin/plugins/SubmarineUtility/res/tag.svg View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="30px"
height="30px"
version="1.1">
<g
inkscape:label="Background"
inkscape:groupmode="layer"
id="background">
<rect
x="0"
y="0"
width="30"
height="30"
rx="3"
ry="3"
style="fill:#404040;stroke:none;"
id="rect4255" />
</g>
<g
stroke="#ffffff"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2">
<path d="
M 3 3 l 10 0 l 14 14 l -10 10 l -14 -14 z
" />
<circle cx="9" cy="9" r="2.5" />
</g>
</svg>

+ 1
- 0
vst2_common_staticlibs.mk View File

@@ -64,6 +64,7 @@ EXTRALIBS+= $(call plugin_lib,Southpole)
EXTRALIBS+= $(call plugin_lib,Southpole-parasites)
EXTRALIBS+= $(call plugin_lib,squinkylabs-plug1)
EXTRALIBS+= $(call plugin_lib,SubmarineFree)
EXTRALIBS+= $(call plugin_lib,SubmarineUtility)
EXTRALIBS+= $(call plugin_lib,SynthKit)
EXTRALIBS+= $(call plugin_lib,Template)
EXTRALIBS+= $(call plugin_lib,TheXOR)


Loading…
Cancel
Save