Skip to content
Draft
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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
214 changes: 208 additions & 6 deletions src/plugins/rv-packages/session_manager/session_manager.mu.in
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ ViewSubComponent := 2;
LayerSubComponent := 3;
ChannelSubComponent := 4;

FILMSTRIP_FRAME_WIDTH := 240;
PREVIEW_WIDTH := 80;
PREVIEW_HEIGHT := 45;

\: itemNode (string; QStandardItem item)
{
let d = item.data(Qt.UserRole + 2);
Expand Down Expand Up @@ -601,6 +605,120 @@ documentation: """
QStandardItemModel with modified drag and drop mime types.
""";

// Displays a static thumbnail image. Falls back to a placeholder pixmap if none loaded.
class: ThumbnailWidget : QLabel
{
method: ThumbnailWidget (ThumbnailWidget; QWidget parent)
{
QLabel.QLabel(this, parent);
setScaledContents(true);
}

method: setFallback (void; QPixmap px) { setPixmap(px); }

method: load (void; string path)
{
let px = QPixmap.fromImage(QImage(path, ""), Qt.AutoColor);
if (!px.isNull()) setPixmap(px);
}
}

// Displays a scrubable filmstrip that will show the corresponding frame
// based on mouse position
class: FilmstripWidget : QLabel
{
QImage _strip;
int _frameWidth;
bool _loaded;

method: FilmstripWidget (FilmstripWidget; QWidget parent)
{
QLabel.QLabel(this, parent);
_frameWidth = FILMSTRIP_FRAME_WIDTH;
_loaded = false;
setScaledContents(true);
setMouseTracking(true);
}

method: showFrameAtX (void; int mouseX)
{
if (!_loaded) return;
let nat_w = _strip.width(),
prop_x = float(mouseX) / float(width()),
fx = int(prop_x * float(nat_w) / float(_frameWidth) + 0.5) * _frameWidth,
clamped = if fx > nat_w - _frameWidth then nat_w - _frameWidth
else if fx < 0 then 0
else fx;
let frame = _strip.copy(QRect(clamped, 0, _frameWidth, _strip.height()));
setPixmap(QPixmap.fromImage(frame, Qt.AutoColor));
}

method: isLoaded (bool;) { _loaded; }

method: load (void; string path)
{
let img = QImage(path, "");
if (!img.isNull())
{
_strip = img;
_loaded = true;
}
}

method: mouseMoveEvent (void; QMouseEvent event)
{
showFrameAtX(event.position().toPoint().x());
QWidget.mouseMoveEvent(this, event);
}
}

// Stacks a FilmstripWidget and ThumbnailWidget. Shows thumbnail by default;
// on hover enter shows the filmstrip scrubbed to the cursor position.
class: SourcePreviewWidget : QWidget
{
FilmstripWidget _filmstrip;
ThumbnailWidget _thumbnail;

method: SourcePreviewWidget (SourcePreviewWidget; QWidget parent)
{
QWidget.QWidget(this, parent);
setAttribute(Qt.WA_Hover, true);

_thumbnail = ThumbnailWidget(this);
_thumbnail.setGeometry(QRect(0, 0, PREVIEW_WIDTH, PREVIEW_HEIGHT));
_thumbnail.show();

_filmstrip = FilmstripWidget(this);
_filmstrip.setGeometry(QRect(0, 0, PREVIEW_WIDTH, PREVIEW_HEIGHT));
_filmstrip.hide();
}

method: setFallback (void; QPixmap px) { _thumbnail.setFallback(px); }
method: loadStrip (void; string path) { _filmstrip.load(path); }
method: loadThumbnail (void; string path) { _thumbnail.load(path); }

method: event (bool; QEvent e)
{
if (e.type() == QEvent.HoverEnter)
{
if (_filmstrip.isLoaded())
{
_filmstrip.showFrameAtX(mapFromGlobal(QCursor.pos()).x());
_filmstrip.show();
_thumbnail.hide();
}
return true;
}
else if (e.type() == QEvent.HoverLeave)
{
_filmstrip.hide();
_thumbnail.show();
return true;
}
return QWidget.event(this, e);
}
}

class: NodeModel : QStandardItemModel
{
method: NodeModel (NodeModel; QObject parent)
Expand Down Expand Up @@ -980,6 +1098,7 @@ class: SessionManagerMode : MinorMode
QIcon _layerIcon;
QIcon _channelIcon;
QIcon _videoIcon;
QIcon _fallbackSourceIcon;
bool _inputOrderLock;
bool _disableUpdates;
bool _progressiveLoadingInProgress;
Expand Down Expand Up @@ -1360,20 +1479,28 @@ class: SessionManagerMode : MinorMode
_inputOrderLock = true;

_inputsModel.clear();
let connections = nodeInputs(node),
vnodes = viewNodes();
let connections = nodeInputs(node);

for_index (i; connections)
{
let innode = connections[i],
item = QStandardItem(iconForNode(innode), uiName(innode)),
vindex = indexOfItem(vnodes, innode);
let innode = connections[i],
isSource = nodeType(innode) == "RVSourceGroup",
item = QStandardItem(iconForNode(innode), uiName(innode));

item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsDragEnabled | Qt.ItemIsEnabled);
item.setData(QVariant(innode), Qt.UserRole + 2);
item.setEditable(false);


if (isSource)
{
item.setText("");
item.setSizeHint(QSize(-1, 55));
}

_inputsModel.appendRow(item);

if (isSource)
_inputsView.setIndexWidget(_inputsModel.indexFromItem(item), makeSourceRowWidget(innode));
}

_inputOrderLock = false;
Expand Down Expand Up @@ -1662,6 +1789,72 @@ class: SessionManagerMode : MinorMode
item;
}

