Pugl upstream v2 to developpull/274/head
@@ -0,0 +1,3 @@ | |||||
[submodule "dgl/src/pugl-upstream"] | |||||
path = dgl/src/pugl-upstream | |||||
url = https://github.com/DISTRHO/pugl.git |
@@ -1,15 +1,25 @@ | |||||
os: linux | |||||
dist: bionic | |||||
languages: c++ | |||||
compiler: gcc | |||||
cache: | |||||
directories: | |||||
- ${HOME}/debs | |||||
jobs: | |||||
# linux native build | |||||
- name: "Linux native" | |||||
os: linux | |||||
compiler: gcc | |||||
dist: bionic | |||||
env: | |||||
- TARGET="linux" | |||||
services: | |||||
- xvfb | |||||
before_install: | before_install: | ||||
- sh ${TRAVIS_BUILD_DIR}/.travis/before_install.sh | |||||
- bash ${TRAVIS_BUILD_DIR}/.travis/before_install.sh | |||||
install: | install: | ||||
- sh ${TRAVIS_BUILD_DIR}/.travis/install.sh | |||||
- bash ${TRAVIS_BUILD_DIR}/.travis/install.sh | |||||
script: | script: | ||||
- sh ${TRAVIS_BUILD_DIR}/.travis/script-linux.sh | |||||
#- sh ${TRAVIS_BUILD_DIR}/.travis/script-macos.sh | |||||
- sh ${TRAVIS_BUILD_DIR}/.travis/script-win32.sh | |||||
- sh ${TRAVIS_BUILD_DIR}/.travis/script-win64.sh | |||||
- make | |||||
- make -C tests |
@@ -2,6 +2,17 @@ | |||||
set -e | set -e | ||||
# Special macOS native handling | |||||
if [ "${TARGET}" = "macos" ] || [ "${TARGET}" = "macos-universal" ]; then | |||||
exit 0 | |||||
fi | |||||
if [ "${TARGET}" = "win32" ] || [ "${TARGET}" = "win64" ]; then | |||||
wget -qO- https://dl.winehq.org/wine-builds/winehq.key | sudo apt-key add - | |||||
sudo apt-add-repository -y 'deb https://dl.winehq.org/wine-builds/ubuntu/ focal main' | |||||
sudo dpkg --add-architecture i386 | |||||
fi | |||||
sudo add-apt-repository -y ppa:kxstudio-debian/kxstudio | sudo add-apt-repository -y ppa:kxstudio-debian/kxstudio | ||||
sudo add-apt-repository -y ppa:kxstudio-debian/mingw | sudo add-apt-repository -y ppa:kxstudio-debian/mingw | ||||
sudo add-apt-repository -y ppa:kxstudio-debian/toolchain | sudo add-apt-repository -y ppa:kxstudio-debian/toolchain | ||||
@@ -2,18 +2,28 @@ | |||||
set -e | set -e | ||||
sudo apt-get install -y \ | |||||
g++ \ | |||||
pkg-config \ | |||||
libcairo2-dev \ | |||||
libjack-jackd2-dev \ | |||||
liblo-dev \ | |||||
libgl1-mesa-dev \ | |||||
libx11-dev \ | |||||
mingw-w64 \ | |||||
binutils-mingw-w64-i686 \ | |||||
binutils-mingw-w64-x86-64 \ | |||||
g++-mingw-w64-i686 \ | |||||
g++-mingw-w64-x86-64 \ | |||||
# Special macOS native handling | |||||
if [ "${TARGET}" = "macos" ] || [ "${TARGET}" = "macos-universal" ]; then | |||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install cairo jack2 liblo | |||||
exit 0 | |||||
fi | |||||
# apple-x86-setup | |||||
# Special handling for caching deb archives | |||||
if [ "$(ls ${HOME}/debs | wc -l)" -ne 0 ]; then | |||||
sudo cp ${HOME}/debs/*.deb /var/cache/apt/archives/ | |||||
fi | |||||
# common | |||||
sudo apt-get install -y build-essential pkg-config | |||||
# specific | |||||
if [ "${TARGET}" = "win32" ]; then | |||||
sudo apt-get install -y binutils-mingw-w64-i686 g++-mingw-w64-i686 mingw-w64 winehq-stable | |||||
elif [ "${TARGET}" = "win64" ]; then | |||||
sudo apt-get install -y binutils-mingw-w64-x86-64 g++-mingw-w64-x86-64 mingw-w64 winehq-stable | |||||
else | |||||
sudo apt-get install -y libcairo2-dev libgl1-mesa-dev libglu1-mesa-dev libjack-jackd2-dev liblo-dev libx11-dev | |||||
fi | |||||
# Special handling for caching deb archives | |||||
sudo mv /var/cache/apt/archives/*.deb ${HOME}/debs/ |
@@ -1,5 +1,5 @@ | |||||
DISTRHO Plugin Framework (DPF) | DISTRHO Plugin Framework (DPF) | ||||
Copyright (C) 2012-2018 Filipe Coelho <falktx@falktx.com> | |||||
Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
Permission to use, copy, modify, and/or distribute this software for any purpose with | Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
or without fee is hereby granted, provided that the above copyright notice and this | or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -26,11 +26,9 @@ examples: dgl | |||||
$(MAKE) all -C examples/MidiThrough | $(MAKE) all -C examples/MidiThrough | ||||
$(MAKE) all -C examples/Parameters | $(MAKE) all -C examples/Parameters | ||||
$(MAKE) all -C examples/States | $(MAKE) all -C examples/States | ||||
ifeq ($(HAVE_CAIRO),true) | ifeq ($(HAVE_CAIRO),true) | ||||
$(MAKE) all -C examples/CairoUI | $(MAKE) all -C examples/CairoUI | ||||
endif | endif | ||||
ifneq ($(MACOS_OR_WINDOWS),true) | ifneq ($(MACOS_OR_WINDOWS),true) | ||||
# ExternalUI is WIP | # ExternalUI is WIP | ||||
$(MAKE) all -C examples/ExternalUI | $(MAKE) all -C examples/ExternalUI | ||||
@@ -54,6 +52,9 @@ else | |||||
gen: | gen: | ||||
endif | endif | ||||
tests: dgl | |||||
$(MAKE) -C tests | |||||
# -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
clean: | clean: | ||||
@@ -73,4 +74,4 @@ endif | |||||
# -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
.PHONY: dgl examples | |||||
.PHONY: dgl examples tests |
@@ -38,6 +38,9 @@ endif | |||||
ifneq (,$(findstring mingw,$(TARGET_MACHINE))) | ifneq (,$(findstring mingw,$(TARGET_MACHINE))) | ||||
WINDOWS=true | WINDOWS=true | ||||
endif | endif | ||||
ifneq (,$(findstring windows,$(TARGET_MACHINE))) | |||||
WINDOWS=true | |||||
endif | |||||
endif | endif | ||||
endif | endif | ||||
@@ -148,6 +151,9 @@ endif | |||||
ifeq ($(MACOS),true) | ifeq ($(MACOS),true) | ||||
# MacOS linker flags | # MacOS linker flags | ||||
LINK_OPTS = -fdata-sections -ffunction-sections -Wl,-dead_strip -Wl,-dead_strip_dylibs | LINK_OPTS = -fdata-sections -ffunction-sections -Wl,-dead_strip -Wl,-dead_strip_dylibs | ||||
ifneq ($(SKIP_STRIPPING),true) | |||||
LINK_OPTS += -Wl,-x | |||||
endif | |||||
else | else | ||||
# Common linker flags | # Common linker flags | ||||
LINK_OPTS = -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,-O1 -Wl,--as-needed | LINK_OPTS = -fdata-sections -ffunction-sections -Wl,--gc-sections -Wl,-O1 -Wl,--as-needed | ||||
@@ -162,10 +168,7 @@ BASE_OPTS = -O2 -ffast-math -fdata-sections -ffunction-sections | |||||
endif | endif | ||||
ifeq ($(WINDOWS),true) | ifeq ($(WINDOWS),true) | ||||
# mingw has issues with this specific optimization | |||||
# See https://github.com/falkTX/Carla/issues/696 | |||||
BASE_OPTS += -fno-rerun-cse-after-loop | |||||
# See https://github.com/falkTX/Carla/issues/855 | |||||
# Needed for windows, see https://github.com/falkTX/Carla/issues/855 | |||||
BASE_OPTS += -mstackrealign | BASE_OPTS += -mstackrealign | ||||
else | else | ||||
# Not needed for Windows | # Not needed for Windows | ||||
@@ -203,7 +206,7 @@ endif | |||||
ifeq ($(TESTBUILD),true) | ifeq ($(TESTBUILD),true) | ||||
BASE_FLAGS += -Werror -Wcast-qual -Wconversion -Wformat -Wformat-security -Wredundant-decls -Wshadow -Wstrict-overflow -fstrict-overflow -Wundef -Wwrite-strings | BASE_FLAGS += -Werror -Wcast-qual -Wconversion -Wformat -Wformat-security -Wredundant-decls -Wshadow -Wstrict-overflow -fstrict-overflow -Wundef -Wwrite-strings | ||||
BASE_FLAGS += -Wpointer-arith -Wabi -Winit-self -Wuninitialized -Wstrict-overflow=5 | |||||
BASE_FLAGS += -Wpointer-arith -Wabi=98 -Winit-self -Wuninitialized -Wstrict-overflow=5 | |||||
# BASE_FLAGS += -Wfloat-equal | # BASE_FLAGS += -Wfloat-equal | ||||
ifeq ($(CC),clang) | ifeq ($(CC),clang) | ||||
BASE_FLAGS += -Wdocumentation -Wdocumentation-unknown-command | BASE_FLAGS += -Wdocumentation -Wdocumentation-unknown-command | ||||
@@ -225,13 +228,17 @@ endif | |||||
# Check for required libraries | # Check for required libraries | ||||
HAVE_CAIRO = $(shell $(PKG_CONFIG) --exists cairo && echo true) | HAVE_CAIRO = $(shell $(PKG_CONFIG) --exists cairo && echo true) | ||||
HAVE_VULKAN = $(shell $(PKG_CONFIG) --exists vulkan && echo true) | |||||
ifeq ($(MACOS_OR_WINDOWS),true) | ifeq ($(MACOS_OR_WINDOWS),true) | ||||
HAVE_OPENGL = true | HAVE_OPENGL = true | ||||
else | else | ||||
HAVE_OPENGL = $(shell $(PKG_CONFIG) --exists gl && echo true) | HAVE_OPENGL = $(shell $(PKG_CONFIG) --exists gl && echo true) | ||||
ifneq ($(HAIKU),true) | ifneq ($(HAIKU),true) | ||||
HAVE_X11 = $(shell $(PKG_CONFIG) --exists x11 && echo true) | |||||
HAVE_X11 = $(shell $(PKG_CONFIG) --exists x11 && echo true) | |||||
HAVE_XCURSOR = $(shell $(PKG_CONFIG) --exists xcursor && echo true) | |||||
HAVE_XEXT = $(shell $(PKG_CONFIG) --exists xext && echo true) | |||||
HAVE_XRANDR = $(shell $(PKG_CONFIG) --exists xrandr && echo true) | |||||
endif | endif | ||||
endif | endif | ||||
@@ -249,7 +256,7 @@ DGL_SYSTEM_LIBS += -lbe | |||||
endif | endif | ||||
ifeq ($(MACOS),true) | ifeq ($(MACOS),true) | ||||
DGL_SYSTEM_LIBS += -framework Cocoa | |||||
DGL_SYSTEM_LIBS += -framework Cocoa -framework CoreVideo | |||||
endif | endif | ||||
ifeq ($(WINDOWS),true) | ifeq ($(WINDOWS),true) | ||||
@@ -258,8 +265,21 @@ endif | |||||
ifneq ($(HAIKU_OR_MACOS_OR_WINDOWS),true) | ifneq ($(HAIKU_OR_MACOS_OR_WINDOWS),true) | ||||
ifeq ($(HAVE_X11),true) | ifeq ($(HAVE_X11),true) | ||||
DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags x11) | |||||
DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags x11) -DHAVE_X11 | |||||
DGL_SYSTEM_LIBS += $(shell $(PKG_CONFIG) --libs x11) | DGL_SYSTEM_LIBS += $(shell $(PKG_CONFIG) --libs x11) | ||||
ifeq ($(HAVE_XCURSOR),true) | |||||
# TODO -DHAVE_XCURSOR | |||||
DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags xcursor) | |||||
DGL_SYSTEM_LIBS += $(shell $(PKG_CONFIG) --libs xcursor) | |||||
endif | |||||
ifeq ($(HAVE_XEXT),true) | |||||
DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags xext) -DHAVE_XEXT -DHAVE_XSYNC | |||||
DGL_SYSTEM_LIBS += $(shell $(PKG_CONFIG) --libs xext) | |||||
endif | |||||
ifeq ($(HAVE_XRANDR),true) | |||||
DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags xrandr) -DHAVE_XRANDR | |||||
DGL_SYSTEM_LIBS += $(shell $(PKG_CONFIG) --libs xrandr) | |||||
endif | |||||
endif | endif | ||||
endif | endif | ||||
@@ -307,6 +327,31 @@ HAVE_CAIRO_OR_OPENGL = true | |||||
endif | endif | ||||
# --------------------------------------------------------------------------------------------------------------------- | |||||
# Set Stub specific stuff | |||||
ifeq ($(HAIKU_OR_MACOS_OR_WINDOWS),true) | |||||
HAVE_STUB = true | |||||
else | |||||
HAVE_STUB = $(HAVE_X11) | |||||
endif | |||||
# --------------------------------------------------------------------------------------------------------------------- | |||||
# Set Vulkan specific stuff | |||||
ifeq ($(HAVE_VULKAN),true) | |||||
DGL_FLAGS += -DHAVE_VULKAN | |||||
VULKAN_FLAGS = $(shell $(PKG_CONFIG) --cflags vulkan) | |||||
VULKAN_LIBS = $(shell $(PKG_CONFIG) --libs vulkan) | |||||
ifneq ($(WINDOWS),true) | |||||
VULKAN_LIBS += -ldl | |||||
endif | |||||
endif | |||||
# --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
# Set optional libraries specific stuff | # Set optional libraries specific stuff | ||||
@@ -320,6 +365,19 @@ LIBLO_FLAGS = $(shell $(PKG_CONFIG) --cflags liblo) | |||||
LIBLO_LIBS = $(shell $(PKG_CONFIG) --libs liblo) | LIBLO_LIBS = $(shell $(PKG_CONFIG) --libs liblo) | ||||
endif | endif | ||||
# --------------------------------------------------------------------------------------------------------------------- | |||||
# Backwards-compatible HAVE_DGL | |||||
ifeq ($(MACOS_OR_WINDOWS),true) | |||||
HAVE_DGL = true | |||||
else ifeq ($(HAVE_OPENGL),true) | |||||
ifeq ($(HAIKU),true) | |||||
HAVE_DGL = true | |||||
else | |||||
HAVE_DGL = $(HAVE_X11) | |||||
endif | |||||
endif | |||||
# --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
# Set app extension | # Set app extension | ||||
@@ -55,6 +55,10 @@ endif | |||||
OBJS_DSP = $(FILES_DSP:%=$(BUILD_DIR)/%.o) | OBJS_DSP = $(FILES_DSP:%=$(BUILD_DIR)/%.o) | ||||
OBJS_UI = $(FILES_UI:%=$(BUILD_DIR)/%.o) | OBJS_UI = $(FILES_UI:%=$(BUILD_DIR)/%.o) | ||||
ifeq ($(MACOS),true) | |||||
OBJS_UI += $(BUILD_DIR)/DistrhoUI_macOS_$(NAME).mm.o | |||||
endif | |||||
# --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
# Set plugin binary file targets | # Set plugin binary file targets | ||||
@@ -67,10 +71,22 @@ lv2_dsp = $(TARGET_DIR)/$(NAME).lv2/$(NAME)_dsp$(LIB_EXT) | |||||
lv2_ui = $(TARGET_DIR)/$(NAME).lv2/$(NAME)_ui$(LIB_EXT) | lv2_ui = $(TARGET_DIR)/$(NAME).lv2/$(NAME)_ui$(LIB_EXT) | ||||
vst = $(TARGET_DIR)/$(NAME)-vst$(LIB_EXT) | vst = $(TARGET_DIR)/$(NAME)-vst$(LIB_EXT) | ||||
# --------------------------------------------------------------------------------------------------------------------- | |||||
# Set plugin symbols to export | |||||
ifeq ($(MACOS),true) | |||||
SYMBOLS_LADSPA = -Wl,-exported_symbol,_ladspa_descriptor | |||||
SYMBOLS_DSSI = -Wl,-exported_symbol,_ladspa_descriptor -Wl,-exported_symbol,_dssi_descriptor | |||||
SYMBOLS_LV2 = -Wl,-exported_symbol,_lv2_descriptor -Wl,-exported_symbol,_lv2_generate_ttl | |||||
SYMBOLS_LV2UI = -Wl,-exported_symbol,_lv2ui_descriptor | |||||
SYMBOLS_VST2 = -Wl,-exported_symbol,_VSTPluginMain | |||||
endif | |||||
# --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
# Handle UI stuff, disable UI support automatically | # Handle UI stuff, disable UI support automatically | ||||
ifeq ($(FILES_UI),) | ifeq ($(FILES_UI),) | ||||
HAVE_DGL = false | |||||
UI_TYPE = none | UI_TYPE = none | ||||
endif | endif | ||||
@@ -102,11 +118,32 @@ HAVE_DGL = false | |||||
endif | endif | ||||
endif | endif | ||||
ifeq ($(UI_TYPE),vulkan) | |||||
ifeq ($(HAVE_VULKAN),true) | |||||
DGL_FLAGS += -DDGL_VULKAN | |||||
DGL_FLAGS += $(VULKAN_FLAGS) | |||||
DGL_LIBS += $(VULKAN_LIBS) | |||||
DGL_LIB = $(DPF_PATH)/build/libdgl-vulkan.a | |||||
HAVE_DGL = true | |||||
else | |||||
HAVE_DGL = false | |||||
endif | |||||
endif | |||||
ifeq ($(UI_TYPE),external) | ifeq ($(UI_TYPE),external) | ||||
DGL_FLAGS += -DDGL_EXTERNAL | DGL_FLAGS += -DDGL_EXTERNAL | ||||
HAVE_DGL = true | HAVE_DGL = true | ||||
endif | endif | ||||
ifeq ($(UI_TYPE),stub) | |||||
ifeq ($(HAVE_STUB),true) | |||||
DGL_LIB = $(DPF_PATH)/build/libdgl-stub.a | |||||
HAVE_DGL = true | |||||
else | |||||
HAVE_DGL = false | |||||
endif | |||||
endif | |||||
DGL_LIBS += $(DGL_SYSTEM_LIBS) -lm | DGL_LIBS += $(DGL_SYSTEM_LIBS) -lm | ||||
ifneq ($(HAVE_DGL),true) | ifneq ($(HAVE_DGL),true) | ||||
@@ -131,6 +168,11 @@ all: | |||||
# --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
# Common | # Common | ||||
$(BUILD_DIR)/%.S.o: %.S | |||||
-@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | |||||
@echo "Compiling $<" | |||||
@$(CC) $< $(BUILD_C_FLAGS) -c -o $@ | |||||
$(BUILD_DIR)/%.c.o: %.c | $(BUILD_DIR)/%.c.o: %.c | ||||
-@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | ||||
@echo "Compiling $<" | @echo "Compiling $<" | ||||
@@ -162,6 +204,11 @@ $(BUILD_DIR)/DistrhoUIMain_%.cpp.o: $(DPF_PATH)/distrho/DistrhoUIMain.cpp | |||||
@echo "Compiling DistrhoUIMain.cpp ($*)" | @echo "Compiling DistrhoUIMain.cpp ($*)" | ||||
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -DDISTRHO_PLUGIN_TARGET_$* -c -o $@ | $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -DDISTRHO_PLUGIN_TARGET_$* -c -o $@ | ||||
$(BUILD_DIR)/DistrhoUI_macOS_%.mm.o: $(DPF_PATH)/distrho/DistrhoUI_macOS.mm | |||||
-@mkdir -p $(BUILD_DIR) | |||||
@echo "Compiling DistrhoUI_macOS.mm ($*)" | |||||
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -DPUGL_NAMESPACE=$* -DGL_SILENCE_DEPRECATION -Wno-deprecated-declarations -I$(DPF_PATH)/dgl/src -I$(DPF_PATH)/dgl/src/pugl-upstream/include -ObjC++ -c -o $@ | |||||
$(BUILD_DIR)/DistrhoPluginMain_JACK.cpp.o: $(DPF_PATH)/distrho/DistrhoPluginMain.cpp | $(BUILD_DIR)/DistrhoPluginMain_JACK.cpp.o: $(DPF_PATH)/distrho/DistrhoPluginMain.cpp | ||||
-@mkdir -p $(BUILD_DIR) | -@mkdir -p $(BUILD_DIR) | ||||
@echo "Compiling DistrhoPluginMain.cpp (JACK)" | @echo "Compiling DistrhoPluginMain.cpp (JACK)" | ||||
@@ -194,7 +241,7 @@ ladspa: $(ladspa_dsp) | |||||
$(ladspa_dsp): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_LADSPA.cpp.o | $(ladspa_dsp): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_LADSPA.cpp.o | ||||
-@mkdir -p $(shell dirname $@) | -@mkdir -p $(shell dirname $@) | ||||
@echo "Creating LADSPA plugin for $(NAME)" | @echo "Creating LADSPA plugin for $(NAME)" | ||||
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(SHARED) -o $@ | |||||
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(SHARED) $(SYMBOLS_LADSPA) -o $@ | |||||
# --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
# DSSI | # DSSI | ||||
@@ -206,7 +253,7 @@ dssi_ui: $(dssi_ui) | |||||
$(dssi_dsp): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_DSSI.cpp.o | $(dssi_dsp): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_DSSI.cpp.o | ||||
-@mkdir -p $(shell dirname $@) | -@mkdir -p $(shell dirname $@) | ||||
@echo "Creating DSSI plugin library for $(NAME)" | @echo "Creating DSSI plugin library for $(NAME)" | ||||
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(SHARED) -o $@ | |||||
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(SHARED) $(SYMBOLS_DSSI) -o $@ | |||||
$(dssi_ui): $(OBJS_UI) $(BUILD_DIR)/DistrhoUIMain_DSSI.cpp.o $(DGL_LIB) | $(dssi_ui): $(OBJS_UI) $(BUILD_DIR)/DistrhoUIMain_DSSI.cpp.o $(DGL_LIB) | ||||
-@mkdir -p $(shell dirname $@) | -@mkdir -p $(shell dirname $@) | ||||
@@ -223,17 +270,17 @@ lv2_sep: $(lv2_dsp) $(lv2_ui) | |||||
$(lv2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.o $(DGL_LIB) | $(lv2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.o $(DGL_LIB) | ||||
-@mkdir -p $(shell dirname $@) | -@mkdir -p $(shell dirname $@) | ||||
@echo "Creating LV2 plugin for $(NAME)" | @echo "Creating LV2 plugin for $(NAME)" | ||||
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(SHARED) -o $@ | |||||
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_LV2) $(SYMBOLS_LV2UI) -o $@ | |||||
$(lv2_dsp): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o | $(lv2_dsp): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o | ||||
-@mkdir -p $(shell dirname $@) | -@mkdir -p $(shell dirname $@) | ||||
@echo "Creating LV2 plugin library for $(NAME)" | @echo "Creating LV2 plugin library for $(NAME)" | ||||
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(SHARED) -o $@ | |||||
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(SHARED) $(SYMBOLS_LV2) -o $@ | |||||
$(lv2_ui): $(OBJS_UI) $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.o $(DGL_LIB) | $(lv2_ui): $(OBJS_UI) $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.o $(DGL_LIB) | ||||
-@mkdir -p $(shell dirname $@) | -@mkdir -p $(shell dirname $@) | ||||
@echo "Creating LV2 plugin UI for $(NAME)" | @echo "Creating LV2 plugin UI for $(NAME)" | ||||
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(SHARED) -o $@ | |||||
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_LV2UI) -o $@ | |||||
# --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
# VST | # VST | ||||
@@ -247,7 +294,7 @@ $(vst): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_VST.cpp.o | |||||
endif | endif | ||||
-@mkdir -p $(shell dirname $@) | -@mkdir -p $(shell dirname $@) | ||||
@echo "Creating VST plugin for $(NAME)" | @echo "Creating VST plugin for $(NAME)" | ||||
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(SHARED) -o $@ | |||||
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_VST2) -o $@ | |||||
# --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -21,22 +21,15 @@ | |||||
START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
// ----------------------------------------------------------------------- | |||||
// Forward class names | |||||
class Window; | |||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
/** | /** | ||||
Base DGL Application class. | Base DGL Application class. | ||||
One application instance is required for creating a window. | One application instance is required for creating a window. | ||||
There's no single/global application instance in DGL, and multiple | |||||
windows can share the same app instance. | |||||
There's no single/global application instance in DGL, and multiple windows can share the same app instance. | |||||
In standalone mode an application will automatically quit its | |||||
event-loop when all its windows are closed. | |||||
In standalone mode an application will automatically quit its event-loop when all its windows are closed. | |||||
*/ | */ | ||||
class Application | class Application | ||||
{ | { | ||||
@@ -44,7 +37,8 @@ public: | |||||
/** | /** | ||||
Constructor. | Constructor. | ||||
*/ | */ | ||||
Application(); | |||||
// NOTE: the default value is not yet passed, so we catch where we use this | |||||
Application(bool isStandalone = true); | |||||
/** | /** | ||||
Destructor. | Destructor. | ||||
@@ -62,11 +56,12 @@ public: | |||||
idle() is called at regular intervals. | idle() is called at regular intervals. | ||||
@note This function is meant for standalones only, *never* call this from plugins. | @note This function is meant for standalones only, *never* call this from plugins. | ||||
*/ | */ | ||||
void exec(int idleTime = 10); | |||||
void exec(uint idleTimeInMs = 10); | |||||
/** | /** | ||||
Quit the application. | Quit the application. | ||||
This stops the event-loop and closes all Windows. | This stops the event-loop and closes all Windows. | ||||
@note This function is meant for standalones only, *never* call this from plugins. | |||||
*/ | */ | ||||
void quit(); | void quit(); | ||||
@@ -76,6 +71,30 @@ public: | |||||
*/ | */ | ||||
bool isQuiting() const noexcept; | bool isQuiting() const noexcept; | ||||
/** | |||||
Add a callback function to be triggered on every idle cycle. | |||||
You can add more than one, and remove them at anytime with removeIdleCallback(). | |||||
Idle callbacks trigger right after OS event handling and Window idle events (within the same cycle). | |||||
There are no guarantees in terms of timing. | |||||
*/ | |||||
void addIdleCallback(IdleCallback* callback); | |||||
/** | |||||
Remove an idle callback previously added via addIdleCallback(). | |||||
*/ | |||||
void removeIdleCallback(IdleCallback* callback); | |||||
/** | |||||
Set the class name of the application. | |||||
This is a stable identifier for the application, used as the window class/instance name on X11 and Windows. | |||||
It is not displayed to the user, but can be used in scripts and by window managers, | |||||
so it should be the same for every instance of the application, but different from other applications. | |||||
Plugins created with DPF have their class name automatically set based on DGL_NAMESPACE and plugin name. | |||||
*/ | |||||
void setClassName(const char* name); | |||||
private: | private: | ||||
struct PrivateData; | struct PrivateData; | ||||
PrivateData* const pData; | PrivateData* const pData; | ||||
@@ -84,7 +103,7 @@ private: | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Application) | DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Application) | ||||
}; | }; | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
END_NAMESPACE_DGL | END_NAMESPACE_DGL | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -20,7 +20,7 @@ | |||||
#include "../distrho/extra/LeakDetector.hpp" | #include "../distrho/extra/LeakDetector.hpp" | ||||
#include "../distrho/extra/ScopedPointer.hpp" | #include "../distrho/extra/ScopedPointer.hpp" | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// Define namespace | // Define namespace | ||||
#ifndef DGL_NAMESPACE | #ifndef DGL_NAMESPACE | ||||
@@ -33,33 +33,46 @@ | |||||
START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// Base DGL enums | // Base DGL enums | ||||
/** | |||||
Convenience symbols for ASCII control characters. | |||||
*/ | |||||
enum Char { | |||||
kCharBackspace = 0x08, | |||||
kCharEscape = 0x1B, | |||||
kCharDelete = 0x7F | |||||
}; | |||||
/** | /** | ||||
Keyboard modifier flags. | Keyboard modifier flags. | ||||
*/ | */ | ||||
enum Modifier { | enum Modifier { | ||||
kModifierShift = 1 << 0, /**< Shift key */ | |||||
kModifierControl = 1 << 1, /**< Control key */ | |||||
kModifierAlt = 1 << 2, /**< Alt/Option key */ | |||||
kModifierSuper = 1 << 3 /**< Mod4/Command/Windows key */ | |||||
kModifierShift = 1u << 0u, ///< Shift key | |||||
kModifierControl = 1u << 1u, ///< Control key | |||||
kModifierAlt = 1u << 2u, ///< Alt/Option key | |||||
kModifierSuper = 1u << 3u ///< Mod4/Command/Windows key | |||||
}; | }; | ||||
/** | /** | ||||
Special (non-Unicode) keyboard keys. | |||||
Keyboard key codepoints. | |||||
All keys are identified by a Unicode code point in PuglEventKey::key. This | |||||
enumeration defines constants for special keys that do not have a standard | |||||
code point, and some convenience constants for control characters. Note | |||||
that all keys are handled in the same way, this enumeration is just for | |||||
convenience when writing hard-coded key bindings. | |||||
Keys that do not have a standard code point use values in the Private Use | |||||
Area in the Basic Multilingual Plane (`U+E000` to `U+F8FF`). Applications | |||||
must take care to not interpret these values beyond key detection, the | |||||
mapping used here is arbitrary and specific to DPF. | |||||
*/ | */ | ||||
enum Key { | enum Key { | ||||
kKeyF1 = 1, | |||||
// Convenience symbols for ASCII control characters | |||||
kKeyBackspace = 0x08, | |||||
kKeyEscape = 0x1B, | |||||
kKeyDelete = 0x7F, | |||||
// Backwards compatibility with old DPF | |||||
kCharBackspace DISTRHO_DEPRECATED_BY("kKeyBackspace") = kKeyBackspace, | |||||
kCharEscape DISTRHO_DEPRECATED_BY("kKeyEscape") = kKeyEscape, | |||||
kCharDelete DISTRHO_DEPRECATED_BY("kKeyDelete") = kKeyDelete, | |||||
// Unicode Private Use Area | |||||
kKeyF1 = 0xE000, | |||||
kKeyF2, | kKeyF2, | ||||
kKeyF3, | kKeyF3, | ||||
kKeyF4, | kKeyF4, | ||||
@@ -81,30 +94,75 @@ enum Key { | |||||
kKeyEnd, | kKeyEnd, | ||||
kKeyInsert, | kKeyInsert, | ||||
kKeyShift, | kKeyShift, | ||||
kKeyShiftL = kKeyShift, | |||||
kKeyShiftR, | |||||
kKeyControl, | kKeyControl, | ||||
kKeyControlL = kKeyControl, | |||||
kKeyControlR, | |||||
kKeyAlt, | kKeyAlt, | ||||
kKeySuper | |||||
kKeyAltL = kKeyAlt, | |||||
kKeyAltR, | |||||
kKeySuper, | |||||
kKeySuperL = kKeySuper, | |||||
kKeySuperR, | |||||
kKeyMenu, | |||||
kKeyCapsLock, | |||||
kKeyScrollLock, | |||||
kKeyNumLock, | |||||
kKeyPrintScreen, | |||||
kKeyPause | |||||
}; | |||||
/** | |||||
Common flags for all events. | |||||
*/ | |||||
enum Flag { | |||||
kFlagSendEvent = 1, ///< Event is synthetic | |||||
kFlagIsHint = 2 ///< Event is a hint (not direct user input) | |||||
}; | |||||
/** | |||||
Reason for a crossing event. | |||||
*/ | |||||
enum CrossingMode { | |||||
kCrossingNormal, ///< Crossing due to pointer motion | |||||
kCrossingGrab, ///< Crossing due to a grab | |||||
kCrossingUngrab ///< Crossing due to a grab release | |||||
}; | |||||
/** | |||||
Scroll direction. | |||||
Describes the direction of a scroll event along with whether the scroll is a "smooth" scroll. | |||||
The discrete directions are for devices like mouse wheels with constrained axes, | |||||
while a smooth scroll is for those with arbitrary scroll direction freedom, like some touchpads. | |||||
*/ | |||||
enum ScrollDirection { | |||||
kScrollUp, ///< Scroll up | |||||
kScrollDown, ///< Scroll down | |||||
kScrollLeft, ///< Scroll left | |||||
kScrollRight, ///< Scroll right | |||||
kScrollSmooth ///< Smooth scroll in any direction | |||||
}; | }; | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// Base DGL classes | // Base DGL classes | ||||
/** | /** | ||||
Graphics context, definition depends on build type. | Graphics context, definition depends on build type. | ||||
*/ | */ | ||||
struct GraphicsContext; | |||||
struct GraphicsContext {}; | |||||
/** | /** | ||||
Idle callback. | Idle callback. | ||||
*/ | */ | ||||
class IdleCallback | |||||
struct IdleCallback | |||||
{ | { | ||||
public: | |||||
virtual ~IdleCallback() {} | virtual ~IdleCallback() {} | ||||
virtual void idleCallback() = 0; | virtual void idleCallback() = 0; | ||||
}; | }; | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
END_NAMESPACE_DGL | END_NAMESPACE_DGL | ||||
@@ -114,6 +172,6 @@ END_NAMESPACE_DGL | |||||
using namespace DGL_NAMESPACE; | using namespace DGL_NAMESPACE; | ||||
#endif | #endif | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
#endif // DGL_BASE_HPP_INCLUDED | #endif // DGL_BASE_HPP_INCLUDED |
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -17,23 +17,176 @@ | |||||
#ifndef DGL_CAIRO_HPP_INCLUDED | #ifndef DGL_CAIRO_HPP_INCLUDED | ||||
#define DGL_CAIRO_HPP_INCLUDED | #define DGL_CAIRO_HPP_INCLUDED | ||||
#include "Base.hpp" | |||||
#include "ImageBase.hpp" | |||||
#include "ImageBaseWidgets.hpp" | |||||
#include <cairo/cairo.h> | #include <cairo/cairo.h> | ||||
START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
/** | /** | ||||
Graphics context. | |||||
Cairo Graphics context. | |||||
*/ | */ | ||||
struct GraphicsContext | |||||
struct CairoGraphicsContext : GraphicsContext | |||||
{ | { | ||||
cairo_t* cairo; // FIXME proper name.. | |||||
cairo_t* handle; | |||||
}; | }; | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
/** | |||||
Cairo Image class. | |||||
TODO ... | |||||
*/ | |||||
class CairoImage : public ImageBase | |||||
{ | |||||
public: | |||||
/** | |||||
Constructor for a null Image. | |||||
*/ | |||||
CairoImage(); | |||||
/** | |||||
Constructor using raw image data. | |||||
@note @a rawData must remain valid for the lifetime of this Image. | |||||
*/ | |||||
CairoImage(const char* rawData, uint width, uint height, ImageFormat format); | |||||
/** | |||||
Constructor using raw image data. | |||||
@note @a rawData must remain valid for the lifetime of this Image. | |||||
*/ | |||||
CairoImage(const char* rawData, const Size<uint>& size, ImageFormat format); | |||||
/** | |||||
Constructor using another image data. | |||||
*/ | |||||
CairoImage(const CairoImage& image); | |||||
/** | |||||
Destructor. | |||||
*/ | |||||
~CairoImage() override; | |||||
/** | |||||
Load raw image data from memory. | |||||
@note @a rawData must remain valid for the lifetime of this Image. | |||||
*/ | |||||
void loadFromMemory(const char* rawData, | |||||
const Size<uint>& size, | |||||
ImageFormat format = kImageFormatBGRA) noexcept override; | |||||
/** | |||||
Load PNG image from memory. | |||||
Image size is read from PNG contents. | |||||
@note @a pngData must remain valid for the lifetime of this Image. | |||||
*/ | |||||
void loadFromPNG(const char* pngData, uint dataSize) noexcept; | |||||
/** | |||||
Draw this image at position @a pos using the graphics context @a context. | |||||
*/ | |||||
void drawAt(const GraphicsContext& context, const Point<int>& pos) override; | |||||
/** | |||||
Get the cairo surface currently associated with this image. | |||||
FIXME might be removed | |||||
*/ | |||||
inline cairo_surface_t* getSurface() const noexcept | |||||
{ | |||||
return surface; | |||||
} | |||||
/** | |||||
TODO document this. | |||||
*/ | |||||
CairoImage& operator=(const CairoImage& image) noexcept; | |||||
// FIXME this should not be needed | |||||
inline void loadFromMemory(const char* rdata, uint w, uint h, ImageFormat fmt = kImageFormatBGRA) | |||||
{ loadFromMemory(rdata, Size<uint>(w, h), fmt); }; | |||||
inline void draw(const GraphicsContext& context) | |||||
{ drawAt(context, Point<int>(0, 0)); }; | |||||
inline void drawAt(const GraphicsContext& context, int x, int y) | |||||
{ drawAt(context, Point<int>(x, y)); }; | |||||
private: | |||||
cairo_surface_t* surface; | |||||
uchar* surfacedata; | |||||
int* datarefcount; | |||||
}; | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
/** | |||||
CairoWidget, handy class that takes graphics context during onDisplay and passes it in a new function. | |||||
*/ | |||||
template <class BaseWidget> | |||||
class CairoBaseWidget : public BaseWidget | |||||
{ | |||||
public: | |||||
/** | |||||
Constructor for a CairoSubWidget. | |||||
*/ | |||||
explicit CairoBaseWidget(Widget* const parentGroupWidget); | |||||
/** | |||||
Constructor for a CairoTopLevelWidget. | |||||
*/ | |||||
explicit CairoBaseWidget(Window& windowToMapTo); | |||||
/** | |||||
Constructor for a CairoStandaloneWindow without parent window. | |||||
*/ | |||||
explicit CairoBaseWidget(Application& app); | |||||
/** | |||||
Constructor for a CairoStandaloneWindow with parent window. | |||||
*/ | |||||
explicit CairoBaseWidget(Application& app, Window& parentWindow); | |||||
/** | |||||
Destructor. | |||||
*/ | |||||
virtual ~CairoBaseWidget() {} | |||||
protected: | |||||
/** | |||||
New virtual onDisplay function. | |||||
@see onDisplay | |||||
*/ | |||||
virtual void onCairoDisplay(const CairoGraphicsContext& context) = 0; | |||||
private: | |||||
/** | |||||
Widget display function. | |||||
Implemented internally to pass context into the drawing function. | |||||
*/ | |||||
void onDisplay() override | |||||
{ | |||||
const CairoGraphicsContext& context((const CairoGraphicsContext&)BaseWidget::getGraphicsContext()); | |||||
onCairoDisplay(context); | |||||
} | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CairoBaseWidget); | |||||
}; | |||||
typedef CairoBaseWidget<SubWidget> CairoSubWidget; | |||||
typedef CairoBaseWidget<TopLevelWidget> CairoTopLevelWidget; | |||||
typedef CairoBaseWidget<StandaloneWindow> CairoStandaloneWindow; | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
typedef ImageBaseAboutWindow<CairoImage> CairoImageAboutWindow; | |||||
typedef ImageBaseButton<CairoImage> CairoImageButton; | |||||
typedef ImageBaseKnob<CairoImage> CairoImageKnob; | |||||
typedef ImageBaseSlider<CairoImage> CairoImageSlider; | |||||
typedef ImageBaseSwitch<CairoImage> CairoImageSwitch; | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
END_NAMESPACE_DGL | END_NAMESPACE_DGL | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -23,7 +23,7 @@ struct NVGcolor; | |||||
START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
/** | /** | ||||
A color made from red, green, blue and alpha floating-point values in [0..1] range. | A color made from red, green, blue and alpha floating-point values in [0..1] range. | ||||
@@ -44,13 +44,13 @@ struct Color { | |||||
/** | /** | ||||
Create a color from red, green, blue and alpha numeric values. | Create a color from red, green, blue and alpha numeric values. | ||||
Values must be in [0..255] range. | |||||
All values except alpha must be in [0..255] range, with alpha in [0..1] range. | |||||
*/ | */ | ||||
Color(int red, int green, int blue, int alpha = 255) noexcept; | |||||
Color(int red, int green, int blue, float alpha = 1.0f) noexcept; | |||||
/** | /** | ||||
Create a color from red, green, blue and alpha floating-point values. | Create a color from red, green, blue and alpha floating-point values. | ||||
Values must in [0..1] range. | |||||
All values must in [0..1] range. | |||||
*/ | */ | ||||
Color(float red, float green, float blue, float alpha = 1.0f) noexcept; | Color(float red, float green, float blue, float alpha = 1.0f) noexcept; | ||||
@@ -74,7 +74,7 @@ struct Color { | |||||
/** | /** | ||||
Create a color from a HTML string like "#333" or "#112233". | Create a color from a HTML string like "#333" or "#112233". | ||||
*/ | */ | ||||
static Color fromHTML(const char* rgb, float alpha = 1.0f); | |||||
static Color fromHTML(const char* rgb, float alpha = 1.0f) noexcept; | |||||
/** | /** | ||||
Linearly interpolate this color against another. | Linearly interpolate this color against another. | ||||
@@ -83,7 +83,7 @@ struct Color { | |||||
/** | /** | ||||
Check if this color matches another. | Check if this color matches another. | ||||
@note Comparison is forced within 8-bit color values. | |||||
@note Comparison is done within 8-bit color space. | |||||
*/ | */ | ||||
bool isEqual(const Color& color, bool withAlpha = true) noexcept; | bool isEqual(const Color& color, bool withAlpha = true) noexcept; | ||||
bool isNotEqual(const Color& color, bool withAlpha = true) noexcept; | bool isNotEqual(const Color& color, bool withAlpha = true) noexcept; | ||||
@@ -95,6 +95,11 @@ struct Color { | |||||
*/ | */ | ||||
void fixBounds() noexcept; | void fixBounds() noexcept; | ||||
/** | |||||
Set this color for use in the next drawing operation for the provided context. | |||||
*/ | |||||
void setFor(const GraphicsContext& context, bool includeAlpha = false); | |||||
/** | /** | ||||
@internal | @internal | ||||
Needed for NanoVG compatibility. | Needed for NanoVG compatibility. | ||||
@@ -103,7 +108,7 @@ struct Color { | |||||
operator NVGcolor() const noexcept; | operator NVGcolor() const noexcept; | ||||
}; | }; | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
END_NAMESPACE_DGL | END_NAMESPACE_DGL | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -21,7 +21,7 @@ | |||||
START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// Forward class names | // Forward class names | ||||
template<typename> class Line; | template<typename> class Line; | ||||
@@ -29,7 +29,7 @@ template<typename> class Circle; | |||||
template<typename> class Triangle; | template<typename> class Triangle; | ||||
template<typename> class Rectangle; | template<typename> class Rectangle; | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
/** | /** | ||||
DGL Point class. | DGL Point class. | ||||
@@ -114,14 +114,14 @@ public: | |||||
bool operator!=(const Point<T>& pos) const noexcept; | bool operator!=(const Point<T>& pos) const noexcept; | ||||
private: | private: | ||||
T fX, fY; | |||||
T x, y; | |||||
template<typename> friend class Line; | template<typename> friend class Line; | ||||
template<typename> friend class Circle; | template<typename> friend class Circle; | ||||
template<typename> friend class Triangle; | template<typename> friend class Triangle; | ||||
template<typename> friend class Rectangle; | template<typename> friend class Rectangle; | ||||
}; | }; | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
/** | /** | ||||
DGL Size class. | DGL Size class. | ||||
@@ -195,7 +195,7 @@ public: | |||||
/** | /** | ||||
Return true if size is not null (0x0). | Return true if size is not null (0x0). | ||||
A non-null size is still invalid if its width or height is negative. | |||||
A non-null size is still invalid if its width or height are negative. | |||||
*/ | */ | ||||
bool isNotNull() const noexcept; | bool isNotNull() const noexcept; | ||||
@@ -210,6 +210,8 @@ public: | |||||
*/ | */ | ||||
bool isInvalid() const noexcept; | bool isInvalid() const noexcept; | ||||
Size<int> toInt() const noexcept; | |||||
Size<T> operator+(const Size<T>& size) noexcept; | Size<T> operator+(const Size<T>& size) noexcept; | ||||
Size<T> operator-(const Size<T>& size) noexcept; | Size<T> operator-(const Size<T>& size) noexcept; | ||||
Size<T>& operator=(const Size<T>& size) noexcept; | Size<T>& operator=(const Size<T>& size) noexcept; | ||||
@@ -346,11 +348,6 @@ public: | |||||
*/ | */ | ||||
void moveBy(const Point<T>& pos) noexcept; | void moveBy(const Point<T>& pos) noexcept; | ||||
/** | |||||
Draw this line using the current OpenGL state. | |||||
*/ | |||||
void draw(); | |||||
/** | /** | ||||
Return true if line is null (start and end pos are equal). | Return true if line is null (start and end pos are equal). | ||||
*/ | */ | ||||
@@ -361,12 +358,28 @@ public: | |||||
*/ | */ | ||||
bool isNotNull() const noexcept; | bool isNotNull() const noexcept; | ||||
#ifndef DPF_TEST_POINT_CPP | |||||
/** | |||||
Draw this line using the provided graphics context, optionally specifying line width. | |||||
*/ | |||||
void draw(const GraphicsContext& context, T width = 1); | |||||
#endif | |||||
Line<T>& operator=(const Line<T>& line) noexcept; | Line<T>& operator=(const Line<T>& line) noexcept; | ||||
bool operator==(const Line<T>& line) const noexcept; | bool operator==(const Line<T>& line) const noexcept; | ||||
bool operator!=(const Line<T>& line) const noexcept; | bool operator!=(const Line<T>& line) const noexcept; | ||||
#ifndef DPF_TEST_POINT_CPP | |||||
/** | |||||
Draw this line using the current OpenGL state.@n | |||||
DEPRECATED Please use draw(const GraphicsContext&) instead. | |||||
*/ | |||||
DISTRHO_DEPRECATED_BY("draw(const GraphicsContext&)") | |||||
void draw(); | |||||
#endif | |||||
private: | private: | ||||
Point<T> fPosStart, fPosEnd; | |||||
Point<T> posStart, posEnd; | |||||
}; | }; | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -461,19 +474,35 @@ public: | |||||
void setNumSegments(const uint num); | void setNumSegments(const uint num); | ||||
/** | /** | ||||
Draw this circle using the current OpenGL state. | |||||
Draw this circle using the provided graphics context. | |||||
*/ | */ | ||||
void draw(); | |||||
void draw(const GraphicsContext& context); | |||||
/** | /** | ||||
Draw lines (outline of this circle) using the current OpenGL state. | |||||
Draw lines (outline of this circle) using the provided graphics context, optionally specifying line width. | |||||
*/ | */ | ||||
void drawOutline(); | |||||
void drawOutline(const GraphicsContext& context, T lineWidth = 1); | |||||
Circle<T>& operator=(const Circle<T>& cir) noexcept; | Circle<T>& operator=(const Circle<T>& cir) noexcept; | ||||
bool operator==(const Circle<T>& cir) const noexcept; | bool operator==(const Circle<T>& cir) const noexcept; | ||||
bool operator!=(const Circle<T>& cir) const noexcept; | bool operator!=(const Circle<T>& cir) const noexcept; | ||||
#ifndef DPF_TEST_POINT_CPP | |||||
/** | |||||
Draw this circle using the current OpenGL state.@n | |||||
DEPRECATED Please use draw(const GraphicsContext&) instead. | |||||
*/ | |||||
DISTRHO_DEPRECATED_BY("draw(const GraphicsContext&)") | |||||
void draw(); | |||||
/** | |||||
Draw lines (outline of this circle) using the current OpenGL state.@n | |||||
DEPRECATED Please use drawOutline(const GraphicsContext&,T) instead. | |||||
*/ | |||||
DISTRHO_DEPRECATED_BY("drawOutline(const GraphicsContext&)") | |||||
void drawOutline(); | |||||
#endif | |||||
private: | private: | ||||
Point<T> fPos; | Point<T> fPos; | ||||
float fSize; | float fSize; | ||||
@@ -481,9 +510,6 @@ private: | |||||
// cached values | // cached values | ||||
float fTheta, fCos, fSin; | float fTheta, fCos, fSin; | ||||
/** @internal */ | |||||
void _draw(const bool outline); | |||||
}; | }; | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -541,24 +567,37 @@ public: | |||||
bool isInvalid() const noexcept; | bool isInvalid() const noexcept; | ||||
/** | /** | ||||
Draw this triangle using the current OpenGL state. | |||||
Draw this triangle using the provided graphics context. | |||||
*/ | */ | ||||
void draw(); | |||||
void draw(const GraphicsContext& context); | |||||
/** | /** | ||||
Draw lines (outline of this triangle) using the current OpenGL state. | |||||
Draw lines (outline of this triangle) using the provided graphics context, optionally specifying line width. | |||||
*/ | */ | ||||
void drawOutline(); | |||||
void drawOutline(const GraphicsContext& context, T lineWidth = 1); | |||||
Triangle<T>& operator=(const Triangle<T>& tri) noexcept; | Triangle<T>& operator=(const Triangle<T>& tri) noexcept; | ||||
bool operator==(const Triangle<T>& tri) const noexcept; | bool operator==(const Triangle<T>& tri) const noexcept; | ||||
bool operator!=(const Triangle<T>& tri) const noexcept; | bool operator!=(const Triangle<T>& tri) const noexcept; | ||||
private: | |||||
Point<T> fPos1, fPos2, fPos3; | |||||
#ifndef DPF_TEST_POINT_CPP | |||||
/** | |||||
Draw this triangle using the current OpenGL state.@n | |||||
DEPRECATED Please use draw(const GraphicsContext&) instead. | |||||
*/ | |||||
DISTRHO_DEPRECATED_BY("draw(const GraphicsContext&)") | |||||
void draw(); | |||||
/** @internal */ | |||||
void _draw(const bool outline); | |||||
/** | |||||
Draw lines (outline of this triangle) using the current OpenGL state.@n | |||||
DEPRECATED Please use drawOutline(const GraphicsContext&,T) instead. | |||||
*/ | |||||
DISTRHO_DEPRECATED_BY("drawOutline(const GraphicsContext&)") | |||||
void drawOutline(); | |||||
#endif | |||||
private: | |||||
Point<T> pos1, pos2, pos3; | |||||
}; | }; | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -712,6 +751,12 @@ public: | |||||
*/ | */ | ||||
bool contains(const Point<T>& pos) const noexcept; | bool contains(const Point<T>& pos) const noexcept; | ||||
/** | |||||
Check if this rectangle contains the point @a pos of another type. | |||||
*/ | |||||
template<typename T2> | |||||
bool contains(const Point<T2>& pos) const noexcept; | |||||
/** | /** | ||||
Check if this rectangle contains X. | Check if this rectangle contains X. | ||||
*/ | */ | ||||
@@ -723,14 +768,37 @@ public: | |||||
bool containsY(const T& y) const noexcept; | bool containsY(const T& y) const noexcept; | ||||
/** | /** | ||||
Draw this rectangle using the current OpenGL state. | |||||
Return true if size is null (0x0). | |||||
An null size is also invalid. | |||||
*/ | */ | ||||
void draw(); | |||||
bool isNull() const noexcept; | |||||
/** | /** | ||||
Draw lines (outline of this rectangle) using the current OpenGL state. | |||||
Return true if size is not null (0x0). | |||||
A non-null size is still invalid if its width or height are negative. | |||||
*/ | */ | ||||
void drawOutline(); | |||||
bool isNotNull() const noexcept; | |||||
/** | |||||
Return true if size is valid (width and height are higher than zero). | |||||
*/ | |||||
bool isValid() const noexcept; | |||||
/** | |||||
Return true if size is invalid (width or height are lower or equal to zero). | |||||
An invalid size might not be null under some circumstances. | |||||
*/ | |||||
bool isInvalid() const noexcept; | |||||
/** | |||||
Draw this rectangle using the provided graphics context. | |||||
*/ | |||||
void draw(const GraphicsContext& context); | |||||
/** | |||||
Draw lines (outline of this rectangle) using the provided graphics context, optionally specifying line width. | |||||
*/ | |||||
void drawOutline(const GraphicsContext& context, T lineWidth = 1); | |||||
Rectangle<T>& operator=(const Rectangle<T>& rect) noexcept; | Rectangle<T>& operator=(const Rectangle<T>& rect) noexcept; | ||||
Rectangle<T>& operator*=(double m) noexcept; | Rectangle<T>& operator*=(double m) noexcept; | ||||
@@ -738,12 +806,23 @@ public: | |||||
bool operator==(const Rectangle<T>& size) const noexcept; | bool operator==(const Rectangle<T>& size) const noexcept; | ||||
bool operator!=(const Rectangle<T>& size) const noexcept; | bool operator!=(const Rectangle<T>& size) const noexcept; | ||||
private: | |||||
Point<T> fPos; | |||||
Size<T> fSize; | |||||
/** | |||||
Draw this rectangle using the current OpenGL state.@n | |||||
DEPRECATED Please use draw(const GraphicsContext&) instead. | |||||
*/ | |||||
DISTRHO_DEPRECATED_BY("draw(const GraphicsContext&)") | |||||
void draw(); | |||||
/** @internal */ | |||||
void _draw(const bool outline); | |||||
/** | |||||
Draw lines (outline of this rectangle) using the current OpenGL state.@n | |||||
DEPRECATED Please use drawOutline(const GraphicsContext&,T) instead. | |||||
*/ | |||||
DISTRHO_DEPRECATED_BY("drawOutline(const GraphicsContext&)") | |||||
void drawOutline(); | |||||
private: | |||||
Point<T> pos; | |||||
Size<T> size; | |||||
}; | }; | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -17,108 +17,19 @@ | |||||
#ifndef DGL_IMAGE_HPP_INCLUDED | #ifndef DGL_IMAGE_HPP_INCLUDED | ||||
#define DGL_IMAGE_HPP_INCLUDED | #define DGL_IMAGE_HPP_INCLUDED | ||||
#include "ImageBase.hpp" | |||||
#ifdef DGL_CAIRO | |||||
#include "Cairo.hpp" | |||||
#else | |||||
#include "OpenGL.hpp" | #include "OpenGL.hpp" | ||||
#endif | |||||
START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
// ----------------------------------------------------------------------- | |||||
/** | |||||
OpenGL Image class. | |||||
This is an Image class that handles raw image data in pixels. | |||||
You can init the image data on the contructor or later on by calling loadFromMemory(). | |||||
To generate raw data useful for this class see the utils/png2rgba.py script. | |||||
Be careful when using a PNG without alpha channel, for those the format is 'GL_BGR' | |||||
instead of the default 'GL_BGRA'. | |||||
Images are drawn on screen via 2D textures. | |||||
*/ | |||||
class Image : public ImageBase | |||||
{ | |||||
public: | |||||
/** | |||||
Constructor for a null Image. | |||||
*/ | |||||
Image(); | |||||
/** | |||||
Constructor using raw image data. | |||||
@note @a rawData must remain valid for the lifetime of this Image. | |||||
*/ | |||||
Image(const char* const rawData, | |||||
const uint width, | |||||
const uint height, | |||||
const GLenum format = GL_BGRA, | |||||
const GLenum type = GL_UNSIGNED_BYTE); | |||||
/** | |||||
Constructor using raw image data. | |||||
@note @a rawData must remain valid for the lifetime of this Image. | |||||
*/ | |||||
Image(const char* const rawData, | |||||
const Size<uint>& size, | |||||
const GLenum format = GL_BGRA, | |||||
const GLenum type = GL_UNSIGNED_BYTE); | |||||
/** | |||||
Constructor using another image data. | |||||
*/ | |||||
Image(const Image& image); | |||||
/** | |||||
Destructor. | |||||
*/ | |||||
~Image() override; | |||||
/** | |||||
Load image data from memory. | |||||
@note @a rawData must remain valid for the lifetime of this Image. | |||||
*/ | |||||
void loadFromMemory(const char* const rawData, | |||||
const uint width, | |||||
const uint height, | |||||
const GLenum format = GL_BGRA, | |||||
const GLenum type = GL_UNSIGNED_BYTE) noexcept; | |||||
/** | |||||
Load image data from memory. | |||||
@note @a rawData must remain valid for the lifetime of this Image. | |||||
*/ | |||||
void loadFromMemory(const char* const rawData, | |||||
const Size<uint>& size, | |||||
const GLenum format = GL_BGRA, | |||||
const GLenum type = GL_UNSIGNED_BYTE) noexcept; | |||||
/** | |||||
Get the image format. | |||||
*/ | |||||
GLenum getFormat() const noexcept; | |||||
/** | |||||
Get the image type. | |||||
*/ | |||||
GLenum getType() const noexcept; | |||||
/** | |||||
TODO document this. | |||||
*/ | |||||
Image& operator=(const Image& image) noexcept; | |||||
protected: | |||||
/** @internal */ | |||||
void _drawAt(const Point<int>& pos) override; | |||||
private: | |||||
GLenum fFormat; | |||||
GLenum fType; | |||||
GLuint fTextureId; | |||||
bool fIsReady; | |||||
}; | |||||
// ----------------------------------------------------------------------- | |||||
#ifdef DGL_CAIRO | |||||
typedef CairoImage Image; | |||||
#else | |||||
typedef OpenGLImage Image; | |||||
#endif | |||||
END_NAMESPACE_DGL | END_NAMESPACE_DGL | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -21,7 +21,16 @@ | |||||
START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
enum ImageFormat { | |||||
kImageFormatNull, | |||||
kImageFormatGrayscale, | |||||
kImageFormatBGR, | |||||
kImageFormatBGRA, | |||||
kImageFormatRGB, | |||||
kImageFormatRGBA, | |||||
}; | |||||
/** | /** | ||||
Base DGL Image class. | Base DGL Image class. | ||||
@@ -44,13 +53,13 @@ protected: | |||||
Constructor using raw image data. | Constructor using raw image data. | ||||
@note @a rawData must remain valid for the lifetime of this Image. | @note @a rawData must remain valid for the lifetime of this Image. | ||||
*/ | */ | ||||
ImageBase(const char* const rawData, const uint width, const uint height); | |||||
ImageBase(const char* rawData, uint width, uint height, ImageFormat format); | |||||
/** | /** | ||||
Constructor using raw image data. | Constructor using raw image data. | ||||
@note @a rawData must remain valid for the lifetime of this Image. | @note @a rawData must remain valid for the lifetime of this Image. | ||||
*/ | */ | ||||
ImageBase(const char* const rawData, const Size<uint>& size); | |||||
ImageBase(const char* rawData, const Size<uint>& size, ImageFormat format); | |||||
/** | /** | ||||
Constructor using another image data. | Constructor using another image data. | ||||
@@ -68,6 +77,11 @@ public: | |||||
*/ | */ | ||||
bool isValid() const noexcept; | bool isValid() const noexcept; | ||||
/** | |||||
Check if this image is not valid. | |||||
*/ | |||||
bool isInvalid() const noexcept; | |||||
/** | /** | ||||
Get width. | Get width. | ||||
*/ | */ | ||||
@@ -89,19 +103,38 @@ public: | |||||
const char* getRawData() const noexcept; | const char* getRawData() const noexcept; | ||||
/** | /** | ||||
Draw this image at (0, 0) point. | |||||
Get the image format. | |||||
*/ | */ | ||||
void draw(); | |||||
ImageFormat getFormat() const noexcept; | |||||
/** | /** | ||||
Draw this image at (x, y) point. | |||||
Load image data from memory. | |||||
@note @a rawData must remain valid for the lifetime of this Image. | |||||
*/ | */ | ||||
void drawAt(const int x, const int y); | |||||
void loadFromMemory(const char* rawData, uint width, uint height, ImageFormat format = kImageFormatBGRA) noexcept; | |||||
/** | /** | ||||
Draw this image at position @a pos. | |||||
Load image data from memory. | |||||
@note @a rawData must remain valid for the lifetime of this Image. | |||||
*/ | */ | ||||
void drawAt(const Point<int>& pos); | |||||
virtual void loadFromMemory(const char* rawData, | |||||
const Size<uint>& size, | |||||
ImageFormat format = kImageFormatBGRA) noexcept; | |||||
/** | |||||
Draw this image at (0, 0) point using the current OpenGL context. | |||||
*/ | |||||
void draw(const GraphicsContext& context); | |||||
/** | |||||
Draw this image at (x, y) point using the current OpenGL context. | |||||
*/ | |||||
void drawAt(const GraphicsContext& context, int x, int y); | |||||
/** | |||||
Draw this image at position @a pos using the current OpenGL context. | |||||
*/ | |||||
virtual void drawAt(const GraphicsContext& context, const Point<int>& pos) = 0; | |||||
/** | /** | ||||
TODO document this. | TODO document this. | ||||
@@ -111,14 +144,12 @@ public: | |||||
bool operator!=(const ImageBase& image) const noexcept; | bool operator!=(const ImageBase& image) const noexcept; | ||||
protected: | protected: | ||||
/** @internal */ | |||||
virtual void _drawAt(const Point<int>& pos) = 0; | |||||
const char* fRawData; | |||||
Size<uint> fSize; | |||||
const char* rawData; | |||||
Size<uint> size; | |||||
ImageFormat format; | |||||
}; | }; | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
END_NAMESPACE_DGL | END_NAMESPACE_DGL | ||||
@@ -0,0 +1,223 @@ | |||||
/* | |||||
* DISTRHO Plugin Framework (DPF) | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#ifndef DGL_IMAGE_BASE_WIDGETS_HPP_INCLUDED | |||||
#define DGL_IMAGE_BASE_WIDGETS_HPP_INCLUDED | |||||
#include "StandaloneWindow.hpp" | |||||
#include "SubWidget.hpp" | |||||
START_NAMESPACE_DGL | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
template <class ImageType> | |||||
class ImageBaseAboutWindow : public StandaloneWindow | |||||
{ | |||||
public: | |||||
explicit ImageBaseAboutWindow(Window& parentWindow, const ImageType& image = ImageType()); | |||||
explicit ImageBaseAboutWindow(TopLevelWidget* parentTopLevelWidget, const ImageType& image = ImageType()); | |||||
void setImage(const ImageType& image); | |||||
protected: | |||||
void onDisplay() override; | |||||
bool onKeyboard(const KeyboardEvent&) override; | |||||
bool onMouse(const MouseEvent&) override; | |||||
private: | |||||
ImageType img; | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ImageBaseAboutWindow) | |||||
}; | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
template <class ImageType> | |||||
class ImageBaseButton : public SubWidget | |||||
{ | |||||
public: | |||||
class Callback | |||||
{ | |||||
public: | |||||
virtual ~Callback() {} | |||||
virtual void imageButtonClicked(ImageBaseButton* imageButton, int button) = 0; | |||||
}; | |||||
explicit ImageBaseButton(Widget* parentWidget, const ImageType& image); | |||||
explicit ImageBaseButton(Widget* parentWidget, const ImageType& imageNormal, const ImageType& imageDown); | |||||
explicit ImageBaseButton(Widget* parentWidget, const ImageType& imageNormal, const ImageType& imageHover, const ImageType& imageDown); | |||||
~ImageBaseButton() override; | |||||
void setCallback(Callback* callback) noexcept; | |||||
protected: | |||||
void onDisplay() override; | |||||
bool onMouse(const MouseEvent&) override; | |||||
bool onMotion(const MotionEvent&) override; | |||||
private: | |||||
struct PrivateData; | |||||
PrivateData* const pData; | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ImageBaseButton) | |||||
}; | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
template <class ImageType> | |||||
class ImageBaseKnob : public SubWidget | |||||
{ | |||||
public: | |||||
enum Orientation { | |||||
Horizontal, | |||||
Vertical | |||||
}; | |||||
class Callback | |||||
{ | |||||
public: | |||||
virtual ~Callback() {} | |||||
virtual void imageKnobDragStarted(ImageBaseKnob* imageKnob) = 0; | |||||
virtual void imageKnobDragFinished(ImageBaseKnob* imageKnob) = 0; | |||||
virtual void imageKnobValueChanged(ImageBaseKnob* imageKnob, float value) = 0; | |||||
}; | |||||
explicit ImageBaseKnob(Widget* parentWidget, const ImageType& image, Orientation orientation = Vertical) noexcept; | |||||
explicit ImageBaseKnob(const ImageBaseKnob& imageKnob); | |||||
ImageBaseKnob& operator=(const ImageBaseKnob& imageKnob); | |||||
~ImageBaseKnob() override; | |||||
float getValue() const noexcept; | |||||
void setDefault(float def) noexcept; | |||||
void setRange(float min, float max) noexcept; | |||||
void setStep(float step) noexcept; | |||||
void setValue(float value, bool sendCallback = false) noexcept; | |||||
void setUsingLogScale(bool yesNo) noexcept; | |||||
void setCallback(Callback* callback) noexcept; | |||||
void setOrientation(Orientation orientation) noexcept; | |||||
void setRotationAngle(int angle); | |||||
void setImageLayerCount(uint count) noexcept; | |||||
protected: | |||||
void onDisplay() override; | |||||
bool onMouse(const MouseEvent&) override; | |||||
bool onMotion(const MotionEvent&) override; | |||||
bool onScroll(const ScrollEvent&) override; | |||||
private: | |||||
struct PrivateData; | |||||
PrivateData* const pData; | |||||
DISTRHO_LEAK_DETECTOR(ImageBaseKnob) | |||||
}; | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// note set range and step before setting the value | |||||
template <class ImageType> | |||||
class ImageBaseSlider : public SubWidget | |||||
{ | |||||
public: | |||||
class Callback | |||||
{ | |||||
public: | |||||
virtual ~Callback() {} | |||||
virtual void imageSliderDragStarted(ImageBaseSlider* imageSlider) = 0; | |||||
virtual void imageSliderDragFinished(ImageBaseSlider* imageSlider) = 0; | |||||
virtual void imageSliderValueChanged(ImageBaseSlider* imageSlider, float value) = 0; | |||||
}; | |||||
explicit ImageBaseSlider(Widget* parentWidget, const ImageType& image) noexcept; | |||||
~ImageBaseSlider() override; | |||||
float getValue() const noexcept; | |||||
void setValue(float value, bool sendCallback = false) noexcept; | |||||
void setDefault(float def) noexcept; | |||||
void setStartPos(const Point<int>& startPos) noexcept; | |||||
void setStartPos(int x, int y) noexcept; | |||||
void setEndPos(const Point<int>& endPos) noexcept; | |||||
void setEndPos(int x, int y) noexcept; | |||||
void setInverted(bool inverted) noexcept; | |||||
void setRange(float min, float max) noexcept; | |||||
void setStep(float step) noexcept; | |||||
void setCallback(Callback* callback) noexcept; | |||||
protected: | |||||
void onDisplay() override; | |||||
bool onMouse(const MouseEvent&) override; | |||||
bool onMotion(const MotionEvent&) override; | |||||
private: | |||||
struct PrivateData; | |||||
PrivateData* const pData; | |||||
// these should not be used | |||||
void setAbsoluteX(int) const noexcept {} | |||||
void setAbsoluteY(int) const noexcept {} | |||||
void setAbsolutePos(int, int) const noexcept {} | |||||
void setAbsolutePos(const Point<int>&) const noexcept {} | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ImageBaseSlider) | |||||
}; | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
template <class ImageType> | |||||
class ImageBaseSwitch : public SubWidget | |||||
{ | |||||
public: | |||||
class Callback | |||||
{ | |||||
public: | |||||
virtual ~Callback() {} | |||||
virtual void imageSwitchClicked(ImageBaseSwitch* imageSwitch, bool down) = 0; | |||||
}; | |||||
explicit ImageBaseSwitch(Widget* parentWidget, const ImageType& imageNormal, const ImageType& imageDown) noexcept; | |||||
explicit ImageBaseSwitch(const ImageBaseSwitch& imageSwitch) noexcept; | |||||
ImageBaseSwitch& operator=(const ImageBaseSwitch& imageSwitch) noexcept; | |||||
~ImageBaseSwitch() override; | |||||
bool isDown() const noexcept; | |||||
void setDown(bool down) noexcept; | |||||
void setCallback(Callback* callback) noexcept; | |||||
protected: | |||||
void onDisplay() override; | |||||
bool onMouse(const MouseEvent&) override; | |||||
private: | |||||
struct PrivateData; | |||||
PrivateData* const pData; | |||||
DISTRHO_LEAK_DETECTOR(ImageBaseSwitch) | |||||
}; | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
END_NAMESPACE_DGL | |||||
#endif // DGL_IMAGE_BASE_WIDGETS_HPP_INCLUDED |
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -18,266 +18,24 @@ | |||||
#define DGL_IMAGE_WIDGETS_HPP_INCLUDED | #define DGL_IMAGE_WIDGETS_HPP_INCLUDED | ||||
#include "Image.hpp" | #include "Image.hpp" | ||||
#include "Widget.hpp" | |||||
#include "Window.hpp" | |||||
#include "ImageBaseWidgets.hpp" | |||||
START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
// ----------------------------------------------------------------------- | |||||
#ifndef DISTRHO_OS_HAIKU | |||||
class ImageAboutWindow : public Window, | |||||
public Widget | |||||
#else | |||||
// crash when creating or opening 2nd window | |||||
class ImageAboutWindow | |||||
#endif | |||||
{ | |||||
public: | |||||
explicit ImageAboutWindow(Window& parent, const Image& image = Image()); | |||||
explicit ImageAboutWindow(Widget* widget, const Image& image = Image()); | |||||
void setImage(const Image& image); | |||||
#ifndef DISTRHO_OS_HAIKU | |||||
protected: | |||||
void onDisplay() override; | |||||
bool onKeyboard(const KeyboardEvent&) override; | |||||
bool onMouse(const MouseEvent&) override; | |||||
void onReshape(uint width, uint height) override; | |||||
#ifdef DGL_CAIRO | |||||
typedef CairoImageAboutWindow ImageAboutWindow; | |||||
typedef CairoImageButton ImageButton; | |||||
typedef CairoImageKnob ImageKnob; | |||||
typedef CairoImageSlider ImageSlider; | |||||
typedef CairoImageSwitch ImageSwitch; | |||||
#else | #else | ||||
void exec() {} | |||||
typedef OpenGLImageAboutWindow ImageAboutWindow; | |||||
typedef OpenGLImageButton ImageButton; | |||||
typedef OpenGLImageKnob ImageKnob; | |||||
typedef OpenGLImageSlider ImageSlider; | |||||
typedef OpenGLImageSwitch ImageSwitch; | |||||
#endif | #endif | ||||
private: | |||||
Image fImgBackground; | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ImageAboutWindow) | |||||
}; | |||||
// ----------------------------------------------------------------------- | |||||
class ImageButton : public Widget | |||||
{ | |||||
public: | |||||
class Callback | |||||
{ | |||||
public: | |||||
virtual ~Callback() {} | |||||
virtual void imageButtonClicked(ImageButton* imageButton, int button) = 0; | |||||
}; | |||||
explicit ImageButton(Window& parent, const Image& image); | |||||
explicit ImageButton(Window& parent, const Image& imageNormal, const Image& imageDown); | |||||
explicit ImageButton(Window& parent, const Image& imageNormal, const Image& imageHover, const Image& imageDown); | |||||
explicit ImageButton(Widget* widget, const Image& image); | |||||
explicit ImageButton(Widget* widget, const Image& imageNormal, const Image& imageDown); | |||||
explicit ImageButton(Widget* widget, const Image& imageNormal, const Image& imageHover, const Image& imageDown); | |||||
~ImageButton() override; | |||||
void setCallback(Callback* callback) noexcept; | |||||
protected: | |||||
void onDisplay() override; | |||||
bool onMouse(const MouseEvent&) override; | |||||
bool onMotion(const MotionEvent&) override; | |||||
private: | |||||
struct PrivateData; | |||||
PrivateData* const pData; | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ImageButton) | |||||
}; | |||||
// ----------------------------------------------------------------------- | |||||
class ImageKnob : public Widget | |||||
{ | |||||
public: | |||||
enum Orientation { | |||||
Horizontal, | |||||
Vertical | |||||
}; | |||||
class Callback | |||||
{ | |||||
public: | |||||
virtual ~Callback() {} | |||||
virtual void imageKnobDragStarted(ImageKnob* imageKnob) = 0; | |||||
virtual void imageKnobDragFinished(ImageKnob* imageKnob) = 0; | |||||
virtual void imageKnobValueChanged(ImageKnob* imageKnob, float value) = 0; | |||||
}; | |||||
explicit ImageKnob(Window& parent, const Image& image, Orientation orientation = Vertical) noexcept; | |||||
explicit ImageKnob(Widget* widget, const Image& image, Orientation orientation = Vertical) noexcept; | |||||
explicit ImageKnob(const ImageKnob& imageKnob); | |||||
ImageKnob& operator=(const ImageKnob& imageKnob); | |||||
~ImageKnob() override; | |||||
float getValue() const noexcept; | |||||
void setDefault(float def) noexcept; | |||||
void setRange(float min, float max) noexcept; | |||||
void setStep(float step) noexcept; | |||||
void setValue(float value, bool sendCallback = false) noexcept; | |||||
void setUsingLogScale(bool yesNo) noexcept; | |||||
void setCallback(Callback* callback) noexcept; | |||||
void setOrientation(Orientation orientation) noexcept; | |||||
void setRotationAngle(int angle); | |||||
void setImageLayerCount(uint count) noexcept; | |||||
protected: | |||||
void onDisplay() override; | |||||
bool onMouse(const MouseEvent&) override; | |||||
bool onMotion(const MotionEvent&) override; | |||||
bool onScroll(const ScrollEvent&) override; | |||||
private: | |||||
Image fImage; | |||||
float fMinimum; | |||||
float fMaximum; | |||||
float fStep; | |||||
float fValue; | |||||
float fValueDef; | |||||
float fValueTmp; | |||||
bool fUsingDefault; | |||||
bool fUsingLog; | |||||
Orientation fOrientation; | |||||
int fRotationAngle; | |||||
bool fDragging; | |||||
int fLastX; | |||||
int fLastY; | |||||
Callback* fCallback; | |||||
bool fIsImgVertical; | |||||
uint fImgLayerWidth; | |||||
uint fImgLayerHeight; | |||||
uint fImgLayerCount; | |||||
bool fIsReady; | |||||
GLuint fTextureId; | |||||
float _logscale(float value) const; | |||||
float _invlogscale(float value) const; | |||||
DISTRHO_LEAK_DETECTOR(ImageKnob) | |||||
}; | |||||
// ----------------------------------------------------------------------- | |||||
// note set range and step before setting the value | |||||
class ImageSlider : public Widget | |||||
{ | |||||
public: | |||||
class Callback | |||||
{ | |||||
public: | |||||
virtual ~Callback() {} | |||||
virtual void imageSliderDragStarted(ImageSlider* imageSlider) = 0; | |||||
virtual void imageSliderDragFinished(ImageSlider* imageSlider) = 0; | |||||
virtual void imageSliderValueChanged(ImageSlider* imageSlider, float value) = 0; | |||||
}; | |||||
explicit ImageSlider(Window& parent, const Image& image) noexcept; | |||||
explicit ImageSlider(Widget* widget, const Image& image) noexcept; | |||||
float getValue() const noexcept; | |||||
void setValue(float value, bool sendCallback = false) noexcept; | |||||
void setDefault(float def) noexcept; | |||||
void setStartPos(const Point<int>& startPos) noexcept; | |||||
void setStartPos(int x, int y) noexcept; | |||||
void setEndPos(const Point<int>& endPos) noexcept; | |||||
void setEndPos(int x, int y) noexcept; | |||||
void setInverted(bool inverted) noexcept; | |||||
void setRange(float min, float max) noexcept; | |||||
void setStep(float step) noexcept; | |||||
void setCallback(Callback* callback) noexcept; | |||||
protected: | |||||
void onDisplay() override; | |||||
bool onMouse(const MouseEvent&) override; | |||||
bool onMotion(const MotionEvent&) override; | |||||
private: | |||||
Image fImage; | |||||
float fMinimum; | |||||
float fMaximum; | |||||
float fStep; | |||||
float fValue; | |||||
float fValueDef; | |||||
float fValueTmp; | |||||
bool fUsingDefault; | |||||
bool fDragging; | |||||
bool fInverted; | |||||
bool fValueIsSet; | |||||
int fStartedX; | |||||
int fStartedY; | |||||
Callback* fCallback; | |||||
Point<int> fStartPos; | |||||
Point<int> fEndPos; | |||||
Rectangle<int> fSliderArea; | |||||
void _recheckArea() noexcept; | |||||
// these should not be used | |||||
void setAbsoluteX(int) const noexcept {} | |||||
void setAbsoluteY(int) const noexcept {} | |||||
void setAbsolutePos(int, int) const noexcept {} | |||||
void setAbsolutePos(const Point<int>&) const noexcept {} | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ImageSlider) | |||||
}; | |||||
// ----------------------------------------------------------------------- | |||||
class ImageSwitch : public Widget | |||||
{ | |||||
public: | |||||
class Callback | |||||
{ | |||||
public: | |||||
virtual ~Callback() {} | |||||
virtual void imageSwitchClicked(ImageSwitch* imageSwitch, bool down) = 0; | |||||
}; | |||||
explicit ImageSwitch(Window& parent, const Image& imageNormal, const Image& imageDown) noexcept; | |||||
explicit ImageSwitch(Widget* widget, const Image& imageNormal, const Image& imageDown) noexcept; | |||||
explicit ImageSwitch(const ImageSwitch& imageSwitch) noexcept; | |||||
ImageSwitch& operator=(const ImageSwitch& imageSwitch) noexcept; | |||||
bool isDown() const noexcept; | |||||
void setDown(bool down) noexcept; | |||||
void setCallback(Callback* callback) noexcept; | |||||
protected: | |||||
void onDisplay() override; | |||||
bool onMouse(const MouseEvent&) override; | |||||
private: | |||||
Image fImageNormal; | |||||
Image fImageDown; | |||||
bool fIsDown; | |||||
Callback* fCallback; | |||||
DISTRHO_LEAK_DETECTOR(ImageSwitch) | |||||
}; | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DGL | END_NAMESPACE_DGL | ||||
#endif // DGL_IMAGE_WIDGETS_HPP_INCLUDED | #endif // DGL_IMAGE_WIDGETS_HPP_INCLUDED |
@@ -10,8 +10,16 @@ include ../Makefile.base.mk | |||||
BUILD_C_FLAGS += $(DGL_FLAGS) -I. -Isrc | BUILD_C_FLAGS += $(DGL_FLAGS) -I. -Isrc | ||||
BUILD_CXX_FLAGS += $(DGL_FLAGS) -I. -Isrc -DDONT_SET_USING_DGL_NAMESPACE -Wno-unused-parameter | BUILD_CXX_FLAGS += $(DGL_FLAGS) -I. -Isrc -DDONT_SET_USING_DGL_NAMESPACE -Wno-unused-parameter | ||||
BUILD_CXX_FLAGS += -Isrc/pugl-upstream/include | |||||
LINK_FLAGS += $(DGL_LIBS) | LINK_FLAGS += $(DGL_LIBS) | ||||
# TODO fix these after pugl-upstream is done | |||||
BUILD_CXX_FLAGS += -Wno-attributes -Wno-extra -Wno-missing-field-initializers -Wno-narrowing | |||||
ifeq ($(MACOS),true) | |||||
BUILD_CXX_FLAGS += -DGL_SILENCE_DEPRECATION -Wno-deprecated-declarations | |||||
endif | |||||
# ifneq ($(MACOS_OLD),true) | # ifneq ($(MACOS_OLD),true) | ||||
# needed by sofd right now, fix later | # needed by sofd right now, fix later | ||||
# BUILD_CXX_FLAGS += -Wno-type-limits -fpermissive | # BUILD_CXX_FLAGS += -Wno-type-limits -fpermissive | ||||
@@ -21,39 +29,64 @@ LINK_FLAGS += $(DGL_LIBS) | |||||
OBJS_common = \ | OBJS_common = \ | ||||
../build/dgl/Application.cpp.o \ | ../build/dgl/Application.cpp.o \ | ||||
../build/dgl/ApplicationPrivateData.cpp.o \ | |||||
../build/dgl/Color.cpp.o \ | ../build/dgl/Color.cpp.o \ | ||||
../build/dgl/Geometry.cpp.o \ | ../build/dgl/Geometry.cpp.o \ | ||||
../build/dgl/ImageBase.cpp.o \ | ../build/dgl/ImageBase.cpp.o \ | ||||
../build/dgl/ImageBaseWidgets.cpp.o \ | |||||
../build/dgl/Resources.cpp.o \ | ../build/dgl/Resources.cpp.o \ | ||||
../build/dgl/Widget.cpp.o | |||||
# TODO: ImageWidgets.cpp | |||||
../build/dgl/SubWidget.cpp.o \ | |||||
../build/dgl/SubWidgetPrivateData.cpp.o \ | |||||
../build/dgl/TopLevelWidget.cpp.o \ | |||||
../build/dgl/TopLevelWidgetPrivateData.cpp.o \ | |||||
../build/dgl/Widget.cpp.o \ | |||||
../build/dgl/WidgetPrivateData.cpp.o \ | |||||
../build/dgl/Window.cpp.o \ | |||||
../build/dgl/WindowPrivateData.cpp.o | |||||
# ../build/dgl/WindowFileBrowser.cpp.o | |||||
# --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
OBJS_cairo = $(OBJS_common) \ | OBJS_cairo = $(OBJS_common) \ | ||||
../build/dgl/Cairo.cpp.cairo.o \ | |||||
../build/dgl/WidgetPrivateData.cpp.cairo.o | |||||
../build/dgl/Cairo.cpp.cairo.o | |||||
ifeq ($(MACOS),true) | ifeq ($(MACOS),true) | ||||
OBJS_cairo += ../build/dgl/Window.mm.cairo.o | |||||
OBJS_cairo += ../build/dgl/pugl.mm.cairo.o | |||||
else | else | ||||
OBJS_cairo += ../build/dgl/Window.cpp.cairo.o | |||||
OBJS_cairo += ../build/dgl/pugl.cpp.cairo.o | |||||
endif | endif | ||||
# --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
OBJS_opengl = $(OBJS_common) \ | OBJS_opengl = $(OBJS_common) \ | ||||
../build/dgl/OpenGL.cpp.opengl.o \ | ../build/dgl/OpenGL.cpp.opengl.o \ | ||||
../build/dgl/Image.cpp.opengl.o \ | |||||
../build/dgl/ImageWidgets.cpp.opengl.o \ | |||||
../build/dgl/NanoVG.cpp.opengl.o \ | |||||
../build/dgl/WidgetPrivateData.cpp.opengl.o | |||||
../build/dgl/NanoVG.cpp.opengl.o | |||||
ifeq ($(MACOS),true) | |||||
OBJS_opengl += ../build/dgl/pugl.mm.opengl.o | |||||
else | |||||
OBJS_opengl += ../build/dgl/pugl.cpp.opengl.o | |||||
endif | |||||
# --------------------------------------------------------------------------------------------------------------------- | |||||
OBJS_stub = $(OBJS_common) | |||||
ifeq ($(MACOS),true) | ifeq ($(MACOS),true) | ||||
OBJS_opengl += ../build/dgl/Window.mm.opengl.o | |||||
OBJS_stub += ../build/dgl/pugl.mm.o | |||||
else | else | ||||
OBJS_opengl += ../build/dgl/Window.cpp.opengl.o | |||||
OBJS_stub += ../build/dgl/pugl.cpp.o | |||||
endif | |||||
# --------------------------------------------------------------------------------------------------------------------- | |||||
OBJS_vulkan = $(OBJS_common) \ | |||||
../build/dgl/Vulkan.cpp.vulkan.o | |||||
ifeq ($(MACOS),true) | |||||
OBJS_vulkan += ../build/dgl/pugl.mm.vulkan.o | |||||
else | |||||
OBJS_vulkan += ../build/dgl/pugl.cpp.vulkan.o | |||||
endif | endif | ||||
# --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
@@ -68,6 +101,14 @@ TARGETS += ../build/libdgl-opengl.a | |||||
TARGETS += ../build/libdgl.a | TARGETS += ../build/libdgl.a | ||||
endif | endif | ||||
ifeq ($(HAVE_STUB),true) | |||||
TARGETS += ../build/libdgl-stub.a | |||||
endif | |||||
ifeq ($(HAVE_VULKAN),true) | |||||
TARGETS += ../build/libdgl-vulkan.a | |||||
endif | |||||
# --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
all: $(TARGETS) | all: $(TARGETS) | ||||
@@ -86,6 +127,18 @@ all: $(TARGETS) | |||||
$(SILENT)rm -f $@ | $(SILENT)rm -f $@ | ||||
$(SILENT)$(AR) crs $@ $^ | $(SILENT)$(AR) crs $@ $^ | ||||
../build/libdgl-stub.a: $(OBJS_stub) | |||||
-@mkdir -p ../build | |||||
@echo "Creating libdgl-stub.a" | |||||
$(SILENT)rm -f $@ | |||||
$(SILENT)$(AR) crs $@ $^ | |||||
../build/libdgl-vulkan.a: $(OBJS_vulkan) | |||||
-@mkdir -p ../build | |||||
@echo "Creating libdgl-vulkan.a" | |||||
$(SILENT)rm -f $@ | |||||
$(SILENT)$(AR) crs $@ $^ | |||||
# Compat name, to be removed soon | # Compat name, to be removed soon | ||||
../build/libdgl.a: ../build/libdgl-opengl.a | ../build/libdgl.a: ../build/libdgl-opengl.a | ||||
@echo "Symlinking libdgl.a" | @echo "Symlinking libdgl.a" | ||||
@@ -103,6 +156,11 @@ all: $(TARGETS) | |||||
@echo "Compiling $<" | @echo "Compiling $<" | ||||
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | ||||
../build/dgl/%.mm.o: src/%.mm | |||||
-@mkdir -p ../build/dgl | |||||
@echo "Compiling $<" | |||||
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -ObjC++ -o $@ | |||||
# --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
../build/dgl/%.cpp.cairo.o: src/%.cpp | ../build/dgl/%.cpp.cairo.o: src/%.cpp | ||||
@@ -110,15 +168,10 @@ all: $(TARGETS) | |||||
@echo "Compiling $< (Cairo variant)" | @echo "Compiling $< (Cairo variant)" | ||||
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(CAIRO_FLAGS) -DDGL_CAIRO -c -o $@ | $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(CAIRO_FLAGS) -DDGL_CAIRO -c -o $@ | ||||
../build/dgl/Window.cpp.cairo.o: src/Window.cpp src/sofd/* src/pugl/* | |||||
-@mkdir -p ../build/dgl | |||||
@echo "Compiling $< (Cairo variant)" | |||||
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(CAIRO_FLAGS) -DDGL_CAIRO -c -o $@ | |||||
../build/dgl/Window.mm.cairo.o: src/Window.cpp src/sofd/* src/pugl/* | |||||
../build/dgl/%.mm.cairo.o: src/%.mm | |||||
-@mkdir -p ../build/dgl | -@mkdir -p ../build/dgl | ||||
@echo "Compiling $< (Cairo variant)" | @echo "Compiling $< (Cairo variant)" | ||||
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(CAIRO_FLAGS) -DDGL_CAIRO -ObjC++ -c -o $@ | |||||
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(CAIRO_FLAGS) -DDGL_CAIRO -c -ObjC++ -o $@ | |||||
# --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
@@ -127,15 +180,22 @@ all: $(TARGETS) | |||||
@echo "Compiling $< (OpenGL variant)" | @echo "Compiling $< (OpenGL variant)" | ||||
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(OPENGL_FLAGS) -DDGL_OPENGL -c -o $@ | $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(OPENGL_FLAGS) -DDGL_OPENGL -c -o $@ | ||||
../build/dgl/Window.cpp.opengl.o: src/Window.cpp src/sofd/* src/pugl/* | |||||
../build/dgl/%.mm.opengl.o: src/%.mm | |||||
-@mkdir -p ../build/dgl | -@mkdir -p ../build/dgl | ||||
@echo "Compiling $< (OpenGL variant)" | @echo "Compiling $< (OpenGL variant)" | ||||
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(OPENGL_FLAGS) -DDGL_OPENGL -c -o $@ | |||||
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(OPENGL_FLAGS) -DDGL_OPENGL -c -ObjC++ -o $@ | |||||
../build/dgl/Window.mm.opengl.o: src/Window.cpp src/sofd/* src/pugl/* | |||||
# --------------------------------------------------------------------------------------------------------------------- | |||||
../build/dgl/%.cpp.vulkan.o: src/%.cpp | |||||
-@mkdir -p ../build/dgl | -@mkdir -p ../build/dgl | ||||
@echo "Compiling $< (OpenGL variant)" | |||||
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(OPENGL_FLAGS) -DDGL_OPENGL -ObjC++ -c -o $@ | |||||
@echo "Compiling $< (Vulkan variant)" | |||||
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(VULKAN_FLAGS) -DDGL_VULKAN -c -o $@ | |||||
../build/dgl/%.mm.vulkan.o: src/%.mm | |||||
-@mkdir -p ../build/dgl | |||||
@echo "Compiling $< (Vulkan variant)" | |||||
$(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(VULKAN_FLAGS) -DDGL_VULKAN -c -ObjC++ -o $@ | |||||
# --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
@@ -150,5 +210,7 @@ debug: | |||||
-include $(OBJS_common:%.o=%.d) | -include $(OBJS_common:%.o=%.d) | ||||
-include $(OBJS_cairo:%.o=%.d) | -include $(OBJS_cairo:%.o=%.d) | ||||
-include $(OBJS_opengl:%.o=%.d) | -include $(OBJS_opengl:%.o=%.d) | ||||
-include $(OBJS_stub:%.o=%.d) | |||||
-include $(OBJS_vulkan:%.o=%.d) | |||||
# --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- |
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -19,7 +19,9 @@ | |||||
#include "Color.hpp" | #include "Color.hpp" | ||||
#include "OpenGL.hpp" | #include "OpenGL.hpp" | ||||
#include "Widget.hpp" | |||||
#include "SubWidget.hpp" | |||||
#include "TopLevelWidget.hpp" | |||||
#include "StandaloneWindow.hpp" | |||||
#ifndef DGL_NO_SHARED_RESOURCES | #ifndef DGL_NO_SHARED_RESOURCES | ||||
# define NANOVG_DEJAVU_SANS_TTF "__dpf_dejavusans_ttf__" | # define NANOVG_DEJAVU_SANS_TTF "__dpf_dejavusans_ttf__" | ||||
@@ -305,7 +307,9 @@ public: | |||||
/** | /** | ||||
Constructor reusing a NanoVG context, used for subwidgets. | Constructor reusing a NanoVG context, used for subwidgets. | ||||
*/ | */ | ||||
/* | |||||
NanoVG(NanoWidget* groupWidget); | NanoVG(NanoWidget* groupWidget); | ||||
*/ | |||||
/** | /** | ||||
Destructor. | Destructor. | ||||
@@ -851,7 +855,7 @@ public: | |||||
/** | /** | ||||
Load DPF's internal shared resources for this NanoVG class. | Load DPF's internal shared resources for this NanoVG class. | ||||
*/ | */ | ||||
virtual void loadSharedResources(); | |||||
virtual bool loadSharedResources(); | |||||
#endif | #endif | ||||
private: | private: | ||||
@@ -873,30 +877,39 @@ private: | |||||
The drawing function onDisplay() is implemented internally but a | The drawing function onDisplay() is implemented internally but a | ||||
new onNanoDisplay() needs to be overridden instead. | new onNanoDisplay() needs to be overridden instead. | ||||
*/ | */ | ||||
class NanoWidget : public Widget, | |||||
public NanoVG | |||||
template <class BaseWidget> | |||||
class NanoBaseWidget : public BaseWidget, | |||||
public NanoVG | |||||
{ | { | ||||
public: | public: | ||||
/** | /** | ||||
Constructor. | |||||
Constructor for a NanoSubWidget. | |||||
@see CreateFlags | @see CreateFlags | ||||
*/ | */ | ||||
explicit NanoWidget(Window& parent, int flags = CREATE_ANTIALIAS); | |||||
explicit NanoBaseWidget(Widget* const parentGroupWidget, int flags = CREATE_ANTIALIAS); | |||||
/** | /** | ||||
Constructor for a subwidget. | |||||
Constructor for a NanoTopLevelWidget. | |||||
@see CreateFlags | |||||
*/ | */ | ||||
explicit NanoWidget(Widget* groupWidget, int flags = CREATE_ANTIALIAS); | |||||
explicit NanoBaseWidget(Window& windowToMapTo, int flags = CREATE_ANTIALIAS); | |||||
/** | /** | ||||
Constructor for a subwidget, reusing a NanoVG context. | |||||
Constructor for a NanoStandaloneWindow without parent window. | |||||
@see CreateFlags | |||||
*/ | */ | ||||
explicit NanoWidget(NanoWidget* groupWidget); | |||||
explicit NanoBaseWidget(Application& app, int flags = CREATE_ANTIALIAS); | |||||
/** | |||||
Constructor for a NanoStandaloneWindow with parent window. | |||||
@see CreateFlags | |||||
*/ | |||||
explicit NanoBaseWidget(Application& app, Window& parentWindow, int flags = CREATE_ANTIALIAS); | |||||
/** | /** | ||||
Destructor. | Destructor. | ||||
*/ | */ | ||||
virtual ~NanoWidget(); | |||||
virtual ~NanoBaseWidget() {} | |||||
protected: | protected: | ||||
/** | /** | ||||
@@ -906,14 +919,16 @@ protected: | |||||
virtual void onNanoDisplay() = 0; | virtual void onNanoDisplay() = 0; | ||||
private: | private: | ||||
struct PrivateData; | |||||
PrivateData* const nData; | |||||
/** | /** | ||||
Widget display function. | Widget display function. | ||||
Implemented internally to wrap begin/endFrame() automatically. | Implemented internally to wrap begin/endFrame() automatically. | ||||
*/ | */ | ||||
void onDisplay() override; | |||||
inline void onDisplay() override | |||||
{ | |||||
NanoVG::beginFrame(BaseWidget::getWidth(), BaseWidget::getHeight()); | |||||
onNanoDisplay(); | |||||
NanoVG::endFrame(); | |||||
} | |||||
// these should not be used | // these should not be used | ||||
void beginFrame(uint,uint) {} | void beginFrame(uint,uint) {} | ||||
@@ -922,9 +937,16 @@ private: | |||||
void cancelFrame() {} | void cancelFrame() {} | ||||
void endFrame() {} | void endFrame() {} | ||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(NanoWidget) | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(NanoBaseWidget) | |||||
}; | }; | ||||
typedef NanoBaseWidget<SubWidget> NanoSubWidget; | |||||
typedef NanoBaseWidget<TopLevelWidget> NanoTopLevelWidget; | |||||
typedef NanoBaseWidget<StandaloneWindow> NanoStandaloneWindow; | |||||
DISTRHO_DEPRECATED_BY("NanoSubWidget") | |||||
typedef NanoSubWidget NanoWidget; | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
END_NAMESPACE_DGL | END_NAMESPACE_DGL | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -18,6 +18,7 @@ | |||||
#define DGL_OPENGL_HPP_INCLUDED | #define DGL_OPENGL_HPP_INCLUDED | ||||
#include "ImageBase.hpp" | #include "ImageBase.hpp" | ||||
#include "ImageBaseWidgets.hpp" | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// Fix OpenGL includes for Windows, based on glfw code (part 1) | // Fix OpenGL includes for Windows, based on glfw code (part 1) | ||||
@@ -108,14 +109,185 @@ START_NAMESPACE_DGL | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
/** | /** | ||||
Graphics context. | |||||
OpenGL Graphics context. | |||||
*/ | */ | ||||
struct GraphicsContext | |||||
struct OpenGLGraphicsContext : GraphicsContext | |||||
{ | { | ||||
}; | }; | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
static inline | |||||
ImageFormat asDISTRHOImageFormat(const GLenum format) | |||||
{ | |||||
switch (format) | |||||
{ | |||||
case GL_LUMINANCE: | |||||
return kImageFormatGrayscale; | |||||
case GL_BGR: | |||||
return kImageFormatBGR; | |||||
case GL_BGRA: | |||||
return kImageFormatBGRA; | |||||
case GL_RGB: | |||||
return kImageFormatRGB; | |||||
case GL_RGBA: | |||||
return kImageFormatRGBA; | |||||
} | |||||
return kImageFormatNull; | |||||
} | |||||
static inline | |||||
GLenum asOpenGLImageFormat(const ImageFormat format) | |||||
{ | |||||
switch (format) | |||||
{ | |||||
case kImageFormatNull: | |||||
break; | |||||
case kImageFormatGrayscale: | |||||
return GL_LUMINANCE; | |||||
case kImageFormatBGR: | |||||
return GL_BGR; | |||||
case kImageFormatBGRA: | |||||
return GL_BGRA; | |||||
case kImageFormatRGB: | |||||
return GL_RGB; | |||||
case kImageFormatRGBA: | |||||
return GL_RGBA; | |||||
} | |||||
return 0x0; | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
/** | |||||
OpenGL Image class. | |||||
This is an Image class that handles raw image data in pixels. | |||||
You can init the image data on the contructor or later on by calling loadFromMemory(). | |||||
To generate raw data useful for this class see the utils/png2rgba.py script. | |||||
Be careful when using a PNG without alpha channel, for those the format is 'GL_BGR' | |||||
instead of the default 'GL_BGRA'. | |||||
Images are drawn on screen via 2D textures. | |||||
*/ | |||||
class OpenGLImage : public ImageBase | |||||
{ | |||||
public: | |||||
/** | |||||
Constructor for a null Image. | |||||
*/ | |||||
OpenGLImage(); | |||||
/** | |||||
Constructor using raw image data. | |||||
@note @a rawData must remain valid for the lifetime of this Image. | |||||
*/ | |||||
OpenGLImage(const char* rawData, uint width, uint height, ImageFormat format = kImageFormatBGRA); | |||||
/** | |||||
Constructor using raw image data. | |||||
@note @a rawData must remain valid for the lifetime of this Image. | |||||
*/ | |||||
OpenGLImage(const char* rawData, const Size<uint>& size, ImageFormat format = kImageFormatBGRA); | |||||
/** | |||||
Constructor using another image data. | |||||
*/ | |||||
OpenGLImage(const OpenGLImage& image); | |||||
/** | |||||
Destructor. | |||||
*/ | |||||
~OpenGLImage() override; | |||||
/** | |||||
Load image data from memory. | |||||
@note @a rawData must remain valid for the lifetime of this Image. | |||||
*/ | |||||
void loadFromMemory(const char* rawData, | |||||
const Size<uint>& size, | |||||
ImageFormat format = kImageFormatBGRA) noexcept override; | |||||
/** | |||||
Draw this image at position @a pos using the graphics context @a context. | |||||
*/ | |||||
void drawAt(const GraphicsContext& context, const Point<int>& pos) override; | |||||
/** | |||||
TODO document this. | |||||
*/ | |||||
OpenGLImage& operator=(const OpenGLImage& image) noexcept; | |||||
// FIXME this should not be needed | |||||
inline void loadFromMemory(const char* rdata, uint w, uint h, ImageFormat fmt = kImageFormatBGRA) | |||||
{ loadFromMemory(rdata, Size<uint>(w, h), fmt); }; | |||||
inline void draw(const GraphicsContext& context) | |||||
{ drawAt(context, Point<int>(0, 0)); }; | |||||
inline void drawAt(const GraphicsContext& context, int x, int y) | |||||
{ drawAt(context, Point<int>(x, y)); }; | |||||
/** | |||||
Constructor using raw image data, specifying an OpenGL image format. | |||||
@note @a rawData must remain valid for the lifetime of this Image. | |||||
DEPRECATED This constructor uses OpenGL image format instead of DISTRHO one. | |||||
*/ | |||||
DISTRHO_DEPRECATED_BY("OpenGLImage(const char*, uint, uint, ImageFormat)") | |||||
explicit OpenGLImage(const char* rawData, uint width, uint height, GLenum glFormat); | |||||
/** | |||||
Constructor using raw image data, specifying an OpenGL image format. | |||||
@note @a rawData must remain valid for the lifetime of this Image. | |||||
DEPRECATED This constructor uses OpenGL image format instead of DISTRHO one. | |||||
*/ | |||||
DISTRHO_DEPRECATED_BY("OpenGLImage(const char*, const Size<uint>&, ImageFormat)") | |||||
explicit OpenGLImage(const char* rawData, const Size<uint>& size, GLenum glFormat); | |||||
/** | |||||
Draw this image at (0, 0) point using the current OpenGL context. | |||||
DEPRECATED This function does not take into consideration the current graphics context and only works in OpenGL. | |||||
*/ | |||||
DISTRHO_DEPRECATED_BY("draw(const GraphicsContext&)") | |||||
void draw(); | |||||
/** | |||||
Draw this image at (x, y) point using the current OpenGL context. | |||||
DEPRECATED This function does not take into consideration the current graphics context and only works in OpenGL. | |||||
*/ | |||||
DISTRHO_DEPRECATED_BY("drawAt(const GraphicsContext&, int, int)") | |||||
void drawAt(int x, int y); | |||||
/** | |||||
Draw this image at position @a pos using the current OpenGL context. | |||||
DEPRECATED This function does not take into consideration the current graphics context and only works in OpenGL. | |||||
*/ | |||||
DISTRHO_DEPRECATED_BY("drawAt(const GraphicsContext&, const Point<int>&)") | |||||
void drawAt(const Point<int>& pos); | |||||
/** | |||||
Get the image type. | |||||
DEPRECATED Type is always assumed to be GL_UNSIGNED_BYTE. | |||||
*/ | |||||
DISTRHO_DEPRECATED | |||||
GLenum getType() const noexcept { return GL_UNSIGNED_BYTE; } | |||||
private: | |||||
GLuint textureId; | |||||
bool setupCalled; | |||||
}; | |||||
// ----------------------------------------------------------------------- | |||||
typedef ImageBaseAboutWindow<OpenGLImage> OpenGLImageAboutWindow; | |||||
typedef ImageBaseButton<OpenGLImage> OpenGLImageButton; | |||||
typedef ImageBaseKnob<OpenGLImage> OpenGLImageKnob; | |||||
typedef ImageBaseSlider<OpenGLImage> OpenGLImageSlider; | |||||
typedef ImageBaseSwitch<OpenGLImage> OpenGLImageSwitch; | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DGL | END_NAMESPACE_DGL | ||||
#endif | #endif |
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -17,39 +17,53 @@ | |||||
#ifndef DGL_STANDALONE_WINDOW_HPP_INCLUDED | #ifndef DGL_STANDALONE_WINDOW_HPP_INCLUDED | ||||
#define DGL_STANDALONE_WINDOW_HPP_INCLUDED | #define DGL_STANDALONE_WINDOW_HPP_INCLUDED | ||||
#include "Application.hpp" | |||||
#include "Widget.hpp" | |||||
#include "TopLevelWidget.hpp" | |||||
#include "Window.hpp" | #include "Window.hpp" | ||||
START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
class StandaloneWindow : public Application, | |||||
public Window | |||||
class StandaloneWindow : public Window, | |||||
public TopLevelWidget | |||||
{ | { | ||||
public: | public: | ||||
/** | /** | ||||
Constructor. | |||||
Constructor without parent. | |||||
*/ | */ | ||||
StandaloneWindow(); | |||||
StandaloneWindow(Application& app) | |||||
: Window(app), | |||||
TopLevelWidget((Window&)*this) {} | |||||
/** | /** | ||||
Show window and execute application. | |||||
Constructor with parent window, typically used to run as modal. | |||||
*/ | */ | ||||
void exec(); | |||||
StandaloneWindow(Application& app, Window& parentWindow) | |||||
: Window(app, parentWindow), | |||||
TopLevelWidget((Window&)*this) {} | |||||
private: | |||||
Widget* fWidget; | |||||
/** @internal */ | |||||
void onReshape(uint width, uint height) override; | |||||
/** @internal */ | |||||
void _addWidget(Widget* widget) override; | |||||
/** @internal */ | |||||
void _removeWidget(Widget* widget) override; | |||||
/** | |||||
Overloaded functions to ensure they apply to the Window class. | |||||
*/ | |||||
bool isVisible() const noexcept { return Window::isVisible(); } | |||||
void setVisible(bool yesNo) { Window::setVisible(yesNo); } | |||||
void hide() { Window::hide(); } | |||||
void show() { Window::show(); } | |||||
uint getWidth() const noexcept { return Window::getWidth(); } | |||||
uint getHeight() const noexcept { return Window::getHeight(); } | |||||
const Size<uint> getSize() const noexcept { return Window::getSize(); } | |||||
void repaint() noexcept { Window::repaint(); } | |||||
void setWidth(uint width) { Window::setWidth(width); } | |||||
void setHeight(uint height) { Window::setHeight(height); } | |||||
void setSize(uint width, uint height) { Window::setSize(width, height); } | |||||
void setSize(const Size<uint>& size) { Window::setSize(size); } | |||||
bool addIdleCallback(IdleCallback* callback, uint timerFrequencyInMs = 0) | |||||
{ return Window::addIdleCallback(callback, timerFrequencyInMs); } | |||||
bool removeIdleCallback(IdleCallback* callback) { return Window::removeIdleCallback(callback); } | |||||
const GraphicsContext& getGraphicsContext() const noexcept { return Window::getGraphicsContext(); } | |||||
void setGeometryConstraints(uint minimumWidth, uint minimumHeight, | |||||
bool keepAspectRatio = false, bool automaticallyScale = false) | |||||
{ Window::setGeometryConstraints(minimumWidth, minimumHeight, keepAspectRatio, automaticallyScale); } | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(StandaloneWindow) | DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(StandaloneWindow) | ||||
}; | }; | ||||
@@ -0,0 +1,148 @@ | |||||
/* | |||||
* DISTRHO Plugin Framework (DPF) | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#ifndef DGL_SUBWIDGET_HPP_INCLUDED | |||||
#define DGL_SUBWIDGET_HPP_INCLUDED | |||||
#include "Widget.hpp" | |||||
START_NAMESPACE_DGL | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
/** | |||||
Sub-Widget class. | |||||
This class is the main entry point for creating any reusable widgets from within DGL. | |||||
It can be freely positioned from within a parent widget, thus being named subwidget. | |||||
Many subwidgets can share the same parent, and subwidgets themselves can also have its own subwidgets. | |||||
It is subwidgets all the way down. | |||||
TODO check absolute vs relative position and see what makes more sense. | |||||
@see CairoSubWidget | |||||
*/ | |||||
class SubWidget : public Widget | |||||
{ | |||||
public: | |||||
/** | |||||
Constructor. | |||||
*/ | |||||
explicit SubWidget(Widget* parentWidget); | |||||
/** | |||||
Destructor. | |||||
*/ | |||||
virtual ~SubWidget(); | |||||
/** | |||||
Check if this widget contains the point defined by @a x and @a y. | |||||
*/ | |||||
// TODO rename as containsRelativePos | |||||
template<typename T> | |||||
bool contains(T x, T y) const noexcept; | |||||
/** | |||||
Check if this widget contains the point @a pos. | |||||
*/ | |||||
// TODO rename as containsRelativePos | |||||
template<typename T> | |||||
bool contains(const Point<T>& pos) const noexcept; | |||||
/** | |||||
Get absolute X. | |||||
*/ | |||||
int getAbsoluteX() const noexcept; | |||||
/** | |||||
Get absolute Y. | |||||
*/ | |||||
int getAbsoluteY() const noexcept; | |||||
/** | |||||
Get absolute position. | |||||
*/ | |||||
Point<int> getAbsolutePos() const noexcept; | |||||
/** | |||||
Get absolute area of this subwidget. | |||||
This is the same as `Rectangle<int>(getAbsolutePos(), getSize());` | |||||
@see getConstrainedAbsoluteArea() | |||||
*/ | |||||
Rectangle<int> getAbsoluteArea() const noexcept; | |||||
/** | |||||
Get absolute area of this subwidget, with special consideration for not allowing negative values. | |||||
@see getAbsoluteArea() | |||||
*/ | |||||
Rectangle<uint> getConstrainedAbsoluteArea() const noexcept; | |||||
/** | |||||
Set absolute X. | |||||
*/ | |||||
void setAbsoluteX(int x) noexcept; | |||||
/** | |||||
Set absolute Y. | |||||
*/ | |||||
void setAbsoluteY(int y) noexcept; | |||||
/** | |||||
Set absolute position using @a x and @a y values. | |||||
*/ | |||||
void setAbsolutePos(int x, int y) noexcept; | |||||
/** | |||||
Set absolute position. | |||||
*/ | |||||
void setAbsolutePos(const Point<int>& pos) noexcept; | |||||
/** | |||||
Get parent Widget, as passed in the constructor. | |||||
*/ | |||||
Widget* getParentWidget() const noexcept; | |||||
/** | |||||
Request repaint of this subwidget's area to the window this widget belongs to. | |||||
*/ | |||||
void repaint() noexcept override; | |||||
/** | |||||
Indicate that this subwidget will draw out of bounds, and thus needs the entire viewport available for drawing. | |||||
*/ | |||||
void setNeedsFullViewportDrawing(bool needsFullViewportForDrawing = true); | |||||
protected: | |||||
/** | |||||
A function called when the subwidget's absolute position is changed. | |||||
*/ | |||||
virtual void onPositionChanged(const PositionChangedEvent&); | |||||
private: | |||||
struct PrivateData; | |||||
PrivateData* const pData; | |||||
friend class Widget; | |||||
template <class BaseWidget> friend class NanoBaseWidget; | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(SubWidget) | |||||
}; | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
END_NAMESPACE_DGL | |||||
#endif // DGL_SUBWIDGET_HPP_INCLUDED | |||||
@@ -0,0 +1,101 @@ | |||||
/* | |||||
* DISTRHO Plugin Framework (DPF) | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#ifndef DGL_TOP_LEVEL_WIDGET_HPP_INCLUDED | |||||
#define DGL_TOP_LEVEL_WIDGET_HPP_INCLUDED | |||||
#include "Widget.hpp" | |||||
#ifdef DISTRHO_DEFINES_H_INCLUDED | |||||
START_NAMESPACE_DISTRHO | |||||
class UI; | |||||
END_NAMESPACE_DISTRHO | |||||
#endif | |||||
START_NAMESPACE_DGL | |||||
class Window; | |||||
// ----------------------------------------------------------------------- | |||||
/** | |||||
Top-Level Widget class. | |||||
This is the only Widget class that is allowed to be used directly on a Window. | |||||
This widget takes the full size of the Window it is mapped to. | |||||
Sub-widgets can be added on top of this top-level widget, by creating them with this class as parent. | |||||
Doing so allows for custom position and sizes. | |||||
This class is used as the type for DPF Plugin UIs. | |||||
So anything that a plugin UI might need that does not belong in a simple Widget will go here. | |||||
*/ | |||||
class TopLevelWidget : public Widget | |||||
{ | |||||
public: | |||||
/** | |||||
Constructor. | |||||
*/ | |||||
explicit TopLevelWidget(Window& windowToMapTo); | |||||
/** | |||||
Destructor. | |||||
*/ | |||||
virtual ~TopLevelWidget(); | |||||
/** | |||||
Get the application associated with this top-level widget's window. | |||||
*/ | |||||
Application& getApp() const noexcept; | |||||
/** | |||||
Get the window associated with this top-level widget. | |||||
*/ | |||||
Window& getWindow() const noexcept; | |||||
// TODO group stuff after here, convenience functions present in Window class | |||||
bool addIdleCallback(IdleCallback* callback, uint timerFrequencyInMs = 0); | |||||
bool removeIdleCallback(IdleCallback* callback); | |||||
double getScaleFactor() const noexcept; | |||||
void repaint() noexcept; | |||||
void repaint(const Rectangle<uint>& rect) noexcept; | |||||
void setGeometryConstraints(uint minimumWidth, | |||||
uint minimumHeight, | |||||
bool keepAspectRatio = false, | |||||
bool automaticallyScale = false); | |||||
DISTRHO_DEPRECATED_BY("getApp()") | |||||
Application& getParentApp() const noexcept { return getApp(); } | |||||
DISTRHO_DEPRECATED_BY("getWindow()") | |||||
Window& getParentWindow() const noexcept { return getWindow(); } | |||||
private: | |||||
struct PrivateData; | |||||
PrivateData* const pData; | |||||
friend class Window; | |||||
#ifdef DISTRHO_DEFINES_H_INCLUDED | |||||
friend class DISTRHO_NAMESPACE::UI; | |||||
#endif | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(TopLevelWidget) | |||||
}; | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DGL | |||||
#endif // DGL_TOP_LEVEL_WIDGET_HPP_INCLUDED |
@@ -0,0 +1,103 @@ | |||||
/* | |||||
* DISTRHO Plugin Framework (DPF) | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#ifndef DGL_VULKAN_HPP_INCLUDED | |||||
#define DGL_VULKAN_HPP_INCLUDED | |||||
#include "ImageBase.hpp" | |||||
#include <vulkan/vulkan_core.h> | |||||
START_NAMESPACE_DGL | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
/** | |||||
Vulkan Graphics context. | |||||
*/ | |||||
struct VulkanGraphicsContext : GraphicsContext | |||||
{ | |||||
}; | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
/** | |||||
Vulkan Image class. | |||||
TODO ... | |||||
*/ | |||||
class VulkanImage : public ImageBase | |||||
{ | |||||
public: | |||||
/** | |||||
Constructor for a null Image. | |||||
*/ | |||||
VulkanImage(); | |||||
/** | |||||
Constructor using raw image data. | |||||
@note @a rawData must remain valid for the lifetime of this Image. | |||||
*/ | |||||
VulkanImage(const char* rawData, uint width, uint height, ImageFormat format); | |||||
/** | |||||
Constructor using raw image data. | |||||
@note @a rawData must remain valid for the lifetime of this Image. | |||||
*/ | |||||
VulkanImage(const char* rawData, const Size<uint>& size, ImageFormat format); | |||||
/** | |||||
Constructor using another image data. | |||||
*/ | |||||
VulkanImage(const VulkanImage& image); | |||||
/** | |||||
Destructor. | |||||
*/ | |||||
~VulkanImage() override; | |||||
/** | |||||
Load image data from memory. | |||||
@note @a rawData must remain valid for the lifetime of this Image. | |||||
*/ | |||||
void loadFromMemory(const char* rawData, | |||||
const Size<uint>& size, | |||||
ImageFormat format = kImageFormatBGRA) noexcept override; | |||||
/** | |||||
Draw this image at position @a pos using the graphics context @a context. | |||||
*/ | |||||
void drawAt(const GraphicsContext& context, const Point<int>& pos) override; | |||||
/** | |||||
TODO document this. | |||||
*/ | |||||
VulkanImage& operator=(const VulkanImage& image) noexcept; | |||||
// FIXME this should not be needed | |||||
inline void loadFromMemory(const char* rdata, uint w, uint h, ImageFormat fmt = kImageFormatBGRA) | |||||
{ loadFromMemory(rdata, Size<uint>(w, h), fmt); }; | |||||
inline void draw(const GraphicsContext& context) | |||||
{ drawAt(context, Point<int>(0, 0)); }; | |||||
inline void drawAt(const GraphicsContext& context, int x, int y) | |||||
{ drawAt(context, Point<int>(x, y)); }; | |||||
}; | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
END_NAMESPACE_DGL | |||||
#endif |
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -19,82 +19,97 @@ | |||||
#include "Geometry.hpp" | #include "Geometry.hpp" | ||||
#include <vector> | |||||
START_NAMESPACE_DGL | |||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// Forward class names | // Forward class names | ||||
#ifdef DISTRHO_DEFINES_H_INCLUDED | |||||
START_NAMESPACE_DISTRHO | |||||
class UI; | |||||
END_NAMESPACE_DISTRHO | |||||
#endif | |||||
START_NAMESPACE_DGL | |||||
class Application; | class Application; | ||||
class ImageSlider; | |||||
class NanoWidget; | |||||
class SubWidget; | |||||
class TopLevelWidget; | |||||
class Window; | class Window; | ||||
class StandaloneWindow; | |||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
/** | /** | ||||
Base DGL Widget class. | Base DGL Widget class. | ||||
This is the base Widget class, from which all widgets are built. | This is the base Widget class, from which all widgets are built. | ||||
All widgets have a parent Window where they'll be drawn. | |||||
This parent is never changed during the widget lifetime. | |||||
All widgets have a parent widget where they'll be drawn, this can be the top-level widget or a group widget. | |||||
This parent is never changed during a widget's lifetime. | |||||
Widgets receive events in relative coordinates. | |||||
(0, 0) means its top-left position. | |||||
Widgets receive events in relative coordinates. (0, 0) means its top-left position. | |||||
Windows paint widgets in the order they are constructed. | |||||
Early widgets are drawn first, at the bottom, then newer ones on top. | |||||
Events are sent in the inverse order so that the top-most widget gets | |||||
The top-level widget will draw subwidgets in the order they are constructed. | |||||
Early subwidgets are drawn first, at the bottom, then newer ones on top. | |||||
Events are sent in the inverse order so that the top-most widgets get | |||||
a chance to catch the event and stop its propagation. | a chance to catch the event and stop its propagation. | ||||
All widget event callbacks do nothing by default. | |||||
All widget event callbacks do nothing by default and onDisplay MUST be reimplemented by subclasses. | |||||
@note It is not possible to subclass this Widget class directly, you must use SubWidget or TopLevelWidget instead. | |||||
*/ | */ | ||||
class Widget | class Widget | ||||
{ | { | ||||
public: | public: | ||||
/** | /** | ||||
Base event data. | Base event data. | ||||
@a mod The currently active keyboard modifiers, @see Modifier. | |||||
@a time The timestamp (if any). | |||||
These are the fields present on all Widget events. | |||||
@a mod Currently active keyboard modifiers, @see Modifier. | |||||
@a mod Event flags, @see Flag. | |||||
@a time Event timestamp (if any). | |||||
*/ | */ | ||||
struct BaseEvent { | struct BaseEvent { | ||||
uint mod; | |||||
uint32_t time; | |||||
uint mod; | |||||
uint flags; | |||||
uint time; | |||||
/** Constuctor */ | /** Constuctor */ | ||||
BaseEvent() noexcept : mod(0x0), time(0) {} | |||||
BaseEvent() noexcept : mod(0x0), flags(0x0), time(0) {} | |||||
/** Destuctor */ | /** Destuctor */ | ||||
virtual ~BaseEvent() noexcept {} | virtual ~BaseEvent() noexcept {} | ||||
}; | }; | ||||
/** | /** | ||||
Keyboard event. | Keyboard event. | ||||
@a press True if the key was pressed, false if released. | |||||
@a key Unicode point of the key pressed. | |||||
This event represents low-level key presses and releases. | |||||
This can be used for "direct" keyboard handing like key bindings, but must not be interpreted as text input. | |||||
Keys are represented portably as Unicode code points, using the "natural" code point for the key. | |||||
The @a key field is the code for the pressed key, without any modifiers applied. | |||||
For example, a press or release of the 'A' key will have `key` 97 ('a') | |||||
regardless of whether shift or control are being held. | |||||
Alternatively, the raw @a keycode can be used to work directly with physical keys, | |||||
but note that this value is not portable and differs between platforms and hardware. | |||||
@a press True if the key was pressed, false if released. | |||||
@a key Unicode point of the key pressed. | |||||
@a keycode Raw keycode. | |||||
@see onKeyboard | @see onKeyboard | ||||
*/ | */ | ||||
struct KeyboardEvent : BaseEvent { | struct KeyboardEvent : BaseEvent { | ||||
bool press; | bool press; | ||||
uint key; | uint key; | ||||
uint keycode; | |||||
/** Constuctor */ | /** Constuctor */ | ||||
KeyboardEvent() noexcept | KeyboardEvent() noexcept | ||||
: BaseEvent(), | : BaseEvent(), | ||||
press(false), | press(false), | ||||
key(0) {} | |||||
key(0), | |||||
keycode(0) {} | |||||
}; | }; | ||||
/** | /** | ||||
Special keyboard event. | Special keyboard event. | ||||
This event allows the use of keys that do not have unicode points. | |||||
Note that some are non-printable keys. | |||||
@a press True if the key was pressed, false if released. | @a press True if the key was pressed, false if released. | ||||
@a key The key pressed. | @a key The key pressed. | ||||
@see onSpecial | @see onSpecial | ||||
@@ -111,54 +126,94 @@ public: | |||||
}; | }; | ||||
/** | /** | ||||
Mouse event. | |||||
@a button The button number (1 = left, 2 = middle, 3 = right). | |||||
Character input event. | |||||
This event represents text input, usually as the result of a key press. | |||||
The text is given both as a Unicode character code and a UTF-8 string. | |||||
Note that this event is generated by the platform's input system, | |||||
so there is not necessarily a direct correspondence between text events and physical key presses. | |||||
For example, with some input methods a sequence of several key presses will generate a single character. | |||||
@a keycode Raw key code. | |||||
@a character Unicode character code. | |||||
@a string UTF-8 string. | |||||
@see onCharacterInput | |||||
*/ | |||||
struct CharacterInputEvent : BaseEvent { | |||||
uint keycode; | |||||
uint character; | |||||
char string[8]; | |||||
/** Constuctor */ | |||||
CharacterInputEvent() noexcept | |||||
: BaseEvent(), | |||||
keycode(0), | |||||
character(0), | |||||
string{'\0','\0','\0','\0','\0','\0','\0','\0'} {} | |||||
}; | |||||
/** | |||||
Mouse press or release event. | |||||
@a button The button number starting from 1 (1 = left, 2 = middle, 3 = right). | |||||
@a press True if the button was pressed, false if released. | @a press True if the button was pressed, false if released. | ||||
@a pos The widget-relative coordinates of the pointer. | @a pos The widget-relative coordinates of the pointer. | ||||
@see onMouse | @see onMouse | ||||
*/ | */ | ||||
struct MouseEvent : BaseEvent { | struct MouseEvent : BaseEvent { | ||||
int button; | |||||
uint button; | |||||
bool press; | bool press; | ||||
Point<int> pos; | |||||
Point<double> pos; | |||||
/** Constuctor */ | /** Constuctor */ | ||||
MouseEvent() noexcept | MouseEvent() noexcept | ||||
: BaseEvent(), | : BaseEvent(), | ||||
button(0), | button(0), | ||||
press(false), | press(false), | ||||
pos(0, 0) {} | |||||
pos(0.0, 0.0) {} | |||||
}; | }; | ||||
/** | /** | ||||
Mouse motion event. | Mouse motion event. | ||||
@a pos The widget-relative coordinates of the pointer. | @a pos The widget-relative coordinates of the pointer. | ||||
@see onMotion | @see onMotion | ||||
*/ | */ | ||||
struct MotionEvent : BaseEvent { | struct MotionEvent : BaseEvent { | ||||
Point<int> pos; | |||||
Point<double> pos; | |||||
/** Constuctor */ | /** Constuctor */ | ||||
MotionEvent() noexcept | MotionEvent() noexcept | ||||
: BaseEvent(), | : BaseEvent(), | ||||
pos(0, 0) {} | |||||
pos(0.0, 0.0) {} | |||||
}; | }; | ||||
/** | /** | ||||
Mouse scroll event. | Mouse scroll event. | ||||
@a pos The widget-relative coordinates of the pointer. | |||||
@a delta The scroll distance. | |||||
The scroll distance is expressed in "lines", | |||||
an arbitrary unit that corresponds to a single tick of a detented mouse wheel. | |||||
For example, `delta.y` = 1.0 scrolls 1 line up. | |||||
Some systems and devices support finer resolution and/or higher values for fast scrolls, | |||||
so programs should handle any value gracefully. | |||||
@a pos The widget-relative coordinates of the pointer. | |||||
@a delta The scroll distance. | |||||
@a direction The direction of the scroll or "smooth". | |||||
@see onScroll | @see onScroll | ||||
*/ | */ | ||||
struct ScrollEvent : BaseEvent { | struct ScrollEvent : BaseEvent { | ||||
Point<int> pos; | |||||
Point<float> delta; | |||||
Point<double> pos; | |||||
Point<double> delta; | |||||
ScrollDirection direction; | |||||
/** Constuctor */ | /** Constuctor */ | ||||
ScrollEvent() noexcept | ScrollEvent() noexcept | ||||
: BaseEvent(), | : BaseEvent(), | ||||
pos(0, 0), | |||||
delta(0.0f, 0.0f) {} | |||||
pos(0.0, 0.0), | |||||
delta(0.0, 0.0), | |||||
direction(kScrollSmooth) {} | |||||
}; | }; | ||||
/** | /** | ||||
@@ -193,16 +248,18 @@ public: | |||||
oldPos(0, 0) {} | oldPos(0, 0) {} | ||||
}; | }; | ||||
private: | |||||
/** | /** | ||||
Constructor. | |||||
Private constructor, reserved for TopLevelWidget class. | |||||
*/ | */ | ||||
explicit Widget(Window& parent); | |||||
explicit Widget(TopLevelWidget* topLevelWidget); | |||||
/** | /** | ||||
Constructor for a subwidget. | |||||
Private constructor, reserved for SubWidget class. | |||||
*/ | */ | ||||
explicit Widget(Widget* groupWidget); | |||||
explicit Widget(Widget* widgetToGroupTo); | |||||
public: | |||||
/** | /** | ||||
Destructor. | Destructor. | ||||
*/ | */ | ||||
@@ -215,9 +272,9 @@ public: | |||||
bool isVisible() const noexcept; | bool isVisible() const noexcept; | ||||
/** | /** | ||||
Set widget visible (or not) according to @a yesNo. | |||||
Set widget visible (or not) according to @a visible. | |||||
*/ | */ | ||||
void setVisible(bool yesNo); | |||||
void setVisible(bool visible); | |||||
/** | /** | ||||
Show widget. | Show widget. | ||||
@@ -244,7 +301,7 @@ public: | |||||
/** | /** | ||||
Get size. | Get size. | ||||
*/ | */ | ||||
const Size<uint>& getSize() const noexcept; | |||||
const Size<uint> getSize() const noexcept; | |||||
/** | /** | ||||
Set width. | Set width. | ||||
@@ -267,81 +324,58 @@ public: | |||||
void setSize(const Size<uint>& size) noexcept; | void setSize(const Size<uint>& size) noexcept; | ||||
/** | /** | ||||
Get absolute X. | |||||
*/ | |||||
int getAbsoluteX() const noexcept; | |||||
/** | |||||
Get absolute Y. | |||||
*/ | |||||
int getAbsoluteY() const noexcept; | |||||
/** | |||||
Get absolute position. | |||||
*/ | |||||
const Point<int>& getAbsolutePos() const noexcept; | |||||
/** | |||||
Set absolute X. | |||||
*/ | |||||
void setAbsoluteX(int x) noexcept; | |||||
/** | |||||
Set absolute Y. | |||||
*/ | |||||
void setAbsoluteY(int y) noexcept; | |||||
/** | |||||
Set absolute position using @a x and @a y values. | |||||
Get the Id associated with this widget. | |||||
@see setId | |||||
*/ | */ | ||||
void setAbsolutePos(int x, int y) noexcept; | |||||
uint getId() const noexcept; | |||||
/** | /** | ||||
Set absolute position. | |||||
Set an Id to be associated with this widget. | |||||
@see getId | |||||
*/ | */ | ||||
void setAbsolutePos(const Point<int>& pos) noexcept; | |||||
void setId(uint id) noexcept; | |||||
/** | /** | ||||
Get this widget's window application. | |||||
Same as calling getParentWindow().getApp(). | |||||
Get the application associated with this widget's window. | |||||
This is the same as calling `getTopLevelWidget()->getApp()`. | |||||
*/ | */ | ||||
Application& getParentApp() const noexcept; | |||||
Application& getApp() const noexcept; | |||||
/** | /** | ||||
Get parent window, as passed in the constructor. | |||||
Get the window associated with this widget. | |||||
This is the same as calling `getTopLevelWidget()->getWindow()`. | |||||
*/ | */ | ||||
Window& getParentWindow() const noexcept; | |||||
Window& getWindow() const noexcept; | |||||
/** | /** | ||||
Check if this widget contains the point defined by @a x and @a y. | |||||
Get the graphics context associated with this widget's window. | |||||
GraphicsContext is an empty struct and needs to be casted into a different type in order to be usable, | |||||
for example GraphicsContext. | |||||
@see CairoSubWidget, CairoTopLevelWidget | |||||
*/ | */ | ||||
bool contains(int x, int y) const noexcept; | |||||
const GraphicsContext& getGraphicsContext() const noexcept; | |||||
/** | /** | ||||
Check if this widget contains the point @a pos. | |||||
Get top-level widget, as passed directly in the constructor | |||||
or going up the chain of group widgets until it finds the top-level one. | |||||
*/ | */ | ||||
bool contains(const Point<int>& pos) const noexcept; | |||||
TopLevelWidget* getTopLevelWidget() const noexcept; | |||||
/** | /** | ||||
Tell this widget's window to repaint itself. | |||||
Request repaint of this widget's area to the window this widget belongs to. | |||||
On the raw Widget class this function does nothing. | |||||
*/ | */ | ||||
void repaint() noexcept; | |||||
virtual void repaint() noexcept; | |||||
/** | |||||
Get the Id associated with this widget. | |||||
@see setId | |||||
*/ | |||||
uint getId() const noexcept; | |||||
DISTRHO_DEPRECATED_BY("getApp()") | |||||
Application& getParentApp() const noexcept { return getApp(); } | |||||
/** | |||||
Set an Id to be associated with this widget. | |||||
@see getId | |||||
*/ | |||||
void setId(uint id) noexcept; | |||||
DISTRHO_DEPRECATED_BY("getWindow()") | |||||
Window& getParentWindow() const noexcept { return getWindow(); } | |||||
protected: | protected: | ||||
/** | /** | ||||
A function called to draw the view contents with OpenGL. | |||||
A function called to draw the widget contents. | |||||
*/ | */ | ||||
virtual void onDisplay() = 0; | virtual void onDisplay() = 0; | ||||
@@ -357,6 +391,12 @@ protected: | |||||
*/ | */ | ||||
virtual bool onSpecial(const SpecialEvent&); | virtual bool onSpecial(const SpecialEvent&); | ||||
/** | |||||
A function called when an UTF-8 character is received. | |||||
@return True to stop event propagation, false otherwise. | |||||
*/ | |||||
virtual bool onCharacterInput(const CharacterInputEvent&); | |||||
/** | /** | ||||
A function called when a mouse button is pressed or released. | A function called when a mouse button is pressed or released. | ||||
@return True to stop event propagation, false otherwise. | @return True to stop event propagation, false otherwise. | ||||
@@ -380,30 +420,16 @@ protected: | |||||
*/ | */ | ||||
virtual void onResize(const ResizeEvent&); | virtual void onResize(const ResizeEvent&); | ||||
/** | |||||
A function called when the widget's absolute position is changed. | |||||
*/ | |||||
virtual void onPositionChanged(const PositionChangedEvent&); | |||||
private: | private: | ||||
struct PrivateData; | struct PrivateData; | ||||
PrivateData* const pData; | PrivateData* const pData; | ||||
/** @internal */ | |||||
explicit Widget(Widget* groupWidget, bool addToSubWidgets); | |||||
friend class ImageSlider; | |||||
friend class NanoWidget; | |||||
friend class Window; | |||||
friend class StandaloneWindow; | |||||
#ifdef DISTRHO_DEFINES_H_INCLUDED | |||||
friend class DISTRHO_NAMESPACE::UI; | |||||
#endif | |||||
friend class SubWidget; | |||||
friend class TopLevelWidget; | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Widget) | DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Widget) | ||||
}; | }; | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
END_NAMESPACE_DGL | END_NAMESPACE_DGL | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -19,50 +19,79 @@ | |||||
#include "Geometry.hpp" | #include "Geometry.hpp" | ||||
#ifdef DISTRHO_DEFINES_H_INCLUDED | |||||
START_NAMESPACE_DISTRHO | |||||
class UIExporter; | |||||
END_NAMESPACE_DISTRHO | |||||
#endif | |||||
START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
class Application; | |||||
class TopLevelWidget; | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
class Application; | |||||
class Widget; | |||||
class StandaloneWindow; | |||||
/** | |||||
DGL Window class. | |||||
This is the where all OS-related events initially happen, before being propagated to any widgets. | |||||
A Window MUST have an Application instance tied to it. | |||||
It is not possible to swap Application instances from within the lifetime of a Window. | |||||
But it is possible to completely change the Widgets that a Window contains during its lifetime. | |||||
Typically the event handling functions as following: | |||||
Application -> Window -> Top-Level-Widget -> SubWidgets | |||||
Please note that, unlike many other graphical toolkits out there, | |||||
DGL makes a clear distinction between a Window and a Widget. | |||||
You cannot directly draw in a Window, you need to create a Widget for that. | |||||
Also, a Window MUST have a single top-level Widget. | |||||
The Window will take care of global screen positioning and resizing, everything else is sent for widgets to handle. | |||||
... | |||||
*/ | |||||
class Window | class Window | ||||
{ | { | ||||
public: | public: | ||||
#ifndef DGL_FILE_BROWSER_DISABLED | #ifndef DGL_FILE_BROWSER_DISABLED | ||||
/** | /** | ||||
File browser options. | File browser options. | ||||
@see Window::openFileBrowser | |||||
*/ | */ | ||||
struct FileBrowserOptions { | struct FileBrowserOptions { | ||||
/** | |||||
File browser button state. | |||||
This allows to customize the behaviour of the file browse dialog buttons. | |||||
*/ | |||||
enum ButtonState { | |||||
kButtonInvisible, | |||||
kButtonVisibleUnchecked, | |||||
kButtonVisibleChecked, | |||||
}; | |||||
/** Start directory, uses current working directory if null */ | |||||
const char* startDir; | const char* startDir; | ||||
/** File browser dialog window title, uses "FileBrowser" if null */ | |||||
const char* title; | const char* title; | ||||
/** File browser dialog window width */ | |||||
uint width; | uint width; | ||||
/** File browser dialog window height */ | |||||
uint height; | uint height; | ||||
// TODO file filter | |||||
/** | |||||
File browser buttons. | |||||
0 means hidden. | |||||
1 means visible and unchecked. | |||||
2 means visible and checked. | |||||
/** | |||||
File browser buttons. | |||||
*/ | */ | ||||
struct Buttons { | struct Buttons { | ||||
uint listAllFiles; | |||||
uint showHidden; | |||||
uint showPlaces; | |||||
/** Whether to list all files vs only those with matching file extension */ | |||||
ButtonState listAllFiles; | |||||
/** Whether to show hidden files */ | |||||
ButtonState showHidden; | |||||
/** Whether to show list of places (bookmarks) */ | |||||
ButtonState showPlaces; | |||||
/** Constuctor for default values */ | /** Constuctor for default values */ | ||||
Buttons() | Buttons() | ||||
: listAllFiles(2), | |||||
showHidden(1), | |||||
showPlaces(1) {} | |||||
: listAllFiles(kButtonVisibleChecked), | |||||
showHidden(kButtonVisibleUnchecked), | |||||
showPlaces(kButtonVisibleUnchecked) {} | |||||
} buttons; | } buttons; | ||||
/** Constuctor for default values */ | /** Constuctor for default values */ | ||||
@@ -75,91 +104,320 @@ public: | |||||
}; | }; | ||||
#endif // DGL_FILE_BROWSER_DISABLED | #endif // DGL_FILE_BROWSER_DISABLED | ||||
/** | |||||
Constructor for a regular, standalone window. | |||||
*/ | |||||
explicit Window(Application& app); | explicit Window(Application& app); | ||||
/** | |||||
Constructor for a modal window, by having another window as its parent. | |||||
The Application instance must be the same between the 2 windows. | |||||
*/ | |||||
explicit Window(Application& app, Window& parent); | explicit Window(Application& app, Window& parent); | ||||
explicit Window(Application& app, intptr_t parentId, double scaling, bool resizable); | |||||
virtual ~Window(); | |||||
void show(); | |||||
void hide(); | |||||
void close(); | |||||
void exec(bool lockWait = false); | |||||
/** | |||||
Constructor for an embed Window without known size, | |||||
typically used in modules or plugins that run inside another host. | |||||
*/ | |||||
explicit Window(Application& app, | |||||
uintptr_t parentWindowHandle, | |||||
double scaleFactor, | |||||
bool resizable); | |||||
void focus(); | |||||
void repaint() noexcept; | |||||
/** | |||||
Constructor for an embed Window with known size, | |||||
typically used in modules or plugins that run inside another host. | |||||
*/ | |||||
explicit Window(Application& app, | |||||
uintptr_t parentWindowHandle, | |||||
uint width, | |||||
uint height, | |||||
double scaleFactor, | |||||
bool resizable); | |||||
#ifndef DGL_FILE_BROWSER_DISABLED | |||||
bool openFileBrowser(const FileBrowserOptions& options); | |||||
#endif | |||||
/** | |||||
Destructor. | |||||
*/ | |||||
virtual ~Window(); | |||||
/** | |||||
Whether this Window is embed into another (usually not DGL-controlled) Window. | |||||
*/ | |||||
bool isEmbed() const noexcept; | bool isEmbed() const noexcept; | ||||
/** | |||||
Check if this window is visible / mapped. | |||||
Invisible windows do not receive events except resize. | |||||
@see setVisible(bool) | |||||
*/ | |||||
bool isVisible() const noexcept; | bool isVisible() const noexcept; | ||||
void setVisible(bool yesNo); | |||||
/** | |||||
Set windows visible (or not) according to @a visible. | |||||
Only valid for standalones, embed windows are always visible. | |||||
@see isVisible(), hide(), show() | |||||
*/ | |||||
void setVisible(bool visible); | |||||
/** | |||||
Show window. | |||||
This is the same as calling setVisible(true). | |||||
@see isVisible(), setVisible(bool) | |||||
*/ | |||||
void show(); | |||||
/** | |||||
Hide window. | |||||
This is the same as calling setVisible(false). | |||||
@see isVisible(), setVisible(bool) | |||||
*/ | |||||
void hide(); | |||||
/** | |||||
Hide window and notify application of a window close event. | |||||
The application event-loop will stop when all windows have been closed. | |||||
For standalone windows only, has no effect if window is embed. | |||||
@see isEmbed() | |||||
@note It is possible to hide the window while not stopping the event-loop. | |||||
A closed window is always hidden, but the reverse is not always true. | |||||
*/ | |||||
void close(); | |||||
/** | |||||
Check if this window is resizable. | |||||
@see setResizable | |||||
*/ | |||||
bool isResizable() const noexcept; | bool isResizable() const noexcept; | ||||
void setResizable(bool yesNo); | |||||
/** | |||||
Set window as resizable (by the user or window manager). | |||||
It is always possible to resize a window programmatically, which is not the same as the user being allowed to it. | |||||
@note This function does nothing for plugins, where the resizable state is set via macro. | |||||
@see DISTRHO_UI_USER_RESIZABLE | |||||
*/ | |||||
void setResizable(bool resizable); | |||||
/** | |||||
Get width. | |||||
*/ | |||||
uint getWidth() const noexcept; | uint getWidth() const noexcept; | ||||
/** | |||||
Get height. | |||||
*/ | |||||
uint getHeight() const noexcept; | uint getHeight() const noexcept; | ||||
/** | |||||
Get size. | |||||
*/ | |||||
Size<uint> getSize() const noexcept; | Size<uint> getSize() const noexcept; | ||||
/** | |||||
Set width. | |||||
*/ | |||||
void setWidth(uint width); | |||||
/** | |||||
Set height. | |||||
*/ | |||||
void setHeight(uint height); | |||||
/** | |||||
Set size using @a width and @a height values. | |||||
*/ | |||||
void setSize(uint width, uint height); | void setSize(uint width, uint height); | ||||
void setSize(Size<uint> size); | |||||
/** | |||||
Set size. | |||||
*/ | |||||
void setSize(const Size<uint>& size); | |||||
/** | |||||
Get the title of the window previously set with setTitle(). | |||||
*/ | |||||
const char* getTitle() const noexcept; | const char* getTitle() const noexcept; | ||||
void setTitle(const char* title); | |||||
void setGeometryConstraints(uint width, uint height, bool aspect); | |||||
void setTransientWinId(uintptr_t winId); | |||||
/** | |||||
Set the title of the window, typically displayed in the title bar or in window switchers. | |||||
This only makes sense for non-embedded windows. | |||||
*/ | |||||
void setTitle(const char* title); | |||||
double getScaling() const noexcept; | |||||
/** | |||||
Check if key repeat events are ignored. | |||||
*/ | |||||
bool isIgnoringKeyRepeat() const noexcept; | |||||
bool getIgnoringKeyRepeat() const noexcept; | |||||
/** | |||||
Set to ignore (or not) key repeat events according to @a ignore. | |||||
*/ | |||||
void setIgnoringKeyRepeat(bool ignore) noexcept; | void setIgnoringKeyRepeat(bool ignore) noexcept; | ||||
/** | |||||
Add a callback function to be triggered on every idle cycle or on a specific timer frequency. | |||||
You can add more than one, and remove them at anytime with removeIdleCallback(). | |||||
This can be used to perform some action at a regular interval with relatively low frequency. | |||||
If providing a timer frequency, there are a few things to note: | |||||
1. There is a platform-specific limit to the number of supported timers, and overhead associated with each, | |||||
so you should create only a few timers and perform several tasks in one if necessary. | |||||
2. This timer frequency is not guaranteed to have a resolution better than 10ms | |||||
(the maximum timer resolution on Windows) and may be rounded up if it is too short. | |||||
On X11 and MacOS, a resolution of about 1ms can usually be relied on. | |||||
*/ | |||||
bool addIdleCallback(IdleCallback* callback, uint timerFrequencyInMs = 0); | |||||
/** | |||||
Remove an idle callback previously added via addIdleCallback(). | |||||
*/ | |||||
bool removeIdleCallback(IdleCallback* callback); | |||||
/** | |||||
Get the application associated with this window. | |||||
*/ | |||||
Application& getApp() const noexcept; | Application& getApp() const noexcept; | ||||
intptr_t getWindowId() const noexcept; | |||||
/** | |||||
Get the graphics context associated with this window. | |||||
GraphicsContext is an empty struct and needs to be casted into a different type in order to be usable, | |||||
for example GraphicsContext. | |||||
@see CairoSubWidget, CairoTopLevelWidget | |||||
*/ | |||||
const GraphicsContext& getGraphicsContext() const noexcept; | const GraphicsContext& getGraphicsContext() const noexcept; | ||||
void addIdleCallback(IdleCallback* const callback); | |||||
void removeIdleCallback(IdleCallback* const callback); | |||||
/** | |||||
Get the "native" window handle. | |||||
Returned value depends on the platform: | |||||
- HaikuOS: This is a pointer to a `BView`. | |||||
- MacOS: This is a pointer to an `NSView*`. | |||||
- Windows: This is a `HWND`. | |||||
- Everything else: This is an [X11] `Window`. | |||||
*/ | |||||
uintptr_t getNativeWindowHandle() const noexcept; | |||||
/** | |||||
Get the scale factor requested for this window. | |||||
This is purely informational, and up to developers to choose what to do with it. | |||||
If you do not want to deal with this yourself, | |||||
consider using setGeometryConstraints() where you can specify to automatically scale the window contents. | |||||
@see setGeometryConstraints | |||||
*/ | |||||
double getScaleFactor() const noexcept; | |||||
/** | |||||
Grab the keyboard input focus. | |||||
*/ | |||||
void focus(); | |||||
#ifndef DGL_FILE_BROWSER_DISABLED | |||||
/** | |||||
Open a file browser dialog with this window as parent. | |||||
A few options can be specified to setup the dialog. | |||||
If a path is selected, onFileSelected() will be called with the user chosen path. | |||||
If the user cancels or does not pick a file, onFileSelected() will be called with nullptr as filename. | |||||
This function does not block the event loop. | |||||
*/ | |||||
bool openFileBrowser(const FileBrowserOptions& options); | |||||
#endif | |||||
/** | |||||
Request repaint of this window, for the entire area. | |||||
*/ | |||||
void repaint() noexcept; | |||||
/** | |||||
Request partial repaint of this window, with bounds according to @a rect. | |||||
*/ | |||||
void repaint(const Rectangle<uint>& rect) noexcept; | |||||
/** | |||||
Run this window as a modal, blocking input events from the parent. | |||||
Only valid for windows that have been created with another window as parent (as passed in the constructor). | |||||
Can optionally block-wait, but such option is only available if the application is running as standalone. | |||||
*/ | |||||
void runAsModal(bool blockWait = false); | |||||
/** | |||||
Set geometry constraints for the Window when resized by the user, and optionally scale contents automatically. | |||||
*/ | |||||
void setGeometryConstraints(uint minimumWidth, | |||||
uint minimumHeight, | |||||
bool keepAspectRatio = false, | |||||
bool automaticallyScale = false); | |||||
/** DEPRECATED Use isIgnoringKeyRepeat(). */ | |||||
DISTRHO_DEPRECATED_BY("isIgnoringKeyRepeat()") | |||||
inline bool getIgnoringKeyRepeat() const noexcept { return isIgnoringKeyRepeat(); } | |||||
/** DEPRECATED Use getScaleFactor(). */ | |||||
DISTRHO_DEPRECATED_BY("getScaleFactor()") | |||||
inline double getScaling() const noexcept { return getScaleFactor(); } | |||||
/** DEPRECATED Use runAsModal(bool). */ | |||||
DISTRHO_DEPRECATED_BY("runAsModal(bool)") | |||||
inline void exec(bool blockWait = false) { runAsModal(blockWait); } | |||||
protected: | protected: | ||||
virtual void onDisplayBefore(); | |||||
virtual void onDisplayAfter(); | |||||
/** | |||||
A function called when the window is attempted to be closed. | |||||
Returning true closes the window, which is the default behaviour. | |||||
Override this method and return false to prevent the window from being closed by the user. | |||||
*/ | |||||
virtual bool onClose(); | |||||
/** | |||||
A function called when the window gains or loses the keyboard focus. | |||||
The default implementation does nothing. | |||||
*/ | |||||
virtual void onFocus(bool focus, CrossingMode mode); | |||||
/** | |||||
A function called when the window is resized. | |||||
If there is a top-level widget associated with this window, its size will be set right after this function. | |||||
The default implementation sets up drawing context where necessary. | |||||
*/ | |||||
virtual void onReshape(uint width, uint height); | virtual void onReshape(uint width, uint height); | ||||
virtual void onClose(); | |||||
#ifndef DGL_FILE_BROWSER_DISABLED | #ifndef DGL_FILE_BROWSER_DISABLED | ||||
virtual void fileBrowserSelected(const char* filename); | |||||
#endif | |||||
/** | |||||
A function called when a path is selected by the user, as triggered by openFileBrowser(). | |||||
This action happens after the user confirms the action, so the file browser dialog will be closed at this point. | |||||
The default implementation does nothing. | |||||
*/ | |||||
virtual void onFileSelected(const char* filename); | |||||
// internal | |||||
void _setAutoScaling(double scaling) noexcept; | |||||
/** DEPRECATED Use onFileSelected(). */ | |||||
DISTRHO_DEPRECATED_BY("onFileSelected(const char*)") | |||||
inline virtual void fileBrowserSelected(const char* filename) { return onFileSelected(filename); } | |||||
#endif | |||||
private: | private: | ||||
struct PrivateData; | struct PrivateData; | ||||
PrivateData* const pData; | PrivateData* const pData; | ||||
friend class Application; | friend class Application; | ||||
friend class Widget; | |||||
friend class StandaloneWindow; | |||||
#ifdef DISTRHO_DEFINES_H_INCLUDED | |||||
friend class DISTRHO_NAMESPACE::UIExporter; | |||||
#endif | |||||
virtual void _addWidget(Widget* const widget); | |||||
virtual void _removeWidget(Widget* const widget); | |||||
void _idle(); | |||||
bool handlePluginKeyboard(const bool press, const uint key); | |||||
bool handlePluginSpecial(const bool press, const Key key); | |||||
friend class TopLevelWidget; | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Window) | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Window); | |||||
}; | }; | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
END_NAMESPACE_DGL | END_NAMESPACE_DGL | ||||
/* TODO | |||||
* add eventcrossing/enter-leave event | |||||
*/ | |||||
#if 0 | |||||
protected: | |||||
bool handlePluginKeyboard(const bool press, const uint key); | |||||
bool handlePluginSpecial(const bool press, const Key key); | |||||
#endif | |||||
// ----------------------------------------------------------------------- | |||||
#endif // DGL_WINDOW_HPP_INCLUDED | #endif // DGL_WINDOW_HPP_INCLUDED |
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -15,14 +15,13 @@ | |||||
*/ | */ | ||||
#include "ApplicationPrivateData.hpp" | #include "ApplicationPrivateData.hpp" | ||||
#include "../Window.hpp" | |||||
START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
Application::Application() | |||||
: pData(new PrivateData()) {} | |||||
Application::Application(const bool isStandalone) | |||||
: pData(new PrivateData(isStandalone)) {} | |||||
Application::~Application() | Application::~Application() | ||||
{ | { | ||||
@@ -31,44 +30,48 @@ Application::~Application() | |||||
void Application::idle() | void Application::idle() | ||||
{ | { | ||||
for (std::list<Window*>::iterator it = pData->windows.begin(), ite = pData->windows.end(); it != ite; ++it) | |||||
{ | |||||
Window* const window(*it); | |||||
window->_idle(); | |||||
} | |||||
for (std::list<IdleCallback*>::iterator it = pData->idleCallbacks.begin(), ite = pData->idleCallbacks.end(); it != ite; ++it) | |||||
{ | |||||
IdleCallback* const idleCallback(*it); | |||||
idleCallback->idleCallback(); | |||||
} | |||||
pData->idle(0); | |||||
} | } | ||||
void Application::exec(int idleTime) | |||||
void Application::exec(const uint idleTimeInMs) | |||||
{ | { | ||||
for (; pData->doLoop;) | |||||
{ | |||||
idle(); | |||||
d_msleep(idleTime); | |||||
} | |||||
DISTRHO_SAFE_ASSERT_RETURN(pData->isStandalone,); | |||||
while (! pData->isQuitting) | |||||
pData->idle(idleTimeInMs); | |||||
} | } | ||||
void Application::quit() | void Application::quit() | ||||
{ | { | ||||
pData->doLoop = false; | |||||
DISTRHO_SAFE_ASSERT_RETURN(pData->isStandalone,); | |||||
for (std::list<Window*>::reverse_iterator rit = pData->windows.rbegin(), rite = pData->windows.rend(); rit != rite; ++rit) | |||||
{ | |||||
Window* const window(*rit); | |||||
window->close(); | |||||
} | |||||
pData->quit(); | |||||
} | } | ||||
bool Application::isQuiting() const noexcept | bool Application::isQuiting() const noexcept | ||||
{ | { | ||||
return !pData->doLoop; | |||||
return pData->isQuitting; | |||||
} | |||||
void Application::addIdleCallback(IdleCallback* const callback) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr,) | |||||
pData->idleCallbacks.push_back(callback); | |||||
} | |||||
void Application::removeIdleCallback(IdleCallback* const callback) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr,) | |||||
pData->idleCallbacks.remove(callback); | |||||
} | |||||
void Application::setClassName(const char* const name) | |||||
{ | |||||
pData->setClassName(name); | |||||
} | } | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
END_NAMESPACE_DGL | END_NAMESPACE_DGL |
@@ -0,0 +1,137 @@ | |||||
/* | |||||
* DISTRHO Plugin Framework (DPF) | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#include "ApplicationPrivateData.hpp" | |||||
#include "../Window.hpp" | |||||
#include "pugl.hpp" | |||||
#include <ctime> | |||||
START_NAMESPACE_DGL | |||||
typedef std::list<DGL_NAMESPACE::Window*>::reverse_iterator WindowListReverseIterator; | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
Application::PrivateData::PrivateData(const bool standalone) | |||||
: world(puglNewWorld(standalone ? PUGL_PROGRAM : PUGL_MODULE, | |||||
standalone ? PUGL_WORLD_THREADS : 0x0)), | |||||
isStandalone(standalone), | |||||
isQuitting(false), | |||||
isQuittingInNextCycle(false), | |||||
isStarting(true), | |||||
visibleWindows(0), | |||||
windows(), | |||||
idleCallbacks() | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(world != nullptr,); | |||||
puglSetWorldHandle(world, this); | |||||
puglSetClassName(world, DISTRHO_MACRO_AS_STRING(DGL_NAMESPACE)); | |||||
#ifdef HAVE_X11 | |||||
sofdFileDialogSetup(world); | |||||
#endif | |||||
} | |||||
Application::PrivateData::~PrivateData() | |||||
{ | |||||
DISTRHO_SAFE_ASSERT(isStarting || isQuitting); | |||||
DISTRHO_SAFE_ASSERT(visibleWindows == 0); | |||||
windows.clear(); | |||||
idleCallbacks.clear(); | |||||
if (world != nullptr) | |||||
puglFreeWorld(world); | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
void Application::PrivateData::oneWindowShown() noexcept | |||||
{ | |||||
if (++visibleWindows == 1) | |||||
{ | |||||
isQuitting = false; | |||||
isStarting = false; | |||||
} | |||||
} | |||||
void Application::PrivateData::oneWindowClosed() noexcept | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(visibleWindows != 0,); | |||||
if (--visibleWindows == 0) | |||||
isQuitting = true; | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
void Application::PrivateData::idle(const uint timeoutInMs) | |||||
{ | |||||
if (isQuittingInNextCycle) | |||||
{ | |||||
quit(); | |||||
isQuittingInNextCycle = false; | |||||
} | |||||
if (world != nullptr) | |||||
{ | |||||
const double timeoutInSeconds = timeoutInMs != 0 | |||||
? static_cast<double>(timeoutInMs) / 1000.0 | |||||
: 0.0; | |||||
puglUpdate(world, timeoutInSeconds); | |||||
} | |||||
for (std::list<IdleCallback*>::iterator it = idleCallbacks.begin(), ite = idleCallbacks.end(); it != ite; ++it) | |||||
{ | |||||
IdleCallback* const idleCallback(*it); | |||||
idleCallback->idleCallback(); | |||||
} | |||||
} | |||||
void Application::PrivateData::quit() | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(isStandalone,); | |||||
if (! isQuittingInNextCycle) | |||||
{ | |||||
isQuittingInNextCycle = true; | |||||
return; | |||||
} | |||||
isQuitting = true; | |||||
#ifndef DPF_TEST_APPLICATION_CPP | |||||
for (WindowListReverseIterator rit = windows.rbegin(), rite = windows.rend(); rit != rite; ++rit) | |||||
{ | |||||
DGL_NAMESPACE::Window* const window(*rit); | |||||
window->close(); | |||||
} | |||||
#endif | |||||
} | |||||
void Application::PrivateData::setClassName(const char* const name) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0',); | |||||
puglSetClassName(world, name); | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
END_NAMESPACE_DGL |
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -18,53 +18,71 @@ | |||||
#define DGL_APP_PRIVATE_DATA_HPP_INCLUDED | #define DGL_APP_PRIVATE_DATA_HPP_INCLUDED | ||||
#include "../Application.hpp" | #include "../Application.hpp" | ||||
#include "../../distrho/extra/Sleep.hpp" | |||||
#include <list> | #include <list> | ||||
typedef struct PuglWorldImpl PuglWorld; | |||||
START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
// ----------------------------------------------------------------------- | |||||
class Window; | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
struct Application::PrivateData { | struct Application::PrivateData { | ||||
bool doLoop; | |||||
/** Pugl world instance. */ | |||||
PuglWorld* const world; | |||||
/** Whether the application is running as standalone, otherwise it is part of a plugin. */ | |||||
const bool isStandalone; | |||||
/** Whether the applicating is about to quit, or already stopped. Defaults to false. */ | |||||
bool isQuitting; | |||||
/** Helper for safely close everything from main thread. */ | |||||
bool isQuittingInNextCycle; | |||||
/** Whether the applicating is starting up, that is, no windows have been made visible yet. Defaults to true. */ | |||||
bool isStarting; | |||||
/** Counter of visible windows, only used in standalone mode. | |||||
If 0->1, application is starting. If 1->0, application is quitting/stopping. */ | |||||
uint visibleWindows; | uint visibleWindows; | ||||
std::list<Window*> windows; | |||||
std::list<IdleCallback*> idleCallbacks; | |||||
PrivateData() | |||||
: doLoop(true), | |||||
visibleWindows(0), | |||||
windows(), | |||||
idleCallbacks() {} | |||||
~PrivateData() | |||||
{ | |||||
DISTRHO_SAFE_ASSERT(! doLoop); | |||||
DISTRHO_SAFE_ASSERT(visibleWindows == 0); | |||||
windows.clear(); | |||||
idleCallbacks.clear(); | |||||
} | |||||
void oneShown() noexcept | |||||
{ | |||||
if (++visibleWindows == 1) | |||||
doLoop = true; | |||||
} | |||||
void oneHidden() noexcept | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(visibleWindows > 0,); | |||||
if (--visibleWindows == 0) | |||||
doLoop = false; | |||||
} | |||||
DISTRHO_DECLARE_NON_COPY_STRUCT(PrivateData) | |||||
/** List of windows for this application. Only used during `close`. */ | |||||
std::list<DGL_NAMESPACE::Window*> windows; | |||||
/** List of idle callbacks for this application. */ | |||||
std::list<DGL_NAMESPACE::IdleCallback*> idleCallbacks; | |||||
/** Constructor and destructor */ | |||||
explicit PrivateData(bool standalone); | |||||
~PrivateData(); | |||||
/** Flag one window as shown, which increments @a visibleWindows. | |||||
Sets @a isQuitting and @a isStarting as false if this is the first window. | |||||
For standalone mode only. */ | |||||
void oneWindowShown() noexcept; | |||||
/** Flag one window as closed, which decrements @a visibleWindows. | |||||
Sets @a isQuitting as true if this is the last window. | |||||
For standalone mode only. */ | |||||
void oneWindowClosed() noexcept; | |||||
/** Run Pugl world update for @a timeoutInMs, and then each idle callback in order of registration. */ | |||||
void idle(uint timeoutInMs); | |||||
/** Set flag indicating application is quitting, and close all windows in reverse order of registration. | |||||
For standalone mode only. */ | |||||
void quit(); | |||||
/** Set pugl world class name. */ | |||||
void setClassName(const char* name); | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PrivateData) | |||||
}; | }; | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
END_NAMESPACE_DGL | END_NAMESPACE_DGL | ||||
@@ -1,6 +1,7 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2019-2021 Jean Pierre Cimalando <jp-dev@inbox.ru> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -14,77 +15,143 @@ | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
*/ | */ | ||||
#include "../Geometry.hpp" | |||||
#include "../Cairo.hpp" | #include "../Cairo.hpp" | ||||
#include "../Color.hpp" | |||||
#include "../ImageBaseWidgets.hpp" | |||||
#include "Common.hpp" | |||||
#include "SubWidgetPrivateData.hpp" | |||||
#include "TopLevelWidgetPrivateData.hpp" | |||||
#include "WidgetPrivateData.hpp" | |||||
#include "WindowPrivateData.hpp" | |||||
// templated classes | |||||
#include "ImageBaseWidgets.cpp" | |||||
START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
static void notImplemented(const char *name) | |||||
static void notImplemented(const char* const name) | |||||
{ | { | ||||
d_stderr2("cairo function not implemented: %s", name); | d_stderr2("cairo function not implemented: %s", name); | ||||
} | } | ||||
// ----------------------------------------------------------------------- | |||||
// Color | |||||
void Color::setFor(const GraphicsContext& context, const bool includeAlpha) | |||||
{ | |||||
cairo_t* const handle = ((const CairoGraphicsContext&)context).handle; | |||||
if (includeAlpha) | |||||
cairo_set_source_rgba(handle, red, green, blue, alpha); | |||||
else | |||||
cairo_set_source_rgb(handle, red, green, blue); | |||||
} | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// Line | // Line | ||||
template<typename T> | |||||
void Line<T>::draw(const GraphicsContext& context, const T width) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(posStart != posEnd,); | |||||
DISTRHO_SAFE_ASSERT_RETURN(width != 0,); | |||||
cairo_t* const handle = ((const CairoGraphicsContext&)context).handle; | |||||
cairo_set_line_width(handle, width); | |||||
cairo_move_to(handle, posStart.getX(), posStart.getY()); | |||||
cairo_line_to(handle, posEnd.getX(), posEnd.getY()); | |||||
cairo_stroke(handle); | |||||
} | |||||
template<typename T> | template<typename T> | ||||
void Line<T>::draw() | void Line<T>::draw() | ||||
{ | { | ||||
notImplemented("Line::draw"); | notImplemented("Line::draw"); | ||||
} | } | ||||
template class Line<double>; | |||||
template class Line<float>; | |||||
template class Line<int>; | |||||
template class Line<uint>; | |||||
template class Line<short>; | |||||
template class Line<ushort>; | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// Circle | // Circle | ||||
template<typename T> | template<typename T> | ||||
void Circle<T>::_draw(const bool outline) | |||||
static void drawCircle(cairo_t* const handle, | |||||
const Point<T>& pos, | |||||
const uint numSegments, | |||||
const float size, | |||||
const float sin, | |||||
const float cos, | |||||
const bool outline) | |||||
{ | { | ||||
notImplemented("Circle::draw"); | |||||
} | |||||
DISTRHO_SAFE_ASSERT_RETURN(numSegments >= 3 && size > 0.0f,); | |||||
// ----------------------------------------------------------------------- | |||||
// Triangle | |||||
const T origx = pos.getX(); | |||||
const T origy = pos.getY(); | |||||
double t, x = size, y = 0.0; | |||||
// TODO use arc | |||||
/* | |||||
cairo_arc(handle, origx, origy, size, sin, cos); | |||||
*/ | |||||
cairo_move_to(handle, x + origx, y + origy); | |||||
for (uint i=1; i<numSegments; ++i) | |||||
{ | |||||
cairo_line_to(handle, x + origx, y + origy); | |||||
t = x; | |||||
x = cos * x - sin * y; | |||||
y = sin * t + cos * y; | |||||
} | |||||
cairo_line_to(handle, x + origx, y + origy); | |||||
if (outline) | |||||
cairo_stroke(handle); | |||||
else | |||||
cairo_fill(handle); | |||||
} | |||||
template<typename T> | template<typename T> | ||||
void Triangle<T>::_draw(const bool outline) | |||||
void Circle<T>::draw(const GraphicsContext& context) | |||||
{ | { | ||||
notImplemented("Triangle::draw"); | |||||
} | |||||
cairo_t* const handle = ((const CairoGraphicsContext&)context).handle; | |||||
// ----------------------------------------------------------------------- | |||||
// Rectangle | |||||
drawCircle<T>(handle, fPos, fNumSegments, fSize, fSin, fCos, false); | |||||
} | |||||
template<typename T> | template<typename T> | ||||
void Rectangle<T>::_draw(const bool outline) | |||||
void Circle<T>::drawOutline(const GraphicsContext& context, const T lineWidth) | |||||
{ | { | ||||
notImplemented("Rectangle::draw"); | |||||
} | |||||
DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,); | |||||
// ----------------------------------------------------------------------- | |||||
// Possible template data types | |||||
cairo_t* const handle = ((const CairoGraphicsContext&)context).handle; | |||||
template class Point<double>; | |||||
template class Point<float>; | |||||
template class Point<int>; | |||||
template class Point<uint>; | |||||
template class Point<short>; | |||||
template class Point<ushort>; | |||||
cairo_set_line_width(handle, lineWidth); | |||||
drawCircle<T>(handle, fPos, fNumSegments, fSize, fSin, fCos, true); | |||||
} | |||||
template class Size<double>; | |||||
template class Size<float>; | |||||
template class Size<int>; | |||||
template class Size<uint>; | |||||
template class Size<short>; | |||||
template class Size<ushort>; | |||||
template<typename T> | |||||
void Circle<T>::draw() | |||||
{ | |||||
notImplemented("Circle::draw"); | |||||
} | |||||
template class Line<double>; | |||||
template class Line<float>; | |||||
template class Line<int>; | |||||
template class Line<uint>; | |||||
template class Line<short>; | |||||
template class Line<ushort>; | |||||
template<typename T> | |||||
void Circle<T>::drawOutline() | |||||
{ | |||||
notImplemented("Circle::drawOutline"); | |||||
} | |||||
template class Circle<double>; | template class Circle<double>; | ||||
template class Circle<float>; | template class Circle<float>; | ||||
@@ -93,6 +160,60 @@ template class Circle<uint>; | |||||
template class Circle<short>; | template class Circle<short>; | ||||
template class Circle<ushort>; | template class Circle<ushort>; | ||||
// ----------------------------------------------------------------------- | |||||
// Triangle | |||||
template<typename T> | |||||
static void drawTriangle(cairo_t* const handle, | |||||
const Point<T>& pos1, | |||||
const Point<T>& pos2, | |||||
const Point<T>& pos3, | |||||
const bool outline) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(pos1 != pos2 && pos1 != pos3,); | |||||
cairo_move_to(handle, pos1.getX(), pos1.getY()); | |||||
cairo_line_to(handle, pos2.getX(), pos2.getY()); | |||||
cairo_line_to(handle, pos3.getX(), pos3.getY()); | |||||
cairo_line_to(handle, pos1.getX(), pos1.getY()); | |||||
if (outline) | |||||
cairo_stroke(handle); | |||||
else | |||||
cairo_fill(handle); | |||||
} | |||||
template<typename T> | |||||
void Triangle<T>::draw(const GraphicsContext& context) | |||||
{ | |||||
cairo_t* const handle = ((const CairoGraphicsContext&)context).handle; | |||||
drawTriangle<T>(handle, pos1, pos2, pos3, false); | |||||
} | |||||
template<typename T> | |||||
void Triangle<T>::drawOutline(const GraphicsContext& context, const T lineWidth) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,); | |||||
cairo_t* const handle = ((const CairoGraphicsContext&)context).handle; | |||||
cairo_set_line_width(handle, lineWidth); | |||||
drawTriangle<T>(handle, pos1, pos2, pos3, true); | |||||
} | |||||
template<typename T> | |||||
void Triangle<T>::draw() | |||||
{ | |||||
notImplemented("Triangle::draw"); | |||||
} | |||||
template<typename T> | |||||
void Triangle<T>::drawOutline() | |||||
{ | |||||
notImplemented("Triangle::drawOutline"); | |||||
} | |||||
template class Triangle<double>; | template class Triangle<double>; | ||||
template class Triangle<float>; | template class Triangle<float>; | ||||
template class Triangle<int>; | template class Triangle<int>; | ||||
@@ -100,6 +221,54 @@ template class Triangle<uint>; | |||||
template class Triangle<short>; | template class Triangle<short>; | ||||
template class Triangle<ushort>; | template class Triangle<ushort>; | ||||
// ----------------------------------------------------------------------- | |||||
// Rectangle | |||||
template<typename T> | |||||
static void drawRectangle(cairo_t* const handle, const Rectangle<T>& rect, const bool outline) | |||||
{ | |||||
cairo_rectangle(handle, rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight()); | |||||
if (outline) | |||||
cairo_stroke(handle); | |||||
else | |||||
cairo_fill(handle); | |||||
} | |||||
template<typename T> | |||||
void Rectangle<T>::draw(const GraphicsContext& context) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(isValid(),); | |||||
cairo_t* const handle = ((const CairoGraphicsContext&)context).handle; | |||||
drawRectangle(handle, *this, false); | |||||
} | |||||
template<typename T> | |||||
void Rectangle<T>::drawOutline(const GraphicsContext& context, const T lineWidth) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(isValid(),); | |||||
DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,); | |||||
cairo_t* const handle = ((const CairoGraphicsContext&)context).handle; | |||||
cairo_set_line_width(handle, lineWidth); | |||||
drawRectangle(handle, *this, true); | |||||
} | |||||
template<typename T> | |||||
void Rectangle<T>::draw() | |||||
{ | |||||
notImplemented("Rectangle::draw"); | |||||
} | |||||
template<typename T> | |||||
void Rectangle<T>::drawOutline() | |||||
{ | |||||
notImplemented("Rectangle::drawOutline"); | |||||
} | |||||
template class Rectangle<double>; | template class Rectangle<double>; | ||||
template class Rectangle<float>; | template class Rectangle<float>; | ||||
template class Rectangle<int>; | template class Rectangle<int>; | ||||
@@ -107,6 +276,529 @@ template class Rectangle<uint>; | |||||
template class Rectangle<short>; | template class Rectangle<short>; | ||||
template class Rectangle<ushort>; | template class Rectangle<ushort>; | ||||
// ----------------------------------------------------------------------- | |||||
// CairoImage | |||||
static cairo_format_t asCairoImageFormat(const ImageFormat format) noexcept | |||||
{ | |||||
switch (format) | |||||
{ | |||||
case kImageFormatNull: | |||||
break; | |||||
case kImageFormatGrayscale: | |||||
return CAIRO_FORMAT_A8; | |||||
case kImageFormatBGR: | |||||
case kImageFormatRGB: | |||||
return CAIRO_FORMAT_RGB24; | |||||
case kImageFormatBGRA: | |||||
case kImageFormatRGBA: | |||||
return CAIRO_FORMAT_ARGB32; | |||||
} | |||||
return CAIRO_FORMAT_INVALID; | |||||
} | |||||
/* | |||||
static ImageFormat asCairoImageFormat(const cairo_format_t format) noexcept | |||||
{ | |||||
switch (format) | |||||
{ | |||||
case CAIRO_FORMAT_INVALID: | |||||
break; | |||||
case CAIRO_FORMAT_ARGB32: | |||||
break; | |||||
case CAIRO_FORMAT_RGB24: | |||||
break; | |||||
case CAIRO_FORMAT_A8: | |||||
break; | |||||
case CAIRO_FORMAT_A1: | |||||
break; | |||||
case CAIRO_FORMAT_RGB16_565: | |||||
break; | |||||
case CAIRO_FORMAT_RGB30: | |||||
break; | |||||
} | |||||
return kImageFormatNull; | |||||
} | |||||
*/ | |||||
CairoImage::CairoImage() | |||||
: ImageBase(), | |||||
surface(nullptr), | |||||
surfacedata(nullptr), | |||||
datarefcount(nullptr) {} | |||||
CairoImage::CairoImage(const char* const rdata, const uint w, const uint h, const ImageFormat fmt) | |||||
: ImageBase(rdata, w, h, fmt), | |||||
surface(nullptr), | |||||
surfacedata(nullptr), | |||||
datarefcount(nullptr) | |||||
{ | |||||
loadFromMemory(rdata, w, h, fmt); | |||||
} | |||||
CairoImage::CairoImage(const char* const rdata, const Size<uint>& s, const ImageFormat fmt) | |||||
: ImageBase(rdata, s, fmt), | |||||
surface(nullptr), | |||||
surfacedata(nullptr), | |||||
datarefcount(nullptr) | |||||
{ | |||||
loadFromMemory(rdata, s, fmt); | |||||
} | |||||
CairoImage::CairoImage(const CairoImage& image) | |||||
: ImageBase(image.rawData, image.size, image.format), | |||||
surface(cairo_surface_reference(image.surface)), | |||||
surfacedata(image.surfacedata), | |||||
datarefcount(image.datarefcount) | |||||
{ | |||||
if (datarefcount != nullptr) | |||||
++(*datarefcount); | |||||
} | |||||
CairoImage::~CairoImage() | |||||
{ | |||||
cairo_surface_destroy(surface); | |||||
if (datarefcount != nullptr && --(*datarefcount) == 0) | |||||
{ | |||||
std::free(surfacedata); | |||||
std::free(datarefcount); | |||||
} | |||||
} | |||||
void CairoImage::loadFromMemory(const char* const rdata, const Size<uint>& s, const ImageFormat fmt) noexcept | |||||
{ | |||||
const cairo_format_t cairoformat = asCairoImageFormat(fmt); | |||||
const int width = static_cast<int>(s.getWidth()); | |||||
const int height = static_cast<int>(s.getHeight()); | |||||
const int stride = cairo_format_stride_for_width(cairoformat, width); | |||||
uchar* const newdata = (uchar*)std::malloc(static_cast<size_t>(width * height * stride * 4)); | |||||
DISTRHO_SAFE_ASSERT_RETURN(newdata != nullptr,); | |||||
cairo_surface_t* const newsurface = cairo_image_surface_create_for_data(newdata, cairoformat, width, height, stride); | |||||
DISTRHO_SAFE_ASSERT_RETURN(newsurface != nullptr,); | |||||
DISTRHO_SAFE_ASSERT_RETURN(s.getWidth() == cairo_image_surface_get_width(newsurface),); | |||||
DISTRHO_SAFE_ASSERT_RETURN(s.getHeight() == cairo_image_surface_get_height(newsurface),); | |||||
cairo_surface_destroy(surface); | |||||
if (datarefcount != nullptr && --(*datarefcount) == 0) | |||||
std::free(surfacedata); | |||||
else | |||||
datarefcount = (int*)malloc(sizeof(*datarefcount)); | |||||
surface = newsurface; | |||||
surfacedata = newdata; | |||||
*datarefcount = 1; | |||||
switch (fmt) | |||||
{ | |||||
case kImageFormatNull: | |||||
break; | |||||
case kImageFormatGrayscale: | |||||
// Grayscale to A8 | |||||
// TODO | |||||
break; | |||||
case kImageFormatBGR: | |||||
// BGR8 to CAIRO_FORMAT_RGB24 | |||||
for (int h = 0; h < height; ++h) | |||||
{ | |||||
for (int w = 0; w < width; ++w) | |||||
{ | |||||
newdata[h*width*4+w*4+0] = static_cast<uchar>(rdata[h*width*3+w*3+0]); | |||||
newdata[h*width*4+w*4+1] = static_cast<uchar>(rdata[h*width*3+w*3+1]); | |||||
newdata[h*width*4+w*4+2] = static_cast<uchar>(rdata[h*width*3+w*3+2]); | |||||
newdata[h*width*4+w*4+3] = 0; | |||||
} | |||||
} | |||||
break; | |||||
case kImageFormatBGRA: | |||||
// BGRA8 to CAIRO_FORMAT_ARGB32 | |||||
// FIXME something is wrong here... | |||||
for (int h = 0, t; h < height; ++h) | |||||
{ | |||||
for (int w = 0; w < width; ++w) | |||||
{ | |||||
if ((t = rdata[h*width*4+w*4+3]) != 0) | |||||
{ | |||||
newdata[h*width*4+w*4+0] = static_cast<uchar>(rdata[h*width*4+w*4+0]); | |||||
newdata[h*width*4+w*4+1] = static_cast<uchar>(rdata[h*width*4+w*4+1]); | |||||
newdata[h*width*4+w*4+2] = static_cast<uchar>(rdata[h*width*4+w*4+2]); | |||||
newdata[h*width*4+w*4+3] = static_cast<uchar>(t); | |||||
} | |||||
else | |||||
{ | |||||
// make all pixels zero, cairo does not render full transparency otherwise | |||||
memset(&newdata[h*width*4+w*4], 0, 4); | |||||
} | |||||
} | |||||
} | |||||
break; | |||||
case kImageFormatRGB: | |||||
// RGB8 to CAIRO_FORMAT_RGB24 | |||||
// TODO | |||||
break; | |||||
case kImageFormatRGBA: | |||||
// RGBA8 to CAIRO_FORMAT_ARGB32 | |||||
// TODO | |||||
break; | |||||
} | |||||
ImageBase::loadFromMemory(rdata, s, fmt); | |||||
} | |||||
// const GraphicsContext& context | |||||
void CairoImage::loadFromPNG(const char* const pngData, const uint pngSize) noexcept | |||||
{ | |||||
struct PngReaderData | |||||
{ | |||||
const char* dataPtr; | |||||
uint sizeLeft; | |||||
static cairo_status_t read(void* const closure, uchar* const data, const uint length) noexcept | |||||
{ | |||||
PngReaderData& readerData = *reinterpret_cast<PngReaderData*>(closure); | |||||
if (readerData.sizeLeft < length) | |||||
return CAIRO_STATUS_READ_ERROR; | |||||
std::memcpy(data, readerData.dataPtr, length); | |||||
readerData.dataPtr += length; | |||||
readerData.sizeLeft -= length; | |||||
return CAIRO_STATUS_SUCCESS; | |||||
} | |||||
}; | |||||
PngReaderData readerData; | |||||
readerData.dataPtr = pngData; | |||||
readerData.sizeLeft = pngSize; | |||||
cairo_surface_t* const newsurface = cairo_image_surface_create_from_png_stream(PngReaderData::read, &readerData); | |||||
DISTRHO_SAFE_ASSERT_RETURN(newsurface != nullptr,); | |||||
const int newwidth = cairo_image_surface_get_width(newsurface); | |||||
const int newheight = cairo_image_surface_get_height(newsurface); | |||||
DISTRHO_SAFE_ASSERT_INT_RETURN(newwidth > 0, newwidth,); | |||||
DISTRHO_SAFE_ASSERT_INT_RETURN(newheight > 0, newheight,); | |||||
cairo_surface_destroy(surface); | |||||
if (datarefcount != nullptr && --(*datarefcount) == 0) | |||||
std::free(surfacedata); | |||||
else | |||||
datarefcount = (int*)malloc(sizeof(*datarefcount)); | |||||
surface = newsurface; | |||||
surfacedata = nullptr; // cairo_image_surface_get_data(newsurface); | |||||
*datarefcount = 1; | |||||
rawData = nullptr; | |||||
format = kImageFormatNull; // asCairoImageFormat(cairo_image_surface_get_format(newsurface)); | |||||
size = Size<uint>(static_cast<uint>(newwidth), static_cast<uint>(newheight)); | |||||
} | |||||
void CairoImage::drawAt(const GraphicsContext& context, const Point<int>& pos) | |||||
{ | |||||
if (surface == nullptr) | |||||
return; | |||||
cairo_t* const handle = ((const CairoGraphicsContext&)context).handle; | |||||
cairo_set_source_surface(handle, surface, pos.getX(), pos.getY()); | |||||
cairo_paint(handle); | |||||
} | |||||
CairoImage& CairoImage::operator=(const CairoImage& image) noexcept | |||||
{ | |||||
cairo_surface_t* newsurface = cairo_surface_reference(image.surface); | |||||
cairo_surface_destroy(surface); | |||||
if (datarefcount != nullptr && --(*datarefcount) == 0) | |||||
{ | |||||
std::free(surfacedata); | |||||
std::free(datarefcount); | |||||
} | |||||
surface = newsurface; | |||||
rawData = image.rawData; | |||||
size = image.size; | |||||
format = image.format; | |||||
surfacedata = image.surfacedata; | |||||
datarefcount = image.datarefcount; | |||||
if (datarefcount != nullptr) | |||||
++(*datarefcount); | |||||
return *this; | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// CairoSubWidget | |||||
template <> | |||||
CairoBaseWidget<SubWidget>::CairoBaseWidget(Widget* const parent) | |||||
: SubWidget(parent) {} | |||||
template class CairoBaseWidget<SubWidget>; | |||||
// ----------------------------------------------------------------------- | |||||
// CairoTopLevelWidget | |||||
template <> | |||||
CairoBaseWidget<TopLevelWidget>::CairoBaseWidget(Window& windowToMapTo) | |||||
: TopLevelWidget(windowToMapTo) {} | |||||
template class CairoBaseWidget<TopLevelWidget>; | |||||
// ----------------------------------------------------------------------- | |||||
// CairoStandaloneWindow | |||||
template <> | |||||
CairoBaseWidget<StandaloneWindow>::CairoBaseWidget(Application& app) | |||||
: StandaloneWindow(app) {} | |||||
template <> | |||||
CairoBaseWidget<StandaloneWindow>::CairoBaseWidget(Application& app, Window& parentWindow) | |||||
: StandaloneWindow(app, parentWindow) {} | |||||
template class CairoBaseWidget<StandaloneWindow>; | |||||
// ----------------------------------------------------------------------- | |||||
// ImageBaseAboutWindow | |||||
#if 0 | |||||
template <> | |||||
void ImageBaseAboutWindow<CairoImage>::onDisplay() | |||||
{ | |||||
img.draw(getGraphicsContext()); | |||||
} | |||||
#endif | |||||
template class ImageBaseAboutWindow<CairoImage>; | |||||
// ----------------------------------------------------------------------- | |||||
// ImageBaseButton | |||||
template class ImageBaseButton<CairoImage>; | |||||
// ----------------------------------------------------------------------- | |||||
// ImageBaseKnob | |||||
template <> | |||||
void ImageBaseKnob<CairoImage>::PrivateData::init() | |||||
{ | |||||
alwaysRepaint = true; | |||||
cairoSurface = nullptr; | |||||
} | |||||
template <> | |||||
void ImageBaseKnob<CairoImage>::PrivateData::cleanup() | |||||
{ | |||||
cairo_surface_destroy((cairo_surface_t*)cairoSurface); | |||||
cairoSurface = nullptr; | |||||
} | |||||
/** | |||||
Get the pixel size in bytes. | |||||
@return pixel size, or 0 if the format is unknown, or pixels are not aligned to bytes. | |||||
*/ | |||||
static int getBytesPerPixel(const cairo_format_t format) noexcept | |||||
{ | |||||
switch (format) | |||||
{ | |||||
case CAIRO_FORMAT_ARGB32: | |||||
case CAIRO_FORMAT_RGB24: | |||||
case CAIRO_FORMAT_RGB30: | |||||
return 4; | |||||
case CAIRO_FORMAT_RGB16_565: | |||||
return 2; | |||||
case CAIRO_FORMAT_A8: | |||||
return 1; | |||||
case CAIRO_FORMAT_A1: | |||||
return 0; | |||||
default: | |||||
DISTRHO_SAFE_ASSERT(false); | |||||
return 0; | |||||
} | |||||
} | |||||
static cairo_surface_t* getRegion(cairo_surface_t* origsurface, int x, int y, int width, int height) noexcept | |||||
{ | |||||
const cairo_format_t format = cairo_image_surface_get_format(origsurface); | |||||
const int bpp = getBytesPerPixel(format); | |||||
if (bpp == 0) | |||||
return nullptr; | |||||
const int fullWidth = cairo_image_surface_get_width(origsurface); | |||||
const int fullHeight = cairo_image_surface_get_height(origsurface); | |||||
const int stride = cairo_image_surface_get_stride(origsurface); | |||||
uchar* const fullData = cairo_image_surface_get_data(origsurface); | |||||
x = (x < fullWidth) ? x : fullWidth; | |||||
y = (y < fullHeight) ? y : fullHeight; | |||||
width = (x + width < fullWidth) ? width : (fullWidth - x); | |||||
height = (x + height < fullHeight) ? height : (fullHeight - x); | |||||
uchar* const data = fullData + (x * bpp + y * stride); | |||||
return cairo_image_surface_create_for_data(data, format, width, height, stride); | |||||
} | |||||
template <> | |||||
void ImageBaseKnob<CairoImage>::onDisplay() | |||||
{ | |||||
const GraphicsContext& context(getGraphicsContext()); | |||||
cairo_t* const handle = ((const CairoGraphicsContext&)context).handle; | |||||
const double normValue = ((pData->usingLog ? pData->invlogscale(pData->value) : pData->value) - pData->minimum) | |||||
/ (pData->maximum - pData->minimum); | |||||
cairo_surface_t* surface = (cairo_surface_t*)pData->cairoSurface; | |||||
if (! pData->isReady) | |||||
{ | |||||
const int layerW = static_cast<int>(pData->imgLayerWidth); | |||||
const int layerH = static_cast<int>(pData->imgLayerHeight); | |||||
int layerNum = 0; | |||||
if (pData->rotationAngle == 0) | |||||
layerNum = static_cast<int>(normValue * static_cast<double>(pData->imgLayerCount - 1) + 0.5); | |||||
const int layerX = pData->isImgVertical ? 0 : layerNum * layerW; | |||||
const int layerY = !pData->isImgVertical ? 0 : layerNum * layerH; | |||||
cairo_surface_t* newsurface; | |||||
if (pData->rotationAngle == 0) | |||||
{ | |||||
newsurface = getRegion(pData->image.getSurface(), layerX, layerY, layerW, layerH); | |||||
} | |||||
else | |||||
{ | |||||
newsurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, layerW, layerH); | |||||
cairo_t* const cr = cairo_create(newsurface); | |||||
cairo_translate(cr, 0.5 * layerW, 0.5 * layerH); | |||||
cairo_rotate(cr, normValue * pData->rotationAngle * (M_PI / 180)); | |||||
cairo_set_source_surface(cr, pData->image.getSurface(), -0.5 * layerW, -0.5 * layerH); | |||||
cairo_paint(cr); | |||||
cairo_destroy(cr); | |||||
} | |||||
DISTRHO_SAFE_ASSERT_RETURN(newsurface != nullptr,); | |||||
cairo_surface_destroy(surface); | |||||
pData->cairoSurface = surface = newsurface; | |||||
pData->isReady = true; | |||||
} | |||||
if (surface != nullptr) | |||||
{ | |||||
cairo_set_source_surface(handle, surface, 0, 0); | |||||
cairo_paint(handle); | |||||
} | |||||
} | |||||
template class ImageBaseKnob<CairoImage>; | |||||
// ----------------------------------------------------------------------- | |||||
// ImageBaseSlider | |||||
template class ImageBaseSlider<CairoImage>; | |||||
// ----------------------------------------------------------------------- | |||||
// ImageBaseSwitch | |||||
template class ImageBaseSwitch<CairoImage>; | |||||
// ----------------------------------------------------------------------- | |||||
void SubWidget::PrivateData::display(const uint width, const uint height, const double autoScaleFactor) | |||||
{ | |||||
cairo_t* const handle = static_cast<const CairoGraphicsContext&>(self->getGraphicsContext()).handle; | |||||
bool needsResetClip = false; | |||||
cairo_matrix_t matrix; | |||||
cairo_get_matrix(handle, &matrix); | |||||
if (needsFullViewportForDrawing || (absolutePos.isZero() && self->getSize() == Size<uint>(width, height))) | |||||
{ | |||||
// full viewport size | |||||
cairo_translate(handle, 0, 0); | |||||
} | |||||
else if (needsViewportScaling) | |||||
{ | |||||
// limit viewport to widget bounds | |||||
// NOTE only used for nanovg for now, which is not relevant here | |||||
cairo_translate(handle, 0, 0); | |||||
} | |||||
else | |||||
{ | |||||
// set viewport pos | |||||
cairo_translate(handle, absolutePos.getX(), absolutePos.getY()); | |||||
// then cut the outer bounds | |||||
cairo_rectangle(handle, | |||||
0, | |||||
0, | |||||
std::round(self->getWidth() * autoScaleFactor), | |||||
std::round(self->getHeight() * autoScaleFactor)); | |||||
cairo_clip(handle); | |||||
needsResetClip = true; | |||||
} | |||||
// display widget | |||||
self->onDisplay(); | |||||
if (needsResetClip) | |||||
cairo_reset_clip(handle); | |||||
cairo_set_matrix(handle, &matrix); | |||||
selfw->pData->displaySubWidgets(width, height, autoScaleFactor); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
void TopLevelWidget::PrivateData::display() | |||||
{ | |||||
if (! selfw->pData->visible) | |||||
return; | |||||
const Size<uint> size(window.getSize()); | |||||
const uint width = size.getWidth(); | |||||
const uint height = size.getHeight(); | |||||
const double autoScaleFactor = window.pData->autoScaleFactor; | |||||
// FIXME anything needed here? | |||||
#if 0 | |||||
// full viewport size | |||||
if (window.pData->autoScaling) | |||||
glViewport(0, -(height * autoScaleFactor - height), width * autoScaleFactor, height * autoScaleFactor); | |||||
else | |||||
glViewport(0, 0, width, height); | |||||
#endif | |||||
// main widget drawing | |||||
self->onDisplay(); | |||||
// now draw subwidgets if there are any | |||||
selfw->pData->displaySubWidgets(width, height, autoScaleFactor); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept | |||||
{ | |||||
GraphicsContext& context((GraphicsContext&)graphicsContext); | |||||
((CairoGraphicsContext&)context).handle = (cairo_t*)puglGetContext(view); | |||||
return context; | |||||
} | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
END_NAMESPACE_DGL | END_NAMESPACE_DGL |
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -16,10 +16,6 @@ | |||||
#include "../Color.hpp" | #include "../Color.hpp" | ||||
#ifndef HAVE_DCAIRO | |||||
#include "nanovg/nanovg.h" | |||||
#endif | |||||
START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -61,27 +57,27 @@ static uchar getFixedRange2(const float& value) | |||||
return 0; | return 0; | ||||
if (value2 >= 255.0f) | if (value2 >= 255.0f) | ||||
return 255; | return 255; | ||||
return static_cast<uchar>(value2); | |||||
return static_cast<uchar>(value2 + 0.5f); | |||||
} | } | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
Color::Color() noexcept | Color::Color() noexcept | ||||
: red(1.0f), | |||||
green(1.0f), | |||||
blue(1.0f), | |||||
: red(0.0f), | |||||
green(0.0f), | |||||
blue(0.0f), | |||||
alpha(1.0f) {} | alpha(1.0f) {} | ||||
Color::Color(int r, int g, int b, int a) noexcept | |||||
Color::Color(const int r, const int g, const int b, const float a) noexcept | |||||
: red(static_cast<float>(r)/255.0f), | : red(static_cast<float>(r)/255.0f), | ||||
green(static_cast<float>(g)/255.0f), | green(static_cast<float>(g)/255.0f), | ||||
blue(static_cast<float>(b)/255.0f), | blue(static_cast<float>(b)/255.0f), | ||||
alpha(static_cast<float>(a)/255.0f) | |||||
alpha(a) | |||||
{ | { | ||||
fixBounds(); | fixBounds(); | ||||
} | } | ||||
Color::Color(float r, float g, float b, float a) noexcept | |||||
Color::Color(const float r, const float g, const float b, const float a) noexcept | |||||
: red(r), | : red(r), | ||||
green(g), | green(g), | ||||
blue(b), | blue(b), | ||||
@@ -109,7 +105,7 @@ Color& Color::operator=(const Color& color) noexcept | |||||
return *this; | return *this; | ||||
} | } | ||||
Color::Color(const Color& color1, const Color& color2, float u) noexcept | |||||
Color::Color(const Color& color1, const Color& color2, const float u) noexcept | |||||
: red(color1.red), | : red(color1.red), | ||||
green(color1.green), | green(color1.green), | ||||
blue(color1.blue), | blue(color1.blue), | ||||
@@ -136,65 +132,66 @@ Color Color::fromHSL(float hue, float saturation, float lightness, float alpha) | |||||
return col; | return col; | ||||
} | } | ||||
Color Color::fromHTML(const char* rgb, float alpha) | |||||
Color Color::fromHTML(const char* rgb, const float alpha) noexcept | |||||
{ | { | ||||
Color fallback; | Color fallback; | ||||
DISTRHO_SAFE_ASSERT_RETURN(rgb != nullptr && rgb[0] != '\0', fallback); | DISTRHO_SAFE_ASSERT_RETURN(rgb != nullptr && rgb[0] != '\0', fallback); | ||||
if (rgb[0] == '#') ++rgb; | |||||
if (rgb[0] == '#') | |||||
++rgb; | |||||
DISTRHO_SAFE_ASSERT_RETURN(rgb[0] != '\0', fallback); | DISTRHO_SAFE_ASSERT_RETURN(rgb[0] != '\0', fallback); | ||||
std::size_t rgblen(std::strlen(rgb)); | |||||
std::size_t rgblen = std::strlen(rgb); | |||||
DISTRHO_SAFE_ASSERT_RETURN(rgblen == 3 || rgblen == 6, fallback); | DISTRHO_SAFE_ASSERT_RETURN(rgblen == 3 || rgblen == 6, fallback); | ||||
char rgbtmp[3] = { '\0', '\0', '\0' }; | |||||
char rgbtmp[5] = { '0', 'x', '\0', '\0', '\0' }; | |||||
int r, g, b; | int r, g, b; | ||||
if (rgblen == 3) | if (rgblen == 3) | ||||
{ | { | ||||
rgbtmp[0] = rgb[0]; | |||||
r = static_cast<int>(std::strtol(rgbtmp, nullptr, 16)); | |||||
rgbtmp[2] = rgb[0]; | |||||
r = static_cast<int>(std::strtol(rgbtmp, nullptr, 16)) * 17; | |||||
rgbtmp[0] = rgb[1]; | |||||
g = static_cast<int>(std::strtol(rgbtmp, nullptr, 16)); | |||||
rgbtmp[2] = rgb[1]; | |||||
g = static_cast<int>(std::strtol(rgbtmp, nullptr, 16)) * 17; | |||||
rgbtmp[0] = rgb[2]; | |||||
b = static_cast<int>(std::strtol(rgbtmp, nullptr, 16)); | |||||
rgbtmp[2] = rgb[2]; | |||||
b = static_cast<int>(std::strtol(rgbtmp, nullptr, 16)) * 17; | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
rgbtmp[0] = rgb[0]; | |||||
rgbtmp[1] = rgb[1]; | |||||
rgbtmp[2] = rgb[0]; | |||||
rgbtmp[3] = rgb[1]; | |||||
r = static_cast<int>(std::strtol(rgbtmp, nullptr, 16)); | r = static_cast<int>(std::strtol(rgbtmp, nullptr, 16)); | ||||
rgbtmp[0] = rgb[2]; | |||||
rgbtmp[1] = rgb[3]; | |||||
rgbtmp[2] = rgb[2]; | |||||
rgbtmp[3] = rgb[3]; | |||||
g = static_cast<int>(std::strtol(rgbtmp, nullptr, 16)); | g = static_cast<int>(std::strtol(rgbtmp, nullptr, 16)); | ||||
rgbtmp[0] = rgb[4]; | |||||
rgbtmp[1] = rgb[5]; | |||||
rgbtmp[2] = rgb[4]; | |||||
rgbtmp[3] = rgb[5]; | |||||
b = static_cast<int>(std::strtol(rgbtmp, nullptr, 16)); | b = static_cast<int>(std::strtol(rgbtmp, nullptr, 16)); | ||||
} | } | ||||
return Color(r, g, b, static_cast<int>(getFixedRange(alpha)*255.0f)); | |||||
return Color(r, g, b, alpha); | |||||
} | } | ||||
void Color::interpolate(const Color& other, float u) noexcept | void Color::interpolate(const Color& other, float u) noexcept | ||||
{ | { | ||||
fixRange(u); | fixRange(u); | ||||
const float oneMinusU(1.0f - u); | |||||
const float oneMinusU = 1.0f - u; | |||||
red = red * oneMinusU + other.red * u; | |||||
green = green * oneMinusU + other.green * u; | |||||
blue = blue * oneMinusU + other.blue * u; | |||||
alpha = alpha * oneMinusU + other.alpha * u; | |||||
red = (red * oneMinusU) + (other.red * u); | |||||
green = (green * oneMinusU) + (other.green * u); | |||||
blue = (blue * oneMinusU) + (other.blue * u); | |||||
alpha = (alpha * oneMinusU) + (other.alpha * u); | |||||
fixBounds(); | fixBounds(); | ||||
} | } | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
bool Color::isEqual(const Color& color, bool withAlpha) noexcept | |||||
bool Color::isEqual(const Color& color, const bool withAlpha) noexcept | |||||
{ | { | ||||
const uchar r1 = getFixedRange2(rgba[0]); | const uchar r1 = getFixedRange2(rgba[0]); | ||||
const uchar g1 = getFixedRange2(rgba[1]); | const uchar g1 = getFixedRange2(rgba[1]); | ||||
@@ -212,7 +209,7 @@ bool Color::isEqual(const Color& color, bool withAlpha) noexcept | |||||
return (r1 == r2 && g1 == g2 && b1 == b2); | return (r1 == r2 && g1 == g2 && b1 == b2); | ||||
} | } | ||||
bool Color::isNotEqual(const Color& color, bool withAlpha) noexcept | |||||
bool Color::isNotEqual(const Color& color, const bool withAlpha) noexcept | |||||
{ | { | ||||
const uchar r1 = getFixedRange2(rgba[0]); | const uchar r1 = getFixedRange2(rgba[0]); | ||||
const uchar g1 = getFixedRange2(rgba[1]); | const uchar g1 = getFixedRange2(rgba[1]); | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -17,12 +17,13 @@ | |||||
#ifndef DGL_COMMON_HPP_INCLUDED | #ifndef DGL_COMMON_HPP_INCLUDED | ||||
#define DGL_COMMON_HPP_INCLUDED | #define DGL_COMMON_HPP_INCLUDED | ||||
#include "../ImageWidgets.hpp" | |||||
#include "../ImageBaseWidgets.hpp" | |||||
START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
template <class ImageType> | |||||
struct ButtonImpl { | struct ButtonImpl { | ||||
enum State { | enum State { | ||||
kStateNormal = 0, | kStateNormal = 0, | ||||
@@ -32,11 +33,11 @@ struct ButtonImpl { | |||||
int button; | int button; | ||||
int state; | int state; | ||||
Widget* self; | |||||
ImageBaseButton<ImageType>* const self; | |||||
ImageButton::Callback* callback_img; | |||||
typename ImageBaseButton<ImageType>::Callback* callback_img; | |||||
ButtonImpl(Widget* const s) noexcept | |||||
explicit ButtonImpl(ImageBaseButton<ImageType>* const s) noexcept | |||||
: button(-1), | : button(-1), | ||||
state(kStateNormal), | state(kStateNormal), | ||||
self(s), | self(s), | ||||
@@ -66,7 +67,7 @@ struct ButtonImpl { | |||||
self->repaint(); | self->repaint(); | ||||
if (callback_img != nullptr) | if (callback_img != nullptr) | ||||
callback_img->imageButtonClicked((ImageButton*)self, button2); | |||||
callback_img->imageButtonClicked(self, button2); | |||||
return true; | return true; | ||||
} | } | ||||
@@ -74,7 +75,7 @@ struct ButtonImpl { | |||||
// button was pressed, wait for release | // button was pressed, wait for release | ||||
if (ev.press && self->contains(ev.pos)) | if (ev.press && self->contains(ev.pos)) | ||||
{ | { | ||||
button = ev.button; | |||||
button = static_cast<int>(ev.button); | |||||
state = kStateDown; | state = kStateDown; | ||||
self->repaint(); | self->repaint(); | ||||
return true; | return true; | ||||
@@ -114,7 +115,70 @@ struct ButtonImpl { | |||||
} | } | ||||
DISTRHO_PREVENT_HEAP_ALLOCATION | DISTRHO_PREVENT_HEAP_ALLOCATION | ||||
DISTRHO_DECLARE_NON_COPY_STRUCT(ButtonImpl) | |||||
DISTRHO_DECLARE_NON_COPYABLE(ButtonImpl) | |||||
}; | |||||
// ----------------------------------------------------------------------- | |||||
template <class ImageType> | |||||
struct ImageBaseKnob<ImageType>::PrivateData { | |||||
ImageType image; | |||||
float minimum; | |||||
float maximum; | |||||
float step; | |||||
float value; | |||||
float valueDef; | |||||
float valueTmp; | |||||
bool usingDefault; | |||||
bool usingLog; | |||||
Orientation orientation; | |||||
int rotationAngle; | |||||
bool dragging; | |||||
double lastX; | |||||
double lastY; | |||||
Callback* callback; | |||||
bool alwaysRepaint; | |||||
bool isImgVertical; | |||||
uint imgLayerWidth; | |||||
uint imgLayerHeight; | |||||
uint imgLayerCount; | |||||
bool isReady; | |||||
union { | |||||
uint glTextureId; | |||||
void* cairoSurface; | |||||
}; | |||||
explicit PrivateData(const ImageType& img, const Orientation o); | |||||
explicit PrivateData(PrivateData* const other); | |||||
void assignFrom(PrivateData* const other); | |||||
~PrivateData() | |||||
{ | |||||
cleanup(); | |||||
} | |||||
void init(); | |||||
void cleanup(); | |||||
inline float logscale(const float v) const | |||||
{ | |||||
const float b = std::log(maximum/minimum)/(maximum-minimum); | |||||
const float a = maximum/std::exp(maximum*b); | |||||
return a * std::exp(b*v); | |||||
} | |||||
inline float invlogscale(const float v) const | |||||
{ | |||||
const float b = std::log(maximum/minimum)/(maximum-minimum); | |||||
const float a = maximum/std::exp(maximum*b); | |||||
return std::log(v/a)/b; | |||||
} | |||||
DISTRHO_DECLARE_NON_COPYABLE(PrivateData) | |||||
}; | }; | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -27,129 +27,129 @@ static const float M_2PIf = 3.14159265358979323846f*2.0f; | |||||
template<typename T> | template<typename T> | ||||
Point<T>::Point() noexcept | Point<T>::Point() noexcept | ||||
: fX(0), | |||||
fY(0) {} | |||||
: x(0), | |||||
y(0) {} | |||||
template<typename T> | template<typename T> | ||||
Point<T>::Point(const T& x, const T& y) noexcept | |||||
: fX(x), | |||||
fY(y) {} | |||||
Point<T>::Point(const T& x2, const T& y2) noexcept | |||||
: x(x2), | |||||
y(y2) {} | |||||
template<typename T> | template<typename T> | ||||
Point<T>::Point(const Point<T>& pos) noexcept | Point<T>::Point(const Point<T>& pos) noexcept | ||||
: fX(pos.fX), | |||||
fY(pos.fY) {} | |||||
: x(pos.x), | |||||
y(pos.y) {} | |||||
template<typename T> | template<typename T> | ||||
const T& Point<T>::getX() const noexcept | const T& Point<T>::getX() const noexcept | ||||
{ | { | ||||
return fX; | |||||
return x; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
const T& Point<T>::getY() const noexcept | const T& Point<T>::getY() const noexcept | ||||
{ | { | ||||
return fY; | |||||
return y; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
void Point<T>::setX(const T& x) noexcept | |||||
void Point<T>::setX(const T& x2) noexcept | |||||
{ | { | ||||
fX = x; | |||||
x = x2; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
void Point<T>::setY(const T& y) noexcept | |||||
void Point<T>::setY(const T& y2) noexcept | |||||
{ | { | ||||
fY = y; | |||||
y = y2; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
void Point<T>::setPos(const T& x, const T& y) noexcept | |||||
void Point<T>::setPos(const T& x2, const T& y2) noexcept | |||||
{ | { | ||||
fX = x; | |||||
fY = y; | |||||
x = x2; | |||||
y = y2; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
void Point<T>::setPos(const Point<T>& pos) noexcept | void Point<T>::setPos(const Point<T>& pos) noexcept | ||||
{ | { | ||||
fX = pos.fX; | |||||
fY = pos.fY; | |||||
x = pos.x; | |||||
y = pos.y; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
void Point<T>::moveBy(const T& x, const T& y) noexcept | |||||
void Point<T>::moveBy(const T& x2, const T& y2) noexcept | |||||
{ | { | ||||
fX = static_cast<T>(fX+x); | |||||
fY = static_cast<T>(fY+y); | |||||
x = static_cast<T>(x+x2); | |||||
y = static_cast<T>(y+y2); | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
void Point<T>::moveBy(const Point<T>& pos) noexcept | void Point<T>::moveBy(const Point<T>& pos) noexcept | ||||
{ | { | ||||
fX = static_cast<T>(fX+pos.fX); | |||||
fY = static_cast<T>(fY+pos.fY); | |||||
x = static_cast<T>(x+pos.x); | |||||
y = static_cast<T>(y+pos.y); | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
bool Point<T>::isZero() const noexcept | bool Point<T>::isZero() const noexcept | ||||
{ | { | ||||
return fX == 0 && fY == 0; | |||||
return x == 0 && y == 0; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
bool Point<T>::isNotZero() const noexcept | bool Point<T>::isNotZero() const noexcept | ||||
{ | { | ||||
return fX != 0 || fY != 0; | |||||
return x != 0 || y != 0; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
Point<T> Point<T>::operator+(const Point<T>& pos) noexcept | Point<T> Point<T>::operator+(const Point<T>& pos) noexcept | ||||
{ | { | ||||
return Point<T>(fX+pos.fX, fY+pos.fY); | |||||
return Point<T>(x+pos.x, y+pos.y); | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
Point<T> Point<T>::operator-(const Point<T>& pos) noexcept | Point<T> Point<T>::operator-(const Point<T>& pos) noexcept | ||||
{ | { | ||||
return Point<T>(fX-pos.fX, fY-pos.fY); | |||||
return Point<T>(x-pos.x, y-pos.y); | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
Point<T>& Point<T>::operator=(const Point<T>& pos) noexcept | Point<T>& Point<T>::operator=(const Point<T>& pos) noexcept | ||||
{ | { | ||||
fX = pos.fX; | |||||
fY = pos.fY; | |||||
x = pos.x; | |||||
y = pos.y; | |||||
return *this; | return *this; | ||||
} | } | ||||
template<typename T> | template<typename T> | ||||
Point<T>& Point<T>::operator+=(const Point<T>& pos) noexcept | Point<T>& Point<T>::operator+=(const Point<T>& pos) noexcept | ||||
{ | { | ||||
fX = static_cast<T>(fX+pos.fX); | |||||
fY = static_cast<T>(fY+pos.fY); | |||||
x = static_cast<T>(x+pos.x); | |||||
y = static_cast<T>(y+pos.y); | |||||
return *this; | return *this; | ||||
} | } | ||||
template<typename T> | template<typename T> | ||||
Point<T>& Point<T>::operator-=(const Point<T>& pos) noexcept | Point<T>& Point<T>::operator-=(const Point<T>& pos) noexcept | ||||
{ | { | ||||
fX = static_cast<T>(fX-pos.fX); | |||||
fY = static_cast<T>(fY-pos.fY); | |||||
x = static_cast<T>(x-pos.x); | |||||
y = static_cast<T>(y-pos.y); | |||||
return *this; | return *this; | ||||
} | } | ||||
template<typename T> | template<typename T> | ||||
bool Point<T>::operator==(const Point<T>& pos) const noexcept | bool Point<T>::operator==(const Point<T>& pos) const noexcept | ||||
{ | { | ||||
return (fX == pos.fX && fY == pos.fY); | |||||
return (x == pos.x && y == pos.y); | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
bool Point<T>::operator!=(const Point<T>& pos) const noexcept | bool Point<T>::operator!=(const Point<T>& pos) const noexcept | ||||
{ | { | ||||
return (fX != pos.fX || fY != pos.fY); | |||||
return (x != pos.x || y != pos.y); | |||||
} | } | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -246,6 +246,27 @@ bool Size<T>::isInvalid() const noexcept | |||||
return fWidth <= 0 || fHeight <= 0; | return fWidth <= 0 || fHeight <= 0; | ||||
} | } | ||||
template<typename T> | |||||
Size<int> Size<T>::toInt() const noexcept | |||||
{ | |||||
return Size<int>(static_cast<int>(fWidth), | |||||
static_cast<int>(fHeight)); | |||||
} | |||||
template<> | |||||
Size<int> Size<double>::toInt() const noexcept | |||||
{ | |||||
return Size<int>(static_cast<int>(fWidth + 0.5), | |||||
static_cast<int>(fHeight + 0.5)); | |||||
} | |||||
template<> | |||||
Size<int> Size<float>::toInt() const noexcept | |||||
{ | |||||
return Size<int>(static_cast<int>(fWidth + 0.5f), | |||||
static_cast<int>(fHeight + 0.5f)); | |||||
} | |||||
template<typename T> | template<typename T> | ||||
Size<T> Size<T>::operator+(const Size<T>& size) noexcept | Size<T> Size<T>::operator+(const Size<T>& size) noexcept | ||||
{ | { | ||||
@@ -315,162 +336,162 @@ bool Size<T>::operator!=(const Size<T>& size) const noexcept | |||||
template<typename T> | template<typename T> | ||||
Line<T>::Line() noexcept | Line<T>::Line() noexcept | ||||
: fPosStart(0, 0), | |||||
fPosEnd(0, 0) {} | |||||
: posStart(0, 0), | |||||
posEnd(0, 0) {} | |||||
template<typename T> | template<typename T> | ||||
Line<T>::Line(const T& startX, const T& startY, const T& endX, const T& endY) noexcept | Line<T>::Line(const T& startX, const T& startY, const T& endX, const T& endY) noexcept | ||||
: fPosStart(startX, startY), | |||||
fPosEnd(endX, endY) {} | |||||
: posStart(startX, startY), | |||||
posEnd(endX, endY) {} | |||||
template<typename T> | template<typename T> | ||||
Line<T>::Line(const T& startX, const T& startY, const Point<T>& endPos) noexcept | Line<T>::Line(const T& startX, const T& startY, const Point<T>& endPos) noexcept | ||||
: fPosStart(startX, startY), | |||||
fPosEnd(endPos) {} | |||||
: posStart(startX, startY), | |||||
posEnd(endPos) {} | |||||
template<typename T> | template<typename T> | ||||
Line<T>::Line(const Point<T>& startPos, const T& endX, const T& endY) noexcept | Line<T>::Line(const Point<T>& startPos, const T& endX, const T& endY) noexcept | ||||
: fPosStart(startPos), | |||||
fPosEnd(endX, endY) {} | |||||
: posStart(startPos), | |||||
posEnd(endX, endY) {} | |||||
template<typename T> | template<typename T> | ||||
Line<T>::Line(const Point<T>& startPos, const Point<T>& endPos) noexcept | Line<T>::Line(const Point<T>& startPos, const Point<T>& endPos) noexcept | ||||
: fPosStart(startPos), | |||||
fPosEnd(endPos) {} | |||||
: posStart(startPos), | |||||
posEnd(endPos) {} | |||||
template<typename T> | template<typename T> | ||||
Line<T>::Line(const Line<T>& line) noexcept | Line<T>::Line(const Line<T>& line) noexcept | ||||
: fPosStart(line.fPosStart), | |||||
fPosEnd(line.fPosEnd) {} | |||||
: posStart(line.posStart), | |||||
posEnd(line.posEnd) {} | |||||
template<typename T> | template<typename T> | ||||
const T& Line<T>::getStartX() const noexcept | const T& Line<T>::getStartX() const noexcept | ||||
{ | { | ||||
return fPosStart.fX; | |||||
return posStart.x; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
const T& Line<T>::getStartY() const noexcept | const T& Line<T>::getStartY() const noexcept | ||||
{ | { | ||||
return fPosStart.fY; | |||||
return posStart.y; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
const T& Line<T>::getEndX() const noexcept | const T& Line<T>::getEndX() const noexcept | ||||
{ | { | ||||
return fPosEnd.fX; | |||||
return posEnd.x; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
const T& Line<T>::getEndY() const noexcept | const T& Line<T>::getEndY() const noexcept | ||||
{ | { | ||||
return fPosEnd.fY; | |||||
return posEnd.y; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
const Point<T>& Line<T>::getStartPos() const noexcept | const Point<T>& Line<T>::getStartPos() const noexcept | ||||
{ | { | ||||
return fPosStart; | |||||
return posStart; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
const Point<T>& Line<T>::getEndPos() const noexcept | const Point<T>& Line<T>::getEndPos() const noexcept | ||||
{ | { | ||||
return fPosEnd; | |||||
return posEnd; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
void Line<T>::setStartX(const T& x) noexcept | void Line<T>::setStartX(const T& x) noexcept | ||||
{ | { | ||||
fPosStart.fX = x; | |||||
posStart.x = x; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
void Line<T>::setStartY(const T& y) noexcept | void Line<T>::setStartY(const T& y) noexcept | ||||
{ | { | ||||
fPosStart.fY = y; | |||||
posStart.y = y; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
void Line<T>::setStartPos(const T& x, const T& y) noexcept | void Line<T>::setStartPos(const T& x, const T& y) noexcept | ||||
{ | { | ||||
fPosStart = Point<T>(x, y); | |||||
posStart = Point<T>(x, y); | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
void Line<T>::setStartPos(const Point<T>& pos) noexcept | void Line<T>::setStartPos(const Point<T>& pos) noexcept | ||||
{ | { | ||||
fPosStart = pos; | |||||
posStart = pos; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
void Line<T>::setEndX(const T& x) noexcept | void Line<T>::setEndX(const T& x) noexcept | ||||
{ | { | ||||
fPosEnd.fX = x; | |||||
posEnd.x = x; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
void Line<T>::setEndY(const T& y) noexcept | void Line<T>::setEndY(const T& y) noexcept | ||||
{ | { | ||||
fPosEnd.fY = y; | |||||
posEnd.y = y; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
void Line<T>::setEndPos(const T& x, const T& y) noexcept | void Line<T>::setEndPos(const T& x, const T& y) noexcept | ||||
{ | { | ||||
fPosEnd = Point<T>(x, y); | |||||
posEnd = Point<T>(x, y); | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
void Line<T>::setEndPos(const Point<T>& pos) noexcept | void Line<T>::setEndPos(const Point<T>& pos) noexcept | ||||
{ | { | ||||
fPosEnd = pos; | |||||
posEnd = pos; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
void Line<T>::moveBy(const T& x, const T& y) noexcept | void Line<T>::moveBy(const T& x, const T& y) noexcept | ||||
{ | { | ||||
fPosStart.moveBy(x, y); | |||||
fPosEnd.moveBy(x, y); | |||||
posStart.moveBy(x, y); | |||||
posEnd.moveBy(x, y); | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
void Line<T>::moveBy(const Point<T>& pos) noexcept | void Line<T>::moveBy(const Point<T>& pos) noexcept | ||||
{ | { | ||||
fPosStart.moveBy(pos); | |||||
fPosEnd.moveBy(pos); | |||||
posStart.moveBy(pos); | |||||
posEnd.moveBy(pos); | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
bool Line<T>::isNull() const noexcept | bool Line<T>::isNull() const noexcept | ||||
{ | { | ||||
return fPosStart == fPosEnd; | |||||
return posStart == posEnd; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
bool Line<T>::isNotNull() const noexcept | bool Line<T>::isNotNull() const noexcept | ||||
{ | { | ||||
return fPosStart != fPosEnd; | |||||
return posStart != posEnd; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
Line<T>& Line<T>::operator=(const Line<T>& line) noexcept | Line<T>& Line<T>::operator=(const Line<T>& line) noexcept | ||||
{ | { | ||||
fPosStart = line.fPosStart; | |||||
fPosEnd = line.fPosEnd; | |||||
posStart = line.posStart; | |||||
posEnd = line.posEnd; | |||||
return *this; | return *this; | ||||
} | } | ||||
template<typename T> | template<typename T> | ||||
bool Line<T>::operator==(const Line<T>& line) const noexcept | bool Line<T>::operator==(const Line<T>& line) const noexcept | ||||
{ | { | ||||
return (fPosStart == line.fPosStart && fPosEnd == line.fPosEnd); | |||||
return (posStart == line.posStart && posEnd == line.posEnd); | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
bool Line<T>::operator!=(const Line<T>& line) const noexcept | bool Line<T>::operator!=(const Line<T>& line) const noexcept | ||||
{ | { | ||||
return (fPosStart != line.fPosStart || fPosEnd != line.fPosEnd); | |||||
return (posStart != line.posStart || posEnd != line.posEnd); | |||||
} | } | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -524,13 +545,13 @@ Circle<T>::Circle(const Circle<T>& cir) noexcept | |||||
template<typename T> | template<typename T> | ||||
const T& Circle<T>::getX() const noexcept | const T& Circle<T>::getX() const noexcept | ||||
{ | { | ||||
return fPos.fX; | |||||
return fPos.x; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
const T& Circle<T>::getY() const noexcept | const T& Circle<T>::getY() const noexcept | ||||
{ | { | ||||
return fPos.fY; | |||||
return fPos.y; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
@@ -542,20 +563,20 @@ const Point<T>& Circle<T>::getPos() const noexcept | |||||
template<typename T> | template<typename T> | ||||
void Circle<T>::setX(const T& x) noexcept | void Circle<T>::setX(const T& x) noexcept | ||||
{ | { | ||||
fPos.fX = x; | |||||
fPos.x = x; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
void Circle<T>::setY(const T& y) noexcept | void Circle<T>::setY(const T& y) noexcept | ||||
{ | { | ||||
fPos.fY = y; | |||||
fPos.y = y; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
void Circle<T>::setPos(const T& x, const T& y) noexcept | void Circle<T>::setPos(const T& x, const T& y) noexcept | ||||
{ | { | ||||
fPos.fX = x; | |||||
fPos.fY = y; | |||||
fPos.x = x; | |||||
fPos.y = y; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
@@ -599,18 +620,6 @@ void Circle<T>::setNumSegments(const uint num) | |||||
fSin = std::sin(fTheta); | fSin = std::sin(fTheta); | ||||
} | } | ||||
template<typename T> | |||||
void Circle<T>::draw() | |||||
{ | |||||
_draw(false); | |||||
} | |||||
template<typename T> | |||||
void Circle<T>::drawOutline() | |||||
{ | |||||
_draw(true); | |||||
} | |||||
template<typename T> | template<typename T> | ||||
Circle<T>& Circle<T>::operator=(const Circle<T>& cir) noexcept | Circle<T>& Circle<T>::operator=(const Circle<T>& cir) noexcept | ||||
{ | { | ||||
@@ -640,83 +649,71 @@ bool Circle<T>::operator!=(const Circle<T>& cir) const noexcept | |||||
template<typename T> | template<typename T> | ||||
Triangle<T>::Triangle() noexcept | Triangle<T>::Triangle() noexcept | ||||
: fPos1(0, 0), | |||||
fPos2(0, 0), | |||||
fPos3(0, 0) {} | |||||
: pos1(0, 0), | |||||
pos2(0, 0), | |||||
pos3(0, 0) {} | |||||
template<typename T> | template<typename T> | ||||
Triangle<T>::Triangle(const T& x1, const T& y1, const T& x2, const T& y2, const T& x3, const T& y3) noexcept | Triangle<T>::Triangle(const T& x1, const T& y1, const T& x2, const T& y2, const T& x3, const T& y3) noexcept | ||||
: fPos1(x1, y1), | |||||
fPos2(x2, y2), | |||||
fPos3(x3, y3) {} | |||||
: pos1(x1, y1), | |||||
pos2(x2, y2), | |||||
pos3(x3, y3) {} | |||||
template<typename T> | template<typename T> | ||||
Triangle<T>::Triangle(const Point<T>& pos1, const Point<T>& pos2, const Point<T>& pos3) noexcept | |||||
: fPos1(pos1), | |||||
fPos2(pos2), | |||||
fPos3(pos3) {} | |||||
Triangle<T>::Triangle(const Point<T>& p1, const Point<T>& p2, const Point<T>& p3) noexcept | |||||
: pos1(p1), | |||||
pos2(p2), | |||||
pos3(p3) {} | |||||
template<typename T> | template<typename T> | ||||
Triangle<T>::Triangle(const Triangle<T>& tri) noexcept | Triangle<T>::Triangle(const Triangle<T>& tri) noexcept | ||||
: fPos1(tri.fPos1), | |||||
fPos2(tri.fPos2), | |||||
fPos3(tri.fPos3) {} | |||||
: pos1(tri.pos1), | |||||
pos2(tri.pos2), | |||||
pos3(tri.pos3) {} | |||||
template<typename T> | template<typename T> | ||||
bool Triangle<T>::isNull() const noexcept | bool Triangle<T>::isNull() const noexcept | ||||
{ | { | ||||
return fPos1 == fPos2 && fPos1 == fPos3; | |||||
return pos1 == pos2 && pos1 == pos3; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
bool Triangle<T>::isNotNull() const noexcept | bool Triangle<T>::isNotNull() const noexcept | ||||
{ | { | ||||
return fPos1 != fPos2 || fPos1 != fPos3; | |||||
return pos1 != pos2 || pos1 != pos3; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
bool Triangle<T>::isValid() const noexcept | bool Triangle<T>::isValid() const noexcept | ||||
{ | { | ||||
return fPos1 != fPos2 && fPos1 != fPos3; | |||||
return pos1 != pos2 && pos1 != pos3; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
bool Triangle<T>::isInvalid() const noexcept | bool Triangle<T>::isInvalid() const noexcept | ||||
{ | { | ||||
return fPos1 == fPos2 || fPos1 == fPos3; | |||||
} | |||||
template<typename T> | |||||
void Triangle<T>::draw() | |||||
{ | |||||
_draw(false); | |||||
} | |||||
template<typename T> | |||||
void Triangle<T>::drawOutline() | |||||
{ | |||||
_draw(true); | |||||
return pos1 == pos2 || pos1 == pos3; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
Triangle<T>& Triangle<T>::operator=(const Triangle<T>& tri) noexcept | Triangle<T>& Triangle<T>::operator=(const Triangle<T>& tri) noexcept | ||||
{ | { | ||||
fPos1 = tri.fPos1; | |||||
fPos2 = tri.fPos2; | |||||
fPos3 = tri.fPos3; | |||||
pos1 = tri.pos1; | |||||
pos2 = tri.pos2; | |||||
pos3 = tri.pos3; | |||||
return *this; | return *this; | ||||
} | } | ||||
template<typename T> | template<typename T> | ||||
bool Triangle<T>::operator==(const Triangle<T>& tri) const noexcept | bool Triangle<T>::operator==(const Triangle<T>& tri) const noexcept | ||||
{ | { | ||||
return (fPos1 == tri.fPos1 && fPos2 == tri.fPos2 && fPos3 == tri.fPos3); | |||||
return (pos1 == tri.pos1 && pos2 == tri.pos2 && pos3 == tri.pos3); | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
bool Triangle<T>::operator!=(const Triangle<T>& tri) const noexcept | bool Triangle<T>::operator!=(const Triangle<T>& tri) const noexcept | ||||
{ | { | ||||
return (fPos1 != tri.fPos1 || fPos2 != tri.fPos2 || fPos3 != tri.fPos3); | |||||
return (pos1 != tri.pos1 || pos2 != tri.pos2 || pos3 != tri.pos3); | |||||
} | } | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -724,226 +721,257 @@ bool Triangle<T>::operator!=(const Triangle<T>& tri) const noexcept | |||||
template<typename T> | template<typename T> | ||||
Rectangle<T>::Rectangle() noexcept | Rectangle<T>::Rectangle() noexcept | ||||
: fPos(0, 0), | |||||
fSize(0, 0) {} | |||||
: pos(0, 0), | |||||
size(0, 0) {} | |||||
template<typename T> | template<typename T> | ||||
Rectangle<T>::Rectangle(const T& x, const T& y, const T& width, const T& height) noexcept | |||||
: fPos(x, y), | |||||
fSize(width, height) {} | |||||
Rectangle<T>::Rectangle(const T& x, const T& y, const T& w, const T& h) noexcept | |||||
: pos(x, y), | |||||
size(w, h) {} | |||||
template<typename T> | template<typename T> | ||||
Rectangle<T>::Rectangle(const T& x, const T& y, const Size<T>& size) noexcept | |||||
: fPos(x, y), | |||||
fSize(size) {} | |||||
Rectangle<T>::Rectangle(const T& x, const T& y, const Size<T>& s) noexcept | |||||
: pos(x, y), | |||||
size(s) {} | |||||
template<typename T> | template<typename T> | ||||
Rectangle<T>::Rectangle(const Point<T>& pos, const T& width, const T& height) noexcept | |||||
: fPos(pos), | |||||
fSize(width, height) {} | |||||
Rectangle<T>::Rectangle(const Point<T>& p, const T& w, const T& h) noexcept | |||||
: pos(p), | |||||
size(w, h) {} | |||||
template<typename T> | template<typename T> | ||||
Rectangle<T>::Rectangle(const Point<T>& pos, const Size<T>& size) noexcept | |||||
: fPos(pos), | |||||
fSize(size) {} | |||||
Rectangle<T>::Rectangle(const Point<T>& p, const Size<T>& s) noexcept | |||||
: pos(p), | |||||
size(s) {} | |||||
template<typename T> | template<typename T> | ||||
Rectangle<T>::Rectangle(const Rectangle<T>& rect) noexcept | Rectangle<T>::Rectangle(const Rectangle<T>& rect) noexcept | ||||
: fPos(rect.fPos), | |||||
fSize(rect.fSize) {} | |||||
: pos(rect.pos), | |||||
size(rect.size) {} | |||||
template<typename T> | template<typename T> | ||||
const T& Rectangle<T>::getX() const noexcept | const T& Rectangle<T>::getX() const noexcept | ||||
{ | { | ||||
return fPos.fX; | |||||
return pos.x; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
const T& Rectangle<T>::getY() const noexcept | const T& Rectangle<T>::getY() const noexcept | ||||
{ | { | ||||
return fPos.fY; | |||||
return pos.y; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
const T& Rectangle<T>::getWidth() const noexcept | const T& Rectangle<T>::getWidth() const noexcept | ||||
{ | { | ||||
return fSize.fWidth; | |||||
return size.fWidth; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
const T& Rectangle<T>::getHeight() const noexcept | const T& Rectangle<T>::getHeight() const noexcept | ||||
{ | { | ||||
return fSize.fHeight; | |||||
return size.fHeight; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
const Point<T>& Rectangle<T>::getPos() const noexcept | const Point<T>& Rectangle<T>::getPos() const noexcept | ||||
{ | { | ||||
return fPos; | |||||
return pos; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
const Size<T>& Rectangle<T>::getSize() const noexcept | const Size<T>& Rectangle<T>::getSize() const noexcept | ||||
{ | { | ||||
return fSize; | |||||
return size; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
void Rectangle<T>::setX(const T& x) noexcept | void Rectangle<T>::setX(const T& x) noexcept | ||||
{ | { | ||||
fPos.fX = x; | |||||
pos.x = x; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
void Rectangle<T>::setY(const T& y) noexcept | void Rectangle<T>::setY(const T& y) noexcept | ||||
{ | { | ||||
fPos.fY = y; | |||||
pos.y = y; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
void Rectangle<T>::setPos(const T& x, const T& y) noexcept | void Rectangle<T>::setPos(const T& x, const T& y) noexcept | ||||
{ | { | ||||
fPos.fX = x; | |||||
fPos.fY = y; | |||||
pos.x = x; | |||||
pos.y = y; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
void Rectangle<T>::setPos(const Point<T>& pos) noexcept | |||||
void Rectangle<T>::setPos(const Point<T>& pos2) noexcept | |||||
{ | { | ||||
fPos = pos; | |||||
pos = pos2; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
void Rectangle<T>::moveBy(const T& x, const T& y) noexcept | void Rectangle<T>::moveBy(const T& x, const T& y) noexcept | ||||
{ | { | ||||
fPos.moveBy(x, y); | |||||
pos.moveBy(x, y); | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
void Rectangle<T>::moveBy(const Point<T>& pos) noexcept | |||||
void Rectangle<T>::moveBy(const Point<T>& pos2) noexcept | |||||
{ | { | ||||
fPos.moveBy(pos); | |||||
pos.moveBy(pos2); | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
void Rectangle<T>::setWidth(const T& width) noexcept | void Rectangle<T>::setWidth(const T& width) noexcept | ||||
{ | { | ||||
fSize.fWidth = width; | |||||
size.fWidth = width; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
void Rectangle<T>::setHeight(const T& height) noexcept | void Rectangle<T>::setHeight(const T& height) noexcept | ||||
{ | { | ||||
fSize.fHeight = height; | |||||
size.fHeight = height; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
void Rectangle<T>::setSize(const T& width, const T& height) noexcept | void Rectangle<T>::setSize(const T& width, const T& height) noexcept | ||||
{ | { | ||||
fSize.fWidth = width; | |||||
fSize.fHeight = height; | |||||
size.fWidth = width; | |||||
size.fHeight = height; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
void Rectangle<T>::setSize(const Size<T>& size) noexcept | |||||
void Rectangle<T>::setSize(const Size<T>& size2) noexcept | |||||
{ | { | ||||
fSize = size; | |||||
size = size2; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
void Rectangle<T>::growBy(double multiplier) noexcept | void Rectangle<T>::growBy(double multiplier) noexcept | ||||
{ | { | ||||
fSize.growBy(multiplier); | |||||
size.growBy(multiplier); | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
void Rectangle<T>::shrinkBy(double divider) noexcept | void Rectangle<T>::shrinkBy(double divider) noexcept | ||||
{ | { | ||||
fSize.shrinkBy(divider); | |||||
size.shrinkBy(divider); | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
void Rectangle<T>::setRectangle(const Point<T>& pos, const Size<T>& size) noexcept | |||||
void Rectangle<T>::setRectangle(const Point<T>& pos2, const Size<T>& size2) noexcept | |||||
{ | { | ||||
fPos = pos; | |||||
fSize = size; | |||||
pos = pos2; | |||||
size = size2; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
void Rectangle<T>::setRectangle(const Rectangle<T>& rect) noexcept | void Rectangle<T>::setRectangle(const Rectangle<T>& rect) noexcept | ||||
{ | { | ||||
fPos = rect.fPos; | |||||
fSize = rect.fSize; | |||||
pos = rect.pos; | |||||
size = rect.size; | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
bool Rectangle<T>::contains(const T& x, const T& y) const noexcept | bool Rectangle<T>::contains(const T& x, const T& y) const noexcept | ||||
{ | { | ||||
return (x >= fPos.fX && y >= fPos.fY && x <= fPos.fX+fSize.fWidth && y <= fPos.fY+fSize.fHeight); | |||||
return (x >= pos.x && y >= pos.y && x <= pos.x+size.fWidth && y <= pos.y+size.fHeight); | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
bool Rectangle<T>::contains(const Point<T>& pos) const noexcept | |||||
bool Rectangle<T>::contains(const Point<T>& p) const noexcept | |||||
{ | { | ||||
return contains(pos.fX, pos.fY); | |||||
return contains(p.x, p.y); | |||||
} | |||||
template<typename T> | |||||
template<typename T2> | |||||
bool Rectangle<T>::contains(const Point<T2>& p) const noexcept | |||||
{ | |||||
return (p.x >= pos.x && p.y >= pos.y && p.x <= pos.x+size.fWidth && p.y <= pos.y+size.fHeight); | |||||
} | |||||
template<> template<> | |||||
bool Rectangle<int>::contains(const Point<double>& p) const noexcept | |||||
{ | |||||
return (p.x >= pos.x && p.y >= pos.y && p.x <= pos.x+size.fWidth && p.y <= pos.y+size.fHeight); | |||||
} | |||||
template<> template<> | |||||
bool Rectangle<uint>::contains(const Point<double>& p) const noexcept | |||||
{ | |||||
return (p.x >= pos.x && p.y >= pos.y && p.x <= pos.x+size.fWidth && p.y <= pos.y+size.fHeight); | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
bool Rectangle<T>::containsX(const T& x) const noexcept | bool Rectangle<T>::containsX(const T& x) const noexcept | ||||
{ | { | ||||
return (x >= fPos.fX && x <= fPos.fX + fSize.fWidth); | |||||
return (x >= pos.x && x <= pos.x + size.fWidth); | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
bool Rectangle<T>::containsY(const T& y) const noexcept | bool Rectangle<T>::containsY(const T& y) const noexcept | ||||
{ | { | ||||
return (y >= fPos.fY && y <= fPos.fY + fSize.fHeight); | |||||
return (y >= pos.y && y <= pos.y + size.fHeight); | |||||
} | |||||
template<typename T> | |||||
bool Rectangle<T>::isNull() const noexcept | |||||
{ | |||||
return size.isNull(); | |||||
} | |||||
template<typename T> | |||||
bool Rectangle<T>::isNotNull() const noexcept | |||||
{ | |||||
return size.isNotNull(); | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
void Rectangle<T>::draw() | |||||
bool Rectangle<T>::isValid() const noexcept | |||||
{ | { | ||||
_draw(false); | |||||
return size.isValid(); | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
void Rectangle<T>::drawOutline() | |||||
bool Rectangle<T>::isInvalid() const noexcept | |||||
{ | { | ||||
_draw(true); | |||||
return size.isInvalid(); | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
Rectangle<T>& Rectangle<T>::operator=(const Rectangle<T>& rect) noexcept | Rectangle<T>& Rectangle<T>::operator=(const Rectangle<T>& rect) noexcept | ||||
{ | { | ||||
fPos = rect.fPos; | |||||
fSize = rect.fSize; | |||||
pos = rect.pos; | |||||
size = rect.size; | |||||
return *this; | return *this; | ||||
} | } | ||||
template<typename T> | template<typename T> | ||||
Rectangle<T>& Rectangle<T>::operator*=(double m) noexcept | Rectangle<T>& Rectangle<T>::operator*=(double m) noexcept | ||||
{ | { | ||||
fSize *= m; | |||||
size *= m; | |||||
return *this; | return *this; | ||||
} | } | ||||
template<typename T> | template<typename T> | ||||
Rectangle<T>& Rectangle<T>::operator/=(double d) noexcept | Rectangle<T>& Rectangle<T>::operator/=(double d) noexcept | ||||
{ | { | ||||
fSize /= d; | |||||
size /= d; | |||||
return *this; | return *this; | ||||
} | } | ||||
template<typename T> | template<typename T> | ||||
bool Rectangle<T>::operator==(const Rectangle<T>& rect) const noexcept | bool Rectangle<T>::operator==(const Rectangle<T>& rect) const noexcept | ||||
{ | { | ||||
return (fPos == rect.fPos && fSize == rect.fSize); | |||||
return (pos == rect.pos && size == rect.size); | |||||
} | } | ||||
template<typename T> | template<typename T> | ||||
bool Rectangle<T>::operator!=(const Rectangle<T>& rect) const noexcept | bool Rectangle<T>::operator!=(const Rectangle<T>& rect) const noexcept | ||||
{ | { | ||||
return (fPos != rect.fPos || fSize != rect.fSize); | |||||
return (pos != rect.pos || size != rect.size); | |||||
} | } | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -1,150 +0,0 @@ | |||||
/* | |||||
* DISTRHO Plugin Framework (DPF) | |||||
* Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#include "../Image.hpp" | |||||
START_NAMESPACE_DGL | |||||
// ----------------------------------------------------------------------- | |||||
Image::Image() | |||||
: ImageBase(), | |||||
fFormat(0), | |||||
fType(0), | |||||
fTextureId(0), | |||||
fIsReady(false) | |||||
{ | |||||
glGenTextures(1, &fTextureId); | |||||
} | |||||
Image::Image(const Image& image) | |||||
: ImageBase(image), | |||||
fFormat(image.fFormat), | |||||
fType(image.fType), | |||||
fTextureId(0), | |||||
fIsReady(false) | |||||
{ | |||||
glGenTextures(1, &fTextureId); | |||||
} | |||||
Image::Image(const char* const rawData, const uint width, const uint height, const GLenum format, const GLenum type) | |||||
: ImageBase(rawData, width, height), | |||||
fFormat(format), | |||||
fType(type), | |||||
fTextureId(0), | |||||
fIsReady(false) | |||||
{ | |||||
glGenTextures(1, &fTextureId); | |||||
} | |||||
Image::Image(const char* const rawData, const Size<uint>& size, const GLenum format, const GLenum type) | |||||
: ImageBase(rawData, size), | |||||
fFormat(format), | |||||
fType(type), | |||||
fTextureId(0), | |||||
fIsReady(false) | |||||
{ | |||||
glGenTextures(1, &fTextureId); | |||||
} | |||||
Image::~Image() | |||||
{ | |||||
if (fTextureId != 0) | |||||
{ | |||||
#ifndef DISTRHO_OS_MAC // FIXME | |||||
glDeleteTextures(1, &fTextureId); | |||||
#endif | |||||
fTextureId = 0; | |||||
} | |||||
} | |||||
void Image::loadFromMemory(const char* const rawData, | |||||
const uint width, | |||||
const uint height, | |||||
const GLenum format, | |||||
const GLenum type) noexcept | |||||
{ | |||||
loadFromMemory(rawData, Size<uint>(width, height), format, type); | |||||
} | |||||
void Image::loadFromMemory(const char* const rawData, | |||||
const Size<uint>& size, | |||||
const GLenum format, | |||||
const GLenum type) noexcept | |||||
{ | |||||
fRawData = rawData; | |||||
fSize = size; | |||||
fFormat = format; | |||||
fType = type; | |||||
fIsReady = false; | |||||
} | |||||
GLenum Image::getFormat() const noexcept | |||||
{ | |||||
return fFormat; | |||||
} | |||||
GLenum Image::getType() const noexcept | |||||
{ | |||||
return fType; | |||||
} | |||||
Image& Image::operator=(const Image& image) noexcept | |||||
{ | |||||
fRawData = image.fRawData; | |||||
fSize = image.fSize; | |||||
fFormat = image.fFormat; | |||||
fType = image.fType; | |||||
fIsReady = false; | |||||
return *this; | |||||
} | |||||
void Image::_drawAt(const Point<int>& pos) | |||||
{ | |||||
if (fTextureId == 0 || ! isValid()) | |||||
return; | |||||
glEnable(GL_TEXTURE_2D); | |||||
glBindTexture(GL_TEXTURE_2D, fTextureId); | |||||
if (! fIsReady) | |||||
{ | |||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); | |||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); | |||||
static const float trans[] = { 0.0f, 0.0f, 0.0f, 0.0f }; | |||||
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, trans); | |||||
glPixelStorei(GL_PACK_ALIGNMENT, 1); | |||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | |||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, | |||||
static_cast<GLsizei>(fSize.getWidth()), static_cast<GLsizei>(fSize.getHeight()), 0, | |||||
fFormat, fType, fRawData); | |||||
fIsReady = true; | |||||
} | |||||
Rectangle<int>(pos, static_cast<int>(fSize.getWidth()), static_cast<int>(fSize.getHeight())).draw(); | |||||
glBindTexture(GL_TEXTURE_2D, 0); | |||||
glDisable(GL_TEXTURE_2D); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DGL |
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -18,82 +18,107 @@ | |||||
START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// protected constructors | |||||
ImageBase::ImageBase() | ImageBase::ImageBase() | ||||
: fRawData(nullptr), | |||||
fSize(0, 0) {} | |||||
: rawData(nullptr), | |||||
size(0, 0), | |||||
format(kImageFormatNull) {} | |||||
ImageBase::ImageBase(const char* const rawData, const uint width, const uint height) | |||||
: fRawData(rawData), | |||||
fSize(width, height) {} | |||||
ImageBase::ImageBase(const char* const rdata, const uint width, const uint height, const ImageFormat fmt) | |||||
: rawData(rdata), | |||||
size(width, height), | |||||
format(fmt) {} | |||||
ImageBase::ImageBase(const char* const rawData, const Size<uint>& size) | |||||
: fRawData(rawData), | |||||
fSize(size) {} | |||||
ImageBase::ImageBase(const char* const rdata, const Size<uint>& s, const ImageFormat fmt) | |||||
: rawData(rdata), | |||||
size(s), | |||||
format(fmt) {} | |||||
ImageBase::ImageBase(const ImageBase& image) | ImageBase::ImageBase(const ImageBase& image) | ||||
: fRawData(image.fRawData), | |||||
fSize(image.fSize) {} | |||||
: rawData(image.rawData), | |||||
size(image.size), | |||||
format(image.format) {} | |||||
ImageBase::~ImageBase() {} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// public methods | |||||
// ----------------------------------------------------------------------- | |||||
ImageBase::~ImageBase() {} | |||||
bool ImageBase::isValid() const noexcept | bool ImageBase::isValid() const noexcept | ||||
{ | { | ||||
return (fRawData != nullptr && fSize.isValid()); | |||||
return (rawData != nullptr && size.isValid()); | |||||
} | |||||
bool ImageBase::isInvalid() const noexcept | |||||
{ | |||||
return (rawData == nullptr || size.isInvalid()); | |||||
} | } | ||||
uint ImageBase::getWidth() const noexcept | uint ImageBase::getWidth() const noexcept | ||||
{ | { | ||||
return fSize.getWidth(); | |||||
return size.getWidth(); | |||||
} | } | ||||
uint ImageBase::getHeight() const noexcept | uint ImageBase::getHeight() const noexcept | ||||
{ | { | ||||
return fSize.getHeight(); | |||||
return size.getHeight(); | |||||
} | } | ||||
const Size<uint>& ImageBase::getSize() const noexcept | const Size<uint>& ImageBase::getSize() const noexcept | ||||
{ | { | ||||
return fSize; | |||||
return size; | |||||
} | } | ||||
const char* ImageBase::getRawData() const noexcept | const char* ImageBase::getRawData() const noexcept | ||||
{ | { | ||||
return fRawData; | |||||
return rawData; | |||||
} | } | ||||
// ----------------------------------------------------------------------- | |||||
ImageFormat ImageBase::getFormat() const noexcept | |||||
{ | |||||
return format; | |||||
} | |||||
void ImageBase::loadFromMemory(const char* const rdata, | |||||
const uint width, | |||||
const uint height, | |||||
const ImageFormat fmt) noexcept | |||||
{ | |||||
loadFromMemory(rdata, Size<uint>(width, height), fmt); | |||||
} | |||||
void ImageBase::draw() | |||||
void ImageBase::loadFromMemory(const char* const rdata, const Size<uint>& s, const ImageFormat fmt) noexcept | |||||
{ | { | ||||
_drawAt(Point<int>()); | |||||
rawData = rdata; | |||||
size = s; | |||||
format = fmt; | |||||
} | } | ||||
void ImageBase::drawAt(const int x, const int y) | |||||
void ImageBase::draw(const GraphicsContext& context) | |||||
{ | { | ||||
_drawAt(Point<int>(x, y)); | |||||
drawAt(context, Point<int>(0, 0)); | |||||
} | } | ||||
void ImageBase::drawAt(const Point<int>& pos) | |||||
void ImageBase::drawAt(const GraphicsContext& context, const int x, const int y) | |||||
{ | { | ||||
_drawAt(pos); | |||||
drawAt(context, Point<int>(x, y)); | |||||
} | } | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// public operators | |||||
ImageBase& ImageBase::operator=(const ImageBase& image) noexcept | ImageBase& ImageBase::operator=(const ImageBase& image) noexcept | ||||
{ | { | ||||
fRawData = image.fRawData; | |||||
fSize = image.fSize; | |||||
rawData = image.rawData; | |||||
size = image.size; | |||||
return *this; | return *this; | ||||
} | } | ||||
bool ImageBase::operator==(const ImageBase& image) const noexcept | bool ImageBase::operator==(const ImageBase& image) const noexcept | ||||
{ | { | ||||
return (fRawData == image.fRawData && fSize == image.fSize); | |||||
return (rawData == image.rawData && size == image.size); | |||||
} | } | ||||
bool ImageBase::operator!=(const ImageBase& image) const noexcept | bool ImageBase::operator!=(const ImageBase& image) const noexcept | ||||
@@ -101,6 +126,6 @@ bool ImageBase::operator!=(const ImageBase& image) const noexcept | |||||
return !operator==(image); | return !operator==(image); | ||||
} | } | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
END_NAMESPACE_DGL | END_NAMESPACE_DGL |
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -15,7 +15,7 @@ | |||||
*/ | */ | ||||
#include "../NanoVG.hpp" | #include "../NanoVG.hpp" | ||||
#include "WidgetPrivateData.hpp" | |||||
#include "SubWidgetPrivateData.hpp" | |||||
#ifndef DGL_NO_SHARED_RESOURCES | #ifndef DGL_NO_SHARED_RESOURCES | ||||
# include "Resources.hpp" | # include "Resources.hpp" | ||||
@@ -257,11 +257,6 @@ NanoVG::NanoVG(int flags) | |||||
fInFrame(false), | fInFrame(false), | ||||
fIsSubWidget(false) {} | fIsSubWidget(false) {} | ||||
NanoVG::NanoVG(NanoWidget* groupWidget) | |||||
: fContext(groupWidget->fContext), | |||||
fInFrame(false), | |||||
fIsSubWidget(true) {} | |||||
NanoVG::~NanoVG() | NanoVG::~NanoVG() | ||||
{ | { | ||||
DISTRHO_SAFE_ASSERT(! fInFrame); | DISTRHO_SAFE_ASSERT(! fInFrame); | ||||
@@ -277,8 +272,8 @@ void NanoVG::beginFrame(const uint width, const uint height, const float scaleFa | |||||
if (fContext == nullptr) return; | if (fContext == nullptr) return; | ||||
DISTRHO_SAFE_ASSERT_RETURN(scaleFactor > 0.0f,); | DISTRHO_SAFE_ASSERT_RETURN(scaleFactor > 0.0f,); | ||||
DISTRHO_SAFE_ASSERT_RETURN(! fInFrame,); | DISTRHO_SAFE_ASSERT_RETURN(! fInFrame,); | ||||
fInFrame = true; | fInFrame = true; | ||||
nvgBeginFrame(fContext, static_cast<int>(width), static_cast<int>(height), scaleFactor); | nvgBeginFrame(fContext, static_cast<int>(width), static_cast<int>(height), scaleFactor); | ||||
} | } | ||||
@@ -286,14 +281,13 @@ void NanoVG::beginFrame(Widget* const widget) | |||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(widget != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(widget != nullptr,); | ||||
DISTRHO_SAFE_ASSERT_RETURN(! fInFrame,); | DISTRHO_SAFE_ASSERT_RETURN(! fInFrame,); | ||||
fInFrame = true; | fInFrame = true; | ||||
if (fContext == nullptr) | if (fContext == nullptr) | ||||
return; | return; | ||||
Window& window(widget->getParentWindow()); | |||||
nvgBeginFrame(fContext, static_cast<int>(window.getWidth()), static_cast<int>(window.getHeight()), 1.0f); | |||||
if (TopLevelWidget* const tlw = widget->getTopLevelWidget()) | |||||
nvgBeginFrame(fContext, static_cast<int>(tlw->getWidth()), static_cast<int>(tlw->getHeight()), 1.0f); | |||||
} | } | ||||
void NanoVG::cancelFrame() | void NanoVG::cancelFrame() | ||||
@@ -789,26 +783,26 @@ void NanoVG::stroke() | |||||
NanoVG::FontId NanoVG::createFontFromFile(const char* name, const char* filename) | NanoVG::FontId NanoVG::createFontFromFile(const char* name, const char* filename) | ||||
{ | { | ||||
if (fContext == nullptr) return -1; | |||||
DISTRHO_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', -1); | DISTRHO_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', -1); | ||||
DISTRHO_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', -1); | DISTRHO_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', -1); | ||||
DISTRHO_SAFE_ASSERT_RETURN(fContext != nullptr, -1); | |||||
return nvgCreateFont(fContext, name, filename); | return nvgCreateFont(fContext, name, filename); | ||||
} | } | ||||
NanoVG::FontId NanoVG::createFontFromMemory(const char* name, const uchar* data, uint dataSize, bool freeData) | NanoVG::FontId NanoVG::createFontFromMemory(const char* name, const uchar* data, uint dataSize, bool freeData) | ||||
{ | { | ||||
if (fContext == nullptr) return -1; | |||||
DISTRHO_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', -1); | DISTRHO_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', -1); | ||||
DISTRHO_SAFE_ASSERT_RETURN(data != nullptr, -1); | DISTRHO_SAFE_ASSERT_RETURN(data != nullptr, -1); | ||||
DISTRHO_SAFE_ASSERT_RETURN(fContext != nullptr, -1); | |||||
return nvgCreateFontMem(fContext, name, const_cast<uchar*>(data), static_cast<int>(dataSize), freeData); | return nvgCreateFontMem(fContext, name, const_cast<uchar*>(data), static_cast<int>(dataSize), freeData); | ||||
} | } | ||||
NanoVG::FontId NanoVG::findFont(const char* name) | NanoVG::FontId NanoVG::findFont(const char* name) | ||||
{ | { | ||||
if (fContext == nullptr) return -1; | |||||
DISTRHO_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', -1); | DISTRHO_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', -1); | ||||
DISTRHO_SAFE_ASSERT_RETURN(fContext != nullptr, -1); | |||||
return nvgFindFont(fContext, name); | return nvgFindFont(fContext, name); | ||||
} | } | ||||
@@ -930,79 +924,56 @@ int NanoVG::textBreakLines(const char* string, const char* end, float breakRowWi | |||||
} | } | ||||
#ifndef DGL_NO_SHARED_RESOURCES | #ifndef DGL_NO_SHARED_RESOURCES | ||||
void NanoVG::loadSharedResources() | |||||
bool NanoVG::loadSharedResources() | |||||
{ | { | ||||
if (fContext == nullptr) return; | |||||
if (fContext == nullptr) return false; | |||||
if (nvgFindFont(fContext, NANOVG_DEJAVU_SANS_TTF) >= 0) | if (nvgFindFont(fContext, NANOVG_DEJAVU_SANS_TTF) >= 0) | ||||
return; | |||||
return true; | |||||
using namespace dpf_resources; | using namespace dpf_resources; | ||||
nvgCreateFontMem(fContext, NANOVG_DEJAVU_SANS_TTF, (uchar*)dejavusans_ttf, dejavusans_ttf_size, 0); | |||||
return nvgCreateFontMem(fContext, NANOVG_DEJAVU_SANS_TTF, (uchar*)dejavusans_ttf, dejavusans_ttf_size, 0) >= 0; | |||||
} | } | ||||
#endif | #endif | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// NanoSubWidget | |||||
struct NanoWidget::PrivateData { | |||||
NanoWidget* const self; | |||||
std::vector<NanoWidget*> subWidgets; | |||||
PrivateData(NanoWidget* const s) | |||||
: self(s), | |||||
subWidgets() {} | |||||
~PrivateData() | |||||
{ | |||||
subWidgets.clear(); | |||||
} | |||||
}; | |||||
NanoWidget::NanoWidget(Window& parent, int flags) | |||||
: Widget(parent), | |||||
NanoVG(flags), | |||||
nData(new PrivateData(this)) | |||||
template <> | |||||
NanoBaseWidget<SubWidget>::NanoBaseWidget(Widget* const parent, int flags) | |||||
: SubWidget(parent), | |||||
NanoVG(flags) | |||||
{ | { | ||||
pData->needsScaling = true; | |||||
pData->needsViewportScaling = true; | |||||
} | } | ||||
NanoWidget::NanoWidget(Widget* groupWidget, int flags) | |||||
: Widget(groupWidget, true), | |||||
NanoVG(flags), | |||||
nData(new PrivateData(this)) | |||||
{ | |||||
pData->needsScaling = true; | |||||
} | |||||
template class NanoBaseWidget<SubWidget>; | |||||
NanoWidget::NanoWidget(NanoWidget* groupWidget) | |||||
: Widget(groupWidget, false), | |||||
NanoVG(groupWidget), | |||||
nData(new PrivateData(this)) | |||||
{ | |||||
pData->needsScaling = true; | |||||
pData->skipDisplay = true; | |||||
groupWidget->nData->subWidgets.push_back(this); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// NanoTopLevelWidget | |||||
NanoWidget::~NanoWidget() | |||||
{ | |||||
delete nData; | |||||
} | |||||
template <> | |||||
NanoBaseWidget<TopLevelWidget>::NanoBaseWidget(Window& windowToMapTo, int flags) | |||||
: TopLevelWidget(windowToMapTo), | |||||
NanoVG(flags) {} | |||||
void NanoWidget::onDisplay() | |||||
{ | |||||
NanoVG::beginFrame(getWidth(), getHeight()); | |||||
onNanoDisplay(); | |||||
template class NanoBaseWidget<TopLevelWidget>; | |||||
for (std::vector<NanoWidget*>::iterator it = nData->subWidgets.begin(); it != nData->subWidgets.end(); ++it) | |||||
{ | |||||
NanoWidget* const widget(*it); | |||||
widget->onNanoDisplay(); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// NanoStandaloneWindow | |||||
NanoVG::endFrame(); | |||||
} | |||||
template <> | |||||
NanoBaseWidget<StandaloneWindow>::NanoBaseWidget(Application& app, int flags) | |||||
: StandaloneWindow(app), | |||||
NanoVG(flags) {} | |||||
template <> | |||||
NanoBaseWidget<StandaloneWindow>::NanoBaseWidget(Application& app, Window& parentWindow, int flags) | |||||
: StandaloneWindow(app, parentWindow), | |||||
NanoVG(flags) {} | |||||
template class NanoBaseWidget<StandaloneWindow>; | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -14,136 +14,255 @@ | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
*/ | */ | ||||
#include "../Geometry.hpp" | |||||
#include "../OpenGL.hpp" | #include "../OpenGL.hpp" | ||||
#include "../Color.hpp" | |||||
#include "../ImageWidgets.hpp" | |||||
#include "Common.hpp" | |||||
#include "SubWidgetPrivateData.hpp" | |||||
#include "TopLevelWidgetPrivateData.hpp" | |||||
#include "WidgetPrivateData.hpp" | |||||
#include "WindowPrivateData.hpp" | |||||
// templated classes | |||||
#include "ImageBaseWidgets.cpp" | |||||
START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
// ----------------------------------------------------------------------- | |||||
// Color | |||||
void Color::setFor(const GraphicsContext&, const bool includeAlpha) | |||||
{ | |||||
if (includeAlpha) | |||||
glColor4f(red, green, blue, alpha); | |||||
else | |||||
glColor3f(red, green, blue); | |||||
} | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// Line | // Line | ||||
template<typename T> | template<typename T> | ||||
void Line<T>::draw() | |||||
static void drawLine(const Point<T>& posStart, const Point<T>& posEnd) | |||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(fPosStart != fPosEnd,); | |||||
DISTRHO_SAFE_ASSERT_RETURN(posStart != posEnd,); | |||||
glBegin(GL_LINES); | glBegin(GL_LINES); | ||||
{ | { | ||||
glVertex2d(fPosStart.fX, fPosStart.fY); | |||||
glVertex2d(fPosEnd.fX, fPosEnd.fY); | |||||
glVertex2d(posStart.getX(), posStart.getY()); | |||||
glVertex2d(posEnd.getX(), posEnd.getY()); | |||||
} | } | ||||
glEnd(); | glEnd(); | ||||
} | } | ||||
template<typename T> | |||||
void Line<T>::draw(const GraphicsContext&, const T width) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(width != 0,); | |||||
glLineWidth(static_cast<GLfloat>(width)); | |||||
drawLine<T>(posStart, posEnd); | |||||
} | |||||
// deprecated calls | |||||
template<typename T> | |||||
void Line<T>::draw() | |||||
{ | |||||
drawLine<T>(posStart, posEnd); | |||||
} | |||||
template class Line<double>; | |||||
template class Line<float>; | |||||
template class Line<int>; | |||||
template class Line<uint>; | |||||
template class Line<short>; | |||||
template class Line<ushort>; | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// Circle | // Circle | ||||
template<typename T> | template<typename T> | ||||
void Circle<T>::_draw(const bool outline) | |||||
static void drawCircle(const Point<T>& pos, | |||||
const uint numSegments, | |||||
const float size, | |||||
const float sin, | |||||
const float cos, | |||||
const bool outline) | |||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(fNumSegments >= 3 && fSize > 0.0f,); | |||||
DISTRHO_SAFE_ASSERT_RETURN(numSegments >= 3 && size > 0.0f,); | |||||
double t, x = fSize, y = 0.0; | |||||
const T origx = pos.getX(); | |||||
const T origy = pos.getY(); | |||||
double t, x = size, y = 0.0; | |||||
glBegin(outline ? GL_LINE_LOOP : GL_POLYGON); | glBegin(outline ? GL_LINE_LOOP : GL_POLYGON); | ||||
for (uint i=0; i<fNumSegments; ++i) | |||||
for (uint i=0; i<numSegments; ++i) | |||||
{ | { | ||||
glVertex2d(x + fPos.fX, y + fPos.fY); | |||||
glVertex2d(x + origx, y + origy); | |||||
t = x; | t = x; | ||||
x = fCos * x - fSin * y; | |||||
y = fSin * t + fCos * y; | |||||
x = cos * x - sin * y; | |||||
y = sin * t + cos * y; | |||||
} | } | ||||
glEnd(); | glEnd(); | ||||
} | } | ||||
template<typename T> | |||||
void Circle<T>::draw(const GraphicsContext&) | |||||
{ | |||||
drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, false); | |||||
} | |||||
template<typename T> | |||||
void Circle<T>::drawOutline(const GraphicsContext&, const T lineWidth) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,); | |||||
glLineWidth(static_cast<GLfloat>(lineWidth)); | |||||
drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, true); | |||||
} | |||||
// deprecated calls | |||||
template<typename T> | |||||
void Circle<T>::draw() | |||||
{ | |||||
drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, false); | |||||
} | |||||
template<typename T> | |||||
void Circle<T>::drawOutline() | |||||
{ | |||||
drawCircle<T>(fPos, fNumSegments, fSize, fSin, fCos, true); | |||||
} | |||||
template class Circle<double>; | |||||
template class Circle<float>; | |||||
template class Circle<int>; | |||||
template class Circle<uint>; | |||||
template class Circle<short>; | |||||
template class Circle<ushort>; | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// Triangle | // Triangle | ||||
template<typename T> | template<typename T> | ||||
void Triangle<T>::_draw(const bool outline) | |||||
static void drawTriangle(const Point<T>& pos1, | |||||
const Point<T>& pos2, | |||||
const Point<T>& pos3, | |||||
const bool outline) | |||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(fPos1 != fPos2 && fPos1 != fPos3,); | |||||
DISTRHO_SAFE_ASSERT_RETURN(pos1 != pos2 && pos1 != pos3,); | |||||
glBegin(outline ? GL_LINE_LOOP : GL_TRIANGLES); | glBegin(outline ? GL_LINE_LOOP : GL_TRIANGLES); | ||||
{ | { | ||||
glVertex2d(fPos1.fX, fPos1.fY); | |||||
glVertex2d(fPos2.fX, fPos2.fY); | |||||
glVertex2d(fPos3.fX, fPos3.fY); | |||||
glVertex2d(pos1.getX(), pos1.getY()); | |||||
glVertex2d(pos2.getX(), pos2.getY()); | |||||
glVertex2d(pos3.getX(), pos3.getY()); | |||||
} | } | ||||
glEnd(); | glEnd(); | ||||
} | } | ||||
template<typename T> | |||||
void Triangle<T>::draw(const GraphicsContext&) | |||||
{ | |||||
drawTriangle<T>(pos1, pos2, pos3, false); | |||||
} | |||||
template<typename T> | |||||
void Triangle<T>::drawOutline(const GraphicsContext&, const T lineWidth) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,); | |||||
glLineWidth(static_cast<GLfloat>(lineWidth)); | |||||
drawTriangle<T>(pos1, pos2, pos3, true); | |||||
} | |||||
// deprecated calls | |||||
template<typename T> | |||||
void Triangle<T>::draw() | |||||
{ | |||||
drawTriangle<T>(pos1, pos2, pos3, false); | |||||
} | |||||
template<typename T> | |||||
void Triangle<T>::drawOutline() | |||||
{ | |||||
drawTriangle<T>(pos1, pos2, pos3, true); | |||||
} | |||||
template class Triangle<double>; | |||||
template class Triangle<float>; | |||||
template class Triangle<int>; | |||||
template class Triangle<uint>; | |||||
template class Triangle<short>; | |||||
template class Triangle<ushort>; | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// Rectangle | // Rectangle | ||||
template<typename T> | template<typename T> | ||||
void Rectangle<T>::_draw(const bool outline) | |||||
static void drawRectangle(const Rectangle<T>& rect, const bool outline) | |||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(fSize.isValid(),); | |||||
DISTRHO_SAFE_ASSERT_RETURN(rect.isValid(),); | |||||
glBegin(outline ? GL_LINE_LOOP : GL_QUADS); | glBegin(outline ? GL_LINE_LOOP : GL_QUADS); | ||||
{ | { | ||||
const T x = rect.getX(); | |||||
const T y = rect.getY(); | |||||
const T w = rect.getWidth(); | |||||
const T h = rect.getHeight(); | |||||
glTexCoord2f(0.0f, 0.0f); | glTexCoord2f(0.0f, 0.0f); | ||||
glVertex2d(fPos.fX, fPos.fY); | |||||
glVertex2d(x, y); | |||||
glTexCoord2f(1.0f, 0.0f); | glTexCoord2f(1.0f, 0.0f); | ||||
glVertex2d(fPos.fX+fSize.fWidth, fPos.fY); | |||||
glVertex2d(x+w, y); | |||||
glTexCoord2f(1.0f, 1.0f); | glTexCoord2f(1.0f, 1.0f); | ||||
glVertex2d(fPos.fX+fSize.fWidth, fPos.fY+fSize.fHeight); | |||||
glVertex2d(x+w, y+h); | |||||
glTexCoord2f(0.0f, 1.0f); | glTexCoord2f(0.0f, 1.0f); | ||||
glVertex2d(fPos.fX, fPos.fY+fSize.fHeight); | |||||
glVertex2d(x, y+h); | |||||
} | } | ||||
glEnd(); | glEnd(); | ||||
} | } | ||||
// ----------------------------------------------------------------------- | |||||
// Possible template data types | |||||
template class Point<double>; | |||||
template class Point<float>; | |||||
template class Point<int>; | |||||
template class Point<uint>; | |||||
template class Point<short>; | |||||
template class Point<ushort>; | |||||
template class Size<double>; | |||||
template class Size<float>; | |||||
template class Size<int>; | |||||
template class Size<uint>; | |||||
template class Size<short>; | |||||
template class Size<ushort>; | |||||
template<typename T> | |||||
void Rectangle<T>::draw(const GraphicsContext&) | |||||
{ | |||||
drawRectangle<T>(*this, false); | |||||
} | |||||
template class Line<double>; | |||||
template class Line<float>; | |||||
template class Line<int>; | |||||
template class Line<uint>; | |||||
template class Line<short>; | |||||
template class Line<ushort>; | |||||
template<typename T> | |||||
void Rectangle<T>::drawOutline(const GraphicsContext&, const T lineWidth) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(lineWidth != 0,); | |||||
template class Circle<double>; | |||||
template class Circle<float>; | |||||
template class Circle<int>; | |||||
template class Circle<uint>; | |||||
template class Circle<short>; | |||||
template class Circle<ushort>; | |||||
glLineWidth(static_cast<GLfloat>(lineWidth)); | |||||
drawRectangle<T>(*this, true); | |||||
} | |||||
template class Triangle<double>; | |||||
template class Triangle<float>; | |||||
template class Triangle<int>; | |||||
template class Triangle<uint>; | |||||
template class Triangle<short>; | |||||
template class Triangle<ushort>; | |||||
// deprecated calls | |||||
template<typename T> | |||||
void Rectangle<T>::draw() | |||||
{ | |||||
drawRectangle<T>(*this, false); | |||||
} | |||||
template<typename T> | |||||
void Rectangle<T>::drawOutline() | |||||
{ | |||||
drawRectangle<T>(*this, true); | |||||
} | |||||
template class Rectangle<double>; | template class Rectangle<double>; | ||||
template class Rectangle<float>; | template class Rectangle<float>; | ||||
@@ -152,6 +271,387 @@ template class Rectangle<uint>; | |||||
template class Rectangle<short>; | template class Rectangle<short>; | ||||
template class Rectangle<ushort>; | template class Rectangle<ushort>; | ||||
// ----------------------------------------------------------------------- | |||||
// OpenGLImage | |||||
static void setupOpenGLImage(const OpenGLImage& image, GLuint textureId) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(image.isValid(),); | |||||
glEnable(GL_TEXTURE_2D); | |||||
glBindTexture(GL_TEXTURE_2D, textureId); | |||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); | |||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); | |||||
static const float trans[] = { 0.0f, 0.0f, 0.0f, 0.0f }; | |||||
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, trans); | |||||
glPixelStorei(GL_PACK_ALIGNMENT, 1); | |||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | |||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, | |||||
static_cast<GLsizei>(image.getWidth()), | |||||
static_cast<GLsizei>(image.getHeight()), | |||||
0, | |||||
asOpenGLImageFormat(image.getFormat()), GL_UNSIGNED_BYTE, image.getRawData()); | |||||
glBindTexture(GL_TEXTURE_2D, 0); | |||||
glDisable(GL_TEXTURE_2D); | |||||
} | |||||
static void drawOpenGLImage(const OpenGLImage& image, const Point<int>& pos, const GLuint textureId, bool& setupCalled) | |||||
{ | |||||
if (textureId == 0 || image.isInvalid()) | |||||
return; | |||||
if (! setupCalled) | |||||
{ | |||||
setupOpenGLImage(image, textureId); | |||||
setupCalled = true; | |||||
} | |||||
glEnable(GL_TEXTURE_2D); | |||||
glBindTexture(GL_TEXTURE_2D, textureId); | |||||
glBegin(GL_QUADS); | |||||
{ | |||||
const int x = pos.getX(); | |||||
const int y = pos.getY(); | |||||
const int w = static_cast<int>(image.getWidth()); | |||||
const int h = static_cast<int>(image.getHeight()); | |||||
glTexCoord2f(0.0f, 0.0f); | |||||
glVertex2d(x, y); | |||||
glTexCoord2f(1.0f, 0.0f); | |||||
glVertex2d(x+w, y); | |||||
glTexCoord2f(1.0f, 1.0f); | |||||
glVertex2d(x+w, y+h); | |||||
glTexCoord2f(0.0f, 1.0f); | |||||
glVertex2d(x, y+h); | |||||
} | |||||
glEnd(); | |||||
glBindTexture(GL_TEXTURE_2D, 0); | |||||
glDisable(GL_TEXTURE_2D); | |||||
} | |||||
OpenGLImage::OpenGLImage() | |||||
: ImageBase(), | |||||
textureId(0), | |||||
setupCalled(false) | |||||
{ | |||||
glGenTextures(1, &textureId); | |||||
DISTRHO_SAFE_ASSERT(textureId != 0); | |||||
} | |||||
OpenGLImage::OpenGLImage(const char* const rdata, const uint w, const uint h, const ImageFormat fmt) | |||||
: ImageBase(rdata, w, h, fmt), | |||||
textureId(0), | |||||
setupCalled(false) | |||||
{ | |||||
glGenTextures(1, &textureId); | |||||
DISTRHO_SAFE_ASSERT(textureId != 0); | |||||
} | |||||
OpenGLImage::OpenGLImage(const char* const rdata, const Size<uint>& s, const ImageFormat fmt) | |||||
: ImageBase(rdata, s, fmt), | |||||
textureId(0), | |||||
setupCalled(false) | |||||
{ | |||||
glGenTextures(1, &textureId); | |||||
DISTRHO_SAFE_ASSERT(textureId != 0); | |||||
} | |||||
OpenGLImage::OpenGLImage(const OpenGLImage& image) | |||||
: ImageBase(image), | |||||
textureId(0), | |||||
setupCalled(false) | |||||
{ | |||||
glGenTextures(1, &textureId); | |||||
DISTRHO_SAFE_ASSERT(textureId != 0); | |||||
} | |||||
OpenGLImage::~OpenGLImage() | |||||
{ | |||||
if (textureId != 0) | |||||
glDeleteTextures(1, &textureId); | |||||
} | |||||
void OpenGLImage::loadFromMemory(const char* const rdata, const Size<uint>& s, const ImageFormat fmt) noexcept | |||||
{ | |||||
setupCalled = false; | |||||
ImageBase::loadFromMemory(rdata, s, fmt); | |||||
} | |||||
void OpenGLImage::drawAt(const GraphicsContext&, const Point<int>& pos) | |||||
{ | |||||
drawOpenGLImage(*this, pos, textureId, setupCalled); | |||||
} | |||||
OpenGLImage& OpenGLImage::operator=(const OpenGLImage& image) noexcept | |||||
{ | |||||
rawData = image.rawData; | |||||
size = image.size; | |||||
format = image.format; | |||||
setupCalled = false; | |||||
return *this; | |||||
} | |||||
// deprecated calls | |||||
OpenGLImage::OpenGLImage(const char* const rdata, const uint w, const uint h, const GLenum fmt) | |||||
: ImageBase(rdata, w, h, asDISTRHOImageFormat(fmt)), | |||||
textureId(0), | |||||
setupCalled(false) | |||||
{ | |||||
glGenTextures(1, &textureId); | |||||
DISTRHO_SAFE_ASSERT(textureId != 0); | |||||
} | |||||
OpenGLImage::OpenGLImage(const char* const rdata, const Size<uint>& s, const GLenum fmt) | |||||
: ImageBase(rdata, s, asDISTRHOImageFormat(fmt)), | |||||
textureId(0), | |||||
setupCalled(false) | |||||
{ | |||||
glGenTextures(1, &textureId); | |||||
DISTRHO_SAFE_ASSERT(textureId != 0); | |||||
} | |||||
void OpenGLImage::draw() | |||||
{ | |||||
drawOpenGLImage(*this, Point<int>(0, 0), textureId, setupCalled); | |||||
} | |||||
void OpenGLImage::drawAt(const int x, const int y) | |||||
{ | |||||
drawOpenGLImage(*this, Point<int>(x, y), textureId, setupCalled); | |||||
} | |||||
void OpenGLImage::drawAt(const Point<int>& pos) | |||||
{ | |||||
drawOpenGLImage(*this, pos, textureId, setupCalled); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// ImageBaseAboutWindow | |||||
#if 0 | |||||
template <> | |||||
void ImageBaseAboutWindow<OpenGLImage>::onDisplay() | |||||
{ | |||||
const GraphicsContext& context(getGraphicsContext()); | |||||
img.draw(context); | |||||
} | |||||
#endif | |||||
template class ImageBaseAboutWindow<OpenGLImage>; | |||||
// ----------------------------------------------------------------------- | |||||
// ImageBaseButton | |||||
template class ImageBaseButton<OpenGLImage>; | |||||
// ----------------------------------------------------------------------- | |||||
// ImageBaseKnob | |||||
template <> | |||||
void ImageBaseKnob<OpenGLImage>::PrivateData::init() | |||||
{ | |||||
glTextureId = 0; | |||||
glGenTextures(1, &glTextureId); | |||||
} | |||||
template <> | |||||
void ImageBaseKnob<OpenGLImage>::PrivateData::cleanup() | |||||
{ | |||||
if (glTextureId == 0) | |||||
return; | |||||
glDeleteTextures(1, &glTextureId); | |||||
glTextureId = 0; | |||||
} | |||||
template <> | |||||
void ImageBaseKnob<OpenGLImage>::onDisplay() | |||||
{ | |||||
const GraphicsContext& context(getGraphicsContext()); | |||||
const float normValue = ((pData->usingLog ? pData->invlogscale(pData->value) : pData->value) - pData->minimum) | |||||
/ (pData->maximum - pData->minimum); | |||||
glEnable(GL_TEXTURE_2D); | |||||
glBindTexture(GL_TEXTURE_2D, pData->glTextureId); | |||||
if (! pData->isReady) | |||||
{ | |||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); | |||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); | |||||
static const float trans[] = { 0.0f, 0.0f, 0.0f, 0.0f }; | |||||
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, trans); | |||||
glPixelStorei(GL_PACK_ALIGNMENT, 1); | |||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | |||||
uint imageDataOffset = 0; | |||||
if (pData->rotationAngle == 0) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(pData->imgLayerCount > 0,); | |||||
DISTRHO_SAFE_ASSERT_RETURN(normValue >= 0.0f,); | |||||
const uint& v1(pData->isImgVertical ? pData->imgLayerWidth : pData->imgLayerHeight); | |||||
const uint& v2(pData->isImgVertical ? pData->imgLayerHeight : pData->imgLayerWidth); | |||||
// TODO kImageFormatGreyscale | |||||
const uint layerDataSize = v1 * v2 * ((pData->image.getFormat() == kImageFormatBGRA || | |||||
pData->image.getFormat() == kImageFormatRGBA) ? 4 : 3); | |||||
/* */ imageDataOffset = layerDataSize * uint(normValue * float(pData->imgLayerCount-1)); | |||||
} | |||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, | |||||
static_cast<GLsizei>(getWidth()), static_cast<GLsizei>(getHeight()), 0, | |||||
asOpenGLImageFormat(pData->image.getFormat()), GL_UNSIGNED_BYTE, pData->image.getRawData() + imageDataOffset); | |||||
pData->isReady = true; | |||||
} | |||||
const int w = static_cast<int>(getWidth()); | |||||
const int h = static_cast<int>(getHeight()); | |||||
if (pData->rotationAngle != 0) | |||||
{ | |||||
glPushMatrix(); | |||||
const int w2 = w/2; | |||||
const int h2 = h/2; | |||||
glTranslatef(static_cast<float>(w2), static_cast<float>(h2), 0.0f); | |||||
glRotatef(normValue*static_cast<float>(pData->rotationAngle), 0.0f, 0.0f, 1.0f); | |||||
Rectangle<int>(-w2, -h2, w, h).draw(context); | |||||
glPopMatrix(); | |||||
} | |||||
else | |||||
{ | |||||
Rectangle<int>(0, 0, w, h).draw(context); | |||||
} | |||||
glBindTexture(GL_TEXTURE_2D, 0); | |||||
glDisable(GL_TEXTURE_2D); | |||||
} | |||||
template class ImageBaseKnob<OpenGLImage>; | |||||
// ----------------------------------------------------------------------- | |||||
// ImageBaseSlider | |||||
template class ImageBaseSlider<OpenGLImage>; | |||||
// ----------------------------------------------------------------------- | |||||
// ImageBaseSwitch | |||||
template class ImageBaseSwitch<OpenGLImage>; | |||||
// ----------------------------------------------------------------------- | |||||
void SubWidget::PrivateData::display(const uint width, const uint height, const double autoScaleFactor) | |||||
{ | |||||
bool needsDisableScissor = false; | |||||
if (needsFullViewportForDrawing || (absolutePos.isZero() && self->getSize() == Size<uint>(width, height))) | |||||
{ | |||||
// full viewport size | |||||
glViewport(0, | |||||
-static_cast<int>(height * autoScaleFactor - height + 0.5), | |||||
static_cast<int>(width * autoScaleFactor + 0.5), | |||||
static_cast<int>(height * autoScaleFactor + 0.5)); | |||||
} | |||||
else if (needsViewportScaling) | |||||
{ | |||||
// limit viewport to widget bounds | |||||
glViewport(absolutePos.getX(), | |||||
static_cast<int>(height - self->getHeight()) - absolutePos.getY(), | |||||
static_cast<int>(self->getWidth()), | |||||
static_cast<int>(self->getHeight())); | |||||
} | |||||
else | |||||
{ | |||||
// set viewport pos | |||||
glViewport(static_cast<int>(absolutePos.getX() * autoScaleFactor + 0.5), | |||||
-static_cast<int>(std::round((height * autoScaleFactor - height) | |||||
+ (absolutePos.getY() * autoScaleFactor))), | |||||
static_cast<int>(std::round(width * autoScaleFactor)), | |||||
static_cast<int>(std::round(height * autoScaleFactor))); | |||||
// then cut the outer bounds | |||||
glScissor(static_cast<int>(absolutePos.getX() * autoScaleFactor + 0.5), | |||||
static_cast<int>(height - std::round((static_cast<int>(self->getHeight()) + absolutePos.getY()) | |||||
* autoScaleFactor)), | |||||
static_cast<int>(std::round(self->getWidth() * autoScaleFactor)), | |||||
static_cast<int>(std::round(self->getHeight() * autoScaleFactor))); | |||||
glEnable(GL_SCISSOR_TEST); | |||||
needsDisableScissor = true; | |||||
} | |||||
// display widget | |||||
self->onDisplay(); | |||||
if (needsDisableScissor) | |||||
glDisable(GL_SCISSOR_TEST); | |||||
selfw->pData->displaySubWidgets(width, height, autoScaleFactor); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
void TopLevelWidget::PrivateData::display() | |||||
{ | |||||
if (! selfw->pData->visible) | |||||
return; | |||||
const Size<uint> size(window.getSize()); | |||||
const uint width = size.getWidth(); | |||||
const uint height = size.getHeight(); | |||||
const double autoScaleFactor = window.pData->autoScaleFactor; | |||||
// full viewport size | |||||
if (window.pData->autoScaling) | |||||
{ | |||||
glViewport(0, | |||||
-static_cast<int>(height * autoScaleFactor - height), | |||||
static_cast<int>(width * autoScaleFactor), | |||||
static_cast<int>(height * autoScaleFactor)); | |||||
} | |||||
else | |||||
{ | |||||
glViewport(0, 0, static_cast<int>(width), static_cast<int>(height)); | |||||
} | |||||
// main widget drawing | |||||
self->onDisplay(); | |||||
// now draw subwidgets if there are any | |||||
selfw->pData->displaySubWidgets(width, height, autoScaleFactor); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept | |||||
{ | |||||
return (const GraphicsContext&)graphicsContext; | |||||
} | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
END_NAMESPACE_DGL | END_NAMESPACE_DGL |
@@ -0,0 +1,144 @@ | |||||
/* | |||||
* DISTRHO Plugin Framework (DPF) | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#include "SubWidgetPrivateData.hpp" | |||||
#include "../TopLevelWidget.hpp" | |||||
START_NAMESPACE_DGL | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
SubWidget::SubWidget(Widget* const parentWidget) | |||||
: Widget(parentWidget), | |||||
pData(new PrivateData(this, parentWidget)) {} | |||||
SubWidget::~SubWidget() | |||||
{ | |||||
delete pData; | |||||
} | |||||
template<typename T> | |||||
bool SubWidget::contains(T x, T y) const noexcept | |||||
{ | |||||
return Rectangle<double>(0, 0, getWidth(), getHeight()).contains(x, y); | |||||
} | |||||
template<typename T> | |||||
bool SubWidget::contains(const Point<T>& pos) const noexcept | |||||
{ | |||||
return contains(pos.getX(), pos.getY()); | |||||
} | |||||
int SubWidget::getAbsoluteX() const noexcept | |||||
{ | |||||
return pData->absolutePos.getX(); | |||||
} | |||||
int SubWidget::getAbsoluteY() const noexcept | |||||
{ | |||||
return pData->absolutePos.getY(); | |||||
} | |||||
Point<int> SubWidget::getAbsolutePos() const noexcept | |||||
{ | |||||
return pData->absolutePos; | |||||
} | |||||
Rectangle<int> SubWidget::getAbsoluteArea() const noexcept | |||||
{ | |||||
return Rectangle<int>(getAbsolutePos(), getSize().toInt()); | |||||
} | |||||
Rectangle<uint> SubWidget::getConstrainedAbsoluteArea() const noexcept | |||||
{ | |||||
return Rectangle<uint>(static_cast<uint>(std::max(0, getAbsoluteX())), | |||||
static_cast<uint>(std::max(0, getAbsoluteY())), | |||||
getSize()); | |||||
} | |||||
void SubWidget::setAbsoluteX(int x) noexcept | |||||
{ | |||||
setAbsolutePos(Point<int>(x, getAbsoluteY())); | |||||
} | |||||
void SubWidget::setAbsoluteY(int y) noexcept | |||||
{ | |||||
setAbsolutePos(Point<int>(getAbsoluteX(), y)); | |||||
} | |||||
void SubWidget::setAbsolutePos(int x, int y) noexcept | |||||
{ | |||||
setAbsolutePos(Point<int>(x, y)); | |||||
} | |||||
void SubWidget::setAbsolutePos(const Point<int>& pos) noexcept | |||||
{ | |||||
if (pData->absolutePos == pos) | |||||
return; | |||||
PositionChangedEvent ev; | |||||
ev.oldPos = pData->absolutePos; | |||||
ev.pos = pos; | |||||
pData->absolutePos = pos; | |||||
onPositionChanged(ev); | |||||
// repaint the bounds of parent | |||||
pData->parentWidget->repaint(); | |||||
} | |||||
Widget* SubWidget::getParentWidget() const noexcept | |||||
{ | |||||
return pData->parentWidget; | |||||
} | |||||
void SubWidget::repaint() noexcept | |||||
{ | |||||
if (! isVisible()) | |||||
return; | |||||
if (TopLevelWidget* const topw = getTopLevelWidget()) | |||||
{ | |||||
if (pData->needsFullViewportForDrawing) | |||||
topw->repaint(); | |||||
else | |||||
topw->repaint(getConstrainedAbsoluteArea()); | |||||
} | |||||
} | |||||
void SubWidget::setNeedsFullViewportDrawing(const bool needsFullViewportForDrawing) | |||||
{ | |||||
pData->needsFullViewportForDrawing = needsFullViewportForDrawing; | |||||
} | |||||
void SubWidget::onPositionChanged(const PositionChangedEvent&) | |||||
{ | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// Possible template data types | |||||
template<> | |||||
bool SubWidget::contains(const Point<double>& pos) const noexcept | |||||
{ | |||||
return contains(pos.getX(), pos.getY()); | |||||
} | |||||
// float, int, uint, short, ushort | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
END_NAMESPACE_DGL |
@@ -0,0 +1,42 @@ | |||||
/* | |||||
* DISTRHO Plugin Framework (DPF) | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#include "SubWidgetPrivateData.hpp" | |||||
#include "WidgetPrivateData.hpp" | |||||
START_NAMESPACE_DGL | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
SubWidget::PrivateData::PrivateData(SubWidget* const s, Widget* const pw) | |||||
: self(s), | |||||
selfw((Widget*)s), | |||||
parentWidget(pw), | |||||
absolutePos(), | |||||
needsFullViewportForDrawing(false), | |||||
needsViewportScaling(false) | |||||
{ | |||||
parentWidget->pData->subWidgets.push_back(self); | |||||
} | |||||
SubWidget::PrivateData::~PrivateData() | |||||
{ | |||||
parentWidget->pData->subWidgets.remove(self); | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
END_NAMESPACE_DGL |
@@ -0,0 +1,47 @@ | |||||
/* | |||||
* DISTRHO Plugin Framework (DPF) | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#ifndef DGL_SUBWIDGET_PRIVATE_DATA_HPP_INCLUDED | |||||
#define DGL_SUBWIDGET_PRIVATE_DATA_HPP_INCLUDED | |||||
#include "../SubWidget.hpp" | |||||
START_NAMESPACE_DGL | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
struct SubWidget::PrivateData { | |||||
SubWidget* const self; | |||||
Widget* const selfw; | |||||
Widget* const parentWidget; | |||||
Point<int> absolutePos; | |||||
bool needsFullViewportForDrawing; // needed for widgets drawing out of bounds | |||||
bool needsViewportScaling; // needed for NanoVG | |||||
explicit PrivateData(SubWidget* const s, Widget* const pw); | |||||
~PrivateData(); | |||||
// NOTE display function is different depending on build type, must call displaySubWidgets at the end | |||||
void display(uint width, uint height, double autoScaleFactor); | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PrivateData) | |||||
}; | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
END_NAMESPACE_DGL | |||||
#endif // DGL_SUBWIDGET_PRIVATE_DATA_HPP_INCLUDED |
@@ -0,0 +1,78 @@ | |||||
/* | |||||
* DISTRHO Plugin Framework (DPF) | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#include "TopLevelWidgetPrivateData.hpp" | |||||
#include "../Window.hpp" | |||||
START_NAMESPACE_DGL | |||||
// ----------------------------------------------------------------------- | |||||
TopLevelWidget::TopLevelWidget(Window& windowToMapTo) | |||||
: Widget(this), | |||||
pData(new PrivateData(this, windowToMapTo)) {} | |||||
TopLevelWidget::~TopLevelWidget() | |||||
{ | |||||
delete pData; | |||||
} | |||||
Application& TopLevelWidget::getApp() const noexcept | |||||
{ | |||||
return pData->window.getApp(); | |||||
} | |||||
Window& TopLevelWidget::getWindow() const noexcept | |||||
{ | |||||
return pData->window; | |||||
} | |||||
bool TopLevelWidget::addIdleCallback(IdleCallback* const callback, const uint timerFrequencyInMs) | |||||
{ | |||||
return pData->window.addIdleCallback(callback, timerFrequencyInMs); | |||||
} | |||||
bool TopLevelWidget::removeIdleCallback(IdleCallback* const callback) | |||||
{ | |||||
return pData->window.removeIdleCallback(callback); | |||||
} | |||||
double TopLevelWidget::getScaleFactor() const noexcept | |||||
{ | |||||
return pData->window.getScaleFactor(); | |||||
} | |||||
void TopLevelWidget::repaint() noexcept | |||||
{ | |||||
pData->window.repaint(); | |||||
} | |||||
void TopLevelWidget::repaint(const Rectangle<uint>& rect) noexcept | |||||
{ | |||||
pData->window.repaint(rect); | |||||
} | |||||
void TopLevelWidget::setGeometryConstraints(const uint minimumWidth, | |||||
const uint minimumHeight, | |||||
const bool keepAspectRatio, | |||||
const bool automaticallyScale) | |||||
{ | |||||
pData->window.setGeometryConstraints(minimumWidth, minimumHeight, keepAspectRatio, automaticallyScale); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DGL |
@@ -0,0 +1,163 @@ | |||||
/* | |||||
* DISTRHO Plugin Framework (DPF) | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#include "TopLevelWidgetPrivateData.hpp" | |||||
#include "WidgetPrivateData.hpp" | |||||
#include "WindowPrivateData.hpp" | |||||
#include "pugl.hpp" | |||||
START_NAMESPACE_DGL | |||||
// ----------------------------------------------------------------------- | |||||
TopLevelWidget::PrivateData::PrivateData(TopLevelWidget* const s, Window& w) | |||||
: self(s), | |||||
selfw(s), | |||||
window(w) | |||||
{ | |||||
window.pData->topLevelWidget = self; | |||||
} | |||||
TopLevelWidget::PrivateData::~PrivateData() | |||||
{ | |||||
// FIXME? | |||||
window.pData->topLevelWidget = nullptr; | |||||
} | |||||
bool TopLevelWidget::PrivateData::keyboardEvent(const KeyboardEvent& ev) | |||||
{ | |||||
// ignore event if we are not visible | |||||
if (! selfw->pData->visible) | |||||
return false; | |||||
// give top-level widget chance to catch this event first | |||||
if (self->onKeyboard(ev)) | |||||
return true; | |||||
// propagate event to all subwidgets recursively | |||||
return selfw->pData->giveKeyboardEventForSubWidgets(ev); | |||||
} | |||||
bool TopLevelWidget::PrivateData::specialEvent(const SpecialEvent& ev) | |||||
{ | |||||
// ignore event if we are not visible | |||||
if (! selfw->pData->visible) | |||||
return false; | |||||
// give top-level widget chance to catch this event first | |||||
if (self->onSpecial(ev)) | |||||
return true; | |||||
// propagate event to all subwidgets recursively | |||||
return selfw->pData->giveSpecialEventForSubWidgets(ev); | |||||
} | |||||
bool TopLevelWidget::PrivateData::characterInputEvent(const CharacterInputEvent& ev) | |||||
{ | |||||
// ignore event if we are not visible | |||||
if (! selfw->pData->visible) | |||||
return false; | |||||
// give top-level widget chance to catch this event first | |||||
if (self->onCharacterInput(ev)) | |||||
return true; | |||||
// propagate event to all subwidgets recursively | |||||
return selfw->pData->giveCharacterInputEventForSubWidgets(ev); | |||||
} | |||||
bool TopLevelWidget::PrivateData::mouseEvent(const MouseEvent& ev) | |||||
{ | |||||
// ignore event if we are not visible | |||||
if (! selfw->pData->visible) | |||||
return false; | |||||
MouseEvent rev = ev; | |||||
if (window.pData->autoScaling) | |||||
{ | |||||
const double autoScaleFactor = window.pData->autoScaleFactor; | |||||
rev.pos.setX(ev.pos.getX() / autoScaleFactor); | |||||
rev.pos.setY(ev.pos.getY() / autoScaleFactor); | |||||
} | |||||
// give top-level widget chance to catch this event first | |||||
if (self->onMouse(ev)) | |||||
return true; | |||||
// propagate event to all subwidgets recursively | |||||
return selfw->pData->giveMouseEventForSubWidgets(rev); | |||||
} | |||||
bool TopLevelWidget::PrivateData::motionEvent(const MotionEvent& ev) | |||||
{ | |||||
// ignore event if we are not visible | |||||
if (! selfw->pData->visible) | |||||
return false; | |||||
MotionEvent rev = ev; | |||||
if (window.pData->autoScaling) | |||||
{ | |||||
const double autoScaleFactor = window.pData->autoScaleFactor; | |||||
rev.pos.setX(ev.pos.getX() / autoScaleFactor); | |||||
rev.pos.setY(ev.pos.getY() / autoScaleFactor); | |||||
} | |||||
// give top-level widget chance to catch this event first | |||||
if (self->onMotion(ev)) | |||||
return true; | |||||
// propagate event to all subwidgets recursively | |||||
return selfw->pData->giveMotionEventForSubWidgets(rev); | |||||
} | |||||
bool TopLevelWidget::PrivateData::scrollEvent(const ScrollEvent& ev) | |||||
{ | |||||
// ignore event if we are not visible | |||||
if (! selfw->pData->visible) | |||||
return false; | |||||
ScrollEvent rev = ev; | |||||
if (window.pData->autoScaling) | |||||
{ | |||||
const double autoScaleFactor = window.pData->autoScaleFactor; | |||||
rev.pos.setX(ev.pos.getX() / autoScaleFactor); | |||||
rev.pos.setY(ev.pos.getY() / autoScaleFactor); | |||||
rev.delta.setX(ev.delta.getX() / autoScaleFactor); | |||||
rev.delta.setY(ev.delta.getY() / autoScaleFactor); | |||||
} | |||||
// give top-level widget chance to catch this event first | |||||
if (self->onScroll(ev)) | |||||
return true; | |||||
// propagate event to all subwidgets recursively | |||||
return selfw->pData->giveScrollEventForSubWidgets(rev); | |||||
} | |||||
void TopLevelWidget::PrivateData::fallbackOnResize() | |||||
{ | |||||
puglFallbackOnResize(window.pData->view); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DGL |
@@ -0,0 +1,51 @@ | |||||
/* | |||||
* DISTRHO Plugin Framework (DPF) | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#ifndef DGL_TOP_LEVEL_WIDGET_PRIVATE_DATA_HPP_INCLUDED | |||||
#define DGL_TOP_LEVEL_WIDGET_PRIVATE_DATA_HPP_INCLUDED | |||||
#include "../TopLevelWidget.hpp" | |||||
#include <list> | |||||
START_NAMESPACE_DGL | |||||
// ----------------------------------------------------------------------- | |||||
struct TopLevelWidget::PrivateData { | |||||
TopLevelWidget* const self; | |||||
Widget* const selfw; | |||||
Window& window; | |||||
explicit PrivateData(TopLevelWidget* const s, Window& w); | |||||
~PrivateData(); | |||||
void display(); | |||||
bool keyboardEvent(const KeyboardEvent& ev); | |||||
bool specialEvent(const SpecialEvent& ev); | |||||
bool characterInputEvent(const CharacterInputEvent& ev); | |||||
bool mouseEvent(const MouseEvent& ev); | |||||
bool motionEvent(const MotionEvent& ev); | |||||
bool scrollEvent(const ScrollEvent& ev); | |||||
void fallbackOnResize(); | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PrivateData) | |||||
}; | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DGL | |||||
#endif // DGL_TOP_LEVEL_WIDGET_PRIVATE_DATA_HPP_INCLUDED |
@@ -0,0 +1,243 @@ | |||||
/* | |||||
* DISTRHO Plugin Framework (DPF) | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#include "../Vulkan.hpp" | |||||
#include "../Color.hpp" | |||||
#include "SubWidgetPrivateData.hpp" | |||||
#include "TopLevelWidgetPrivateData.hpp" | |||||
#include "WidgetPrivateData.hpp" | |||||
#include "WindowPrivateData.hpp" | |||||
START_NAMESPACE_DGL | |||||
// ----------------------------------------------------------------------- | |||||
static void notImplemented(const char* const name) | |||||
{ | |||||
d_stderr2("vulkan function not implemented: %s", name); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// Color | |||||
void Color::setFor(const GraphicsContext&, bool) | |||||
{ | |||||
notImplemented("Color::setFor"); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// Line | |||||
template<typename T> | |||||
void Line<T>::draw(const GraphicsContext&, T) | |||||
{ | |||||
notImplemented("Line::draw"); | |||||
} | |||||
template<typename T> | |||||
void Line<T>::draw() | |||||
{ | |||||
notImplemented("Line::draw"); | |||||
} | |||||
template class Line<double>; | |||||
template class Line<float>; | |||||
template class Line<int>; | |||||
template class Line<uint>; | |||||
template class Line<short>; | |||||
template class Line<ushort>; | |||||
// ----------------------------------------------------------------------- | |||||
// Circle | |||||
template<typename T> | |||||
void Circle<T>::draw(const GraphicsContext&) | |||||
{ | |||||
notImplemented("Circle::draw"); | |||||
} | |||||
template<typename T> | |||||
void Circle<T>::drawOutline(const GraphicsContext&, T) | |||||
{ | |||||
notImplemented("Circle::drawOutline"); | |||||
} | |||||
template<typename T> | |||||
void Circle<T>::draw() | |||||
{ | |||||
notImplemented("Circle::draw"); | |||||
} | |||||
template<typename T> | |||||
void Circle<T>::drawOutline() | |||||
{ | |||||
notImplemented("Circle::drawOutline"); | |||||
} | |||||
template class Circle<double>; | |||||
template class Circle<float>; | |||||
template class Circle<int>; | |||||
template class Circle<uint>; | |||||
template class Circle<short>; | |||||
template class Circle<ushort>; | |||||
// ----------------------------------------------------------------------- | |||||
// Triangle | |||||
template<typename T> | |||||
void Triangle<T>::draw(const GraphicsContext&) | |||||
{ | |||||
notImplemented("Triangle::draw"); | |||||
} | |||||
template<typename T> | |||||
void Triangle<T>::drawOutline(const GraphicsContext&, T) | |||||
{ | |||||
notImplemented("Triangle::drawOutline"); | |||||
} | |||||
template<typename T> | |||||
void Triangle<T>::draw() | |||||
{ | |||||
notImplemented("Triangle::draw"); | |||||
} | |||||
template<typename T> | |||||
void Triangle<T>::drawOutline() | |||||
{ | |||||
notImplemented("Triangle::drawOutline"); | |||||
} | |||||
template class Triangle<double>; | |||||
template class Triangle<float>; | |||||
template class Triangle<int>; | |||||
template class Triangle<uint>; | |||||
template class Triangle<short>; | |||||
template class Triangle<ushort>; | |||||
// ----------------------------------------------------------------------- | |||||
// Rectangle | |||||
template<typename T> | |||||
void Rectangle<T>::draw(const GraphicsContext&) | |||||
{ | |||||
notImplemented("Rectangle::draw"); | |||||
} | |||||
template<typename T> | |||||
void Rectangle<T>::drawOutline(const GraphicsContext&, T) | |||||
{ | |||||
notImplemented("Rectangle::drawOutline"); | |||||
} | |||||
template<typename T> | |||||
void Rectangle<T>::draw() | |||||
{ | |||||
notImplemented("Rectangle::draw"); | |||||
} | |||||
template<typename T> | |||||
void Rectangle<T>::drawOutline() | |||||
{ | |||||
notImplemented("Rectangle::drawOutline"); | |||||
} | |||||
template class Rectangle<double>; | |||||
template class Rectangle<float>; | |||||
template class Rectangle<int>; | |||||
template class Rectangle<uint>; | |||||
template class Rectangle<short>; | |||||
template class Rectangle<ushort>; | |||||
// ----------------------------------------------------------------------- | |||||
// VulkanImage | |||||
VulkanImage::VulkanImage() | |||||
: ImageBase() {} | |||||
VulkanImage::VulkanImage(const char* const rdata, const uint w, const uint h, const ImageFormat fmt) | |||||
: ImageBase(rdata, w, h, fmt) {} | |||||
VulkanImage::VulkanImage(const char* const rdata, const Size<uint>& s, const ImageFormat fmt) | |||||
: ImageBase(rdata, s, fmt) {} | |||||
VulkanImage::VulkanImage(const VulkanImage& image) | |||||
: ImageBase(image.rawData, image.size, image.format) {} | |||||
VulkanImage::~VulkanImage() {} | |||||
void VulkanImage::loadFromMemory(const char* const rdata, const Size<uint>& s, const ImageFormat fmt) noexcept | |||||
{ | |||||
ImageBase::loadFromMemory(rdata, s, fmt); | |||||
} | |||||
void VulkanImage::drawAt(const GraphicsContext&, const Point<int>&) | |||||
{ | |||||
} | |||||
VulkanImage& VulkanImage::operator=(const VulkanImage& image) noexcept | |||||
{ | |||||
rawData = image.rawData; | |||||
size = image.size; | |||||
format = image.format; | |||||
return *this; | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
void SubWidget::PrivateData::display(const uint width, const uint height, const double autoScaleFactor) | |||||
{ | |||||
// TODO | |||||
selfw->pData->displaySubWidgets(width, height, autoScaleFactor); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
void TopLevelWidget::PrivateData::display() | |||||
{ | |||||
if (! selfw->pData->visible) | |||||
return; | |||||
const Size<uint> size(window.getSize()); | |||||
const uint width = size.getWidth(); | |||||
const uint height = size.getHeight(); | |||||
const double autoScaleFactor = window.pData->autoScaleFactor; | |||||
// TODO | |||||
// main widget drawing | |||||
self->onDisplay(); | |||||
// now draw subwidgets if there are any | |||||
selfw->pData->displaySubWidgets(width, height, autoScaleFactor); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept | |||||
{ | |||||
return (const GraphicsContext&)graphicsContext; | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DGL | |||||
// ----------------------------------------------------------------------- |
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -15,33 +15,22 @@ | |||||
*/ | */ | ||||
#include "WidgetPrivateData.hpp" | #include "WidgetPrivateData.hpp" | ||||
#include "../TopLevelWidget.hpp" | |||||
#include "../Window.hpp" | |||||
START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// Widget | // Widget | ||||
Widget::Widget(Window& parent) | |||||
: pData(new PrivateData(this, parent, nullptr, false)) | |||||
{ | |||||
parent._addWidget(this); | |||||
} | |||||
Widget::Widget(Widget* groupWidget) | |||||
: pData(new PrivateData(this, groupWidget->getParentWindow(), groupWidget, true)) | |||||
{ | |||||
pData->parent._addWidget(this); | |||||
} | |||||
Widget::Widget(TopLevelWidget* const topLevelWidget) | |||||
: pData(new PrivateData(this, topLevelWidget)) {} | |||||
Widget::Widget(Widget* groupWidget, bool addToSubWidgets) | |||||
: pData(new PrivateData(this, groupWidget->getParentWindow(), groupWidget, addToSubWidgets)) | |||||
{ | |||||
pData->parent._addWidget(this); | |||||
} | |||||
Widget::Widget(Widget* const parentWidget) | |||||
: pData(new PrivateData(this, parentWidget)) {} | |||||
Widget::~Widget() | Widget::~Widget() | ||||
{ | { | ||||
pData->parent._removeWidget(this); | |||||
delete pData; | delete pData; | ||||
} | } | ||||
@@ -50,13 +39,13 @@ bool Widget::isVisible() const noexcept | |||||
return pData->visible; | return pData->visible; | ||||
} | } | ||||
void Widget::setVisible(bool yesNo) | |||||
void Widget::setVisible(bool visible) | |||||
{ | { | ||||
if (pData->visible == yesNo) | |||||
if (pData->visible == visible) | |||||
return; | return; | ||||
pData->visible = yesNo; | |||||
pData->parent.repaint(); | |||||
pData->visible = visible; | |||||
repaint(); | |||||
} | } | ||||
void Widget::show() | void Widget::show() | ||||
@@ -79,7 +68,7 @@ uint Widget::getHeight() const noexcept | |||||
return pData->size.getHeight(); | return pData->size.getHeight(); | ||||
} | } | ||||
const Size<uint>& Widget::getSize() const noexcept | |||||
const Size<uint> Widget::getSize() const noexcept | |||||
{ | { | ||||
return pData->size; | return pData->size; | ||||
} | } | ||||
@@ -96,7 +85,7 @@ void Widget::setWidth(uint width) noexcept | |||||
pData->size.setWidth(width); | pData->size.setWidth(width); | ||||
onResize(ev); | onResize(ev); | ||||
pData->parent.repaint(); | |||||
repaint(); | |||||
} | } | ||||
void Widget::setHeight(uint height) noexcept | void Widget::setHeight(uint height) noexcept | ||||
@@ -111,7 +100,7 @@ void Widget::setHeight(uint height) noexcept | |||||
pData->size.setHeight(height); | pData->size.setHeight(height); | ||||
onResize(ev); | onResize(ev); | ||||
pData->parent.repaint(); | |||||
repaint(); | |||||
} | } | ||||
void Widget::setSize(uint width, uint height) noexcept | void Widget::setSize(uint width, uint height) noexcept | ||||
@@ -131,77 +120,34 @@ void Widget::setSize(const Size<uint>& size) noexcept | |||||
pData->size = size; | pData->size = size; | ||||
onResize(ev); | onResize(ev); | ||||
pData->parent.repaint(); | |||||
} | |||||
int Widget::getAbsoluteX() const noexcept | |||||
{ | |||||
return pData->absolutePos.getX(); | |||||
} | |||||
int Widget::getAbsoluteY() const noexcept | |||||
{ | |||||
return pData->absolutePos.getY(); | |||||
} | |||||
const Point<int>& Widget::getAbsolutePos() const noexcept | |||||
{ | |||||
return pData->absolutePos; | |||||
repaint(); | |||||
} | } | ||||
void Widget::setAbsoluteX(int x) noexcept | |||||
Application& Widget::getApp() const noexcept | |||||
{ | { | ||||
setAbsolutePos(Point<int>(x, getAbsoluteY())); | |||||
DISTRHO_SAFE_ASSERT(pData->topLevelWidget != nullptr); | |||||
return pData->topLevelWidget->getApp(); | |||||
} | } | ||||
void Widget::setAbsoluteY(int y) noexcept | |||||
Window& Widget::getWindow() const noexcept | |||||
{ | { | ||||
setAbsolutePos(Point<int>(getAbsoluteX(), y)); | |||||
DISTRHO_SAFE_ASSERT(pData->topLevelWidget != nullptr); | |||||
return pData->topLevelWidget->getWindow(); | |||||
} | } | ||||
void Widget::setAbsolutePos(int x, int y) noexcept | |||||
const GraphicsContext& Widget::getGraphicsContext() const noexcept | |||||
{ | { | ||||
setAbsolutePos(Point<int>(x, y)); | |||||
DISTRHO_SAFE_ASSERT(pData->topLevelWidget != nullptr); | |||||
return pData->topLevelWidget->getWindow().getGraphicsContext(); | |||||
} | } | ||||
void Widget::setAbsolutePos(const Point<int>& pos) noexcept | |||||
TopLevelWidget* Widget::getTopLevelWidget() const noexcept | |||||
{ | { | ||||
if (pData->absolutePos == pos) | |||||
return; | |||||
PositionChangedEvent ev; | |||||
ev.oldPos = pData->absolutePos; | |||||
ev.pos = pos; | |||||
pData->absolutePos = pos; | |||||
onPositionChanged(ev); | |||||
pData->parent.repaint(); | |||||
} | |||||
Application& Widget::getParentApp() const noexcept | |||||
{ | |||||
return pData->parent.getApp(); | |||||
} | |||||
Window& Widget::getParentWindow() const noexcept | |||||
{ | |||||
return pData->parent; | |||||
} | |||||
bool Widget::contains(int x, int y) const noexcept | |||||
{ | |||||
return (x >= 0 && y >= 0 && static_cast<uint>(x) < pData->size.getWidth() && static_cast<uint>(y) < pData->size.getHeight()); | |||||
} | |||||
bool Widget::contains(const Point<int>& pos) const noexcept | |||||
{ | |||||
return contains(pos.getX(), pos.getY()); | |||||
return pData->topLevelWidget; | |||||
} | } | ||||
void Widget::repaint() noexcept | void Widget::repaint() noexcept | ||||
{ | { | ||||
pData->parent.repaint(); | |||||
} | } | ||||
uint Widget::getId() const noexcept | uint Widget::getId() const noexcept | ||||
@@ -224,6 +170,11 @@ bool Widget::onSpecial(const SpecialEvent&) | |||||
return false; | return false; | ||||
} | } | ||||
bool Widget::onCharacterInput(const CharacterInputEvent&) | |||||
{ | |||||
return false; | |||||
} | |||||
bool Widget::onMouse(const MouseEvent&) | bool Widget::onMouse(const MouseEvent&) | ||||
{ | { | ||||
return false; | return false; | ||||
@@ -243,10 +194,6 @@ void Widget::onResize(const ResizeEvent&) | |||||
{ | { | ||||
} | } | ||||
void Widget::onPositionChanged(const PositionChangedEvent&) | |||||
{ | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
END_NAMESPACE_DGL | END_NAMESPACE_DGL |
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -15,91 +15,204 @@ | |||||
*/ | */ | ||||
#include "WidgetPrivateData.hpp" | #include "WidgetPrivateData.hpp" | ||||
#ifdef DGL_CAIRO | |||||
# include "../Cairo.hpp" | |||||
#endif | |||||
#ifdef DGL_OPENGL | |||||
# include "../OpenGL.hpp" | |||||
#endif | |||||
#include "SubWidgetPrivateData.hpp" | |||||
#include "../TopLevelWidget.hpp" | |||||
START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
#define FOR_EACH_SUBWIDGET(it) \ | |||||
for (std::list<SubWidget*>::iterator it = subWidgets.begin(); it != subWidgets.end(); ++it) | |||||
#define FOR_EACH_SUBWIDGET_INV(rit) \ | |||||
for (std::list<SubWidget*>::reverse_iterator rit = subWidgets.rbegin(); rit != subWidgets.rend(); ++rit) | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
void Widget::PrivateData::display(const uint width, | |||||
const uint height, | |||||
const double scaling, | |||||
const bool renderingSubWidget) | |||||
Widget::PrivateData::PrivateData(Widget* const s, TopLevelWidget* const tlw) | |||||
: self(s), | |||||
topLevelWidget(tlw), | |||||
parentWidget(nullptr), | |||||
id(0), | |||||
needsScaling(false), | |||||
visible(true), | |||||
size(0, 0), | |||||
subWidgets() {} | |||||
Widget::PrivateData::PrivateData(Widget* const s, Widget* const pw) | |||||
: self(s), | |||||
topLevelWidget(findTopLevelWidget(pw)), | |||||
parentWidget(pw), | |||||
id(0), | |||||
needsScaling(false), | |||||
visible(true), | |||||
size(0, 0), | |||||
subWidgets() {} | |||||
Widget::PrivateData::~PrivateData() | |||||
{ | |||||
subWidgets.clear(); | |||||
} | |||||
void Widget::PrivateData::displaySubWidgets(const uint width, const uint height, const double autoScaleFactor) | |||||
{ | { | ||||
if ((skipDisplay && ! renderingSubWidget) || size.isInvalid() || ! visible) | |||||
if (subWidgets.size() == 0) | |||||
return; | return; | ||||
#ifdef DGL_OPENGL | |||||
bool needsDisableScissor = false; | |||||
for (std::list<SubWidget*>::iterator it = subWidgets.begin(); it != subWidgets.end(); ++it) | |||||
{ | |||||
SubWidget* const subwidget(*it); | |||||
// reset color | |||||
glColor4f(1.0f, 1.0f, 1.0f, 1.0f); | |||||
if (subwidget->isVisible()) | |||||
subwidget->pData->display(width, height, autoScaleFactor); | |||||
} | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
bool Widget::PrivateData::giveKeyboardEventForSubWidgets(const KeyboardEvent& ev) | |||||
{ | |||||
if (! visible) | |||||
return false; | |||||
if (subWidgets.size() == 0) | |||||
return false; | |||||
FOR_EACH_SUBWIDGET_INV(rit) | |||||
{ | |||||
SubWidget* const widget(*rit); | |||||
if (widget->isVisible() && widget->onKeyboard(ev)) | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
bool Widget::PrivateData::giveSpecialEventForSubWidgets(const SpecialEvent& ev) | |||||
{ | |||||
if (! visible) | |||||
return false; | |||||
if (subWidgets.size() == 0) | |||||
return false; | |||||
FOR_EACH_SUBWIDGET_INV(rit) | |||||
{ | |||||
SubWidget* const widget(*rit); | |||||
if (widget->isVisible() && widget->onSpecial(ev)) | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
bool Widget::PrivateData::giveCharacterInputEventForSubWidgets(const CharacterInputEvent& ev) | |||||
{ | |||||
if (! visible) | |||||
return false; | |||||
if (subWidgets.size() == 0) | |||||
return false; | |||||
if (needsFullViewport || (absolutePos.isZero() && size == Size<uint>(width, height))) | |||||
FOR_EACH_SUBWIDGET_INV(rit) | |||||
{ | { | ||||
// full viewport size | |||||
glViewport(0, | |||||
-(height * scaling - height), | |||||
width * scaling, | |||||
height * scaling); | |||||
SubWidget* const widget(*rit); | |||||
if (widget->isVisible() && widget->onCharacterInput(ev)) | |||||
return true; | |||||
} | } | ||||
else if (needsScaling) | |||||
return false; | |||||
} | |||||
bool Widget::PrivateData::giveMouseEventForSubWidgets(MouseEvent& ev) | |||||
{ | |||||
if (! visible) | |||||
return false; | |||||
if (subWidgets.size() == 0) | |||||
return false; | |||||
const double x = ev.pos.getX(); | |||||
const double y = ev.pos.getY(); | |||||
FOR_EACH_SUBWIDGET_INV(rit) | |||||
{ | { | ||||
// limit viewport to widget bounds | |||||
glViewport(absolutePos.getX(), | |||||
height - self->getHeight() - absolutePos.getY(), | |||||
self->getWidth(), | |||||
self->getHeight()); | |||||
SubWidget* const widget(*rit); | |||||
if (! widget->isVisible()) | |||||
continue; | |||||
ev.pos = Point<double>(x - widget->getAbsoluteX(), | |||||
y - widget->getAbsoluteY()); | |||||
if (widget->onMouse(ev)) | |||||
return true; | |||||
} | } | ||||
else | |||||
return false; | |||||
} | |||||
bool Widget::PrivateData::giveMotionEventForSubWidgets(MotionEvent& ev) | |||||
{ | |||||
if (! visible) | |||||
return false; | |||||
if (subWidgets.size() == 0) | |||||
return false; | |||||
const double x = ev.pos.getX(); | |||||
const double y = ev.pos.getY(); | |||||
FOR_EACH_SUBWIDGET_INV(rit) | |||||
{ | { | ||||
// only set viewport pos | |||||
glViewport(absolutePos.getX() * scaling, | |||||
-std::round((height * scaling - height) + (absolutePos.getY() * scaling)), | |||||
std::round(width * scaling), | |||||
std::round(height * scaling)); | |||||
// then cut the outer bounds | |||||
glScissor(absolutePos.getX() * scaling, | |||||
height - std::round((self->getHeight() + absolutePos.getY()) * scaling), | |||||
std::round(self->getWidth() * scaling), | |||||
std::round(self->getHeight() * scaling)); | |||||
glEnable(GL_SCISSOR_TEST); | |||||
needsDisableScissor = true; | |||||
SubWidget* const widget(*rit); | |||||
if (! widget->isVisible()) | |||||
continue; | |||||
ev.pos = Point<double>(x - widget->getAbsoluteX(), | |||||
y - widget->getAbsoluteY()); | |||||
if (widget->onMotion(ev)) | |||||
return true; | |||||
} | } | ||||
#endif | |||||
#ifdef DGL_CAIRO | |||||
cairo_t* cr = parent.getGraphicsContext().cairo; | |||||
cairo_matrix_t matrix; | |||||
cairo_get_matrix(cr, &matrix); | |||||
cairo_translate(cr, absolutePos.getX(), absolutePos.getY()); | |||||
// TODO: scaling and cropping | |||||
#endif | |||||
return false; | |||||
} | |||||
// display widget | |||||
self->onDisplay(); | |||||
bool Widget::PrivateData::giveScrollEventForSubWidgets(ScrollEvent& ev) | |||||
{ | |||||
if (! visible) | |||||
return false; | |||||
if (subWidgets.size() == 0) | |||||
return false; | |||||
#ifdef DGL_CAIRO | |||||
cairo_set_matrix(cr, &matrix); | |||||
#endif | |||||
const double x = ev.pos.getX(); | |||||
const double y = ev.pos.getY(); | |||||
#ifdef DGL_OPENGL | |||||
if (needsDisableScissor) | |||||
FOR_EACH_SUBWIDGET_INV(rit) | |||||
{ | { | ||||
glDisable(GL_SCISSOR_TEST); | |||||
needsDisableScissor = false; | |||||
SubWidget* const widget(*rit); | |||||
if (! widget->isVisible()) | |||||
continue; | |||||
ev.pos = Point<double>(x - widget->getAbsoluteX(), | |||||
y - widget->getAbsoluteY()); | |||||
if (widget->onScroll(ev)) | |||||
return true; | |||||
} | } | ||||
#endif | |||||
displaySubWidgets(width, height, scaling); | |||||
return false; | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
TopLevelWidget* Widget::PrivateData::findTopLevelWidget(Widget* const pw) | |||||
{ | |||||
if (pw->pData->topLevelWidget != nullptr) | |||||
return pw->pData->topLevelWidget; | |||||
if (pw->pData->parentWidget != nullptr) | |||||
return findTopLevelWidget(pw->pData->parentWidget); | |||||
return nullptr; | |||||
} | } | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -18,69 +18,44 @@ | |||||
#define DGL_WIDGET_PRIVATE_DATA_HPP_INCLUDED | #define DGL_WIDGET_PRIVATE_DATA_HPP_INCLUDED | ||||
#include "../Widget.hpp" | #include "../Widget.hpp" | ||||
#include "../Window.hpp" | |||||
#include <vector> | |||||
#include <list> | |||||
START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
struct Widget::PrivateData { | struct Widget::PrivateData { | ||||
Widget* const self; | Widget* const self; | ||||
Window& parent; | |||||
Point<int> absolutePos; | |||||
Size<uint> size; | |||||
std::vector<Widget*> subWidgets; | |||||
TopLevelWidget* const topLevelWidget; | |||||
Widget* const parentWidget; | |||||
uint id; | uint id; | ||||
bool needsFullViewport; | |||||
bool needsScaling; | bool needsScaling; | ||||
bool skipDisplay; | |||||
bool visible; | bool visible; | ||||
Size<uint> size; | |||||
std::list<SubWidget*> subWidgets; | |||||
PrivateData(Widget* const s, Window& p, Widget* groupWidget, bool addToSubWidgets) | |||||
: self(s), | |||||
parent(p), | |||||
absolutePos(0, 0), | |||||
size(0, 0), | |||||
subWidgets(), | |||||
id(0), | |||||
needsFullViewport(false), | |||||
needsScaling(false), | |||||
skipDisplay(false), | |||||
visible(true) | |||||
{ | |||||
if (addToSubWidgets && groupWidget != nullptr) | |||||
{ | |||||
skipDisplay = true; | |||||
groupWidget->pData->subWidgets.push_back(self); | |||||
} | |||||
} | |||||
~PrivateData() | |||||
{ | |||||
subWidgets.clear(); | |||||
} | |||||
// called via TopLevelWidget | |||||
explicit PrivateData(Widget* const s, TopLevelWidget* const tlw); | |||||
// called via SubWidget | |||||
explicit PrivateData(Widget* const s, Widget* const pw); | |||||
~PrivateData(); | |||||
// display function is different depending on build type | |||||
void display(const uint width, const uint height, const double scaling, const bool renderingSubWidget); | |||||
void displaySubWidgets(uint width, uint height, double autoScaleFactor); | |||||
void displaySubWidgets(const uint width, const uint height, const double scaling) | |||||
{ | |||||
for (std::vector<Widget*>::iterator it = subWidgets.begin(); it != subWidgets.end(); ++it) | |||||
{ | |||||
Widget* const widget(*it); | |||||
DISTRHO_SAFE_ASSERT_CONTINUE(widget->pData != this); | |||||
bool giveKeyboardEventForSubWidgets(const KeyboardEvent& ev); | |||||
bool giveSpecialEventForSubWidgets(const SpecialEvent& ev); | |||||
bool giveCharacterInputEventForSubWidgets(const CharacterInputEvent& ev); | |||||
bool giveMouseEventForSubWidgets(MouseEvent& ev); | |||||
bool giveMotionEventForSubWidgets(MotionEvent& ev); | |||||
bool giveScrollEventForSubWidgets(ScrollEvent& ev); | |||||
widget->pData->display(width, height, scaling, true); | |||||
} | |||||
} | |||||
static TopLevelWidget* findTopLevelWidget(Widget* const w); | |||||
DISTRHO_DECLARE_NON_COPY_STRUCT(PrivateData) | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PrivateData) | |||||
}; | }; | ||||
// ----------------------------------------------------------------------- | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
END_NAMESPACE_DGL | END_NAMESPACE_DGL | ||||
@@ -0,0 +1,223 @@ | |||||
/* | |||||
* DISTRHO Plugin Framework (DPF) | |||||
* Copyright (C) 2012-2020 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2019 Jean Pierre Cimalando <jp-dev@inbox.ru> | |||||
* Copyright (C) 2019 Robin Gareus <robin@gareus.org> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#include "../StandaloneWindow.hpp" | |||||
// static int fib_filter_filename_filter(const char* const name) | |||||
// { | |||||
// return 1; | |||||
// (void)name; | |||||
// } | |||||
// TODO use DGL_NAMESPACE for class names | |||||
#ifdef DISTRHO_OS_MAC | |||||
@interface FilePanelDelegate : NSObject | |||||
{ | |||||
void (*fCallback)(NSOpenPanel*, int, void*); | |||||
void* fUserData; | |||||
} | |||||
-(id)initWithCallback:(void(*)(NSOpenPanel*, int, void*))callback userData:(void*)userData; | |||||
-(void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo; | |||||
@end | |||||
@implementation FilePanelDelegate | |||||
-(id)initWithCallback:(void(*)(NSOpenPanel*, int, void*))callback userData:(void *)userData | |||||
{ | |||||
[super init]; | |||||
self->fCallback = callback; | |||||
self->fUserData = userData; | |||||
return self; | |||||
} | |||||
-(void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo | |||||
{ | |||||
self->fCallback(sheet, returnCode, self->fUserData); | |||||
(void)contextInfo; | |||||
} | |||||
@end | |||||
#endif | |||||
START_NAMESPACE_DGL | |||||
// ----------------------------------------------------------------------- | |||||
bool Window::openFileBrowser(const FileBrowserOptions& options) | |||||
{ | |||||
#if defined(DISTRHO_OS_WINDOWS) | |||||
// the old and compatible dialog API | |||||
OPENFILENAMEW ofn; | |||||
memset(&ofn, 0, sizeof(ofn)); | |||||
ofn.lStructSize = sizeof(ofn); | |||||
ofn.hwndOwner = pData->hwnd; | |||||
// set initial directory in UTF-16 coding | |||||
std::vector<WCHAR> startDirW; | |||||
if (options.startDir) | |||||
{ | |||||
startDirW.resize(strlen(options.startDir) + 1); | |||||
if (MultiByteToWideChar(CP_UTF8, 0, options.startDir, -1, startDirW.data(), startDirW.size())) | |||||
ofn.lpstrInitialDir = startDirW.data(); | |||||
} | |||||
// set title in UTF-16 coding | |||||
std::vector<WCHAR> titleW; | |||||
if (options.title) | |||||
{ | |||||
titleW.resize(strlen(options.title) + 1); | |||||
if (MultiByteToWideChar(CP_UTF8, 0, options.title, -1, titleW.data(), titleW.size())) | |||||
ofn.lpstrTitle = titleW.data(); | |||||
} | |||||
// prepare a buffer to receive the result | |||||
std::vector<WCHAR> fileNameW(32768); // the Unicode maximum | |||||
ofn.lpstrFile = fileNameW.data(); | |||||
ofn.nMaxFile = (DWORD)fileNameW.size(); | |||||
// TODO synchronous only, can't do better with WinAPI native dialogs. | |||||
// threading might work, if someone is motivated to risk it. | |||||
if (GetOpenFileNameW(&ofn)) | |||||
{ | |||||
// back to UTF-8 | |||||
std::vector<char> fileNameA(4 * 32768); | |||||
if (WideCharToMultiByte(CP_UTF8, 0, fileNameW.data(), -1, fileNameA.data(), (int)fileNameA.size(), nullptr, nullptr)) | |||||
{ | |||||
// handle it during the next idle cycle (fake async) | |||||
pData->fSelectedFile = fileNameA.data(); | |||||
} | |||||
} | |||||
return true; | |||||
#elif defined(DISTRHO_OS_MAC) | |||||
if (pData->fOpenFilePanel) // permit one dialog at most | |||||
{ | |||||
[pData->fOpenFilePanel makeKeyAndOrderFront:nil]; | |||||
return false; | |||||
} | |||||
NSOpenPanel* panel = [NSOpenPanel openPanel]; | |||||
pData->fOpenFilePanel = [panel retain]; | |||||
[panel setCanChooseFiles:YES]; | |||||
[panel setCanChooseDirectories:NO]; | |||||
[panel setAllowsMultipleSelection:NO]; | |||||
if (options.startDir) | |||||
[panel setDirectory:[NSString stringWithUTF8String:options.startDir]]; | |||||
if (options.title) | |||||
{ | |||||
NSString* titleString = [[NSString alloc] | |||||
initWithBytes:options.title | |||||
length:strlen(options.title) | |||||
encoding:NSUTF8StringEncoding]; | |||||
[panel setTitle:titleString]; | |||||
} | |||||
id delegate = pData->fFilePanelDelegate; | |||||
if (!delegate) | |||||
{ | |||||
delegate = [[FilePanelDelegate alloc] initWithCallback:&PrivateData::openPanelDidEnd | |||||
userData:pData]; | |||||
pData->fFilePanelDelegate = [delegate retain]; | |||||
} | |||||
[panel beginSheetForDirectory:nullptr | |||||
file:nullptr | |||||
modalForWindow:nullptr | |||||
modalDelegate:delegate | |||||
didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) | |||||
contextInfo:nullptr]; | |||||
return true; | |||||
#elif defined(SOFD_HAVE_X11) | |||||
using DISTRHO_NAMESPACE::String; | |||||
// -------------------------------------------------------------------------- | |||||
// configure start dir | |||||
// TODO: get abspath if needed | |||||
// TODO: cross-platform | |||||
String startDir(options.startDir); | |||||
# ifdef DISTRHO_OS_LINUX | |||||
if (startDir.isEmpty()) | |||||
{ | |||||
if (char* const dir_name = get_current_dir_name()) | |||||
{ | |||||
startDir = dir_name; | |||||
std::free(dir_name); | |||||
} | |||||
} | |||||
# endif | |||||
DISTRHO_SAFE_ASSERT_RETURN(startDir.isNotEmpty(), false); | |||||
if (! startDir.endsWith('/')) | |||||
startDir += "/"; | |||||
DISTRHO_SAFE_ASSERT_RETURN(x_fib_configure(0, startDir) == 0, false); | |||||
// -------------------------------------------------------------------------- | |||||
// configure title | |||||
String title(options.title); | |||||
if (title.isEmpty()) | |||||
{ | |||||
title = pData->getTitle(); | |||||
if (title.isEmpty()) | |||||
title = "FileBrowser"; | |||||
} | |||||
DISTRHO_SAFE_ASSERT_RETURN(x_fib_configure(1, title) == 0, false); | |||||
// -------------------------------------------------------------------------- | |||||
// configure filters | |||||
x_fib_cfg_filter_callback(nullptr); //fib_filter_filename_filter); | |||||
// -------------------------------------------------------------------------- | |||||
// configure buttons | |||||
x_fib_cfg_buttons(3, options.buttons.listAllFiles-1); | |||||
x_fib_cfg_buttons(1, options.buttons.showHidden-1); | |||||
x_fib_cfg_buttons(2, options.buttons.showPlaces-1); | |||||
// -------------------------------------------------------------------------- | |||||
// show | |||||
return (x_fib_show(pData->xDisplay, pData->xWindow, /*options.width*/0, /*options.height*/0) == 0); | |||||
#else | |||||
// not implemented | |||||
return false; | |||||
// unused | |||||
(void)options; | |||||
#endif | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DGL |
@@ -0,0 +1,296 @@ | |||||
/* | |||||
* DISTRHO Plugin Framework (DPF) | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#ifndef DGL_WINDOW_PRIVATE_DATA_HPP_INCLUDED | |||||
#define DGL_WINDOW_PRIVATE_DATA_HPP_INCLUDED | |||||
#include "../Window.hpp" | |||||
#include "../Widget.hpp" | |||||
#include "ApplicationPrivateData.hpp" | |||||
#include "pugl.hpp" | |||||
START_NAMESPACE_DGL | |||||
class TopLevelWidget; | |||||
// ----------------------------------------------------------------------- | |||||
struct Window::PrivateData : IdleCallback { | |||||
/** Reference to the DGL Application class this (private data) window associates with. */ | |||||
Application& app; | |||||
/** Direct access to the DGL Application private data where we registers ourselves in. */ | |||||
Application::PrivateData* const appData; | |||||
/** Pointer to the the DGL Window class that this private data belongs to. */ | |||||
Window* const self; | |||||
/** Pugl view instance. */ | |||||
PuglView* const view; | |||||
/** Reserved space for graphics context. */ | |||||
mutable uint8_t graphicsContext[sizeof(void*)]; | |||||
/** The top-level widget associated with this Window. */ | |||||
TopLevelWidget* topLevelWidget; | |||||
/** Whether this Window is closed (not visible or counted in the Application it is tied to). | |||||
Defaults to true unless embed (embed windows are never closed). */ | |||||
bool isClosed; | |||||
/** Whether this Window is currently visible/mapped. Defaults to false. */ | |||||
bool isVisible; | |||||
/** Whether this Window is embed into another (usually not DGL-controlled) Window. */ | |||||
const bool isEmbed; | |||||
/** Scale factor to report to widgets on request, purely informational. */ | |||||
double scaleFactor; | |||||
/** Automatic scaling to apply on widgets, implemented internally. */ | |||||
bool autoScaling; | |||||
double autoScaleFactor; | |||||
/** Pugl minWidth, minHeight access. */ | |||||
uint minWidth, minHeight; | |||||
#ifdef DISTRHO_OS_WINDOWS | |||||
/** Selected file for openFileBrowser on windows, stored for fake async operation. */ | |||||
const char* win32SelectedFile; | |||||
#endif | |||||
/** Modal window setup. */ | |||||
struct Modal { | |||||
PrivateData* parent; // parent of this window (so we can become modal) | |||||
PrivateData* child; // child window to give focus to when modal mode is enabled | |||||
bool enabled; // wherever modal mode is enabled (only possible if parent != null) | |||||
/** Constructor for a non-modal window. */ | |||||
Modal() noexcept | |||||
: parent(nullptr), | |||||
child(nullptr), | |||||
enabled(false) {} | |||||
/** Constructor for a modal window (with a parent). */ | |||||
Modal(PrivateData* const p) noexcept | |||||
: parent(p), | |||||
child(nullptr), | |||||
enabled(false) {} | |||||
/** Destructor. */ | |||||
~Modal() noexcept | |||||
{ | |||||
DISTRHO_SAFE_ASSERT(! enabled); | |||||
} | |||||
DISTRHO_DECLARE_NON_COPYABLE(Modal) | |||||
DISTRHO_PREVENT_HEAP_ALLOCATION | |||||
} modal; | |||||
/** Constructor for a regular, standalone window. */ | |||||
explicit PrivateData(Application& app, Window* self); | |||||
/** Constructor for a modal window. */ | |||||
explicit PrivateData(Application& app, Window* self, PrivateData* ppData); | |||||
/** Constructor for an embed Window, with a few extra hints from the host side. */ | |||||
explicit PrivateData(Application& app, Window* self, uintptr_t parentWindowHandle, double scaling, bool resizable); | |||||
/** Constructor for an embed Window, with a few extra hints from the host side. */ | |||||
explicit PrivateData(Application& app, Window* self, uintptr_t parentWindowHandle, | |||||
uint width, uint height, double scaling, bool resizable); | |||||
/** Destructor. */ | |||||
~PrivateData() override; | |||||
/** Helper initialization function called at the end of all this class constructors. */ | |||||
void init(uint width, uint height, bool resizable); | |||||
/** Hide window and notify application of a window close event. | |||||
* Does nothing if window is embed (that is, not standalone). | |||||
* The application event-loop will stop when all windows have been closed. | |||||
* | |||||
* @note It is possible to hide the window while not stopping the event-loop. | |||||
* A closed window is always hidden, but the reverse is not always true. | |||||
*/ | |||||
void close(); | |||||
void show(); | |||||
void hide(); | |||||
void focus(); | |||||
void setResizable(bool resizable); | |||||
const GraphicsContext& getGraphicsContext() const noexcept; | |||||
// idle callback stuff | |||||
void idleCallback() override; | |||||
bool addIdleCallback(IdleCallback* callback, uint timerFrequencyInMs); | |||||
bool removeIdleCallback(IdleCallback* callback); | |||||
// file handling | |||||
bool openFileBrowser(const Window::FileBrowserOptions& options); | |||||
// modal handling | |||||
void startModal(); | |||||
void stopModal(); | |||||
void runAsModal(bool blockWait); | |||||
// pugl events | |||||
void onPuglConfigure(double width, double height); | |||||
void onPuglExpose(); | |||||
void onPuglClose(); | |||||
void onPuglFocus(bool focus, CrossingMode mode); | |||||
void onPuglKey(const Widget::KeyboardEvent& ev); | |||||
void onPuglSpecial(const Widget::SpecialEvent& ev); | |||||
void onPuglText(const Widget::CharacterInputEvent& ev); | |||||
void onPuglMouse(const Widget::MouseEvent& ev); | |||||
void onPuglMotion(const Widget::MotionEvent& ev); | |||||
void onPuglScroll(const Widget::ScrollEvent& ev); | |||||
// Pugl event handling entry point | |||||
static PuglStatus puglEventCallback(PuglView* view, const PuglEvent* event); | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PrivateData) | |||||
}; | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DGL | |||||
#if 0 | |||||
// #if defined(DISTRHO_OS_HAIKU) | |||||
// BApplication* bApplication; | |||||
// BView* bView; | |||||
// BWindow* bWindow; | |||||
#if defined(DISTRHO_OS_MAC) | |||||
// NSView<PuglGenericView>* mView; | |||||
// id mWindow; | |||||
// id mParentWindow; | |||||
# ifndef DGL_FILE_BROWSER_DISABLED | |||||
NSOpenPanel* fOpenFilePanel; | |||||
id fFilePanelDelegate; | |||||
# endif | |||||
#elif defined(DISTRHO_OS_WINDOWS) | |||||
// HWND hwnd; | |||||
// HWND hwndParent; | |||||
# ifndef DGL_FILE_BROWSER_DISABLED | |||||
String fSelectedFile; | |||||
# endif | |||||
#endif | |||||
#endif | |||||
#if 0 | |||||
// ----------------------------------------------------------------------- | |||||
// Window Private | |||||
struct Window::PrivateData { | |||||
// ------------------------------------------------------------------- | |||||
bool handlePluginSpecial(const bool press, const Key key) | |||||
{ | |||||
DBGp("PUGL: handlePluginSpecial : %i %i\n", press, key); | |||||
if (fModal.childFocus != nullptr) | |||||
{ | |||||
fModal.childFocus->focus(); | |||||
return true; | |||||
} | |||||
int mods = 0x0; | |||||
switch (key) | |||||
{ | |||||
case kKeyShift: | |||||
mods |= kModifierShift; | |||||
break; | |||||
case kKeyControl: | |||||
mods |= kModifierControl; | |||||
break; | |||||
case kKeyAlt: | |||||
mods |= kModifierAlt; | |||||
break; | |||||
default: | |||||
break; | |||||
} | |||||
if (mods != 0x0) | |||||
{ | |||||
if (press) | |||||
fView->mods |= mods; | |||||
else | |||||
fView->mods &= ~(mods); | |||||
} | |||||
Widget::SpecialEvent ev; | |||||
ev.press = press; | |||||
ev.key = key; | |||||
ev.mod = static_cast<Modifier>(fView->mods); | |||||
ev.time = 0; | |||||
FOR_EACH_WIDGET_INV(rit) | |||||
{ | |||||
Widget* const widget(*rit); | |||||
if (widget->isVisible() && widget->onSpecial(ev)) | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
#if defined(DISTRHO_OS_MAC) && !defined(DGL_FILE_BROWSER_DISABLED) | |||||
static void openPanelDidEnd(NSOpenPanel* panel, int returnCode, void *userData) | |||||
{ | |||||
PrivateData* pData = (PrivateData*)userData; | |||||
if (returnCode == NSOKButton) | |||||
{ | |||||
NSArray* urls = [panel URLs]; | |||||
NSURL* fileUrl = nullptr; | |||||
for (NSUInteger i = 0, n = [urls count]; i < n && !fileUrl; ++i) | |||||
{ | |||||
NSURL* url = (NSURL*)[urls objectAtIndex:i]; | |||||
if ([url isFileURL]) | |||||
fileUrl = url; | |||||
} | |||||
if (fileUrl) | |||||
{ | |||||
PuglView* view = pData->fView; | |||||
if (view->fileSelectedFunc) | |||||
{ | |||||
const char* fileName = [fileUrl.path UTF8String]; | |||||
view->fileSelectedFunc(view, fileName); | |||||
} | |||||
} | |||||
} | |||||
[pData->fOpenFilePanel release]; | |||||
pData->fOpenFilePanel = nullptr; | |||||
} | |||||
#endif | |||||
// ------------------------------------------------------------------- | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PrivateData) | |||||
}; | |||||
#endif | |||||
#endif // DGL_WINDOW_PRIVATE_DATA_HPP_INCLUDED |
@@ -0,0 +1,29 @@ | |||||
/* | |||||
Copyright (C) 2012-2020 Filipe Coelho <falktx@falktx.com> | |||||
Permission to use, copy, modify, and/or distribute this software for any | |||||
purpose with or without fee is hereby granted, provided that the above | |||||
copyright notice and this permission notice appear in all copies. | |||||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
/** | |||||
@file extras.c pugl extra implementations for DPF. | |||||
*/ | |||||
#include "extras.h" | |||||
#include "../pugl-upstream/src/implementation.h" | |||||
const char* | |||||
puglGetWindowTitle(const PuglView* view) | |||||
{ | |||||
return view->title; | |||||
} |
@@ -0,0 +1,50 @@ | |||||
/* | |||||
Copyright (C) 2012-2020 Filipe Coelho <falktx@falktx.com> | |||||
Permission to use, copy, modify, and/or distribute this software for any | |||||
purpose with or without fee is hereby granted, provided that the above | |||||
copyright notice and this permission notice appear in all copies. | |||||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
/** | |||||
@file pugl.h pugl extra API for DPF. | |||||
*/ | |||||
#ifndef PUGL_EXTRAS_PUGL_H | |||||
#define PUGL_EXTRAS_PUGL_H | |||||
#include "../pugl-upstream/include/pugl/pugl.h" | |||||
PUGL_BEGIN_DECLS | |||||
PUGL_API const char* | |||||
puglGetWindowTitle(const PuglView* view); | |||||
PUGL_API int | |||||
puglGetViewHint(const PuglView* view, PuglViewHint hint); | |||||
PUGL_API void | |||||
puglRaiseWindow(PuglView* view); | |||||
PUGL_API void | |||||
puglSetWindowSize(PuglView* view, unsigned int width, unsigned int height); | |||||
PUGL_API void | |||||
puglUpdateGeometryConstraints(PuglView* view, unsigned int width, unsigned int height, bool aspect); | |||||
#ifdef DISTRHO_OS_WINDOWS | |||||
PUGL_API void | |||||
puglWin32SetWindowResizable(PuglView* view, bool resizable); | |||||
#endif | |||||
PUGL_END_DECLS | |||||
#endif // PUGL_EXTRAS_PUGL_H |
@@ -0,0 +1,81 @@ | |||||
/* | |||||
Copyright 2012-2019 David Robillard <http://drobilla.net> | |||||
Copyright 2019-2020 Filipe Coelho <falktx@falktx.com> | |||||
Permission to use, copy, modify, and/or distribute this software for any | |||||
purpose with or without fee is hereby granted, provided that the above | |||||
copyright notice and this permission notice appear in all copies. | |||||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
/** | |||||
@file mac.cpp HaikuOS implementation. | |||||
*/ | |||||
#include "haiku.h" | |||||
#include "pugl/detail/implementation.h" | |||||
PuglStatus | |||||
puglGrabFocus(PuglView* view) | |||||
{ | |||||
view->impl->bView->MakeFocus(true); | |||||
return PUGL_SUCCESS; | |||||
} | |||||
// extras follow | |||||
void | |||||
puglRaiseWindow(PuglView* view) | |||||
{ | |||||
} | |||||
void | |||||
puglSetWindowSize(PuglView* view, unsigned int width, unsigned int height) | |||||
{ | |||||
bView->ResizeTo(width, height); | |||||
if (bWindow != nullptr && bWindow->LockLooper()) | |||||
{ | |||||
bWindow->MoveTo(50, 50); | |||||
bWindow->ResizeTo(width, height); | |||||
if (! forced) | |||||
bWindow->Flush(); | |||||
bWindow->UnlockLooper(); | |||||
} | |||||
// TODO resizable | |||||
} | |||||
void setVisible(const bool yesNo) | |||||
{ | |||||
if (bWindow != nullptr) | |||||
{ | |||||
if (bWindow->LockLooper()) | |||||
{ | |||||
if (yesNo) | |||||
bWindow->Show(); | |||||
else | |||||
bWindow->Hide(); | |||||
// TODO use flush? | |||||
bWindow->Sync(); | |||||
bWindow->UnlockLooper(); | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
if (yesNo) | |||||
bView->Show(); | |||||
else | |||||
bView->Hide(); | |||||
} | |||||
} |
@@ -0,0 +1,35 @@ | |||||
/* | |||||
Copyright 2012-2019 David Robillard <http://drobilla.net> | |||||
Copyright 2019-2020 Filipe Coelho <falktx@falktx.com> | |||||
Permission to use, copy, modify, and/or distribute this software for any | |||||
purpose with or without fee is hereby granted, provided that the above | |||||
copyright notice and this permission notice appear in all copies. | |||||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
/** | |||||
@file haiku.h Shared definitions for HaikuOS implementation. | |||||
*/ | |||||
#include "pugl/pugl.h" | |||||
#include <Application.h> | |||||
#include <Window.h> | |||||
// using? interface/ | |||||
struct PuglWorldInternalsImpl { | |||||
BApplication* app; | |||||
}; | |||||
struct PuglInternalsImpl { | |||||
BViewType* view; | |||||
BWindow* window; | |||||
}; |
@@ -0,0 +1,48 @@ | |||||
/* | |||||
Copyright (C) 2012-2020 Filipe Coelho <falktx@falktx.com> | |||||
Permission to use, copy, modify, and/or distribute this software for any | |||||
purpose with or without fee is hereby granted, provided that the above | |||||
copyright notice and this permission notice appear in all copies. | |||||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
/** | |||||
@file mac.m MacOS extra implementation for DPF. | |||||
*/ | |||||
#include "pugl/detail/mac.h" | |||||
void | |||||
puglRaiseWindow(PuglView* view) | |||||
{ | |||||
} | |||||
void | |||||
puglSetWindowSize(PuglView* view, unsigned int width, unsigned int height) | |||||
{ | |||||
// NOTE: pugl mac code does nothing with x and y | |||||
const PuglRect frame = { 0.0, 0.0, (double)width, (double)height }; | |||||
puglSetFrame(view, frame); | |||||
} | |||||
void | |||||
puglUpdateGeometryConstraints(PuglView* view, unsigned int width, unsigned int height, bool aspect) | |||||
{ | |||||
// NOTE this is a combination of puglSetMinSize and puglSetAspectRatio | |||||
view->minWidth = width; | |||||
view->minHeight = height; | |||||
[view->impl->window setContentMinSize:sizePoints(view, width, height)]; | |||||
if (aspect) { | |||||
[view->impl->window setContentAspectRatio:sizePoints(view, width, height)]; | |||||
} | |||||
} |
@@ -0,0 +1,118 @@ | |||||
/* | |||||
Copyright (C) 2012-2020 Filipe Coelho <falktx@falktx.com> | |||||
Permission to use, copy, modify, and/or distribute this software for any | |||||
purpose with or without fee is hereby granted, provided that the above | |||||
copyright notice and this permission notice appear in all copies. | |||||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
/** | |||||
@file win.c Windows extra implementation for DPF. | |||||
*/ | |||||
#include "pugl/detail/win.h" | |||||
#include "pugl/detail/implementation.h" | |||||
void | |||||
puglRaiseWindow(PuglView* view) | |||||
{ | |||||
SetForegroundWindow(view->impl->hwnd); | |||||
SetActiveWindow(view->impl->hwnd); | |||||
return PUGL_SUCCESS; | |||||
} | |||||
void | |||||
puglSetWindowSize(PuglView* view, unsigned int width, unsigned int height) | |||||
{ | |||||
view->frame.width = width; | |||||
view->frame.height = height; | |||||
// NOTE the following code matches upstream pugl, except we add SWP_NOMOVE flag | |||||
if (view->impl->hwnd) { | |||||
RECT rect = { (long)frame.x, | |||||
(long)frame.y, | |||||
(long)frame.x + (long)frame.width, | |||||
(long)frame.y + (long)frame.height }; | |||||
AdjustWindowRectEx(&rect, puglWinGetWindowFlags(view), | |||||
FALSE, | |||||
puglWinGetWindowExFlags(view)); | |||||
SetWindowPos(view->impl->hwnd, | |||||
HWND_TOP, | |||||
rect.left, | |||||
rect.top, | |||||
rect.right - rect.left, | |||||
rect.bottom - rect.top, | |||||
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER); | |||||
} | |||||
} | |||||
void | |||||
puglUpdateGeometryConstraints(PuglView* view, unsigned int width, unsigned int height, bool aspect) | |||||
{ | |||||
// NOTE this is a combination of puglSetMinSize and puglSetAspectRatio, but stilL TODO on pugl | |||||
Display* display = view->world->impl->display; | |||||
view->minWidth = width; | |||||
view->minHeight = height; | |||||
if (aspect) { | |||||
view->minAspectX = width; | |||||
view->minAspectY = height; | |||||
view->maxAspectX = width; | |||||
view->maxAspectY = height; | |||||
} | |||||
} | |||||
void | |||||
puglWin32RestoreWindow(PuglView* view) | |||||
{ | |||||
PuglInternals* impl = view->impl; | |||||
ShowWindow(impl->hwnd, SW_RESTORE); | |||||
SetFocus(impl->hwnd); | |||||
} | |||||
void | |||||
puglWin32ShowWindowCentered(PuglView* view) | |||||
{ | |||||
PuglInternals* impl = view->impl; | |||||
RECT rectChild, rectParent; | |||||
if (impl->transientParent != 0 && | |||||
GetWindowRect(impl->hwnd, &rectChild) && | |||||
GetWindowRect(impl->transientParent, &rectParent)) | |||||
{ | |||||
SetWindowPos(impl->hwnd, (HWND)impl->transientParent, | |||||
rectParent.left + (rectChild.right-rectChild.left)/2, | |||||
rectParent.top + (rectChild.bottom-rectChild.top)/2, | |||||
0, 0, SWP_SHOWWINDOW|SWP_NOSIZE); | |||||
} | |||||
else | |||||
{ | |||||
ShowWindow(hwnd, SW_SHOWNORMAL); | |||||
} | |||||
SetFocus(impl->hwnd); | |||||
} | |||||
void | |||||
puglWin32SetWindowResizable(PuglView* view, bool resizable) | |||||
{ | |||||
PuglInternals* impl = view->impl; | |||||
const int winFlags = resizable ? GetWindowLong(hwnd, GWL_STYLE) | WS_SIZEBOX | |||||
: GetWindowLong(hwnd, GWL_STYLE) & ~WS_SIZEBOX; | |||||
SetWindowLong(impl->hwnd, GWL_STYLE, winFlags); | |||||
} |
@@ -0,0 +1,111 @@ | |||||
/* | |||||
Copyright (C) 2012-2020 Filipe Coelho <falktx@falktx.com> | |||||
Permission to use, copy, modify, and/or distribute this software for any | |||||
purpose with or without fee is hereby granted, provided that the above | |||||
copyright notice and this permission notice appear in all copies. | |||||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
/** | |||||
@file x11.c X11 extra implementation for DPF. | |||||
*/ | |||||
// NOTE can't import this file twice! | |||||
#ifndef PUGL_DETAIL_X11_H_INCLUDED | |||||
#include "../pugl-upstream/src/x11.h" | |||||
#endif | |||||
#include "../pugl-upstream/src/implementation.h" | |||||
#include <sys/types.h> | |||||
#include <unistd.h> | |||||
void | |||||
puglRaiseWindow(PuglView* view) | |||||
{ | |||||
XRaiseWindow(view->impl->display, view->impl->win); | |||||
} | |||||
void | |||||
puglSetWindowSize(PuglView* view, unsigned int width, unsigned int height) | |||||
{ | |||||
view->frame.width = width; | |||||
view->frame.height = height; | |||||
if (view->impl->win) { | |||||
#if 0 | |||||
if (! fResizable) | |||||
{ | |||||
XSizeHints sizeHints; | |||||
memset(&sizeHints, 0, sizeof(sizeHints)); | |||||
sizeHints.flags = PSize|PMinSize|PMaxSize; | |||||
sizeHints.width = static_cast<int>(width); | |||||
sizeHints.height = static_cast<int>(height); | |||||
sizeHints.min_width = static_cast<int>(width); | |||||
sizeHints.min_height = static_cast<int>(height); | |||||
sizeHints.max_width = static_cast<int>(width); | |||||
sizeHints.max_height = static_cast<int>(height); | |||||
XSetWMNormalHints(xDisplay, xWindow, &sizeHints); | |||||
} | |||||
#endif | |||||
XResizeWindow(view->world->impl->display, view->impl->win, width, height); | |||||
} | |||||
} | |||||
void | |||||
puglUpdateGeometryConstraints(PuglView* view, unsigned int width, unsigned int height, bool aspect) | |||||
{ | |||||
// NOTE this is a combination of puglSetMinSize and puglSetAspectRatio | |||||
Display* display = view->world->impl->display; | |||||
view->minWidth = width; | |||||
view->minHeight = height; | |||||
if (aspect) { | |||||
view->minAspectX = width; | |||||
view->minAspectY = height; | |||||
view->maxAspectX = width; | |||||
view->maxAspectY = height; | |||||
} | |||||
#if 0 | |||||
if (view->impl->win) { | |||||
XSizeHints sizeHints = getSizeHints(view); | |||||
XSetNormalHints(display, view->impl->win, &sizeHints); | |||||
// NOTE old code used this instead | |||||
// XSetWMNormalHints(display, view->impl->win, &sizeHints); | |||||
} | |||||
#endif | |||||
} | |||||
void | |||||
puglExtraSetWindowTypeAndPID(PuglView* view) | |||||
{ | |||||
PuglInternals* const impl = view->impl; | |||||
const pid_t pid = getpid(); | |||||
const Atom _nwp = XInternAtom(impl->display, "_NET_WM_PID", False); | |||||
XChangeProperty(impl->display, impl->win, _nwp, XA_CARDINAL, 32, PropModeReplace, (const uchar*)&pid, 1); | |||||
const Atom _wt = XInternAtom(impl->display, "_NET_WM_WINDOW_TYPE", False); | |||||
// Setting the window to both dialog and normal will produce a decorated floating dialog | |||||
// Order is important: DIALOG needs to come before NORMAL | |||||
const Atom _wts[2] = { | |||||
XInternAtom(impl->display, "_NET_WM_WINDOW_TYPE_DIALOG", False), | |||||
XInternAtom(impl->display, "_NET_WM_WINDOW_TYPE_NORMAL", False) | |||||
}; | |||||
XChangeProperty(impl->display, impl->win, _wt, XA_ATOM, 32, PropModeReplace, (const uchar*)&_wts, 2); | |||||
} |
@@ -0,0 +1 @@ | |||||
Subproject commit c5a5eb4cdcb12dc8d74be4f5fbb335e8b3eac711 |
@@ -0,0 +1,458 @@ | |||||
/* | |||||
* DISTRHO Plugin Framework (DPF) | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#include "pugl.hpp" | |||||
/* we will include all header files used in pugl in their C++ friendly form, then pugl stuff in custom namespace */ | |||||
#include <cassert> | |||||
#include <cmath> | |||||
#include <cstdlib> | |||||
#include <cstring> | |||||
#include <ctime> | |||||
#if defined(DISTRHO_OS_HAIKU) | |||||
#elif defined(DISTRHO_OS_MAC) | |||||
# import <Cocoa/Cocoa.h> | |||||
# include <dlfcn.h> | |||||
# include <mach/mach_time.h> | |||||
# ifdef DGL_CAIRO | |||||
# include <cairo.h> | |||||
# include <cairo-quartz.h> | |||||
# endif | |||||
# ifdef DGL_OPENGL | |||||
# include <OpenGL/gl.h> | |||||
# endif | |||||
# ifdef DGL_VULKAN | |||||
# import <QuartzCore/CAMetalLayer.h> | |||||
# include <vulkan/vulkan_core.h> | |||||
# include <vulkan/vulkan_macos.h> | |||||
# endif | |||||
#elif defined(DISTRHO_OS_WINDOWS) | |||||
# include <wctype.h> | |||||
# include <windows.h> | |||||
# include <windowsx.h> | |||||
# ifdef DGL_CAIRO | |||||
# include <cairo.h> | |||||
# include <cairo-win32.h> | |||||
# endif | |||||
# ifdef DGL_OPENGL | |||||
# include <GL/gl.h> | |||||
# endif | |||||
# ifdef DGL_VULKAN | |||||
# include <vulkan/vulkan.h> | |||||
# include <vulkan/vulkan_win32.h> | |||||
# endif | |||||
#else | |||||
# include <dlfcn.h> | |||||
# include <sys/select.h> | |||||
# include <sys/time.h> | |||||
# include <X11/X.h> | |||||
# include <X11/Xatom.h> | |||||
# include <X11/Xlib.h> | |||||
# include <X11/Xutil.h> | |||||
# include <X11/keysym.h> | |||||
# ifdef HAVE_XCURSOR | |||||
# include <X11/Xcursor/Xcursor.h> | |||||
# include <X11/cursorfont.h> | |||||
# endif | |||||
# ifdef HAVE_XRANDR | |||||
# include <X11/extensions/Xrandr.h> | |||||
# endif | |||||
# ifdef HAVE_XSYNC | |||||
# include <X11/extensions/sync.h> | |||||
# include <X11/extensions/syncconst.h> | |||||
# endif | |||||
# ifdef DGL_CAIRO | |||||
# include <cairo.h> | |||||
# include <cairo-xlib.h> | |||||
# endif | |||||
# ifdef DGL_OPENGL | |||||
# include <GL/gl.h> | |||||
# include <GL/glx.h> | |||||
# endif | |||||
# ifdef DGL_VULKAN | |||||
# include <vulkan/vulkan_core.h> | |||||
# include <vulkan/vulkan_xlib.h> | |||||
# endif | |||||
#endif | |||||
#ifdef HAVE_X11 | |||||
# define DBLCLKTME 400 | |||||
# include "sofd/libsofd.h" | |||||
# include "sofd/libsofd.c" | |||||
#endif | |||||
#ifndef DISTRHO_OS_MAC | |||||
START_NAMESPACE_DGL | |||||
#endif | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
#if defined(DISTRHO_OS_HAIKU) | |||||
#elif defined(DISTRHO_OS_MAC) | |||||
# ifndef DISTRHO_MACOS_NAMESPACE_MACRO | |||||
# define DISTRHO_MACOS_NAMESPACE_MACRO_HELPER(NS, SEP, INTERFACE) NS ## SEP ## INTERFACE | |||||
# define DISTRHO_MACOS_NAMESPACE_MACRO(NS, INTERFACE) DISTRHO_MACOS_NAMESPACE_MACRO_HELPER(NS, _, INTERFACE) | |||||
# define PuglStubView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PuglStubView) | |||||
# define PuglWrapperView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PuglWrapperView) | |||||
# define PuglWindow DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PuglWindow) | |||||
# endif | |||||
# import "pugl-upstream/src/mac.m" | |||||
# import "pugl-upstream/src/mac_stub.m" | |||||
# ifdef DGL_CAIRO | |||||
# import "pugl-upstream/src/mac_cairo.m" | |||||
# endif | |||||
# ifdef DGL_OPENGL | |||||
# import "pugl-upstream/src/mac_gl.m" | |||||
# endif | |||||
# ifdef DGL_VULKAN | |||||
# import "pugl-upstream/src/mac_vulkan.m" | |||||
# endif | |||||
#elif defined(DISTRHO_OS_WINDOWS) | |||||
# include "pugl-upstream/src/win.c" | |||||
# include "pugl-upstream/src/win_stub.c" | |||||
# ifdef DGL_CAIRO | |||||
# include "pugl-upstream/src/win_cairo.c" | |||||
# endif | |||||
# ifdef DGL_OPENGL | |||||
# include "pugl-upstream/src/win_gl.c" | |||||
# endif | |||||
# ifdef DGL_VULKAN | |||||
# include "pugl-upstream/src/win_vulkan.c" | |||||
# endif | |||||
#else | |||||
# include "pugl-upstream/src/x11.c" | |||||
# include "pugl-upstream/src/x11_stub.c" | |||||
# ifdef DGL_CAIRO | |||||
# include "pugl-upstream/src/x11_cairo.c" | |||||
# endif | |||||
# ifdef DGL_OPENGL | |||||
# include "pugl-upstream/src/x11_gl.c" | |||||
# endif | |||||
# ifdef DGL_VULKAN | |||||
# include "pugl-upstream/src/x11_vulkan.c" | |||||
# endif | |||||
#endif | |||||
#include "pugl-upstream/src/implementation.c" | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// expose backend enter | |||||
void puglBackendEnter(PuglView* view) | |||||
{ | |||||
view->backend->enter(view, NULL); | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// missing in pugl, directly returns title char* pointer | |||||
const char* puglGetWindowTitle(const PuglView* view) | |||||
{ | |||||
return view->title; | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// bring view window into the foreground, aka "raise" window | |||||
void puglRaiseWindow(PuglView* view) | |||||
{ | |||||
#if defined(DISTRHO_OS_HAIKU) || defined(DISTRHO_OS_MAC) | |||||
// nothing here yet | |||||
#elif defined(DISTRHO_OS_WINDOWS) | |||||
SetForegroundWindow(view->impl->hwnd); | |||||
SetActiveWindow(view->impl->hwnd); | |||||
#else | |||||
XRaiseWindow(view->impl->display, view->impl->win); | |||||
#endif | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// set backend that matches current build | |||||
void puglSetMatchingBackendForCurrentBuild(PuglView* const view) | |||||
{ | |||||
#ifdef DGL_CAIRO | |||||
puglSetBackend(view, puglCairoBackend()); | |||||
#endif | |||||
#ifdef DGL_OPENGL | |||||
puglSetBackend(view, puglGlBackend()); | |||||
#endif | |||||
#ifdef DGL_VULKAN | |||||
puglSetBackend(view, puglVulkanBackend()); | |||||
#endif | |||||
if (view->backend == nullptr) | |||||
puglSetBackend(view, puglStubBackend()); | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// Combine puglSetMinSize and puglSetAspectRatio | |||||
PuglStatus puglSetGeometryConstraints(PuglView* const view, const uint width, const uint height, const bool aspect) | |||||
{ | |||||
view->minWidth = (int)width; | |||||
view->minHeight = (int)height; | |||||
if (aspect) { | |||||
view->minAspectX = (int)width; | |||||
view->minAspectY = (int)height; | |||||
view->maxAspectX = (int)width; | |||||
view->maxAspectY = (int)height; | |||||
} | |||||
#if defined(DISTRHO_OS_HAIKU) | |||||
// nothing? | |||||
#elif defined(DISTRHO_OS_MAC) | |||||
/* | |||||
if (view->impl->window) | |||||
{ | |||||
[view->impl->window setContentMinSize:sizePoints(view, view->minWidth, view->minHeight)]; | |||||
if (aspect) | |||||
[view->impl->window setContentAspectRatio:sizePoints(view, view->minAspectX, view->minAspectY)]; | |||||
} | |||||
*/ | |||||
puglSetMinSize(view, width, height); | |||||
puglSetAspectRatio(view, width, height, width, height); | |||||
#elif defined(DISTRHO_OS_WINDOWS) | |||||
// nothing | |||||
#else | |||||
return updateSizeHints(view); | |||||
#endif | |||||
return PUGL_SUCCESS; | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// set window size without changing frame x/y position | |||||
PuglStatus puglSetWindowSize(PuglView* const view, const uint width, const uint height) | |||||
{ | |||||
#if defined(DISTRHO_OS_HAIKU) || defined(DISTRHO_OS_MAC) | |||||
// keep upstream behaviour | |||||
const PuglRect frame = { view->frame.x, view->frame.y, (double)width, (double)height }; | |||||
return puglSetFrame(view, frame); | |||||
#elif defined(DISTRHO_OS_WINDOWS) | |||||
// matches upstream pugl, except we add SWP_NOMOVE flag | |||||
if (view->impl->hwnd) | |||||
{ | |||||
const PuglRect frame = view->frame; | |||||
RECT rect = { (long)frame.x, | |||||
(long)frame.y, | |||||
(long)frame.x + (long)frame.width, | |||||
(long)frame.y + (long)frame.height }; | |||||
AdjustWindowRectEx(&rect, puglWinGetWindowFlags(view), FALSE, puglWinGetWindowExFlags(view)); | |||||
if (! SetWindowPos(view->impl->hwnd, | |||||
HWND_TOP, | |||||
rect.left, | |||||
rect.top, | |||||
rect.right - rect.left, | |||||
rect.bottom - rect.top, | |||||
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER)) | |||||
return PUGL_UNKNOWN_ERROR; | |||||
} | |||||
#else | |||||
// matches upstream pugl, except we use XResizeWindow instead of XMoveResizeWindow | |||||
if (view->impl->win) | |||||
{ | |||||
if (! XResizeWindow(view->world->impl->display, view->impl->win, width, height)) | |||||
return PUGL_UNKNOWN_ERROR; | |||||
} | |||||
#endif | |||||
view->frame.width = width; | |||||
view->frame.height = height; | |||||
return PUGL_SUCCESS; | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// DGL specific, build-specific drawing prepare | |||||
void puglOnDisplayPrepare(PuglView*) | |||||
{ | |||||
#ifdef DGL_OPENGL | |||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |||||
glLoadIdentity(); | |||||
#endif | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// DGL specific, build-specific fallback resize | |||||
void puglFallbackOnResize(PuglView* const view) | |||||
{ | |||||
#ifdef DGL_OPENGL | |||||
glEnable(GL_BLEND); | |||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |||||
glMatrixMode(GL_PROJECTION); | |||||
glLoadIdentity(); | |||||
glOrtho(0.0, static_cast<GLdouble>(view->frame.width), static_cast<GLdouble>(view->frame.height), 0.0, 0.0, 1.0); | |||||
glViewport(0, 0, static_cast<GLsizei>(view->frame.width), static_cast<GLsizei>(view->frame.height)); | |||||
glMatrixMode(GL_MODELVIEW); | |||||
glLoadIdentity(); | |||||
#endif | |||||
} | |||||
#ifdef DISTRHO_OS_WINDOWS | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// win32 specific, call ShowWindow with SW_RESTORE | |||||
void puglWin32RestoreWindow(PuglView* const view) | |||||
{ | |||||
PuglInternals* impl = view->impl; | |||||
DISTRHO_SAFE_ASSERT_RETURN(impl->hwnd != nullptr,); | |||||
ShowWindow(impl->hwnd, SW_RESTORE); | |||||
SetFocus(impl->hwnd); | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// win32 specific, center view based on parent coordinates (if there is one) | |||||
void puglWin32ShowWindowCentered(PuglView* const view) | |||||
{ | |||||
PuglInternals* impl = view->impl; | |||||
DISTRHO_SAFE_ASSERT_RETURN(impl->hwnd != nullptr,); | |||||
RECT rectChild, rectParent; | |||||
if (view->transientParent != 0 && | |||||
GetWindowRect(impl->hwnd, &rectChild) && | |||||
GetWindowRect((HWND)view->transientParent, &rectParent)) | |||||
{ | |||||
SetWindowPos(impl->hwnd, (HWND)view->transientParent, | |||||
rectParent.left + (rectChild.right-rectChild.left)/2, | |||||
rectParent.top + (rectChild.bottom-rectChild.top)/2, | |||||
0, 0, SWP_SHOWWINDOW|SWP_NOSIZE); | |||||
} | |||||
else | |||||
{ | |||||
ShowWindow(impl->hwnd, SW_SHOWNORMAL); | |||||
} | |||||
SetFocus(impl->hwnd); | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// win32 specific, set or unset WS_SIZEBOX style flag | |||||
void puglWin32SetWindowResizable(PuglView* const view, const bool resizable) | |||||
{ | |||||
PuglInternals* impl = view->impl; | |||||
DISTRHO_SAFE_ASSERT_RETURN(impl->hwnd != nullptr,); | |||||
const int winFlags = resizable ? GetWindowLong(impl->hwnd, GWL_STYLE) | WS_SIZEBOX | |||||
: GetWindowLong(impl->hwnd, GWL_STYLE) & ~WS_SIZEBOX; | |||||
SetWindowLong(impl->hwnd, GWL_STYLE, winFlags); | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
#endif | |||||
#ifdef HAVE_X11 | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// X11 specific, setup event loop filter for sofd file dialog | |||||
static bool sofd_has_action; | |||||
static char* sofd_filename; | |||||
static bool sofd_event_filter(Display* const display, XEvent* const xevent) | |||||
{ | |||||
if (x_fib_handle_events(display, xevent) == 0) | |||||
return false; | |||||
if (sofd_filename != nullptr) | |||||
std::free(sofd_filename); | |||||
if (x_fib_status() > 0) | |||||
sofd_filename = x_fib_filename(); | |||||
else | |||||
sofd_filename = nullptr; | |||||
x_fib_close(display); | |||||
sofd_has_action = true; | |||||
return true; | |||||
} | |||||
void sofdFileDialogSetup(PuglWorld* const world) | |||||
{ | |||||
puglX11SetEventFilter(world, sofd_event_filter); | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// X11 specific, show file dialog via sofd | |||||
bool sofdFileDialogShow(PuglView* const view, | |||||
const char* const startDir, const char* const title, | |||||
const uint flags, const uint width, const uint height) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(x_fib_configure(0, startDir) == 0, false); | |||||
DISTRHO_SAFE_ASSERT_RETURN(x_fib_configure(1, title) == 0, false); | |||||
/* | |||||
x_fib_cfg_buttons(3, options.buttons.listAllFiles-1); | |||||
x_fib_cfg_buttons(1, options.buttons.showHidden-1); | |||||
x_fib_cfg_buttons(2, options.buttons.showPlaces-1); | |||||
*/ | |||||
PuglInternals* const impl = view->impl; | |||||
return (x_fib_show(impl->display, impl->win, width, height) == 0); | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// X11 specific, close sofd file dialog | |||||
void sofdFileDialogClose(PuglView* const view) | |||||
{ | |||||
PuglInternals* const impl = view->impl; | |||||
x_fib_close(impl->display); | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// X11 specific, get path chosen via sofd file dialog | |||||
bool sofdFileDialogGetPath(char** path) | |||||
{ | |||||
if (! sofd_has_action) | |||||
return false; | |||||
sofd_has_action = false; | |||||
*path = sofd_filename; | |||||
return true; | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// X11 specific, free path of sofd file dialog, no longer needed | |||||
void sofdFileDialogFree(char* const path) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(path == nullptr || path == sofd_filename,); | |||||
std::free(sofd_filename); | |||||
sofd_filename = nullptr; | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
#endif | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
#ifndef DISTRHO_OS_MAC | |||||
END_NAMESPACE_DGL | |||||
#endif |
@@ -0,0 +1,121 @@ | |||||
/* | |||||
* DISTRHO Plugin Framework (DPF) | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#ifndef DGL_PUGL_HPP_INCLUDED | |||||
#define DGL_PUGL_HPP_INCLUDED | |||||
#include "../Base.hpp" | |||||
/* we will include all header files used in pugl in their C++ friendly form, then pugl stuff in custom namespace */ | |||||
#include <cstdbool> | |||||
#include <cstddef> | |||||
#include <cstdint> | |||||
#define PUGL_API | |||||
#define PUGL_DISABLE_DEPRECATED | |||||
#define PUGL_NO_INCLUDE_GLU_H | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
#ifndef DISTRHO_OS_MAC | |||||
START_NAMESPACE_DGL | |||||
#else | |||||
USE_NAMESPACE_DGL | |||||
#endif | |||||
#include "pugl-upstream/include/pugl/pugl.h" | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
PUGL_BEGIN_DECLS | |||||
// expose backend enter | |||||
PUGL_API void | |||||
puglBackendEnter(PuglView* view); | |||||
// missing in pugl, directly returns title char* pointer | |||||
PUGL_API const char* | |||||
puglGetWindowTitle(const PuglView* view); | |||||
// bring view window into the foreground, aka "raise" window | |||||
PUGL_API void | |||||
puglRaiseWindow(PuglView* view); | |||||
// DGL specific, assigns backend that matches current DGL build | |||||
PUGL_API void | |||||
puglSetMatchingBackendForCurrentBuild(PuglView* view); | |||||
// Combine puglSetMinSize and puglSetAspectRatio | |||||
PUGL_API PuglStatus | |||||
puglSetGeometryConstraints(PuglView* view, unsigned int width, unsigned int height, bool aspect); | |||||
// set window size without changing frame x/y position | |||||
PUGL_API PuglStatus | |||||
puglSetWindowSize(PuglView* view, unsigned int width, unsigned int height); | |||||
// DGL specific, build-specific drawing prepare | |||||
PUGL_API void | |||||
puglOnDisplayPrepare(PuglView* view); | |||||
// DGL specific, build-specific fallback resize | |||||
PUGL_API void | |||||
puglFallbackOnResize(PuglView* view); | |||||
#ifdef DISTRHO_OS_WINDOWS | |||||
// win32 specific, call ShowWindow with SW_RESTORE | |||||
PUGL_API void | |||||
puglWin32RestoreWindow(PuglView* view); | |||||
// win32 specific, center view based on parent coordinates (if there is one) | |||||
PUGL_API void | |||||
puglWin32ShowWindowCentered(PuglView* view); | |||||
// win32 specific, set or unset WS_SIZEBOX style flag | |||||
PUGL_API void | |||||
puglWin32SetWindowResizable(PuglView* view, bool resizable); | |||||
#endif | |||||
#ifdef HAVE_X11 | |||||
// X11 specific, setup event loop filter for sofd file dialog | |||||
PUGL_API void | |||||
sofdFileDialogSetup(PuglWorld* world); | |||||
// X11 specific, show file dialog via sofd | |||||
PUGL_API bool | |||||
sofdFileDialogShow(PuglView* view, const char* startDir, const char* title, uint flags, uint width, uint height); | |||||
// X11 specific, close sofd file dialog | |||||
PUGL_API void | |||||
sofdFileDialogClose(PuglView* view); | |||||
// X11 specific, get path chosen via sofd file dialog | |||||
PUGL_API bool | |||||
sofdFileDialogGetPath(char** path); | |||||
// X11 specific, free path of sofd file dialog, no longer needed | |||||
PUGL_API void | |||||
sofdFileDialogFree(char* path); | |||||
#endif | |||||
PUGL_END_DECLS | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
#ifndef DISTRHO_OS_MAC | |||||
END_NAMESPACE_DGL | |||||
#endif | |||||
#endif // DGL_PUGL_HPP_INCLUDED |
@@ -0,0 +1 @@ | |||||
pugl.cpp |
@@ -32,7 +32,7 @@ | |||||
*/ | */ | ||||
#ifdef SOFD_TEST | #ifdef SOFD_TEST | ||||
#define SOFD_HAVE_X11 | |||||
#define HAVE_X11 | |||||
#include "libsofd.h" | #include "libsofd.h" | ||||
#endif | #endif | ||||
@@ -337,7 +337,7 @@ const char *x_fib_recent_file(const char *appname) { | |||||
return NULL; | return NULL; | ||||
} | } | ||||
#ifdef SOFD_HAVE_X11 | |||||
#ifdef HAVE_X11 | |||||
#include <mntent.h> | #include <mntent.h> | ||||
#include <dirent.h> | #include <dirent.h> | ||||
@@ -475,7 +475,10 @@ static int (*_fib_filter_function)(const char *filename); | |||||
#define FAREATEXTL (FAREAMRGL + TEXTSEP) //px; filename text-left FAREAMRGL + TEXTSEP | #define FAREATEXTL (FAREAMRGL + TEXTSEP) //px; filename text-left FAREAMRGL + TEXTSEP | ||||
#define SORTBTNOFF -10 //px; | #define SORTBTNOFF -10 //px; | ||||
#define DBLCLKTME 400 //msec; double click time | |||||
#ifndef DBLCLKTME | |||||
#define DBLCLKTME 200 //msec; double click time | |||||
#endif | |||||
#define DRAW_OUTLINE | #define DRAW_OUTLINE | ||||
#define DOUBLE_BUFFER | #define DOUBLE_BUFFER | ||||
@@ -1208,7 +1211,7 @@ static int fib_dirlistadd (Display *dpy, const int i, const char* path, const ch | |||||
static int fib_openrecent (Display *dpy, const char *sel) { | static int fib_openrecent (Display *dpy, const char *sel) { | ||||
int i; | int i; | ||||
unsigned int j; | |||||
unsigned int j; | |||||
assert (_recentcnt > 0); | assert (_recentcnt > 0); | ||||
fib_pre_opendir (dpy); | fib_pre_opendir (dpy); | ||||
query_font_geometry (dpy, _fib_gc, "Last Used", &_fib_font_time_width, NULL, NULL, NULL); | query_font_geometry (dpy, _fib_gc, "Last Used", &_fib_font_time_width, NULL, NULL, NULL); | ||||
@@ -1332,8 +1335,8 @@ static int fib_open (Display *dpy, int item) { | |||||
static void cb_cancel (Display *dpy) { | static void cb_cancel (Display *dpy) { | ||||
_status = -1; | _status = -1; | ||||
// unused | |||||
return; (void)dpy; | |||||
// unused | |||||
return; (void)dpy; | |||||
} | } | ||||
static void cb_open (Display *dpy) { | static void cb_open (Display *dpy) { | ||||
@@ -1478,8 +1481,8 @@ static int fib_widget_at_pos (Display *dpy, int x, int y, int *it) { | |||||
return 0; | return 0; | ||||
// unused | |||||
(void)dpy; | |||||
// unused | |||||
(void)dpy; | |||||
} | } | ||||
static void fib_update_hover (Display *dpy, int need_expose, const int type, const int item) { | static void fib_update_hover (Display *dpy, int need_expose, const int type, const int item) { | ||||
@@ -1592,9 +1595,11 @@ static void fib_mousedown (Display *dpy, int x, int y, int btn, unsigned long ti | |||||
fib_select (dpy, it); | fib_select (dpy, it); | ||||
_dblclk = time; | _dblclk = time; | ||||
} | } | ||||
/*if (_fsel >= 0) { | |||||
/* | |||||
if (_fsel >= 0) { | |||||
if (!(_dirlist[_fsel].flags & 4)); | if (!(_dirlist[_fsel].flags & 4)); | ||||
}*/ | |||||
} | |||||
*/ | |||||
} | } | ||||
break; | break; | ||||
case 1: // paths | case 1: // paths | ||||
@@ -1656,8 +1661,8 @@ static void fib_mousedown (Display *dpy, int x, int y, int btn, unsigned long ti | |||||
static void fib_mouseup (Display *dpy, int x, int y, int btn, unsigned long time) { | static void fib_mouseup (Display *dpy, int x, int y, int btn, unsigned long time) { | ||||
_scrl_my = -1; | _scrl_my = -1; | ||||
// unused | |||||
return; (void)dpy; (void)x; (void)y; (void)btn; (void)time; | |||||
// unused | |||||
return; (void)dpy; (void)x; (void)y; (void)btn; (void)time; | |||||
} | } | ||||
static void add_place_raw (Display *dpy, const char *name, const char *path) { | static void add_place_raw (Display *dpy, const char *name, const char *path) { | ||||
@@ -1885,8 +1890,8 @@ static int x_error_handler (Display *d, XErrorEvent *e) { | |||||
font_err = 1; | font_err = 1; | ||||
return 0; | return 0; | ||||
// unused | |||||
(void)d; (void)e; | |||||
// unused | |||||
(void)d; (void)e; | |||||
} | } | ||||
int x_fib_show (Display *dpy, Window parent, int x, int y) { | int x_fib_show (Display *dpy, Window parent, int x, int y) { | ||||
@@ -2340,7 +2345,7 @@ char *x_fib_filename () { | |||||
else | else | ||||
return NULL; | return NULL; | ||||
} | } | ||||
#endif // SOFD_HAVE_X11 | |||||
#endif // HAVE_X11 | |||||
#if defined(__clang__) | #if defined(__clang__) | ||||
# pragma clang diagnostic pop | # pragma clang diagnostic pop | ||||
@@ -22,10 +22,15 @@ | |||||
*/ | */ | ||||
#ifndef LIBSOFD_H | #ifndef LIBSOFD_H | ||||
#define LIBSOFD_H | |||||
#define LIBSOFD_H 1 | |||||
#ifdef HAVE_X11 | |||||
#include <X11/Xlib.h> | #include <X11/Xlib.h> | ||||
#ifdef __cplusplus | |||||
extern "C" { | |||||
#endif | |||||
/////////////////////////////////////////////////////////////////////////////// | /////////////////////////////////////////////////////////////////////////////// | ||||
/* public API */ | /* public API */ | ||||
@@ -110,6 +115,16 @@ int x_fib_cfg_buttons (int k, int v); | |||||
*/ | */ | ||||
int x_fib_cfg_filter_callback (int (*cb)(const char*)); | int x_fib_cfg_filter_callback (int (*cb)(const char*)); | ||||
#ifdef __cplusplus | |||||
} | |||||
#endif | |||||
#endif /* END X11 specific functions */ | |||||
#ifdef __cplusplus | |||||
extern "C" { | |||||
#endif | |||||
/* 'recently used' API. x-platform | /* 'recently used' API. x-platform | ||||
* NOTE: all functions use a static cache and are not reentrant. | * NOTE: all functions use a static cache and are not reentrant. | ||||
* It is expected that none of these functions are called in | * It is expected that none of these functions are called in | ||||
@@ -172,4 +187,8 @@ unsigned int x_fib_recent_count (); | |||||
*/ | */ | ||||
const char *x_fib_recent_at (unsigned int i); | const char *x_fib_recent_at (unsigned int i); | ||||
#endif // LIBSOFD_H | |||||
#ifdef __cplusplus | |||||
} | |||||
#endif | |||||
#endif // header guard |
@@ -563,6 +563,28 @@ START_NAMESPACE_DISTRHO | |||||
*/ | */ | ||||
#define DISTRHO_PLUGIN_WANT_TIMEPOS 1 | #define DISTRHO_PLUGIN_WANT_TIMEPOS 1 | ||||
/** | |||||
Wherever the %UI uses a custom toolkit implementation based on OpenGL.@n | |||||
When enabled, the macros @ref DISTRHO_UI_CUSTOM_INCLUDE_PATH and @ref DISTRHO_UI_CUSTOM_WIDGET_TYPE are required. | |||||
*/ | |||||
#define DISTRHO_UI_USE_CUSTOM 1 | |||||
/** | |||||
The include path to the header file used by the custom toolkit implementation. | |||||
This path must be relative to dpf/distrho/DistrhoUI.hpp | |||||
@see DISTRHO_UI_USE_CUSTOM | |||||
*/ | |||||
#define DISTRHO_UI_CUSTOM_INCLUDE_PATH | |||||
/** | |||||
The top-level-widget typedef to use for the custom toolkit. | |||||
This widget class MUST be a subclass of DGL TopLevelWindow class. | |||||
It is recommended that you keep this widget class inside the DGL namespace, | |||||
and define widget type as e.g. DGL_NAMESPACE::MyCustomTopLevelWidget. | |||||
@see DISTRHO_UI_USE_CUSTOM | |||||
*/ | |||||
#define DISTRHO_UI_CUSTOM_WIDGET_TYPE | |||||
/** | /** | ||||
Wherever the %UI uses NanoVG for drawing instead of the default raw OpenGL calls.@n | Wherever the %UI uses NanoVG for drawing instead of the default raw OpenGL calls.@n | ||||
When enabled your %UI instance will subclass @ref NanoWidget instead of @ref Widget. | When enabled your %UI instance will subclass @ref NanoWidget instead of @ref Widget. | ||||
@@ -369,7 +369,7 @@ struct ParameterEnumerationValues { | |||||
} | } | ||||
} | } | ||||
DISTRHO_DECLARE_NON_COPY_STRUCT(ParameterEnumerationValues) | |||||
DISTRHO_DECLARE_NON_COPYABLE(ParameterEnumerationValues) | |||||
}; | }; | ||||
/** | /** | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2020 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -20,23 +20,32 @@ | |||||
#include "extra/LeakDetector.hpp" | #include "extra/LeakDetector.hpp" | ||||
#include "src/DistrhoPluginChecks.h" | #include "src/DistrhoPluginChecks.h" | ||||
#ifdef DGL_CAIRO | |||||
# include "Cairo.hpp" | |||||
#endif | |||||
#ifdef DGL_OPENGL | |||||
# include "OpenGL.hpp" | |||||
#endif | |||||
#ifdef DGL_VULKAN | |||||
# include "Vulkan.hpp" | |||||
#endif | |||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | ||||
# include "../dgl/Base.hpp" | # include "../dgl/Base.hpp" | ||||
# include "extra/ExternalWindow.hpp" | # include "extra/ExternalWindow.hpp" | ||||
typedef DISTRHO_NAMESPACE::ExternalWindow UIWidget; | typedef DISTRHO_NAMESPACE::ExternalWindow UIWidget; | ||||
#elif DISTRHO_UI_USE_CUSTOM | |||||
# include DISTRHO_UI_CUSTOM_INCLUDE_PATH | |||||
typedef DISTRHO_UI_CUSTOM_WIDGET_TYPE UIWidget; | |||||
#elif DISTRHO_UI_USE_CAIRO | |||||
# include "../dgl/Cairo.hpp" | |||||
typedef DGL_NAMESPACE::CairoTopLevelWidget UIWidget; | |||||
#elif DISTRHO_UI_USE_NANOVG | #elif DISTRHO_UI_USE_NANOVG | ||||
# include "../dgl/NanoVG.hpp" | # include "../dgl/NanoVG.hpp" | ||||
typedef DGL_NAMESPACE::NanoWidget UIWidget; | |||||
typedef DGL_NAMESPACE::NanoTopLevelWidget UIWidget; | |||||
#else | #else | ||||
# include "../dgl/Widget.hpp" | |||||
typedef DGL_NAMESPACE::Widget UIWidget; | |||||
#endif | |||||
#ifdef DGL_CAIRO | |||||
# include "Cairo.hpp" | |||||
#endif | |||||
#ifdef DGL_OPENGL | |||||
# include "OpenGL.hpp" | |||||
# include "../dgl/TopLevelWidget.hpp" | |||||
typedef DGL_NAMESPACE::TopLevelWidget UIWidget; | |||||
#endif | #endif | ||||
START_NAMESPACE_DISTRHO | START_NAMESPACE_DISTRHO | ||||
@@ -69,27 +78,32 @@ public: | |||||
*/ | */ | ||||
virtual ~UI(); | virtual ~UI(); | ||||
#if DISTRHO_UI_USER_RESIZABLE && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
/** | |||||
Set geometry constraints for the UI when resized by the user, and optionally scale UI automatically. | |||||
@see Window::setGeometryConstraints(uint,uint,bool) | |||||
@see Window::setScaling(double) | |||||
*/ | |||||
void setGeometryConstraints(uint minWidth, uint minHeight, bool keepAspectRatio, bool automaticallyScale = false); | |||||
#endif | |||||
/* -------------------------------------------------------------------------------------------------------- | /* -------------------------------------------------------------------------------------------------------- | ||||
* Host state */ | * Host state */ | ||||
/** | /** | ||||
Get the color used for UI background (i.e. window color) in RGBA format. | Get the color used for UI background (i.e. window color) in RGBA format. | ||||
Returns 0 by default, in case of error or lack of host support. | Returns 0 by default, in case of error or lack of host support. | ||||
The following example code can be use to extract individual colors: | |||||
``` | |||||
const int red = (bgColor >> 24) & 0xff; | |||||
const int green = (bgColor >> 16) & 0xff; | |||||
const int blue = (bgColor >> 8) & 0xff; | |||||
``` | |||||
*/ | */ | ||||
uint getBackgroundColor() const noexcept; | uint getBackgroundColor() const noexcept; | ||||
/** | /** | ||||
Get the color used for UI foreground (i.e. text color) in RGBA format. | Get the color used for UI foreground (i.e. text color) in RGBA format. | ||||
Returns 0xffffffff by default, in case of error or lack of host support. | Returns 0xffffffff by default, in case of error or lack of host support. | ||||
The following example code can be use to extract individual colors: | |||||
``` | |||||
const int red = (fgColor >> 24) & 0xff; | |||||
const int green = (fgColor >> 16) & 0xff; | |||||
const int blue = (fgColor >> 8) & 0xff; | |||||
``` | |||||
*/ | */ | ||||
uint getForegroundColor() const noexcept; | uint getForegroundColor() const noexcept; | ||||
@@ -232,7 +246,7 @@ protected: | |||||
# ifndef DGL_FILE_BROWSER_DISABLED | # ifndef DGL_FILE_BROWSER_DISABLED | ||||
/** | /** | ||||
File browser selected function. | File browser selected function. | ||||
@see Window::fileBrowserSelected(const char*) | |||||
@see Window::onFileSelected(const char*) | |||||
*/ | */ | ||||
virtual void uiFileBrowserSelected(const char* filename); | virtual void uiFileBrowserSelected(const char* filename); | ||||
# endif | # endif | ||||
@@ -259,18 +273,10 @@ protected: | |||||
private: | private: | ||||
struct PrivateData; | struct PrivateData; | ||||
PrivateData* const pData; | |||||
PrivateData* const uiData; | |||||
friend class UIExporter; | friend class UIExporter; | ||||
friend class UIExporterWindow; | friend class UIExporterWindow; | ||||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
// these should not be used | |||||
void setAbsoluteX(int) const noexcept {} | |||||
void setAbsoluteY(int) const noexcept {} | |||||
void setAbsolutePos(int, int) const noexcept {} | |||||
void setAbsolutePos(const DGL_NAMESPACE::Point<int>&) const noexcept {} | |||||
#endif | |||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(UI) | DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(UI) | ||||
}; | }; | ||||
@@ -0,0 +1,33 @@ | |||||
/* | |||||
* DISTRHO Plugin Framework (DPF) | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#ifndef PUGL_NAMESPACE | |||||
# error PUGL_NAMESPACE must be set when compiling this file | |||||
#endif | |||||
#include "src/DistrhoPluginChecks.h" | |||||
#include "../dgl/Base.hpp" | |||||
#define DISTRHO_MACOS_NAMESPACE_MACRO_HELPER(DGL_NS, SEP, PUGL_NS, INTERFACE) DGL_NS ## SEP ## PUGL_NS ## SEP ## INTERFACE | |||||
#define DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NS, PUGL_NS, INTERFACE) DISTRHO_MACOS_NAMESPACE_MACRO_HELPER(DGL_NS, _, PUGL_NS, INTERFACE) | |||||
#define PuglOpenGLView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PUGL_NAMESPACE, OpenGLView) | |||||
#define PuglStubView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PUGL_NAMESPACE, StubView) | |||||
#define PuglWindow DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PUGL_NAMESPACE, Window) | |||||
#define PuglWindowDelegate DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PUGL_NAMESPACE, WindowDelegate) | |||||
#define PuglWrapperView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PUGL_NAMESPACE, WrapperView) | |||||
#import "src/pugl.mm" |
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2018 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -50,6 +50,9 @@ inline float round(float __x) | |||||
# define M_PI 3.14159265358979323846 | # define M_PI 3.14159265358979323846 | ||||
#endif | #endif | ||||
#define DISTRHO_MACRO_AS_STRING_VALUE(MACRO) #MACRO | |||||
#define DISTRHO_MACRO_AS_STRING(MACRO) DISTRHO_MACRO_AS_STRING_VALUE(MACRO) | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// misc functions | // misc functions | ||||
@@ -196,6 +199,16 @@ void d_safe_assert_uint2(const char* const assertion, const char* const file, | |||||
d_stderr2("assertion failure: \"%s\" in file %s, line %i, v1 %u, v2 %u", assertion, file, line, v1, v2); | d_stderr2("assertion failure: \"%s\" in file %s, line %i, v1 %u, v2 %u", assertion, file, line, v1, v2); | ||||
} | } | ||||
/* | |||||
* Print a safe assertion error message, with a custom error message. | |||||
*/ | |||||
static inline | |||||
void d_custom_safe_assert(const char* const message, const char* const assertion, const char* const file, | |||||
const int line) noexcept | |||||
{ | |||||
d_stderr2("assertion failure: %s, condition \"%s\" in file %s, line %i", message, assertion, file, line); | |||||
} | |||||
/* | /* | ||||
* Print a safe exception error message. | * Print a safe exception error message. | ||||
*/ | */ | ||||
@@ -192,7 +192,7 @@ private: | |||||
friend class UIExporter; | friend class UIExporter; | ||||
DISTRHO_DECLARE_NON_COPY_CLASS(ExternalWindow) | |||||
DISTRHO_DECLARE_NON_COPYABLE(ExternalWindow) | |||||
}; | }; | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -54,13 +54,13 @@ START_NAMESPACE_DISTRHO | |||||
DISTRHO_NAMESPACE::LeakedObjectDetector<ClassName> DISTRHO_JOIN_MACRO(leakDetector_, ClassName); | DISTRHO_NAMESPACE::LeakedObjectDetector<ClassName> DISTRHO_JOIN_MACRO(leakDetector_, ClassName); | ||||
# define DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ClassName) \ | # define DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ClassName) \ | ||||
DISTRHO_DECLARE_NON_COPY_CLASS(ClassName) \ | |||||
DISTRHO_DECLARE_NON_COPYABLE(ClassName) \ | |||||
DISTRHO_LEAK_DETECTOR(ClassName) | DISTRHO_LEAK_DETECTOR(ClassName) | ||||
#else | #else | ||||
/** Don't use leak detection on release builds. */ | /** Don't use leak detection on release builds. */ | ||||
# define DISTRHO_LEAK_DETECTOR(ClassName) | # define DISTRHO_LEAK_DETECTOR(ClassName) | ||||
# define DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ClassName) \ | # define DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ClassName) \ | ||||
DISTRHO_DECLARE_NON_COPY_CLASS(ClassName) | |||||
DISTRHO_DECLARE_NON_COPYABLE(ClassName) | |||||
#endif | #endif | ||||
//============================================================================== | //============================================================================== | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -39,7 +39,7 @@ public: | |||||
/* | /* | ||||
* Constructor. | * Constructor. | ||||
*/ | */ | ||||
Mutex(bool inheritPriority = true) noexcept | |||||
Mutex(const bool inheritPriority = true) noexcept | |||||
: fMutex() | : fMutex() | ||||
{ | { | ||||
pthread_mutexattr_t attr; | pthread_mutexattr_t attr; | ||||
@@ -61,9 +61,9 @@ public: | |||||
/* | /* | ||||
* Lock the mutex. | * Lock the mutex. | ||||
*/ | */ | ||||
void lock() const noexcept | |||||
bool lock() const noexcept | |||||
{ | { | ||||
pthread_mutex_lock(&fMutex); | |||||
return (pthread_mutex_lock(&fMutex) == 0); | |||||
} | } | ||||
/* | /* | ||||
@@ -86,8 +86,7 @@ public: | |||||
private: | private: | ||||
mutable pthread_mutex_t fMutex; | mutable pthread_mutex_t fMutex; | ||||
DISTRHO_PREVENT_HEAP_ALLOCATION | |||||
DISTRHO_DECLARE_NON_COPY_CLASS(Mutex) | |||||
DISTRHO_DECLARE_NON_COPYABLE(Mutex) | |||||
}; | }; | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -133,12 +132,13 @@ public: | |||||
/* | /* | ||||
* Lock the mutex. | * Lock the mutex. | ||||
*/ | */ | ||||
void lock() const noexcept | |||||
bool lock() const noexcept | |||||
{ | { | ||||
#ifdef DISTRHO_OS_WINDOWS | #ifdef DISTRHO_OS_WINDOWS | ||||
EnterCriticalSection(&fSection); | EnterCriticalSection(&fSection); | ||||
return true; | |||||
#else | #else | ||||
pthread_mutex_lock(&fMutex); | |||||
return (pthread_mutex_lock(&fMutex) == 0); | |||||
#endif | #endif | ||||
} | } | ||||
@@ -174,8 +174,7 @@ private: | |||||
mutable pthread_mutex_t fMutex; | mutable pthread_mutex_t fMutex; | ||||
#endif | #endif | ||||
DISTRHO_PREVENT_HEAP_ALLOCATION | |||||
DISTRHO_DECLARE_NON_COPY_CLASS(RecursiveMutex) | |||||
DISTRHO_DECLARE_NON_COPYABLE(RecursiveMutex) | |||||
}; | }; | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -256,7 +255,7 @@ private: | |||||
volatile bool fTriggered; | volatile bool fTriggered; | ||||
DISTRHO_PREVENT_HEAP_ALLOCATION | DISTRHO_PREVENT_HEAP_ALLOCATION | ||||
DISTRHO_DECLARE_NON_COPY_CLASS(Signal) | |||||
DISTRHO_DECLARE_NON_COPYABLE(Signal) | |||||
}; | }; | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -281,7 +280,7 @@ private: | |||||
const Mutex& fMutex; | const Mutex& fMutex; | ||||
DISTRHO_PREVENT_HEAP_ALLOCATION | DISTRHO_PREVENT_HEAP_ALLOCATION | ||||
DISTRHO_DECLARE_NON_COPY_CLASS(ScopeLocker) | |||||
DISTRHO_DECLARE_NON_COPYABLE(ScopeLocker) | |||||
}; | }; | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -295,6 +294,10 @@ public: | |||||
: fMutex(mutex), | : fMutex(mutex), | ||||
fLocked(mutex.tryLock()) {} | fLocked(mutex.tryLock()) {} | ||||
ScopeTryLocker(const Mutex& mutex, const bool forceLock) noexcept | |||||
: fMutex(mutex), | |||||
fLocked(forceLock ? mutex.lock() : mutex.tryLock()) {} | |||||
~ScopeTryLocker() noexcept | ~ScopeTryLocker() noexcept | ||||
{ | { | ||||
if (fLocked) | if (fLocked) | ||||
@@ -316,7 +319,7 @@ private: | |||||
const bool fLocked; | const bool fLocked; | ||||
DISTRHO_PREVENT_HEAP_ALLOCATION | DISTRHO_PREVENT_HEAP_ALLOCATION | ||||
DISTRHO_DECLARE_NON_COPY_CLASS(ScopeTryLocker) | |||||
DISTRHO_DECLARE_NON_COPYABLE(ScopeTryLocker) | |||||
}; | }; | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -341,7 +344,7 @@ private: | |||||
const Mutex& fMutex; | const Mutex& fMutex; | ||||
DISTRHO_PREVENT_HEAP_ALLOCATION | DISTRHO_PREVENT_HEAP_ALLOCATION | ||||
DISTRHO_DECLARE_NON_COPY_CLASS(ScopeUnlocker) | |||||
DISTRHO_DECLARE_NON_COPYABLE(ScopeUnlocker) | |||||
}; | }; | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -0,0 +1,136 @@ | |||||
/* | |||||
* DISTRHO Plugin Framework (DPF) | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#ifndef DISTRHO_SCOPED_SAFE_LOCALE_HPP_INCLUDED | |||||
#define DISTRHO_SCOPED_SAFE_LOCALE_HPP_INCLUDED | |||||
#include "../DistrhoUtils.hpp" | |||||
#include <clocale> | |||||
#if ! (defined(DISTRHO_OS_HAIKU) || defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WINDOWS)) | |||||
# define DISTRHO_USE_NEWLOCALE | |||||
#endif | |||||
#if defined(DISTRHO_OS_WINDOWS) && __MINGW64_VERSION_MAJOR >= 5 | |||||
# define DISTRHO_USE_CONFIGTHREADLOCALE | |||||
#endif | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
// ScopedSafeLocale class definition | |||||
/** | |||||
ScopedSafeLocale is a handy class for setting current locale to C on constructor, and revert back on destructor. | |||||
It tries to be thread-safe, but it is not always possible. | |||||
Put it inside a scope of code where string conversions happen to ensure they are consistent across many systems. | |||||
For example: | |||||
``` | |||||
// stack buffer to put converted float value in | |||||
char strbuf[0xff]; | |||||
{ | |||||
// safe locale operations during this scope | |||||
const ScopedSafeLocale sl; | |||||
snprintf(strbuf, 0xff, "%f", value); | |||||
} | |||||
// do something with `strbuf` now, locale is reverted and left just as it was before | |||||
``` | |||||
*/ | |||||
class ScopedSafeLocale { | |||||
public: | |||||
/* | |||||
* Constructor. | |||||
* Current system locale will saved, while "C" is set as the next one to use. | |||||
*/ | |||||
inline ScopedSafeLocale() noexcept; | |||||
/* | |||||
* Destructor. | |||||
* System locale will revert back to the one saved during constructor. | |||||
*/ | |||||
inline ~ScopedSafeLocale() noexcept; | |||||
private: | |||||
#ifdef DISTRHO_USE_NEWLOCALE | |||||
locale_t newloc, oldloc; | |||||
#else | |||||
# ifdef DISTRHO_USE_CONFIGTHREADLOCALE | |||||
const int oldthreadloc; | |||||
# endif | |||||
char* const oldloc; | |||||
#endif | |||||
DISTRHO_DECLARE_NON_COPYABLE(ScopedSafeLocale) | |||||
DISTRHO_PREVENT_HEAP_ALLOCATION | |||||
}; | |||||
// ----------------------------------------------------------------------- | |||||
// ScopedSafeLocale class implementation | |||||
#ifdef DISTRHO_USE_NEWLOCALE | |||||
static constexpr const locale_t kNullLocale = (locale_t)nullptr; | |||||
#endif | |||||
inline ScopedSafeLocale::ScopedSafeLocale() noexcept | |||||
#ifdef DISTRHO_USE_NEWLOCALE | |||||
: newloc(::newlocale(LC_NUMERIC_MASK, "C", kNullLocale)), | |||||
oldloc(newloc != kNullLocale ? ::uselocale(newloc) : kNullLocale) {} | |||||
#else | |||||
# ifdef DISTRHO_USE_CONFIGTHREADLOCALE | |||||
: oldthreadloc(_configthreadlocale(_ENABLE_PER_THREAD_LOCALE)), | |||||
# else | |||||
: | |||||
# endif | |||||
oldloc(strdup(::setlocale(LC_NUMERIC, nullptr))) | |||||
{ | |||||
::setlocale(LC_NUMERIC, "C"); | |||||
} | |||||
#endif | |||||
inline ScopedSafeLocale::~ScopedSafeLocale() noexcept | |||||
{ | |||||
#ifdef DISTRHO_USE_NEWLOCALE | |||||
if (oldloc != kNullLocale) | |||||
::uselocale(oldloc); | |||||
if (newloc != kNullLocale) | |||||
::freelocale(newloc); | |||||
#else // DISTRHO_USE_NEWLOCALE | |||||
if (oldloc != nullptr) | |||||
{ | |||||
::setlocale(LC_NUMERIC, oldloc); | |||||
std::free(oldloc); | |||||
} | |||||
# ifdef DISTRHO_USE_CONFIGTHREADLOCALE | |||||
if (oldthreadloc != -1) | |||||
_configthreadlocale(oldthreadloc); | |||||
# endif | |||||
#endif // DISTRHO_USE_NEWLOCALE | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
#undef DISTRHO_USE_CONFIGTHREADLOCALE | |||||
#undef DISTRHO_USE_NEWLOCALE | |||||
END_NAMESPACE_DISTRHO | |||||
#endif // DISTRHO_SCOPED_SAFE_LOCALE_HPP_INCLUDED |
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -18,6 +18,7 @@ | |||||
#define DISTRHO_STRING_HPP_INCLUDED | #define DISTRHO_STRING_HPP_INCLUDED | ||||
#include "../DistrhoUtils.hpp" | #include "../DistrhoUtils.hpp" | ||||
#include "../extra/ScopedSafeLocale.hpp" | |||||
#include <algorithm> | #include <algorithm> | ||||
@@ -37,14 +38,16 @@ public: | |||||
*/ | */ | ||||
explicit String() noexcept | explicit String() noexcept | ||||
: fBuffer(_null()), | : fBuffer(_null()), | ||||
fBufferLen(0) {} | |||||
fBufferLen(0), | |||||
fBufferAlloc(false) {} | |||||
/* | /* | ||||
* Simple character. | * Simple character. | ||||
*/ | */ | ||||
explicit String(const char c) noexcept | explicit String(const char c) noexcept | ||||
: fBuffer(_null()), | : fBuffer(_null()), | ||||
fBufferLen(0) | |||||
fBufferLen(0), | |||||
fBufferAlloc(false) | |||||
{ | { | ||||
char ch[2]; | char ch[2]; | ||||
ch[0] = c; | ch[0] = c; | ||||
@@ -58,7 +61,8 @@ public: | |||||
*/ | */ | ||||
explicit String(char* const strBuf, const bool copyData = true) noexcept | explicit String(char* const strBuf, const bool copyData = true) noexcept | ||||
: fBuffer(_null()), | : fBuffer(_null()), | ||||
fBufferLen(0) | |||||
fBufferLen(0), | |||||
fBufferAlloc(false) | |||||
{ | { | ||||
if (copyData || strBuf == nullptr) | if (copyData || strBuf == nullptr) | ||||
{ | { | ||||
@@ -66,10 +70,10 @@ public: | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
fBuffer = strBuf; | |||||
fBufferLen = std::strlen(strBuf); | |||||
fBuffer = strBuf; | |||||
fBufferLen = std::strlen(strBuf); | |||||
fBufferAlloc = true; | |||||
} | } | ||||
} | } | ||||
/* | /* | ||||
@@ -77,7 +81,8 @@ public: | |||||
*/ | */ | ||||
explicit String(const char* const strBuf) noexcept | explicit String(const char* const strBuf) noexcept | ||||
: fBuffer(_null()), | : fBuffer(_null()), | ||||
fBufferLen(0) | |||||
fBufferLen(0), | |||||
fBufferAlloc(false) | |||||
{ | { | ||||
_dup(strBuf); | _dup(strBuf); | ||||
} | } | ||||
@@ -87,7 +92,8 @@ public: | |||||
*/ | */ | ||||
explicit String(const int value) noexcept | explicit String(const int value) noexcept | ||||
: fBuffer(_null()), | : fBuffer(_null()), | ||||
fBufferLen(0) | |||||
fBufferLen(0), | |||||
fBufferAlloc(false) | |||||
{ | { | ||||
char strBuf[0xff+1]; | char strBuf[0xff+1]; | ||||
std::snprintf(strBuf, 0xff, "%d", value); | std::snprintf(strBuf, 0xff, "%d", value); | ||||
@@ -101,7 +107,8 @@ public: | |||||
*/ | */ | ||||
explicit String(const unsigned int value, const bool hexadecimal = false) noexcept | explicit String(const unsigned int value, const bool hexadecimal = false) noexcept | ||||
: fBuffer(_null()), | : fBuffer(_null()), | ||||
fBufferLen(0) | |||||
fBufferLen(0), | |||||
fBufferAlloc(false) | |||||
{ | { | ||||
char strBuf[0xff+1]; | char strBuf[0xff+1]; | ||||
std::snprintf(strBuf, 0xff, hexadecimal ? "0x%x" : "%u", value); | std::snprintf(strBuf, 0xff, hexadecimal ? "0x%x" : "%u", value); | ||||
@@ -115,7 +122,8 @@ public: | |||||
*/ | */ | ||||
explicit String(const long value) noexcept | explicit String(const long value) noexcept | ||||
: fBuffer(_null()), | : fBuffer(_null()), | ||||
fBufferLen(0) | |||||
fBufferLen(0), | |||||
fBufferAlloc(false) | |||||
{ | { | ||||
char strBuf[0xff+1]; | char strBuf[0xff+1]; | ||||
std::snprintf(strBuf, 0xff, "%ld", value); | std::snprintf(strBuf, 0xff, "%ld", value); | ||||
@@ -129,7 +137,8 @@ public: | |||||
*/ | */ | ||||
explicit String(const unsigned long value, const bool hexadecimal = false) noexcept | explicit String(const unsigned long value, const bool hexadecimal = false) noexcept | ||||
: fBuffer(_null()), | : fBuffer(_null()), | ||||
fBufferLen(0) | |||||
fBufferLen(0), | |||||
fBufferAlloc(false) | |||||
{ | { | ||||
char strBuf[0xff+1]; | char strBuf[0xff+1]; | ||||
std::snprintf(strBuf, 0xff, hexadecimal ? "0x%lx" : "%lu", value); | std::snprintf(strBuf, 0xff, hexadecimal ? "0x%lx" : "%lu", value); | ||||
@@ -143,7 +152,8 @@ public: | |||||
*/ | */ | ||||
explicit String(const long long value) noexcept | explicit String(const long long value) noexcept | ||||
: fBuffer(_null()), | : fBuffer(_null()), | ||||
fBufferLen(0) | |||||
fBufferLen(0), | |||||
fBufferAlloc(false) | |||||
{ | { | ||||
char strBuf[0xff+1]; | char strBuf[0xff+1]; | ||||
std::snprintf(strBuf, 0xff, "%lld", value); | std::snprintf(strBuf, 0xff, "%lld", value); | ||||
@@ -157,7 +167,8 @@ public: | |||||
*/ | */ | ||||
explicit String(const unsigned long long value, const bool hexadecimal = false) noexcept | explicit String(const unsigned long long value, const bool hexadecimal = false) noexcept | ||||
: fBuffer(_null()), | : fBuffer(_null()), | ||||
fBufferLen(0) | |||||
fBufferLen(0), | |||||
fBufferAlloc(false) | |||||
{ | { | ||||
char strBuf[0xff+1]; | char strBuf[0xff+1]; | ||||
std::snprintf(strBuf, 0xff, hexadecimal ? "0x%llx" : "%llu", value); | std::snprintf(strBuf, 0xff, hexadecimal ? "0x%llx" : "%llu", value); | ||||
@@ -171,10 +182,16 @@ public: | |||||
*/ | */ | ||||
explicit String(const float value) noexcept | explicit String(const float value) noexcept | ||||
: fBuffer(_null()), | : fBuffer(_null()), | ||||
fBufferLen(0) | |||||
fBufferLen(0), | |||||
fBufferAlloc(false) | |||||
{ | { | ||||
char strBuf[0xff+1]; | char strBuf[0xff+1]; | ||||
std::snprintf(strBuf, 0xff, "%.12g", static_cast<double>(value)); | |||||
{ | |||||
const ScopedSafeLocale ssl; | |||||
std::snprintf(strBuf, 0xff, "%.12g", static_cast<double>(value)); | |||||
} | |||||
strBuf[0xff] = '\0'; | strBuf[0xff] = '\0'; | ||||
_dup(strBuf); | _dup(strBuf); | ||||
@@ -185,10 +202,16 @@ public: | |||||
*/ | */ | ||||
explicit String(const double value) noexcept | explicit String(const double value) noexcept | ||||
: fBuffer(_null()), | : fBuffer(_null()), | ||||
fBufferLen(0) | |||||
fBufferLen(0), | |||||
fBufferAlloc(false) | |||||
{ | { | ||||
char strBuf[0xff+1]; | char strBuf[0xff+1]; | ||||
std::snprintf(strBuf, 0xff, "%.24g", value); | |||||
{ | |||||
const ScopedSafeLocale ssl; | |||||
std::snprintf(strBuf, 0xff, "%.24g", value); | |||||
} | |||||
strBuf[0xff] = '\0'; | strBuf[0xff] = '\0'; | ||||
_dup(strBuf); | _dup(strBuf); | ||||
@@ -202,7 +225,8 @@ public: | |||||
*/ | */ | ||||
String(const String& str) noexcept | String(const String& str) noexcept | ||||
: fBuffer(_null()), | : fBuffer(_null()), | ||||
fBufferLen(0) | |||||
fBufferLen(0), | |||||
fBufferAlloc(false) | |||||
{ | { | ||||
_dup(str.fBuffer); | _dup(str.fBuffer); | ||||
} | } | ||||
@@ -217,13 +241,12 @@ public: | |||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(fBuffer != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(fBuffer != nullptr,); | ||||
if (fBuffer == _null()) | |||||
return; | |||||
std::free(fBuffer); | |||||
if (fBufferAlloc) | |||||
std::free(fBuffer); | |||||
fBuffer = nullptr; | |||||
fBufferLen = 0; | |||||
fBuffer = nullptr; | |||||
fBufferLen = 0; | |||||
fBufferAlloc = false; | |||||
} | } | ||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
@@ -253,6 +276,20 @@ public: | |||||
return (fBufferLen != 0); | return (fBufferLen != 0); | ||||
} | } | ||||
/* | |||||
* Check if the string contains a specific character, case-sensitive. | |||||
*/ | |||||
bool contains(const char c) const noexcept | |||||
{ | |||||
for (std::size_t i=0; i<fBufferLen; ++i) | |||||
{ | |||||
if (fBuffer[i] == c) | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
/* | /* | ||||
* Check if the string contains another string, optionally ignoring case. | * Check if the string contains another string, optionally ignoring case. | ||||
*/ | */ | ||||
@@ -388,7 +425,7 @@ public: | |||||
if (ret < 0) | if (ret < 0) | ||||
{ | { | ||||
// should never happen! | // should never happen! | ||||
d_safe_assert("ret >= 0", __FILE__, __LINE__); | |||||
d_safe_assert_int("ret >= 0", __FILE__, __LINE__, int(ret)); | |||||
if (found != nullptr) | if (found != nullptr) | ||||
*found = false; | *found = false; | ||||
@@ -490,6 +527,29 @@ public: | |||||
return *this; | return *this; | ||||
} | } | ||||
/* | |||||
* Remove all occurrences of character 'c', shifting and truncating the string as necessary. | |||||
*/ | |||||
String& remove(const char c) noexcept | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(c != '\0', *this); | |||||
if (fBufferLen == 0) | |||||
return *this; | |||||
for (std::size_t i=0; i < fBufferLen; ++i) | |||||
{ | |||||
if (fBuffer[i] == c) | |||||
{ | |||||
--fBufferLen; | |||||
std::memmove(fBuffer+i, fBuffer+i+1, fBufferLen-i); | |||||
} | |||||
} | |||||
fBuffer[fBufferLen] = '\0'; | |||||
return *this; | |||||
} | |||||
/* | /* | ||||
* Truncate the string to size 'n'. | * Truncate the string to size 'n'. | ||||
*/ | */ | ||||
@@ -498,9 +558,7 @@ public: | |||||
if (n >= fBufferLen) | if (n >= fBufferLen) | ||||
return *this; | return *this; | ||||
for (std::size_t i=n; i < fBufferLen; ++i) | |||||
fBuffer[i] = '\0'; | |||||
fBuffer[n] = '\0'; | |||||
fBufferLen = n; | fBufferLen = n; | ||||
return *this; | return *this; | ||||
@@ -529,7 +587,7 @@ public: | |||||
} | } | ||||
/* | /* | ||||
* Convert to all ascii characters to lowercase. | |||||
* Convert all ascii characters to lowercase. | |||||
*/ | */ | ||||
String& toLower() noexcept | String& toLower() noexcept | ||||
{ | { | ||||
@@ -545,7 +603,7 @@ public: | |||||
} | } | ||||
/* | /* | ||||
* Convert to all ascii characters to uppercase. | |||||
* Convert all ascii characters to uppercase. | |||||
*/ | */ | ||||
String& toUpper() noexcept | String& toUpper() noexcept | ||||
{ | { | ||||
@@ -570,13 +628,15 @@ public: | |||||
/* | /* | ||||
* Get and release the string buffer, while also clearing this string. | * Get and release the string buffer, while also clearing this string. | ||||
* This allows to keep a pointer to the buffer after this object is deleted. | |||||
* Result must be freed. | * Result must be freed. | ||||
*/ | */ | ||||
char* getAndReleaseBuffer() noexcept | char* getAndReleaseBuffer() noexcept | ||||
{ | { | ||||
char* const ret = fBuffer; | |||||
char* ret = fBufferLen > 0 ? fBuffer : nullptr; | |||||
fBuffer = _null(); | fBuffer = _null(); | ||||
fBufferLen = 0; | fBufferLen = 0; | ||||
fBufferAlloc = false; | |||||
return ret; | return ret; | ||||
} | } | ||||
@@ -591,7 +651,7 @@ public: | |||||
"abcdefghijklmnopqrstuvwxyz" | "abcdefghijklmnopqrstuvwxyz" | ||||
"0123456789+/"; | "0123456789+/"; | ||||
const std::size_t kTmpBufSize = std::min(d_nextPowerOf2(dataSize/3), 65536U); | |||||
const std::size_t kTmpBufSize = std::min(d_nextPowerOf2(static_cast<uint32_t>(dataSize/3)), 65536U); | |||||
const uchar* bytesToEncode((const uchar*)data); | const uchar* bytesToEncode((const uchar*)data); | ||||
@@ -723,16 +783,26 @@ public: | |||||
String& operator+=(const char* const strBuf) noexcept | String& operator+=(const char* const strBuf) noexcept | ||||
{ | { | ||||
if (strBuf == nullptr) | |||||
if (strBuf == nullptr || strBuf[0] == '\0') | |||||
return *this; | |||||
const std::size_t strBufLen = std::strlen(strBuf); | |||||
// for empty strings, we can just take the appended string as our entire data | |||||
if (isEmpty()) | |||||
{ | |||||
_dup(strBuf, strBufLen); | |||||
return *this; | return *this; | ||||
} | |||||
const std::size_t newBufSize = fBufferLen + std::strlen(strBuf) + 1; | |||||
char newBuf[newBufSize]; | |||||
// we have some data ourselves, reallocate to add the new stuff | |||||
char* const newBuf = (char*)realloc(fBuffer, fBufferLen + strBufLen + 1); | |||||
DISTRHO_SAFE_ASSERT_RETURN(newBuf != nullptr, *this); | |||||
std::strcpy(newBuf, fBuffer); | |||||
std::strcat(newBuf, strBuf); | |||||
std::memcpy(newBuf + fBufferLen, strBuf, strBufLen + 1); | |||||
_dup(newBuf, newBufSize-1); | |||||
fBuffer = newBuf; | |||||
fBufferLen += strBufLen; | |||||
return *this; | return *this; | ||||
} | } | ||||
@@ -744,13 +814,18 @@ public: | |||||
String operator+(const char* const strBuf) noexcept | String operator+(const char* const strBuf) noexcept | ||||
{ | { | ||||
const std::size_t newBufSize = fBufferLen + ((strBuf != nullptr) ? std::strlen(strBuf) : 0) + 1; | |||||
char newBuf[newBufSize]; | |||||
if (strBuf == nullptr || strBuf[0] == '\0') | |||||
return *this; | |||||
if (isEmpty()) | |||||
return String(strBuf); | |||||
std::strcpy(newBuf, fBuffer); | |||||
const std::size_t strBufLen = std::strlen(strBuf); | |||||
const std::size_t newBufSize = fBufferLen + strBufLen; | |||||
char* const newBuf = (char*)malloc(newBufSize + 1); | |||||
DISTRHO_SAFE_ASSERT_RETURN(newBuf != nullptr, String()); | |||||
if (strBuf != nullptr) | |||||
std::strcat(newBuf, strBuf); | |||||
std::memcpy(newBuf, fBuffer, fBufferLen); | |||||
std::memcpy(newBuf + fBufferLen, strBuf, strBufLen + 1); | |||||
return String(newBuf); | return String(newBuf); | ||||
} | } | ||||
@@ -763,8 +838,9 @@ public: | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
private: | private: | ||||
char* fBuffer; // the actual string buffer | |||||
std::size_t fBufferLen; // string length | |||||
char* fBuffer; // the actual string buffer | |||||
std::size_t fBufferLen; // string length | |||||
bool fBufferAlloc; // wherever the buffer is allocated, not using _null() | |||||
/* | /* | ||||
* Static null string. | * Static null string. | ||||
@@ -792,7 +868,7 @@ private: | |||||
if (std::strcmp(fBuffer, strBuf) == 0) | if (std::strcmp(fBuffer, strBuf) == 0) | ||||
return; | return; | ||||
if (fBuffer != _null()) | |||||
if (fBufferAlloc) | |||||
std::free(fBuffer); | std::free(fBuffer); | ||||
fBufferLen = (size > 0) ? size : std::strlen(strBuf); | fBufferLen = (size > 0) ? size : std::strlen(strBuf); | ||||
@@ -800,28 +876,31 @@ private: | |||||
if (fBuffer == nullptr) | if (fBuffer == nullptr) | ||||
{ | { | ||||
fBuffer = _null(); | |||||
fBufferLen = 0; | |||||
fBuffer = _null(); | |||||
fBufferLen = 0; | |||||
fBufferAlloc = false; | |||||
return; | return; | ||||
} | } | ||||
std::strcpy(fBuffer, strBuf); | |||||
fBufferAlloc = true; | |||||
std::strcpy(fBuffer, strBuf); | |||||
fBuffer[fBufferLen] = '\0'; | fBuffer[fBufferLen] = '\0'; | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
DISTRHO_SAFE_ASSERT(size == 0); | |||||
DISTRHO_SAFE_ASSERT_UINT(size == 0, static_cast<uint>(size)); | |||||
// don't recreate null string | // don't recreate null string | ||||
if (fBuffer == _null()) | |||||
if (! fBufferAlloc) | |||||
return; | return; | ||||
DISTRHO_SAFE_ASSERT(fBuffer != nullptr); | DISTRHO_SAFE_ASSERT(fBuffer != nullptr); | ||||
std::free(fBuffer); | std::free(fBuffer); | ||||
fBuffer = _null(); | |||||
fBufferLen = 0; | |||||
fBuffer = _null(); | |||||
fBufferLen = 0; | |||||
fBufferAlloc = false; | |||||
} | } | ||||
} | } | ||||
@@ -833,12 +912,19 @@ private: | |||||
static inline | static inline | ||||
String operator+(const String& strBefore, const char* const strBufAfter) noexcept | String operator+(const String& strBefore, const char* const strBufAfter) noexcept | ||||
{ | { | ||||
const char* const strBufBefore = strBefore.buffer(); | |||||
const std::size_t newBufSize = strBefore.length() + ((strBufAfter != nullptr) ? std::strlen(strBufAfter) : 0) + 1; | |||||
char newBuf[newBufSize]; | |||||
if (strBufAfter == nullptr || strBufAfter[0] == '\0') | |||||
return strBefore; | |||||
if (strBefore.isEmpty()) | |||||
return String(strBufAfter); | |||||
const std::size_t strBeforeLen = strBefore.length(); | |||||
const std::size_t strBufAfterLen = std::strlen(strBufAfter); | |||||
const std::size_t newBufSize = strBeforeLen + strBufAfterLen; | |||||
char* const newBuf = (char*)malloc(newBufSize + 1); | |||||
DISTRHO_SAFE_ASSERT_RETURN(newBuf != nullptr, String()); | |||||
std::strcpy(newBuf, strBufBefore); | |||||
std::strcat(newBuf, strBufAfter); | |||||
std::memcpy(newBuf, strBefore.buffer(), strBeforeLen); | |||||
std::memcpy(newBuf + strBeforeLen, strBufAfter, strBufAfterLen + 1); | |||||
return String(newBuf); | return String(newBuf); | ||||
} | } | ||||
@@ -846,12 +932,19 @@ String operator+(const String& strBefore, const char* const strBufAfter) noexcep | |||||
static inline | static inline | ||||
String operator+(const char* const strBufBefore, const String& strAfter) noexcept | String operator+(const char* const strBufBefore, const String& strAfter) noexcept | ||||
{ | { | ||||
const char* const strBufAfter = strAfter.buffer(); | |||||
const std::size_t newBufSize = ((strBufBefore != nullptr) ? std::strlen(strBufBefore) : 0) + strAfter.length() + 1; | |||||
char newBuf[newBufSize]; | |||||
std::strcpy(newBuf, strBufBefore); | |||||
std::strcat(newBuf, strBufAfter); | |||||
if (strAfter.isEmpty()) | |||||
return String(strBufBefore); | |||||
if (strBufBefore == nullptr || strBufBefore[0] == '\0') | |||||
return strAfter; | |||||
const std::size_t strBufBeforeLen = std::strlen(strBufBefore); | |||||
const std::size_t strAfterLen = strAfter.length(); | |||||
const std::size_t newBufSize = strBufBeforeLen + strAfterLen; | |||||
char* const newBuf = (char*)malloc(newBufSize + 1); | |||||
DISTRHO_SAFE_ASSERT_RETURN(newBuf != nullptr, String()); | |||||
std::memcpy(newBuf, strBufBefore, strBufBeforeLen); | |||||
std::memcpy(newBuf + strBufBeforeLen, strAfter.buffer(), strAfterLen + 1); | |||||
return String(newBuf); | return String(newBuf); | ||||
} | } | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -88,33 +88,70 @@ public: | |||||
/* | /* | ||||
* Start the thread. | * Start the thread. | ||||
*/ | */ | ||||
bool startThread() noexcept | |||||
bool startThread(const bool withRealtimePriority = false) noexcept | |||||
{ | { | ||||
// check if already running | // check if already running | ||||
DISTRHO_SAFE_ASSERT_RETURN(! isThreadRunning(), true); | DISTRHO_SAFE_ASSERT_RETURN(! isThreadRunning(), true); | ||||
pthread_t handle; | |||||
pthread_attr_t attr; | |||||
pthread_attr_init(&attr); | |||||
struct sched_param sched_param; | |||||
std::memset(&sched_param, 0, sizeof(sched_param)); | |||||
if (withRealtimePriority) | |||||
{ | |||||
sched_param.sched_priority = 80; | |||||
#ifndef DISTRHO_OS_HAIKU | |||||
if (pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) == 0 && | |||||
pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED) == 0 && | |||||
# ifndef DISTRHO_OS_WINDOWS | |||||
(pthread_attr_setschedpolicy(&attr, SCHED_FIFO) == 0 || | |||||
pthread_attr_setschedpolicy(&attr, SCHED_RR) == 0) && | |||||
# endif | |||||
pthread_attr_setschedparam(&attr, &sched_param) == 0) | |||||
{ | |||||
d_stdout("Thread setup with realtime priority successful"); | |||||
} | |||||
else | |||||
#endif | |||||
{ | |||||
d_stdout("Thread setup with realtime priority failed, going with normal priority instead"); | |||||
pthread_attr_destroy(&attr); | |||||
pthread_attr_init(&attr); | |||||
} | |||||
} | |||||
const MutexLocker ml(fLock); | const MutexLocker ml(fLock); | ||||
fShouldExit = false; | fShouldExit = false; | ||||
pthread_t handle; | |||||
bool ok = pthread_create(&handle, &attr, _entryPoint, this) == 0; | |||||
pthread_attr_destroy(&attr); | |||||
if (pthread_create(&handle, nullptr, _entryPoint, this) == 0) | |||||
{ | |||||
if (withRealtimePriority && !ok) | |||||
{ | |||||
d_stdout("Thread with realtime priority failed on creation, going with normal priority instead"); | |||||
pthread_attr_init(&attr); | |||||
ok = pthread_create(&handle, &attr, _entryPoint, this) == 0; | |||||
pthread_attr_destroy(&attr); | |||||
} | |||||
DISTRHO_SAFE_ASSERT_RETURN(ok, false); | |||||
#ifdef PTW32_DLLPORT | #ifdef PTW32_DLLPORT | ||||
DISTRHO_SAFE_ASSERT_RETURN(handle.p != nullptr, false); | |||||
DISTRHO_SAFE_ASSERT_RETURN(handle.p != nullptr, false); | |||||
#else | #else | ||||
DISTRHO_SAFE_ASSERT_RETURN(handle != 0, false); | |||||
DISTRHO_SAFE_ASSERT_RETURN(handle != 0, false); | |||||
#endif | #endif | ||||
pthread_detach(handle); | |||||
_copyFrom(handle); | |||||
pthread_detach(handle); | |||||
_copyFrom(handle); | |||||
// wait for thread to start | |||||
fSignal.wait(); | |||||
return true; | |||||
} | |||||
return false; | |||||
// wait for thread to start | |||||
fSignal.wait(); | |||||
return true; | |||||
} | } | ||||
/* | /* | ||||
@@ -161,10 +198,7 @@ public: | |||||
_copyTo(threadId); | _copyTo(threadId); | ||||
_init(); | _init(); | ||||
try { | |||||
pthread_cancel(threadId); | |||||
} DISTRHO_SAFE_EXCEPTION("pthread_cancel"); | |||||
pthread_detach(threadId); | |||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
@@ -191,6 +225,14 @@ public: | |||||
return fName; | return fName; | ||||
} | } | ||||
/* | |||||
* Returns the Id/handle of the thread. | |||||
*/ | |||||
pthread_t getThreadId() const noexcept | |||||
{ | |||||
return fHandle; | |||||
} | |||||
/* | /* | ||||
* Changes the name of the caller thread. | * Changes the name of the caller thread. | ||||
*/ | */ | ||||
@@ -201,7 +243,7 @@ public: | |||||
#ifdef DISTRHO_OS_LINUX | #ifdef DISTRHO_OS_LINUX | ||||
prctl(PR_SET_NAME, name, 0, 0, 0); | prctl(PR_SET_NAME, name, 0, 0, 0); | ||||
#endif | #endif | ||||
#if defined(__GLIBC__) && (__GLIBC__ * 1000 + __GLIBC_MINOR__) >= 2012 | |||||
#if defined(__GLIBC__) && (__GLIBC__ * 1000 + __GLIBC_MINOR__) >= 2012 && !defined(DISTRHO_OS_GNU_HURD) | |||||
pthread_setname_np(pthread_self(), name); | pthread_setname_np(pthread_self(), name); | ||||
#endif | #endif | ||||
} | } | ||||
@@ -259,7 +301,8 @@ private: | |||||
*/ | */ | ||||
void _runEntryPoint() noexcept | void _runEntryPoint() noexcept | ||||
{ | { | ||||
setCurrentThreadName(fName); | |||||
if (fName.isNotEmpty()) | |||||
setCurrentThreadName(fName); | |||||
// report ready | // report ready | ||||
fSignal.signal(); | fSignal.signal(); | ||||
@@ -281,7 +324,7 @@ private: | |||||
return nullptr; | return nullptr; | ||||
} | } | ||||
DISTRHO_DECLARE_NON_COPY_CLASS(Thread) | |||||
DISTRHO_DECLARE_NON_COPYABLE(Thread) | |||||
}; | }; | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -39,6 +39,10 @@ | |||||
# define DISTRHO_OS_HAIKU 1 | # define DISTRHO_OS_HAIKU 1 | ||||
# elif defined(__linux__) || defined(__linux) | # elif defined(__linux__) || defined(__linux) | ||||
# define DISTRHO_OS_LINUX 1 | # define DISTRHO_OS_LINUX 1 | ||||
# elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) | |||||
# define DISTRHO_OS_BSD 1 | |||||
# elif defined(__GNU__) | |||||
# define DISTRHO_OS_GNU_HURD 1 | |||||
# endif | # endif | ||||
#endif | #endif | ||||
@@ -75,12 +79,35 @@ | |||||
# define DISTRHO_DEPRECATED | # define DISTRHO_DEPRECATED | ||||
#endif | #endif | ||||
/* Define DISTRHO_DEPRECATED_BY */ | |||||
#if defined(__clang__) | |||||
# define DISTRHO_DEPRECATED_BY(other) __attribute__((deprecated("", other))) | |||||
#elif defined(__GNUC__) | |||||
# define DISTRHO_DEPRECATED_BY(other) __attribute__((deprecated("Use " other))) | |||||
#else | |||||
# define DISTRHO_DEPRECATED_BY(other) DISTRHO_DEPRECATED | |||||
#endif | |||||
/* Define DISTRHO_SAFE_ASSERT* */ | /* Define DISTRHO_SAFE_ASSERT* */ | ||||
#define DISTRHO_SAFE_ASSERT(cond) if (! (cond)) d_safe_assert(#cond, __FILE__, __LINE__); | |||||
#define DISTRHO_SAFE_ASSERT(cond) if (! (cond)) d_safe_assert (#cond, __FILE__, __LINE__); | |||||
#define DISTRHO_SAFE_ASSERT_INT(cond, value) if (! (cond)) d_safe_assert_int (#cond, __FILE__, __LINE__, static_cast<int>(value)); | |||||
#define DISTRHO_SAFE_ASSERT_INT2(cond, v1, v2) if (! (cond)) d_safe_assert_int2 (#cond, __FILE__, __LINE__, static_cast<int>(v1), static_cast<int>(v2)); | |||||
#define DISTRHO_SAFE_ASSERT_UINT(cond, value) if (! (cond)) d_safe_assert_uint (#cond, __FILE__, __LINE__, static_cast<uint>(value)); | |||||
#define DISTRHO_SAFE_ASSERT_UINT2(cond, v1, v2) if (! (cond)) d_safe_assert_uint2(#cond, __FILE__, __LINE__, static_cast<uint>(v1), static_cast<uint>(v2)); | |||||
#define DISTRHO_SAFE_ASSERT_BREAK(cond) if (! (cond)) { d_safe_assert(#cond, __FILE__, __LINE__); break; } | #define DISTRHO_SAFE_ASSERT_BREAK(cond) if (! (cond)) { d_safe_assert(#cond, __FILE__, __LINE__); break; } | ||||
#define DISTRHO_SAFE_ASSERT_CONTINUE(cond) if (! (cond)) { d_safe_assert(#cond, __FILE__, __LINE__); continue; } | #define DISTRHO_SAFE_ASSERT_CONTINUE(cond) if (! (cond)) { d_safe_assert(#cond, __FILE__, __LINE__); continue; } | ||||
#define DISTRHO_SAFE_ASSERT_RETURN(cond, ret) if (! (cond)) { d_safe_assert(#cond, __FILE__, __LINE__); return ret; } | #define DISTRHO_SAFE_ASSERT_RETURN(cond, ret) if (! (cond)) { d_safe_assert(#cond, __FILE__, __LINE__); return ret; } | ||||
#define DISTRHO_CUSTOM_SAFE_ASSERT(msg, cond) if (! (cond)) d_custom_safe_assert(msg, #cond, __FILE__, __LINE__); | |||||
#define DISTRHO_CUSTOM_SAFE_ASSERT_BREAK(msg, cond) if (! (cond)) { d_custom_safe_assert(msg, #cond, __FILE__, __LINE__); break; } | |||||
#define DISTRHO_CUSTOM_SAFE_ASSERT_CONTINUE(msg, cond) if (! (cond)) { d_custom_safe_assert(msg, #cond, __FILE__, __LINE__); continue; } | |||||
#define DISTRHO_CUSTOM_SAFE_ASSERT_RETURN(msg, cond, ret) if (! (cond)) { d_custom_safe_assert(msg, #cond, __FILE__, __LINE__); return ret; } | |||||
#define DISTRHO_CUSTOM_SAFE_ASSERT_ONCE_BREAK(msg, cond) if (! (cond)) { static bool _p; if (!_p) { _p = true; d_custom_safe_assert(msg, #cond, __FILE__, __LINE__); } break; } | |||||
#define DISTRHO_CUSTOM_SAFE_ASSERT_ONCE_CONTINUE(msg, cond) if (! (cond)) { static bool _p; if (!_p) { _p = true; d_custom_safe_assert(msg, #cond, __FILE__, __LINE__); } continue; } | |||||
#define DISTRHO_CUSTOM_SAFE_ASSERT_ONCE_RETURN(msg, cond, ret) if (! (cond)) { static bool _p; if (!_p) { _p = true; d_custom_safe_assert(msg, #cond, __FILE__, __LINE__); } return ret; } | |||||
#define DISTRHO_SAFE_ASSERT_INT_BREAK(cond, value) if (! (cond)) { d_safe_assert_int(#cond, __FILE__, __LINE__, static_cast<int>(value); break; } | #define DISTRHO_SAFE_ASSERT_INT_BREAK(cond, value) if (! (cond)) { d_safe_assert_int(#cond, __FILE__, __LINE__, static_cast<int>(value); break; } | ||||
#define DISTRHO_SAFE_ASSERT_INT_CONTINUE(cond, value) if (! (cond)) { d_safe_assert_int(#cond, __FILE__, __LINE__, static_cast<int>(value)); continue; } | #define DISTRHO_SAFE_ASSERT_INT_CONTINUE(cond, value) if (! (cond)) { d_safe_assert_int(#cond, __FILE__, __LINE__, static_cast<int>(value)); continue; } | ||||
#define DISTRHO_SAFE_ASSERT_INT_RETURN(cond, value, ret) if (! (cond)) { d_safe_assert_int(#cond, __FILE__, __LINE__, static_cast<int>(value)); return ret; } | #define DISTRHO_SAFE_ASSERT_INT_RETURN(cond, value, ret) if (! (cond)) { d_safe_assert_int(#cond, __FILE__, __LINE__, static_cast<int>(value)); return ret; } | ||||
@@ -103,39 +130,23 @@ | |||||
#define DISTRHO_SAFE_EXCEPTION_CONTINUE(msg) catch(...) { d_safe_exception(msg, __FILE__, __LINE__); continue; } | #define DISTRHO_SAFE_EXCEPTION_CONTINUE(msg) catch(...) { d_safe_exception(msg, __FILE__, __LINE__); continue; } | ||||
#define DISTRHO_SAFE_EXCEPTION_RETURN(msg, ret) catch(...) { d_safe_exception(msg, __FILE__, __LINE__); return ret; } | #define DISTRHO_SAFE_EXCEPTION_RETURN(msg, ret) catch(...) { d_safe_exception(msg, __FILE__, __LINE__); return ret; } | ||||
/* Define DISTRHO_DECLARE_NON_COPY_CLASS */ | |||||
/* Define DISTRHO_DECLARE_NON_COPYABLE */ | |||||
#ifdef DISTRHO_PROPER_CPP11_SUPPORT | #ifdef DISTRHO_PROPER_CPP11_SUPPORT | ||||
# define DISTRHO_DECLARE_NON_COPY_CLASS(ClassName) \ | |||||
private: \ | |||||
ClassName(ClassName&) = delete; \ | |||||
ClassName(const ClassName&) = delete; \ | |||||
ClassName& operator=(ClassName&) = delete ; \ | |||||
# define DISTRHO_DECLARE_NON_COPYABLE(ClassName) \ | |||||
private: \ | |||||
ClassName(ClassName&) = delete; \ | |||||
ClassName(const ClassName&) = delete; \ | |||||
ClassName& operator=(ClassName&) = delete; \ | |||||
ClassName& operator=(const ClassName&) = delete; | ClassName& operator=(const ClassName&) = delete; | ||||
#else | #else | ||||
# define DISTRHO_DECLARE_NON_COPY_CLASS(ClassName) \ | |||||
private: \ | |||||
ClassName(ClassName&); \ | |||||
ClassName(const ClassName&); \ | |||||
ClassName& operator=(ClassName&); \ | |||||
# define DISTRHO_DECLARE_NON_COPYABLE(ClassName) \ | |||||
private: \ | |||||
ClassName(ClassName&); \ | |||||
ClassName(const ClassName&); \ | |||||
ClassName& operator=(ClassName&); \ | |||||
ClassName& operator=(const ClassName&); | ClassName& operator=(const ClassName&); | ||||
#endif | #endif | ||||
/* Define DISTRHO_DECLARE_NON_COPY_STRUCT */ | |||||
#ifdef DISTRHO_PROPER_CPP11_SUPPORT | |||||
# define DISTRHO_DECLARE_NON_COPY_STRUCT(StructName) \ | |||||
StructName(StructName&) = delete; \ | |||||
StructName(const StructName&) = delete; \ | |||||
StructName& operator=(StructName&) = delete; \ | |||||
StructName& operator=(const StructName&) = delete; | |||||
#else | |||||
# define DISTRHO_DECLARE_NON_COPY_STRUCT(StructName) \ | |||||
private: \ | |||||
StructName(StructName&); \ | |||||
StructName(const StructName&); \ | |||||
StructName& operator=(StructName&); \ | |||||
StructName& operator=(const StructName&); | |||||
#endif | |||||
/* Define DISTRHO_PREVENT_HEAP_ALLOCATION */ | /* Define DISTRHO_PREVENT_HEAP_ALLOCATION */ | ||||
#ifdef DISTRHO_PROPER_CPP11_SUPPORT | #ifdef DISTRHO_PROPER_CPP11_SUPPORT | ||||
# define DISTRHO_PREVENT_HEAP_ALLOCATION \ | # define DISTRHO_PREVENT_HEAP_ALLOCATION \ | ||||
@@ -157,10 +168,27 @@ private: \ | |||||
#define END_NAMESPACE_DISTRHO } | #define END_NAMESPACE_DISTRHO } | ||||
#define USE_NAMESPACE_DISTRHO using namespace DISTRHO_NAMESPACE; | #define USE_NAMESPACE_DISTRHO using namespace DISTRHO_NAMESPACE; | ||||
/* Define DISTRHO_OS_SEP and DISTRHO_OS_SPLIT */ | |||||
#ifdef DISTRHO_OS_WINDOWS | |||||
# define DISTRHO_OS_SEP '\\' | |||||
# define DISTRHO_OS_SEP_STR "\\" | |||||
# define DISTRHO_OS_SPLIT ';' | |||||
# define DISTRHO_OS_SPLIT_STR ";" | |||||
#else | |||||
# define DISTRHO_OS_SEP '/' | |||||
# define DISTRHO_OS_SEP_STR "/" | |||||
# define DISTRHO_OS_SPLIT ':' | |||||
# define DISTRHO_OS_SPLIT_STR ":" | |||||
#endif | |||||
/* Useful typedefs */ | /* Useful typedefs */ | ||||
typedef unsigned char uchar; | typedef unsigned char uchar; | ||||
typedef unsigned short int ushort; | typedef unsigned short int ushort; | ||||
typedef unsigned int uint; | typedef unsigned int uint; | ||||
typedef unsigned long int ulong; | typedef unsigned long int ulong; | ||||
/* Deprecated macros */ | |||||
#define DISTRHO_DECLARE_NON_COPY_CLASS(ClassName) DISTRHO_DECLARE_NON_COPYABLE(ClassName) | |||||
#define DISTRHO_DECLARE_NON_COPY_STRUCT(StructName) DISTRHO_DECLARE_NON_COPYABLE(StructName) | |||||
#endif // DISTRHO_DEFINES_H_INCLUDED | #endif // DISTRHO_DEFINES_H_INCLUDED |
@@ -142,11 +142,12 @@ | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// Enable full state if plugin exports presets | // Enable full state if plugin exports presets | ||||
#if DISTRHO_PLUGIN_WANT_PROGRAMS && DISTRHO_PLUGIN_WANT_STATE && ! DISTRHO_PLUGIN_WANT_FULL_STATE | |||||
# warning Plugins with programs and state need to implement full state API | |||||
# undef DISTRHO_PLUGIN_WANT_FULL_STATE | |||||
# define DISTRHO_PLUGIN_WANT_FULL_STATE 1 | |||||
#endif | |||||
// FIXME | |||||
// #if DISTRHO_PLUGIN_WANT_PROGRAMS && DISTRHO_PLUGIN_WANT_STATE && ! DISTRHO_PLUGIN_WANT_FULL_STATE | |||||
// # warning Plugins with programs and state need to implement full state API | |||||
// # undef DISTRHO_PLUGIN_WANT_FULL_STATE | |||||
// # define DISTRHO_PLUGIN_WANT_FULL_STATE 1 | |||||
// #endif | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// Disable UI if DGL or External UI is not available | // Disable UI if DGL or External UI is not available | ||||
@@ -161,6 +162,14 @@ | |||||
# define DISTRHO_PLUGIN_HAS_UI 0 | # define DISTRHO_PLUGIN_HAS_UI 0 | ||||
#endif | #endif | ||||
// ----------------------------------------------------------------------- | |||||
// Prevent users from messing about with DPF internals | |||||
#ifdef DISTRHO_UI_IS_STANDALONE | |||||
# error DISTRHO_UI_IS_STANDALONE must not be defined | |||||
#endif | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
#endif // DISTRHO_PLUGIN_CHECKS_H_INCLUDED | #endif // DISTRHO_PLUGIN_CHECKS_H_INCLUDED |
@@ -113,7 +113,7 @@ struct Plugin::PrivateData { | |||||
#endif | #endif | ||||
#ifdef DISTRHO_PLUGIN_TARGET_LV2 | #ifdef DISTRHO_PLUGIN_TARGET_LV2 | ||||
# if (DISTRHO_PLUGIN_IS_SYNTH || DISTRHO_PLUGIN_WANT_TIMEPOS || DISTRHO_PLUGIN_WANT_STATE) | |||||
# if (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_TIMEPOS || DISTRHO_PLUGIN_WANT_STATE) | |||||
parameterOffset += 1; | parameterOffset += 1; | ||||
# if DISTRHO_PLUGIN_WANT_STATE | # if DISTRHO_PLUGIN_WANT_STATE | ||||
parameterOffset += 1; | parameterOffset += 1; | ||||
@@ -17,6 +17,7 @@ | |||||
#include "DistrhoPluginInternal.hpp" | #include "DistrhoPluginInternal.hpp" | ||||
#if DISTRHO_PLUGIN_HAS_UI | #if DISTRHO_PLUGIN_HAS_UI | ||||
# define DISTRHO_UI_IS_STANDALONE true | |||||
# include "DistrhoUIInternal.hpp" | # include "DistrhoUIInternal.hpp" | ||||
#else | #else | ||||
# include "../extra/Sleep.hpp" | # include "../extra/Sleep.hpp" | ||||
@@ -81,16 +82,6 @@ static void initSignalHandler() | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
#if DISTRHO_PLUGIN_HAS_UI | |||||
// TODO | |||||
static double getDesktopScaleFactor() noexcept | |||||
{ | |||||
return 1.0; | |||||
} | |||||
#endif | |||||
// ----------------------------------------------------------------------- | |||||
#if DISTRHO_PLUGIN_HAS_UI | #if DISTRHO_PLUGIN_HAS_UI | ||||
class PluginJack : public IdleCallback | class PluginJack : public IdleCallback | ||||
#else | #else | ||||
@@ -110,7 +101,7 @@ public: | |||||
nullptr, // file request | nullptr, // file request | ||||
nullptr, // bundle | nullptr, // bundle | ||||
fPlugin.getInstancePointer(), | fPlugin.getInstancePointer(), | ||||
getDesktopScaleFactor()), | |||||
0.0), | |||||
#endif | #endif | ||||
fClient(client) | fClient(client) | ||||
{ | { | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2020 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -15,6 +15,7 @@ | |||||
*/ | */ | ||||
#include "DistrhoPluginInternal.hpp" | #include "DistrhoPluginInternal.hpp" | ||||
#include "../extra/ScopedSafeLocale.hpp" | |||||
#if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_HAS_EMBED_UI | #if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_HAS_EMBED_UI | ||||
# undef DISTRHO_PLUGIN_HAS_UI | # undef DISTRHO_PLUGIN_HAS_UI | ||||
@@ -22,6 +23,9 @@ | |||||
#endif | #endif | ||||
#if DISTRHO_PLUGIN_HAS_UI | #if DISTRHO_PLUGIN_HAS_UI | ||||
# undef DISTRHO_UI_USER_RESIZABLE | |||||
# define DISTRHO_UI_USER_RESIZABLE 0 | |||||
# define DISTRHO_UI_IS_STANDALONE 0 | |||||
# include "DistrhoUIInternal.hpp" | # include "DistrhoUIInternal.hpp" | ||||
#endif | #endif | ||||
@@ -29,14 +33,16 @@ | |||||
# define __cdecl | # define __cdecl | ||||
#endif | #endif | ||||
#define VESTIGE_HEADER | |||||
#ifndef VESTIGE_HEADER | |||||
# define VESTIGE_HEADER 1 | |||||
#endif | |||||
#define VST_FORCE_DEPRECATED 0 | #define VST_FORCE_DEPRECATED 0 | ||||
#include <clocale> | #include <clocale> | ||||
#include <map> | #include <map> | ||||
#include <string> | #include <string> | ||||
#ifdef VESTIGE_HEADER | |||||
#if VESTIGE_HEADER | |||||
# include "vestige/vestige.h" | # include "vestige/vestige.h" | ||||
#define effFlagsProgramChunks (1 << 5) | #define effFlagsProgramChunks (1 << 5) | ||||
#define effSetProgramName 4 | #define effSetProgramName 4 | ||||
@@ -101,35 +107,11 @@ void snprintf_iparam(char* const dst, const int32_t value, const size_t size) | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
class ScopedSafeLocale { | |||||
public: | |||||
ScopedSafeLocale() noexcept | |||||
: locale(::strdup(::setlocale(LC_NUMERIC, nullptr))) | |||||
{ | |||||
::setlocale(LC_NUMERIC, "C"); | |||||
} | |||||
~ScopedSafeLocale() noexcept | |||||
{ | |||||
if (locale != nullptr) | |||||
{ | |||||
::setlocale(LC_NUMERIC, locale); | |||||
std::free(locale); | |||||
} | |||||
} | |||||
private: | |||||
char* const locale; | |||||
DISTRHO_DECLARE_NON_COPY_CLASS(ScopedSafeLocale) | |||||
DISTRHO_PREVENT_HEAP_ALLOCATION | |||||
}; | |||||
// ----------------------------------------------------------------------- | |||||
class ParameterCheckHelper | |||||
struct ParameterCheckHelper | |||||
{ | { | ||||
public: | |||||
bool* parameterChecks; | |||||
float* parameterValues; | |||||
ParameterCheckHelper() | ParameterCheckHelper() | ||||
: parameterChecks(nullptr), | : parameterChecks(nullptr), | ||||
parameterValues(nullptr) {} | parameterValues(nullptr) {} | ||||
@@ -148,9 +130,6 @@ public: | |||||
} | } | ||||
} | } | ||||
bool* parameterChecks; | |||||
float* parameterValues; | |||||
#if DISTRHO_PLUGIN_WANT_STATE | #if DISTRHO_PLUGIN_WANT_STATE | ||||
virtual void setStateFromUI(const char* const newKey, const char* const newValue) = 0; | virtual void setStateFromUI(const char* const newKey, const char* const newValue) = 0; | ||||
#endif | #endif | ||||
@@ -181,19 +160,8 @@ public: | |||||
nullptr, | nullptr, | ||||
plugin->getInstancePointer(), | plugin->getInstancePointer(), | ||||
scaleFactor), | scaleFactor), | ||||
fShouldCaptureVstKeys(false) | |||||
fKeyboardModifiers(0) | |||||
{ | { | ||||
// FIXME only needed for windows? | |||||
//#ifdef DISTRHO_OS_WINDOWS | |||||
char strBuf[0xff+1]; | |||||
std::memset(strBuf, 0, sizeof(char)*(0xff+1)); | |||||
hostCallback(audioMasterGetProductString, 0, 0, strBuf); | |||||
d_stdout("Plugin UI running in '%s'", strBuf); | |||||
// TODO make a white-list of needed hosts | |||||
if (/*std::strcmp(strBuf, "") == 0*/ true) | |||||
fShouldCaptureVstKeys = true; | |||||
//#endif | |||||
} | } | ||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
@@ -237,12 +205,9 @@ public: | |||||
} | } | ||||
# endif | # endif | ||||
# if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
int handlePluginKeyEvent(const bool down, int32_t index, const intptr_t value) | int handlePluginKeyEvent(const bool down, int32_t index, const intptr_t value) | ||||
{ | { | ||||
# if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
if (! fShouldCaptureVstKeys) | |||||
return 0; | |||||
d_stdout("handlePluginKeyEvent %i %i %li\n", down, index, (long int)value); | d_stdout("handlePluginKeyEvent %i %i %li\n", down, index, (long int)value); | ||||
using namespace DGL_NAMESPACE; | using namespace DGL_NAMESPACE; | ||||
@@ -250,62 +215,127 @@ public: | |||||
int special = 0; | int special = 0; | ||||
switch (value) | switch (value) | ||||
{ | { | ||||
// convert some specials to normal keys | |||||
case 1: index = kCharBackspace; break; | |||||
case 6: index = kCharEscape; break; | |||||
case 7: index = ' '; break; | |||||
case 22: index = kCharDelete; break; | |||||
// convert some VST special values to normal keys | |||||
case 1: index = kKeyBackspace; break; | |||||
case 2: index = '\t'; break; | |||||
// 3 clear | |||||
case 4: index = '\r'; break; | |||||
case 6: index = kKeyEscape; break; | |||||
case 7: index = ' '; break; | |||||
// 8 next | |||||
// 17 select | |||||
// 18 print | |||||
case 19: index = '\n'; break; | |||||
// 20 snapshot | |||||
case 22: index = kKeyDelete; break; | |||||
// 23 help | |||||
case 57: index = '='; break; | |||||
// numpad stuff follows | |||||
case 24: index = '0'; break; | |||||
case 25: index = '1'; break; | |||||
case 26: index = '2'; break; | |||||
case 27: index = '3'; break; | |||||
case 28: index = '4'; break; | |||||
case 29: index = '5'; break; | |||||
case 30: index = '6'; break; | |||||
case 31: index = '7'; break; | |||||
case 32: index = '8'; break; | |||||
case 33: index = '9'; break; | |||||
case 34: index = '*'; break; | |||||
case 35: index = '+'; break; | |||||
// 36 separator | |||||
case 37: index = '-'; break; | |||||
case 38: index = '.'; break; | |||||
case 39: index = '/'; break; | |||||
// handle rest of special keys | // handle rest of special keys | ||||
case 40: special = kKeyF1; break; | |||||
case 41: special = kKeyF2; break; | |||||
case 42: special = kKeyF3; break; | |||||
case 43: special = kKeyF4; break; | |||||
case 44: special = kKeyF5; break; | |||||
case 45: special = kKeyF6; break; | |||||
case 46: special = kKeyF7; break; | |||||
case 47: special = kKeyF8; break; | |||||
case 48: special = kKeyF9; break; | |||||
case 49: special = kKeyF10; break; | |||||
case 50: special = kKeyF11; break; | |||||
case 51: special = kKeyF12; break; | |||||
case 11: special = kKeyLeft; break; | |||||
case 12: special = kKeyUp; break; | |||||
case 13: special = kKeyRight; break; | |||||
case 14: special = kKeyDown; break; | |||||
case 15: special = kKeyPageUp; break; | |||||
case 16: special = kKeyPageDown; break; | |||||
case 10: special = kKeyHome; break; | |||||
case 9: special = kKeyEnd; break; | |||||
case 21: special = kKeyInsert; break; | |||||
case 54: special = kKeyShift; break; | |||||
case 55: special = kKeyControl; break; | |||||
case 56: special = kKeyAlt; break; | |||||
/* these special keys are missing: | |||||
- kKeySuper | |||||
- kKeyCapsLock | |||||
- kKeyPrintScreen | |||||
*/ | |||||
case 40: special = kKeyF1; break; | |||||
case 41: special = kKeyF2; break; | |||||
case 42: special = kKeyF3; break; | |||||
case 43: special = kKeyF4; break; | |||||
case 44: special = kKeyF5; break; | |||||
case 45: special = kKeyF6; break; | |||||
case 46: special = kKeyF7; break; | |||||
case 47: special = kKeyF8; break; | |||||
case 48: special = kKeyF9; break; | |||||
case 49: special = kKeyF10; break; | |||||
case 50: special = kKeyF11; break; | |||||
case 51: special = kKeyF12; break; | |||||
case 11: special = kKeyLeft; break; | |||||
case 12: special = kKeyUp; break; | |||||
case 13: special = kKeyRight; break; | |||||
case 14: special = kKeyDown; break; | |||||
case 15: special = kKeyPageUp; break; | |||||
case 16: special = kKeyPageDown; break; | |||||
case 10: special = kKeyHome; break; | |||||
case 9: special = kKeyEnd; break; | |||||
case 21: special = kKeyInsert; break; | |||||
case 54: special = kKeyShift; break; | |||||
case 55: special = kKeyControl; break; | |||||
case 56: special = kKeyAlt; break; | |||||
case 58: special = kKeyMenu; break; | |||||
case 52: special = kKeyNumLock; break; | |||||
case 53: special = kKeyScrollLock; break; | |||||
case 5: special = kKeyPause; break; | |||||
} | |||||
switch (special) | |||||
{ | |||||
case kKeyShift: | |||||
if (down) | |||||
fKeyboardModifiers |= kModifierShift; | |||||
else | |||||
fKeyboardModifiers &= ~kModifierShift; | |||||
break; | |||||
case kKeyControl: | |||||
if (down) | |||||
fKeyboardModifiers |= kModifierControl; | |||||
else | |||||
fKeyboardModifiers &= ~kModifierControl; | |||||
break; | |||||
case kKeyAlt: | |||||
if (down) | |||||
fKeyboardModifiers |= kModifierAlt; | |||||
else | |||||
fKeyboardModifiers &= ~kModifierAlt; | |||||
break; | |||||
} | } | ||||
if (special != 0) | if (special != 0) | ||||
return fUI.handlePluginSpecial(down, static_cast<Key>(special)); | |||||
{ | |||||
fUI.handlePluginSpecial(down, static_cast<Key>(special), fKeyboardModifiers); | |||||
return 1; | |||||
} | |||||
if (index >= 0) | |||||
return fUI.handlePluginKeyboard(down, static_cast<uint>(index)); | |||||
# endif | |||||
if (index > 0) | |||||
{ | |||||
fUI.handlePluginKeyboard(down, static_cast<uint>(index), fKeyboardModifiers); | |||||
return 1; | |||||
} | |||||
return 0; | return 0; | ||||
} | } | ||||
# endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
protected: | protected: | ||||
intptr_t hostCallback(const int32_t opcode, | |||||
const int32_t index = 0, | |||||
const intptr_t value = 0, | |||||
void* const ptr = nullptr, | |||||
const float opt = 0.0f) | |||||
inline intptr_t hostCallback(const int32_t opcode, | |||||
const int32_t index = 0, | |||||
const intptr_t value = 0, | |||||
void* const ptr = nullptr, | |||||
const float opt = 0.0f) const | |||||
{ | { | ||||
return fAudioMaster(fEffect, opcode, index, value, ptr, opt); | return fAudioMaster(fEffect, opcode, index, value, ptr, opt); | ||||
} | } | ||||
void editParameter(const uint32_t index, const bool started) | |||||
void editParameter(const uint32_t index, const bool started) const | |||||
{ | { | ||||
hostCallback(started ? audioMasterBeginEdit : audioMasterEndEdit, index); | hostCallback(started ? audioMasterBeginEdit : audioMasterEndEdit, index); | ||||
} | } | ||||
@@ -357,7 +387,7 @@ private: | |||||
// Plugin UI | // Plugin UI | ||||
UIExporter fUI; | UIExporter fUI; | ||||
bool fShouldCaptureVstKeys; | |||||
uint16_t fKeyboardModifiers; | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
// Callbacks | // Callbacks | ||||
@@ -654,12 +684,12 @@ public: | |||||
} | } | ||||
break; | break; | ||||
//case effIdle: | |||||
case effEditIdle: | case effEditIdle: | ||||
if (fVstUI != nullptr) | if (fVstUI != nullptr) | ||||
fVstUI->idle(); | fVstUI->idle(); | ||||
break; | break; | ||||
# if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
case effEditKeyDown: | case effEditKeyDown: | ||||
if (fVstUI != nullptr) | if (fVstUI != nullptr) | ||||
return fVstUI->handlePluginKeyEvent(true, index, value); | return fVstUI->handlePluginKeyEvent(true, index, value); | ||||
@@ -669,6 +699,7 @@ public: | |||||
if (fVstUI != nullptr) | if (fVstUI != nullptr) | ||||
return fVstUI->handlePluginKeyEvent(false, index, value); | return fVstUI->handlePluginKeyEvent(false, index, value); | ||||
break; | break; | ||||
# endif | |||||
#endif // DISTRHO_PLUGIN_HAS_UI | #endif // DISTRHO_PLUGIN_HAS_UI | ||||
#if DISTRHO_PLUGIN_WANT_STATE | #if DISTRHO_PLUGIN_WANT_STATE | ||||
@@ -724,9 +755,6 @@ public: | |||||
// add another separator | // add another separator | ||||
chunkStr += "\xff"; | chunkStr += "\xff"; | ||||
// temporarily set locale to "C" while converting floats | |||||
const ScopedSafeLocale ssl; | |||||
for (uint32_t i=0; i<paramCount; ++i) | for (uint32_t i=0; i<paramCount; ++i) | ||||
{ | { | ||||
if (fPlugin.isParameterOutputOrTrigger(i)) | if (fPlugin.isParameterOutputOrTrigger(i)) | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2020 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -14,15 +14,18 @@ | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
*/ | */ | ||||
#include "DistrhoUIInternal.hpp" | |||||
#include "DistrhoUIPrivateData.hpp" | |||||
#include "src/WindowPrivateData.hpp" | |||||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | ||||
# include "src/WidgetPrivateData.hpp" | |||||
# include "src/TopLevelWidgetPrivateData.hpp" | |||||
#endif | #endif | ||||
#include "NanoVG.hpp" | |||||
START_NAMESPACE_DISTRHO | START_NAMESPACE_DISTRHO | ||||
/* ------------------------------------------------------------------------------------------------------------ | /* ------------------------------------------------------------------------------------------------------------ | ||||
* Static data, see DistrhoUIInternal.hpp */ | |||||
* Static data, see DistrhoUIInternal.hpp and DistrhoUIPrivateData.hpp */ | |||||
double d_lastUiSampleRate = 0.0; | double d_lastUiSampleRate = 0.0; | ||||
void* d_lastUiDspPtr = nullptr; | void* d_lastUiDspPtr = nullptr; | ||||
@@ -34,20 +37,46 @@ uintptr_t g_nextWindowId = 0; | |||||
Window* d_lastUiWindow = nullptr; | Window* d_lastUiWindow = nullptr; | ||||
#endif | #endif | ||||
// ----------------------------------------------------------------------------------------------------------- | |||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
UI* createUiWrapper(void* const dspPtr, const uintptr_t winId, const double scaleFactor, const char* const bundlePath) | |||||
{ | |||||
d_lastUiDspPtr = dspPtr; | |||||
g_nextWindowId = winId; | |||||
g_nextScaleFactor = scaleFactor; | |||||
g_nextBundlePath = bundlePath; | |||||
UI* const ret = createUI(); | |||||
d_lastUiDspPtr = nullptr; | |||||
g_nextWindowId = 0; | |||||
g_nextScaleFactor = 1.0; | |||||
g_nextBundlePath = nullptr; | |||||
return ret; | |||||
} | |||||
#else | |||||
UI* createUiWrapper(void* const dspPtr, Window* const window) | |||||
{ | |||||
d_lastUiDspPtr = dspPtr; | |||||
d_lastUiWindow = window; | |||||
UI* const ret = createUI(); | |||||
d_lastUiDspPtr = nullptr; | |||||
d_lastUiWindow = nullptr; | |||||
return ret; | |||||
} | |||||
#endif // DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
/* ------------------------------------------------------------------------------------------------------------ | /* ------------------------------------------------------------------------------------------------------------ | ||||
* UI */ | * UI */ | ||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | ||||
UI::UI(uint width, uint height) | UI::UI(uint width, uint height) | ||||
: UIWidget(width, height), | : UIWidget(width, height), | ||||
pData(new PrivateData()) {} | |||||
uiData(new PrivateData()) {} | |||||
#else | #else | ||||
UI::UI(uint width, uint height) | UI::UI(uint width, uint height) | ||||
: UIWidget(*d_lastUiWindow), | : UIWidget(*d_lastUiWindow), | ||||
pData(new PrivateData()) | |||||
uiData(new PrivateData()) | |||||
{ | { | ||||
((UIWidget*)this)->pData->needsFullViewport = false; | |||||
if (width > 0 && height > 0) | if (width > 0 && height > 0) | ||||
setSize(width, height); | setSize(width, height); | ||||
} | } | ||||
@@ -55,75 +84,55 @@ UI::UI(uint width, uint height) | |||||
UI::~UI() | UI::~UI() | ||||
{ | { | ||||
delete pData; | |||||
} | |||||
#if DISTRHO_UI_USER_RESIZABLE && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
void UI::setGeometryConstraints(uint minWidth, uint minHeight, bool keepAspectRatio, bool automaticallyScale) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT_RETURN(minWidth > 0,); | |||||
DISTRHO_SAFE_ASSERT_RETURN(minHeight > 0,); | |||||
pData->automaticallyScale = automaticallyScale; | |||||
pData->minWidth = minWidth; | |||||
pData->minHeight = minHeight; | |||||
Window& window(getParentWindow()); | |||||
const double uiScaleFactor = window.getScaling(); | |||||
window.setGeometryConstraints(minWidth * uiScaleFactor, minHeight * uiScaleFactor, keepAspectRatio); | |||||
if (d_isNotZero(uiScaleFactor - 1.0)) | |||||
setSize(getWidth() * uiScaleFactor, getHeight() * uiScaleFactor); | |||||
delete uiData; | |||||
} | } | ||||
#endif | |||||
/* ------------------------------------------------------------------------------------------------------------ | /* ------------------------------------------------------------------------------------------------------------ | ||||
* Host state */ | * Host state */ | ||||
uint UI::getBackgroundColor() const noexcept | uint UI::getBackgroundColor() const noexcept | ||||
{ | { | ||||
return pData->bgColor; | |||||
return uiData->bgColor; | |||||
} | } | ||||
uint UI::getForegroundColor() const noexcept | uint UI::getForegroundColor() const noexcept | ||||
{ | { | ||||
return pData->fgColor; | |||||
return uiData->fgColor; | |||||
} | } | ||||
double UI::getSampleRate() const noexcept | double UI::getSampleRate() const noexcept | ||||
{ | { | ||||
return pData->sampleRate; | |||||
return uiData->sampleRate; | |||||
} | } | ||||
void UI::editParameter(uint32_t index, bool started) | void UI::editParameter(uint32_t index, bool started) | ||||
{ | { | ||||
pData->editParamCallback(index + pData->parameterOffset, started); | |||||
uiData->editParamCallback(index + uiData->parameterOffset, started); | |||||
} | } | ||||
void UI::setParameterValue(uint32_t index, float value) | void UI::setParameterValue(uint32_t index, float value) | ||||
{ | { | ||||
pData->setParamCallback(index + pData->parameterOffset, value); | |||||
uiData->setParamCallback(index + uiData->parameterOffset, value); | |||||
} | } | ||||
#if DISTRHO_PLUGIN_WANT_STATE | #if DISTRHO_PLUGIN_WANT_STATE | ||||
void UI::setState(const char* key, const char* value) | void UI::setState(const char* key, const char* value) | ||||
{ | { | ||||
pData->setStateCallback(key, value); | |||||
uiData->setStateCallback(key, value); | |||||
} | } | ||||
#endif | #endif | ||||
#if DISTRHO_PLUGIN_WANT_STATEFILES | #if DISTRHO_PLUGIN_WANT_STATEFILES | ||||
bool UI::requestStateFile(const char* key) | bool UI::requestStateFile(const char* key) | ||||
{ | { | ||||
return pData->fileRequestCallback(key); | |||||
return uiData->fileRequestCallback(key); | |||||
} | } | ||||
#endif | #endif | ||||
#if DISTRHO_PLUGIN_WANT_MIDI_INPUT | #if DISTRHO_PLUGIN_WANT_MIDI_INPUT | ||||
void UI::sendNote(uint8_t channel, uint8_t note, uint8_t velocity) | void UI::sendNote(uint8_t channel, uint8_t note, uint8_t velocity) | ||||
{ | { | ||||
pData->sendNoteCallback(channel, note, velocity); | |||||
uiData->sendNoteCallback(channel, note, velocity); | |||||
} | } | ||||
#endif | #endif | ||||
@@ -133,7 +142,7 @@ void UI::sendNote(uint8_t channel, uint8_t note, uint8_t velocity) | |||||
void* UI::getPluginInstancePointer() const noexcept | void* UI::getPluginInstancePointer() const noexcept | ||||
{ | { | ||||
return pData->dspPtr; | |||||
return uiData->dspPtr; | |||||
} | } | ||||
#endif | #endif | ||||
@@ -157,7 +166,7 @@ uintptr_t UI::getNextWindowId() noexcept | |||||
return g_nextWindowId; | return g_nextWindowId; | ||||
} | } | ||||
# endif | # endif | ||||
#endif | |||||
#endif // DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
/* ------------------------------------------------------------------------------------------------------------ | /* ------------------------------------------------------------------------------------------------------------ | ||||
* DSP/Plugin Callbacks (optional) */ | * DSP/Plugin Callbacks (optional) */ | ||||
@@ -174,22 +183,10 @@ void UI::uiFileBrowserSelected(const char*) | |||||
} | } | ||||
# endif | # endif | ||||
void UI::uiReshape(uint width, uint height) | |||||
{ | |||||
#ifdef DGL_OPENGL | |||||
glEnable(GL_BLEND); | |||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |||||
glMatrixMode(GL_PROJECTION); | |||||
glLoadIdentity(); | |||||
glOrtho(0.0, static_cast<GLdouble>(width), static_cast<GLdouble>(height), 0.0, 0.0, 1.0); | |||||
glViewport(0, 0, static_cast<GLsizei>(width), static_cast<GLsizei>(height)); | |||||
glMatrixMode(GL_MODELVIEW); | |||||
glLoadIdentity(); | |||||
#else | |||||
// unused | |||||
(void)width; | |||||
(void)height; | |||||
#endif | |||||
void UI::uiReshape(uint, uint) | |||||
{ | |||||
// NOTE this must be the same as Window::onReshape | |||||
pData->fallbackOnResize(); | |||||
} | } | ||||
/* ------------------------------------------------------------------------------------------------------------ | /* ------------------------------------------------------------------------------------------------------------ | ||||
@@ -197,13 +194,28 @@ void UI::uiReshape(uint width, uint height) | |||||
void UI::onResize(const ResizeEvent& ev) | void UI::onResize(const ResizeEvent& ev) | ||||
{ | { | ||||
if (pData->resizeInProgress) | |||||
if (uiData->resizeInProgress) | |||||
return; | return; | ||||
pData->setSizeCallback(ev.size.getWidth(), ev.size.getHeight()); | |||||
UIWidget::onResize(ev); | |||||
const uint width = ev.size.getWidth(); | |||||
const uint height = ev.size.getHeight(); | |||||
/* | |||||
pData->window.setSize(width, height); | |||||
*/ | |||||
uiData->setSizeCallback(width, height); | |||||
} | } | ||||
#endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | #endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | ||||
// ----------------------------------------------------------------------------------------------------------- | // ----------------------------------------------------------------------------------------------------------- | ||||
END_NAMESPACE_DISTRHO | END_NAMESPACE_DISTRHO | ||||
// ----------------------------------------------------------------------- | |||||
// Possible template data types | |||||
// template class NanoBaseWidget<SubWidget>; | |||||
// template class NanoBaseWidget<TopLevelWidget>; | |||||
// template class NanoBaseWidget<StandaloneWindow>; |
@@ -14,6 +14,7 @@ | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
*/ | */ | ||||
#define DISTRHO_UI_IS_STANDALONE 1 | |||||
#include "DistrhoUIInternal.hpp" | #include "DistrhoUIInternal.hpp" | ||||
#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2020 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -17,7 +17,7 @@ | |||||
#ifndef DISTRHO_UI_INTERNAL_HPP_INCLUDED | #ifndef DISTRHO_UI_INTERNAL_HPP_INCLUDED | ||||
#define DISTRHO_UI_INTERNAL_HPP_INCLUDED | #define DISTRHO_UI_INTERNAL_HPP_INCLUDED | ||||
#include "../DistrhoUI.hpp" | |||||
#include "DistrhoUIPrivateData.hpp" | |||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | ||||
# include "../extra/Sleep.hpp" | # include "../extra/Sleep.hpp" | ||||
@@ -46,163 +46,48 @@ extern Window* d_lastUiWindow; | |||||
#endif | #endif | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// UI callbacks | |||||
typedef void (*editParamFunc) (void* ptr, uint32_t rindex, bool started); | |||||
typedef void (*setParamFunc) (void* ptr, uint32_t rindex, float value); | |||||
typedef void (*setStateFunc) (void* ptr, const char* key, const char* value); | |||||
typedef void (*sendNoteFunc) (void* ptr, uint8_t channel, uint8_t note, uint8_t velo); | |||||
typedef void (*setSizeFunc) (void* ptr, uint width, uint height); | |||||
typedef bool (*fileRequestFunc) (void* ptr, const char* key); | |||||
// ----------------------------------------------------------------------- | |||||
// UI private data | |||||
struct UI::PrivateData { | |||||
// DSP | |||||
double sampleRate; | |||||
uint32_t parameterOffset; | |||||
#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||||
void* dspPtr; | |||||
#endif | |||||
// UI | |||||
bool automaticallyScale; | |||||
bool resizeInProgress; | |||||
uint minWidth; | |||||
uint minHeight; | |||||
uint bgColor; | |||||
uint fgColor; | |||||
// Callbacks | |||||
void* callbacksPtr; | |||||
editParamFunc editParamCallbackFunc; | |||||
setParamFunc setParamCallbackFunc; | |||||
setStateFunc setStateCallbackFunc; | |||||
sendNoteFunc sendNoteCallbackFunc; | |||||
setSizeFunc setSizeCallbackFunc; | |||||
fileRequestFunc fileRequestCallbackFunc; | |||||
PrivateData() noexcept | |||||
: sampleRate(d_lastUiSampleRate), | |||||
parameterOffset(0), | |||||
#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||||
dspPtr(d_lastUiDspPtr), | |||||
#endif | |||||
automaticallyScale(false), | |||||
resizeInProgress(false), | |||||
minWidth(0), | |||||
minHeight(0), | |||||
bgColor(0), | |||||
fgColor(0), | |||||
callbacksPtr(nullptr), | |||||
editParamCallbackFunc(nullptr), | |||||
setParamCallbackFunc(nullptr), | |||||
setStateCallbackFunc(nullptr), | |||||
sendNoteCallbackFunc(nullptr), | |||||
setSizeCallbackFunc(nullptr), | |||||
fileRequestCallbackFunc(nullptr) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT(d_isNotZero(sampleRate)); | |||||
#if defined(DISTRHO_PLUGIN_TARGET_DSSI) || defined(DISTRHO_PLUGIN_TARGET_LV2) | |||||
parameterOffset += DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS; | |||||
# if DISTRHO_PLUGIN_WANT_LATENCY | |||||
parameterOffset += 1; | |||||
# endif | |||||
#endif | |||||
#ifdef DISTRHO_PLUGIN_TARGET_LV2 | |||||
# if (DISTRHO_PLUGIN_IS_SYNTH || DISTRHO_PLUGIN_WANT_TIMEPOS || DISTRHO_PLUGIN_WANT_STATE) | |||||
parameterOffset += 1; | |||||
# if DISTRHO_PLUGIN_WANT_STATE | |||||
parameterOffset += 1; | |||||
# endif | |||||
# endif | |||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
UI* createUiWrapper(void* dspPtr, uintptr_t winId, double scaleFactor, const char* bundlePath); | |||||
#else // DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
UI* createUiWrapper(void* dspPtr, Window* window); | |||||
#endif | #endif | ||||
} | |||||
void editParamCallback(const uint32_t rindex, const bool started) | |||||
{ | |||||
if (editParamCallbackFunc != nullptr) | |||||
editParamCallbackFunc(callbacksPtr, rindex, started); | |||||
} | |||||
void setParamCallback(const uint32_t rindex, const float value) | |||||
{ | |||||
if (setParamCallbackFunc != nullptr) | |||||
setParamCallbackFunc(callbacksPtr, rindex, value); | |||||
} | |||||
void setStateCallback(const char* const key, const char* const value) | |||||
{ | |||||
if (setStateCallbackFunc != nullptr) | |||||
setStateCallbackFunc(callbacksPtr, key, value); | |||||
} | |||||
void sendNoteCallback(const uint8_t channel, const uint8_t note, const uint8_t velocity) | |||||
{ | |||||
if (sendNoteCallbackFunc != nullptr) | |||||
sendNoteCallbackFunc(callbacksPtr, channel, note, velocity); | |||||
} | |||||
void setSizeCallback(const uint width, const uint height) | |||||
{ | |||||
if (setSizeCallbackFunc != nullptr) | |||||
setSizeCallbackFunc(callbacksPtr, width, height); | |||||
} | |||||
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
// ----------------------------------------------------------------------- | |||||
// Plugin Application, will set class name based on plugin details | |||||
bool fileRequestCallback(const char* key) | |||||
class PluginApplication : public Application | |||||
{ | |||||
public: | |||||
PluginApplication() | |||||
: Application(DISTRHO_UI_IS_STANDALONE) | |||||
{ | { | ||||
if (fileRequestCallbackFunc != nullptr) | |||||
return fileRequestCallbackFunc(callbacksPtr, key); | |||||
// TODO use old style DPF dialog here | |||||
return false; | |||||
const char* const className = ( | |||||
#ifdef DISTRHO_PLUGIN_BRAND | |||||
DISTRHO_PLUGIN_BRAND | |||||
#else | |||||
DISTRHO_MACRO_AS_STRING(DISTRHO_NAMESPACE) | |||||
#endif | |||||
"-" DISTRHO_PLUGIN_NAME | |||||
); | |||||
setClassName(className); | |||||
} | } | ||||
}; | }; | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// Plugin Window, needed to take care of resize properly | // Plugin Window, needed to take care of resize properly | ||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
static inline | |||||
UI* createUiWrapper(void* const dspPtr, const uintptr_t winId, const double scaleFactor, const char* const bundlePath) | |||||
{ | |||||
d_lastUiDspPtr = dspPtr; | |||||
g_nextWindowId = winId; | |||||
g_nextScaleFactor = scaleFactor; | |||||
g_nextBundlePath = bundlePath; | |||||
UI* const ret = createUI(); | |||||
d_lastUiDspPtr = nullptr; | |||||
g_nextWindowId = 0; | |||||
g_nextScaleFactor = 1.0; | |||||
g_nextBundlePath = nullptr; | |||||
return ret; | |||||
} | |||||
#else // DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
static inline | |||||
UI* createUiWrapper(void* const dspPtr, Window* const window) | |||||
{ | |||||
d_lastUiDspPtr = dspPtr; | |||||
d_lastUiWindow = window; | |||||
UI* const ret = createUI(); | |||||
d_lastUiDspPtr = nullptr; | |||||
d_lastUiWindow = nullptr; | |||||
return ret; | |||||
} | |||||
class UIExporterWindow : public Window | class UIExporterWindow : public Window | ||||
{ | { | ||||
public: | public: | ||||
UIExporterWindow(Application& app, const intptr_t winId, const double scaleFactor, void* const dspPtr) | |||||
UIExporterWindow(PluginApplication& app, const intptr_t winId, const double scaleFactor, void* const dspPtr) | |||||
: Window(app, winId, scaleFactor, DISTRHO_UI_USER_RESIZABLE), | : Window(app, winId, scaleFactor, DISTRHO_UI_USER_RESIZABLE), | ||||
fUI(createUiWrapper(dspPtr, this)), | fUI(createUiWrapper(dspPtr, this)), | ||||
fIsReady(false) | fIsReady(false) | ||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | ||||
DISTRHO_SAFE_ASSERT_RETURN(fUI->pData != nullptr,); | |||||
DISTRHO_SAFE_ASSERT_RETURN(fUI->uiData != nullptr,); | |||||
setSize(fUI->getWidth(), fUI->getHeight()); | setSize(fUI->getWidth(), fUI->getHeight()); | ||||
} | } | ||||
@@ -228,19 +113,14 @@ protected: | |||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | ||||
UI::PrivateData* const pData = fUI->pData; | |||||
DISTRHO_SAFE_ASSERT_RETURN(pData != nullptr,); | |||||
if (pData->automaticallyScale) | |||||
{ | |||||
const double scaleHorizontal = static_cast<double>(width) / static_cast<double>(pData->minWidth); | |||||
const double scaleVertical = static_cast<double>(height) / static_cast<double>(pData->minHeight); | |||||
_setAutoScaling(scaleHorizontal < scaleVertical ? scaleHorizontal : scaleVertical); | |||||
} | |||||
UI::PrivateData* const uiData = fUI->uiData; | |||||
DISTRHO_SAFE_ASSERT_RETURN(uiData != nullptr,); | |||||
pData->resizeInProgress = true; | |||||
/* | |||||
uiData->resizeInProgress = true; | |||||
fUI->setSize(width, height); | fUI->setSize(width, height); | ||||
pData->resizeInProgress = false; | |||||
uiData->resizeInProgress = false; | |||||
*/ | |||||
fUI->uiReshape(width, height); | fUI->uiReshape(width, height); | ||||
fIsReady = true; | fIsReady = true; | ||||
@@ -248,7 +128,7 @@ protected: | |||||
# ifndef DGL_FILE_BROWSER_DISABLED | # ifndef DGL_FILE_BROWSER_DISABLED | ||||
// custom file-browser selected | // custom file-browser selected | ||||
void fileBrowserSelected(const char* filename) override | |||||
void onFileSelected(const char* const filename) override | |||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | ||||
@@ -278,7 +158,7 @@ public: | |||||
const fileRequestFunc fileRequestCall, | const fileRequestFunc fileRequestCall, | ||||
const char* const bundlePath = nullptr, | const char* const bundlePath = nullptr, | ||||
void* const dspPtr = nullptr, | void* const dspPtr = nullptr, | ||||
const float scaleFactor = 1.0f, | |||||
const double scaleFactor = 1.0, | |||||
const uint32_t bgColor = 0, | const uint32_t bgColor = 0, | ||||
const uint32_t fgColor = 0xffffffff) | const uint32_t fgColor = 0xffffffff) | ||||
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | ||||
@@ -289,7 +169,7 @@ public: | |||||
fChangingSize(false), | fChangingSize(false), | ||||
fUI(glWindow.getUI()), | fUI(glWindow.getUI()), | ||||
#endif | #endif | ||||
fData((fUI != nullptr) ? fUI->pData : nullptr) | |||||
fData((fUI != nullptr) ? fUI->uiData : nullptr) | |||||
{ | { | ||||
DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | ||||
DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,); | ||||
@@ -339,7 +219,7 @@ public: | |||||
return fUI->isRunning(); | return fUI->isRunning(); | ||||
} | } | ||||
intptr_t getWindowId() const noexcept | |||||
uintptr_t getNativeWindowHandle() const noexcept | |||||
{ | { | ||||
return 0; | return 0; | ||||
} | } | ||||
@@ -359,9 +239,9 @@ public: | |||||
return glWindow.isVisible(); | return glWindow.isVisible(); | ||||
} | } | ||||
intptr_t getWindowId() const noexcept | |||||
uintptr_t getNativeWindowHandle() const noexcept | |||||
{ | { | ||||
return glWindow.getWindowId(); | |||||
return glWindow.getNativeWindowHandle(); | |||||
} | } | ||||
#endif | #endif | ||||
@@ -461,8 +341,8 @@ public: | |||||
DISTRHO_SAFE_ASSERT_RETURN(cb != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(cb != nullptr,); | ||||
DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,); | ||||
glWindow.addIdleCallback(cb); | |||||
glWindow.setVisible(true); | glWindow.setVisible(true); | ||||
glApp.addIdleCallback(cb); | |||||
glApp.exec(); | glApp.exec(); | ||||
} | } | ||||
@@ -549,9 +429,11 @@ public: | |||||
fChangingSize = false; | fChangingSize = false; | ||||
} | } | ||||
void setWindowTransientWinId(const uintptr_t winId) | |||||
void setWindowTransientWinId(const uintptr_t /*winId*/) | |||||
{ | { | ||||
#if 0 /* TODO */ | |||||
glWindow.setTransientWinId(winId); | glWindow.setTransientWinId(winId); | ||||
#endif | |||||
} | } | ||||
bool setWindowVisible(const bool yesNo) | bool setWindowVisible(const bool yesNo) | ||||
@@ -561,14 +443,20 @@ public: | |||||
return ! glApp.isQuiting(); | return ! glApp.isQuiting(); | ||||
} | } | ||||
bool handlePluginKeyboard(const bool press, const uint key) | |||||
bool handlePluginKeyboard(const bool /*press*/, const uint /*key*/, const uint16_t /*mods*/) | |||||
{ | { | ||||
#if 0 /* TODO */ | |||||
return glWindow.handlePluginKeyboard(press, key); | return glWindow.handlePluginKeyboard(press, key); | ||||
#endif | |||||
return false; | |||||
} | } | ||||
bool handlePluginSpecial(const bool press, const DGL_NAMESPACE::Key key) | |||||
bool handlePluginSpecial(const bool /*press*/, const DGL_NAMESPACE::Key /*key*/, const uint16_t /*mods*/) | |||||
{ | { | ||||
#if 0 /* TODO */ | |||||
return glWindow.handlePluginSpecial(press, key); | return glWindow.handlePluginSpecial(press, key); | ||||
#endif | |||||
return false; | |||||
} | } | ||||
#endif | #endif | ||||
@@ -594,8 +482,8 @@ private: | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
// DGL Application and Window for this widget | // DGL Application and Window for this widget | ||||
Application glApp; | |||||
UIExporterWindow glWindow; | |||||
PluginApplication glApp; | |||||
UIExporterWindow glWindow; | |||||
// prevent recursion | // prevent recursion | ||||
bool fChangingSize; | bool fChangingSize; | ||||
@@ -14,6 +14,7 @@ | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
*/ | */ | ||||
#define DISTRHO_UI_IS_STANDALONE 0 | |||||
#include "DistrhoUIInternal.hpp" | #include "DistrhoUIInternal.hpp" | ||||
#include "../extra/String.hpp" | #include "../extra/String.hpp" | ||||
@@ -100,7 +101,7 @@ public: | |||||
fUiResize->ui_resize(fUiResize->handle, fUI.getWidth(), fUI.getHeight()); | fUiResize->ui_resize(fUiResize->handle, fUI.getWidth(), fUI.getHeight()); | ||||
if (widget != nullptr) | if (widget != nullptr) | ||||
*widget = (LV2UI_Widget)fUI.getWindowId(); | |||||
*widget = (LV2UI_Widget)fUI.getNativeWindowHandle(); | |||||
#if DISTRHO_PLUGIN_WANT_STATE | #if DISTRHO_PLUGIN_WANT_STATE | ||||
// tell the DSP we're ready to receive msgs | // tell the DSP we're ready to receive msgs | ||||
@@ -0,0 +1,152 @@ | |||||
/* | |||||
* DISTRHO Plugin Framework (DPF) | |||||
* Copyright (C) 2012-2020 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
* or without fee is hereby granted, provided that the above copyright notice and this | |||||
* permission notice appear in all copies. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#ifndef DISTRHO_UI_PRIVATE_DATA_HPP_INCLUDED | |||||
#define DISTRHO_UI_PRIVATE_DATA_HPP_INCLUDED | |||||
#include "../DistrhoUI.hpp" | |||||
START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | |||||
// Static data, see DistrhoUI.cpp | |||||
extern double d_lastUiSampleRate; | |||||
extern void* d_lastUiDspPtr; | |||||
// ----------------------------------------------------------------------- | |||||
// UI callbacks | |||||
typedef void (*editParamFunc) (void* ptr, uint32_t rindex, bool started); | |||||
typedef void (*setParamFunc) (void* ptr, uint32_t rindex, float value); | |||||
typedef void (*setStateFunc) (void* ptr, const char* key, const char* value); | |||||
typedef void (*sendNoteFunc) (void* ptr, uint8_t channel, uint8_t note, uint8_t velo); | |||||
typedef void (*setSizeFunc) (void* ptr, uint width, uint height); | |||||
typedef bool (*fileRequestFunc) (void* ptr, const char* key); | |||||
// ----------------------------------------------------------------------- | |||||
// UI private data | |||||
struct UI::PrivateData { | |||||
// DSP | |||||
double sampleRate; | |||||
uint32_t parameterOffset; | |||||
#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||||
void* dspPtr; | |||||
#endif | |||||
// UI | |||||
bool automaticallyScale; | |||||
bool resizeInProgress; | |||||
uint minWidth; | |||||
uint minHeight; | |||||
uint bgColor; | |||||
uint fgColor; | |||||
// Callbacks | |||||
void* callbacksPtr; | |||||
editParamFunc editParamCallbackFunc; | |||||
setParamFunc setParamCallbackFunc; | |||||
setStateFunc setStateCallbackFunc; | |||||
sendNoteFunc sendNoteCallbackFunc; | |||||
setSizeFunc setSizeCallbackFunc; | |||||
fileRequestFunc fileRequestCallbackFunc; | |||||
PrivateData() noexcept | |||||
: sampleRate(d_lastUiSampleRate), | |||||
parameterOffset(0), | |||||
#if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | |||||
dspPtr(d_lastUiDspPtr), | |||||
#endif | |||||
automaticallyScale(false), | |||||
resizeInProgress(false), | |||||
minWidth(0), | |||||
minHeight(0), | |||||
bgColor(0), | |||||
fgColor(0), | |||||
callbacksPtr(nullptr), | |||||
editParamCallbackFunc(nullptr), | |||||
setParamCallbackFunc(nullptr), | |||||
setStateCallbackFunc(nullptr), | |||||
sendNoteCallbackFunc(nullptr), | |||||
setSizeCallbackFunc(nullptr), | |||||
fileRequestCallbackFunc(nullptr) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT(d_isNotZero(sampleRate)); | |||||
#if defined(DISTRHO_PLUGIN_TARGET_DSSI) || defined(DISTRHO_PLUGIN_TARGET_LV2) | |||||
parameterOffset += DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS; | |||||
# if DISTRHO_PLUGIN_WANT_LATENCY | |||||
parameterOffset += 1; | |||||
# endif | |||||
#endif | |||||
#ifdef DISTRHO_PLUGIN_TARGET_LV2 | |||||
# if (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_TIMEPOS || DISTRHO_PLUGIN_WANT_STATE) | |||||
parameterOffset += 1; | |||||
# if DISTRHO_PLUGIN_WANT_STATE | |||||
parameterOffset += 1; | |||||
# endif | |||||
# endif | |||||
#endif | |||||
} | |||||
void editParamCallback(const uint32_t rindex, const bool started) | |||||
{ | |||||
if (editParamCallbackFunc != nullptr) | |||||
editParamCallbackFunc(callbacksPtr, rindex, started); | |||||
} | |||||
void setParamCallback(const uint32_t rindex, const float value) | |||||
{ | |||||
if (setParamCallbackFunc != nullptr) | |||||
setParamCallbackFunc(callbacksPtr, rindex, value); | |||||
} | |||||
void setStateCallback(const char* const key, const char* const value) | |||||
{ | |||||
if (setStateCallbackFunc != nullptr) | |||||
setStateCallbackFunc(callbacksPtr, key, value); | |||||
} | |||||
void sendNoteCallback(const uint8_t channel, const uint8_t note, const uint8_t velocity) | |||||
{ | |||||
if (sendNoteCallbackFunc != nullptr) | |||||
sendNoteCallbackFunc(callbacksPtr, channel, note, velocity); | |||||
} | |||||
void setSizeCallback(const uint width, const uint height) | |||||
{ | |||||
if (setSizeCallbackFunc != nullptr) | |||||
setSizeCallbackFunc(callbacksPtr, width, height); | |||||
} | |||||
bool fileRequestCallback(const char* key) | |||||
{ | |||||
if (fileRequestCallbackFunc != nullptr) | |||||
return fileRequestCallbackFunc(callbacksPtr, key); | |||||
// TODO use old style DPF dialog here | |||||
return false; | |||||
} | |||||
}; | |||||
// ----------------------------------------------------------------------- | |||||
END_NAMESPACE_DISTRHO | |||||
#endif // DISTRHO_UI_PRIVATE_DATA_HPP_INCLUDED |
@@ -0,0 +1,19 @@ | |||||
/* (Auto-generated binary data file). */ | |||||
#ifndef BINARY_ARTWORK_HPP | |||||
#define BINARY_ARTWORK_HPP | |||||
namespace Artwork | |||||
{ | |||||
extern const char* buttonOffData; | |||||
const unsigned int buttonOffDataSize = 970; | |||||
extern const char* buttonOnData; | |||||
const unsigned int buttonOnDataSize = 983; | |||||
extern const char* knobData; | |||||
const unsigned int knobDataSize = 52344; | |||||
} | |||||
#endif // BINARY_ARTWORK_HPP | |||||
@@ -1,6 +1,7 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | * Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | ||||
* Copyright (C) 2019-2021 Jean Pierre Cimalando <jp-dev@inbox.ru> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -77,7 +78,13 @@ public: | |||||
void run(const float** inputs, float** outputs, uint32_t frames) | void run(const float** inputs, float** outputs, uint32_t frames) | ||||
{ | { | ||||
memcpy(outputs[0], inputs[0], frames * sizeof(float)); | |||||
/** | |||||
This plugin does nothing, it just demonstrates cairo UI usage. | |||||
So here we directly copy inputs over outputs, leaving the audio untouched. | |||||
We need to be careful in case the host re-uses the same buffer for both inputs and outputs. | |||||
*/ | |||||
if (outputs[0] != inputs[0]) | |||||
std::memcpy(outputs[0], inputs[0], sizeof(float)*frames); | |||||
} | } | ||||
}; | }; | ||||
@@ -1,6 +1,7 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2019-2021 Jean Pierre Cimalando <jp-dev@inbox.ru> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -15,9 +16,10 @@ | |||||
*/ | */ | ||||
#include "DistrhoUI.hpp" | #include "DistrhoUI.hpp" | ||||
#include "Artwork.hpp" | |||||
#include "DemoWidgetBanner.hpp" | #include "DemoWidgetBanner.hpp" | ||||
#include "DemoWidgetClickable.hpp" | #include "DemoWidgetClickable.hpp" | ||||
#include "Window.hpp" | |||||
START_NAMESPACE_DISTRHO | START_NAMESPACE_DISTRHO | ||||
@@ -36,16 +38,29 @@ public: | |||||
fWidgetBanner = widgetBanner; | fWidgetBanner = widgetBanner; | ||||
widgetBanner->setSize(180, 80); | widgetBanner->setSize(180, 80); | ||||
widgetBanner->setAbsolutePos(10, 10); | widgetBanner->setAbsolutePos(10, 10); | ||||
} | |||||
~CairoExampleUI() | |||||
{ | |||||
CairoImage knobSkin; | |||||
knobSkin.loadFromPNG(Artwork::knobData, Artwork::knobDataSize); | |||||
CairoImageKnob* knob = new CairoImageKnob(this, knobSkin); | |||||
fKnob = knob; | |||||
knob->setSize(80, 80); | |||||
knob->setAbsolutePos(10, 100); | |||||
CairoImage buttonOn, buttonOff; | |||||
buttonOn.loadFromPNG(Artwork::buttonOnData, Artwork::buttonOnDataSize); | |||||
buttonOff.loadFromPNG(Artwork::buttonOffData, Artwork::buttonOffDataSize); | |||||
CairoImageButton* button = new CairoImageButton(this, buttonOff, buttonOn); | |||||
fButton = button; | |||||
button->setSize(60, 35); | |||||
button->setAbsolutePos(100, 160); | |||||
} | } | ||||
void onDisplay() | |||||
protected: | |||||
void onCairoDisplay(const CairoGraphicsContext& context) | |||||
{ | { | ||||
cairo_t* cr = getParentWindow().getGraphicsContext().cairo; | |||||
cairo_t* const cr = context.handle; | |||||
cairo_set_source_rgb(cr, 1.0, 0.8, 0.5); | cairo_set_source_rgb(cr, 1.0, 0.8, 0.5); | ||||
cairo_paint(cr); | cairo_paint(cr); | ||||
} | } | ||||
@@ -60,6 +75,8 @@ public: | |||||
private: | private: | ||||
ScopedPointer<DemoWidgetClickable> fWidgetClickable; | ScopedPointer<DemoWidgetClickable> fWidgetClickable; | ||||
ScopedPointer<DemoWidgetBanner> fWidgetBanner; | ScopedPointer<DemoWidgetBanner> fWidgetBanner; | ||||
ScopedPointer<CairoImageKnob> fKnob; | |||||
ScopedPointer<CairoImageButton> fButton; | |||||
}; | }; | ||||
UI* createUI() | UI* createUI() | ||||
@@ -1,6 +1,7 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2019-2021 Jean Pierre Cimalando <jp-dev@inbox.ru> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -16,9 +17,6 @@ | |||||
#include "DemoWidgetBanner.hpp" | #include "DemoWidgetBanner.hpp" | ||||
#include "Cairo.hpp" | |||||
#include "Window.hpp" | |||||
START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -54,14 +52,15 @@ enum | |||||
columns = 72, | columns = 72, | ||||
}; | }; | ||||
DemoWidgetBanner::DemoWidgetBanner(Widget* group) | |||||
: Widget(group) | |||||
{ | |||||
} | |||||
DemoWidgetBanner::DemoWidgetBanner(SubWidget* parent) | |||||
: CairoSubWidget(parent) {} | |||||
DemoWidgetBanner::DemoWidgetBanner(TopLevelWidget* parent) | |||||
: CairoSubWidget(parent) {} | |||||
void DemoWidgetBanner::onDisplay() | |||||
void DemoWidgetBanner::onCairoDisplay(const CairoGraphicsContext& context) | |||||
{ | { | ||||
cairo_t* cr = getParentWindow().getGraphicsContext().cairo; | |||||
cairo_t* cr = context.handle; | |||||
Size<uint> sz = getSize(); | Size<uint> sz = getSize(); | ||||
int w = sz.getWidth(); | int w = sz.getWidth(); | ||||
@@ -1,6 +1,7 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2019-2021 Jean Pierre Cimalando <jp-dev@inbox.ru> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -14,17 +15,21 @@ | |||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||||
*/ | */ | ||||
#include "Widget.hpp" | |||||
#pragma once | |||||
#include "Cairo.hpp" | |||||
START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
class DemoWidgetBanner : public Widget | |||||
class DemoWidgetBanner : public CairoSubWidget | |||||
{ | { | ||||
public: | public: | ||||
explicit DemoWidgetBanner(Widget* group); | |||||
void onDisplay() override; | |||||
explicit DemoWidgetBanner(SubWidget* parent); | |||||
explicit DemoWidgetBanner(TopLevelWidget* parent); | |||||
protected: | |||||
void onCairoDisplay(const CairoGraphicsContext& context) override; | |||||
}; | }; | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
@@ -1,6 +1,7 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2019-2021 Jean Pierre Cimalando <jp-dev@inbox.ru> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * Permission to use, copy, modify, and/or distribute this software for any purpose with | ||||
* or without fee is hereby granted, provided that the above copyright notice and this | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -16,21 +17,19 @@ | |||||
#include "DemoWidgetClickable.hpp" | #include "DemoWidgetClickable.hpp" | ||||
#include "Cairo.hpp" | |||||
#include "Window.hpp" | |||||
START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
DemoWidgetClickable::DemoWidgetClickable(Widget* group) | |||||
: Widget(group) | |||||
{ | |||||
} | |||||
DemoWidgetClickable::DemoWidgetClickable(SubWidget* parent) | |||||
: CairoSubWidget(parent) {} | |||||
DemoWidgetClickable::DemoWidgetClickable(TopLevelWidget* parent) | |||||
: CairoSubWidget(parent) {} | |||||
void DemoWidgetClickable::onDisplay() | |||||
void DemoWidgetClickable::onCairoDisplay(const CairoGraphicsContext& context) | |||||
{ | { | ||||
cairo_t* cr = getParentWindow().getGraphicsContext().cairo; | |||||
cairo_t* cr = context.handle; | |||||
Size<uint> sz = getSize(); | Size<uint> sz = getSize(); | ||||
int w = sz.getWidth(); | int w = sz.getWidth(); | ||||