Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion include/xstudio/utility/string_helpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,18 @@ namespace utility {
return elems;
}

inline constexpr char path_list_separator() {
#ifdef _WIN32
return ';';
#else
return ':';
#endif
}

inline std::vector<std::string> split_path_list(const std::string &s) {
return split(s, path_list_separator());
}

// not optimal..
inline bool starts_with(const std::string &haystack, const std::string &needle) {
if (haystack.size() < needle.size())
Expand Down Expand Up @@ -361,4 +373,4 @@ namespace utility {


} // namespace utility
} // namespace xstudio
} // namespace xstudio
4 changes: 2 additions & 2 deletions src/global_store/src/global_store.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ bool xstudio::global_store::load_preferences(
// folders
char *plugin_path = std::getenv("XSTUDIO_PLUGIN_PATH");
if (plugin_path) {
for (const auto &p : xstudio::utility::split(plugin_path, ':')) {
for (const auto &p : xstudio::utility::split_path_list(plugin_path)) {
if (fs::is_directory(p + "/preferences"))
preference_load_defaults(prefs, p + "/preferences");
}
Expand Down Expand Up @@ -441,4 +441,4 @@ utility::JsonStore GlobalStoreHelper::get_existing_or_create_new_preference(
JsonStoreHelper::set(v, path, async, broadcast_change);
}
return default_;
}
}
2 changes: 1 addition & 1 deletion src/plugin_manager/src/plugin_manager_actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ PluginManagerActor::PluginManagerActor(caf::actor_config &cfg) : caf::event_base
// xstudio plugins
char *plugin_path = std::getenv("XSTUDIO_PLUGIN_PATH");
if (plugin_path) {
for (const auto &p : xstudio::utility::split(plugin_path, ':')) {
for (const auto &p : xstudio::utility::split_path_list(plugin_path)) {
manager_.emplace_front_path(p);
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/ui/qml/studio/src/qml_setup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ void xstudio::ui::qml::setup_xstudio_qml_emgine(QQmlEngine *engine, caf::actor_s
// with plugins
char *plugin_path = std::getenv("XSTUDIO_PLUGIN_PATH");
if (plugin_path) {
for (const auto &p : xstudio::utility::split(plugin_path, ':')) {
for (const auto &p : xstudio::utility::split_path_list(plugin_path)) {

// note - some xSTUDIO plugins have the backend plugin component
// and a Qt/QML plugin component built into the same binary.
Expand All @@ -144,4 +144,4 @@ void xstudio::ui::qml::setup_xstudio_qml_emgine(QQmlEngine *engine, caf::actor_s
engine->addImportPath(QStringFromStd(p + "/qml"));
}
}
}
}
24 changes: 23 additions & 1 deletion src/utility/test/string_helpers_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,26 @@ TEST(StringHelpersTest, split_vector) {
EXPECT_EQ(split11[0].size(), 10);
EXPECT_EQ(split11[0][0], 1);
EXPECT_EQ(split11[0][9], 10);
}
}

TEST(StringHelpersTest, path_list_separator) {
#ifdef _WIN32
EXPECT_EQ(path_list_separator(), ';');
#else
EXPECT_EQ(path_list_separator(), ':');
#endif
}

TEST(StringHelpersTest, split_path_list) {
#ifdef _WIN32
const auto paths = split_path_list("C:\\plugins;D:\\plugins");
ASSERT_EQ(paths.size(), 2);
EXPECT_EQ(paths[0], "C:\\plugins");
EXPECT_EQ(paths[1], "D:\\plugins");
#else
const auto paths = split_path_list("/tmp/plugins:/opt/plugins");
ASSERT_EQ(paths.size(), 2);
EXPECT_EQ(paths[0], "/tmp/plugins");
EXPECT_EQ(paths[1], "/opt/plugins");
#endif
}
56 changes: 47 additions & 9 deletions ui/qml/xstudio/views/timeline/XsTimeline.qml
Original file line number Diff line number Diff line change
Expand Up @@ -1391,6 +1391,43 @@ Rectangle {
property var initialValue: 0
property real minScaleX: 0

function wheelDelta(pixelDelta, angleDelta) {
return pixelDelta !== 0 ? pixelDelta : angleDelta
}

function scrollTimelineHorizontally(deltaX) {
let stackItem = list_view.itemAtIndex(0)
if(
!stackItem ||
Math.abs(deltaX) < 1 ||
stackItem.scrollbar.size >= 1.0 ||
stackItem.scrollbar.width <= 0
) {
return false
}

let positionDelta = (stackItem.scrollbar.size / stackItem.scrollbar.width) * deltaX
stackItem.jumpToPosition(stackItem.currentPosition() + positionDelta)
return true
}

function scrollTimelineVertically(deltaY) {
if(
hovered == null ||
Math.abs(deltaY) < 1 ||
!["Video Track", "Audio Track", "Gap", "Clip"].includes(hovered.itemTypeRole)
) {
return false
}

if(["Video Track", "Audio Track"].includes(hovered.itemTypeRole))
hovered.parentLV.flick(0, deltaY > 0 ? 500 : -500)
else if(["Gap", "Clip"].includes(hovered.itemTypeRole))
hovered.parentLV.parentLV.flick(0, deltaY > 0 ? 500 : -500)

return true
}

Rectangle {
id: region
visible: ma.isRegionSelection
Expand Down Expand Up @@ -1600,36 +1637,37 @@ Rectangle {
}

onWheel: wheel => {
let deltaX = wheelDelta(wheel.pixelDelta.x, wheel.angleDelta.x)
let deltaY = wheelDelta(wheel.pixelDelta.y, wheel.angleDelta.y)

// maintain position as we zoom..
if(wheel.modifiers == Qt.ShiftModifier) {
// wheel.angleDelta.y always return 0 on MacOS laptops
// when SHIFT is pressed and a mouse wheel is used, but in
// that case the x component is updating and usable.
let deltaY = wheel.angleDelta.y == 0 ? wheel.angleDelta.x : wheel.angleDelta.y
let zoomDelta = deltaY == 0 ? deltaX : deltaY
// Limit the scale to keep it within a usable range and
// avoid a negative scaleY value.
if(deltaY > 1) {
if(zoomDelta > 1) {
scaleY = Math.min(2.0, scaleY + 0.2)
} else {
scaleY = Math.max(0.6, scaleY - 0.2)
}
wheel.accepted = true
} else if(wheel.modifiers == Qt.ControlModifier) {
let tmp = scaleX
if(wheel.angleDelta.y > 1) {
let zoomDelta = deltaY == 0 ? deltaX : deltaY
if(zoomDelta > 1) {
tmp += 0.2
} else {
tmp -= 0.2
}
scaleX = Math.max((list_view.width - trackHeaderWidth) / theSessionData.timelineRect([timeline_items.rootIndex]).width, tmp)
list_view.itemAtIndex(0).jumpToFrame(timelinePlayhead.logicalFrame, ListView.Center)
wheel.accepted = true
} else if(hovered != null && ["Video Track", "Audio Track","Gap","Clip"].includes(hovered.itemTypeRole)) {
if(["Video Track", "Audio Track"].includes(hovered.itemTypeRole))
hovered.parentLV.flick(0, wheel.angleDelta.y > 1 ? 500 : -500)
else if(["Gap", "Clip"].includes(hovered.itemTypeRole))
hovered.parentLV.parentLV.flick(0, wheel.angleDelta.y > 1 ? 500 : -500)
} else if(Math.abs(deltaX) > Math.abs(deltaY)) {
wheel.accepted = scrollTimelineHorizontally(deltaX)
} else if(scrollTimelineVertically(deltaY)) {
wheel.accepted = true
} else {
wheel.accepted = false
Expand Down Expand Up @@ -2224,4 +2262,4 @@ Rectangle {
// }
// }

}
}