summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ui/qt/overlay_scroll_bar.cpp251
-rw-r--r--ui/qt/overlay_scroll_bar.h33
-rw-r--r--ui/qt/packet_list.cpp113
-rw-r--r--ui/qt/packet_list.h3
4 files changed, 237 insertions, 163 deletions
diff --git a/ui/qt/overlay_scroll_bar.cpp b/ui/qt/overlay_scroll_bar.cpp
index 351faba3a8..51d077a160 100644
--- a/ui/qt/overlay_scroll_bar.cpp
+++ b/ui/qt/overlay_scroll_bar.cpp
@@ -21,130 +21,215 @@
#include "overlay_scroll_bar.h"
+#include "color_utils.h"
+
+#include <QMouseEvent>
#include <QPainter>
+#include <QProxyStyle>
#include <QResizeEvent>
-#include <QStyle>
#include <QStyleOptionSlider>
// To do:
-// - The slider hole doesn't match up with the slider on OS X + Qt 5.3.2.
-// - Instead of drawing the map over the scrollbar we could draw it to the
-// right of the scrollbar. Many text editors to this. It would let us
-// widen the map a bit, which would in turn let us add frame size or
-// timing information.
+// - We could graph something useful (e.g. delay times) in packet_map_img_.
+// https://www.wireshark.org/lists/ethereal-dev/200011/msg00122.html
+// - Properly handle transience.
+
+// We want a normal scrollbar with space on either side on which we can draw
+// and receive mouse events. Adding space using a stylesheet loses native
+// styling on Windows. Overriding QProxyStyle::drawComplexControl (which is
+// called by QScrollBar::paintEvent) results in odd behavior on Windows.
+//
+// The best solution so far seems to be to simply create a normal-sized child
+// scrollbar, manually position it, and synchronize it with its parent. We
+// can then alter the parent's mouse and paint behavior to our heart's
+// content.
+
+class OsbProxyStyle : public QProxyStyle
+{
+ public:
+ // Hack to keep the scrollbar from disappearing on OS X. We should
+ // handle this more gracefully.
+ virtual int styleHint(StyleHint hint, const QStyleOption *option = Q_NULLPTR, const QWidget *widget = Q_NULLPTR, QStyleHintReturn *returnData = Q_NULLPTR) const {
+ if (hint == SH_ScrollBar_Transient) return false;
+
+ return QProxyStyle::styleHint(hint, option, widget, returnData);
+ }
+};
OverlayScrollBar::OverlayScrollBar(Qt::Orientation orientation, QWidget *parent) :
QScrollBar(orientation, parent = 0),
- near_overlay_(QImage()),
- far_overlay_(QImage()),
+ child_sb_(orientation, this),
+ packet_map_img_(QImage()),
+ packet_map_width_(0),
+ start_pos_(-1),
+ end_pos_(-1),
selected_pos_(-1)
-{}
+{
+ setStyle(new OsbProxyStyle);
+
+ child_sb_.raise();
+ child_sb_.installEventFilter(this);
+
+ // XXX Do we need to connect anything else?
+ connect(this, SIGNAL(rangeChanged(int,int)), &child_sb_, SLOT(setRange(int,int)));
+ connect(this, SIGNAL(valueChanged(int)), &child_sb_, SLOT(setValue(int)));
+
+ connect(&child_sb_, SIGNAL(valueChanged(int)), this, SLOT(setValue(int)));
+}
QSize OverlayScrollBar::sizeHint() const
{
- return QSize(QScrollBar::sizeHint().width() + (far_overlay_.width() * 2), QScrollBar::sizeHint().height());
+ return QSize(packet_map_width_ + child_sb_.sizeHint().width(),
+ QScrollBar::sizeHint().height());
}
-void OverlayScrollBar::setNearOverlayImage(QImage &overlay_image, int selected_pos)
+void OverlayScrollBar::setNearOverlayImage(QImage &overlay_image, int start_pos, int end_pos, int selected_pos)
{
- near_overlay_ = overlay_image;
+ int old_width = packet_map_img_.width();
+ packet_map_img_ = overlay_image;
+ start_pos_ = start_pos;
+ end_pos_ = end_pos;
selected_pos_ = selected_pos;
- update();
-}
-void OverlayScrollBar::setFarOverlayImage(QImage &overlay_image)
-{
- int old_width = far_overlay_.width();
- far_overlay_ = overlay_image;
- if (old_width != far_overlay_.width()) {
+ if (old_width != packet_map_img_.width()) {
+ qreal dp_ratio = 1.0;
+ #if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
+ dp_ratio = devicePixelRatio();
+ #endif
+
+ packet_map_width_ = packet_map_img_.width() / dp_ratio;
+
updateGeometry();
}
update();
}
+void OverlayScrollBar::setMarkedPacketImage(QImage &mp_image)
+{
+ qreal dp_ratio = 1.0;
+#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
+ dp_ratio = devicePixelRatio();
+#endif
+
+ marked_packet_img_ = mp_image;
+ marked_packet_width_ = mp_image.width() / dp_ratio;
+
+ child_sb_.update();
+}
+
QRect OverlayScrollBar::grooveRect()
{
QStyleOptionSlider opt;
+
initStyleOption(&opt);
+ opt.rect = child_sb_.rect();
- return style()->subControlRect(QStyle::CC_ScrollBar, &opt, QStyle::SC_ScrollBarGroove, this);
+ return child_sb_.style()->subControlRect(QStyle::CC_ScrollBar, &opt, QStyle::SC_ScrollBarGroove, &child_sb_);
+}
+
+void OverlayScrollBar::resizeEvent(QResizeEvent *event)
+{
+ QScrollBar::resizeEvent(event);
+
+ child_sb_.move(packet_map_width_, 0);
+ child_sb_.resize(child_sb_.sizeHint().width(), height());
}
void OverlayScrollBar::paintEvent(QPaintEvent *event)
{
- QScrollBar::paintEvent(event);
- if (!near_overlay_.isNull()) {
- QRect groove_rect = grooveRect();
- QSize gr_size = groove_rect.size();
- qreal dp_ratio = 1.0;
+ qreal dp_ratio = 1.0;
+ QSize pm_size(packet_map_width_, geometry().height());
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
- dp_ratio = devicePixelRatio();
- gr_size *= dp_ratio;
+ dp_ratio = devicePixelRatio();
+ pm_size *= dp_ratio;
#endif
- QImage groove_overlay(gr_size, QImage::Format_ARGB32_Premultiplied);
- groove_overlay.fill(Qt::transparent);
-
- // Draw the image supplied by the packet list and apply a mask.
- QPainter go_painter(&groove_overlay);
- go_painter.setPen(Qt::NoPen);
-
- int fo_width = far_overlay_.width();
- QRect near_dest(fo_width, 0, gr_size.width() - (fo_width * 2), gr_size.height());
- go_painter.drawImage(near_dest, near_overlay_.scaled(near_dest.size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
- if (fo_width > 0) {
- QRect far_dest(0, 0, fo_width, gr_size.height());
- go_painter.drawImage(far_dest, far_overlay_);
- far_dest.moveLeft(gr_size.width() - fo_width);
- go_painter.drawImage(far_dest, far_overlay_.mirrored(true, false));
- }
+
+ QPainter painter(this);
+
+ painter.fillRect(event->rect(), palette().window());
+
+ if (!packet_map_img_.isNull()) {
+ QImage packet_map(pm_size, QImage::Format_ARGB32_Premultiplied);
+ packet_map.fill(Qt::transparent);
+
+ // Draw the image supplied by the packet list.
+ QPainter pm_painter(&packet_map);
+ pm_painter.setPen(Qt::NoPen);
+
+ QRect near_dest(0, 0, pm_size.width(), pm_size.height());
+ pm_painter.drawImage(near_dest, packet_map_img_.scaled(near_dest.size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
// Selected packet indicator
- if (selected_pos_ >= 0 && selected_pos_ < near_overlay_.height()) {
- int no_pos = near_dest.height() * selected_pos_ / near_overlay_.height();
- go_painter.save();
- go_painter.setBrush(palette().highlight().color());
- go_painter.drawRect(0, no_pos, gr_size.width(), dp_ratio);
- go_painter.restore();
+ if (selected_pos_ >= 0 && selected_pos_ < packet_map_img_.height()) {
+ pm_painter.save();
+ int no_pos = near_dest.height() * selected_pos_ / packet_map_img_.height();
+ pm_painter.setBrush(palette().highlight().color());
+ pm_painter.drawRect(0, no_pos, pm_size.width(), dp_ratio);
+ pm_painter.restore();
}
- // Outline
- QRect near_outline(near_dest);
- near_outline.adjust(0, 0, -1, -1);
- go_painter.save();
- QColor no_fg(palette().text().color());
- no_fg.setAlphaF(0.25);
- go_painter.setPen(no_fg);
- go_painter.drawRect(near_outline);
- go_painter.restore();
-
- // Punch a hole for the slider.
- QStyleOptionSlider opt;
- initStyleOption(&opt);
-
- QRect slider_rect = style()->subControlRect(QStyle::CC_ScrollBar, &opt, QStyle::SC_ScrollBarSlider, this);
+ // Borders
+ pm_painter.save();
+ QColor border_color(ColorUtils::alphaBlend(palette().text(), palette().window(), 0.25));
+ pm_painter.setPen(border_color);
+ pm_painter.drawLine(near_dest.topLeft(), near_dest.bottomLeft());
+ pm_painter.drawLine(near_dest.topRight(), near_dest.bottomRight());
+ pm_painter.restore();
+
+ // Draw the map.
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
- slider_rect.setHeight(slider_rect.height() * devicePixelRatio());
- slider_rect.setWidth(slider_rect.width() * devicePixelRatio());
- slider_rect.moveTop((slider_rect.top() - groove_rect.top()) * devicePixelRatio());
-#else
- slider_rect.moveTop(slider_rect.top() - groove_rect.top());
+ packet_map.setDevicePixelRatio(dp_ratio);
#endif
- slider_rect.adjust(fo_width + 1, 1, -1 - fo_width, -1);
-
- go_painter.save();
- go_painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
- QColor slider_hole(Qt::white);
- slider_hole.setAlphaF(0.1);
- go_painter.setBrush(slider_hole);
- go_painter.drawRect(slider_rect);
- go_painter.restore();
-
- // Draw over the groove.
- QPainter painter(this);
+ painter.drawImage(0, 0, packet_map);
+ }
+}
+
+bool OverlayScrollBar::eventFilter(QObject *watched, QEvent *event)
+{
+ bool ret = false;
+ if (watched == &child_sb_ && event->type() == QEvent::Paint) {
+ // Paint the scrollbar first.
+ child_sb_.event(event);
+ ret = true;
+
+ if (!marked_packet_img_.isNull()) {
+ qreal dp_ratio = 1.0;
+ QRect groove_rect = grooveRect();
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
- groove_overlay.setDevicePixelRatio(devicePixelRatio());
+ dp_ratio = devicePixelRatio();
+ groove_rect.setTopLeft(groove_rect.topLeft() * dp_ratio);
+ groove_rect.setSize(groove_rect.size() * dp_ratio);
#endif
- painter.drawImage(groove_rect.topLeft(), groove_overlay);
+
+ QImage marked_map(groove_rect.width(), groove_rect.height(), QImage::Format_ARGB32_Premultiplied);
+ marked_map.fill(Qt::transparent);
+
+ QPainter mm_painter(&marked_map);
+ mm_painter.setPen(Qt::NoPen);
+
+ QRect far_dest(0, 0, groove_rect.width(), groove_rect.height());
+ mm_painter.drawImage(far_dest, marked_packet_img_.scaled(far_dest.size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
+
+ #if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
+ marked_map.setDevicePixelRatio(dp_ratio);
+ #endif
+ QPainter painter(&child_sb_);
+ painter.drawImage(groove_rect.left(), groove_rect.top(), marked_map);
+ }
+ }
+
+ return ret;
+}
+
+void OverlayScrollBar::mouseReleaseEvent(QMouseEvent *event)
+{
+ QRect pm_r(0, 0, packet_map_width_, height());
+
+ if (pm_r.contains(event->pos())) {
+ qreal map_ratio = qreal(end_pos_ - start_pos_) / geometry().height();
+
+ // Try to put the clicked packet near but not at the top.
+ setValue((event->pos().y() * map_ratio) + start_pos_ - (pageStep() / 4));
}
}
diff --git a/ui/qt/overlay_scroll_bar.h b/ui/qt/overlay_scroll_bar.h
index d1e37d408c..a9e2d7ad3b 100644
--- a/ui/qt/overlay_scroll_bar.h
+++ b/ui/qt/overlay_scroll_bar.h
@@ -35,25 +35,46 @@ public:
/** Set the "near" overlay image.
* @param overlay_image An image containing a 1:1 mapping of nearby
- * packet colors to raster lines.
+ * packet colors to raster lines. It should be sized in device
+ * pixels.
+ * @param start_pos The first packet number represented by the image.
+ * -1 means no packet is selected.
+ * @param end_pos The last packet number represented by the image. -1
+ * means no packet is selected.
* @param selected_pos The position of the selected packet within the
* image. -1 means no packet is selected.
*/
- void setNearOverlayImage(QImage &overlay_image, int selected_pos = -1);
+ void setNearOverlayImage(QImage &overlay_image, int start_pos = -1, int end_pos = -1, int selected_pos = -1);
/** Set the "far" overlay image.
* @param overlay_image An image showing the position of marked, ignored,
- * and reference time packets over the entire packet list.
+ * and reference time packets over the entire packet list. It
+ * should be sized in device pixels.
+ */
+ void setMarkedPacketImage(QImage &mp_image);
+
+
+ /** The "groove" area of the child scrollbar.
*/
- void setFarOverlayImage(QImage &overlay_image);
QRect grooveRect();
+public slots:
+
protected:
+ virtual void resizeEvent(QResizeEvent * event);
virtual void paintEvent(QPaintEvent * event);
+ virtual bool eventFilter(QObject *watched, QEvent *event);
+ virtual void mousePressEvent(QMouseEvent *) { /* No-op */ }
+ virtual void mouseReleaseEvent(QMouseEvent * event);
private:
- QImage near_overlay_;
- QImage far_overlay_;
+ QScrollBar child_sb_;
+ QImage packet_map_img_;
+ QImage marked_packet_img_;
+ int packet_map_width_;
+ int marked_packet_width_;
+ int start_pos_;
+ int end_pos_;
int selected_pos_;
};
diff --git a/ui/qt/packet_list.cpp b/ui/qt/packet_list.cpp
index c775317518..ad417e9f35 100644
--- a/ui/qt/packet_list.cpp
+++ b/ui/qt/packet_list.cpp
@@ -592,6 +592,13 @@ void PacketList::mousePressEvent (QMouseEvent *event)
setAutoScroll(true);
}
+void PacketList::resizeEvent(QResizeEvent *event)
+{
+ create_near_overlay_ = true;
+ create_far_overlay_ = true;
+ QTreeView::resizeEvent(event);
+}
+
void PacketList::setColumnVisibility()
{
set_column_visibility_ = true;
@@ -857,7 +864,7 @@ void PacketList::clear() {
QImage overlay;
overlay_sb_->setNearOverlayImage(overlay);
- overlay_sb_->setFarOverlayImage(overlay);
+ overlay_sb_->setMarkedPacketImage(overlay);
create_near_overlay_ = true;
create_far_overlay_ = true;
@@ -1429,7 +1436,7 @@ void PacketList::vScrollBarActionTriggered(int)
// Odd (prime?) numbers resulted in fewer scaling artifacts. A multiplier
// of 9 washed out colors a little too much.
-const int height_multiplier_ = 7;
+//const int height_multiplier_ = 7;
void PacketList::drawNearOverlay()
{
if (create_near_overlay_) {
@@ -1444,18 +1451,15 @@ void PacketList::drawNearOverlay()
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
dp_ratio = overlay_sb_->devicePixelRatio();
#endif
- int o_height = overlay_sb_->height() * dp_ratio * height_multiplier_;
+ int o_height = overlay_sb_->height() * dp_ratio;
int o_rows = qMin(packet_list_model_->rowCount(), o_height);
+ int o_width = (wsApp->fontMetrics().height() * 2 * dp_ratio) + 2; // 2ems + 1-pixel border on either side.
int selected_pos = -1;
if (recent.packet_list_colorize && o_rows > 0) {
- QImage overlay(1, o_height, QImage::Format_ARGB32_Premultiplied);
+ QImage overlay(o_width, o_height, QImage::Format_ARGB32_Premultiplied);
QPainter painter(&overlay);
-#if 0
- QElapsedTimer timer;
- timer.start();
-#endif
overlay.fill(Qt::transparent);
@@ -1469,18 +1473,6 @@ void PacketList::drawNearOverlay()
for (int row = start; row < end; row++) {
packet_list_model_->ensureRowColorized(row);
-#if 0
- // Try to remain responsive for large captures.
- if (timer.elapsed() > update_time_) {
- wsApp->processEvents();
- if (!cap_file_ || cap_file_->state != FILE_READ_DONE) {
- create_overlay_ = true;
- return;
- }
- timer.restart();
- }
-#endif
-
frame_data *fdata = packet_list_model_->getRowFdata(row);
const color_t *bgcolor = NULL;
if (fdata->color_filter) {
@@ -1491,9 +1483,7 @@ void PacketList::drawNearOverlay()
int next_line = (row - start) * o_height / o_rows;
if (bgcolor) {
QColor color(ColorUtils::fromColorT(bgcolor));
-
- painter.setPen(color);
- painter.drawLine(0, cur_line, 0, next_line);
+ painter.fillRect(0, cur_line, o_width, next_line - cur_line, color);
}
cur_line = next_line;
}
@@ -1511,7 +1501,7 @@ void PacketList::drawNearOverlay()
}
}
- overlay_sb_->setNearOverlayImage(overlay, selected_pos);
+ overlay_sb_->setNearOverlayImage(overlay, start, end, selected_pos);
} else {
QImage overlay;
overlay_sb_->setNearOverlayImage(overlay);
@@ -1528,78 +1518,55 @@ void PacketList::drawFarOverlay()
if (!prefs.gui_packet_list_show_minimap) return;
+ QSize groove_size = overlay_sb_->grooveRect().size();
qreal dp_ratio = 1.0;
#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
dp_ratio = overlay_sb_->devicePixelRatio();
+ groove_size *= dp_ratio;
#endif
- int o_width = 2 * dp_ratio;
- int o_height = overlay_sb_->height() * dp_ratio;
+ int o_width = groove_size.width();
+ int o_height = groove_size.height();
int pl_rows = packet_list_model_->rowCount();
+ QImage overlay(o_width, o_height, QImage::Format_ARGB32_Premultiplied);
- if (recent.packet_list_colorize && pl_rows > 0) {
- // Create a tall image here. OverlayScrollBar will scale it to fit.
- QImage overlay(o_width, o_height, QImage::Format_ARGB32_Premultiplied);
+ // If only there were references from popular culture about getting into
+ // some sort of groove.
+ if (!overlay.isNull() && recent.packet_list_colorize && pl_rows > 0) {
QPainter painter(&overlay);
- painter.setRenderHint(QPainter::Antialiasing);
-#if 0
- QElapsedTimer timer;
- timer.start();
-#endif
- // The default "marked" background is black and the default "ignored"
- // background is white. Instead of trying to figure out if our
- // available colors will show up, just use the palette's background
- // here and foreground below.
-#if QT_VERSION < QT_VERSION_CHECK(4, 8, 0)
- overlay.fill(palette().base().color().value());
-#else
- overlay.fill(palette().base().color());
-#endif
- QColor arrow_fg = palette().text().color();
- arrow_fg.setAlphaF(0.3);
- painter.setPen(arrow_fg);
- painter.setBrush(arrow_fg);
+ // Draw text-colored tick marks on a transparent background.
+ // Hopefully no themes use the text color for the groove color.
+ overlay.fill(Qt::transparent);
+
+ QColor tick_color = palette().text().color();
+ tick_color.setAlphaF(0.3);
+ painter.setPen(tick_color);
bool have_far = false;
for (int row = 0; row < pl_rows; row++) {
-#if 0
- // Try to remain responsive for large captures.
- if (timer.elapsed() > update_time_) {
- wsApp->processEvents();
- if (!cap_file_ || cap_file_->state != FILE_READ_DONE) {
- create_overlay_ = true;
- return;
- }
- timer.restart();
- }
-#endif
frame_data *fdata = packet_list_model_->getRowFdata(row);
- bool marked = false;
if (fdata->flags.marked || fdata->flags.ref_time || fdata->flags.ignored) {
- marked = true;
- }
-
- if (marked) {
- int new_line = (row) * o_height / pl_rows;
-
- QPointF points[3] = {
- QPointF(o_width, new_line),
- QPointF(0, new_line - (o_width * 0.7)),
- QPointF(0, new_line + (o_width * 0.7))
- };
- painter.drawPolygon(points, 3);
+ int new_line = row * o_height / pl_rows;
+ int tick_width = o_width / 3;
+ // Marked or ignored: left side, time refs: right side.
+ // XXX Draw ignored ticks in the middle?
+ int x1 = fdata->flags.ref_time ? o_width - tick_width : 1;
+ int x2 = fdata->flags.ref_time ? o_width - 1 : tick_width;
+
+ painter.drawLine(x1, new_line, x2, new_line);
have_far = true;
}
}
if (have_far) {
- overlay_sb_->setFarOverlayImage(overlay);
+ overlay_sb_->setMarkedPacketImage(overlay);
return;
}
+ } else {
QImage null_overlay;
- overlay_sb_->setFarOverlayImage(null_overlay);
+ overlay_sb_->setMarkedPacketImage(null_overlay);
}
}
diff --git a/ui/qt/packet_list.h b/ui/qt/packet_list.h
index 2c11029bff..aad3d03fb6 100644
--- a/ui/qt/packet_list.h
+++ b/ui/qt/packet_list.h
@@ -82,7 +82,8 @@ protected:
void contextMenuEvent(QContextMenuEvent *event);
void timerEvent(QTimerEvent *event);
void paintEvent(QPaintEvent *event);
- virtual void mousePressEvent (QMouseEvent * event);
+ virtual void mousePressEvent (QMouseEvent *event);
+ virtual void resizeEvent(QResizeEvent *event);
protected slots:
void rowsInserted(const QModelIndex &parent, int start, int end);