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: 12f5004ab83b
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: 96a33805ec37
Choose a head ref
  • 3 commits
  • 3 files changed
  • 1 contributor

Commits on Sep 6, 2020

  1. WaveformArea: now have shared font descriptions for text elements rat…

    …her than creating them anew every render call. Fixes #158.
    azonenberg committed Sep 6, 2020
    Copy the full SHA
    fb50a5b View commit details
  2. WaveformArea: Don't try to draw text if symbol is really short. Overl…

    …ays now use angular instead of rounded edges to speed rendering of large captures. Fixed some visual artifacts on right side of plot.
    azonenberg committed Sep 6, 2020
    Copy the full SHA
    7951f55 View commit details
  3. Copy the full SHA
    96a3380 View commit details
Showing with 141 additions and 120 deletions.
  1. +13 −0 src/glscopeclient/WaveformArea.cpp
  2. +6 −0 src/glscopeclient/WaveformArea.h
  3. +122 −120 src/glscopeclient/WaveformArea_cairo.cpp
13 changes: 13 additions & 0 deletions src/glscopeclient/WaveformArea.cpp
Original file line number Diff line number Diff line change
@@ -52,7 +52,16 @@ WaveformArea::WaveformArea(
, m_channel(channel)
, m_parent(parent)
, m_pixelsPerVolt(1)
, m_axisLabelFont("monospace normal 10")
, m_infoBoxFont("sans normal 10")
, m_cursorLabelFont("sans normal 10")
, m_decodeFont("sans normal 10")
{
m_axisLabelFont.set_weight(Pango::WEIGHT_NORMAL);
m_infoBoxFont.set_weight(Pango::WEIGHT_NORMAL);
m_cursorLabelFont.set_weight(Pango::WEIGHT_NORMAL);
m_decodeFont.set_weight(Pango::WEIGHT_NORMAL);

SharedCtorInit();
}

@@ -66,6 +75,10 @@ WaveformArea::WaveformArea(const WaveformArea* clone)
, m_channel(clone->m_channel)
, m_parent(clone->m_parent)
, m_pixelsPerVolt(clone->m_pixelsPerVolt)
, m_axisLabelFont(clone->m_axisLabelFont)
, m_infoBoxFont(clone->m_infoBoxFont)
, m_cursorLabelFont(clone->m_cursorLabelFont)
, m_decodeFont(clone->m_decodeFont)
{
SharedCtorInit();
}
6 changes: 6 additions & 0 deletions src/glscopeclient/WaveformArea.h
Original file line number Diff line number Diff line change
@@ -498,6 +498,12 @@ class WaveformArea : public Gtk::GLArea
bool m_firstFrame;
bool m_geometryDirty;
bool m_positionDirty;

//Fonts used for drawing various UI elements
Pango::FontDescription m_axisLabelFont;
Pango::FontDescription m_infoBoxFont;
Pango::FontDescription m_cursorLabelFont;
Pango::FontDescription m_decodeFont;
};

#endif
242 changes: 122 additions & 120 deletions src/glscopeclient/WaveformArea_cairo.cpp
Original file line number Diff line number Diff line change
@@ -86,21 +86,19 @@ void WaveformArea::RenderBackgroundGradient(Cairo::RefPtr< Cairo::Context > cr)

