diff --git a/plugins/editor/layout/main.fl b/plugins/editor/layout/main.fl index 4492d8ce..5dd7724d 100644 --- a/plugins/editor/layout/main.fl +++ b/plugins/editor/layout/main.fl @@ -440,6 +440,22 @@ widget_class mainView {open xywh {435 220 80 25} labelsize 14 textsize 14 class ValueMenu } + Fl_Box {} { + label Zoom + xywh {555 195 95 25} labelsize 12 align 20 + class Label + } + Fl_Spinner zoomMenu_ { + comment {tag=kTagZoomMenu} + xywh {680 195 100 25} labelsize 12 textsize 12 + class OptionMenu + } + Fl_Button defaultZoomButton_ { + label {Set Default} + comment {tag=kTagSetDefaultZoom} + xywh {680 220 100 25} labelsize 12 + class ValueButton + } } } Fl_Box piano_ { diff --git a/plugins/editor/src/editor/EditIds.cpp b/plugins/editor/src/editor/EditIds.cpp index c4de6bbd..34ea4e1c 100644 --- a/plugins/editor/src/editor/EditIds.cpp +++ b/plugins/editor/src/editor/EditIds.cpp @@ -38,5 +38,7 @@ EditRange EditRange::get(EditId id) return { 0, 0, 1 }; case EditId::UIActivePanel: return { 0, 0, 255 }; + case EditId::UIZoom: + return { 100, 100, 300 }; } } diff --git a/plugins/editor/src/editor/EditIds.h b/plugins/editor/src/editor/EditIds.h index 897c7ee3..d0ab1b0e 100644 --- a/plugins/editor/src/editor/EditIds.h +++ b/plugins/editor/src/editor/EditIds.h @@ -51,6 +51,7 @@ enum class EditId : int { UINumPreloadedSamples, UINumActiveVoices, UIActivePanel, + UIZoom, // BackgroundImage, // diff --git a/plugins/editor/src/editor/Editor.cpp b/plugins/editor/src/editor/Editor.cpp index 17bd2ab3..b90cdc40 100644 --- a/plugins/editor/src/editor/Editor.cpp +++ b/plugins/editor/src/editor/Editor.cpp @@ -18,6 +18,7 @@ #include "BitArray.h" #include "Theme.h" #include "plugin/MessageUtils.h" +#include "plugin/SfizzSettings.h" #include #include #include @@ -29,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -62,6 +64,8 @@ struct Editor::Impl : EditorController::Receiver, std::string fallbackFilesDir_; bool multi_ { false }; + float zoom_ = 1.0f; + int currentKeyswitch_ = -1; std::unordered_map keyswitchNames_; @@ -106,6 +110,8 @@ struct Editor::Impl : EditorController::Receiver, kTagChooseUserFilesDir, kTagAbout, kTagThemeMenu, + kTagZoomMenu, + kTagSetDefaultZoom, kTagFirstChangePanel, kTagLastChangePanel = kTagFirstChangePanel + kNumPanels - 1, }; @@ -140,6 +146,8 @@ struct Editor::Impl : EditorController::Receiver, CTextLabel* keyswitchBadge_ = nullptr; CTextLabel* lblHover_ = nullptr; COptionMenu* themeMenu_ = nullptr; + COptionMenu* zoomMenu_ = nullptr; + STextButton* defaultZoomButton_ = nullptr; std::unique_ptr theme_; STitleContainer* userFilesGroup_ = nullptr; @@ -272,6 +280,9 @@ struct Editor::Impl : EditorController::Receiver, void onThemeChanged() override; std::vector> OnThemeChanged; + // Zoom + void setZoom(int zoom); + // Misc static std::string getUnicodeNoteName(unsigned key) { @@ -315,8 +326,14 @@ void Editor::open(CFrame& frame) getResourceBasePath().u8string().c_str()); impl.frame_ = &frame; + frame.addView(impl.mainView_.get()); + SfizzSettings settings; + int zoom = atoi(settings.load_or("default_zoom", "100").c_str()); + impl.setZoom(zoom); + fprintf(stderr, "[sfizz] zoom factor: %f\n", impl.frame_->getZoom()); + impl.frameDisabler_ = makeOwned(&frame); impl.memQueryTimer_ = makeOwned([this](CVSTGUITimer*) { @@ -1167,6 +1184,7 @@ void Editor::Impl::createFrameContents() adjustMinMaxToEditRange(freewheelingSampleQualitySlider_, EditId::FreewheelingSampleQuality); adjustMinMaxToEditRange(freewheelingOscillatorQualitySlider_, EditId::FreewheelingOscillatorQuality); adjustMinMaxToEditRange(sustainCancelsReleaseCheckbox_, EditId::SustainCancelsRelease); + adjustMinMaxToEditRange(zoomMenu_, EditId::UIZoom); for (int value : {1, 2, 4, 8, 16, 32, 64, 96, 128, 160, 192, 224, 256}) numVoicesSlider_->addEntry(std::to_string(value), value); @@ -1175,6 +1193,7 @@ void Editor::Impl::createFrameContents() int value = 1 << log2value; oversamplingSlider_->addEntry(std::to_string(value) + "x", log2value); } + oversamplingSlider_->setValueToStringFunction2( [](float value, std::string& result, CParamDisplay*) -> bool { @@ -1182,6 +1201,17 @@ void Editor::Impl::createFrameContents() return true; }); + for (int value : { 100, 125, 150, 175, 200, 225, 250, 275, 300 }) { + zoomMenu_->addEntry(std::to_string(value) + "%", value); + } + + zoomMenu_->setValueToStringFunction2( + [](float value, std::string& result, CParamDisplay*) -> bool + { + result = std::to_string(static_cast(value) * 100) + "%"; + return true; + }); + for (int log2value = 10; log2value <= 16; ++log2value) { int value = 1 << log2value; char text[256]; @@ -1978,6 +2008,29 @@ void Editor::Impl::setActivePanel(unsigned panelId) } } +void Editor::Impl::setZoom(int zoom) +{ + if (!zoomMenu_) + return; + + float zoomFactor = static_cast(zoom) / 100; + + std::vector values = + { 100, 125, 150, 175, 200, 225, 250, 275, 300 }; + + size_t pos = std::distance(values.cbegin(), + find(values.cbegin(), values.cend(), zoom)); + + if (pos < values.size()) { + zoom_ = zoomFactor; + zoomMenu_->setCurrent(pos); + frame_->setZoom(zoom_); + } else { + zoom_ = 1.0f; + zoomMenu_->setCurrent(0); + } +} + void Editor::Impl::formatLabel(CTextLabel* label, const char* fmt, ...) { va_list ap; @@ -2159,6 +2212,26 @@ void Editor::Impl::valueChanged(CControl* ctl) } break; + case kTagZoomMenu: { + std::vector values = + { 1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 2.75, 3.0 }; + + auto zoom = values.at(value); + zoom_ = zoom; +#if 0 + fprintf(stderr, "[sfizz] valueChanged: %f\n", zoom_); + // TODO: Recreate frame with the new size + frame_->setZoom(zoom_); +#endif + } break; + + case kTagSetDefaultZoom: { + SfizzSettings settings; + char zoom[64]; + sprintf(zoom, "%i", static_cast(zoom_ * 100)); + zoom[sizeof(zoom) - 1] = '\0'; + settings.store("default_zoom", zoom); + } break; default: if (tag >= kTagFirstChangePanel && tag <= kTagLastChangePanel) { int panelId = tag - kTagFirstChangePanel; diff --git a/plugins/editor/src/editor/layout/main.hpp b/plugins/editor/src/editor/layout/main.hpp index 0a1d5d3e..0aaf434e 100644 --- a/plugins/editor/src/editor/layout/main.hpp +++ b/plugins/editor/src/editor/layout/main.hpp @@ -228,16 +228,24 @@ view__49->addView(view__87); auto* const view__88 = createValueMenu(CRect(430, 110, 510, 135), kTagSetFreewheelingOscillatorQuality, "", kCenterText, 14); freewheelingOscillatorQualitySlider_ = view__88; view__49->addView(view__88); -auto* const view__89 = createPiano(CRect(0, 410, 800, 480), -1, "", kCenterText, 16); -piano_ = view__89; -view__0->addView(view__89); -auto* const view__90 = createLogicalGroup(CRect(5, 110, 795, 410), -1, "", kCenterText, 14); -subPanels_[kPanelGeneral] = view__90; -view__0->addView(view__90); -view__90->setVisible(false); +auto* const view__89 = createLabel(CRect(550, 85, 645, 110), -1, "Zoom", kLeftText, 12); +view__49->addView(view__89); +auto* const view__90 = createOptionMenu(CRect(675, 85, 775, 110), kTagZoomMenu, "", kCenterText, 12); +zoomMenu_ = view__90; +view__49->addView(view__90); +auto* const view__91 = createValueButton(CRect(675, 110, 775, 135), kTagSetDefaultZoom, "Set Default", kCenterText, 12); +defaultZoomButton_ = view__91; +view__49->addView(view__91); +auto* const view__92 = createPiano(CRect(0, 410, 800, 480), -1, "", kCenterText, 16); +piano_ = view__92; +view__0->addView(view__92); +auto* const view__93 = createLogicalGroup(CRect(5, 110, 795, 410), -1, "", kCenterText, 14); +subPanels_[kPanelGeneral] = view__93; +view__0->addView(view__93); +view__93->setVisible(false); enterPalette(invertedPalette); -auto* const view__91 = createHoverBox(CRect(5, 105, 175, 130), -1, "", kCenterText, 14); -lblHover_ = view__91; -view__0->addView(view__91); -view__91->setVisible(false); +auto* const view__94 = createHoverBox(CRect(5, 105, 175, 130), -1, "", kCenterText, 14); +lblHover_ = view__94; +view__0->addView(view__94); +view__94->setVisible(false); enterPalette(defaultPalette); diff --git a/plugins/lv2/sfizz_ui.cpp b/plugins/lv2/sfizz_ui.cpp index eb3045e2..5c974eb5 100644 --- a/plugins/lv2/sfizz_ui.cpp +++ b/plugins/lv2/sfizz_ui.cpp @@ -46,6 +46,11 @@ #include #include #include + +#ifndef LV2_UI__scaleFactor +#define LV2_UI__scaleFactor LV2_UI_PREFIX "scaleFactor" +#endif + #include #include #include @@ -113,6 +118,10 @@ struct sfizz_ui_t : EditorController, VSTGUIEditorInterface { LV2_URID patch_set_uri; LV2_URID patch_property_uri; LV2_URID patch_value_uri; +#if !defined(__APPLE__) + LV2_URID opt_scalefactor_uri; + float scale_factor = 0.0f; +#endif LV2_URID sfizz_sfz_file_uri; LV2_URID sfizz_scala_file_uri; LV2_URID sfizz_osc_blob_uri; @@ -180,6 +189,7 @@ instantiate(const LV2UI_Descriptor *descriptor, LV2_URID_Map *map = nullptr; LV2_URID_Unmap *unmap = nullptr; + const LV2_Options_Option* options = nullptr; for (const LV2_Feature *const *f = features; *f; f++) { @@ -195,6 +205,8 @@ instantiate(const LV2UI_Descriptor *descriptor, parentWindowId = (**f).data; else if (!strcmp((**f).URI, LV2_INSTANCE_ACCESS_URI)) self->plugin = (sfizz_plugin_t *)(**f).data; + else if (!strcmp((**f).URI, LV2_OPTIONS__options)) + options = (const LV2_Options_Option*)(**f).data; // scaleFactor only ATM } // The map feature is required @@ -213,6 +225,9 @@ instantiate(const LV2UI_Descriptor *descriptor, self->atom_path_uri = map->map(map->handle, LV2_ATOM__Path); self->atom_urid_uri = map->map(map->handle, LV2_ATOM__URID); self->midi_event_uri = map->map(map->handle, LV2_MIDI__MidiEvent); +#if !defined(__APPLE__) + self->opt_scalefactor_uri = map->map(map->handle, LV2_UI__scaleFactor); +#endif self->patch_get_uri = map->map(map->handle, LV2_PATCH__Get); self->patch_set_uri = map->map(map->handle, LV2_PATCH__Set); self->patch_property_uri = map->map(map->handle, LV2_PATCH__property); @@ -224,6 +239,22 @@ instantiate(const LV2UI_Descriptor *descriptor, self->sfizz_audio_level_uri = map->map(map->handle, SFIZZ__AudioLevel); self->ccmap.reset(sfizz_lv2_ccmap_create(map)); +#if !defined(__APPLE__) + if (options != nullptr) { + for (int i=0; options[i].key != 0; ++i) + { + if (options[i].key == self->opt_scalefactor_uri) { + if (options[i].type == self->atom_float_uri) { + self->scale_factor = *(const float*)options[i].value; + fprintf(stderr, "[sfizz] scale factor: %f\n", self->scale_factor); + } else { + fprintf(stderr, "[sfizz] Host provides UI scale factor but has wrong value type\n"); + } + } + } + } +#endif + // set up the resource path // * on Linux, this is determined by going 2 folders back from the SO path // name, and appending "Contents/Resources" (not overridable) @@ -281,8 +312,19 @@ instantiate(const LV2UI_Descriptor *descriptor, *widget = reinterpret_cast(uiFrame->getPlatformFrame()->getPlatformRepresentation()); +#if !defined (__APPLE__) + float scaleFactor = uiFrame->getZoom() * self->scale_factor; + uiFrame->setZoom(scaleFactor); + fprintf(stderr, "[sfizz] zoom factor: %f\n", scaleFactor); + + int width = Editor::viewWidth * scaleFactor; + int height = Editor::viewHeight * scaleFactor; +#else + int width = Editor::viewWidth; + int height = Editor::viewHeight; +#endif if (self->resize) - self->resize->ui_resize(self->resize->handle, Editor::viewWidth, Editor::viewHeight); + self->resize->ui_resize(self->resize->handle, width, height); // send a request to receive all parameters uint8_t buffer[256]; diff --git a/plugins/lv2/sfizz_ui.ttl.in b/plugins/lv2/sfizz_ui.ttl.in index a0150653..53470317 100644 --- a/plugins/lv2/sfizz_ui.ttl.in +++ b/plugins/lv2/sfizz_ui.ttl.in @@ -1,4 +1,5 @@ @prefix lv2: . +@prefix opts: . @prefix ui: . @prefix urid: . @@ -10,6 +11,7 @@ lv2:optionalFeature ui:resize ; lv2:optionalFeature ui:parent ; lv2:optionalFeature ui:touch ; + opts:supportedOption ui:scaleFactor ; lv2:requiredFeature urid:map ; lv2:requiredFeature urid:unmap ; lv2:requiredFeature .