User interface update

This commit is contained in:
Jean Pierre Cimalando 2020-09-02 12:19:26 +02:00
parent 0849a1b5e5
commit 40e48bcc54
29 changed files with 2720 additions and 475 deletions

View file

@ -3,8 +3,23 @@ include("cmake/Vstgui.cmake")
set(EDITOR_RESOURCES
logo.png
logo_text.png
logo_text@2x.png
icon_white.png
icon_white@2x.png
knob48.png
knob48@2x.png
Fonts/fluentui-system-regular-20.ttf
PARENT_SCOPE)
function(copy_editor_resources SOURCE_DIR DESTINATION_DIR)
foreach(res ${EDITOR_RESOURCES})
get_filename_component(_dir "${res}" DIRECTORY)
file(MAKE_DIRECTORY "${DESTINATION_DIR}/${_dir}")
file(COPY "${SOURCE_DIR}/${res}" DESTINATION "${DESTINATION_DIR}/${_dir}")
endforeach()
endfunction()
# editor
add_library(sfizz_editor STATIC EXCLUDE_FROM_ALL
src/editor/EditIds.h
@ -14,8 +29,53 @@ add_library(sfizz_editor STATIC EXCLUDE_FROM_ALL
src/editor/EditorController.h
src/editor/GUIComponents.h
src/editor/GUIComponents.cpp
src/editor/NativeHelpers.h
src/editor/NativeHelpers.cpp
src/editor/layout/main.hpp
src/editor/utility/vstgui_after.h
src/editor/utility/vstgui_before.h)
target_include_directories(sfizz_editor PUBLIC "src")
target_link_libraries(sfizz_editor PRIVATE sfizz-vstgui)
target_link_libraries(sfizz_editor PUBLIC absl::strings)
if(APPLE)
find_library(APPLE_APPKIT_LIBRARY "AppKit")
find_library(APPLE_CORESERVICES_LIBRARY "CoreServices")
find_library(APPLE_FOUNDATION_LIBRARY "Foundation")
target_sources(sfizz_editor PRIVATE
src/editor/NativeHelpers.mm)
target_link_libraries(sfizz_editor PRIVATE
"${APPLE_APPKIT_LIBRARY}"
"${APPLE_CORESERVICES_LIBRARY}"
"${APPLE_FOUNDATION_LIBRARY}")
target_compile_options(sfizz_editor PRIVATE "-fobjc-arc")
endif()
# dependencies
if(WIN32)
#
elseif(APPLE)
#
else()
find_package(PkgConfig REQUIRED)
pkg_check_modules(sfizz-gio "gio-2.0" REQUIRED)
target_include_directories(sfizz_editor PRIVATE ${sfizz-gio_INCLUDE_DIRS})
target_link_libraries(sfizz_editor PRIVATE ${sfizz-gio_LIBRARIES})
endif()
target_include_directories(sfizz_editor PRIVATE "../src/external") # ghc::filesystem
# layout tool
if(NOT CMAKE_CROSSCOMPILING)
add_executable(layout-maker
"tools/layout-maker/sources/layout.h"
"tools/layout-maker/sources/reader.cpp"
"tools/layout-maker/sources/reader.h"
"tools/layout-maker/sources/main.cpp")
target_link_libraries(layout-maker PRIVATE absl::strings)
add_custom_command(
OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/src/editor/layout/main.hpp"
COMMAND "${CMAKE_CURRENT_BINARY_DIR}/layout-maker"
"${CMAKE_CURRENT_SOURCE_DIR}/layout/main.fl"
> "${CMAKE_CURRENT_SOURCE_DIR}/src/editor/layout/main.hpp"
DEPENDS layout-maker "${CMAKE_CURRENT_SOURCE_DIR}/layout/main.fl")
endif()

View file

@ -211,6 +211,8 @@ endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
# higher C++ requirement on Windows
set_property(TARGET sfizz-vstgui PROPERTY CXX_STANDARD 14)
# Windows 10 RS2 DDI for custom fonts
target_compile_definitions(sfizz-vstgui PRIVATE "NTDDI_VERSION=0x0A000003")
endif()
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")

344
editor/layout/main.fl Normal file
View file

@ -0,0 +1,344 @@
# data file for the Fltk User Interface Designer (fluid)
version 1.0305
header_name {.h}
code_name {.cxx}
widget_class mainView {open
xywh {410 523 800 475} type Double
class LogicalGroup visible
} {
Fl_Group {} {
comment {theme=darkTheme} open
xywh {0 0 800 110}
class LogicalGroup
} {
Fl_Group {} {open
xywh {5 4 100 101} box ROUNDED_BOX align 0
class RoundedGroup
} {
Fl_Box {} {
comment {tag=kTagFirstChangePanel+kPanelGeneral}
image {../resources/icon_white.png} xywh {7 6 96 96}
class SfizzMainButton
}
}
Fl_Group {} {open
xywh {110 5 380 100} box ROUNDED_BOX
class RoundedGroup
} {
Fl_Box {} {
label {File:}
xywh {125 15 40 25} labelsize 16
class Label
}
Fl_Box {} {
label {KS:}
xywh {125 45 40 25} labelsize 16
class Label
}
Fl_Box {} {
label {Separator 1}
xywh {120 40 355 5} box BORDER_BOX labeltype NO_LABEL
class HLine
}
Fl_Box {} {
label {Separator 2}
xywh {120 70 355 5} box BORDER_BOX labeltype NO_LABEL
class HLine
}
Fl_Box sfzFileLabel_ {
label {DefaultInstrument.sfz}
xywh {190 15 230 25} labelsize 20
class Label
}
Fl_Box {} {
label {Key switch}
xywh {190 45 230 25} labelsize 20
class Label
}
Fl_Box {} {
label {Voices:}
xywh {120 75 60 25} labelsize 12 align 24
class Label
}
Fl_Button {} {
comment {tag=kTagLoadSfzFile}
xywh {425 15 25 25} labelsize 24
class LoadFileButton
}
Fl_Button {} {
comment {tag=kTagEditSfzFile}
xywh {450 15 25 25} labelsize 24
class EditFileButton
}
Fl_Box infoVoicesLabel_ {
xywh {185 75 50 25} labelsize 12 align 16
class Label
}
Fl_Box {} {
label {Max:}
xywh {240 75 60 25} labelsize 12 align 24
class Label
}
Fl_Box numVoicesLabel_ {
xywh {305 75 50 25} labelsize 12 align 16
class Label
}
Fl_Box {} {
label {Memory:}
xywh {360 75 60 25} labelsize 12 align 24
class Label
}
Fl_Box memoryLabel_ {
xywh {425 75 50 25} labelsize 12 align 16
class Label
}
}
Fl_Group {} {open
xywh {495 5 100 100} box ROUNDED_BOX
class RoundedGroup
} {
Fl_Light_Button {} {
label SETUP
comment {tag=kTagFirstChangePanel+kPanelSettings}
xywh {510 42 70 25}
class LightButton
}
Fl_Light_Button {} {
label CC
comment {tag=kTagFirstChangePanel+kPanelControls}
xywh {510 15 70 25}
class LightButton
}
Fl_Light_Button {} {
label INFO
comment {tag=kTagFirstChangePanel+kPanelInfo}
xywh {510 69 70 25}
class LightButton
}
}
Fl_Group {} {open
xywh {600 5 195 100} box ROUNDED_BOX
class RoundedGroup
} {
Fl_Dial {} {
xywh {615 20 48 48} value 0.5 hide
class Knob48
}
Fl_Box {} {
label Center
xywh {610 70 60 25} labelsize 12 hide
class ValueLabel
}
Fl_Dial volumeSlider_ {
comment {tag=kTagSetVolume}
xywh {680 20 48 48} value 0.5
class Knob48
}
Fl_Box volumeLabel_ {
label {0.0 dB}
xywh {675 70 60 25} labelsize 12
class ValueLabel
}
Fl_Box {} {
xywh {745 20 35 70} box BORDER_BOX
class VMeter
}
}
}
Fl_Group {subPanels_[kPanelGeneral]} {
xywh {5 110 790 285} hide
class LogicalGroup
} {
Fl_Group {} {open
xywh {5 110 120 285} box ROUNDED_BOX
class RoundedGroup
} {
Fl_Box {} {
label {Curves:}
xywh {15 120 60 25} labelsize 12 align 20
class Label
}
Fl_Box {} {
label {Masters:}
xywh {15 145 60 25} labelsize 12 align 20
class Label
}
Fl_Box {} {
label {Groups:}
xywh {15 170 60 25} labelsize 12 align 20
class Label
}
Fl_Box {} {
label {Regions:}
xywh {15 195 60 25} labelsize 12 align 20
class Label
}
Fl_Box {} {
label {Samples:}
xywh {15 220 60 25} labelsize 12 align 20
class Label
}
Fl_Box infoCurvesLabel_ {
label 0
xywh {75 120 40 25} labelsize 12 align 16
class Label
}
Fl_Box infoMastersLabel_ {
label 0
xywh {75 145 40 25} labelsize 12 align 16
class Label
}
Fl_Box infoGroupsLabel_ {
label 0
xywh {75 170 40 25} labelsize 12 align 16
class Label
}
Fl_Box infoRegionsLabel_ {
label 0
xywh {75 195 40 25} labelsize 12 align 16
class Label
}
Fl_Box infoSamplesLabel_ {
label 0
xywh {75 220 40 25} labelsize 12 align 16
class Label
}
}
Fl_Group {} {open
xywh {130 110 665 280}
class LogicalGroup
} {
Fl_Box {} {
image {../resources/logo_text.png} xywh {260 125 400 250}
class SfizzLargePicture
}
}
}
Fl_Group {subPanels_[kPanelControls]} {
xywh {5 110 790 285} hide
class LogicalGroup
} {
Fl_Group {} {open
xywh {5 110 790 285} box ROUNDED_BOX
class RoundedGroup
} {
Fl_Box {} {
label {Controls not available}
xywh {5 110 790 285} labelsize 40
class Label
}
}
}
Fl_Group {subPanels_[kPanelSettings]} {open
xywh {5 110 790 285}
class LogicalGroup
} {
Fl_Group {} {
label Engine open selected
xywh {260 125 280 110} box ROUNDED_BOX labelsize 12 align 17
class TitleGroup
} {
Fl_Spinner numVoicesSlider_ {
comment {tag=kTagSetNumVoices}
xywh {285 185 60 25} labelsize 12 textsize 12
class ValueMenu
}
Fl_Box {} {
label Polyphony
xywh {275 145 80 25} labelsize 12
class ValueLabel
}
Fl_Spinner oversamplingSlider_ {
comment {tag=kTagSetOversampling}
xywh {370 185 60 25} labelsize 12 textsize 12
class ValueMenu
}
Fl_Box {} {
label Oversampling
xywh {360 145 80 25} labelsize 12
class ValueLabel
}
Fl_Box {} {
label {Preload size}
xywh {445 145 80 25} labelsize 12
class ValueLabel
}
Fl_Spinner preloadSizeSlider_ {
comment {tag=kTagSetPreloadSize}
xywh {455 185 60 25} labelsize 12 textsize 12
class ValueMenu
}
}
Fl_Group {} {
label Tuning open
xywh {205 260 390 120} box ROUNDED_BOX labelsize 12 align 17
class TitleGroup
} {
Fl_Box {} {
label {Root key}
xywh {330 280 80 25} labelsize 12
class ValueLabel
}
Fl_Spinner tuningFrequencySlider_ {
comment {tag=kTagSetTuningFrequency}
xywh {425 320 60 25} labelsize 12 textsize 12
class ValueMenu
}
Fl_Box {} {
label Frequency
xywh {415 280 80 25} labelsize 12
class ValueLabel
}
Fl_Dial stretchedTuningSlider_ {
comment {tag=kTagSetStretchedTuning}
xywh {515 305 48 48} value 0.5
class Knob48
}
Fl_Box {} {
label Stretch
xywh {500 280 80 25} labelsize 12
class ValueLabel
}
Fl_Box {} {
label {Scala file}
xywh {225 280 100 25} labelsize 12
class ValueLabel
}
Fl_Button scalaFileButton_ {
label DefaultScale
comment {tag=kTagLoadScalaFile}
xywh {225 320 100 25} labelsize 12
class ValueButton
}
Fl_Spinner scalaRootKeySlider_ {
comment {tag=kTagSetScalaRootKey}
xywh {340 320 35 25} labelsize 12 textsize 12
class ValueMenu
}
Fl_Spinner scalaRootOctaveSlider_ {
comment {tag=kTagSetScalaRootKey}
xywh {375 320 30 25} labelsize 12 textsize 12
class ValueMenu
}
}
}
Fl_Group {subPanels_[kPanelInfo]} {
xywh {5 110 790 285} hide
class LogicalGroup
} {
Fl_Group {} {open
xywh {5 110 790 285} box ROUNDED_BOX
class RoundedGroup
} {
Fl_Box {} {
label {Informative text goes here}
xywh {5 110 790 285} labelsize 40
class Label
}
}
}
Fl_Box {} {
xywh {5 400 790 70}
class Piano
}
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

BIN
editor/resources/knob.knob Normal file

Binary file not shown.

BIN
editor/resources/knob48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View file

@ -0,0 +1,252 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:export-ydpi="192"
inkscape:export-xdpi="192"
inkscape:export-filename="/home/jpc/documents/projects/sfizz/editor/resources/logo_text@2x.png"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
sodipodi:docname="logo_text.svg"
id="svg8"
version="1.1"
viewBox="0 0 105.83333 66.145836"
height="250"
width="400">
<title
id="title1469">sfizz logo</title>
<defs
id="defs2">
<linearGradient
id="linearGradient1445"
inkscape:collect="always">
<stop
id="stop1441"
offset="0"
style="stop-color:#646464;stop-opacity:1" />
<stop
id="stop1443"
offset="1"
style="stop-color:#000000;stop-opacity:1" />
</linearGradient>
<inkscape:path-effect
effect="fillet_chamfer"
id="path-effect1150"
is_visible="true"
lpeversion="1"
satellites_param="F,0,0,1,0,1,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,1,0,2 @ F,0,0,1,0,0,0,2 | F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.47797039,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.51256137,0,2 | F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.33778335,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.27944107,0,2 | F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.25554572,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.29009315,0,2"
unit="mm"
method="auto"
mode="C"
radius="1"
chamfer_steps="2"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" />
<inkscape:path-effect
hide_knots="false"
only_selected="false"
apply_with_radius="true"
apply_no_radius="true"
use_knot_distance="true"
flexible="false"
chamfer_steps="2"
radius="1"
mode="C"
method="auto"
unit="mm"
satellites_param="F,0,0,1,0,1,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,1,0,2 @ F,0,0,1,0,0,0,2 | F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.47797039,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.51256137,0,2 | F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.33778335,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.27944107,0,2 | F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.25554572,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.29009315,0,2"
lpeversion="1"
is_visible="true"
id="path-effect1136"
effect="fillet_chamfer" />
<inkscape:path-effect
hide_knots="false"
only_selected="false"
apply_with_radius="true"
apply_no_radius="true"
use_knot_distance="true"
flexible="false"
chamfer_steps="2"
radius="1"
mode="C"
method="auto"
unit="mm"
satellites_param="F,0,0,1,0,1,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,1,0,2 @ F,0,0,1,0,0,0,2 | F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.47797039,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.51256137,0,2 | F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.33778335,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.27944107,0,2 | F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.25554572,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.29009315,0,2"
lpeversion="1"
is_visible="true"
id="path-effect968"
effect="fillet_chamfer" />
<inkscape:path-effect
effect="fillet_chamfer"
id="path-effect921"
is_visible="true"
lpeversion="1"
satellites_param="F,0,0,1,0,1,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,1,0,2 @ F,0,0,1,0,0,0,2 | F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.47797039,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.51256137,0,2 | F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.33778335,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.27944107,0,2 | F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.25554572,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.29009315,0,2"
unit="mm"
method="auto"
mode="C"
radius="1"
chamfer_steps="2"
flexible="false"
use_knot_distance="true"
apply_no_radius="true"
apply_with_radius="true"
only_selected="false"
hide_knots="false" />
<inkscape:path-effect
hide_knots="false"
only_selected="false"
apply_with_radius="true"
apply_no_radius="true"
use_knot_distance="true"
flexible="false"
chamfer_steps="2"
radius="1"
mode="C"
method="auto"
unit="mm"
satellites_param="F,0,0,1,0,1,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,1,0,2 @ F,0,0,1,0,0,0,2 | F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.47797039,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.51256137,0,2 | F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.33778335,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.27944107,0,2 | F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.25554572,0,2 @ F,0,0,1,0,0,0,2 @ F,0,0,1,0,0.29009315,0,2"
lpeversion="1"
is_visible="true"
id="path-effect1183"
effect="fillet_chamfer" />
<inkscape:path-effect
end_linecap_type="zerowidth"
scale_width="1"
miter_limit="4"
linejoin_type="round"
start_linecap_type="zerowidth"
interpolator_beta="0.2"
interpolator_type="CubicBezierFit"
sort_points="true"
offset_points="0.19099662,0.36320029 | 0.41721681,0.40988822 | 0.9095762,0.070646707"
lpeversion="1"
is_visible="true"
id="path-effect1172"
effect="powerstroke" />
<clipPath
id="clipPath917"
clipPathUnits="userSpaceOnUse">
<rect
y="68.872978"
x="24.792475"
height="25.252825"
width="39.659527"
id="rect919"
style="fill:#ffffff;stroke:none;stroke-width:2;stroke-linecap:round;paint-order:markers stroke fill" />
</clipPath>
<linearGradient
gradientUnits="userSpaceOnUse"
y2="231.60674"
x2="539.22601"
y1="190.42654"
x1="539.22601"
id="linearGradient1447"
xlink:href="#linearGradient1445"
inkscape:collect="always"
gradientTransform="translate(34.589224,10.333824)" />
</defs>
<sodipodi:namedview
fit-margin-bottom="10"
fit-margin-right="10"
fit-margin-left="10"
fit-margin-top="10"
inkscape:snap-bbox-midpoints="true"
inkscape:snap-center="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:bbox-paths="true"
inkscape:snap-bbox="true"
inkscape:guide-bbox="true"
inkscape:window-maximized="1"
inkscape:window-y="27"
inkscape:window-x="0"
inkscape:window-height="1008"
inkscape:window-width="1920"
showguides="false"
inkscape:snap-global="false"
showgrid="false"
inkscape:document-rotation="0"
inkscape:current-layer="layer1"
inkscape:document-units="px"
inkscape:cy="53.822531"
inkscape:cx="17.632385"
inkscape:zoom="1"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base"
units="px">
<sodipodi:guide
id="guide899"
orientation="1,0"
position="-452.4563,176.31198" />
<sodipodi:guide
id="guide901"
orientation="0,-1"
position="-351.71366,154.32488" />
<sodipodi:guide
id="guide1008"
orientation="1,0"
position="-536.98274,156.82863" />
<sodipodi:guide
id="guide1185"
orientation="1,0"
position="-351.75629,154.33106" />
</sodipodi:namedview>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>sfizz logo</dc:title>
<dc:date>2020-05-16</dc:date>
<dc:creator>
<cc:Agent>
<dc:title>Tobiasz 'unfa' Karoń</dc:title>
</cc:Agent>
</dc:creator>
<dc:rights>
<cc:Agent>
<dc:title>CC-0</dc:title>
</cc:Agent>
</dc:rights>
<cc:license
rdf:resource="http://creativecommons.org/publicdomain/zero/1.0/" />
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/publicdomain/zero/1.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
</cc:License>
</rdf:RDF>
</metadata>
<g
transform="translate(-495.92008,-191.91875)"
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Layer 1">
<path
id="path1439"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:34.8154px;line-height:1.25;font-family:ABeeZee;-inkscape-font-specification:ABeeZee;letter-spacing:0px;word-spacing:0px;fill:url(#linearGradient1447);fill-opacity:1;stroke:none;stroke-width:0.264584"
d="m 569.95053,215.93967 h 13.61282 v 2.40226 l -9.9572,12.91651 h 10.13128 v 2.78523 h -13.99579 v -2.47189 l 9.99202,-12.91651 h -9.78313 z m -16.4328,0 h 13.61282 v 2.40226 l -9.9572,12.91651 h 10.13128 v 2.78523 h -13.99579 v -2.47189 l 9.99202,-12.91651 h -9.78313 z m -6.38378,18.104 h -3.13338 l 3.1682,-18.104 h 3.13339 z m 2.33264,-21.20257 c -0.64989,0 -1.14891,-0.18568 -1.49707,-0.55705 -0.32494,-0.39457 -0.48741,-0.84717 -0.48741,-1.3578 0,-0.74273 0.2321,-1.33459 0.69631,-1.77559 0.4642,-0.46421 1.04446,-0.69631 1.74077,-0.69631 0.64989,0 1.1373,0.19729 1.46224,0.59187 0.34815,0.37136 0.52223,0.81235 0.52223,1.32298 0,0.74273 -0.2321,1.34619 -0.6963,1.8104 -0.46421,0.441 -1.04446,0.6615 -1.74077,0.6615 z m -12.24537,3.76006 h 5.36157 l -0.48741,2.7156 h -5.36157 l -3.06376,17.23362 c -0.18568,1.02125 -0.4526,1.88003 -0.80075,2.57634 -0.34815,0.71952 -0.76594,1.29978 -1.25336,1.74077 -0.48741,0.44099 -1.04446,0.75433 -1.67114,0.94002 -0.62667,0.20889 -1.29977,0.31334 -2.01929,0.31334 -0.76594,0 -1.46225,-0.10445 -2.08892,-0.31334 -0.64989,-0.20889 -1.21854,-0.49902 -1.70596,-0.87039 l 1.25336,-2.57634 c 0.32494,0.32495 0.70791,0.58026 1.1489,0.76594 0.41779,0.18568 0.8936,0.27852 1.42744,0.27852 0.62667,0 1.16051,-0.2205 1.6015,-0.66149 0.46421,-0.44099 0.78915,-1.14891 0.97484,-2.12374 l 3.06375,-17.30325 h -2.78523 l 0.48741,-2.7156 h 2.78524 l 0.52223,-2.78523 c 0.39457,-2.13535 1.14891,-3.65562 2.263,-4.56082 1.11409,-0.92841 2.54152,-1.39262 4.28229,-1.39262 0.95162,0 1.83361,0.12766 2.64597,0.38297 0.81236,0.23211 1.54348,0.52224 2.19337,0.87039 l -1.21854,2.64597 c -0.53383,-0.27853 -1.09088,-0.53384 -1.67114,-0.76594 -0.55704,-0.23211 -1.21853,-0.34816 -1.98447,-0.34816 -0.85878,0 -1.5899,0.25531 -2.19337,0.76594 -0.60347,0.48742 -0.99804,1.25336 -1.18373,2.29782 z m -21.96217,13.36911 c 0.60347,0.53384 1.3578,0.96323 2.263,1.28817 0.92841,0.32495 1.91485,0.48742 2.95931,0.48742 1.29977,0 2.2746,-0.20889 2.92449,-0.62668 0.6731,-0.44099 1.00965,-0.99804 1.00965,-1.67114 0,-0.34815 -0.0696,-0.6731 -0.20889,-0.97483 -0.11605,-0.30173 -0.34816,-0.59186 -0.69631,-0.87039 -0.32495,-0.27852 -0.77755,-0.54544 -1.3578,-0.80075 -0.58026,-0.27852 -1.33459,-0.58025 -2.263,-0.9052 -1.71756,-0.58026 -2.99413,-1.26496 -3.8297,-2.05411 -0.83557,-0.81236 -1.25335,-1.92645 -1.25335,-3.34228 0,-0.69631 0.15087,-1.34619 0.4526,-1.94966 0.32495,-0.60347 0.77755,-1.1257 1.3578,-1.56669 0.60347,-0.46421 1.32299,-0.82397 2.15856,-1.07928 0.85878,-0.25531 1.83361,-0.38297 2.92449,-0.38297 1.18372,0 2.21658,0.12766 3.09857,0.38297 0.9052,0.2321 1.71756,0.53383 2.43708,0.9052 l -0.87039,2.57634 c -0.62667,-0.37137 -1.34619,-0.6731 -2.15855,-0.9052 -0.78915,-0.2321 -1.67114,-0.34815 -2.64597,-0.34815 -1.20693,0 -2.12374,0.24371 -2.75042,0.73112 -0.62668,0.48741 -0.94002,1.02125 -0.94002,1.60151 0,0.27852 0.0464,0.53383 0.13927,0.76594 0.11605,0.2321 0.31333,0.4526 0.59186,0.66149 0.27852,0.20889 0.64988,0.41779 1.11409,0.62668 0.46421,0.20889 1.04446,0.42938 1.74077,0.66149 1.13731,0.39457 2.10053,0.80075 2.88968,1.21854 0.78915,0.39457 1.42743,0.83557 1.91485,1.32298 0.48741,0.48742 0.83557,1.02126 1.04446,1.60151 0.20889,0.55705 0.31334,1.18372 0.31334,1.88003 0,0.81236 -0.17408,1.54348 -0.52223,2.19337 -0.34816,0.64989 -0.83558,1.20693 -1.46225,1.67114 -0.62668,0.44099 -1.39262,0.77754 -2.29782,1.00965 -0.88199,0.25531 -1.86842,0.38297 -2.95931,0.38297 -1.39261,0 -2.63436,-0.17408 -3.72524,-0.52223 -1.09089,-0.34815 -1.99609,-0.80075 -2.71561,-1.3578 z"
sodipodi:nodetypes="cccccccccccccccccccccccccccscscscscsccccccscsccccsccccccccsccccscccccscscccccscccsccccssscssccccssccsscc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because it is too large Load diff

View file

@ -5,34 +5,422 @@
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
#include "GUIComponents.h"
#include <cmath>
#include "utility/vstgui_before.h"
#include "vstgui/lib/cdrawcontext.h"
#include "vstgui/lib/cgraphicspath.h"
#include "vstgui/lib/cframe.h"
#include "utility/vstgui_after.h"
SimpleSlider::SimpleSlider(const CRect& bounds, IControlListener* listener, int32_t tag)
: CSliderBase(bounds, listener, tag)
///
SBoxContainer::SBoxContainer(const CRect& size)
: CViewContainer(size)
{
setStyle(kHorizontal|kLeft);
CPoint offsetHandle(2.0, 2.0);
setOffsetHandle(offsetHandle);
CCoord handleSize = 20.0;
setHandleSizePrivate(handleSize, bounds.bottom - bounds.top - 2 * offsetHandle.y);
setHandleRangePrivate(bounds.right - bounds.left - handleSize - 2 * offsetHandle.x);
CViewContainer::setBackgroundColor(CColor(0, 0, 0, 0));
}
void SimpleSlider::draw(CDrawContext* dc)
void SBoxContainer::setCornerRadius(CCoord radius)
{
cornerRadius_ = radius;
setDirty();
}
void SBoxContainer::setBackgroundColor(const CColor& color)
{
backgroundColor_ = color;
setDirty();
}
CColor SBoxContainer::getBackgroundColor() const
{
return backgroundColor_;
}
void SBoxContainer::drawRect(CDrawContext* dc, const CRect& updateRect)
{
CRect bounds = getViewSize();
CRect handle = calculateHandleRect(getValueNormalized());
dc->setDrawMode(kAntiAliasing);
dc->setFrameColor(_frame);
dc->drawRect(bounds, kDrawStroked);
SharedPointer<CGraphicsPath> path = owned(dc->createGraphicsPath());
path->addRoundRect(bounds, cornerRadius_);
dc->setFillColor(_fill);
dc->drawRect(handle, kDrawFilled);
dc->setFillColor(backgroundColor_);
dc->drawGraphicsPath(path.get(), CDrawContext::kPathFilled);
CViewContainer::drawRect(dc, updateRect);
}
///
STitleContainer::STitleContainer(const CRect& size, UTF8StringPtr text)
: SBoxContainer(size), text_(text ? text : ""), titleFont_(kNormalFont)
{
}
void STitleContainer::setTitleFont(CFontRef font)
{
titleFont_ = font;
setDirty();
}
void STitleContainer::setTitleFontColor(CColor color)
{
titleFontColor_ = color;
setDirty();
}
void STitleContainer::setTitleBackgroundColor(CColor color)
{
titleBackgroundColor_ = color;
setDirty();
}
void STitleContainer::drawRect(CDrawContext* dc, const CRect& updateRect)
{
SBoxContainer::drawRect(dc, updateRect);
CRect bounds = getViewSize();
CCoord cornerRadius = cornerRadius_;
dc->setDrawMode(kAntiAliasing);
CCoord fontHeight = titleFont_->getSize();
CCoord titleHeight = fontHeight + 8.0;
CRect titleBounds = bounds;
titleBounds.bottom = titleBounds.top + titleHeight;
SharedPointer<CGraphicsPath> path = owned(dc->createGraphicsPath());
path->beginSubpath(titleBounds.getBottomRight());
path->addLine(titleBounds.getBottomLeft());
path->addArc(CRect(titleBounds.left, titleBounds.top, titleBounds.left + 2.0 * cornerRadius, titleBounds.top + 2.0 * cornerRadius), 180., 270., true);
path->addArc(CRect(titleBounds.right - 2.0 * cornerRadius, titleBounds.top, titleBounds.right, titleBounds.top + 2.0 * cornerRadius), 270., 360., true);
path->closeSubpath();
dc->setFillColor(titleBackgroundColor_);
dc->drawGraphicsPath(path, CDrawContext::kPathFilled);
dc->setFont(titleFont_);
dc->setFontColor(titleFontColor_);
dc->drawString(text_.c_str(), titleBounds, kCenterText);
}
///
void SFileDropTarget::setFileDropFunction(FileDropFunction f)
{
dropFunction_ = std::move(f);
}
DragOperation SFileDropTarget::onDragEnter(DragEventData data)
{
op_ = isFileDrop(data.drag) ?
DragOperation::Copy : DragOperation::None;
return op_;
}
DragOperation SFileDropTarget::onDragMove(DragEventData data)
{
(void)data;
return op_;
}
void SFileDropTarget::onDragLeave(DragEventData data)
{
(void)data;
op_ = DragOperation::None;
}
bool SFileDropTarget::onDrop(DragEventData data)
{
if (op_ != DragOperation::Copy || !isFileDrop(data.drag))
return false;
IDataPackage::Type type;
const void* bytes;
uint32_t size = data.drag->getData(0, bytes, type);
std::string path(reinterpret_cast<const char*>(bytes), size);
if (dropFunction_)
dropFunction_(path);
return true;
}
bool SFileDropTarget::isFileDrop(IDataPackage* package)
{
return package->getCount() == 1 &&
package->getDataType(0) == IDataPackage::kFilePath;
}
///
SPiano::SPiano(const CRect& bounds)
: CView(bounds), font_(kNormalFont)
{
}
void SPiano::setFont(CFontRef font)
{
font_ = font;
setDirty();
}
void SPiano::clearKeyRanges()
{
keyInRange_.reset();
}
void SPiano::addKeyRange(int start, int end)
{
start = std::min(127, std::max(0, start));
end = std::min(127, std::max(0, end));
for (int x = start; x <= end; ++x)
keyInRange_.set(x);
}
CCoord SPiano::getKeyWidth()
{
return 6.0;
}
CCoord SPiano::getKeySwitchesHeight()
{
return 20.0;
}
CCoord SPiano::getKeyRangesHeight()
{
return 11.0;
}
CCoord SPiano::getKeysHeight() const
{
return getHeight() -
(getKeySwitchesHeight() + getKeyRangesHeight() + getOctavesHeight());
}
CCoord SPiano::getOctavesHeight() const
{
return font_->getSize();
}
void SPiano::getZoneDimensions(
CRect* pKeySwitches,
CRect* pKeyboard,
CRect* pKeyRanges,
CRect* pOctaves)
{
CRect bounds = getViewSize();
CRect keySwitches(bounds);
keySwitches.setHeight(getKeySwitchesHeight());
CRect keyboard(bounds);
keyboard.top = keySwitches.bottom;
keyboard.setHeight(getKeysHeight());
CRect keyRanges(bounds);
keyRanges.top = keyboard.bottom;
keyRanges.setHeight(getKeyRangesHeight());
CRect octaves(bounds);
octaves.top = keyRanges.bottom;
octaves.setHeight(getOctavesHeight());
// apply some paddings
keySwitches.extend(-2.0, -2.0);
keyboard.extend(-2.0, -2.0);
keyRanges.extend(-2.0, -4.0);
octaves.extend(-2.0, -2.0);
// offsets for centered keyboard
CCoord keyWidth = getKeyWidth();
CCoord offset = std::round((keyboard.getWidth() - (128.0 * keyWidth)) * 0.5);
if (offset > 0) {
keySwitches.extend(-offset, 0.0);
keyboard.extend(-offset, 0.0);
keyRanges.extend(-offset, 0.0);
octaves.extend(-offset, 0.0);
}
//
if (pKeySwitches)
*pKeySwitches = keySwitches;
if (pKeyboard)
*pKeyboard = keyboard;
if (pKeyRanges)
*pKeyRanges = keyRanges;
if (pOctaves)
*pOctaves = octaves;
}
void SPiano::draw(CDrawContext* dc)
{
CRect bounds = getViewSize();
dc->setDrawMode(kAntiAliasing);
SharedPointer<CGraphicsPath> path;
path = owned(dc->createGraphicsPath());
path->addRoundRect(bounds, 5.0);
dc->setFillColor(CColor(0xca, 0xca, 0xca));
dc->drawGraphicsPath(path, CDrawContext::kPathFilled);
//
CRect rectKeySwitches;
CRect rectKeyboard;
CRect rectKeyRanges;
CRect rectOctaves;
getZoneDimensions(&rectKeySwitches, &rectKeyboard, &rectKeyRanges, &rectOctaves);
//
path = owned(dc->createGraphicsPath());
path->addRoundRect(rectKeyboard, 1.0);
dc->setFillColor(CColor(0xff, 0xff, 0xff));
dc->drawGraphicsPath(path, CDrawContext::kPathFilled);
CCoord keyWidth = getKeyWidth();
for (int key = 0; key < 128; ++key) {
CCoord keyX = rectKeyboard.left + key * keyWidth;
int key12 = key % 12;
if (key12 == 1 || key12 == 3 ||
key12 == 6 || key12 == 8 || key12 == 10)
{
CRect blackRect(keyX, rectKeyboard.top + 2, keyX + keyWidth, rectKeyboard.bottom - 2);
path = owned(dc->createGraphicsPath());
path->addRoundRect(blackRect, 1.0);
dc->setFillColor(CColor(0x02, 0x02, 0x02));
dc->drawGraphicsPath(path, CDrawContext::kPathFilled);
}
if (key != 0 && key12 == 0) {
dc->setLineWidth(1.5);
dc->setFrameColor(CColor(0x63, 0x63, 0x63));
dc->drawLine(CPoint(keyX, rectKeyboard.top), CPoint(keyX, rectKeyboard.bottom));
}
if (key12 == 5) {
CCoord pad = rectKeyboard.getHeight() * 0.4;
dc->setLineWidth(1.0);
dc->setFrameColor(CColor(0x63, 0x63, 0x63));
dc->drawLine(CPoint(keyX, rectKeyboard.top + pad), CPoint(keyX, rectKeyboard.bottom - pad));
}
}
//
for (int rangeStart = 0; rangeStart < 128;)
{
if (!keyInRange_[rangeStart]) {
++rangeStart;
}
else {
int rangeEnd = rangeStart;
while (rangeEnd + 1 < 128 && keyInRange_[rangeEnd + 1])
++rangeEnd;
CCoord rangeStartX = rectKeyRanges.left + rangeStart * keyWidth;
CCoord rangeEndX = rectKeyRanges.left + (rangeEnd + 1.0) * keyWidth;
CRect rectRange(rangeStartX, rectKeyRanges.top, rangeEndX, rectKeyRanges.bottom);
path = owned(dc->createGraphicsPath());
path->addRoundRect(rectRange, 2.0);
dc->setFillColor(CColor(0x0f, 0x0f, 0x0f));
dc->drawGraphicsPath(path, CDrawContext::kPathFilled);
rangeStart = rangeEnd + 1;
}
}
//
for (int key = 0; key < 128; ++key) {
CCoord keyX = rectOctaves.left + key * keyWidth;
int key12 = key % 12;
if (key12 == 0) {
CRect textRect(keyX, rectOctaves.top, keyX + 12 * keyWidth, rectOctaves.bottom);
dc->setFont(font_);
dc->setFontColor(CColor(0x63, 0x63, 0x63));
dc->drawString(std::to_string(key / 12 - 1).c_str(), textRect, kLeftText);
}
}
//
}
///
SValueMenu::SValueMenu(const CRect& bounds, IControlListener* listener, int32_t tag)
: CParamDisplay(bounds), menuListener_(owned(new MenuListener(*this)))
{
setListener(listener);
setTag(tag);
}
CMenuItem* SValueMenu::addEntry(CMenuItem* item, float value, int32_t index)
{
if (index < 0 || index > getNbEntries()) {
menuItems_.emplace_back(owned(item));
menuItemValues_.emplace_back(value);
}
else
{
menuItems_.insert(menuItems_.begin() + index, owned(item));
menuItemValues_.insert(menuItemValues_.begin() + index, value);
}
return item;
}
CMenuItem* SValueMenu::addEntry(const UTF8String& title, float value, int32_t index, int32_t itemFlags)
{
if (title == "-")
return addSeparator(index);
CMenuItem* item = new CMenuItem(title, nullptr, 0, nullptr, itemFlags);
return addEntry(item, value, index);
}
CMenuItem* SValueMenu::addSeparator(int32_t index)
{
CMenuItem* item = new CMenuItem("", nullptr, 0, nullptr, CMenuItem::kSeparator);
return addEntry(item, 0.0f, index);
}
int32_t SValueMenu::getNbEntries() const
{
return static_cast<int32_t>(menuItems_.size());
}
CMouseEventResult SValueMenu::onMouseDown(CPoint& where, const CButtonState& buttons)
{
(void)where;
if (buttons & (kLButton|kRButton|kApple)) {
CFrame* frame = getFrame();
CRect bounds = getViewSize();
CPoint frameWhere = bounds.getBottomLeft();
this->localToFrame(frameWhere);
auto self = shared(this);
frame->doAfterEventProcessing([self, frameWhere]() {
if (CFrame* frame = self->getFrame()) {
SharedPointer<COptionMenu> menu = owned(new COptionMenu(CRect(), self->menuListener_, -1, nullptr, nullptr, COptionMenu::kPopupStyle));
for (const SharedPointer<CMenuItem>& item : self->menuItems_) {
menu->addEntry(item);
item->remember(); // above call does not increment refcount
}
menu->popup(frame, frameWhere + CPoint(0.0, 1.0));
}
});
return kMouseDownEventHandledButDontNeedMovedOrUpEvents;
}
return kMouseEventNotHandled;
}
void SValueMenu::onItemClicked(int32_t index)
{
float oldValue = getValue();
setValue(menuItemValues_[index]);
if (getValue() != oldValue)
valueChanged();
}

View file

@ -5,22 +5,144 @@
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
#pragma once
#include <bitset>
#include "utility/vstgui_before.h"
#include "vstgui/lib/controls/cslider.h"
#include "vstgui/lib/controls/cknob.h"
#include "vstgui/lib/controls/ctextlabel.h"
#include "vstgui/lib/controls/coptionmenu.h"
#include "vstgui/lib/cviewcontainer.h"
#include "vstgui/lib/ccolor.h"
#include "vstgui/lib/dragging.h"
#include "utility/vstgui_after.h"
using namespace VSTGUI;
class SimpleSlider : public CSliderBase {
///
class SBoxContainer : public CViewContainer {
public:
SimpleSlider(const CRect& bounds, IControlListener* listener, int32_t tag);
void draw(CDrawContext* dc) override;
explicit SBoxContainer(const CRect& size);
virtual ~SBoxContainer() {}
void setCornerRadius(CCoord radius);
void setBackgroundColor(const CColor& color) override;
CColor getBackgroundColor() const override;
CLASS_METHODS(SimpleSlider, CSliderBase)
protected:
void drawRect(CDrawContext* dc, const CRect& updateRect) override;
protected:
CCoord cornerRadius_ = 0.0;
CColor backgroundColor_;
};
///
class STitleContainer : public SBoxContainer {
public:
explicit STitleContainer(const CRect& size, UTF8StringPtr text = nullptr);
~STitleContainer() {}
void setTitleFont(CFontRef font);
CFontRef getTitleFont() { return titleFont_; }
void setTitleFontColor(CColor color);
CColor getTitleFontColor() const { return titleFontColor_; }
void setTitleBackgroundColor(CColor color);
CColor getTitleBackgroundColor() const { return titleBackgroundColor_; }
protected:
void drawRect(CDrawContext* dc, const CRect& updateRect) override;
private:
CColor _frame = CColor(0x00, 0x00, 0x00);
CColor _fill = CColor(0x00, 0x00, 0x00);
std::string text_;
CColor titleFontColor_;
CColor titleBackgroundColor_;
SharedPointer<CFontDesc> titleFont_;
};
///
class SFileDropTarget : public IDropTarget,
public NonAtomicReferenceCounted {
public:
typedef std::function<void(const std::string&)> FileDropFunction;
void setFileDropFunction(FileDropFunction f);
protected:
DragOperation onDragEnter(DragEventData data) override;
DragOperation onDragMove(DragEventData data) override;
void onDragLeave(DragEventData data) override;
bool onDrop(DragEventData data) override;
private:
static bool isFileDrop(IDataPackage* package);
private:
DragOperation op_ = DragOperation::None;
FileDropFunction dropFunction_;
};
///
class SPiano : public CView {
public:
explicit SPiano(const CRect& bounds);
CFontRef getFont() const { return font_; }
void setFont(CFontRef font);
void clearKeyRanges();
void addKeyRange(int start, int end);
protected:
static CCoord getKeyWidth();
static CCoord getKeySwitchesHeight();
static CCoord getKeyRangesHeight();
CCoord getKeysHeight() const;
CCoord getOctavesHeight() const;
void getZoneDimensions(
CRect* pKeySwitches,
CRect* pKeyboard,
CRect* pKeyRanges,
CRect* pOctaves);
void draw(CDrawContext* dc) override;
private:
SharedPointer<CFontDesc> font_;
std::bitset<128> keyInRange_;
};
///
class SValueMenu : public CParamDisplay {
public:
explicit SValueMenu(const CRect& bounds, IControlListener* listener, int32_t tag);
CMenuItem* addEntry(CMenuItem* item, float value, int32_t index = -1);
CMenuItem* addEntry(const UTF8String& title, float value, int32_t index = -1, int32_t itemFlags = CMenuItem::kNoFlags);
CMenuItem* addSeparator(int32_t index = -1);
int32_t getNbEntries() const;
protected:
CMouseEventResult onMouseDown(CPoint& where, const CButtonState& buttons);
private:
class MenuListener;
//
void onItemClicked(int32_t index);
//
CMenuItemList menuItems_;
std::vector<float> menuItemValues_;
SharedPointer<MenuListener> menuListener_;
//
class MenuListener : public IControlListener, public NonAtomicReferenceCounted {
public:
explicit MenuListener(SValueMenu& menu) : menu_(menu) {}
void valueChanged(CControl* control) override
{
menu_.onItemClicked(static_cast<int32_t>(control->getValue()));
}
private:
SValueMenu& menu_;
};
};

View file

@ -0,0 +1,50 @@
// SPDX-License-Identifier: BSD-2-Clause
// This code is part of the sfizz library and is licensed under a BSD 2-clause
// license. You should have receive a LICENSE.md file along with the code.
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
#include "NativeHelpers.h"
#if defined(_WIN32)
#include "ghc/fs_std.hpp"
#include <windows.h>
#include <cstring>
bool openFileInExternalEditor(const char *filename)
{
std::wstring path = fs::u8path(filename).wstring();
SHELLEXECUTEINFOW info;
memset(&info, 0, sizeof(info));
info.cbSize = sizeof(info);
info.fMask = SEE_MASK_CLASSNAME;
info.lpVerb = L"open";
info.lpFile = path.c_str();
info.lpClass = L"txtfile";
info.nShow = SW_SHOW;
return ShellExecuteExW(&info);
}
#elif defined(__APPLE__)
// implemented in NativeHelpers.mm
#else
#include <gio/gio.h>
bool openFileInExternalEditor(const char *filename)
{
GAppInfo* appinfo = g_app_info_get_default_for_type("text/plain", FALSE);
if (!appinfo)
return 1;
GList* files = nullptr;
GFile* file = g_file_new_for_path(filename);
files = g_list_append(files, file);
gboolean success = g_app_info_launch(appinfo, files, nullptr, nullptr);
g_object_unref(file);
g_list_free(files);
g_object_unref(appinfo);
return success == TRUE;
}
#endif

View file

@ -0,0 +1,9 @@
// SPDX-License-Identifier: BSD-2-Clause
// This code is part of the sfizz library and is licensed under a BSD 2-clause
// license. You should have receive a LICENSE.md file along with the code.
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
#pragma once
bool openFileInExternalEditor(const char *filename);

View file

@ -0,0 +1,30 @@
// SPDX-License-Identifier: BSD-2-Clause
// This code is part of the sfizz library and is licensed under a BSD 2-clause
// license. You should have receive a LICENSE.md file along with the code.
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
#include "NativeHelpers.h"
#if defined(__APPLE__)
#import <AppKit/AppKit.h>
#import <CoreServices/CoreServices.h>
#import <Foundation/Foundation.h>
bool openFileInExternalEditor(const char *fileNameUTF8)
{
BOOL wasOpened = NO;
NSURL* applicationURL = (__bridge_transfer NSURL*)LSCopyDefaultApplicationURLForContentType(
kUTTypePlainText, kLSRolesEditor, nil);
if (!applicationURL)
return false;
if ([applicationURL isFileURL]) {
NSWorkspace* workspace = [NSWorkspace sharedWorkspace];
NSString* fileName = [NSString stringWithUTF8String:fileNameUTF8];
wasOpened = [workspace openFile:fileName withApplication:[applicationURL path]];
}
return wasOpened == YES;
}
#endif

View file

@ -0,0 +1,167 @@
/* This file is generated by the layout maker tool. */
LogicalGroup* const view__0 = createLogicalGroup(CRect(0, 0, 800, 475), -1, "", kCenterText, 14);
mainView = view__0;
enterTheme(darkTheme);
LogicalGroup* const view__1 = createLogicalGroup(CRect(0, 0, 800, 110), -1, "", kCenterText, 14);
view__0->addView(view__1);
RoundedGroup* const view__2 = createRoundedGroup(CRect(5, 4, 105, 105), -1, "", kCenterText, 14);
view__1->addView(view__2);
SfizzMainButton* const view__3 = createSfizzMainButton(CRect(2, 2, 98, 98), kTagFirstChangePanel+kPanelGeneral, "", kCenterText, 14);
view__2->addView(view__3);
RoundedGroup* const view__4 = createRoundedGroup(CRect(110, 5, 490, 105), -1, "", kCenterText, 14);
view__1->addView(view__4);
Label* const view__5 = createLabel(CRect(15, 10, 55, 35), -1, "File:", kCenterText, 16);
view__4->addView(view__5);
Label* const view__6 = createLabel(CRect(15, 40, 55, 65), -1, "KS:", kCenterText, 16);
view__4->addView(view__6);
HLine* const view__7 = createHLine(CRect(10, 35, 365, 40), -1, "", kCenterText, 14);
view__4->addView(view__7);
HLine* const view__8 = createHLine(CRect(10, 65, 365, 70), -1, "", kCenterText, 14);
view__4->addView(view__8);
Label* const view__9 = createLabel(CRect(80, 10, 310, 35), -1, "DefaultInstrument.sfz", kCenterText, 20);
sfzFileLabel_ = view__9;
view__4->addView(view__9);
Label* const view__10 = createLabel(CRect(80, 40, 310, 65), -1, "Key switch", kCenterText, 20);
view__4->addView(view__10);
Label* const view__11 = createLabel(CRect(10, 70, 70, 95), -1, "Voices:", kRightText, 12);
view__4->addView(view__11);
LoadFileButton* const view__12 = createLoadFileButton(CRect(315, 10, 340, 35), kTagLoadSfzFile, "", kCenterText, 24);
view__4->addView(view__12);
EditFileButton* const view__13 = createEditFileButton(CRect(340, 10, 365, 35), kTagEditSfzFile, "", kCenterText, 24);
view__4->addView(view__13);
Label* const view__14 = createLabel(CRect(75, 70, 125, 95), -1, "", kCenterText, 12);
infoVoicesLabel_ = view__14;
view__4->addView(view__14);
Label* const view__15 = createLabel(CRect(130, 70, 190, 95), -1, "Max:", kRightText, 12);
view__4->addView(view__15);
Label* const view__16 = createLabel(CRect(195, 70, 245, 95), -1, "", kCenterText, 12);
numVoicesLabel_ = view__16;
view__4->addView(view__16);
Label* const view__17 = createLabel(CRect(250, 70, 310, 95), -1, "Memory:", kRightText, 12);
view__4->addView(view__17);
Label* const view__18 = createLabel(CRect(315, 70, 365, 95), -1, "", kCenterText, 12);
memoryLabel_ = view__18;
view__4->addView(view__18);
RoundedGroup* const view__19 = createRoundedGroup(CRect(495, 5, 595, 105), -1, "", kCenterText, 14);
view__1->addView(view__19);
LightButton* const view__20 = createLightButton(CRect(15, 37, 85, 62), kTagFirstChangePanel+kPanelSettings, "SETUP", kCenterText, 14);
view__19->addView(view__20);
LightButton* const view__21 = createLightButton(CRect(15, 10, 85, 35), kTagFirstChangePanel+kPanelControls, "CC", kCenterText, 14);
view__19->addView(view__21);
LightButton* const view__22 = createLightButton(CRect(15, 64, 85, 89), kTagFirstChangePanel+kPanelInfo, "INFO", kCenterText, 14);
view__19->addView(view__22);
RoundedGroup* const view__23 = createRoundedGroup(CRect(600, 5, 795, 105), -1, "", kCenterText, 14);
view__1->addView(view__23);
Knob48* const view__24 = createKnob48(CRect(15, 15, 63, 63), -1, "", kCenterText, 14);
view__23->addView(view__24);
view__24->setVisible(false);
ValueLabel* const view__25 = createValueLabel(CRect(10, 65, 70, 90), -1, "Center", kCenterText, 12);
view__23->addView(view__25);
view__25->setVisible(false);
Knob48* const view__26 = createKnob48(CRect(80, 15, 128, 63), kTagSetVolume, "", kCenterText, 14);
volumeSlider_ = view__26;
view__23->addView(view__26);
ValueLabel* const view__27 = createValueLabel(CRect(75, 65, 135, 90), -1, "0.0 dB", kCenterText, 12);
volumeLabel_ = view__27;
view__23->addView(view__27);
VMeter* const view__28 = createVMeter(CRect(145, 15, 180, 85), -1, "", kCenterText, 14);
view__23->addView(view__28);
enterTheme(defaultTheme);
LogicalGroup* const view__29 = createLogicalGroup(CRect(5, 110, 795, 395), -1, "", kCenterText, 14);
subPanels_[kPanelGeneral] = view__29;
view__0->addView(view__29);
view__29->setVisible(false);
RoundedGroup* const view__30 = createRoundedGroup(CRect(0, 0, 120, 285), -1, "", kCenterText, 14);
view__29->addView(view__30);
Label* const view__31 = createLabel(CRect(10, 10, 70, 35), -1, "Curves:", kLeftText, 12);
view__30->addView(view__31);
Label* const view__32 = createLabel(CRect(10, 35, 70, 60), -1, "Masters:", kLeftText, 12);
view__30->addView(view__32);
Label* const view__33 = createLabel(CRect(10, 60, 70, 85), -1, "Groups:", kLeftText, 12);
view__30->addView(view__33);
Label* const view__34 = createLabel(CRect(10, 85, 70, 110), -1, "Regions:", kLeftText, 12);
view__30->addView(view__34);
Label* const view__35 = createLabel(CRect(10, 110, 70, 135), -1, "Samples:", kLeftText, 12);
view__30->addView(view__35);
Label* const view__36 = createLabel(CRect(70, 10, 110, 35), -1, "0", kCenterText, 12);
infoCurvesLabel_ = view__36;
view__30->addView(view__36);
Label* const view__37 = createLabel(CRect(70, 35, 110, 60), -1, "0", kCenterText, 12);
infoMastersLabel_ = view__37;
view__30->addView(view__37);
Label* const view__38 = createLabel(CRect(70, 60, 110, 85), -1, "0", kCenterText, 12);
infoGroupsLabel_ = view__38;
view__30->addView(view__38);
Label* const view__39 = createLabel(CRect(70, 85, 110, 110), -1, "0", kCenterText, 12);
infoRegionsLabel_ = view__39;
view__30->addView(view__39);
Label* const view__40 = createLabel(CRect(70, 110, 110, 135), -1, "0", kCenterText, 12);
infoSamplesLabel_ = view__40;
view__30->addView(view__40);
LogicalGroup* const view__41 = createLogicalGroup(CRect(125, 0, 790, 280), -1, "", kCenterText, 14);
view__29->addView(view__41);
SfizzLargePicture* const view__42 = createSfizzLargePicture(CRect(130, 15, 530, 265), -1, "", kCenterText, 14);
view__41->addView(view__42);
LogicalGroup* const view__43 = createLogicalGroup(CRect(5, 110, 795, 395), -1, "", kCenterText, 14);
subPanels_[kPanelControls] = view__43;
view__0->addView(view__43);
view__43->setVisible(false);
RoundedGroup* const view__44 = createRoundedGroup(CRect(0, 0, 790, 285), -1, "", kCenterText, 14);
view__43->addView(view__44);
Label* const view__45 = createLabel(CRect(0, 0, 790, 285), -1, "Controls not available", kCenterText, 40);
view__44->addView(view__45);
LogicalGroup* const view__46 = createLogicalGroup(CRect(5, 110, 795, 395), -1, "", kCenterText, 14);
subPanels_[kPanelSettings] = view__46;
view__0->addView(view__46);
TitleGroup* const view__47 = createTitleGroup(CRect(255, 15, 535, 125), -1, "Engine", kCenterText, 12);
view__46->addView(view__47);
ValueMenu* const view__48 = createValueMenu(CRect(25, 60, 85, 85), kTagSetNumVoices, "", kCenterText, 12);
numVoicesSlider_ = view__48;
view__47->addView(view__48);
ValueLabel* const view__49 = createValueLabel(CRect(15, 20, 95, 45), -1, "Polyphony", kCenterText, 12);
view__47->addView(view__49);
ValueMenu* const view__50 = createValueMenu(CRect(110, 60, 170, 85), kTagSetOversampling, "", kCenterText, 12);
oversamplingSlider_ = view__50;
view__47->addView(view__50);
ValueLabel* const view__51 = createValueLabel(CRect(100, 20, 180, 45), -1, "Oversampling", kCenterText, 12);
view__47->addView(view__51);
ValueLabel* const view__52 = createValueLabel(CRect(185, 20, 265, 45), -1, "Preload size", kCenterText, 12);
view__47->addView(view__52);
ValueMenu* const view__53 = createValueMenu(CRect(195, 60, 255, 85), kTagSetPreloadSize, "", kCenterText, 12);
preloadSizeSlider_ = view__53;
view__47->addView(view__53);
TitleGroup* const view__54 = createTitleGroup(CRect(200, 150, 590, 270), -1, "Tuning", kCenterText, 12);
view__46->addView(view__54);
ValueLabel* const view__55 = createValueLabel(CRect(125, 20, 205, 45), -1, "Root key", kCenterText, 12);
view__54->addView(view__55);
ValueMenu* const view__56 = createValueMenu(CRect(220, 60, 280, 85), kTagSetTuningFrequency, "", kCenterText, 12);
tuningFrequencySlider_ = view__56;
view__54->addView(view__56);
ValueLabel* const view__57 = createValueLabel(CRect(210, 20, 290, 45), -1, "Frequency", kCenterText, 12);
view__54->addView(view__57);
Knob48* const view__58 = createKnob48(CRect(310, 45, 358, 93), kTagSetStretchedTuning, "", kCenterText, 14);
stretchedTuningSlider_ = view__58;
view__54->addView(view__58);
ValueLabel* const view__59 = createValueLabel(CRect(295, 20, 375, 45), -1, "Stretch", kCenterText, 12);
view__54->addView(view__59);
ValueLabel* const view__60 = createValueLabel(CRect(20, 20, 120, 45), -1, "Scala file", kCenterText, 12);
view__54->addView(view__60);
ValueButton* const view__61 = createValueButton(CRect(20, 60, 120, 85), kTagLoadScalaFile, "DefaultScale", kCenterText, 12);
scalaFileButton_ = view__61;
view__54->addView(view__61);
ValueMenu* const view__62 = createValueMenu(CRect(135, 60, 170, 85), kTagSetScalaRootKey, "", kCenterText, 12);
scalaRootKeySlider_ = view__62;
view__54->addView(view__62);
ValueMenu* const view__63 = createValueMenu(CRect(170, 60, 200, 85), kTagSetScalaRootKey, "", kCenterText, 12);
scalaRootOctaveSlider_ = view__63;
view__54->addView(view__63);
LogicalGroup* const view__64 = createLogicalGroup(CRect(5, 110, 795, 395), -1, "", kCenterText, 14);
subPanels_[kPanelInfo] = view__64;
view__0->addView(view__64);
view__64->setVisible(false);
RoundedGroup* const view__65 = createRoundedGroup(CRect(0, 0, 790, 285), -1, "", kCenterText, 14);
view__64->addView(view__65);
Label* const view__66 = createLabel(CRect(0, 0, 790, 285), -1, "Informative text goes here", kCenterText, 40);
view__65->addView(view__66);
Piano* const view__67 = createPiano(CRect(5, 400, 795, 470), -1, "", kCenterText, 14);
view__0->addView(view__67);

View file

@ -0,0 +1,23 @@
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

View file

@ -0,0 +1,2 @@
This purpose of this tool is to accept UI designs make with Fluid, the FLTK
design editor, and convert these designs to music plugin interfaces.

View file

@ -0,0 +1,42 @@
#pragma once
#include <vector>
#include <string>
struct LayoutImage {
std::string filepath;
int x = 0;
int y = 0;
int w = 0;
int h = 0;
};
struct LayoutItem {
std::string id;
std::string classname;
std::string label;
int x = 0;
int y = 0;
int w = 0;
int h = 0;
std::string box;
std::string down_box;
int labelfont = 0;
int labelsize = 14;
std::string labeltype;
int textsize = 14;
int align = 0;
double value = 0;
double minimum = 0;
double maximum = 0;
double step = 0;
std::string type;
std::string callback;
LayoutImage image;
bool hidden = false;
std::string comment;
std::vector<LayoutItem> items;
};
struct Layout {
std::vector<LayoutItem> items;
};

View file

@ -0,0 +1,136 @@
#include "layout.h"
#include "reader.h"
#include <absl/strings/ascii.h>
#include <absl/strings/string_view.h>
#include <unordered_map>
#include <iostream>
///
typedef std::unordered_map<std::string, std::string> Metadata;
static Metadata metadata_from_comment(absl::string_view comment)
{
Metadata md;
while (!comment.empty()) {
absl::string_view line;
size_t pos = comment.find_first_of("\r\n");
if (pos != comment.npos) {
line = comment.substr(0, pos);
comment.remove_prefix(pos + 1);
}
else {
line = comment;
comment = {};
}
line = absl::StripAsciiWhitespace(line);
if (line.empty() || line[0] == '#')
continue;
std::string key, value;
pos = line.find_first_of('=');
if (pos != comment.npos) {
key = std::string(line.substr(0, pos));
value = std::string(line.substr(pos + 1));
}
else
key = std::string(line);
md.emplace(std::move(key), std::move(value));
}
return md;
}
///
static void codegen_item(int& idCounter, int parentId, int parentX, int parentY, const LayoutItem& item, absl::string_view oldTheme)
{
const Metadata md = metadata_from_comment(item.comment);
absl::string_view tag = "-1";
absl::string_view newTheme;
Metadata::const_iterator it;
it = md.find("tag");
if (it != md.end())
tag = it->second;
it = md.find("theme");
if (it != md.end())
newTheme = it->second;
absl::string_view currentTheme = newTheme.empty() ? oldTheme : newTheme;
int id = idCounter++;
int myX = item.x;
int myY = item.y;
if (parentId == -1) {
myX = 0;
myY = 0;
}
int relX = myX - parentX;
int relY = myY - parentY;
//std::cout << "// Begin " << id << " " << item.classname << " {" << item.label << "}" << "\n";
if (!newTheme.empty())
std::cout << "enterTheme(" << newTheme << ");\n";
absl::string_view label;
if (!item.label.empty() && item.labeltype != "NO_LABEL")
label = item.label;
absl::string_view align = "kCenterText";
if (item.align & 4)
align = "kLeftText";
else if (item.align & 8)
align = "kRightText";
std::cout << item.classname << "* const view__" << id << " = create" << item.classname << "(CRect(" << relX << ", " << relY << ", " << (relX + item.w) << ", " << (relY + item.h) << "), " << tag << ", \"" << label << "\", " << align << ", " << item.labelsize << ");\n";
if (!item.id.empty())
std::cout << item.id << " = view__" << id << ";\n";
if (parentId != -1)
std::cout << "view__" << parentId << "->addView(view__" << id << ");\n";
if (item.hidden)
std::cout << "view__" << id << "->setVisible(false);\n";
for (const LayoutItem& subItem : item.items)
codegen_item(idCounter, id, myX, myY, subItem, currentTheme);
if (!newTheme.empty())
std::cout << "enterTheme(" << oldTheme << ");\n";
//std::cout << "// End " << id << " " << item.classname << " {" << item.label << "}" << "\n";
}
static void codegen_layout(const LayoutItem& item)
{
int idCounter = 0;
codegen_item(idCounter, -1, 0, 0, item, "defaultTheme");
}
///
int main(int argc, char *argv[])
{
if (argc != 2) {
std::cerr << "Please indicate a fluid design file.\n";
return 1;
}
Layout layout = read_file_layout(argv[1]);
if (layout.items.size() != 1) {
std::cerr << "There must be exactly 1 top level component.";
return 1;
}
std::cout << "/* This file is generated by the layout maker tool. */\n";
codegen_layout(layout.items[0]);
return 0;
}

View file

@ -0,0 +1,359 @@
#include "reader.h"
#include <absl/strings/string_view.h>
#include <iostream>
#include <fstream>
typedef std::vector<std::string> TokenList;
static bool read_file_tokens(const char *filename, TokenList &tokens);
static Layout read_tokens_layout(TokenList::iterator &tok_it, TokenList::iterator tok_end);
Layout read_file_layout(const char *filename)
{
std::vector<std::string> tokens;
if (!read_file_tokens(filename, tokens))
throw std::runtime_error("Cannot read fluid design file.");
TokenList::iterator tok_it = tokens.begin();
TokenList::iterator tok_end = tokens.end();
return read_tokens_layout(tok_it, tok_end);
}
static std::string consume_next_token(TokenList::iterator &tok_it, TokenList::iterator tok_end)
{
if (tok_it == tok_end)
throw file_format_error("Premature end of tokens");
return *tok_it++;
}
static bool try_consume_next_token(const char *text, TokenList::iterator &tok_it, TokenList::iterator tok_end)
{
if (tok_it == tok_end)
return false;
if (*tok_it != text)
return false;
++tok_it;
return true;
}
static void ensure_next_token(const char *text, TokenList::iterator &tok_it, TokenList::iterator tok_end)
{
std::string tok = consume_next_token(tok_it, tok_end);
if (tok != text)
throw file_format_error("Unexpected token: " + tok);
}
static std::string consume_enclosed_string(TokenList::iterator &tok_it, TokenList::iterator tok_end)
{
ensure_next_token("{", tok_it, tok_end);
unsigned depth = 1;
std::string text;
for (;;) {
std::string part = consume_next_token(tok_it, tok_end);
if (part == "}") {
if (--depth == 0)
return text;
}
else if (part == "{")
++depth;
if (!text.empty())
text.push_back(' ');
text.append(part);
}
return text;
}
static std::string consume_any_string(TokenList::iterator &tok_it, TokenList::iterator tok_end)
{
if (tok_it != tok_end && *tok_it == "{")
return consume_enclosed_string(tok_it, tok_end);
else
return consume_next_token(tok_it, tok_end);
}
static int consume_int_token(TokenList::iterator &tok_it, TokenList::iterator tok_end)
{
std::string text = consume_next_token(tok_it, tok_end);
return std::stoi(text);
}
static int consume_real_token(TokenList::iterator &tok_it, TokenList::iterator tok_end)
{
std::string text = consume_next_token(tok_it, tok_end);
return std::stod(text);
}
static void consume_image_properties(LayoutImage &image, TokenList::iterator &tok_it, TokenList::iterator tok_end)
{
for (bool have = true; have;) {
if (try_consume_next_token("xywh", tok_it, tok_end)) {
ensure_next_token("{", tok_it, tok_end);
image.x = consume_int_token(tok_it, tok_end);
image.y = consume_int_token(tok_it, tok_end);
image.w = consume_int_token(tok_it, tok_end);
image.h = consume_int_token(tok_it, tok_end);
ensure_next_token("}", tok_it, tok_end);
}
else
have = false;
}
}
// static void consume_layout_item_properties(LayoutItem &item, TokenList::iterator &tok_it, TokenList::iterator tok_end)
// {
// ensure_next_token("{", tok_it, tok_end);
// for (std::string text; (text = consume_next_token(tok_it, tok_end)) != "}";) {
// if (text == "open" || text == "selected")
// ; // skip
// else if (text == "label")
// item.label = consume_any_string(tok_it, tok_end);
// else if (text == "xywh") {
// ensure_next_token("{", tok_it, tok_end);
// item.x = consume_int_token(tok_it, tok_end);
// item.y = consume_int_token(tok_it, tok_end);
// item.w = consume_int_token(tok_it, tok_end);
// item.h = consume_int_token(tok_it, tok_end);
// ensure_next_token("}", tok_it, tok_end);
// }
// else if (text == "box")
// item.box = consume_next_token(tok_it, tok_end);
// else if (text == "labelfont")
// item.labelfont = consume_int_token(tok_it, tok_end);
// else if (text == "labelsize")
// item.labelsize = consume_int_token(tok_it, tok_end);
// else if (text == "labeltype")
// item.labeltype = consume_any_string(tok_it, tok_end);
// else if (text == "align")
// item.align = consume_int_token(tok_it, tok_end);
// else if (text == "type")
// item.type = consume_any_string(tok_it, tok_end);
// else if (text == "callback")
// item.callback = consume_any_string(tok_it, tok_end);
// else if (text == "class")
// item.classname = consume_any_string(tok_it, tok_end);
// else if (text == "minimum")
// item.minimum = consume_real_token(tok_it, tok_end);
// else if (text == "maximum")
// item.maximum = consume_real_token(tok_it, tok_end);
// else if (text == "step")
// item.step = consume_real_token(tok_it, tok_end);
// else if (text == "image") {
// item.image.filepath = consume_any_string(tok_it, tok_end);
// consume_image_properties(item.image, tok_it, tok_end);
// }
// }
// }
static void consume_layout_item_properties(LayoutItem &item, TokenList::iterator &tok_it, TokenList::iterator tok_end)
{
ensure_next_token("{", tok_it, tok_end);
for (bool have = true; have;) {
if (try_consume_next_token("open", tok_it, tok_end))
; // skip
else if (try_consume_next_token("selected", tok_it, tok_end))
; // skip
else if (try_consume_next_token("label", tok_it, tok_end))
item.label = consume_any_string(tok_it, tok_end);
else if (try_consume_next_token("xywh", tok_it, tok_end)) {
ensure_next_token("{", tok_it, tok_end);
item.x = consume_int_token(tok_it, tok_end);
item.y = consume_int_token(tok_it, tok_end);
item.w = consume_int_token(tok_it, tok_end);
item.h = consume_int_token(tok_it, tok_end);
ensure_next_token("}", tok_it, tok_end);
}
else if (try_consume_next_token("box", tok_it, tok_end))
item.box = consume_next_token(tok_it, tok_end);
else if (try_consume_next_token("down_box", tok_it, tok_end))
item.down_box = consume_next_token(tok_it, tok_end);
else if (try_consume_next_token("labelfont", tok_it, tok_end))
item.labelfont = consume_int_token(tok_it, tok_end);
else if (try_consume_next_token("labelsize", tok_it, tok_end))
item.labelsize = consume_int_token(tok_it, tok_end);
else if (try_consume_next_token("labeltype", tok_it, tok_end))
item.labeltype = consume_any_string(tok_it, tok_end);
else if (try_consume_next_token("textsize", tok_it, tok_end))
item.textsize = consume_int_token(tok_it, tok_end);
else if (try_consume_next_token("align", tok_it, tok_end))
item.align = consume_int_token(tok_it, tok_end);
else if (try_consume_next_token("type", tok_it, tok_end))
item.type = consume_any_string(tok_it, tok_end);
else if (try_consume_next_token("callback", tok_it, tok_end))
item.callback = consume_any_string(tok_it, tok_end);
else if (try_consume_next_token("class", tok_it, tok_end))
item.classname = consume_any_string(tok_it, tok_end);
else if (try_consume_next_token("value", tok_it, tok_end))
item.value = consume_real_token(tok_it, tok_end);
else if (try_consume_next_token("minimum", tok_it, tok_end))
item.minimum = consume_real_token(tok_it, tok_end);
else if (try_consume_next_token("maximum", tok_it, tok_end))
item.maximum = consume_real_token(tok_it, tok_end);
else if (try_consume_next_token("step", tok_it, tok_end))
item.step = consume_real_token(tok_it, tok_end);
else if (try_consume_next_token("image", tok_it, tok_end))
item.image.filepath = consume_any_string(tok_it, tok_end);
else if (try_consume_next_token("hide", tok_it, tok_end))
item.hidden = true;
else if (try_consume_next_token("visible", tok_it, tok_end))
/* skip */;
else if (try_consume_next_token("comment", tok_it, tok_end))
item.comment = consume_any_string(tok_it, tok_end);
else
have = false;
}
ensure_next_token("}", tok_it, tok_end);
}
static LayoutItem consume_layout_item(const std::string &classname, TokenList::iterator &tok_it, TokenList::iterator tok_end, bool anonymous = false)
{
LayoutItem item;
item.classname = classname;
if (!anonymous)
item.id = consume_any_string(tok_it, tok_end);
consume_layout_item_properties(item, tok_it, tok_end);
if (tok_it != tok_end && *tok_it == "{") {
consume_next_token(tok_it, tok_end);
for (std::string text; (text = consume_next_token(tok_it, tok_end)) != "}";) {
if (text == "decl") {
consume_any_string(tok_it, tok_end);
consume_any_string(tok_it, tok_end);
}
else if (text == "Function") {
consume_any_string(tok_it, tok_end);
consume_any_string(tok_it, tok_end);
consume_any_string(tok_it, tok_end);
}
else
item.items.push_back(consume_layout_item(text, tok_it, tok_end));
}
}
return item;
}
static Layout read_tokens_layout(TokenList::iterator &tok_it, TokenList::iterator tok_end)
{
Layout layout;
std::string version_name;
std::string header_name;
std::string code_name;
while (tok_it != tok_end) {
std::string key = consume_next_token(tok_it, tok_end);
if (key == "version")
version_name = consume_next_token(tok_it, tok_end);
else if (key == "header_name") {
ensure_next_token("{", tok_it, tok_end);
header_name = consume_next_token(tok_it, tok_end);
ensure_next_token("}", tok_it, tok_end);
}
else if (key == "code_name") {
ensure_next_token("{", tok_it, tok_end);
code_name = consume_next_token(tok_it, tok_end);
ensure_next_token("}", tok_it, tok_end);
}
else if (key == "decl") {
consume_any_string(tok_it, tok_end);
consume_any_string(tok_it, tok_end);
}
else if (key == "widget_class") {
key = consume_next_token(tok_it, tok_end);
layout.items.push_back(consume_layout_item(key, tok_it, tok_end, true));
layout.items.back().id = key;
}
else
layout.items.push_back(consume_layout_item(key, tok_it, tok_end));
}
return layout;
}
///
class tokenizer {
public:
tokenizer(
absl::string_view text,
absl::string_view dropped_delims,
absl::string_view kept_delims);
absl::string_view next();
private:
absl::string_view text_;
absl::string_view dropped_delims_;
absl::string_view kept_delims_;
};
tokenizer::tokenizer(
absl::string_view text,
absl::string_view dropped_delims,
absl::string_view kept_delims)
: text_(text), dropped_delims_(dropped_delims), kept_delims_(kept_delims)
{
}
absl::string_view tokenizer::next()
{
auto is_dropped = [this](char c) -> bool {
return dropped_delims_.find(c) != dropped_delims_.npos;
};
auto is_kept = [this](char c) -> bool {
return kept_delims_.find(c) != kept_delims_.npos;
};
auto is_delim = [this](char c) -> bool {
return dropped_delims_.find(c) != dropped_delims_.npos ||
kept_delims_.find(c) != kept_delims_.npos;
};
absl::string_view text = text_;
while (!text.empty() && is_dropped(text[0]))
text.remove_prefix(1);
if (text.empty())
return {};
size_t pos;
{
auto it = std::find_if(text.begin(), text.end(), is_delim);
if (it == text.end())
pos = text.size();
else {
pos = std::distance(text.begin(), it);
pos += is_kept(text[0]);
}
}
absl::string_view token = text.substr(0, pos);
text_ = text.substr(pos);
return token;
}
///
static bool read_file_tokens(const char *filename, TokenList &tokens)
{
std::ifstream stream(filename);
std::string line;
std::string text;
while (std::getline(stream, line)) {
if (!line.empty() && line[0] != '#') {
text.append(line);
text.push_back('\n');
}
}
if (stream.bad())
return false;
tokenizer tok(text, " \t\r\n", "{}");
absl::string_view token;
while (!(token = tok.next()).empty())
tokens.emplace_back(token);
return !stream.bad();
}

View file

@ -0,0 +1,13 @@
#pragma once
#include "layout.h"
#include <string>
#include <stdexcept>
Layout read_file_layout(const char *filename);
///
struct file_format_error : public std::runtime_error {
public:
explicit file_format_error(const std::string &reason = "Format error")
: runtime_error(reason) {}
};

View file

@ -98,10 +98,9 @@ endforeach()
if (SFIZZ_LV2_UI)
execute_process (
COMMAND "${CMAKE_COMMAND}" -E make_directory "${PROJECT_BINARY_DIR}/Contents/Resources")
foreach(res ${EDITOR_RESOURCES})
file (COPY "${CMAKE_CURRENT_SOURCE_DIR}/../editor/resources/${res}"
DESTINATION "${PROJECT_BINARY_DIR}/Contents/Resources")
endforeach()
copy_editor_resources(
"${CMAKE_CURRENT_SOURCE_DIR}/../editor/resources"
"${PROJECT_BINARY_DIR}/Contents/Resources")
endif()
# Installation

View file

@ -50,9 +50,7 @@ Name: "vst3"; Description: "VST3 plugin"; Types: full custom;
[Files]
Source: "sfizz.lv2\Contents\Binary\sfizz.dll"; Components: lv2; DestDir: "{commoncf}\LV2\sfizz.lv2\Contents\Binary"; Flags: ignoreversion
Source: "sfizz.lv2\Contents\Binary\sfizz_ui.dll"; Components: lv2; DestDir: "{commoncf}\LV2\sfizz.lv2\Contents\Binary"; Flags: ignoreversion
Source: "sfizz.lv2\Contents\Resources\DefaultInstrument.sfz"; Components: lv2; DestDir: "{commoncf}\LV2\sfizz.lv2\Contents\Resources"
Source: "sfizz.lv2\Contents\Resources\DefaultScale.scl"; Components: lv2; DestDir: "{commoncf}\LV2\sfizz.lv2\Contents\Resources"
Source: "sfizz.lv2\Contents\Resources\logo.png"; Components: lv2; DestDir: "{commoncf}\LV2\sfizz.lv2\Contents\Resources"
Source: "sfizz.lv2\Contents\Resources\*"; Components: lv2; DestDir: "{commoncf}\LV2\sfizz.lv2\Contents\Resources"
Source: "sfizz.lv2\manifest.ttl"; Components: lv2; DestDir: "{commoncf}\LV2\sfizz.lv2"
Source: "sfizz.lv2\sfizz.ttl"; Components: lv2; DestDir: "{commoncf}\LV2\sfizz.lv2"
Source: "sfizz.lv2\sfizz_ui.ttl"; Components: lv2; DestDir: "{commoncf}\LV2\sfizz.lv2"
@ -60,7 +58,7 @@ Source: "sfizz.lv2\lgpl-3.0.txt"; Components: main; DestDir: "{app}"
Source: "sfizz.lv2\LICENSE.md"; Components: main; DestDir: "{app}"
Source: "sfizz.vst3\desktop.ini"; Components: vst3; DestDir: "{commoncf}\VST3\sfizz.vst3"
Source: "sfizz.vst3\Contents\@VST3_PACKAGE_ARCHITECTURE@-win\sfizz.vst3"; Components: vst3; DestDir: "{commoncf}\VST3\sfizz.vst3\Contents\@VST3_PACKAGE_ARCHITECTURE@-win"; Flags: ignoreversion
Source: "sfizz.vst3\Contents\Resources\logo.png"; Components: vst3; DestDir: "{commoncf}\VST3\sfizz.vst3\Contents\Resources"
Source: "sfizz.vst3\Contents\Resources\*"; Components: vst3; DestDir: "{commoncf}\VST3\sfizz.vst3\Contents\Resources"
Source: "sfizz.vst3\Plugin.ico"; Components: vst3; DestDir: "{commoncf}\VST3\sfizz.vst3"
Source: "sfizz.vst3\gpl-3.0.txt"; Components: main; DestDir: "{app}"
;Source: "setup\vc_redist.x64.exe"; DestDir: {tmp}; Flags: deleteafterinstall

View file

@ -68,10 +68,9 @@ endif()
# Create the bundle (see "VST 3 Locations / Format")
execute_process (
COMMAND "${CMAKE_COMMAND}" -E make_directory "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/Resources")
foreach(res ${EDITOR_RESOURCES})
file (COPY "${CMAKE_CURRENT_SOURCE_DIR}/../editor/resources/${res}"
DESTINATION "${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/Resources")
endforeach()
copy_editor_resources(
"${CMAKE_CURRENT_SOURCE_DIR}/../editor/resources"
"${PROJECT_BINARY_DIR}/${VSTPLUGIN_BUNDLE_NAME}/Contents/Resources")
if(WIN32)
set_target_properties(${VSTPLUGIN_PRJ_NAME} PROPERTIES
SUFFIX ".vst3"