Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: ngscopeclient/scopehal-apps
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 76deb9d904db
Choose a base ref
...
head repository: ngscopeclient/scopehal-apps
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: b4db425b3239
Choose a head ref
  • 2 commits
  • 3 files changed
  • 1 contributor

Commits on Dec 6, 2020

  1. FilterGraphEditorWidget: clarifications to node titles, made sure cha…

    …nnel hwname is always visible on inputs. See #161.
    azonenberg committed Dec 6, 2020

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    54243ae View commit details
  2. FilterGraphEditorWidget: Added context menu and initial handler for n…

    …ode deletion (doesn't do anything). Refactoring of mouse event handling. See #161.
    azonenberg committed Dec 6, 2020
    Copy the full SHA
    b4db425 View commit details
Showing with 128 additions and 71 deletions.
  1. +1 −1 lib
  2. +117 −62 src/glscopeclient/FilterGraphEditorWidget.cpp
  3. +10 −8 src/glscopeclient/FilterGraphEditorWidget.h
2 changes: 1 addition & 1 deletion lib
179 changes: 117 additions & 62 deletions src/glscopeclient/FilterGraphEditorWidget.cpp
Original file line number Diff line number Diff line change
@@ -113,8 +113,13 @@ void FilterGraphEditorNode::UpdateSize()
m_titleLayout = Pango::Layout::create(m_parent->get_pango_context());
m_titleLayout->set_font_description(headerfont);
auto filter = dynamic_cast<Filter*>(m_channel);
if( (filter != NULL) && filter->IsUsingDefaultName() )
m_titleLayout->set_text(filter->GetProtocolDisplayName());
if(filter != NULL)
{
if(filter->IsUsingDefaultName())
m_titleLayout->set_text(filter->GetProtocolDisplayName());
else
m_titleLayout->set_text(filter->GetProtocolDisplayName() + ": " + m_channel->GetDisplayName());
}
else
m_titleLayout->set_text(m_channel->GetDisplayName());
m_titleLayout->get_pixel_size(twidth, theight);
@@ -172,6 +177,7 @@ void FilterGraphEditorNode::UpdateSize()
if(filter != NULL)
{
tabs.set_tab(0, Pango::TAB_LEFT, 150);

for(auto it = filter->GetParamBegin(); it != filter->GetParamEnd(); it ++)
paramText += it->first + ": \t" + it->second.ToString() + "\n";
}
@@ -182,6 +188,8 @@ void FilterGraphEditorNode::UpdateSize()
Unit v(Unit::UNIT_VOLTS);
Unit hz(Unit::UNIT_HZ);

paramText += string("Channel: \t") + m_channel->GetHwname() + "\n";

if(m_channel->GetType() == OscilloscopeChannel::CHANNEL_TYPE_ANALOG)
{
switch(m_channel->GetCoupling())
@@ -279,7 +287,7 @@ void FilterGraphEditorNode::Render(const Cairo::RefPtr<Cairo::Context>& cr)
auto disabled_color = m_parent->GetPreferences().GetColor("Appearance.Filter Graph.disabled_port_color");
auto line_highlight_color = m_parent->GetPreferences().GetColor("Appearance.Filter Graph.line_highlight_color");

if(this == m_parent->GetDraggedNode() )
if(this == m_parent->GetSelectedNode() )
outline_color = line_highlight_color;

//This is a bit messy... but there's no other good way to figure out what type of input a port wants!
@@ -458,12 +466,18 @@ FilterGraphEditorWidget::FilterGraphEditorWidget(FilterGraphEditor* parent)
, m_filterDialog(NULL)
, m_highlightedPath(NULL)
, m_dragMode(DRAG_NONE)
, m_draggedNode(NULL)
, m_selectedNode(NULL)
, m_dragDeltaY(0)
, m_sourceNode(NULL)
, m_sourcePort(0)
{
add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::POINTER_MOTION_MASK);

auto item = Gtk::manage(new Gtk::MenuItem("Delete", false));
item->signal_activate().connect(
sigc::mem_fun(*this, &FilterGraphEditorWidget::OnDelete));
m_contextMenu.append(*item);

m_contextMenu.show_all();
}

FilterGraphEditorWidget::~FilterGraphEditorWidget()
@@ -811,12 +825,9 @@ void FilterGraphEditorWidget::UpdatePositions()

void FilterGraphEditorWidget::AssignInitialPositions(set<FilterGraphEditorNode*>& nodes)
{
//Start just below the top edge (with a bit of margin)
for(auto node : nodes)
{
//If Y position is zero, move us down by a little bit so we're not touching the edge
if(node->m_rect.get_y() == 0)
node->m_rect.set_y(5);
}
node->m_rect.set_y(5);

for(auto node : nodes)
{
@@ -1101,6 +1112,10 @@ bool FilterGraphEditorWidget::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
for(auto it : m_nodes)
it.second->Render(cr);

//Draw the node being dragged last (if there is one) so it shows up in the foreground
if(m_dragMode == DRAG_NODE)
m_selectedNode->Render(cr);

//Draw all paths
//const int dot_radius = 3;
auto linecolor = GetPreferences().GetColor("Appearance.Filter Graph.line_color");
@@ -1146,10 +1161,10 @@ bool FilterGraphEditorWidget::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
cr->set_dash(dashes, 0);

//Find the start position
auto sourcerect = m_sourceNode->GetOutputPorts()[m_sourcePort].m_rect;
auto sourcerect = m_selectedNode->GetOutputPorts()[m_sourcePort].m_rect;
cr->move_to(
sourcerect.get_right() + m_sourceNode->m_rect.get_x(),
sourcerect.get_top() + sourcerect.get_height()/2 + m_sourceNode->m_rect.get_y());
sourcerect.get_right() + m_selectedNode->m_rect.get_x(),
sourcerect.get_top() + sourcerect.get_height()/2 + m_selectedNode->m_rect.get_y());
cr->line_to(m_mousePosition.x, m_mousePosition.y);
cr->stroke();

@@ -1163,82 +1178,100 @@ bool FilterGraphEditorWidget::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
// Event handlers

bool FilterGraphEditorWidget::on_button_press_event(GdkEventButton* event)
{
if(event->type == GDK_BUTTON_PRESS)
{
if(event->button == 1)
OnLeftClick(event);
else if(event->button == 3)
OnRightClick(event);
}

if(event->type == GDK_2BUTTON_PRESS)
OnDoubleClick(event);

return true;
}

void FilterGraphEditorWidget::OnLeftClick(GdkEventButton* event)
{
auto node = HitTestNode(event->x, event->y);

if( (event->type == GDK_BUTTON_PRESS) && (event->button == 1) )
switch(m_dragMode)
{
switch(m_dragMode)
{
//Complete drawing a net
case DRAG_NET_SOURCE:
//Complete drawing a net
case DRAG_NET_SOURCE:
{
//Get the source signal
auto source = GetSourceStream();

//Make sure we clicked on a destination port
if(!node)
return;
auto f = dynamic_cast<Filter*>(node->m_channel);
if(!f)
return;
auto dest = HitTestNodeInput(event->x, event->y);

//Configure the input, if it's legal
if(f->ValidateChannel(dest->m_index, source))
{
//Get the source signal
auto source = GetSourceStream();

//Make sure we clicked on a destination port
if(!node)
return true;
auto f = dynamic_cast<Filter*>(node->m_channel);
if(!f)
return true;
auto dest = HitTestNodeInput(event->x, event->y);

//Configure the input, if it's legal
if(f->ValidateChannel(dest->m_index, source))
{
f->SetInput(dest->m_index, source);
if(f->IsUsingDefaultName())
f->UseDefaultName(true);
f->SetInput(dest->m_index, source);
if(f->IsUsingDefaultName())
f->UseDefaultName(true);

m_parent->GetParent()->RefreshAllFilters();
m_parent->GetParent()->RefreshAllViews();

Refresh();
}
m_parent->GetParent()->RefreshAllFilters();
m_parent->GetParent()->RefreshAllViews();

m_dragMode = DRAG_NONE;
queue_draw();
Refresh();
}
break;

//Normal
default:
{
if(!node)
return true;
m_dragMode = DRAG_NONE;
queue_draw();
}
break;

//Normal
default:
{
m_selectedNode = node;

if(node)
{
//We clicked on a node. Where on it?
auto source = HitTestNodeOutput(event->x, event->y);

//Start drawing a net from a source
if(source != NULL)
{
m_dragMode = DRAG_NET_SOURCE;
m_sourceNode = node;
m_sourcePort = source->m_index;
}

//Start dragging the node
else
{
m_dragMode = DRAG_NODE;
m_draggedNode = node;
m_dragDeltaY = event->y - node->m_rect.get_y();
}

m_highlightedPath = NULL;
queue_draw();
}
break;

}
queue_draw();
}
break;

}
}

if(event->type == GDK_2BUTTON_PRESS)
OnDoubleClick(event);
void FilterGraphEditorWidget::OnRightClick(GdkEventButton* event)
{
//Update display with the node we clicked on highlighted
m_selectedNode = HitTestNode(event->x, event->y);
queue_draw();

return true;
m_contextMenu.popup(event->button, event->time);
}

bool FilterGraphEditorWidget::on_button_release_event(GdkEventButton* event)
@@ -1253,11 +1286,28 @@ bool FilterGraphEditorWidget::on_button_release_event(GdkEventButton* event)
//no action
break;

//TODO: Snap into final place?
//We just finished dragging a node
case DRAG_NODE:
m_draggedNode = NULL;
queue_draw();
m_dragMode = DRAG_NONE;
{
//Target for collision detection (allow a bit of margin beyond the actual box bounds)
auto target = m_selectedNode->m_rect;
target.expand(0, 5);

//If we collided with anything, unplace it and reassign to the first free space it fits in
auto cols = m_columns[m_selectedNode->m_column];
for(auto node : cols->m_nodes)
{
if(node == m_selectedNode)
continue;

if(node->m_rect.intersects(target))
node->m_positionValid = false;
}

//Done
m_dragMode = DRAG_NONE;
Refresh();
}
break;

default:
@@ -1281,7 +1331,7 @@ bool FilterGraphEditorWidget::on_motion_notify_event(GdkEventMotion* event)
//Move the node
case DRAG_NODE:
m_highlightedPath = NULL;
m_draggedNode->m_rect.set_y(event->y - m_dragDeltaY);
m_selectedNode->m_rect.set_y(event->y - m_dragDeltaY);
Refresh();
break;

@@ -1390,7 +1440,12 @@ StreamDescriptor FilterGraphEditorWidget::GetSourceStream()
return StreamDescriptor(NULL, 0);

else
return StreamDescriptor(m_sourceNode->m_channel, m_sourcePort);
return StreamDescriptor(m_selectedNode->m_channel, m_sourcePort);
}

void FilterGraphEditorWidget::OnDelete()
{
LogDebug("delete\n");
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
18 changes: 10 additions & 8 deletions src/glscopeclient/FilterGraphEditorWidget.h
Original file line number Diff line number Diff line change
@@ -134,8 +134,8 @@ class FilterGraphEditorWidget : public Gtk::DrawingArea

void Refresh();

FilterGraphEditorNode* GetDraggedNode()
{ return m_draggedNode; }
FilterGraphEditorNode* GetSelectedNode()
{ return m_selectedNode; }

PreferenceManager& GetPreferences();

@@ -162,6 +162,8 @@ class FilterGraphEditorWidget : public Gtk::DrawingArea
//Event handlers
virtual bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr);
virtual bool on_button_press_event(GdkEventButton* event);
void OnLeftClick(GdkEventButton* event);
void OnRightClick(GdkEventButton* event);
virtual bool on_button_release_event(GdkEventButton* event);
virtual bool on_motion_notify_event(GdkEventMotion* event);
void OnDoubleClick(GdkEventButton* event);
@@ -189,7 +191,12 @@ class FilterGraphEditorWidget : public Gtk::DrawingArea
void ResolvePathConflicts();
void RoutePath(FilterGraphEditorPath* path);

//Context menu handlers
void OnDelete();

protected:
Gtk::Menu m_contextMenu;

FilterGraphEditor* m_parent;

std::map<OscilloscopeChannel*, FilterGraphEditorNode*> m_nodes;
@@ -207,13 +214,8 @@ class FilterGraphEditorWidget : public Gtk::DrawingArea
FilterGraphEditorPath* m_highlightedPath;

DragMode m_dragMode;

//Node currently being dragged
FilterGraphEditorNode* m_draggedNode;
FilterGraphEditorNode* m_selectedNode;
int m_dragDeltaY;

//Source of the net being drawn
FilterGraphEditorNode* m_sourceNode;
size_t m_sourcePort;

//Current mouse position