Merge pull request #1153 from redtide/hidpi

HiDPI: handle system scale factor in LV2, custom zoom
This commit is contained in:
redtide 2023-04-09 14:00:34 +02:00 committed by GitHub
commit 289d6efc25
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 156 additions and 12 deletions

View file

@ -440,6 +440,22 @@ widget_class mainView {open
xywh {435 220 80 25} labelsize 14 textsize 14 xywh {435 220 80 25} labelsize 14 textsize 14
class ValueMenu 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_ { Fl_Box piano_ {

View file

@ -38,5 +38,7 @@ EditRange EditRange::get(EditId id)
return { 0, 0, 1 }; return { 0, 0, 1 };
case EditId::UIActivePanel: case EditId::UIActivePanel:
return { 0, 0, 255 }; return { 0, 0, 255 };
case EditId::UIZoom:
return { 100, 100, 300 };
} }
} }

View file

@ -51,6 +51,7 @@ enum class EditId : int {
UINumPreloadedSamples, UINumPreloadedSamples,
UINumActiveVoices, UINumActiveVoices,
UIActivePanel, UIActivePanel,
UIZoom,
// //
BackgroundImage, BackgroundImage,
// //

View file

@ -18,6 +18,7 @@
#include "BitArray.h" #include "BitArray.h"
#include "Theme.h" #include "Theme.h"
#include "plugin/MessageUtils.h" #include "plugin/MessageUtils.h"
#include "plugin/SfizzSettings.h"
#include <absl/strings/string_view.h> #include <absl/strings/string_view.h>
#include <absl/strings/match.h> #include <absl/strings/match.h>
#include <absl/strings/ascii.h> #include <absl/strings/ascii.h>
@ -29,6 +30,7 @@
#include <unordered_map> #include <unordered_map>
#include <algorithm> #include <algorithm>
#include <functional> #include <functional>
#include <iterator>
#include <type_traits> #include <type_traits>
#include <system_error> #include <system_error>
#include <fstream> #include <fstream>
@ -62,6 +64,8 @@ struct Editor::Impl : EditorController::Receiver,
std::string fallbackFilesDir_; std::string fallbackFilesDir_;
bool multi_ { false }; bool multi_ { false };
float zoom_ = 1.0f;
int currentKeyswitch_ = -1; int currentKeyswitch_ = -1;
std::unordered_map<unsigned, std::string> keyswitchNames_; std::unordered_map<unsigned, std::string> keyswitchNames_;
@ -106,6 +110,8 @@ struct Editor::Impl : EditorController::Receiver,
kTagChooseUserFilesDir, kTagChooseUserFilesDir,
kTagAbout, kTagAbout,
kTagThemeMenu, kTagThemeMenu,
kTagZoomMenu,
kTagSetDefaultZoom,
kTagFirstChangePanel, kTagFirstChangePanel,
kTagLastChangePanel = kTagFirstChangePanel + kNumPanels - 1, kTagLastChangePanel = kTagFirstChangePanel + kNumPanels - 1,
}; };
@ -140,6 +146,8 @@ struct Editor::Impl : EditorController::Receiver,
CTextLabel* keyswitchBadge_ = nullptr; CTextLabel* keyswitchBadge_ = nullptr;
CTextLabel* lblHover_ = nullptr; CTextLabel* lblHover_ = nullptr;
COptionMenu* themeMenu_ = nullptr; COptionMenu* themeMenu_ = nullptr;
COptionMenu* zoomMenu_ = nullptr;
STextButton* defaultZoomButton_ = nullptr;
std::unique_ptr<Theme> theme_; std::unique_ptr<Theme> theme_;
STitleContainer* userFilesGroup_ = nullptr; STitleContainer* userFilesGroup_ = nullptr;
@ -272,6 +280,9 @@ struct Editor::Impl : EditorController::Receiver,
void onThemeChanged() override; void onThemeChanged() override;
std::vector<std::function<void()>> OnThemeChanged; std::vector<std::function<void()>> OnThemeChanged;
// Zoom
void setZoom(int zoom);
// Misc // Misc
static std::string getUnicodeNoteName(unsigned key) static std::string getUnicodeNoteName(unsigned key)
{ {
@ -315,8 +326,14 @@ void Editor::open(CFrame& frame)
getResourceBasePath().u8string().c_str()); getResourceBasePath().u8string().c_str());
impl.frame_ = &frame; impl.frame_ = &frame;
frame.addView(impl.mainView_.get()); 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<SFrameDisabler>(&frame); impl.frameDisabler_ = makeOwned<SFrameDisabler>(&frame);
impl.memQueryTimer_ = makeOwned<CVSTGUITimer>([this](CVSTGUITimer*) { impl.memQueryTimer_ = makeOwned<CVSTGUITimer>([this](CVSTGUITimer*) {
@ -1167,6 +1184,7 @@ void Editor::Impl::createFrameContents()
adjustMinMaxToEditRange(freewheelingSampleQualitySlider_, EditId::FreewheelingSampleQuality); adjustMinMaxToEditRange(freewheelingSampleQualitySlider_, EditId::FreewheelingSampleQuality);
adjustMinMaxToEditRange(freewheelingOscillatorQualitySlider_, EditId::FreewheelingOscillatorQuality); adjustMinMaxToEditRange(freewheelingOscillatorQualitySlider_, EditId::FreewheelingOscillatorQuality);
adjustMinMaxToEditRange(sustainCancelsReleaseCheckbox_, EditId::SustainCancelsRelease); adjustMinMaxToEditRange(sustainCancelsReleaseCheckbox_, EditId::SustainCancelsRelease);
adjustMinMaxToEditRange(zoomMenu_, EditId::UIZoom);
for (int value : {1, 2, 4, 8, 16, 32, 64, 96, 128, 160, 192, 224, 256}) for (int value : {1, 2, 4, 8, 16, 32, 64, 96, 128, 160, 192, 224, 256})
numVoicesSlider_->addEntry(std::to_string(value), value); numVoicesSlider_->addEntry(std::to_string(value), value);
@ -1175,6 +1193,7 @@ void Editor::Impl::createFrameContents()
int value = 1 << log2value; int value = 1 << log2value;
oversamplingSlider_->addEntry(std::to_string(value) + "x", log2value); oversamplingSlider_->addEntry(std::to_string(value) + "x", log2value);
} }
oversamplingSlider_->setValueToStringFunction2( oversamplingSlider_->setValueToStringFunction2(
[](float value, std::string& result, CParamDisplay*) -> bool [](float value, std::string& result, CParamDisplay*) -> bool
{ {
@ -1182,6 +1201,17 @@ void Editor::Impl::createFrameContents()
return true; 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<int>(value) * 100) + "%";
return true;
});
for (int log2value = 10; log2value <= 16; ++log2value) { for (int log2value = 10; log2value <= 16; ++log2value) {
int value = 1 << log2value; int value = 1 << log2value;
char text[256]; 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<float>(zoom) / 100;
std::vector<int> 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, ...) void Editor::Impl::formatLabel(CTextLabel* label, const char* fmt, ...)
{ {
va_list ap; va_list ap;
@ -2159,6 +2212,26 @@ void Editor::Impl::valueChanged(CControl* ctl)
} }
break; break;
case kTagZoomMenu: {
std::vector<float> 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<int>(zoom_ * 100));
zoom[sizeof(zoom) - 1] = '\0';
settings.store("default_zoom", zoom);
} break;
default: default:
if (tag >= kTagFirstChangePanel && tag <= kTagLastChangePanel) { if (tag >= kTagFirstChangePanel && tag <= kTagLastChangePanel) {
int panelId = tag - kTagFirstChangePanel; int panelId = tag - kTagFirstChangePanel;

View file

@ -228,16 +228,24 @@ view__49->addView(view__87);
auto* const view__88 = createValueMenu(CRect(430, 110, 510, 135), kTagSetFreewheelingOscillatorQuality, "", kCenterText, 14); auto* const view__88 = createValueMenu(CRect(430, 110, 510, 135), kTagSetFreewheelingOscillatorQuality, "", kCenterText, 14);
freewheelingOscillatorQualitySlider_ = view__88; freewheelingOscillatorQualitySlider_ = view__88;
view__49->addView(view__88); view__49->addView(view__88);
auto* const view__89 = createPiano(CRect(0, 410, 800, 480), -1, "", kCenterText, 16); auto* const view__89 = createLabel(CRect(550, 85, 645, 110), -1, "Zoom", kLeftText, 12);
piano_ = view__89; view__49->addView(view__89);
view__0->addView(view__89); auto* const view__90 = createOptionMenu(CRect(675, 85, 775, 110), kTagZoomMenu, "", kCenterText, 12);
auto* const view__90 = createLogicalGroup(CRect(5, 110, 795, 410), -1, "", kCenterText, 14); zoomMenu_ = view__90;
subPanels_[kPanelGeneral] = view__90; view__49->addView(view__90);
view__0->addView(view__90); auto* const view__91 = createValueButton(CRect(675, 110, 775, 135), kTagSetDefaultZoom, "Set Default", kCenterText, 12);
view__90->setVisible(false); 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); enterPalette(invertedPalette);
auto* const view__91 = createHoverBox(CRect(5, 105, 175, 130), -1, "", kCenterText, 14); auto* const view__94 = createHoverBox(CRect(5, 105, 175, 130), -1, "", kCenterText, 14);
lblHover_ = view__91; lblHover_ = view__94;
view__0->addView(view__91); view__0->addView(view__94);
view__91->setVisible(false); view__94->setVisible(false);
enterPalette(defaultPalette); enterPalette(defaultPalette);

View file

@ -46,6 +46,11 @@
#include <lv2/patch/patch.h> #include <lv2/patch/patch.h>
#include <lv2/urid/urid.h> #include <lv2/urid/urid.h>
#include <lv2/instance-access/instance-access.h> #include <lv2/instance-access/instance-access.h>
#ifndef LV2_UI__scaleFactor
#define LV2_UI__scaleFactor LV2_UI_PREFIX "scaleFactor"
#endif
#include <ghc/fs_std.hpp> #include <ghc/fs_std.hpp>
#include <string> #include <string>
#include <memory> #include <memory>
@ -113,6 +118,10 @@ struct sfizz_ui_t : EditorController, VSTGUIEditorInterface {
LV2_URID patch_set_uri; LV2_URID patch_set_uri;
LV2_URID patch_property_uri; LV2_URID patch_property_uri;
LV2_URID patch_value_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_sfz_file_uri;
LV2_URID sfizz_scala_file_uri; LV2_URID sfizz_scala_file_uri;
LV2_URID sfizz_osc_blob_uri; LV2_URID sfizz_osc_blob_uri;
@ -180,6 +189,7 @@ instantiate(const LV2UI_Descriptor *descriptor,
LV2_URID_Map *map = nullptr; LV2_URID_Map *map = nullptr;
LV2_URID_Unmap *unmap = nullptr; LV2_URID_Unmap *unmap = nullptr;
const LV2_Options_Option* options = nullptr;
for (const LV2_Feature *const *f = features; *f; f++) for (const LV2_Feature *const *f = features; *f; f++)
{ {
@ -195,6 +205,8 @@ instantiate(const LV2UI_Descriptor *descriptor,
parentWindowId = (**f).data; parentWindowId = (**f).data;
else if (!strcmp((**f).URI, LV2_INSTANCE_ACCESS_URI)) else if (!strcmp((**f).URI, LV2_INSTANCE_ACCESS_URI))
self->plugin = (sfizz_plugin_t *)(**f).data; 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 // 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_path_uri = map->map(map->handle, LV2_ATOM__Path);
self->atom_urid_uri = map->map(map->handle, LV2_ATOM__URID); self->atom_urid_uri = map->map(map->handle, LV2_ATOM__URID);
self->midi_event_uri = map->map(map->handle, LV2_MIDI__MidiEvent); 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_get_uri = map->map(map->handle, LV2_PATCH__Get);
self->patch_set_uri = map->map(map->handle, LV2_PATCH__Set); self->patch_set_uri = map->map(map->handle, LV2_PATCH__Set);
self->patch_property_uri = map->map(map->handle, LV2_PATCH__property); 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->sfizz_audio_level_uri = map->map(map->handle, SFIZZ__AudioLevel);
self->ccmap.reset(sfizz_lv2_ccmap_create(map)); 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 // set up the resource path
// * on Linux, this is determined by going 2 folders back from the SO path // * on Linux, this is determined by going 2 folders back from the SO path
// name, and appending "Contents/Resources" (not overridable) // name, and appending "Contents/Resources" (not overridable)
@ -281,8 +312,19 @@ instantiate(const LV2UI_Descriptor *descriptor,
*widget = reinterpret_cast<LV2UI_Widget>(uiFrame->getPlatformFrame()->getPlatformRepresentation()); *widget = reinterpret_cast<LV2UI_Widget>(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) 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 // send a request to receive all parameters
uint8_t buffer[256]; uint8_t buffer[256];

View file

@ -1,4 +1,5 @@
@prefix lv2: <http://lv2plug.in/ns/lv2core#> . @prefix lv2: <http://lv2plug.in/ns/lv2core#> .
@prefix opts: <http://lv2plug.in/ns/ext/options#> .
@prefix ui: <http://lv2plug.in/ns/extensions/ui#> . @prefix ui: <http://lv2plug.in/ns/extensions/ui#> .
@prefix urid: <http://lv2plug.in/ns/ext/urid#> . @prefix urid: <http://lv2plug.in/ns/ext/urid#> .
@ -10,6 +11,7 @@
lv2:optionalFeature ui:resize ; lv2:optionalFeature ui:resize ;
lv2:optionalFeature ui:parent ; lv2:optionalFeature ui:parent ;
lv2:optionalFeature ui:touch ; lv2:optionalFeature ui:touch ;
opts:supportedOption ui:scaleFactor ;
lv2:requiredFeature urid:map ; lv2:requiredFeature urid:map ;
lv2:requiredFeature urid:unmap ; lv2:requiredFeature urid:unmap ;
lv2:requiredFeature <http://lv2plug.in/ns/ext/instance-access> . lv2:requiredFeature <http://lv2plug.in/ns/ext/instance-access> .