diff --git a/src/plugin/python_plugins/on_screen_version_name/on_screen_version_name.py b/src/plugin/python_plugins/on_screen_version_name/on_screen_version_name.py index 2ad58f58f..db77a2948 100644 --- a/src/plugin/python_plugins/on_screen_version_name/on_screen_version_name.py +++ b/src/plugin/python_plugins/on_screen_version_name/on_screen_version_name.py @@ -133,7 +133,9 @@ def media_item_hud_data(self, media_item = None): # display_info is an array of values corresponding to the columns # of the Media List Panel in the xSTUDIO UI (the columns are fully # user-configurable, by the way) - return media_item.display_info[idx] + return media_item.display_info[idx] \ + if idx < len(media_item.display_info) \ + else "" else: return "" diff --git a/src/plugin/utility/filesystem_browser/FileSystemBrowser/xstudio/FSPathInput.qml b/src/plugin/utility/filesystem_browser/FileSystemBrowser/xstudio/FSPathInput.qml index 3a6a105d3..bf41798aa 100644 --- a/src/plugin/utility/filesystem_browser/FileSystemBrowser/xstudio/FSPathInput.qml +++ b/src/plugin/utility/filesystem_browser/FileSystemBrowser/xstudio/FSPathInput.qml @@ -14,6 +14,18 @@ RowLayout { spacing: 1 property var completionList: [] + function getCommonPrefix(strings) { + if (!strings || strings.length === 0) return ""; + var prefix = strings[0]; + for (var i = 1; i < strings.length; i++) { + while (strings[i].indexOf(prefix) !== 0) { + prefix = prefix.substring(0, prefix.length - 1); + if (prefix === "") return ""; + } + } + return prefix; + } + XsPrimaryButton { Layout.preferredHeight: XsStyleSheet.primaryButtonStdHeight diff --git a/src/plugin/viewport_overlay/media_metadata_hud/src/media_metadata_hud.cpp b/src/plugin/viewport_overlay/media_metadata_hud/src/media_metadata_hud.cpp index 62ed79d1b..962961926 100644 --- a/src/plugin/viewport_overlay/media_metadata_hud/src/media_metadata_hud.cpp +++ b/src/plugin/viewport_overlay/media_metadata_hud/src/media_metadata_hud.cpp @@ -80,6 +80,10 @@ void MediaMetadataRenderer::render_image_overlay( const auto viewport_width = (float)gl_viewport[2]; const auto viewport_height = (float)gl_viewport[3]; + // don't render if the viewport is small (ie. for thumbnails) + if (viewport_width < 300.0f) + return; + if (display_settings_ != data->display_settings_) { display_settings_ = data->display_settings_; diff --git a/src/plugin_manager/src/plugin_base.cpp b/src/plugin_manager/src/plugin_base.cpp index 3011f0813..7c050d2af 100644 --- a/src/plugin_manager/src/plugin_base.cpp +++ b/src/plugin_manager/src/plugin_base.cpp @@ -173,6 +173,14 @@ StandardPlugin::StandardPlugin( if (p != watched_attr_event_handlers_.end()) { p->second(attr_id, role_id, role_data); } + }, + [=](utility::event_atom, + utility::name_atom, + const std::string &name) { + }, + [=](utility::event_atom, + utility::last_changed_atom, + const utility::time_point &last_change) { }}; } diff --git a/src/python_module/src/py_register.cpp b/src/python_module/src/py_register.cpp index c8c42ecd6..f04f0da90 100644 --- a/src/python_module/src/py_register.cpp +++ b/src/python_module/src/py_register.cpp @@ -328,6 +328,7 @@ void register_bookmark_detail_class(py::module &m, const std::string &name) { .def_readwrite("author", &bookmark::BookmarkDetail::author_) .def_readwrite("owner", &bookmark::BookmarkDetail::owner_) .def_readwrite("note", &bookmark::BookmarkDetail::note_) + .def_readwrite("subject", &bookmark::BookmarkDetail::subject_) .def_readwrite("created", &bookmark::BookmarkDetail::created_) .def_readonly("has_note", &bookmark::BookmarkDetail::has_note_) .def_readonly("has_annotation", &bookmark::BookmarkDetail::has_annotation_); diff --git a/src/ui/base/src/keyboard.cpp b/src/ui/base/src/keyboard.cpp index c00874d47..b6329f9b4 100644 --- a/src/ui/base/src/keyboard.cpp +++ b/src/ui/base/src/keyboard.cpp @@ -232,13 +232,25 @@ std::string Hotkey::hotkey_sequence() const { r = "Shift+" + r; } if ((modifiers_ & MetaModifier) == MetaModifier) { +#ifdef __apple__ + r = "Ctrl+" + r; +#else r = "Meta+" + r; +#endif } if ((modifiers_ & AltModifier) == AltModifier) { +#ifdef __apple__ + r = "Opt+" + r; +#else r = "Alt+" + r; +#endif } if ((modifiers_ & ControlModifier) == ControlModifier) { +#ifdef __apple__ + r = "Cmd+" + r; +#else r = "Ctrl+" + r; +#endif } return r; } @@ -269,7 +281,7 @@ void Hotkey::sequence_to_key_and_modifier( } } } - if (keycode == -1) { + if (keycode == -1 and not modifier) { throw std::runtime_error( fmt::format("Unable to identify key name in hotkey sequence '{}'", sequence) .c_str()); @@ -306,7 +318,7 @@ void Hotkey::sequence_to_key_and_modifier( } } } - if (keycode == -1) { + if (keycode == -1 and not modifier) { std::string ss; for (const auto &s : seq) { if (!ss.empty()) { @@ -315,6 +327,6 @@ void Hotkey::sequence_to_key_and_modifier( ss += s; } throw std::runtime_error( - fmt::format("Unable to identify key name in hotkey sequence \"{}\"", ss).c_str()); + fmt::format("Unable to identify key name in hotkey sequence '{}'", ss).c_str()); } } \ No newline at end of file diff --git a/src/ui/qml/session/src/session_model_methods_ui.cpp b/src/ui/qml/session/src/session_model_methods_ui.cpp index 8dc30ea44..686d5d80f 100644 --- a/src/ui/qml/session/src/session_model_methods_ui.cpp +++ b/src/ui/qml/session/src/session_model_methods_ui.cpp @@ -1169,7 +1169,7 @@ QFuture> SessionModel::handleOtherDropFuture( *sys, session_actor_, session::add_playlist_atom_v, - "Drag Drop", + StdFromQString(getNextName("Drag Drop {}")), Uuid(), false); target = uua.second.actor(); diff --git a/src/ui/qml/viewport/src/hotkey_ui.cpp b/src/ui/qml/viewport/src/hotkey_ui.cpp index aa3130a18..12526cc18 100644 --- a/src/ui/qml/viewport/src/hotkey_ui.cpp +++ b/src/ui/qml/viewport/src/hotkey_ui.cpp @@ -163,8 +163,7 @@ void HotkeysUI::makeFilteredHotkeysData() { other_hk.uuid() != hk.uuid()) { clash_warning = fmt::format( "clashes with hotkey '{}'", - other_hk.hotkey_name(), - other_hk.hotkey_sequence()); + other_hk.hotkey_name()); } } diff --git a/src/utility/src/chrono.cpp b/src/utility/src/chrono.cpp index 2250180c9..920cff98f 100644 --- a/src/utility/src/chrono.cpp +++ b/src/utility/src/chrono.cpp @@ -8,7 +8,7 @@ xstudio::utility::to_sys_time_point(const std::string &datetime) { #ifdef _WIN32 // TODO: Ahead to fix #else - in >> date::parse("%Y-%m-%dT%TZ", tp); + date::from_stream(in, "%Y-%m-%dT%TZ", tp); #endif return tp; } diff --git a/ui/qml/xstudio/application/XsSessionWindow.qml b/ui/qml/xstudio/application/XsSessionWindow.qml index 0507daf81..38320714a 100644 --- a/ui/qml/xstudio/application/XsSessionWindow.qml +++ b/ui/qml/xstudio/application/XsSessionWindow.qml @@ -87,7 +87,8 @@ ApplicationWindow { } } function setLayoutName(name) { - var idx = ui_layouts_model.searchRecursive(name, "layout_name", ui_layouts_model.root_index) + + var idx = ui_layouts_model.searchRecursive(name || "Review", "layout_name", ui_layouts_model.root_index) if (idx.valid) { layoutBar.selected_layout = idx.row } else if (layoutBar.current_layout_index.row > 0) { diff --git a/ui/qml/xstudio/application/auxillary/XsConformTool.qml b/ui/qml/xstudio/application/auxillary/XsConformTool.qml index e6ecbe053..ee5dc9477 100644 --- a/ui/qml/xstudio/application/auxillary/XsConformTool.qml +++ b/ui/qml/xstudio/application/auxillary/XsConformTool.qml @@ -223,24 +223,18 @@ Item{ function compareSelection(task, selection) { for(let i=0; i< selection.length; i++) { + let pl_index = selection[i].model.getContainerIndex(selection[i]) Future.promise( - engine.conformItemsFuture(task, - selection[i].model.getContainerIndex(selection[i]), - selection[i], true, false) + engine.conformItemsFuture(task, pl_index, selection[i], true, false) ).then( function(media_uuid_list) { - // create new selection. - // console.log(media_uuid_list) - - let tmp = [] - for(let i=0;i conformToSequence(menuContext.mediaSelection, viewportCurrentMediaContainerIndex) + onActivated: (menuContext) => conformToSequence(menuContext.mediaSelection, viewportCurrentMediaContainerIndex, "Conformed Media") } diff --git a/ui/qml/xstudio/application/dialogs/hotkeys/delegates/XsHotkeySequence.qml b/ui/qml/xstudio/application/dialogs/hotkeys/delegates/XsHotkeySequence.qml index 565db259e..12e67d16e 100644 --- a/ui/qml/xstudio/application/dialogs/hotkeys/delegates/XsHotkeySequence.qml +++ b/ui/qml/xstudio/application/dialogs/hotkeys/delegates/XsHotkeySequence.qml @@ -13,6 +13,20 @@ RowLayout { property var borderSize: 4 property var unbound: JSON.stringify(regularKeys) === JSON.stringify([""]) + function platformLabel(modifier) { + if (Qt.platform.os === "osx") { + if (modifier == "Control") + return "Command" + else if (modifier == "Meta") + return "Control" + else if (modifier == "Alt") + return "Option" + else + return modifier + } + return modifier + } + Rectangle { Layout.preferredWidth: textField.width + borderSize*2 Layout.preferredHeight: textField.height + borderSize*2 @@ -55,7 +69,7 @@ RowLayout { XsText { id: textField anchors.centerIn: parent - text: modelData + text: platformLabel(modelData) font.family: XsStyleSheet.fixedWidthFontFamily font.bold: true font.pixelSize: fontSize diff --git a/ui/qml/xstudio/application/panels/log/XsLogPanel.qml b/ui/qml/xstudio/application/panels/log/XsLogPanel.qml index 843ae3451..dd76cd692 100644 --- a/ui/qml/xstudio/application/panels/log/XsLogPanel.qml +++ b/ui/qml/xstudio/application/panels/log/XsLogPanel.qml @@ -165,7 +165,7 @@ Item{ MouseArea{ anchors.fill: parent z: 1 - onClicked: { + onClicked: (mouse)=> { if (mouse.button == Qt.LeftButton) { if (mouse.modifiers & Qt.ShiftModifier) { if(index < startSelection) { diff --git a/ui/qml/xstudio/application/panels/media/functions/XsMediaListFunctions.qml b/ui/qml/xstudio/application/panels/media/functions/XsMediaListFunctions.qml index a3128167e..e8f4cf62a 100644 --- a/ui/qml/xstudio/application/panels/media/functions/XsMediaListFunctions.qml +++ b/ui/qml/xstudio/application/panels/media/functions/XsMediaListFunctions.qml @@ -7,6 +7,11 @@ import xstudio.qml.clipboard 1.0 import xStudio 1.0 Item { + XsPreference { + id: sessionLinkPrefix + path: "/core/session/session_link_prefix" + } + XsPreference { id: sessionRate path: "/core/session/media_rate" @@ -107,6 +112,15 @@ Item { filenames.join(prefix) } + function copyColumnToClipboard(column) { + let data = [] + for( let i=0;i 0 && parent.model.rowCount(parent) > (last_row+1)) { + if (last_row >= 0 && parent.model.rowCount(parent) > (last_row+1)) { mediaSelectionModel.select( parent.model.index(last_row+1, 0, parent), ItemSelectionModel.Select diff --git a/ui/qml/xstudio/application/panels/media/grid_view/XsMediaGrid.qml b/ui/qml/xstudio/application/panels/media/grid_view/XsMediaGrid.qml index 3e73aa535..32ba21478 100644 --- a/ui/qml/xstudio/application/panels/media/grid_view/XsMediaGrid.qml +++ b/ui/qml/xstudio/application/panels/media/grid_view/XsMediaGrid.qml @@ -194,6 +194,7 @@ XsGridView { // are these indeces from the same list as our list here? if (data.length && data[0].parent == mediaListModelDataRoot) { // do a move rows + beforeMoveContentY = contentY theSessionData.moveRows( data, dragTargetIndex.row, @@ -256,6 +257,19 @@ XsGridView { } + // When we do a moveRows, the list view resets contentY to zero. Annoying. + // So here we try and preserve the scrolled position in that case + property real beforeMoveContentY: 0 + onContentYChanged: { + if (contentY == 0) { + // check if this is a reset we want to undo + if (beforeMoveContentY != 0) { + contentY = beforeMoveContentY + beforeMoveContentY = 0 + } + } + } + property var autoScrollVelocity: 200 function autoScroll(mouseY) { if ((height-mouseY) < 0 || mouseY < 0) { diff --git a/ui/qml/xstudio/application/panels/media/list_view/XsMediaList.qml b/ui/qml/xstudio/application/panels/media/list_view/XsMediaList.qml index 7629e4303..ed9143075 100644 --- a/ui/qml/xstudio/application/panels/media/list_view/XsMediaList.qml +++ b/ui/qml/xstudio/application/panels/media/list_view/XsMediaList.qml @@ -285,9 +285,12 @@ XsListView { // So here we try and preserve the scrolled position in that case property real beforeMoveContentY: 0 onContentYChanged: { - if(beforeMoveContentY != 0){ - contentY = beforeMoveContentY - beforeMoveContentY = 0 + if (contentY == 0) { + // check if this is a reset we want to undo + if (beforeMoveContentY != 0) { + contentY = beforeMoveContentY + beforeMoveContentY = 0 + } } } diff --git a/ui/qml/xstudio/application/panels/media/list_view/dialogs/XsMediaListConfigureDialog.qml b/ui/qml/xstudio/application/panels/media/list_view/dialogs/XsMediaListConfigureDialog.qml index f610a6527..a3eb1bb15 100644 --- a/ui/qml/xstudio/application/panels/media/list_view/dialogs/XsMediaListConfigureDialog.qml +++ b/ui/qml/xstudio/application/panels/media/list_view/dialogs/XsMediaListConfigureDialog.qml @@ -86,7 +86,7 @@ metadata with media that isn't from your pipeline.` ListElement { detail_item: "Frame Range - MediaSource (Image)"} } - property var model_index: columns_model.index(-1, -1) + property var model_index: columns_model.rootIndex XsModelProperty { id: __column_title @@ -447,13 +447,14 @@ metadata with media that isn't from your pipeline.` } XsLabel { + id: lbl3 Layout.alignment: Qt.AlignVCenter|Qt.AlignRight text: "Format Expression : " horizontalAlignment: Text.AlignRight visible: advanced.checked XsToolTip{ text: regex_tooltip - visible: hovered + visible: lbl3.hovered } } @@ -477,7 +478,7 @@ metadata with media that isn't from your pipeline.` } XsSimpleButton { - + id: backup_btn text: model_index.model.rowCount(model_index) ? qsTr("Configure Backup") : qsTr("Add Backup") Layout.alignment: Qt.AlignVCenter|Qt.AlignLeft Layout.preferredHeight: XsStyleSheet.widgetStdHeight @@ -494,7 +495,7 @@ metadata with media that isn't from your pipeline.` } XsToolTip{ text: backup_tooltip - visible: hovered + visible: backup_btn.hovered } } diff --git a/ui/qml/xstudio/application/panels/media/widgets/XsMediaListContextMenu.qml b/ui/qml/xstudio/application/panels/media/widgets/XsMediaListContextMenu.qml index 6f3e14766..5b28b56f2 100644 --- a/ui/qml/xstudio/application/panels/media/widgets/XsMediaListContextMenu.qml +++ b/ui/qml/xstudio/application/panels/media/widgets/XsMediaListContextMenu.qml @@ -27,20 +27,6 @@ XsPopupMenu { ****************************************************************/ - Clipboard { - id: clipboard - } - - XsPreference { - id: sessionLinkPrefix - path: "/core/session/session_link_prefix" - } - - XsPreference { - id: sessionRate - path: "/core/session/media_rate" - } - Component.onCompleted: { // make sure the 'Add' sub-menu appears in the correct place helpers.setMenuPathPosition("Select", "media_list_menu_", 10) @@ -280,14 +266,7 @@ XsPopupMenu { menuItemPosition: index menuModelName: btnMenu.menu_model_name panelContext: btnMenu.panelContext - onActivated: { - let data = [] - for( let i=0;i { control.draggingStarted(modelIndex(), control, mode) isDragging = true } onDragging: control.dragging(modelIndex(), control, mode, x / scaleX, y / scaleY / config.itemHeight) onDoubleTapped: control.doubleTapped(control, mode) onTapped: control.tapped(button, x, y, modifiers, control) - onDraggingStopped: { + onDraggingStopped: (mode)=> { control.draggingStopped(modelIndex(), control, mode) isDragging = false } diff --git a/ui/qml/xstudio/application/panels/timeline/delegates/XsDelegateStack.qml b/ui/qml/xstudio/application/panels/timeline/delegates/XsDelegateStack.qml index b461d2985..7929eccef 100644 --- a/ui/qml/xstudio/application/panels/timeline/delegates/XsDelegateStack.qml +++ b/ui/qml/xstudio/application/panels/timeline/delegates/XsDelegateStack.qml @@ -480,7 +480,7 @@ Rectangle { Rectangle { color: XsStyleSheet.accentColor opacity: 0.3 - visible: timelinePlayhead != undefined && timelinePlayhead.enableLoopRange + visible: timelinePlayhead.enableLoopRange != undefined ? timelinePlayhead.enableLoopRange : false anchors.fill: parent property int start: (timelinePlayhead.loopStartFrame - (frameTrack.offset / control.scaleX)) * control.scaleX property int end: (timelinePlayhead.loopEndFrame - (frameTrack.offset / control.scaleX)) * control.scaleX diff --git a/ui/qml/xstudio/application/panels/viewport/widgets/XsViewportActionBar.qml b/ui/qml/xstudio/application/panels/viewport/widgets/XsViewportActionBar.qml index dbbda9031..00e31ecb0 100644 --- a/ui/qml/xstudio/application/panels/viewport/widgets/XsViewportActionBar.qml +++ b/ui/qml/xstudio/application/panels/viewport/widgets/XsViewportActionBar.qml @@ -49,6 +49,7 @@ Item{ Layout.preferredWidth: 40 Layout.preferredHeight: parent.height + text: title ? title : "" imgSrc: icon_path ? icon_path : "" isActive: visible_doc_widgets.indexOf(title) != -1 //enabled: button_enabled diff --git a/ui/qml/xstudio/model/XsBufferedProperty.qml b/ui/qml/xstudio/model/XsBufferedProperty.qml index 9b74952ef..6339bd926 100644 --- a/ui/qml/xstudio/model/XsBufferedProperty.qml +++ b/ui/qml/xstudio/model/XsBufferedProperty.qml @@ -19,7 +19,7 @@ Item { onSourceChanged: { if(enableBuffering) { if(delay && !updateTimer.running) { - console.log(delay, updateTimer.running) + //console.log(delay, updateTimer.running) updateTimer.start() } } diff --git a/ui/qml/xstudio/widgets/XsDoubleAttributeSlider.qml b/ui/qml/xstudio/widgets/XsDoubleAttributeSlider.qml index d539e092b..9e7cf15cd 100644 --- a/ui/qml/xstudio/widgets/XsDoubleAttributeSlider.qml +++ b/ui/qml/xstudio/widgets/XsDoubleAttributeSlider.qml @@ -56,7 +56,7 @@ Rectangle { verticalAlignment: Qt.AlignVCenter anchors.fill: parent onEditingFinished: { -( setValue(parseFloat(text)) + setValue(parseFloat(text)) } } }