void WaveformArea::RenderGrid(Cairo::RefPtr< Cairo::Context > cr)
{
//If we're a digital channel, no grid or anything else makes sense
if(m_channel.m_channel->GetType() == OscilloscopeChannel::CHANNEL_TYPE_DIGITAL)
return;

//Calculate width of right side axis label
int twidth;
int theight;
Glib::RefPtr<Pango::Layout> tlayout = Pango::Layout::create (cr);
Pango::FontDescription font("monospace normal 10");
font.set_weight(Pango::WEIGHT_NORMAL);
tlayout->set_font_description(font);
tlayout->set_font_description(m_axisLabelFont);
tlayout->set_text("500.000 mV_xx");
tlayout->get_pixel_size(twidth, theight);
m_plotRight = m_width - twidth;

//If we're a digital channel, no grid or anything else makes sense.
if(m_channel.m_channel->GetType() == OscilloscopeChannel::CHANNEL_TYPE_DIGITAL)
return;

if(IsWaterfall())
return;

@@ -580,9 +578,7 @@ void WaveformArea::RenderChannelInfoBox(
int twidth;
int theight;
Glib::RefPtr<Pango::Layout> tlayout = Pango::Layout::create (cr);
Pango::FontDescription font("sans normal 10");
font.set_weight(Pango::WEIGHT_NORMAL);
tlayout->set_font_description(font);
tlayout->set_font_description(m_infoBoxFont);
tlayout->set_text(text);
tlayout->get_pixel_size(twidth, theight);

@@ -653,9 +649,7 @@ void WaveformArea::RenderCursor(Cairo::RefPtr< Cairo::Context > cr, int64_t pos,
int twidth;
int theight;
Glib::RefPtr<Pango::Layout> tlayout = Pango::Layout::create (cr);
Pango::FontDescription font("sans normal 10");
font.set_weight(Pango::WEIGHT_NORMAL);
tlayout->set_font_description(font);
tlayout->set_font_description(m_cursorLabelFont);
tlayout->set_text(text);
tlayout->get_pixel_size(twidth, theight);

@@ -777,9 +771,7 @@ void WaveformArea::RenderInBandPower(Cairo::RefPtr< Cairo::Context > cr)
int twidth;
int theight;
Glib::RefPtr<Pango::Layout> tlayout = Pango::Layout::create (cr);
Pango::FontDescription font("sans normal 10");
font.set_weight(Pango::WEIGHT_NORMAL);
tlayout->set_font_description(font);
tlayout->set_font_description(m_cursorLabelFont);
tlayout->set_text(text);
tlayout->get_pixel_size(twidth, theight);

@@ -889,26 +881,21 @@ void WaveformArea::RenderInsertionBar(Cairo::RefPtr< Cairo::Context > cr)

void WaveformArea::MakePathSignalBody(
const Cairo::RefPtr<Cairo::Context>& cr,
float xstart, float /*xoff*/, float xend, float ybot, float /*ymid*/, float ytop)
float xstart, float /*xoff*/, float xend, float ybot, float ymid, float ytop)
{
//If the signal is really tiny, shrink the rounding to avoid going out of bounds
float rounding = 10;
if(xstart + 2*rounding > xend)
rounding = (xend - xstart) / 2;
//Square off edges if really tiny
float rounding = 5;
if((xend-xstart) < 2*rounding)
rounding = 0;

cr->begin_new_sub_path();
cr->arc(xstart + rounding, ytop + rounding, rounding, M_PI, M_PI*1.5f); //top left corner
cr->move_to(xstart + rounding, ytop); //top edge
cr->line_to(xend - rounding, ytop);
cr->arc(xend - rounding, ytop + rounding, rounding, M_PI*1.5f, 0); //top right corner
cr->move_to(xend, ytop + rounding); //right edge
cr->line_to(xend, ybot - rounding);
cr->arc(xend - rounding, ybot - rounding, rounding, 0, M_PI_2); //bottom right corner
cr->move_to(xend - rounding, ybot); //bottom edge
cr->line_to(xstart + rounding, ybot);
cr->arc(xstart + rounding, ybot - rounding, rounding, M_PI_2, M_PI); //bottom left corner
cr->move_to(xstart, ybot - rounding); //left edge
cr->line_to(xstart, ytop + rounding);
cr->move_to(xstart, ymid); //left point
cr->line_to(xstart + rounding, ytop); //top left corner
cr->line_to(xend - rounding, ytop); //top right corner
cr->line_to(xend, ymid); //right point
cr->line_to(xend - rounding, ybot); //bottom right corner
cr->line_to(xstart + rounding, ybot); //bottom left corner
cr->line_to(xstart, ymid); //left point again
}

void WaveformArea::RenderComplexSignal(
@@ -919,125 +906,140 @@ void WaveformArea::RenderComplexSignal(
string str,
Gdk::Color color)
{
Pango::FontDescription font("sans normal 10");
int width = 0, sheight = 0;
GetStringWidth(cr, str, width, sheight, font);
//Clamp start point to left side of display
if(xstart < visleft)
xstart = visleft;

//First-order guess of position: center of the value
float xp = xstart + (xend-xstart)/2;

//Width within this signal outline
float available_width = xend - xstart - 2*xoff;

//Minimum width (if outline ends up being smaller than this, just fill)
float min_width = 40;
if(width < min_width)
min_width = width;

//Does the string fit at all? If not, skip all of the messy math
if(available_width < min_width)
str = "";
else
//If the space is tiny, don't even attempt to render it.
//Figuring out text size is expensive when we have hundreds or thousands of packets on screen, but in this case
//we *know* it won't fit.
bool drew_text = false;
if(available_width > 15)
{
//Center the text by moving it left half a width
xp -= width/2;
int width;
int sheight;

//Off the left end? Push it right
int padding = 5;
if(xp < (visleft + padding))
{
xp = visleft + padding;
available_width = xend - xp - xoff;
}
Glib::RefPtr<Pango::Layout> tlayout = Pango::Layout::create (cr);
tlayout->set_font_description(m_decodeFont);
tlayout->set_text(str);
tlayout->get_pixel_size(width, sheight);

//Minimum width (if outline ends up being smaller than this, just fill)
float min_width = 40;
if(width < min_width)
min_width = width;

//Off the right end? Push it left
else if( (xp + width + padding) > visright)
//Does the string fit at all? If not, skip all of the messy math
if(available_width < min_width)
str = "";
else
{
xp = visright - (width + padding + xoff);
if(xp < xstart)
xp = xstart + xoff;
//Center the text by moving it left half a width
xp -= width/2;

if(xend < visright)
//Off the left end? Push it right
int padding = 5;
if(xp < (visleft + padding))
{
xp = visleft + padding;
available_width = xend - xp - xoff;
else
available_width = visright - xp - xoff;
}
}

//If we don't fit under the new constraints, give up
if(available_width < min_width)
str = "";
}
//Off the right end? Push it left
else if( (xp + width + padding) > visright)
{
xp = visright - (width + padding + xoff);
if(xp < xstart)
xp = xstart + xoff;

//Draw the text
if(str != "")
{
//Text is always white (TODO: only in overlays?)
cr->set_source_rgb(1, 1, 1);

//If we need to trim, decide which way to do it.
//If the text is all caps and includes an underscore, it's probably a macro with a prefix.
//Trim from the left in this case. Otherwise, trim from the right.
bool trim_from_right = true;
bool is_all_upper = true;
for(size_t i=0; i<str.length(); i++)
{
if(islower(str[i]))
is_all_upper = false;
if(xend < visright)
available_width = xend - xp - xoff;
else
available_width = visright - xp - xoff;
}

//If we don't fit under the new constraints, give up
if(available_width < min_width)
str = "";
}
if(is_all_upper && (str.find("_") != string::npos))
trim_from_right = false;

//Some text fits, but maybe not all of it
//We know there's enough room for "some" text
//Try shortening the string a bit at a time until it fits
//(Need to do an O(n) search since character width is variable and unknown to us without knowing details
//of the font currently in use)
string str_render = str;
if(width > available_width)

//Draw the text
if(str != "")
{
for(int len = str.length() - 1; len > 1; len--)
//Text is always white (TODO: only in overlays?)
cr->set_source_rgb(1, 1, 1);

//If we need to trim, decide which way to do it.
//If the text is all caps and includes an underscore, it's probably a macro with a prefix.
//Trim from the left in this case. Otherwise, trim from the right.
bool trim_from_right = true;
bool is_all_upper = true;
for(size_t i=0; i<str.length(); i++)
{
if(trim_from_right)
str_render = str.substr(0, len) + "...";
else
str_render = "..." + str.substr(str.length() - len - 1);

int twidth = 0, theight = 0;
GetStringWidth(cr, str_render, twidth, theight, font);
if(twidth < available_width)
if(islower(str[i]))
is_all_upper = false;
}
if(is_all_upper && (str.find("_") != string::npos))
trim_from_right = false;

//Some text fits, but maybe not all of it
//We know there's enough room for "some" text
//Try shortening the string a bit at a time until it fits
//(Need to do an O(n) search since character width is variable and unknown to us without knowing details
//of the font currently in use)
string str_render = str;
if(width > available_width)
{
for(int len = str.length() - 1; len > 1; len--)
{
//Re-center text in available space
//TODO: Move to avoid any time-split lines
xp += (available_width - twidth)/2;
if(xp < (xstart + xoff))
xp = (xstart + xoff);
break;
if(trim_from_right)
str_render = str.substr(0, len) + "...";
else
str_render = "..." + str.substr(str.length() - len - 1);

int twidth = 0, theight = 0;
tlayout->set_text(str_render);
tlayout->get_pixel_size(twidth, theight);

if(twidth < available_width)
{
//Re-center text in available space
//TODO: Move to avoid any time-split lines
xp += (available_width - twidth)/2;
if(xp < (xstart + xoff))
xp = (xstart + xoff);
break;
}
}
}
}

cr->save();
Glib::RefPtr<Pango::Layout> tlayout = Pango::Layout::create (cr);
cr->move_to(xp, ymid - sheight/2);
font.set_weight(Pango::WEIGHT_NORMAL);
tlayout->set_font_description(font);
tlayout->set_text(str_render);
tlayout->update_from_cairo_context(cr);
tlayout->show_in_cairo_context(cr);
cr->restore();
drew_text = true;
cr->save();
cr->move_to(xp, ymid - sheight/2);
tlayout->update_from_cairo_context(cr);
tlayout->show_in_cairo_context(cr);
cr->restore();
}
}

if(xend > visright)
xend = visright;

//If no text fit, draw filler instead
else
if(!drew_text)
{
cr->set_source_rgb(color.get_red_p() * 0.25, color.get_green_p() * 0.25, color.get_blue_p() * 0.25);
MakePathSignalBody(cr, xstart, xoff, xend, ybot, ymid, ytop);
cr->fill();
}

//Draw the body outline after any filler so it shows up on top
if(xend > visright)
xend = visright;
cr->set_source_rgb(color.get_red_p(), color.get_green_p(), color.get_blue_p());
MakePathSignalBody(cr, xstart, xoff, xend, ybot, ymid, ytop);
cr->stroke();