method: makeSourceRowWidget (QWidget; string node)
{
let widget = QWidget(nil, 0),
layout = QHBoxLayout(widget);
widget.setStyleSheet("background: transparent;");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see you added several setStyleSheet calls, and I believe we should be using our .qss files to set properties based on themes instead. Also, I know users can set a specific font size in the RV preferences tab. You might want to validate how that works with the metalabel font size property you added below

layout.setContentsMargins(8, 0, 8, 0);
layout.setSpacing(5);

// Source preview: stacks thumbnail (default) and filmstrip (on hover)
let preview = SourcePreviewWidget(widget);
preview.setFixedSize(QSize(PREVIEW_WIDTH, PREVIEW_HEIGHT));
preview.setFallback(_fallbackSourceIcon.pixmap(QSize(PREVIEW_WIDTH, PREVIEW_HEIGHT)));

try
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would avoid doing try catch blocks around several lines, and with a catch-all. I would keep it specifically for the line that could throw:

Suggested change
try
try
{
let sourceNode = sourceNodeOfGroup(node);
}
catch (exception exc)
{
print("WARNING: [...]);
}

Since sourceNodeOfGroup can return a string or nil, you should then add a statement around the lines that get the paths and load the thumbnail and filmstrip.

{
let sn = sourceNodeOfGroup(node);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are declaring twice sn in this method (i.e. here and at line 1841). You should reuse the variable instead of calling sourceNodeOfGroup twice.


// Fire events that fetch filmstrip/thumbnail and return file paths
let filmstripPath = sendInternalEvent("session_manager-get-filmstrip-path", sn);
let thumbnailPath = sendInternalEvent("session_manager-get-thumbnail-path", sn);

if (filmstripPath != "" && io.path.exists(filmstripPath))
preview.loadStrip(filmstripPath);
if (thumbnailPath != "" && io.path.exists(thumbnailPath))
preview.loadThumbnail(thumbnailPath);
}
catch (...) { ; }

layout.addWidget(preview);

// Text column
let textWidget = QWidget(widget),
textLayout = QVBoxLayout(textWidget);
textWidget.setStyleSheet("background: transparent;");
textLayout.setSpacing(3);

let nameLabel = QLabel(uiName(node), textWidget);
nameLabel.setStyleSheet("color: #d0d0d0; background: transparent;");
textLayout.addWidget(nameLabel);

string meta = "";
try
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can remove the try catch statement here, and simply guard what is inside of it by checking that the source node is not nil before proceeding. For the media property, You can simply check if propertyExists() on the string before calling getStringProperty which would prevent it from throwing.

{
let sn = sourceNodeOfGroup(node),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rename sn to something more meaningful here. I know there is a lot of mu code using abbreviations or one or two letters as a variable name, but there is no reason to do that for newer code. This is an obvious one, but I saw a few other like nat_w and mprop

mprop = getStringProperty(sn + ".media.movie");
if (!mprop.empty())
{
let parts = io.path.basename(mprop.front()).split(".");
if (parts.size() > 1) meta = parts.back();
}
}
catch (exception exc)
{
print("WARNING: Could not get media type info for %s - %s\n" % (uiName(node), exc));
}

let metaLabel = QLabel(if meta == "" then "—" else meta, textWidget);
metaLabel.setStyleSheet("color: #888888; background: transparent; font-size: 9px;");
textLayout.addWidget(metaLabel);
textLayout.addStretch(1);

layout.addWidget(textWidget, 1);

widget;
}

method: newNodeRow (void;
QStandardItem parentItem,
string node,
Expand Down Expand Up @@ -1692,6 +1885,13 @@ class: SessionManagerMode : MinorMode
if (node == viewNode()) head(tail(statusItems)).setText("\u2714");
addRow(parentItem, item : statusItems);

if (source)
{
item.setText("");
item.setSizeHint(QSize(-1, 55));
_viewTreeView.setIndexWidget(_viewModel.indexFromItem(item), makeSourceRowWidget(node));
}

//
// Tabs in tooltips make win32 Qt crash.
//
Expand Down Expand Up @@ -2929,6 +3129,7 @@ class: SessionManagerMode : MinorMode
_viewTreeView.setDragDropMode(QAbstractItemView.DragDrop);
_viewTreeView.setDefaultDropAction(Qt.MoveAction);
_viewTreeView.setExpandsOnDoubleClick(false);
_viewTreeView.setIndentation(10);

_inputsView.setModel(_inputsModel);
_inputsView.setDragEnabled(true);
Expand Down Expand Up @@ -2986,6 +3187,7 @@ class: SessionManagerMode : MinorMode
_channelIcon = auxIcon("channel.png", true);
_layerIcon = auxIcon("layer.png", true);
_unknownTypeIcon = auxIcon("new_48x48.png", true);
_fallbackSourceIcon = QIcon(auxFilePath("fallback_thumbnail.png"));

_addButton.setDefaultAction(addAction);
_deleteButton.setDefaultAction(deleteAction);
Expand Down
Loading