This commit is contained in:
Joey Yakimowich-Payne 2026-02-06 09:15:25 -07:00
commit 750868c63f
4 changed files with 119 additions and 16 deletions

View file

@ -208,8 +208,8 @@ QVariant WarpGraphModel::nodeData(QtNodes::NodeId nodeId,
}
case QtNodes::NodeRole::Widget: {
auto wIt = m_volumeWidgets.find(nodeId);
if (wIt != m_volumeWidgets.end())
return QVariant::fromValue(wIt->second);
if (wIt != m_volumeWidgets.end() && wIt->second)
return QVariant::fromValue(wIt->second.data());
return QVariant::fromValue(static_cast<QWidget *>(nullptr));
}
default:
@ -329,11 +329,7 @@ bool WarpGraphModel::deleteNode(QtNodes::NodeId const nodeId) {
m_sizes.erase(nodeId);
m_volumeStates.erase(nodeId);
m_styleCache.erase(nodeId);
auto vwIt = m_volumeWidgets.find(nodeId);
if (vwIt != m_volumeWidgets.end()) {
delete vwIt->second;
m_volumeWidgets.erase(vwIt);
}
m_volumeWidgets.erase(nodeId);
Q_EMIT nodeDeleted(nodeId);
return true;
}
@ -356,9 +352,12 @@ void WarpGraphModel::refreshFromClient() {
return;
}
Q_EMIT beginBatchUpdate();
m_refreshing = true;
auto nodesResult = m_client->ListNodes();
if (!nodesResult.ok()) {
m_refreshing = false;
Q_EMIT endBatchUpdate();
return;
}
@ -497,7 +496,8 @@ void WarpGraphModel::refreshFromClient() {
if (savedIt != m_savedPositions.end()) {
m_positions.emplace(qtId, savedIt->second);
} else {
QPointF candidate = nextPosition(nodeIt->second);
auto groupPos = findAppGroupPosition(nodeIt->second);
QPointF candidate = groupPos.value_or(nextPosition(nodeIt->second));
m_positions.emplace(qtId, findNonOverlappingPosition(candidate, nodeIt->second));
}
}
@ -680,8 +680,8 @@ void WarpGraphModel::refreshFromClient() {
cached.mute = mute;
auto wIt = m_volumeWidgets.find(qtId);
if (wIt != m_volumeWidgets.end()) {
auto *vw = static_cast<NodeVolumeWidget *>(wIt->second);
if (wIt != m_volumeWidgets.end() && wIt->second) {
auto *vw = static_cast<NodeVolumeWidget *>(wIt->second.data());
if (!vw->isSliderDown()) {
vw->setVolume(sliderVal);
vw->setMuted(mute);
@ -692,6 +692,7 @@ void WarpGraphModel::refreshFromClient() {
}
m_refreshing = false;
Q_EMIT endBatchUpdate();
}
const WarpNodeData *
@ -763,8 +764,61 @@ QPointF WarpGraphModel::nextPosition(const WarpNodeData &data) {
return pos;
}
std::string WarpGraphModel::appGroupKey(const warppipe::NodeInfo &info) {
if (!info.application_name.empty())
return info.application_name;
if (!info.process_binary.empty())
return info.process_binary;
return {};
}
std::optional<QPointF> WarpGraphModel::findAppGroupPosition(const WarpNodeData &data) const {
WarpNodeType type = classifyNode(data.info);
if (type != WarpNodeType::kApplication)
return std::nullopt;
std::string key = appGroupKey(data.info);
if (key.empty())
return std::nullopt;
double lowestBottom = -1.0;
QPointF siblingPos;
bool found = false;
for (const auto &[existingId, existingData] : m_nodes) {
if (classifyNode(existingData.info) != WarpNodeType::kApplication)
continue;
if (appGroupKey(existingData.info) != key)
continue;
auto posIt = m_positions.find(existingId);
if (posIt == m_positions.end())
continue;
QSizeF existingSize;
auto sizeIt = m_sizes.find(existingId);
if (sizeIt != m_sizes.end()) {
existingSize = QSizeF(sizeIt->second);
} else {
existingSize = QSizeF(estimateNodeSize(existingData));
}
double bottom = posIt->second.y() + existingSize.height();
if (bottom > lowestBottom) {
lowestBottom = bottom;
siblingPos = posIt->second;
found = true;
}
}
if (!found)
return std::nullopt;
return QPointF(siblingPos.x(), lowestBottom + kVerticalGap);
}
QPointF WarpGraphModel::findNonOverlappingPosition(QPointF candidate,
const WarpNodeData &data) const {
const WarpNodeData &data) const {
QSizeF newSize(estimateNodeSize(data));
constexpr int kMaxAttempts = 50;
@ -801,6 +855,22 @@ bool WarpGraphModel::isGhost(QtNodes::NodeId nodeId) const {
return m_ghostNodes.find(nodeId) != m_ghostNodes.end();
}
bool WarpGraphModel::ghostConnectionExists(
QtNodes::ConnectionId connectionId) const {
return m_ghostConnections.find(connectionId) != m_ghostConnections.end();
}
std::unordered_set<QtNodes::ConnectionId>
WarpGraphModel::allGhostConnectionIds(QtNodes::NodeId nodeId) const {
std::unordered_set<QtNodes::ConnectionId> result;
for (const auto &conn : m_ghostConnections) {
if (conn.outNodeId == nodeId || conn.inNodeId == nodeId) {
result.insert(conn);
}
}
return result;
}
uint32_t WarpGraphModel::findPwNodeIdByName(const std::string &name) const {
for (const auto &[qtId, data] : m_nodes) {
if (data.info.name == name) {
@ -855,8 +925,8 @@ void WarpGraphModel::setNodeVolumeState(QtNodes::NodeId nodeId,
}
auto wIt = m_volumeWidgets.find(nodeId);
if (wIt != m_volumeWidgets.end()) {
auto *w = qobject_cast<NodeVolumeWidget *>(wIt->second);
if (wIt != m_volumeWidgets.end() && wIt->second) {
auto *w = qobject_cast<NodeVolumeWidget *>(wIt->second.data());
if (w) {
w->setVolume(volumeToSlider(state.volume));
w->setMuted(state.mute);
@ -1175,6 +1245,19 @@ void WarpGraphModel::autoArrange() {
}
}
std::sort(apps.ids.begin(), apps.ids.end(),
[this](QtNodes::NodeId a, QtNodes::NodeId b) {
auto itA = m_nodes.find(a);
auto itB = m_nodes.find(b);
if (itA == m_nodes.end() || itB == m_nodes.end())
return a < b;
std::string keyA = appGroupKey(itA->second.info);
std::string keyB = appGroupKey(itB->second.info);
if (keyA != keyB)
return keyA < keyB;
return a < b;
});
auto layoutColumn = [&](Column &col, double xOffset) {
double y = 0.0;
for (QtNodes::NodeId id : col.ids) {