From adf428ffd0ded73d3c7ef4196a7c1a3f4403a2fc Mon Sep 17 00:00:00 2001 From: DreamSourceLab Date: Tue, 3 May 2016 15:47:06 +0800 Subject: [PATCH] Add protocol list viewer and export support --- DSView/DSView.qrc | 1 + DSView/darkstyle/style.qss | 1218 +++++++++++++++++++++++++ DSView/main.cpp | 3 +- DSView/pv/data/decode/annotation.cpp | 6 + DSView/pv/data/decode/annotation.h | 1 + DSView/pv/data/decode/row.cpp | 4 +- DSView/pv/data/decode/row.h | 2 +- DSView/pv/data/decode/rowdata.cpp | 38 +- DSView/pv/data/decode/rowdata.h | 9 +- DSView/pv/data/decodermodel.cpp | 108 +++ DSView/pv/data/decodermodel.h | 62 ++ DSView/pv/data/decoderstack.cpp | 345 ++++--- DSView/pv/data/decoderstack.h | 35 +- DSView/pv/dialogs/protocolexp.cpp | 215 +++++ DSView/pv/dialogs/protocolexp.h | 85 ++ DSView/pv/dialogs/protocollist.cpp | 183 ++++ DSView/pv/dialogs/protocollist.h | 76 ++ DSView/pv/dock/protocoldock.cpp | 187 +++- DSView/pv/dock/protocoldock.h | 25 +- DSView/pv/mainwindow.cpp | 2 + DSView/pv/sigsession.cpp | 12 +- DSView/pv/sigsession.h | 8 + DSView/pv/toolbars/samplingbar.cpp | 13 +- DSView/pv/view/decodetrace.cpp | 254 +++--- DSView/pv/view/decodetrace.h | 16 +- DSView/pv/view/devmode.cpp | 66 +- DSView/pv/view/devmode.h | 12 +- DSView/pv/view/groupsignal.cpp | 7 +- DSView/pv/view/header.cpp | 4 +- DSView/pv/view/logicsignal.cpp | 66 +- DSView/pv/view/logicsignal.h | 2 +- DSView/pv/view/ruler.cpp | 5 +- DSView/pv/view/ruler.h | 1 + DSView/pv/view/trace.cpp | 98 +- DSView/pv/view/trace.h | 8 +- DSView/pv/view/view.cpp | 22 +- DSView/pv/view/view.h | 1 + DSView/pv/view/viewport.cpp | 10 +- DSView/pv/widgets/decodergroupbox.cpp | 118 ++- DSView/pv/widgets/decodergroupbox.h | 36 +- DSView/stylesheet.qss | 20 + 41 files changed, 2901 insertions(+), 483 deletions(-) create mode 100755 DSView/darkstyle/style.qss create mode 100644 DSView/pv/data/decodermodel.cpp create mode 100644 DSView/pv/data/decodermodel.h create mode 100644 DSView/pv/dialogs/protocolexp.cpp create mode 100644 DSView/pv/dialogs/protocolexp.h create mode 100644 DSView/pv/dialogs/protocollist.cpp create mode 100644 DSView/pv/dialogs/protocollist.h diff --git a/DSView/DSView.qrc b/DSView/DSView.qrc index 05955d6d..76bf2800 100644 --- a/DSView/DSView.qrc +++ b/DSView/DSView.qrc @@ -56,5 +56,6 @@ icons/start_dis.png icons/start_dis_cn.png icons/settings.png + darkstyle/style.qss diff --git a/DSView/darkstyle/style.qss b/DSView/darkstyle/style.qss new file mode 100755 index 00000000..baa433ed --- /dev/null +++ b/DSView/darkstyle/style.qss @@ -0,0 +1,1218 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) <2013-2014> + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +QProgressBar:horizontal { + border: 1px solid #3A3939; + text-align: center; + padding: 1px; + background: #201F1F; +} +QProgressBar::chunk:horizontal { + background-color: qlineargradient(spread:reflect, x1:1, y1:0.545, x2:1, y2:0, stop:0 rgba(28, 66, 111, 255), stop:1 rgba(37, 87, 146, 255)); +} + +QToolTip +{ + border: 1px solid #3A3939; + background-color: rgb(90, 102, 117);; + color: white; + padding: 1px; + opacity: 200; +} + +QWidget +{ + color: silver; + background-color: #302F2F; + selection-background-color:#3d8ec9; + selection-color: black; + background-clip: border; + border-image: none; + outline: 0; +} + +QWidget:item:hover +{ + background-color: #78879b; + color: black; +} + +QWidget:item:selected +{ + background-color: #3d8ec9; +} + +QCheckBox +{ + spacing: 5px; + outline: none; + color: #bbb; + margin-bottom: 2px; +} + +QCheckBox:disabled +{ + color: #777777; +} +QCheckBox::indicator, +QGroupBox::indicator +{ + width: 18px; + height: 18px; +} +QGroupBox::indicator +{ + margin-left: 2px; +} + +QCheckBox::indicator:unchecked, +QCheckBox::indicator:unchecked:hover, +QGroupBox::indicator:unchecked, +QGroupBox::indicator:unchecked:hover +{ + image: url(:/qss_icons/rc/checkbox_unchecked.png); +} + +QCheckBox::indicator:unchecked:focus, +QCheckBox::indicator:unchecked:pressed, +QGroupBox::indicator:unchecked:focus, +QGroupBox::indicator:unchecked:pressed +{ + border: none; + image: url(:/qss_icons/rc/checkbox_unchecked_focus.png); +} + +QCheckBox::indicator:checked, +QCheckBox::indicator:checked:hover, +QGroupBox::indicator:checked, +QGroupBox::indicator:checked:hover +{ + image: url(:/qss_icons/rc/checkbox_checked.png); +} + +QCheckBox::indicator:checked:focus, +QCheckBox::indicator:checked:pressed, +QGroupBox::indicator:checked:focus, +QGroupBox::indicator:checked:pressed +{ + border: none; + image: url(:/qss_icons/rc/checkbox_checked_focus.png); +} + +QCheckBox::indicator:indeterminate, +QCheckBox::indicator:indeterminate:hover, +QCheckBox::indicator:indeterminate:pressed +QGroupBox::indicator:indeterminate, +QGroupBox::indicator:indeterminate:hover, +QGroupBox::indicator:indeterminate:pressed +{ + image: url(:/qss_icons/rc/checkbox_indeterminate.png); +} + +QCheckBox::indicator:indeterminate:focus, +QGroupBox::indicator:indeterminate:focus +{ + image: url(:/qss_icons/rc/checkbox_indeterminate_focus.png); +} + +QCheckBox::indicator:checked:disabled, +QGroupBox::indicator:checked:disabled +{ + image: url(:/qss_icons/rc/checkbox_checked_disabled.png); +} + +QCheckBox::indicator:unchecked:disabled, +QGroupBox::indicator:unchecked:disabled +{ + image: url(:/qss_icons/rc/checkbox_unchecked_disabled.png); +} + +QRadioButton +{ + spacing: 5px; + outline: none; + color: #bbb; + margin-bottom: 2px; +} + +QRadioButton:disabled +{ + color: #777777; +} +QRadioButton::indicator +{ + width: 21px; + height: 21px; +} + +QRadioButton::indicator:unchecked, +QRadioButton::indicator:unchecked:hover +{ + image: url(:/qss_icons/rc/radio_unchecked.png); +} + +QRadioButton::indicator:unchecked:focus, +QRadioButton::indicator:unchecked:pressed +{ + border: none; + outline: none; + image: url(:/qss_icons/rc/radio_unchecked_focus.png); +} + +QRadioButton::indicator:checked, +QRadioButton::indicator:checked:hover +{ + border: none; + outline: none; + image: url(:/qss_icons/rc/radio_checked.png); +} + +QRadioButton::indicator:checked:focus, +QRadioButton::indicato::menu-arrowr:checked:pressed +{ + border: none; + outline: none; + image: url(:/qss_icons/rc/radio_checked_focus.png); +} + +QRadioButton::indicator:indeterminate, +QRadioButton::indicator:indeterminate:hover, +QRadioButton::indicator:indeterminate:pressed +{ + image: url(:/qss_icons/rc/radio_indeterminate.png); +} + +QRadioButton::indicator:checked:disabled +{ + outline: none; + image: url(:/qss_icons/rc/radio_checked_disabled.png); +} + +QRadioButton::indicator:unchecked:disabled +{ + image: url(:/qss_icons/rc/radio_unchecked_disabled.png); +} + + +QMenuBar +{ + background-color: #302F2F; + color: silver; +} + +QMenuBar::item +{ + background: transparent; +} + +QMenuBar::item:selected +{ + background: transparent; + border: 1px solid #3A3939; +} + +QMenuBar::item:pressed +{ + border: 1px solid #3A3939; + background-color: #3d8ec9; + color: black; + margin-bottom:-1px; + padding-bottom:1px; +} + +QMenu +{ + border: 1px solid #3A3939; + color: silver; + margin: 2px; +} + +QMenu::icon +{ + margin: 5px; +} + +QMenu::item +{ + padding: 5px 30px 5px 30px; + margin-left: 5px; + border: 1px solid transparent; /* reserve space for selection border */ +} + +QMenu::item:selected +{ + color: black; +} + +QMenu::separator { + height: 2px; + background: lightblue; + margin-left: 10px; + margin-right: 5px; +} + +QMenu::indicator { + width: 18px; + height: 18px; +} + +/* non-exclusive indicator = check box style indicator + (see QActionGroup::setExclusive) */ +QMenu::indicator:non-exclusive:unchecked { + image: url(:/qss_icons/rc/checkbox_unchecked.png); +} + +QMenu::indicator:non-exclusive:unchecked:selected { + image: url(:/qss_icons/rc/checkbox_unchecked_disabled.png); +} + +QMenu::indicator:non-exclusive:checked { + image: url(:/qss_icons/rc/checkbox_checked.png); +} + +QMenu::indicator:non-exclusive:checked:selected { + image: url(:/qss_icons/rc/checkbox_checked_disabled.png); +} + +/* exclusive indicator = radio button style indicator (see QActionGroup::setExclusive) */ +QMenu::indicator:exclusive:unchecked { + image: url(:/qss_icons/rc/radio_unchecked.png); +} + +QMenu::indicator:exclusive:unchecked:selected { + image: url(:/qss_icons/rc/radio_unchecked_disabled.png); +} + +QMenu::indicator:exclusive:checked { + image: url(:/qss_icons/rc/radio_checked.png); +} + +QMenu::indicator:exclusive:checked:selected { + image: url(:/qss_icons/rc/radio_checked_disabled.png); +} + +QMenu::right-arrow { + margin: 5px; + image: url(:/qss_icons/rc/right_arrow.png) +} + + +QWidget:disabled +{ + color: #404040; + background-color: #302F2F; +} + +QAbstractItemView +{ + alternate-background-color: #3A3939; + color: silver; + border: 1px solid 3A3939; + border-radius: 2px; + padding: 1px; +} + +QTabWidget:focus, QCheckBox:focus, QRadioButton:focus, QSlider:focus +{ + border: none; +} + +QLineEdit +{ + background-color: #201F1F; + padding: 2px; + border-style: solid; + border: 1px solid #3A3939; + border-radius: 2px; + color: silver; +} + +QGroupBox { + border:1px solid #3A3939; + border-radius: 2px; + margin-top: 20px; +} + +QGroupBox::title { + subcontrol-origin: margin; + subcontrol-position: top center; + padding-left: 10px; + padding-right: 10px; + padding-top: 10px; +} + +QScrollBar:horizontal +{ + height: 15px; + margin: 3px 15px 3px 15px; + border: 1px transparent #2A2929; + border-radius: 4px; + background-color: #2A2929; +} + +QScrollBar::handle:horizontal +{ + background-color: #605F5F; + min-width: 5px; + border-radius: 4px; +} + +QScrollBar::add-line:horizontal +{ + margin: 0px 3px 0px 3px; + border-image: url(:/qss_icons/rc/right_arrow_disabled.png); + width: 10px; + height: 10px; + subcontrol-position: right; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:horizontal +{ + margin: 0px 3px 0px 3px; + border-image: url(:/qss_icons/rc/left_arrow_disabled.png); + height: 10px; + width: 10px; + subcontrol-position: left; + subcontrol-origin: margin; +} + +QScrollBar::add-line:horizontal:hover,QScrollBar::add-line:horizontal:on +{ + border-image: url(:/qss_icons/rc/right_arrow.png); + height: 10px; + width: 10px; + subcontrol-position: right; + subcontrol-origin: margin; +} + + +QScrollBar::sub-line:horizontal:hover, QScrollBar::sub-line:horizontal:on +{ + border-image: url(:/qss_icons/rc/left_arrow.png); + height: 10px; + width: 10px; + subcontrol-position: left; + subcontrol-origin: margin; +} + +QScrollBar::up-arrow:horizontal, QScrollBar::down-arrow:horizontal +{ + background: none; +} + + +QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal +{ + background: none; +} + +QScrollBar:vertical +{ + background-color: #2A2929; + width: 15px; + margin: 15px 3px 15px 3px; + border: 1px transparent #2A2929; + border-radius: 4px; +} + +QScrollBar::handle:vertical +{ + background-color: #605F5F; + min-height: 5px; + border-radius: 4px; +} + +QScrollBar::sub-line:vertical +{ + margin: 3px 0px 3px 0px; + border-image: url(:/qss_icons/rc/up_arrow_disabled.png); + height: 10px; + width: 10px; + subcontrol-position: top; + subcontrol-origin: margin; +} + +QScrollBar::add-line:vertical +{ + margin: 3px 0px 3px 0px; + border-image: url(:/qss_icons/rc/down_arrow_disabled.png); + height: 10px; + width: 10px; + subcontrol-position: bottom; + subcontrol-origin: margin; +} + +QScrollBar::sub-line:vertical:hover,QScrollBar::sub-line:vertical:on +{ + + border-image: url(:/qss_icons/rc/up_arrow.png); + height: 10px; + width: 10px; + subcontrol-position: top; + subcontrol-origin: margin; +} + + +QScrollBar::add-line:vertical:hover, QScrollBar::add-line:vertical:on +{ + border-image: url(:/qss_icons/rc/down_arrow.png); + height: 10px; + width: 10px; + subcontrol-position: bottom; + subcontrol-origin: margin; +} + +QScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical +{ + background: none; +} + + +QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical +{ + background: none; +} + +QTextEdit +{ + background-color: #201F1F; + color: silver; + border: 1px solid #3A3939; +} + +QPlainTextEdit +{ + background-color: #201F1F;; + color: silver; + border-radius: 2px; + border: 1px solid #3A3939; +} + +QHeaderView::section +{ + background-color: #3A3939; + color: silver; + padding-left: 4px; + border: 1px solid #6c6c6c; +} + +QSizeGrip { + image: url(:/qss_icons/rc/sizegrip.png); + width: 12px; + height: 12px; +} + + +QMainWindow::separator +{ + background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0.0 #302F2F, + stop: 0.4 #333333, + stop: 0.5 #404040, + stop: 0.6 #333333, + stop: 1 #302F2F); + color: white; + padding-left: 0px; + spacing: 0px; + width: 3px; + border: 0px solid #202020; +} + +QMenu::separator +{ + height: 1px; + background-color: #3A3939; + color: white; + padding-left: 4px; + margin-left: 10px; + margin-right: 5px; +} + + +QFrame +{ + border-radius: 2px; + border: 1px solid #444; +} + +QFrame[frameShape="0"] +{ + border-radius: 2px; + border: 1px transparent #444; +} + +QStackedWidget +{ + border: 1px transparent black; +} + +QToolBar { + border: 1px transparent #393838; + background: 1px solid #302F2F; + font-weight: bold; +} + +QToolBar::handle:horizontal { + image: url(:/qss_icons/rc/Hmovetoolbar.png); +} +QToolBar::handle:vertical { + image: url(:/qss_icons/rc/Vmovetoolbar.png); +} +QToolBar::separator:horizontal { + image: url(:/qss_icons/rc/Hsepartoolbar.png); +} +QToolBar::separator:vertical { + image: url(:/qss_icons/rc/Vsepartoolbars.png); +} + +QPushButton +{ + color: silver; + background-color: #302F2F; + border-width: 1px; + border-color: #202020; + border-style: solid; + padding-top: 5px; + padding-bottom: 5px; + padding-left: 5px; + padding-right: 5px; + border-radius: 5px; + outline: none; +} + +QPushButton:disabled +{ + background-color: #302F2F; + border-width: 1px; + border-color: #3A3939; + border-style: solid; + padding-top: 5px; + padding-bottom: 5px; + padding-left: 10px; + padding-right: 10px; + border-radius: 5px; + color: #454545; +} + +QComboBox +{ + selection-background-color: #3d8ec9; + background-color: #201F1F; + border-style: solid; + border: 1px solid #3A3939; + border-radius: 2px; + padding: 2px; + min-width: 75px; +} + +QPushButton:checked{ +background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0.0 #302F2F, + stop: 0.5 #6a6868, + stop: 1 #302F2F); +} + +QPushButton:hover +{ +background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0.0 #302F2F, stop: 0.4 #4E4D4D, + stop: 0.5 #6a6868, + stop: 0.6 #4E4D4D, stop: 1 #302F2F); +} + +QComboBox:hover,QAbstractSpinBox:hover,QLineEdit:hover,QTextEdit:hover,QPlainTextEdit:hover,QAbstractView:hover,QTreeView:hover +{ + border: 1px solid #78879b; + color: silver; +} + +QComboBox:on +{ + background-color: #626873; + padding-top: 3px; + padding-left: 4px; + selection-background-color: #4a4a4a; +} + +QComboBox QAbstractItemView +{ + background-color: #201F1F; + border-radius: 2px; + border: 1px solid #444; + selection-background-color: #3d8ec9; +} + +QComboBox::drop-down +{ + subcontrol-origin: padding; + subcontrol-position: top right; + width: 15px; + + border-left-width: 0px; + border-left-color: darkgray; + border-left-style: solid; + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; +} + +QComboBox::down-arrow +{ + image: url(:/qss_icons/rc/down_arrow_disabled.png); +} + +QComboBox::down-arrow:on, QComboBox::down-arrow:hover, +QComboBox::down-arrow:focus +{ + image: url(:/qss_icons/rc/down_arrow.png); +} + +QAbstractSpinBox { + padding-top: 2px; + padding-bottom: 2px; + border: 1px solid #3A3939; + background-color: #201F1F; + color: silver; + border-radius: 2px; + min-width: 75px; +} + +QAbstractSpinBox:up-button +{ + background-color: transparent; + subcontrol-origin: border; + subcontrol-position: center right; +} + +QAbstractSpinBox:down-button +{ + background-color: transparent; + subcontrol-origin: border; + subcontrol-position: center left; +} + +QAbstractSpinBox::up-arrow,QAbstractSpinBox::up-arrow:disabled,QAbstractSpinBox::up-arrow:off { + image: url(:/qss_icons/rc/up_arrow_disabled.png); + width: 10px; + height: 10px; +} +QAbstractSpinBox::up-arrow:hover +{ + image: url(:/qss_icons/rc/up_arrow.png); +} + + +QAbstractSpinBox::down-arrow,QAbstractSpinBox::down-arrow:disabled,QAbstractSpinBox::down-arrow:off +{ + image: url(:/qss_icons/rc/down_arrow_disabled.png); + width: 10px; + height: 10px; +} +QAbstractSpinBox::down-arrow:hover +{ + image: url(:/qss_icons/rc/down_arrow.png); +} + + +QLabel +{ + border: 0px solid black; +} + +QTabWidget{ + border: 1px transparent black; +} + +QTabWidget::pane { + border: 1px transparent #444; + border-radius: 3px; + padding: 3px; +} + +QTabBar +{ + qproperty-drawBase: 0; + left: 5px; /* move to the right by 5px */ +} + +QTabBar:focus +{ + border: 0px transparent black; +} + +QTabBar::close-button { + image: url(:/qss_icons/rc/close.png); + background: transparent; +} + +QTabBar::close-button:hover +{ + image: url(:/qss_icons/rc/close-hover.png); + background: transparent; +} + +QTabBar::close-button:pressed { + image: url(:/qss_icons/rc/close-pressed.png); + background: transparent; +} + +/* TOP TABS */ +QTabBar::tab:top { + color: #b1b1b1; + border: 1px solid #4A4949; + border-bottom: 1px transparent black; + background-color: #302F2F; + padding: 5px; + border-top-left-radius: 2px; + border-top-right-radius: 2px; +} + +QTabBar::tab:top:!selected +{ + color: #b1b1b1; + background-color: #201F1F; + border: 1px transparent #4A4949; + border-bottom: 1px transparent #4A4949; + border-top-left-radius: 0px; + border-top-right-radius: 0px; +} + +QTabBar::tab:top:!selected:hover { + background-color: #48576b; +} + +/* BOTTOM TABS */ +QTabBar::tab:bottom { + color: #b1b1b1; + border: 1px solid #4A4949; + border-top: 1px transparent black; + background-color: #302F2F; + padding: 5px; + border-bottom-left-radius: 2px; + border-bottom-right-radius: 2px; +} + +QTabBar::tab:bottom:!selected +{ + color: #b1b1b1; + background-color: #201F1F; + border: 1px transparent #4A4949; + border-top: 1px transparent #4A4949; + border-bottom-left-radius: 0px; + border-bottom-right-radius: 0px; +} + +QTabBar::tab:bottom:!selected:hover { + background-color: #78879b; +} + +/* LEFT TABS */ +QTabBar::tab:left { + color: #b1b1b1; + border: 1px solid #4A4949; + border-left: 1px transparent black; + background-color: #302F2F; + padding: 5px; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; +} + +QTabBar::tab:left:!selected +{ + color: #b1b1b1; + background-color: #201F1F; + border: 1px transparent #4A4949; + border-right: 1px transparent #4A4949; + border-top-right-radius: 0px; + border-bottom-right-radius: 0px; +} + +QTabBar::tab:left:!selected:hover { + background-color: #48576b; +} + + +/* RIGHT TABS */ +QTabBar::tab:right { + color: #b1b1b1; + border: 1px solid #4A4949; + border-right: 1px transparent black; + background-color: #302F2F; + padding: 5px; + border-top-left-radius: 2px; + border-bottom-left-radius: 2px; +} + +QTabBar::tab:right:!selected +{ + color: #b1b1b1; + background-color: #201F1F; + border: 1px transparent #4A4949; + border-right: 1px transparent #4A4949; + border-top-left-radius: 0px; + border-bottom-left-radius: 0px; +} + +QTabBar::tab:right:!selected:hover { + background-color: #48576b; +} + +QTabBar QToolButton::right-arrow:enabled { + image: url(:/qss_icons/rc/right_arrow.png); + } + + QTabBar QToolButton::left-arrow:enabled { + image: url(:/qss_icons/rc/left_arrow.png); + } + +QTabBar QToolButton::right-arrow:disabled { + image: url(:/qss_icons/rc/right_arrow_disabled.png); + } + + QTabBar QToolButton::left-arrow:disabled { + image: url(:/qss_icons/rc/left_arrow_disabled.png); + } + + +QDockWidget { + border: 1px transparent #403F3F; + titlebar-close-icon: url(:/qss_icons/rc/close.png); + titlebar-normal-icon: url(:/qss_icons/rc/undock.png); +} + +QDockWidget::close-button, QDockWidget::float-button { + border: 1px solid transparent; + border-radius: 2px; + background: transparent; +} + +QDockWidget::close-button:hover, QDockWidget::float-button:hover { + background: rgba(255, 255, 255, 10); +} + +QDockWidget::close-button:pressed, QDockWidget::float-button:pressed { + padding: 1px -1px -1px 1px; + background: rgba(255, 255, 255, 10); +} + +QTreeView, QListView +{ + border: 1px solid #444; + background-color: #201F1F; +} + +QTreeView:branch:selected, QTreeView:branch:hover +{ + background: url(:/qss_icons/rc/transparent.png); +} + +QTreeView::branch:has-siblings:!adjoins-item { + border-image: url(:/qss_icons/rc/transparent.png); +} + +QTreeView::branch:has-siblings:adjoins-item { + border-image: url(:/qss_icons/rc/transparent.png); +} + +QTreeView::branch:!has-children:!has-siblings:adjoins-item { + border-image: url(:/qss_icons/rc/transparent.png); +} + +QTreeView::branch:has-children:!has-siblings:closed, +QTreeView::branch:closed:has-children:has-siblings { + image: url(:/qss_icons/rc/branch_closed.png); +} + +QTreeView::branch:open:has-children:!has-siblings, +QTreeView::branch:open:has-children:has-siblings { + image: url(:/qss_icons/rc/branch_open.png); +} + +QTreeView::branch:has-children:!has-siblings:closed:hover, +QTreeView::branch:closed:has-children:has-siblings:hover { + image: url(:/qss_icons/rc/branch_closed-on.png); + } + +QTreeView::branch:open:has-children:!has-siblings:hover, +QTreeView::branch:open:has-children:has-siblings:hover { + image: url(:/qss_icons/rc/branch_open-on.png); + } + +QListView::item:!selected:hover, QListView::item:!selected:hover, QTreeView::item:!selected:hover { + background: rgba(0, 0, 0, 0); + outline: 0; + color: #FFFFFF +} + +QListView::item:selected:hover, QListView::item:selected:hover, QTreeView::item:selected:hover { + background: #3d8ec9; + color: #FFFFFF; +} + +QSlider::groove:horizontal { + border: 1px solid #3A3939; + height: 8px; + background: #201F1F; + margin: 2px 0; + border-radius: 2px; +} + +QSlider::handle:horizontal { + background: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0.0 silver, stop: 0.2 #a8a8a8, stop: 1 #727272); + border: 1px solid #3A3939; + width: 14px; + height: 14px; + margin: -4px 0; + border-radius: 2px; +} + +QSlider::groove:vertical { + border: 1px solid #3A3939; + width: 8px; + background: #201F1F; + margin: 0 0px; + border-radius: 2px; +} + +QSlider::handle:vertical { + background: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, stop: 0.0 silver, + stop: 0.2 #a8a8a8, stop: 1 #727272); + border: 1px solid #3A3939; + width: 14px; + height: 14px; + margin: 0 -4px; + border-radius: 2px; +} + +QToolButton { + background-color: transparent; + border: 1px transparent #4A4949; + border-radius: 2px; + margin: 3px; + padding: 3px; +} + +QToolButton[popupMode="1"] { /* only for MenuButtonPopup */ + padding-right: 20px; /* make way for the popup button */ + border: 1px transparent #4A4949; + border-radius: 5px; +} + +QToolButton[popupMode="2"] { /* only for InstantPopup */ + padding-right: 10px; /* make way for the popup button */ + border: 1px transparent #4A4949; +} + + +QToolButton:hover, QToolButton::menu-button:hover { + background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0.0 #302F2F, stop: 0.4 #4E4D4D, + stop: 0.5 #4A4949, + stop: 0.6 #4E4D4D, stop: 1 #302F2F); +} + +QToolButton:checked, QToolButton:pressed, +QToolButton::menu-button:pressed { + background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0.0 #302F2F, + stop: 0.5 #4A4949, + stop: 1.0 #302F2F); +} + +/* the subcontrol below is used only in the InstantPopup or DelayedPopup mode */ +QToolButton::menu-indicator { + image: url(:/qss_icons/rc/down_arrow.png); + top: -7px; left: -2px; /* shift it a bit */ +} + +/* the subcontrols below are used only in the MenuButtonPopup mode */ +QToolButton::menu-button { + border: 1px transparent #4A4949; + border-top-right-radius: 6px; + border-bottom-right-radius: 6px; + /* 16px width + 4px for border = 20px allocated above */ + width: 16px; + outline: none; +} + +QToolButton::menu-arrow { + image: url(:/qss_icons/rc/down_arrow.png); +} + +QToolButton::menu-arrow:open { + top: 1px; left: 1px; /* shift it a bit */ + border: 1px solid #3A3939; +} + +QPushButton::menu-indicator { + subcontrol-origin: padding; + subcontrol-position: bottom right; + left: 8px; +} + +QTableView +{ + border: 1px transparent #444; + gridline-color: #6c6c6c; + background-color: #201F1F; +} + + +QTableView, QHeaderView +{ + border-radius: 0px; +} + +QTableView::item:pressed, QListView::item:pressed, QTreeView::item:pressed { + background: #78879b; + color: #FFFFFF; +} + +QTableView::item:selected:active, QTreeView::item:selected:active, QListView::item:selected:active { + background: #3d8ec9; + color: #FFFFFF; +} + +QHeaderView +{ + border: 1px transparent; + border-radius: 2px; + margin: 0px; + padding: 0px; +} + +QHeaderView::section { + background-color: #302F2F; + color: silver; + padding: 4px; + border: 1px transparent #6c6c6c; + border-radius: 0px; + text-align: center; +} + +QHeaderView::section::vertical::first, QHeaderView::section::vertical::only-one +{ + border-top: 1px transparent #6c6c6c; +} + +QHeaderView::section::vertical +{ + border-top: transparent; +} + +QHeaderView::section::horizontal::first, QHeaderView::section::horizontal::only-one +{ + border-left: 1px transparent #6c6c6c; +} + +QHeaderView::section::horizontal +{ + border-left: transparent; +} + + +QHeaderView::section:checked + { + color: white; + background-color: #5A5959; + } + + /* style the sort indicator */ +QHeaderView::down-arrow { + image: url(:/qss_icons/rc/down_arrow.png); +} + +QHeaderView::up-arrow { + image: url(:/qss_icons/rc/up_arrow.png); +} + + +QTableCornerButton::section { + background-color: #3A3939; + border: 1px solid #3A3939; + border-radius: 2px; +} + +QToolBox { + padding: 3px; + border: 1px transparent black; +} + +QToolBox::tab { + color: #b1b1b1; + background-color: #302F2F; + border: 1px solid #4A4949; + border-bottom: 1px transparent #302F2F; + border-top-left-radius: 5px; + border-top-right-radius: 5px; +} + + QToolBox::tab:selected { /* italicize selected tabs */ + font: italic; + background-color: #302F2F; + border-color: #3d8ec9; + } + +QStatusBar::item { + border: 1px solid #3A3939; + border-radius: 2px; + } + + +QFrame[height="3"], QFrame[width="3"] { + background-color: #444; +} + + +QSplitter::handle { + border: 0px dashed #3A3939; +} + +QSplitter::handle:horizontal { + background-color: QLinearGradient( x1: 0, y1: 0, x2: 0, y2: 1, + stop: 0.0 #302F2F, + stop: 0.4 #333333, + stop: 0.5 #404040, + stop: 0.6 #333333, + stop: 1 #302F2F); + width: 3px; +} + +QSplitter::handle:vertical { + background-color: QLinearGradient( x1: 0, y1: 0, x2: 1, y2: 0, + stop: 0.0 #302F2F, + stop: 0.4 #333333, + stop: 0.5 #404040, + stop: 0.6 #333333, + stop: 1 #302F2F); + height: 3px; +} + +QAbstractScrollArea +{ + border-radius: 2px; + border: 0px transparent #3A3939; + background-color: #302F2F; +} diff --git a/DSView/main.cpp b/DSView/main.cpp index bd131f65..60876c69 100644 --- a/DSView/main.cpp +++ b/DSView/main.cpp @@ -147,7 +147,8 @@ int main(int argc, char *argv[]) // Initialise the main window pv::MainWindow w(device_manager, open_file); - QFile qss(":/stylesheet.qss"); + //QFile qss(":/stylesheet.qss"); + QFile qss(":qdarkstyle/style.qss"); qss.open(QFile::ReadOnly); a.setStyleSheet(qss.readAll()); qss.close(); diff --git a/DSView/pv/data/decode/annotation.cpp b/DSView/pv/data/decode/annotation.cpp index a474dd90..652dc1b9 100644 --- a/DSView/pv/data/decode/annotation.cpp +++ b/DSView/pv/data/decode/annotation.cpp @@ -49,6 +49,12 @@ Annotation::Annotation(const srd_proto_data *const pdata) : } } +Annotation::Annotation() +{ + _start_sample = 0; + _end_sample = 0; +} + Annotation::~Annotation() { _annotations.clear(); diff --git a/DSView/pv/data/decode/annotation.h b/DSView/pv/data/decode/annotation.h index a2676bd3..9ed39bf9 100644 --- a/DSView/pv/data/decode/annotation.h +++ b/DSView/pv/data/decode/annotation.h @@ -35,6 +35,7 @@ class Annotation { public: Annotation(const srd_proto_data *const pdata); + Annotation(); ~Annotation(); uint64_t start_sample() const; diff --git a/DSView/pv/data/decode/row.cpp b/DSView/pv/data/decode/row.cpp index 1c0ee9cc..06ae2987 100644 --- a/DSView/pv/data/decode/row.cpp +++ b/DSView/pv/data/decode/row.cpp @@ -68,8 +68,8 @@ const QString Row::title() const bool Row::operator<(const Row &other) const { - return (_decoder < other._decoder) || - (_decoder == other._decoder && _row < other._row); + return (_decoder->name < other._decoder->name) || + (_decoder->name == other._decoder->name && _row->desc < other._row->desc); } } // decode diff --git a/DSView/pv/data/decode/row.h b/DSView/pv/data/decode/row.h index 6826c0fc..73324302 100644 --- a/DSView/pv/data/decode/row.h +++ b/DSView/pv/data/decode/row.h @@ -46,7 +46,7 @@ public: const QString title() const; - bool operator<(const Row &other) const; + bool operator<(const Row &other) const; private: const srd_decoder *_decoder; diff --git a/DSView/pv/data/decode/rowdata.cpp b/DSView/pv/data/decode/rowdata.cpp index 840459a6..1fbd31a5 100644 --- a/DSView/pv/data/decode/rowdata.cpp +++ b/DSView/pv/data/decode/rowdata.cpp @@ -23,6 +23,7 @@ #include "rowdata.h" using std::max; +using std::min; using std::vector; namespace pv { @@ -30,7 +31,8 @@ namespace data { namespace decode { RowData::RowData() : - _max_annotation(0) + _max_annotation(0), + _min_annotation(UINT64_MAX) { } @@ -51,6 +53,11 @@ uint64_t RowData::get_max_annotation() const return _max_annotation; } +uint64_t RowData::get_min_annotation() const +{ + return _min_annotation; +} + void RowData::get_annotation_subset( vector &dest, uint64_t start_sample, uint64_t end_sample) const @@ -62,10 +69,33 @@ void RowData::get_annotation_subset( dest.push_back(*i); } -void RowData::push_annotation(const Annotation &a) +bool RowData::push_annotation(const Annotation &a) { - _annotations.push_back(a); - _max_annotation = max(_max_annotation, a.end_sample() - a.start_sample()); + try { + _annotations.push_back(a); + _max_annotation = max(_max_annotation, a.end_sample() - a.start_sample()); + if (a.end_sample() != a.start_sample()) + _min_annotation = min(_min_annotation, a.end_sample() - a.start_sample()); + return true; + } catch (const std::bad_alloc&) { + return false; + } +} + +uint64_t RowData::get_annotation_size() const +{ + return _annotations.size(); +} + +bool RowData::get_annotation(Annotation &ann, + uint64_t index) const +{ + if (index < _annotations.size()) { + ann = _annotations[index]; + return true; + } else { + return false; + } } } // decode diff --git a/DSView/pv/data/decode/rowdata.h b/DSView/pv/data/decode/rowdata.h index 03076494..11b88420 100644 --- a/DSView/pv/data/decode/rowdata.h +++ b/DSView/pv/data/decode/rowdata.h @@ -39,6 +39,7 @@ public: uint64_t get_max_sample() const; uint64_t get_max_annotation() const; + uint64_t get_min_annotation() const; /** * Extracts sorted annotations between two period into a vector. */ @@ -46,10 +47,16 @@ public: std::vector &dest, uint64_t start_sample, uint64_t end_sample) const; - void push_annotation(const Annotation &a); + bool push_annotation(const Annotation &a); + + uint64_t get_annotation_size() const; + + bool get_annotation(pv::data::decode::Annotation &ann, + uint64_t index) const; private: uint64_t _max_annotation; + uint64_t _min_annotation; std::vector _annotations; }; diff --git a/DSView/pv/data/decodermodel.cpp b/DSView/pv/data/decodermodel.cpp new file mode 100644 index 00000000..9e2c071f --- /dev/null +++ b/DSView/pv/data/decodermodel.cpp @@ -0,0 +1,108 @@ +/* + * This file is part of the DSView project. + * + * Copyright (C) 2016 Andy Deng + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include +#include + +#include +#include + +#include "decoderstack.h" +#include "decodermodel.h" + +using namespace boost; +using namespace std; + +namespace pv { +namespace data { + +DecoderModel::DecoderModel(QObject *parent) + : QAbstractTableModel(parent), + _decoder_stack(NULL) +{ +} + +void DecoderModel::setDecoderStack(boost::shared_ptr decoder_stack) +{ + beginResetModel(); + _decoder_stack = decoder_stack; + endResetModel(); +} + +const boost::shared_ptr& DecoderModel::getDecoderStack() const +{ + return _decoder_stack; +} + +int DecoderModel::rowCount(const QModelIndex & /* parent */) const +{ + if (_decoder_stack) + return _decoder_stack->list_annotation_size(); + else + return 100; +} +int DecoderModel::columnCount(const QModelIndex & /* parent */) const +{ + if (_decoder_stack) + return _decoder_stack->list_rows_size(); + else + return 1; +} + +QVariant DecoderModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (role == Qt::TextAlignmentRole) { + return int(Qt::AlignLeft | Qt::AlignVCenter); + } else if (role == Qt::DisplayRole) { + if (_decoder_stack) { + pv::data::decode::Annotation ann; + if (_decoder_stack->list_annotation(ann, index.column(), index.row())) { + return ann.annotations().at(0); + } + } + } + return QVariant(); +} + +QVariant DecoderModel::headerData(int section, + Qt::Orientation orientation, + int role) const +{ + if (role != Qt::DisplayRole) + return QVariant(); + + if (orientation == Qt::Vertical) + return section; + + if (_decoder_stack) { + QString title; + if (_decoder_stack->list_row_title(section, title)) + return title; + } + return QVariant(); +} + +} // namespace data +} // namespace pv diff --git a/DSView/pv/data/decodermodel.h b/DSView/pv/data/decodermodel.h new file mode 100644 index 00000000..a0eac14b --- /dev/null +++ b/DSView/pv/data/decodermodel.h @@ -0,0 +1,62 @@ +/* + * This file is part of the DSView project. + * + * Copyright (C) 2016 Andy Deng + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef DSVIEW_PV_DATA_DECODERMODEL_H +#define DSVIEW_PV_DATA_DECODERMODEL_H + +#include + +#include + +#include + +namespace pv { +namespace data { + +class DecoderStack; + +namespace decode { +class Annotation; +class Decoder; +class Row; +} + +class DecoderModel : public QAbstractTableModel +{ +public: + DecoderModel(QObject *parent = 0); + + int rowCount(const QModelIndex &parent) const; + int columnCount(const QModelIndex &parent) const; + QVariant data(const QModelIndex &index, int role) const; + QVariant headerData(int section, Qt::Orientation orientation, + int role) const; + + void setDecoderStack(boost::shared_ptr decoder_stack); + const boost::shared_ptr& getDecoderStack() const; + +private: + boost::shared_ptr _decoder_stack; +}; + +} // namespace data +} // namespace pv + +#endif // DSVIEW_PV_DATA_DECODERMODEL_H diff --git a/DSView/pv/data/decoderstack.cpp b/DSView/pv/data/decoderstack.cpp index ed720090..e52a91f4 100644 --- a/DSView/pv/data/decoderstack.cpp +++ b/DSView/pv/data/decoderstack.cpp @@ -68,7 +68,8 @@ DecoderStack::DecoderStack(pv::SigSession &session, _frame_complete(false), _samples_decoded(0), _decode_state(Stopped), - _options_changed(false) + _options_changed(false), + _no_memory(false) { connect(&_session, SIGNAL(frame_began()), this, SLOT(on_new_frame())); @@ -79,6 +80,8 @@ DecoderStack::DecoderStack(pv::SigSession &session, _stack.push_back(shared_ptr( new decode::Decoder(dec))); + + build_row(); } DecoderStack::~DecoderStack() @@ -89,7 +92,10 @@ DecoderStack::~DecoderStack() // } stop_decode(); _stack.clear(); - clear(); + _rows.clear(); + _rows_gshow.clear(); + _rows_lshow.clear(); + _class_rows.clear(); } const std::list< boost::shared_ptr >& @@ -102,20 +108,83 @@ void DecoderStack::push(boost::shared_ptr decoder) { assert(decoder); _stack.push_back(decoder); + build_row(); + _options_changed = true; } -void DecoderStack::remove(int index) +void DecoderStack::remove(boost::shared_ptr &decoder) { - assert(index >= 0); - assert(index < (int)_stack.size()); - // Find the decoder in the stack list< shared_ptr >::iterator iter = _stack.begin(); - for(int i = 0; i < index; i++, iter++) - assert(iter != _stack.end()); + for(int i = 0; i < _stack.size(); i++, iter++) + if ((*iter) == decoder) + break; // Delete the element - _stack.erase(iter); + if (iter != _stack.end()) + _stack.erase(iter); + + build_row(); + _options_changed = true; +} + +void DecoderStack::build_row() +{ + _rows.clear(); + // Add classes + BOOST_FOREACH (const shared_ptr &dec, _stack) + { + assert(dec); + const srd_decoder *const decc = dec->decoder(); + assert(dec->decoder()); + + // Add a row for the decoder if it doesn't have a row list + if (!decc->annotation_rows) { + const Row row(decc); + _rows[row] = decode::RowData(); + std::map::const_iterator iter = _rows_gshow.find(row); + if (iter == _rows_gshow.end()) { + if (row.title().contains("bit", Qt::CaseInsensitive) || + row.title().contains("warning", Qt::CaseInsensitive)) { + _rows_gshow[row] = false; + _rows_lshow[row] = false; + } else { + _rows_gshow[row] = true; + _rows_lshow[row] = true; + } + } + } + + // Add the decoder rows + for (const GSList *l = decc->annotation_rows; l; l = l->next) + { + const srd_decoder_annotation_row *const ann_row = + (srd_decoder_annotation_row *)l->data; + assert(ann_row); + + const Row row(decc, ann_row); + + // Add a new empty row data object + _rows[row] = decode::RowData(); + std::map::const_iterator iter = _rows_gshow.find(row); + if (iter == _rows_gshow.end()) { + if (row.title().contains("bit", Qt::CaseInsensitive) || + row.title().contains("warning", Qt::CaseInsensitive)) { + _rows_gshow[row] = false; + _rows_lshow[row] = false; + } else { + _rows_gshow[row] = true; + _rows_lshow[row] = true; + } + } + + // Map out all the classes + for (const GSList *ll = ann_row->ann_classes; + ll; ll = ll->next) + _class_rows[make_pair(decc, + GPOINTER_TO_INT(ll->data))] = row; + } + } } int64_t DecoderStack::samples_decoded() const @@ -124,36 +193,6 @@ int64_t DecoderStack::samples_decoded() const return _samples_decoded; } -std::vector< std::pair > DecoderStack::get_visible_rows() const -{ - lock_guard lock(_output_mutex); - - std::vector< std::pair > rows; - - BOOST_FOREACH (const shared_ptr &dec, _stack) - { - assert(dec); - - const srd_decoder *const decc = dec->decoder(); - assert(dec->decoder()); - - // Add a row for the decoder if it doesn't have a row list - if (!decc->annotation_rows) - rows.push_back(make_pair(Row(decc), dec->shown())); - - // Add the decoder rows - for (const GSList *l = decc->annotation_rows; l; l = l->next) - { - const srd_decoder_annotation_row *const ann_row = - (srd_decoder_annotation_row *)l->data; - assert(ann_row); - rows.push_back(make_pair(Row(decc, ann_row), dec->shown())); - } - } - - return rows; -} - void DecoderStack::get_annotation_subset( std::vector &dest, const Row &row, uint64_t start_sample, @@ -161,9 +200,9 @@ void DecoderStack::get_annotation_subset( { lock_guard lock(_output_mutex); - std::map::const_iterator iter = - _rows.find(row); - if (iter != _rows.end()) + std::map::const_iterator iter = + _rows.find(row); + if (iter != _rows.end()) (*iter).second.get_annotation_subset(dest, start_sample, end_sample); } @@ -180,6 +219,44 @@ uint64_t DecoderStack::get_max_annotation(const Row &row) return 0; } +uint64_t DecoderStack::get_min_annotation(const Row &row) +{ + lock_guard lock(_output_mutex); + + std::map::const_iterator iter = + _rows.find(row); + if (iter != _rows.end()) + return (*iter).second.get_min_annotation(); + + return 0; +} + +std::map& DecoderStack::get_rows_gshow() +{ + return _rows_gshow; +} + +std::map& DecoderStack::get_rows_lshow() +{ + return _rows_lshow; +} + +void DecoderStack::set_rows_gshow(const decode::Row row, bool show) +{ + std::map::const_iterator iter = _rows_gshow.find(row); + if (iter != _rows_gshow.end()) { + _rows_gshow[row] = show; + } +} + +void DecoderStack::set_rows_lshow(const decode::Row row, bool show) +{ + std::map::const_iterator iter = _rows_lshow.find(row); + if (iter != _rows_lshow.end()) { + _rows_lshow[row] = show; + } +} + bool DecoderStack::has_annotations(const Row &row) const { lock_guard lock(_output_mutex); @@ -195,6 +272,55 @@ bool DecoderStack::has_annotations(const Row &row) const return false; } +uint64_t DecoderStack::list_annotation_size() const +{ + uint64_t max_annotation_size = 0; + int row = 0; + for (map::const_iterator i = _rows.begin(); + i != _rows.end(); i++) { + map::const_iterator iter = _rows_lshow.find((*i).first); + if (iter != _rows_lshow.end() && (*iter).second) + max_annotation_size = max(max_annotation_size, + (*i).second.get_annotation_size()); + } + + return max_annotation_size; +} + +bool DecoderStack::list_annotation(pv::data::decode::Annotation &ann, + uint16_t row_index, uint64_t col_index) const +{ + int row = 0; + for (map::const_iterator i = _rows.begin(); + i != _rows.end(); i++) { + map::const_iterator iter = _rows_lshow.find((*i).first); + if (iter != _rows_lshow.end() && (*iter).second) { + if (row_index-- == 0) { + return (*i).second.get_annotation(ann, col_index); + } + } + } + + return false; +} + + +bool DecoderStack::list_row_title(int row, QString &title) const +{ + int index = 0; + for (map::const_iterator i = _rows.begin(); + i != _rows.end(); i++) { + map::const_iterator iter = _rows_lshow.find((*i).first); + if (iter != _rows_lshow.end() && (*iter).second) { + if (row-- == 0) { + title = (*i).first.title(); + return 1; + } + } + } + return 0; +} + QString DecoderStack::error_message() { lock_guard lock(_output_mutex); @@ -207,16 +333,20 @@ void DecoderStack::clear() _frame_complete = false; _samples_decoded = 0; _error_message = QString(); - _rows.clear(); - _class_rows.clear(); + for (map::const_iterator i = _rows.begin(); + i != _rows.end(); i++) + _rows[(*i).first] = decode::RowData(); + _no_memory = false; } void DecoderStack::stop_decode() { _snapshot.reset(); - if(_decode_state == Stopped) + if(_decode_state == Stopped) { + clear(); return; + } if (_decode_thread.get()) { _decode_thread->interrupt(); @@ -224,6 +354,7 @@ void DecoderStack::stop_decode() _decode_state = Stopped; } _decode_thread.reset(); + clear(); } void DecoderStack::begin_decode() @@ -239,8 +370,6 @@ void DecoderStack::begin_decode() // } stop_decode(); - clear(); - // Check that all decoders have the required channels BOOST_FOREACH(const shared_ptr &dec, _stack) if (!dec->have_required_probes()) { @@ -249,37 +378,6 @@ void DecoderStack::begin_decode() return; } - // Add classes - BOOST_FOREACH (const shared_ptr &dec, _stack) - { - assert(dec); - const srd_decoder *const decc = dec->decoder(); - assert(dec->decoder()); - - // Add a row for the decoder if it doesn't have a row list - if (!decc->annotation_rows) - _rows[Row(decc)] = decode::RowData(); - - // Add the decoder rows - for (const GSList *l = decc->annotation_rows; l; l = l->next) - { - const srd_decoder_annotation_row *const ann_row = - (srd_decoder_annotation_row *)l->data; - assert(ann_row); - - const Row row(decc, ann_row); - - // Add a new empty row data object - _rows[row] = decode::RowData(); - - // Map out all the classes - for (const GSList *ll = ann_row->ann_classes; - ll; ll = ll->next) - _class_rows[make_pair(decc, - GPOINTER_TO_INT(ll->data))] = row; - } - } - // We get the logic data of the first channel in the list. // This works because we are currently assuming all // LogicSignals have the same data/snapshot @@ -313,8 +411,8 @@ uint64_t DecoderStack::get_max_sample_count() const { uint64_t max_sample_count = 0; - for (map::const_iterator i = _rows.begin(); - i != _rows.end(); i++) + for (map::const_iterator i = _rows.begin(); + i != _rows.end(); i++) max_sample_count = max(max_sample_count, (*i).second.get_max_sample()); @@ -333,48 +431,6 @@ boost::optional DecoderStack::wait_for_data() const _sample_count); } -//void DecoderStack::decode_data( -// const uint64_t sample_count, const unsigned int unit_size, -// srd_session *const session) -//{ -// //uint8_t chunk[DecodeChunkLength]; -// uint8_t *chunk = NULL; -// //chunk = (uint8_t *)realloc(chunk, DecodeChunkLength); - -// const uint64_t chunk_sample_count = -// DecodeChunkLength / _snapshot->unit_size(); - -// for (uint64_t i = 0; -// !boost::this_thread::interruption_requested() && -// i < sample_count; -// i += chunk_sample_count) -// { -// //lock_guard decode_lock(_global_decode_mutex); - -// const uint64_t chunk_end = min( -// i + chunk_sample_count, sample_count); -// chunk = _snapshot->get_samples(i, chunk_end); - -// if (srd_session_send(session, i, i + sample_count, chunk, -// (chunk_end - i) * unit_size, unit_size) != SRD_OK) { -// _error_message = tr("Decoder reported an error"); -// break; -// } - -// { -// lock_guard lock(_output_mutex); -// _samples_decoded = chunk_end; -// } - -// if (i % DecodeNotifyPeriod == 0) -// new_decode_data(); - -// } -// _options_changed = false; -// decode_done(); -// //new_decode_data(); -//} - void DecoderStack::decode_data( const uint64_t decode_start, const uint64_t decode_end, const unsigned int unit_size, srd_session *const session) @@ -386,7 +442,7 @@ void DecoderStack::decode_data( for (uint64_t i = decode_start; !boost::this_thread::interruption_requested() && - i < decode_end; + i < decode_end && !_no_memory; i += chunk_sample_count) { //lock_guard decode_lock(_global_decode_mutex); @@ -490,6 +546,11 @@ uint64_t DecoderStack::sample_count() const return 0; } +uint64_t DecoderStack::sample_rate() const +{ + return _samplerate; +} + void DecoderStack::annotation_callback(srd_proto_data *pdata, void *decoder) { assert(pdata); @@ -500,6 +561,9 @@ void DecoderStack::annotation_callback(srd_proto_data *pdata, void *decoder) lock_guard lock(d->_output_mutex); + if (d->_no_memory) + return; + const Annotation a(pdata); // Find the row @@ -508,21 +572,21 @@ void DecoderStack::annotation_callback(srd_proto_data *pdata, void *decoder) const srd_decoder *const decc = pdata->pdo->di->decoder; assert(decc); - map::iterator row_iter = d->_rows.end(); + map::iterator row_iter = d->_rows.end(); // Try looking up the sub-row of this class const map, Row>::const_iterator r = d->_class_rows.find(make_pair(decc, a.format())); if (r != d->_class_rows.end()) - row_iter = d->_rows.find((*r).second); + row_iter = d->_rows.find((*r).second); else { // Failing that, use the decoder as a key - row_iter = d->_rows.find(Row(decc)); + row_iter = d->_rows.find(Row(decc)); } - assert(row_iter != d->_rows.end()); - if (row_iter == d->_rows.end()) { + assert(row_iter != d->_rows.end()); + if (row_iter == d->_rows.end()) { qDebug() << "Unexpected annotation: decoder = " << decc << ", format = " << a.format(); assert(0); @@ -530,7 +594,8 @@ void DecoderStack::annotation_callback(srd_proto_data *pdata, void *decoder) } // Add the annotation - (*row_iter).second.push_annotation(a); + if (!(*row_iter).second.push_annotation(a)) + d->_no_memory = true; } void DecoderStack::on_new_frame() @@ -560,21 +625,25 @@ void DecoderStack::on_frame_ended() begin_decode(); } -int DecoderStack::cur_rows_size() +int DecoderStack::list_rows_size() { int rows_size = 0; + int row = 0; for (map::const_iterator i = _rows.begin(); - i != _rows.end(); i++) - if ((*i).second.get_max_sample() != 0) + i != _rows.end(); i++) { + map::const_iterator iter = _rows_lshow.find((*i).first); + if (iter != _rows_lshow.end() && (*iter).second) rows_size++; - - if (rows_size == 0) - return 1; - else - return rows_size; + } + return rows_size; } -void DecoderStack::options_changed(bool changed) +bool DecoderStack::options_changed() const +{ + return _options_changed; +} + +void DecoderStack::set_options_changed(bool changed) { _options_changed = changed; } diff --git a/DSView/pv/data/decoderstack.h b/DSView/pv/data/decoderstack.h index 0e71dd52..a60d85dc 100644 --- a/DSView/pv/data/decoderstack.h +++ b/DSView/pv/data/decoderstack.h @@ -86,14 +86,13 @@ public: virtual ~DecoderStack(); - const std::list< boost::shared_ptr >& stack() const; + const std::list< boost::shared_ptr >& stack() const; void push(boost::shared_ptr decoder); - void remove(int index); + void remove(boost::shared_ptr& decoder); + void build_row(); int64_t samples_decoded() const; - std::vector< std::pair > get_visible_rows() const; - /** * Extracts sorted annotations between two period into a vector. */ @@ -103,9 +102,23 @@ public: uint64_t end_sample) const; uint64_t get_max_annotation(const decode::Row &row); + uint64_t get_min_annotation(const decode::Row &row); // except instant(end=start) annotation + + std::map &get_rows_gshow(); + std::map &get_rows_lshow(); + void set_rows_gshow(const decode::Row row, bool show); + void set_rows_lshow(const decode::Row row, bool show); bool has_annotations(const decode::Row &row) const; + uint64_t list_annotation_size() const; + + bool list_annotation(decode::Annotation &ann, + uint16_t row_index, uint64_t col_index) const; + + + bool list_row_title(int row, QString &title) const; + QString error_message(); void clear(); @@ -116,11 +129,13 @@ public: void stop_decode(); - int cur_rows_size(); + int list_rows_size(); - void options_changed(bool changed); + bool options_changed() const; + void set_options_changed(bool changed); uint64_t sample_count() const; + uint64_t sample_rate() const; private: boost::optional wait_for_data() const; @@ -170,9 +185,10 @@ private: mutable boost::mutex _output_mutex; int64_t _samples_decoded; - std::map _rows; - - std::map, decode::Row> _class_rows; + std::map _rows; + std::map _rows_gshow; + std::map _rows_lshow; + std::map, decode::Row> _class_rows; QString _error_message; @@ -180,6 +196,7 @@ private: decode_state _decode_state; bool _options_changed; + bool _no_memory; friend class DecoderStackTest::TwoDecoderStack; }; diff --git a/DSView/pv/dialogs/protocolexp.cpp b/DSView/pv/dialogs/protocolexp.cpp new file mode 100644 index 00000000..c3baf6bb --- /dev/null +++ b/DSView/pv/dialogs/protocolexp.cpp @@ -0,0 +1,215 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2012 Joel Holdsworth + * Copyright (C) 2013 DreamSourceLab + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include "protocolexp.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../sigsession.h" +#include "../data/decoderstack.h" +#include "../data/decode/row.h" +#include "../data/decode/annotation.h" +#include "../view/decodetrace.h" +#include "../data/decodermodel.h" + +using namespace boost; +using namespace std; + +namespace pv { +namespace dialogs { + +ProtocolExp::ProtocolExp(QWidget *parent, SigSession &session) : + QDialog(parent), + _session(session), + _button_box(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, + Qt::Horizontal, this), + _export_cancel(false) +{ + _format_combobox = new QComboBox(this); + _format_combobox->addItem(tr("Comma-Separated Values (*.csv)")); + _format_combobox->addItem(tr("Text files (*.txt)")); + + _flayout = new QFormLayout(); + _flayout->addRow(new QLabel(tr("Export Format: "), this), _format_combobox); + + pv::data::DecoderModel* decoder_model = _session.get_decoder_model(); + const boost::shared_ptr& decoder_stack = decoder_model->getDecoderStack(); + if (decoder_stack) { + int row_index = 0; + const std::map& rows(decoder_stack->get_rows_lshow()); + for (std::map::const_iterator i = rows.begin(); + i != rows.end(); i++) { + if ((*i).second) { + QLabel *row_label = new QLabel((*i).first.title(), this); + QRadioButton *row_sel = new QRadioButton(this); + if (row_index == 0) { + row_sel->setChecked(true); + } + _row_label_list.push_back(row_label); + _row_sel_list.push_back(row_sel); + _flayout->addRow(row_label, row_sel); + row_sel->setProperty("index", row_index); + row_sel->setProperty("title", (*i).first.title()); + row_index++; + } + } + } + + _layout = new QVBoxLayout(this); + _layout->addLayout(_flayout); + _layout->addWidget(&_button_box); + setLayout(_layout); + + connect(&_button_box, SIGNAL(accepted()), this, SLOT(accept())); + connect(&_button_box, SIGNAL(rejected()), this, SLOT(reject())); +} + +void ProtocolExp::accept() +{ + using namespace Qt; + using namespace pv::data::decode; + + QDialog::accept(); + + if (!_row_sel_list.empty()) { + QList supportedFormats; + for (int i = _format_combobox->count() - 1; i >= 0; i--) { + supportedFormats.push_back(_format_combobox->itemText(i)); + } + QString filter; + for(int i = 0; i < supportedFormats.count();i++){ + filter.append(supportedFormats[i]); + if(i < supportedFormats.count() - 1) + filter.append(";;"); + } + QString default_filter = _format_combobox->currentText(); + QString file_name = QFileDialog::getSaveFileName( + this, tr("Export Data"), "",filter,&default_filter); + if (!file_name.isEmpty()) { + QFileInfo f(file_name); + QStringList list = default_filter.split('.').last().split(')'); + QString ext = list.first(); + if(f.suffix().compare(ext)) + file_name+=tr(".")+ext; + + QFile file(file_name); + file.open(QIODevice::WriteOnly | QIODevice::Text); + QTextStream out(&file); + out.setCodec("UTF-8"); + out.setGenerateByteOrderMark(true); + + QFuture future; + future = QtConcurrent::run([&]{ + _export_cancel = false; + QString title; + int index; + for (std::list::const_iterator i = _row_sel_list.begin(); + i != _row_sel_list.end(); i++) { + if ((*i)->isChecked()) { + title = (*i)->property("title").toString(); + index = (*i)->property("index").toULongLong(); + break; + } + } + out << QString("%1;%2;%3\n") + .arg("ID") + .arg("Time[s]") + .arg(title); + + pv::data::DecoderModel* decoder_model = _session.get_decoder_model(); + const boost::shared_ptr& decoder_stack = decoder_model->getDecoderStack(); + int row_index = 0; + Row row; + const std::map& rows_lshow(decoder_stack->get_rows_lshow()); + for (std::map::const_iterator i = rows_lshow.begin(); + i != rows_lshow.end(); i++) { + if ((*i).second) { + if (index == row_index) { + row = (*i).first; + break; + } + row_index++; + } + } + + uint64_t exported = 0; + double time_pre_samples = 1.0 / decoder_stack->samplerate(); + vector annotations; + decoder_stack->get_annotation_subset(annotations, row, + 0, decoder_stack->sample_count()-1); + if (!annotations.empty()) { + BOOST_FOREACH(const Annotation &a, annotations) { + out << QString("%1;%2;%3\n") + .arg(QString::number(exported)) + .arg(QString::number(a.start_sample()*time_pre_samples)) + .arg(a.annotations().at(0)); + exported++; + emit export_progress(exported*100/annotations.size()); + if (_export_cancel) + break; + } + } + }); + Qt::WindowFlags flags = Qt::CustomizeWindowHint; + QProgressDialog dlg(tr("Export Protocol List Result... It can take a while."), + tr("Cancel"),0,100,this,flags); + dlg.setWindowModality(Qt::WindowModal); + dlg.setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint); + + QFutureWatcher watcher; + connect(&watcher,SIGNAL(finished()),&dlg,SLOT(cancel())); + connect(this,SIGNAL(export_progress(int)),&dlg,SLOT(setValue(int))); + connect(&dlg,SIGNAL(canceled()),this,SLOT(cancel_export())); + watcher.setFuture(future); + dlg.exec(); + + future.waitForFinished(); + file.close(); + } + } +} + +void ProtocolExp::reject() +{ + using namespace Qt; + + QDialog::reject(); +} + +void ProtocolExp::cancel_export() +{ + _export_cancel = true; +} + +} // namespace dialogs +} // namespace pv diff --git a/DSView/pv/dialogs/protocolexp.h b/DSView/pv/dialogs/protocolexp.h new file mode 100644 index 00000000..c793a75c --- /dev/null +++ b/DSView/pv/dialogs/protocolexp.h @@ -0,0 +1,85 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2012 Joel Holdsworth + * Copyright (C) 2013 DreamSourceLab + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#ifndef DSVIEW_PV_PROTOCOLEXP_H +#define DSVIEW_PV_PROTOCOLEXP_H + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../device/devinst.h" +#include "../prop/binding/deviceoptions.h" + +namespace pv { + +class SigSession; + +namespace data { +namespace decode { +class Row; +} +} + +namespace dialogs { + +class ProtocolExp : public QDialog +{ + Q_OBJECT + +public: + ProtocolExp(QWidget *parent, SigSession &session); + +protected: + void accept(); + void reject(); + +signals: + void export_progress(int percent); + +private slots: + void cancel_export(); + +private: + SigSession &_session; + + QComboBox *_format_combobox; + std::list _row_sel_list; + std::list _row_label_list; + QFormLayout *_flayout; + QVBoxLayout *_layout; + QDialogButtonBox _button_box; + + bool _export_cancel; +}; + +} // namespace dialogs +} // namespace pv + +#endif // DSVIEW_PV_PROTOCOLEXP_H diff --git a/DSView/pv/dialogs/protocollist.cpp b/DSView/pv/dialogs/protocollist.cpp new file mode 100644 index 00000000..6f6e090c --- /dev/null +++ b/DSView/pv/dialogs/protocollist.cpp @@ -0,0 +1,183 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2012 Joel Holdsworth + * Copyright (C) 2013 DreamSourceLab + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include "protocollist.h" + +#include + +#include +#include +#include + +#include "../sigsession.h" +#include "../data/decoderstack.h" +#include "../data/decode/row.h" +#include "../view/decodetrace.h" +#include "../data/decodermodel.h" + +using namespace boost; +using namespace std; + +namespace pv { +namespace dialogs { + +ProtocolList::ProtocolList(QWidget *parent, SigSession &session) : + QDialog(parent), + _session(session), + _button_box(QDialogButtonBox::Ok, + Qt::Horizontal, this) +{ + pv::data::DecoderModel* decoder_model = _session.get_decoder_model(); + + + _protocol_combobox = new QComboBox(this); + const std::vector< boost::shared_ptr > decode_sigs( + _session.get_decode_signals()); + int index = 0; + BOOST_FOREACH(boost::shared_ptr d, decode_sigs) { + _protocol_combobox->addItem(d->get_name()); + if (decoder_model->getDecoderStack() == d->decoder()) + _protocol_combobox->setCurrentIndex(index); + index++; + } + _protocol_combobox->addItem("", qVariantFromValue(NULL)); + if (decoder_model->getDecoderStack() == NULL) + _protocol_combobox->setCurrentIndex(index); + + _flayout = new QFormLayout(); + _flayout->addRow(new QLabel(tr("Decoded Protocols: "), this), _protocol_combobox); + + _layout = new QVBoxLayout(this); + _layout->addLayout(_flayout); + _layout->addWidget(&_button_box); + setLayout(_layout); + + connect(&_button_box, SIGNAL(accepted()), this, SLOT(accept())); + connect(_protocol_combobox, SIGNAL(currentIndexChanged(int)), this, SLOT(set_protocol(int))); + set_protocol(_protocol_combobox->currentIndex()); +} + +void ProtocolList::accept() +{ + using namespace Qt; + + QDialog::accept(); +} + +void ProtocolList::reject() +{ + using namespace Qt; + + QDialog::accept(); +} + +void ProtocolList::set_protocol(int index) +{ + (void)index; + + for(std::list::const_iterator i = _show_checkbox_list.begin(); + i != _show_checkbox_list.end(); i++) { + (*i)->setParent(NULL); + _flayout->removeWidget((*i)); + delete (*i); + } + _show_checkbox_list.clear(); + for(std::list::const_iterator i = _show_label_list.begin(); + i != _show_label_list.end(); i++) { + (*i)->setParent(NULL); + _flayout->removeWidget((*i)); + delete (*i); + } + _show_label_list.clear(); + + boost::shared_ptr decoder_stack; + const std::vector< boost::shared_ptr > decode_sigs( + _session.get_decode_signals()); + int cur_index = 0; + BOOST_FOREACH(boost::shared_ptr d, decode_sigs) { + if (index == cur_index) { + decoder_stack = d->decoder(); + break; + } + cur_index++; + } + + if (!decoder_stack){ + _session.get_decoder_model()->setDecoderStack(NULL); + return; + } + + _session.get_decoder_model()->setDecoderStack(decoder_stack); + int row_index = 0; + const std::map& rows(decoder_stack->get_rows_lshow()); + for (std::map::const_iterator i = rows.begin(); + i != rows.end(); i++) { + QLabel *row_label = new QLabel((*i).first.title(), this); + QCheckBox *row_checkbox = new QCheckBox(this); + //row_checkbox->setChecked(false); + _show_label_list.push_back(row_label); + _show_checkbox_list.push_back(row_checkbox); + _flayout->addRow(row_label, row_checkbox); + + row_checkbox->setChecked((*i).second); + connect(row_checkbox, SIGNAL(clicked(bool)), this, SLOT(on_row_check(bool))); + row_checkbox->setProperty("index", row_index); + row_index++; + } +} + +void ProtocolList::on_row_check(bool show) +{ + QCheckBox *sc = dynamic_cast(sender()); + QVariant id = sc->property("index"); + int index = id.toInt(); + + boost::shared_ptr decoder_stack; + const std::vector< boost::shared_ptr > decode_sigs( + _session.get_decode_signals()); + int cur_index = 0; + BOOST_FOREACH(boost::shared_ptr d, decode_sigs) { + if (cur_index == _protocol_combobox->currentIndex()) { + decoder_stack = d->decoder(); + break; + } + cur_index++; + } + + if (!decoder_stack) + return; + + std::map& rows(decoder_stack->get_rows_lshow()); + for (std::map::const_iterator i = rows.begin(); + i != rows.end(); i++) { + if (index-- == 0) { + decoder_stack->set_rows_lshow((*i).first, show); + break; + } + } + + _session.get_decoder_model()->setDecoderStack(decoder_stack); +} + +} // namespace dialogs +} // namespace pv diff --git a/DSView/pv/dialogs/protocollist.h b/DSView/pv/dialogs/protocollist.h new file mode 100644 index 00000000..6d315322 --- /dev/null +++ b/DSView/pv/dialogs/protocollist.h @@ -0,0 +1,76 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2012 Joel Holdsworth + * Copyright (C) 2013 DreamSourceLab + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#ifndef DSVIEW_PV_PROTOCOLLIST_H +#define DSVIEW_PV_PROTOCOLLIST_H + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../device/devinst.h" +#include "../prop/binding/deviceoptions.h" + +namespace pv { + +class SigSession; + +namespace dialogs { + +class ProtocolList : public QDialog +{ + Q_OBJECT + +public: + ProtocolList(QWidget *parent, SigSession &session); + +protected: + void accept(); + void reject(); + +private slots: + void set_protocol(int index); + void on_row_check(bool show); + +private: + SigSession &_session; + + QComboBox *_protocol_combobox; + std::list _show_checkbox_list; + std::list _show_label_list; + QFormLayout *_flayout; + QVBoxLayout *_layout; + QDialogButtonBox _button_box; + +}; + +} // namespace dialogs +} // namespace pv + +#endif // DSVIEW_PV_PROTOCOLLIST_H diff --git a/DSView/pv/dock/protocoldock.cpp b/DSView/pv/dock/protocoldock.cpp index 7756af9e..637022e1 100644 --- a/DSView/pv/dock/protocoldock.cpp +++ b/DSView/pv/dock/protocoldock.cpp @@ -25,13 +25,21 @@ #include "../sigsession.h" #include "../view/decodetrace.h" #include "../device/devinst.h" +#include "../data/decodermodel.h" +#include "../data/decoderstack.h" +#include "../dialogs/protocollist.h" +#include "../dialogs/protocolexp.h" #include #include #include #include #include +#include +#include +#include +#include #include namespace pv { @@ -41,20 +49,20 @@ ProtocolDock::ProtocolDock(QWidget *parent, SigSession &session) : QScrollArea(parent), _session(session) { - _widget = new QWidget(this); + _up_widget = new QWidget(this); QHBoxLayout *hori_layout = new QHBoxLayout(); - _add_button = new QPushButton(_widget); + _add_button = new QPushButton(_up_widget); _add_button->setFlat(true); _add_button->setIcon(QIcon::fromTheme("protocol", QIcon(":/icons/add.png"))); - _del_all_button = new QPushButton(_widget); + _del_all_button = new QPushButton(_up_widget); _del_all_button->setFlat(true); _del_all_button->setIcon(QIcon::fromTheme("protocol", QIcon(":/icons/del.png"))); _del_all_button->setCheckable(true); - _protocol_combobox = new QComboBox(_widget); + _protocol_combobox = new QComboBox(_up_widget); GSList *l = g_slist_sort(g_slist_copy( (GSList*)srd_decoder_list()), decoder_name_cmp); @@ -80,15 +88,72 @@ ProtocolDock::ProtocolDock(QWidget *parent, SigSession &session) : connect(_del_all_button, SIGNAL(clicked()), this, SLOT(del_protocol())); - _layout = new QVBoxLayout(); - _layout->addLayout(hori_layout); - _layout->addStretch(1); + _up_layout = new QVBoxLayout(); + _up_layout->addLayout(hori_layout); + _up_layout->addStretch(1); - _widget->setLayout(_layout); + _up_widget->setLayout(_up_layout); + _up_widget->setMinimumHeight(120); - this->setWidget(_widget); - _widget->setGeometry(0, 0, sizeHint().width(), 500); - _widget->setObjectName("protocolWidget"); +// this->setWidget(_widget); +// _widget->setGeometry(0, 0, sizeHint().width(), 500); +// _widget->setObjectName("protocolWidget"); + + _dn_widget = new QWidget(this); + + _dn_set_button = new QPushButton(_dn_widget); + _dn_set_button->setFlat(true); + _dn_set_button->setIcon(QIcon::fromTheme("protocol", + QIcon(":/icons/gear.png"))); + connect(_dn_set_button, SIGNAL(clicked()), + this, SLOT(set_model())); + + _dn_save_button = new QPushButton(_dn_widget); + _dn_save_button->setFlat(true); + _dn_save_button->setIcon(QIcon::fromTheme("protocol", + QIcon(":/icons/save.png"))); + connect(_dn_save_button, SIGNAL(clicked()), + this, SLOT(export_table_view())); + + QHBoxLayout *dn_title_layout = new QHBoxLayout(); + dn_title_layout->addWidget(_dn_set_button, 0, Qt::AlignLeft); + dn_title_layout->addWidget(_dn_save_button, 0, Qt::AlignLeft); + dn_title_layout->addWidget(new QLabel(tr("Protocol List Viewer"), _dn_widget), 1, Qt::AlignLeft); + dn_title_layout->addStretch(1); + + _table_view = new QTableView(_dn_widget); + _table_view->setModel(_session.get_decoder_model()); + _table_view->setAlternatingRowColors(true); + _table_view->setShowGrid(false); + _table_view->horizontalHeader()->setStretchLastSection(true); + _table_view->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); + _table_view->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); + + QVBoxLayout *dn_layout = new QVBoxLayout(); + dn_layout->addLayout(dn_title_layout); + dn_layout->addWidget(_table_view); + + _dn_widget->setLayout(dn_layout); + _dn_widget->setMinimumHeight(400); + + _split_widget = new QSplitter(this); + _split_widget->insertWidget(0, _up_widget); + _split_widget->insertWidget(1, _dn_widget); + _split_widget->setOrientation(Qt::Vertical); + _split_widget->setCollapsible(0, false); + _split_widget->setCollapsible(1, false); + //_split_widget->setStretchFactor(1, 1); + //_split_widget + + this->setWidgetResizable(true); + this->setWidget(_split_widget); + //_split_widget->setGeometry(0, 0, sizeHint().width(), 500); + _split_widget->setObjectName("protocolWidget"); + + connect(&_session, SIGNAL(decode_done()), this, SLOT(update_model())); + connect(this, SIGNAL(protocol_updated()), this, SLOT(update_model())); + connect(_table_view, SIGNAL(clicked(QModelIndex)), this, SLOT(item_clicked(QModelIndex))); + connect(_table_view->horizontalHeader(), SIGNAL(sectionResized(int,int,int)), this, SLOT(column_resize(int, int, int))); } ProtocolDock::~ProtocolDock() @@ -126,15 +191,15 @@ void ProtocolDock::add_protocol() //QMap & _options = dlg.get_options(); //QMap _options_index = dlg.get_options_index(); - QPushButton *_del_button = new QPushButton(_widget); - QPushButton *_set_button = new QPushButton(_widget); + QPushButton *_del_button = new QPushButton(_up_widget); + QPushButton *_set_button = new QPushButton(_up_widget); _del_button->setFlat(true); _del_button->setIcon(QIcon::fromTheme("protocol", QIcon(":/icons/del.png"))); _set_button->setFlat(true); _set_button->setIcon(QIcon::fromTheme("protocol", QIcon(":/icons/gear.png"))); - QLabel *_protocol_label = new QLabel(_widget); + QLabel *_protocol_label = new QLabel(_up_widget); _del_button->setCheckable(true); _protocol_label->setText(_protocol_combobox->currentText()); @@ -155,9 +220,10 @@ void ProtocolDock::add_protocol() hori_layout->addWidget(_protocol_label); hori_layout->addStretch(1); _hori_layout_list.push_back(hori_layout); - _layout->insertLayout(_del_button_list.size(), hori_layout); + _up_layout->insertLayout(_del_button_list.size(), hori_layout); //_session.add_protocol_analyzer(_protocol_combobox->currentIndex(), _sel_probes, _options, _options_index); + protocol_updated(); } } } @@ -183,6 +249,7 @@ void ProtocolDock::rst_protocol() } rst_index++; } + protocol_updated(); } void ProtocolDock::del_protocol() @@ -193,7 +260,7 @@ void ProtocolDock::del_protocol() int del_index = 0; for (QVector ::const_iterator i = _hori_layout_list.begin(); i != _hori_layout_list.end(); i++) { - _layout->removeItem((*i)); + _up_layout->removeItem((*i)); delete (*i); delete _del_button_list.at(del_index); delete _set_button_list.at(del_index); @@ -220,7 +287,7 @@ void ProtocolDock::del_protocol() for (QVector ::const_iterator i = _del_button_list.begin(); i != _del_button_list.end(); i++) { if ((*i)->isChecked()) { - _layout->removeItem(_hori_layout_list.at(del_index)); + _up_layout->removeItem(_hori_layout_list.at(del_index)); delete _hori_layout_list.at(del_index); delete _del_button_list.at(del_index); @@ -234,12 +301,12 @@ void ProtocolDock::del_protocol() _protocol_index_list.remove(del_index); _session.remove_decode_signal(del_index); - break; } del_index++; } } + protocol_updated(); } void ProtocolDock::del_all_protocol() @@ -248,7 +315,7 @@ void ProtocolDock::del_all_protocol() int del_index = 0; for (QVector ::const_iterator i = _hori_layout_list.begin(); i != _hori_layout_list.end(); i++) { - _layout->removeItem((*i)); + _up_layout->removeItem((*i)); delete (*i); delete _del_button_list.at(del_index); delete _set_button_list.at(del_index); @@ -262,8 +329,90 @@ void ProtocolDock::del_all_protocol() _set_button_list.clear(); _protocol_label_list.clear(); _protocol_index_list.clear(); + + protocol_updated(); } } +void ProtocolDock::set_model() +{ + pv::dialogs::ProtocolList *protocollist_dlg = new pv::dialogs::ProtocolList(this, _session); + protocollist_dlg->exec(); + resize_table_view(_session.get_decoder_model()); +} + +void ProtocolDock::update_model() +{ + pv::data::DecoderModel *decoder_model = _session.get_decoder_model(); + const std::vector< boost::shared_ptr > decode_sigs( + _session.get_decode_signals()); + if (decode_sigs.size() == 0) + decoder_model->setDecoderStack(NULL); + else if (!decoder_model->getDecoderStack()) + decoder_model->setDecoderStack(decode_sigs.at(0)->decoder()); + else { + int index = 0; + BOOST_FOREACH(const boost::shared_ptr d, decode_sigs) { + if (d->decoder() == decoder_model->getDecoderStack()) { + decoder_model->setDecoderStack(d->decoder()); + break; + } + index++; + } + if (index >= decode_sigs.size()) + decoder_model->setDecoderStack(decode_sigs.at(0)->decoder()); + } + + resize_table_view(decoder_model); +} + +void ProtocolDock::resize_table_view(data::DecoderModel* decoder_model) +{ + if (decoder_model->getDecoderStack()) { + for (int i = 0; i < decoder_model->columnCount(QModelIndex()) - 1; i++) { + _table_view->resizeColumnToContents(i); + if (_table_view->columnWidth(i) > 200) + _table_view->setColumnWidth(i, 200); + } + int top_row = _table_view->rowAt(0); + int bom_row = _table_view->rowAt(_table_view->height()); + if (bom_row >= top_row && top_row >= 0) { + for (int i = top_row; i <= bom_row; i++) + _table_view->resizeRowToContents(i); + } + } +} + +void ProtocolDock::item_clicked(const QModelIndex &index) +{ + pv::data::DecoderModel *decoder_model = _session.get_decoder_model(); + boost::shared_ptr decoder_stack = decoder_model->getDecoderStack(); + if (decoder_stack) { + pv::data::decode::Annotation ann; + if (decoder_stack->list_annotation(ann, index.column(), index.row())) { + _session.show_region(ann.start_sample(), ann.end_sample()); + } + } +} + +void ProtocolDock::column_resize(int index, int old_size, int new_size) +{ + pv::data::DecoderModel *decoder_model = _session.get_decoder_model(); + if (decoder_model->getDecoderStack()) { + int top_row = _table_view->rowAt(0); + int bom_row = _table_view->rowAt(_table_view->height()); + if (bom_row >= top_row && top_row >= 0) { + for (int i = top_row; i <= bom_row; i++) + _table_view->resizeRowToContents(i); + } + } +} + +void ProtocolDock::export_table_view() +{ + pv::dialogs::ProtocolExp *protocolexp_dlg = new pv::dialogs::ProtocolExp(this, _session); + protocolexp_dlg->exec(); +} + } // namespace dock } // namespace pv diff --git a/DSView/pv/dock/protocoldock.h b/DSView/pv/dock/protocoldock.h index 248d1862..96d31124 100644 --- a/DSView/pv/dock/protocoldock.h +++ b/DSView/pv/dock/protocoldock.h @@ -34,15 +34,23 @@ #include #include #include +#include +#include #include #include +#include "../data/decodermodel.h" + namespace pv { class SigSession; +namespace data { +class DecoderModel; +} + namespace dock { class ProtocolDock : public QScrollArea @@ -58,19 +66,29 @@ public: void del_all_protocol(); signals: + void protocol_updated(); private slots: void add_protocol(); void rst_protocol(); void del_protocol(); + void set_model(); + void update_model(); + void export_table_view(); + void item_clicked(const QModelIndex &index); + void column_resize(int index, int old_size, int new_size); private: static int decoder_name_cmp(const void *a, const void *b); + void resize_table_view(data::DecoderModel *decoder_model); private: SigSession &_session; - QWidget *_widget; + QSplitter *_split_widget; + QWidget *_up_widget; + QWidget *_dn_widget; + QTableView *_table_view; QPushButton *_add_button; QPushButton *_del_all_button; @@ -80,7 +98,10 @@ private: QVector _protocol_label_list; QVector _protocol_index_list; QVector _hori_layout_list; - QVBoxLayout *_layout; + QVBoxLayout *_up_layout; + + QPushButton *_dn_set_button; + QPushButton *_dn_save_button; }; } // namespace dock diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp index 2b708075..90417108 100644 --- a/DSView/pv/mainwindow.cpp +++ b/DSView/pv/mainwindow.cpp @@ -197,7 +197,9 @@ void MainWindow::setup_ui() SLOT(device_change())); connect(_dso_trigger_widget, SIGNAL(set_trig_pos(quint64)), _view, SLOT(set_trig_pos(quint64))); + connect(_protocol_widget, SIGNAL(protocol_updated()), _view, SLOT(signals_changed())); + setIconSize(QSize(40,40)); addToolBar(_sampling_bar); addToolBar(_trig_bar); addToolBar(_file_bar); diff --git a/DSView/pv/sigsession.cpp b/DSView/pv/sigsession.cpp index 19bf99f5..8b0802cf 100644 --- a/DSView/pv/sigsession.cpp +++ b/DSView/pv/sigsession.cpp @@ -41,6 +41,7 @@ #include "data/groupsnapshot.h" #include "data/decoderstack.h" #include "data/decode/decoder.h" +#include "data/decodermodel.h" #include "view/analogsignal.h" #include "view/dsosignal.h" @@ -99,6 +100,7 @@ SigSession::SigSession(DeviceManager &device_manager) : _refresh_timer.stop(); _refresh_timer.setSingleShot(true); _data_lock = false; + _decoder_model = new pv::data::DecoderModel(this); connect(this, SIGNAL(start_timer(int)), &_view_timer, SLOT(start(int))); //connect(&_view_timer, SIGNAL(timeout()), this, SLOT(refresh())); connect(&_refresh_timer, SIGNAL(timeout()), this, SLOT(data_unlock())); @@ -455,7 +457,6 @@ void SigSession::start_capture(bool instant, _view_timer.blockSignals(false); // Begin the session - _sampling_thread.reset(new boost::thread( &SigSession::sample_thread_proc, this, _dev_inst, error_handler)); @@ -1104,9 +1105,10 @@ void SigSession::data_feed_in(const struct sr_dev_inst *sdi, _cur_logic_snapshot.reset(); _cur_dso_snapshot.reset(); _cur_analog_snapshot.reset(); - +#ifdef ENABLE_DECODE BOOST_FOREACH(const boost::shared_ptr d, _decode_traces) d->frame_ended(); +#endif } frame_ended(); @@ -1394,6 +1396,12 @@ void SigSession::rst_decoder(view::DecodeTrace *signal) return; } } + +pv::data::DecoderModel* SigSession::get_decoder_model() const +{ + return _decoder_model; +} + #endif } // namespace pv diff --git a/DSView/pv/sigsession.h b/DSView/pv/sigsession.h index 23ad6a90..de159f17 100644 --- a/DSView/pv/sigsession.h +++ b/DSView/pv/sigsession.h @@ -67,6 +67,7 @@ class Logic; class LogicSnapshot; class Group; class GroupSnapshot; +class DecoderModel; } namespace device { @@ -154,6 +155,8 @@ public: void rst_decoder(view::DecodeTrace *signal); + pv::data::DecoderModel* get_decoder_model() const; + #endif void init_signals(); @@ -234,6 +237,7 @@ private: std::vector< boost::shared_ptr > _group_traces; #ifdef ENABLE_DECODE std::vector< boost::shared_ptr > _decode_traces; + pv::data::DecoderModel *_decoder_model; #endif mutable boost::mutex _data_mutex; @@ -291,6 +295,10 @@ signals: void zero_adj(); void progressSaveFileValueChanged(int percent); + void decode_done(); + + void show_region(uint64_t start, uint64_t end); + public slots: void reload(); void refresh(int holdtime); diff --git a/DSView/pv/toolbars/samplingbar.cpp b/DSView/pv/toolbars/samplingbar.cpp index 85b45603..ed758736 100644 --- a/DSView/pv/toolbars/samplingbar.cpp +++ b/DSView/pv/toolbars/samplingbar.cpp @@ -454,7 +454,8 @@ void SamplingBar::update_sample_rate_selector_value() break; } } - update_scale(); + if (samplerate != _sample_rate.itemData(_sample_rate.currentIndex()).value()) + update_scale(); _updating_sample_rate = false; } @@ -511,7 +512,7 @@ void SamplingBar::on_samplecount_sel(int index) g_variant_new_uint64(sample_count)); sample_count_changed(); - update_scale(); + //update_scale(); } } @@ -535,7 +536,7 @@ void SamplingBar::on_samplerate_sel(int index) SR_CONF_SAMPLERATE, g_variant_new_uint64(sample_rate)); - update_scale(); + //update_scale(); } } @@ -625,9 +626,11 @@ void SamplingBar::update_sample_count_selector_value() i).value()) _sample_count.setCurrentIndex(i); + if (samplecount != _sample_count.itemData(_sample_count.currentIndex()).value()) { + sample_count_changed(); + update_scale(); + } _updating_sample_count = false; - sample_count_changed(); - update_scale(); } void SamplingBar::commit_sample_count() diff --git a/DSView/pv/view/decodetrace.cpp b/DSView/pv/view/decodetrace.cpp index a8c84244..bd076af5 100644 --- a/DSView/pv/view/decodetrace.cpp +++ b/DSView/pv/view/decodetrace.cpp @@ -125,7 +125,6 @@ DecodeTrace::DecodeTrace(pv::SigSession &session, _end_index(0), _start_count(0), _end_count(0), - _show_hide_mapper(this), _popup_form(NULL), _popup() { @@ -137,8 +136,6 @@ DecodeTrace::DecodeTrace(pv::SigSession &session, this, SLOT(on_new_decode_data())); connect(_decoder_stack.get(), SIGNAL(decode_done()), this, SLOT(on_decode_done())); - connect(&_show_hide_mapper, SIGNAL(mapped(int)), - this, SLOT(on_show_hide_decoder(int))); } DecodeTrace::~DecodeTrace() @@ -203,7 +200,7 @@ void DecodeTrace::paint_back(QPainter &p, int left, int right) void DecodeTrace::paint_mid(QPainter &p, int left, int right) { - using namespace pv::data::decode; + using namespace pv::data::decode; const double scale = _view->scale(); assert(scale > 0); @@ -249,47 +246,57 @@ void DecodeTrace::paint_mid(QPainter &p, int left, int right) const double decode_startX = _decode_start/samples_per_pixel - (_view->offset() / _view->scale()); const double decode_endX = _decode_end/samples_per_pixel - (_view->offset() / _view->scale()); - const std::vector< std::pair > rows(_decoder_stack->get_visible_rows()); - for (size_t i = 0; i < rows.size(); i++) - { - const Row &row = rows[i].first; - const bool shown = rows[i].second; - if (!shown && _decoder_stack->has_annotations(row)) { - draw_unshown_row(p, y, annotation_height, decode_startX, decode_endX); - y += annotation_height; - _cur_row_headings.push_back(row.title()); - continue; - } + BOOST_FOREACH(boost::shared_ptr dec, + _decoder_stack->stack()) { + if (dec->shown()) { + const std::map& rows(_decoder_stack->get_rows_gshow()); + for (std::map::const_iterator i = rows.begin(); + i != rows.end(); i++) { + if ((*i).first.decoder() == dec->decoder() && + _decoder_stack->has_annotations((*i).first)) { + if ((*i).second) { + const Row &row = (*i).first; + size_t base_colour = 0x13579BDF; + boost::hash_combine(base_colour, this); + boost::hash_combine(base_colour, row.decoder()); + boost::hash_combine(base_colour, row.row()); + base_colour >>= 16; - size_t base_colour = 0x13579BDF; - boost::hash_combine(base_colour, this); - boost::hash_combine(base_colour, row.decoder()); - boost::hash_combine(base_colour, row.row()); - base_colour >>= 16; + const uint64_t min_annotation = + _decoder_stack->get_min_annotation(row); + const double min_annWidth = min_annotation / samples_per_pixel; - const uint64_t max_annotation = - _decoder_stack->get_max_annotation(row); - const double max_annWidth = max_annotation / samples_per_pixel; - if (max_annWidth > 5) { - vector annotations; - _decoder_stack->get_annotation_subset(annotations, row, - start_sample, end_sample); - if (!annotations.empty()) { - BOOST_FOREACH(const Annotation &a, annotations) - draw_annotation(a, p, get_text_colour(), - annotation_height, left, right, - samples_per_pixel, pixels_offset, y, - base_colour); + const uint64_t max_annotation = + _decoder_stack->get_max_annotation(row); + const double max_annWidth = max_annotation / samples_per_pixel; + if (max_annWidth > 5) { + vector annotations; + _decoder_stack->get_annotation_subset(annotations, row, + start_sample, end_sample); + if (!annotations.empty()) { + BOOST_FOREACH(const Annotation &a, annotations) + draw_annotation(a, p, get_text_colour(), + annotation_height, left, right, + samples_per_pixel, pixels_offset, y, + base_colour, min_annWidth); + } + } else if (max_annWidth != 0){ + draw_nodetail(p, annotation_height, left, right, y, base_colour); + } + if (max_annWidth != 0) { + y += annotation_height; + _cur_row_headings.push_back(row.title()); + } + } + } } - } else if (max_annWidth != 0){ - draw_nodetail(p, annotation_height, decode_startX, decode_endX, y, base_colour); - } - if (max_annWidth != 0) { + } else { + draw_unshown_row(p, y, annotation_height, left, right, tr("Unshown")); y += annotation_height; - _cur_row_headings.push_back(row.title()); + _cur_row_headings.push_back(dec->decoder()->name); } - } + } } void DecodeTrace::paint_fore(QPainter &p, int left, int right) @@ -350,8 +357,8 @@ bool DecodeTrace::create_popup() BOOST_FOREACH(boost::shared_ptr dec, _decoder_stack->stack()) { - if (dec->commit()) { - _decoder_stack->options_changed(true); + if (dec->commit() || _decoder_stack->options_changed()) { + _decoder_stack->set_options_changed(true); _decode_start = dec->decode_start(); _decode_end = dec->decode_end(); ret = true; @@ -378,6 +385,9 @@ void DecodeTrace::create_popup_form() _popup_form = new QFormLayout(_popup); _popup->setLayout(_popup_form); populate_popup_form(_popup, _popup_form); + const int width = _popup_form->sizeHint().width(); + const int height = _popup_form->sizeHint().height(); + _popup->resize(width, height); } void DecodeTrace::populate_popup_form(QWidget *parent, QFormLayout *form) @@ -395,20 +405,15 @@ void DecodeTrace::populate_popup_form(QWidget *parent, QFormLayout *form) const list< boost::shared_ptr >& stack = _decoder_stack->stack(); - if (stack.empty()) - { + if (stack.empty()) { QLabel *const l = new QLabel( tr("

No decoders in the stack

")); l->setAlignment(Qt::AlignCenter); form->addRow(l); - } - else - { - list< boost::shared_ptr >::const_iterator iter = - stack.begin(); - for (int i = 0; i < (int)stack.size(); i++, iter++) { - boost::shared_ptr dec(*iter); - create_decoder_form(i, dec, parent, form); + } else { + BOOST_FOREACH(boost::shared_ptr dec,stack) { + //boost::shared_ptr dec(*iter); + create_decoder_form(_decoder_stack, dec, parent, form); } form->addRow(new QLabel( @@ -477,9 +482,9 @@ void DecodeTrace::populate_popup_form(QWidget *parent, QFormLayout *form) } void DecodeTrace::draw_annotation(const pv::data::decode::Annotation &a, - QPainter &p, QColor text_color, int h, int left, int right, - double samples_per_pixel, double pixels_offset, int y, - size_t base_colour) const + QPainter &p, QColor text_color, int h, int left, int right, + double samples_per_pixel, double pixels_offset, int y, + size_t base_colour, double min_annWidth) const { const double start = max(a.start_sample() / samples_per_pixel - pixels_offset, (double)left); @@ -495,7 +500,7 @@ void DecodeTrace::draw_annotation(const pv::data::decode::Annotation &a, if (a.start_sample() == a.end_sample()) draw_instant(a, p, fill, outline, text_color, h, - start, y); + start, y, min_annWidth); else draw_range(a, p, fill, outline, text_color, h, start, end, y); @@ -506,22 +511,31 @@ void DecodeTrace::draw_nodetail(QPainter &p, size_t base_colour) const { const QRectF nodetail_rect(left, y - h/2 + 0.5, right - left, h); - const size_t colour = base_colour % countof(Colours); - const QColor &fill = Colours[colour]; + QString info = tr("Zoom in For Detial"); + int info_left = nodetail_rect.center().x() - p.boundingRect(QRectF(), 0, info).width(); + int info_right = nodetail_rect.center().x() + p.boundingRect(QRectF(), 0, info).width(); + int height = p.boundingRect(QRectF(), 0, info).height(); - p.setPen(Qt::white); - p.setBrush(fill); - p.drawRect(nodetail_rect); - p.drawText(nodetail_rect, Qt::AlignCenter | Qt::AlignVCenter, "Zoom in for more detials"); + p.setPen(Trace::DARK_FORE); + p.drawLine(left, y, info_left, y); + p.drawLine(info_right, y, right, y); + p.drawLine(info_left, y, info_left+5, y - height/2 + 0.5); + p.drawLine(info_left, y, info_left+5, y + height/2 + 0.5); + p.drawLine(info_right, y, info_right-5, y - height/2 + 0.5); + p.drawLine(info_right, y, info_right-5, y + height/2 + 0.5); + + p.setPen(Trace::DARK_FORE); + p.drawText(nodetail_rect, Qt::AlignCenter | Qt::AlignVCenter, info); } void DecodeTrace::draw_instant(const pv::data::decode::Annotation &a, QPainter &p, - QColor fill, QColor outline, QColor text_color, int h, double x, int y) const + QColor fill, QColor outline, QColor text_color, int h, double x, int y, double min_annWidth) const { const QString text = a.annotations().empty() ? QString() : a.annotations().back(); - const double w = min((double)p.boundingRect(QRectF(), 0, text).width(), - 0.0) + h; +// const double w = min((double)p.boundingRect(QRectF(), 0, text).width(), +// 0.0) + h; + const double w = min(min_annWidth, (double)h); const QRectF rect(x - w / 2, y - h / 2, w, h); p.setPen(outline); @@ -564,7 +578,7 @@ void DecodeTrace::draw_range(const pv::data::decode::Annotation &a, QPainter &p, QPointF(start + cap_width, bottom) }; - p.setPen(Qt::white); + p.setPen(DARK_BACK); p.drawConvexPolygon(pts, countof(pts)); if (annotations.empty()) @@ -643,20 +657,8 @@ bool DecodeTrace::draw_unresolved_period(QPainter &p, int h, int left, return false; const int y = get_y(); -// const double start = max(samples_decoded / -// samples_per_pixel - pixels_offset, left - 1.0); -// const double end = min(sample_count / samples_per_pixel - -// pixels_offset, right + 1.0); const QRectF no_decode_rect(left, y - h/2 + 0.5, right - left, h); - p.setPen(QPen(Qt::NoPen)); - p.setBrush(Qt::white); - p.drawRect(no_decode_rect); - - p.setPen(NoDecodeColour); - p.setBrush(QBrush(NoDecodeColour, Qt::Dense7Pattern)); - p.drawRect(no_decode_rect); - const int progress100 = ceil(samples_decoded * 100.0 / need_sample_count); p.setPen(dsLightBlue); QFont font=p.font(); @@ -669,40 +671,40 @@ bool DecodeTrace::draw_unresolved_period(QPainter &p, int h, int left, } void DecodeTrace::draw_unshown_row(QPainter &p, int y, int h, int left, - int right) + int right, QString info) { const QRectF unshown_rect(left, y - h/2 + 0.5, right - left, h); + int info_left = unshown_rect.center().x() - p.boundingRect(QRectF(), 0, info).width(); + int info_right = unshown_rect.center().x() + p.boundingRect(QRectF(), 0, info).width(); + int height = p.boundingRect(QRectF(), 0, info).height(); - p.setPen(QPen(Qt::NoPen)); - p.setBrush(QBrush(NoDecodeColour, Qt::Dense7Pattern)); - p.drawRect(unshown_rect); + p.setPen(Trace::DARK_FORE); + p.drawLine(left, y, info_left, y); + p.drawLine(info_right, y, right, y); + p.drawLine(info_left, y, info_left+5, y - height/2 + 0.5); + p.drawLine(info_left, y, info_left+5, y + height/2 + 0.5); + p.drawLine(info_right, y, info_right-5, y - height/2 + 0.5); + p.drawLine(info_right, y, info_right-5, y + height/2 + 0.5); - p.setPen(dsLightBlue); - QFont font=p.font(); - font.setPointSize(_view->get_signalHeight()*2/3); - font.setBold(true); - p.setFont(font); - p.drawText(unshown_rect, Qt::AlignCenter | Qt::AlignVCenter, "Unshown"); + p.setPen(Trace::DARK_FORE); + p.drawText(unshown_rect, Qt::AlignCenter | Qt::AlignVCenter, info); } -void DecodeTrace::create_decoder_form(int index, +void DecodeTrace::create_decoder_form( + boost::shared_ptr &decoder_stack, boost::shared_ptr &dec, QWidget *parent, - QFormLayout *form) + QFormLayout *form) { const GSList *l; - assert(dec); + assert(dec); const srd_decoder *const decoder = dec->decoder(); assert(decoder); - pv::widgets::DecoderGroupBox *const group = - new pv::widgets::DecoderGroupBox( - QString::fromUtf8(decoder->name)); - group->set_decoder_visible(dec->shown()); - - _show_hide_mapper.setMapping(group, index); - connect(group, SIGNAL(show_hide_decoder()), - &_show_hide_mapper, SLOT(map())); + pv::widgets::DecoderGroupBox *const group = + new pv::widgets::DecoderGroupBox(decoder_stack, dec); + connect(group, SIGNAL(del_stack(boost::shared_ptr&)), + this, SLOT(on_del_stack(boost::shared_ptr&))); QFormLayout *const decoder_form = new QFormLayout; group->add_layout(decoder_form); @@ -739,7 +741,7 @@ void DecodeTrace::create_decoder_form(int index, // Add the options boost::shared_ptr binding( - new prop::binding::DecoderOptions(_decoder_stack, dec)); + new prop::binding::DecoderOptions(decoder_stack, dec)); binding->add_properties_to_form(decoder_form, true); _bindings.push_back(binding); @@ -837,6 +839,7 @@ void DecodeTrace::on_decode_done() _view->set_need_update(true); _view->signals_changed(); } + _session.decode_done(); } void DecodeTrace::on_delete() @@ -860,33 +863,36 @@ void DecodeTrace::on_stack_decoder(srd_decoder *decoder) create_popup_form(); } -void DecodeTrace::on_show_hide_decoder(int index) +void DecodeTrace::on_del_stack(boost::shared_ptr &dec) { - using pv::data::decode::Decoder; + assert(dec); + assert(_decoder_stack); + _decoder_stack->remove(dec); - const list< boost::shared_ptr > stack(_decoder_stack->stack()); - - // Find the decoder in the stack - list< boost::shared_ptr >::const_iterator iter = stack.begin(); - for(int i = 0; i < index; i++, iter++) - assert(iter != stack.end()); - - boost::shared_ptr dec = *iter; - assert(dec); - - const bool show = !dec->shown(); - dec->show(show); - - assert(index < (int)_decoder_forms.size()); - _decoder_forms[index]->set_decoder_visible(show); - - //_view->set_need_update(true); + create_popup_form(); } - int DecodeTrace::rows_size() { - return _decoder_stack->cur_rows_size(); + using pv::data::decode::Decoder; + + int size = 0; + BOOST_FOREACH(boost::shared_ptr dec, + _decoder_stack->stack()) { + if (dec->shown()) { + const std::map& rows(_decoder_stack->get_rows_gshow()); + for (std::map::const_iterator i = rows.begin(); + i != rows.end(); i++) { + if ((*i).first.decoder() == dec->decoder() && + _decoder_stack->has_annotations((*i).first) && + (*i).second) + size++; + } + } else { + size++; + } + } + return size == 0 ? 1 : size; } void DecodeTrace::paint_type_options(QPainter &p, int right, const QPoint pt) @@ -897,9 +903,8 @@ void DecodeTrace::paint_type_options(QPainter &p, int right, const QPoint pt) const QRectF group_index_rect = get_rect(CHNLREG, y, right); QString index_string; int last_index; - p.setPen(Qt::transparent); - p.setBrush(dsBlue); - p.drawRect(group_index_rect); + p.setPen(QPen(DARK_FORE, 1, Qt::DashLine)); + p.drawLine(group_index_rect.bottomLeft(), group_index_rect.bottomRight()); std::list::iterator i = _index_list.begin(); last_index = (*i); index_string = QString::number(last_index); @@ -912,7 +917,7 @@ void DecodeTrace::paint_type_options(QPainter &p, int right, const QPoint pt) index_string = QString::number((*i)) + "," + index_string; last_index = (*i); } - p.setPen(Qt::white); + p.setPen(DARK_FORE); p.drawText(group_index_rect, Qt::AlignRight | Qt::AlignVCenter, index_string); } @@ -986,5 +991,6 @@ void DecodeTrace::frame_ended() } } + } // namespace view } // namespace pv diff --git a/DSView/pv/view/decodetrace.h b/DSView/pv/view/decodetrace.h index 32f17bd9..553da4d9 100644 --- a/DSView/pv/view/decodetrace.h +++ b/DSView/pv/view/decodetrace.h @@ -152,14 +152,14 @@ private: void draw_annotation(const pv::data::decode::Annotation &a, QPainter &p, QColor text_colour, int text_height, int left, int right, double samples_per_pixel, double pixels_offset, int y, - size_t base_colour) const; + size_t base_colour, double min_annWidth) const; void draw_nodetail(QPainter &p, int text_height, int left, int right, int y, size_t base_colour) const; void draw_instant(const pv::data::decode::Annotation &a, QPainter &p, QColor fill, QColor outline, QColor text_color, int h, double x, - int y) const; + int y, double min_annWidth) const; void draw_range(const pv::data::decode::Annotation &a, QPainter &p, QColor fill, QColor outline, QColor text_color, int h, double start, @@ -172,11 +172,11 @@ private: int right); void draw_unshown_row(QPainter &p, int y, int h, int left, - int right); + int right, QString info); - void create_decoder_form(int index, - boost::shared_ptr &dec, - QWidget *parent, QFormLayout *form); + void create_decoder_form(boost::shared_ptr &decoder_stack, + boost::shared_ptr &dec, + QWidget *parent, QFormLayout *form); QComboBox* create_probe_selector(QWidget *parent, const boost::shared_ptr &dec, @@ -195,8 +195,7 @@ private slots: void on_probe_selected(int); void on_stack_decoder(srd_decoder *decoder); - - void on_show_hide_decoder(int index); + void on_del_stack(boost::shared_ptr &dec); void on_decode_done(); @@ -219,7 +218,6 @@ private: std::vector _cur_row_headings; - QSignalMapper _show_hide_mapper; QFormLayout *_popup_form; QDialog *_popup; }; diff --git a/DSView/pv/view/devmode.cpp b/DSView/pv/view/devmode.cpp index f48c453c..2fb0a2b7 100644 --- a/DSView/pv/view/devmode.cpp +++ b/DSView/pv/view/devmode.cpp @@ -44,45 +44,50 @@ using namespace std; namespace pv { namespace view { -DevMode::DevMode(View &parent) : - QWidget(&parent), - _view(parent), - layout(new QGridLayout(this)) +DevMode::DevMode(QWidget *parent, SigSession &session) : + QWidget(parent), + _session(session), + _layout(new QGridLayout(this)) { - setLayout(layout); + setLayout(_layout); } void DevMode::set_device() { int index = 0; - const boost::shared_ptr dev_inst = _view.session().get_device(); + const boost::shared_ptr dev_inst = _session.get_device(); assert(dev_inst); + for(std::map::const_iterator i = _mode_button_list.begin(); + i != _mode_button_list.end(); i++) { + (*i).first->setParent(NULL); + _layout->removeWidget((*i).first); + delete (*i).first; + } _mode_button_list.clear(); - delete layout; - layout = new QGridLayout(this); for (GSList *l = dev_inst->get_dev_mode_list(); l; l = l->next) { sr_dev_mode *mode = (sr_dev_mode *)l->data; - boost::shared_ptr mode_button = boost::shared_ptr(new QPushButton(NULL)); - mode_button->setFlat(true); + QPushButton *mode_button = new QPushButton(this); + //mode_button->setFlat(true); mode_button->setText(mode->name); + mode_button->setCheckable(true); _mode_button_list[mode_button] = mode; + if (dev_inst->dev_inst()->mode == _mode_button_list[mode_button]->mode) + mode_button->setChecked(true); - connect(mode_button.get(), SIGNAL(clicked()), this, SLOT(on_mode_change())); + connect(mode_button, SIGNAL(clicked()), this, SLOT(on_mode_change())); - layout->addWidget(mode_button.get(), index / GRID_COLS, index % GRID_COLS); - layout->addWidget(new QWidget(), index / GRID_COLS, GRID_COLS); - layout->setColumnStretch(GRID_COLS, 1); + _layout->addWidget(mode_button, index / GRID_COLS, index % GRID_COLS); + //layout->addWidget(new QWidget(), index / GRID_COLS, GRID_COLS); + _layout->setColumnStretch(GRID_COLS, 1); index++; - } - - setLayout(layout); + } update(); } @@ -94,40 +99,27 @@ void DevMode::paintEvent(QPaintEvent*) o.initFrom(this); QPainter painter(this); style()->drawPrimitive(QStyle::PE_Widget, &o, &painter, this); - - painter.setRenderHint(QPainter::Antialiasing); - painter.setPen(Qt::NoPen); - for(std::map, sr_dev_mode *>::const_iterator i = _mode_button_list.begin(); - i != _mode_button_list.end(); i++) { - const boost::shared_ptr dev_inst = _view.session().get_device(); - assert(dev_inst); - if (dev_inst->dev_inst()->mode == (*i).second->mode) - painter.setBrush(Trace::dsBlue); - else - painter.setBrush(Trace::dsGray); - - painter.drawRoundedRect((*i).first->geometry(), 4, 4); - } - - painter.end(); } void DevMode::on_mode_change() { - const boost::shared_ptr dev_inst = _view.session().get_device(); + const boost::shared_ptr dev_inst = _session.get_device(); assert(dev_inst); QPushButton *button = qobject_cast(sender()); - for(std::map, sr_dev_mode *>::const_iterator i = _mode_button_list.begin(); + for(std::map::const_iterator i = _mode_button_list.begin(); i != _mode_button_list.end(); i++) { - if ((*i).first.get() == button) { + if ((*i).first == button) { if (dev_inst->dev_inst()->mode != (*i).second->mode) { - _view.session().stop_capture(); + _session.stop_capture(); dev_inst->set_config(NULL, NULL, SR_CONF_DEVICE_MODE, g_variant_new_int16((*i).second->mode)); + button->setChecked(true); mode_changed(); } + } else { + (*i).first->setChecked(false); } } } diff --git a/DSView/pv/view/devmode.h b/DSView/pv/view/devmode.h index 27488805..3e114fbb 100644 --- a/DSView/pv/view/devmode.h +++ b/DSView/pv/view/devmode.h @@ -44,9 +44,9 @@ namespace device{ class DevInst; } -namespace view { +class SigSession; -class View; +namespace view { class DevMode : public QWidget { @@ -56,7 +56,7 @@ private: static const int GRID_COLS = 3; public: - DevMode(View &parent); + DevMode(QWidget *parent, SigSession &session); private: void paintEvent(QPaintEvent *event); @@ -77,10 +77,10 @@ signals: void mode_changed(); private: - View &_view; + SigSession &_session; - QGridLayout * layout; - std::map , sr_dev_mode *> _mode_button_list; + QGridLayout * _layout; + std::map _mode_button_list; QPoint _mouse_point; }; diff --git a/DSView/pv/view/groupsignal.cpp b/DSView/pv/view/groupsignal.cpp index 0c674dfd..aec24c5b 100644 --- a/DSView/pv/view/groupsignal.cpp +++ b/DSView/pv/view/groupsignal.cpp @@ -204,9 +204,8 @@ void GroupSignal::paint_type_options(QPainter &p, int right, const QPoint pt) const QRectF group_index_rect = get_rect(CHNLREG, y, right); QString index_string; int last_index; - p.setPen(Qt::transparent); - p.setBrush(dsBlue); - p.drawRect(group_index_rect); + p.setPen(QPen(DARK_FORE, 1, Qt::DashLine)); + p.drawLine(group_index_rect.bottomLeft(), group_index_rect.bottomRight()); std::list::iterator i = _index_list.begin(); last_index = (*i); index_string = QString::number(last_index); @@ -219,7 +218,7 @@ void GroupSignal::paint_type_options(QPainter &p, int right, const QPoint pt) index_string = QString::number((*i)) + "," + index_string; last_index = (*i); } - p.setPen(Qt::white); + p.setPen(DARK_FORE); p.drawText(group_index_rect, Qt::AlignRight | Qt::AlignVCenter, index_string); } diff --git a/DSView/pv/view/header.cpp b/DSView/pv/view/header.cpp index e6d20c37..ca38299f 100644 --- a/DSView/pv/view/header.cpp +++ b/DSView/pv/view/header.cpp @@ -115,15 +115,13 @@ void Header::paintEvent(QPaintEvent*) QStyleOption o; o.initFrom(this); QPainter painter(this); + //painter.setRenderHint(QPainter::Antialiasing); style()->drawPrimitive(QStyle::PE_Widget, &o, &painter, this); const int w = width(); const vector< boost::shared_ptr > traces( _view.get_traces()); - //QPainter painter(this); - //painter.setRenderHint(QPainter::Antialiasing); - const bool dragging = !_drag_traces.empty(); BOOST_FOREACH(const boost::shared_ptr t, traces) { diff --git a/DSView/pv/view/logicsignal.cpp b/DSView/pv/view/logicsignal.cpp index 4bbe9ad0..00df932b 100644 --- a/DSView/pv/view/logicsignal.cpp +++ b/DSView/pv/view/logicsignal.cpp @@ -44,24 +44,7 @@ const QColor LogicSignal::EdgeColour(0x80, 0x80, 0x80); const QColor LogicSignal::HighColour(0x00, 0xC0, 0x00); const QColor LogicSignal::LowColour(0xC0, 0x00, 0x00); -const QColor LogicSignal::SignalColours[8] = { - QColor(0x16, 0x19, 0x1A), // Black - QColor(0x8F, 0x52, 0x02), // Brown - QColor(0xCC, 0x00, 0x00), // Red - QColor(0xF5, 0x79, 0x00), // Orange - QColor(0xED, 0xD4, 0x00), // Yellow - QColor(0x73, 0xD2, 0x16), // Green - QColor(0x34, 0x65, 0xA4), // Blue - QColor(0x75, 0x50, 0x7B), // Violet -// QColor(17, 133, 209), -// QColor(17, 133, 209), -// QColor(17, 133, 209), -// QColor(17, 133, 209), -// QColor(17, 133, 209), -// QColor(17, 133, 209), -// QColor(17, 133, 209), -// QColor(17, 133, 209), -}; +const QColor LogicSignal::DEFAULT_COLOR = QColor(150, 150, 150, 255); const int LogicSignal::StateHeight = 12; const int LogicSignal::StateRound = 5; @@ -73,7 +56,8 @@ LogicSignal::LogicSignal(boost::shared_ptr dev_inst, _data(data), _trig(NONTRIG) { - _colour = SignalColours[probe->index % countof(SignalColours)]; + //_colour = PROBE_COLORS[probe->index % countof(PROBE_COLORS)]; + _colour = DEFAULT_COLOR; } LogicSignal::LogicSignal(boost::shared_ptr s, @@ -249,35 +233,37 @@ void LogicSignal::paint_type_options(QPainter &p, int right, const QPoint pt) const QRectF lowTrig_rect = get_rect(LOWTRIG, y, right); const QRectF edgeTrig_rect = get_rect(EDGTRIG, y, right); - p.setPen(Qt::transparent); - p.setBrush(posTrig_rect.contains(pt) ? dsYellow.darker() : - (_trig == POSTRIG) ? dsYellow : dsBlue); + p.setPen(Qt::NoPen); + p.setBrush(posTrig_rect.contains(pt) ? dsBlue.lighter() : + (_trig == POSTRIG) ? dsBlue : DARK_BACK); p.drawRect(posTrig_rect); - p.setBrush(higTrig_rect.contains(pt) ? dsYellow.darker() : - (_trig == HIGTRIG) ? dsYellow : dsBlue); + p.setBrush(higTrig_rect.contains(pt) ? dsBlue.lighter() : + (_trig == HIGTRIG) ? dsBlue : DARK_BACK); p.drawRect(higTrig_rect); - p.setBrush(negTrig_rect.contains(pt) ? dsYellow.darker() : - (_trig == NEGTRIG) ? dsYellow : dsBlue); + p.setBrush(negTrig_rect.contains(pt) ? dsBlue.lighter() : + (_trig == NEGTRIG) ? dsBlue : DARK_BACK); p.drawRect(negTrig_rect); - p.setBrush(lowTrig_rect.contains(pt) ? dsYellow.darker() : - (_trig == LOWTRIG) ? dsYellow : dsBlue); + p.setBrush(lowTrig_rect.contains(pt) ? dsBlue.lighter() : + (_trig == LOWTRIG) ? dsBlue : DARK_BACK); p.drawRect(lowTrig_rect); - p.setBrush(edgeTrig_rect.contains(pt) ? dsYellow.darker() : - (_trig == EDGTRIG) ? dsYellow : dsBlue); + p.setBrush(edgeTrig_rect.contains(pt) ? dsBlue.lighter() : + (_trig == EDGTRIG) ? dsBlue : DARK_BACK); p.drawRect(edgeTrig_rect); - p.setPen(QPen(Qt::blue, 1, Qt::DotLine)); + p.setPen(QPen(DARK_FORE, 1, Qt::DashLine)); p.setBrush(Qt::transparent); - p.drawLine(posTrig_rect.right(), posTrig_rect.top() + 3, - posTrig_rect.right(), posTrig_rect.bottom() - 3); - p.drawLine(higTrig_rect.right(), higTrig_rect.top() + 3, - higTrig_rect.right(), higTrig_rect.bottom() - 3); - p.drawLine(negTrig_rect.right(), negTrig_rect.top() + 3, - negTrig_rect.right(), negTrig_rect.bottom() - 3); - p.drawLine(lowTrig_rect.right(), lowTrig_rect.top() + 3, - lowTrig_rect.right(), lowTrig_rect.bottom() - 3); +// p.drawLine(posTrig_rect.right(), posTrig_rect.top(), +// posTrig_rect.right(), posTrig_rect.bottom()); +// p.drawLine(higTrig_rect.right(), higTrig_rect.top(), +// higTrig_rect.right(), higTrig_rect.bottom()); +// p.drawLine(negTrig_rect.right(), negTrig_rect.top(), +// negTrig_rect.right(), negTrig_rect.bottom()); +// p.drawLine(lowTrig_rect.right(), lowTrig_rect.top(), +// lowTrig_rect.right(), lowTrig_rect.bottom()); + p.drawLine(posTrig_rect.left(), posTrig_rect.bottom(), + edgeTrig_rect.right(), edgeTrig_rect.bottom()); - p.setPen(QPen(Qt::white, 2, Qt::SolidLine)); + p.setPen(QPen(DARK_FORE, 2, Qt::SolidLine)); p.setBrush(Qt::transparent); p.drawLine(posTrig_rect.left() + 5, posTrig_rect.bottom() - 5, posTrig_rect.center().x(), posTrig_rect.bottom() - 5); diff --git a/DSView/pv/view/logicsignal.h b/DSView/pv/view/logicsignal.h index 5f4ba7d1..3daa567b 100644 --- a/DSView/pv/view/logicsignal.h +++ b/DSView/pv/view/logicsignal.h @@ -48,7 +48,7 @@ private: static const QColor HighColour; static const QColor LowColour; - static const QColor SignalColours[8]; + static const QColor DEFAULT_COLOR; static const int StateHeight; static const int StateRound; diff --git a/DSView/pv/view/ruler.cpp b/DSView/pv/view/ruler.cpp index 0a3b8015..3fdab4b9 100644 --- a/DSView/pv/view/ruler.cpp +++ b/DSView/pv/view/ruler.cpp @@ -77,6 +77,7 @@ const QColor Ruler::dsBlue = QColor(17, 133, 209, 255); const QColor Ruler::dsYellow = QColor(238, 178, 17, 255); const QColor Ruler::dsRed = QColor(213, 15, 37, 255); const QColor Ruler::dsGreen = QColor(0, 153, 37, 255); +const QColor Ruler::RULER_COLOR = QColor(255, 255, 255, 255); const QColor Ruler::HitColor = dsYellow; const QColor Ruler::WarnColor = dsRed; @@ -458,7 +459,7 @@ void Ruler::draw_logic_tick_mark(QPainter &p) AlignLeft | AlignTop, "8").height(); // Draw the tick marks - p.setPen(dsBlue); + p.setPen(Trace::DARK_FORE); const double minor_tick_period = tick_period / MinPeriodScale; const int minor_order = (int)floorf(log10f(minor_tick_period)); @@ -548,7 +549,7 @@ void Ruler::draw_hover_mark(QPainter &p) return; p.setPen(QPen(Qt::NoPen)); - p.setBrush(dsBlue); + p.setBrush(RULER_COLOR); const int b = height() - 1; const QPointF points[] = { diff --git a/DSView/pv/view/ruler.h b/DSView/pv/view/ruler.h index c22d8cce..d3389bdc 100644 --- a/DSView/pv/view/ruler.h +++ b/DSView/pv/view/ruler.h @@ -54,6 +54,7 @@ private: static const QColor dsYellow; static const QColor dsRed; static const QColor dsGreen; + static const QColor RULER_COLOR; public: static const QColor CursorColor[8]; diff --git a/DSView/pv/view/trace.cpp b/DSView/pv/view/trace.cpp index 52d522d5..3c79bc1a 100644 --- a/DSView/pv/view/trace.cpp +++ b/DSView/pv/view/trace.cpp @@ -50,6 +50,29 @@ const QColor Trace::dsLightBlue = QColor(17, 133, 209, 150); const QColor Trace::dsLightRed = QColor(213, 15, 37, 150); const QPen Trace::SignalAxisPen = QColor(128, 128, 128, 64); +const QColor Trace::DARK_BACK = QColor(48, 47, 47, 255); +const QColor Trace::DARK_FORE = QColor(150, 150, 150, 255); +const QColor Trace::DARK_HIGHLIGHT = QColor(32, 32, 32, 255); + +const QColor Trace::PROBE_COLORS[8] = { + QColor(0x50, 0x50, 0x50), // Black + QColor(0x8F, 0x52, 0x02), // Brown + QColor(0xCC, 0x00, 0x00), // Red + QColor(0xF5, 0x79, 0x00), // Orange + QColor(0xED, 0xD4, 0x00), // Yellow + QColor(0x73, 0xD2, 0x16), // Green + QColor(0x34, 0x65, 0xA4), // Blue + QColor(0x75, 0x50, 0x7B), // Violet +// QColor(17, 133, 209), +// QColor(17, 133, 209), +// QColor(17, 133, 209), +// QColor(17, 133, 209), +// QColor(17, 133, 209), +// QColor(17, 133, 209), +// QColor(17, 133, 209), +// QColor(17, 133, 209), +}; + const QPen Trace::AxisPen(QColor(128, 128, 128, 64)); const int Trace::LabelHitPadding = 2; @@ -220,14 +243,14 @@ void Trace::paint_label(QPainter &p, int right, const QPoint pt) const QRectF name_rect = get_rect("name", y, right); const QRectF label_rect = get_rect("label", get_zeroPos(), right); - p.setRenderHint(QPainter::Antialiasing); + //p.setRenderHint(QPainter::Antialiasing); // Paint the ColorButton p.setPen(Qt::transparent); p.setBrush(enabled() ? _colour : dsDisable); p.drawRect(color_rect); // Paint the signal name - p.setPen(enabled() ? Qt::black : dsDisable); + p.setPen(enabled() ? DARK_FORE: dsDisable); p.drawText(name_rect, Qt::AlignLeft | Qt::AlignVCenter, _name); // Paint the trigButton @@ -244,16 +267,14 @@ void Trace::paint_label(QPainter &p, int right, const QPoint pt) }; p.setPen(Qt::transparent); - if (_type == SR_CHANNEL_DSO) + if (_type == SR_CHANNEL_DSO) { p.setBrush((label_rect.contains(pt) || selected()) ? _colour.darker() : _colour); - else - p.setBrush((label_rect.contains(pt) || selected()) ? dsYellow : dsBlue); - p.drawPolygon(points, countof(points)); - - p.setPen(QPen(Qt::blue, 1, Qt::DotLine)); - p.setBrush(Qt::transparent); - p.drawLine(label_rect.right(), label_rect.top() + 3, - label_rect.right(), label_rect.bottom() - 3); + p.drawPolygon(points, countof(points)); + } else { + QColor color = PROBE_COLORS[*_index_list.begin() % countof(PROBE_COLORS)]; + p.setBrush((label_rect.contains(pt) || selected()) ? color.lighter() : color); + p.drawPolygon(points, countof(points)); + } // Paint the text p.setPen(Qt::white); @@ -326,30 +347,6 @@ void Trace::compute_text_size(QPainter &p) p.boundingRect(QRectF(), 0, "99").height()); } -QRectF Trace::get_rect(const char *s, int y, int right) -{ - const QSizeF color_size(SquareWidth, SquareWidth); - const QSizeF name_size(right - get_leftWidth() - get_rightWidth(), SquareWidth); - //const QSizeF label_size(_text_size.width() + Margin, SquareWidth); - const QSizeF label_size(SquareWidth, SquareWidth); - - if (!strcmp(s, "name")) - return QRectF( - get_leftWidth(), - y - name_size.height() / 2, - name_size.width(), name_size.height()); - else if (!strcmp(s, "label")) - return QRectF( - right - 1.5f * label_size.width(), - y - SquareWidth / 2, - label_size.width(), label_size.height()); - else - return QRectF( - 2, - y - SquareWidth / 2, - SquareWidth, SquareWidth); -} - QRectF Trace::get_view_rect() const { assert(_view); @@ -385,7 +382,7 @@ int Trace::rows_size() int Trace::get_leftWidth() const { - return SquareWidth + Margin; + return SquareWidth/2 + Margin; } int Trace::get_rightWidth() const @@ -398,5 +395,34 @@ int Trace::get_headerHeight() const return SquareWidth; } +QRectF Trace::get_rect(const char *s, int y, int right) const +{ + const QSizeF color_size(get_leftWidth() - Margin, SquareWidth); + const QSizeF name_size(right - get_leftWidth() - get_rightWidth(), SquareWidth); + //const QSizeF label_size(_text_size.width() + Margin, SquareWidth); + const QSizeF label_size(SquareWidth, SquareWidth); + + if (!strcmp(s, "name")) + return QRectF( + get_leftWidth(), + y - name_size.height() / 2, + name_size.width(), name_size.height()); + else if (!strcmp(s, "label")) + return QRectF( + right - 1.5f * label_size.width(), + y - label_size.height() / 2, + label_size.width(), label_size.height()); + else if (!strcmp(s, "color")) + return QRectF( + 2, + y - color_size.height() / 2, + color_size.width(), color_size.height()); + else + return QRectF( + 2, + y - SquareWidth / 2, + SquareWidth, SquareWidth); +} + } // namespace view } // namespace pv diff --git a/DSView/pv/view/trace.h b/DSView/pv/view/trace.h index 329400bd..26d9b504 100644 --- a/DSView/pv/view/trace.h +++ b/DSView/pv/view/trace.h @@ -70,6 +70,12 @@ public: static const QColor dsLightRed; static const QPen SignalAxisPen; + static const QColor DARK_BACK; + static const QColor DARK_FORE; + static const QColor DARK_HIGHLIGHT; + + static const QColor PROBE_COLORS[8]; + protected: Trace(QString name, uint16_t index, int type); Trace(QString name, std::list index_list, int type, int sec_index); @@ -225,7 +231,7 @@ public: * area. * @return Returns the rectangle of the signal label. */ - QRectF get_rect(const char *s, int y, int right); + QRectF get_rect(const char *s, int y, int right) const; virtual int rows_size(); diff --git a/DSView/pv/view/view.cpp b/DSView/pv/view/view.cpp index e421a8ce..df0e2e87 100644 --- a/DSView/pv/view/view.cpp +++ b/DSView/pv/view/view.cpp @@ -74,7 +74,7 @@ View::View(SigSession &session, pv::toolbars::SamplingBar *sampling_bar, QWidget _viewport(new Viewport(*this)), _ruler(new Ruler(*this)), _header(new Header(*this)), - _devmode(new DevMode(*this)), + _devmode(new DevMode(this, session)), _scale(1e-8), _preScale(1e-6), _maxscale(1e9), @@ -98,15 +98,17 @@ View::View(SigSession &session, pv::toolbars::SamplingBar *sampling_bar, QWidget setViewportMargins(headerWidth(), RulerHeight, 0, 0); setViewport(_viewport); + connect(&_session, SIGNAL(device_setted()), + _devmode, SLOT(set_device())); connect(&_session, SIGNAL(signals_changed()), this, SLOT(signals_changed())); connect(&_session, SIGNAL(data_updated()), this, SLOT(data_updated())); connect(&_session, SIGNAL(receive_trigger(quint64)), this, SLOT(set_trig_pos(quint64))); + connect(&_session, SIGNAL(show_region(uint64_t,uint64_t)), + this, SLOT(show_region(uint64_t, uint64_t))); - connect(&_session, SIGNAL(device_setted()), - _devmode, SLOT(set_device())); connect(_devmode, SIGNAL(mode_changed()), this, SIGNAL(mode_changed())); @@ -464,9 +466,9 @@ void View::update_scale() } _minscale = (1.0 / sample_rate) / MaxPixelsPerSample; - _offset = 0; + //_offset = 0; _preScale = _scale; - _preOffset = _offset; + //_preOffset = _offset; _trig_cursor->set_index(_trig_pos); @@ -514,6 +516,7 @@ void View::signals_changed() _viewport->clear_measure(); header_updated(); normalize_layout(); + data_updated(); } bool View::eventFilter(QObject *object, QEvent *event) @@ -834,5 +837,14 @@ QString View::trigger_time() return _trigger_time.toString("yyyy-MM-dd hh:mm:ss ddd"); } +void View::show_region(uint64_t start, uint64_t end) +{ + assert(start <= end); + const double ideal_scale = (end-start) * 2.0 / _session.get_device()->get_sample_rate() / get_view_width(); + const double new_scale = max(min(ideal_scale, _maxscale), _minscale); + const double new_off = (start + end) * 0.5 / _session.get_device()->get_sample_rate() - new_scale * get_view_width() / 2; + set_scale_offset(new_scale, new_off); +} + } // namespace view } // namespace pv diff --git a/DSView/pv/view/view.h b/DSView/pv/view/view.h index 27fabea0..1f903737 100644 --- a/DSView/pv/view/view.h +++ b/DSView/pv/view/view.h @@ -221,6 +221,7 @@ public slots: void signals_changed(); void data_updated(); void update_scale(); + void show_region(uint64_t start, uint64_t end); private slots: diff --git a/DSView/pv/view/viewport.cpp b/DSView/pv/view/viewport.cpp index c53e5d51..4f5b6f67 100644 --- a/DSView/pv/view/viewport.cpp +++ b/DSView/pv/view/viewport.cpp @@ -445,11 +445,11 @@ void Viewport::mouseMoveEvent(QMouseEvent *event) if (_action_type == DSO_YM) _dso_ym_end = event->pos().y(); - - measure(); } _mouse_point = event->pos(); + + measure(); update(); } @@ -719,7 +719,6 @@ void Viewport::leaveEvent(QEvent *) _mm_period = "#####"; _mm_freq = "#####"; _mm_duty = "#####"; - measure_updated(); } else if (_action_type == DSO_YM) { _dso_ym_valid = false; } @@ -727,6 +726,7 @@ void Viewport::leaveEvent(QEvent *) if (_action_type != NO_ACTION) _action_type = NO_ACTION; + measure(); update(); } @@ -767,7 +767,7 @@ void Viewport::measure() boost::shared_ptr dsoSig; if (logicSig = dynamic_pointer_cast(s)) { if (_action_type == NO_ACTION) { - if (logicSig->measure(_view.hover_point(), _cur_sample, _nxt_sample, _thd_sample)) { + if (logicSig->measure(_mouse_point, _cur_sample, _nxt_sample, _thd_sample)) { _measure_type = LOGIC_FREQ; _mm_width = _view.get_ruler()->format_real_time(_nxt_sample - _cur_sample, sample_rate); @@ -1173,7 +1173,7 @@ void Viewport::on_drag_timer() void Viewport::paintTrigTime(QPainter &p) { if (_view.session().get_device()->dev_inst()->mode == LOGIC) { - p.setPen(Trace::dsBack); + p.setPen(Trace::DARK_FORE); p.drawText(this->rect(), Qt::AlignRight | Qt::AlignBottom, "Last Trigger Time: "+_view.trigger_time()); } diff --git a/DSView/pv/widgets/decodergroupbox.cpp b/DSView/pv/widgets/decodergroupbox.cpp index 3b4ec20a..d03082e6 100644 --- a/DSView/pv/widgets/decodergroupbox.cpp +++ b/DSView/pv/widgets/decodergroupbox.cpp @@ -17,52 +17,134 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +extern "C" { +#include +} #include "decodergroupbox.h" +#include "../data/decoderstack.h" +#include "../data/decode/decoder.h" +#include "../data/decode/row.h" #include #include #include #include +#include + +#include #include namespace pv { namespace widgets { -DecoderGroupBox::DecoderGroupBox(QString title, QWidget *parent) : - QWidget(parent), - _layout(new QGridLayout), - _show_hide_button(QIcon(":/icons/shown.png"), QString(), this) +DecoderGroupBox::DecoderGroupBox(boost::shared_ptr &decoder_stack, + boost::shared_ptr &dec, + QWidget *parent) : + QWidget(parent), + _decoder_stack(decoder_stack), + _dec(dec), + _layout(new QGridLayout) { _layout->setContentsMargins(0, 0, 0, 0); - setLayout(_layout); + setLayout(_layout); - _layout->addWidget(new QLabel(QString("

%1

").arg(title)), + _layout->addWidget(new QLabel(QString("

%1

").arg(_dec->decoder()->name)), 0, 0); _layout->setColumnStretch(0, 1); - QHBoxLayout *const toolbar = new QHBoxLayout; - _layout->addLayout(toolbar, 0, 1); + const srd_decoder *const d = _dec->decoder(); + assert(d); + const bool have_probes = (d->channels || d->opt_channels) != 0; + if (!have_probes) { + _del_button = new QPushButton(QIcon(":/icons/del.png"), QString(), this); + _layout->addWidget(_del_button, 0, 1); + connect(_del_button, SIGNAL(clicked()), this, SLOT(on_del_stack())); + } - _show_hide_button.setFlat(true); - //_show_hide_button.setIconSize(QSize(16, 16)); - connect(&_show_hide_button, SIGNAL(clicked()), - this, SIGNAL(show_hide_decoder())); - toolbar->addWidget(&_show_hide_button); + _index = 0; + BOOST_FOREACH(boost::shared_ptr dec, + _decoder_stack->stack()) { + if (dec == _dec) + break; + _index++; + } + _show_button = new QPushButton(QIcon(_dec->shown() ? + ":/icons/shown.png" : + ":/icons/hidden.png"), QString(), this); + _show_button->setProperty("index", -1); + connect(_show_button, SIGNAL(clicked()), + this, SLOT(tog_icon())); + _layout->addWidget(_show_button, 0, 2); + + + // add row show/hide + int index = 0; + const std::map& rows(_decoder_stack->get_rows_gshow()); + for (std::map::const_iterator i = rows.begin(); + i != rows.end(); i++) { + if ((*i).first.decoder() == _dec->decoder()) { + QPushButton *show_button = new QPushButton(QIcon((*i).second ? + ":/icons/shown.png" : + ":/icons/hidden.png"), QString(), this); + show_button->setProperty("index", index); + connect(show_button, SIGNAL(clicked()), this, SLOT(tog_icon())); + _row_show_button.push_back(show_button); + _layout->addWidget(new QLabel((*i).first.title(), this), _row_show_button.size(), 0); + _layout->addWidget(show_button, _row_show_button.size(), 2); + } + index++; + } } void DecoderGroupBox::add_layout(QLayout *layout) { assert(layout); - _layout->addLayout(layout, 1, 0, 1, 2); + _layout->addLayout(layout, _row_show_button.size()+1, 0, 1, 3); } -void DecoderGroupBox::set_decoder_visible(bool visible) +void DecoderGroupBox::tog_icon() { - _show_hide_button.setIcon(QIcon(visible ? - ":/icons/shown.png" : - ":/icons/hidden.png")); + QPushButton *sc = dynamic_cast(sender()); + QVariant id = sc->property("index"); + int index = id.toInt(); + if (index == -1) { + int i = _index; + BOOST_FOREACH(boost::shared_ptr dec, + _decoder_stack->stack()) { + if (i-- == 0) { + dec->show(!dec->shown()); + sc->setIcon(QIcon(dec->shown() ? ":/icons/shown.png" : + ":/icons/hidden.png")); + break; + } + } + } else { + std::map& rows(_decoder_stack->get_rows_gshow()); + for (std::map::const_iterator i = rows.begin(); + i != rows.end(); i++) { + if (index-- == 0) { + _decoder_stack->set_rows_gshow((*i).first, !(*i).second); + //rows[(*i).first] = !(*i).second; + sc->setIcon(QIcon(rows[(*i).first] ? ":/icons/shown.png" : + ":/icons/hidden.png")); + break; + } + } + } +} + +void DecoderGroupBox::on_del_stack() +{ + int i = _index; + BOOST_FOREACH(boost::shared_ptr dec, + _decoder_stack->stack()) { + if (i-- == 0) { + del_stack(dec); + break; + } + } } } // widgets diff --git a/DSView/pv/widgets/decodergroupbox.h b/DSView/pv/widgets/decodergroupbox.h index 07878ae2..c69543d5 100644 --- a/DSView/pv/widgets/decodergroupbox.h +++ b/DSView/pv/widgets/decodergroupbox.h @@ -22,11 +22,19 @@ #define DSVIEW_PV_WIDGETS_DECODERGROUPBOX_H #include - -class QGridLayout; -class QToolBar; +#include +#include +#include namespace pv { + +namespace data{ +class DecoderStack; +namespace decode{ +class Decoder; +} +} + namespace widgets { class DecoderGroupBox : public QWidget @@ -34,18 +42,30 @@ class DecoderGroupBox : public QWidget Q_OBJECT public: - DecoderGroupBox(QString title, QWidget *parent = NULL); + DecoderGroupBox(boost::shared_ptr &decoder_stack, + boost::shared_ptr &dec, + QWidget *parent = NULL); void add_layout(QLayout *layout); - void set_decoder_visible(bool visible); - signals: void show_hide_decoder(); + void show_hide_row(); + void del_stack(boost::shared_ptr &_dec); + +private slots: + void tog_icon(); + void on_del_stack(); private: - QGridLayout *const _layout; - QPushButton _show_hide_button; + boost::shared_ptr &_decoder_stack; + boost::shared_ptr &_dec; + int _index; + + QGridLayout *const _layout; + QPushButton *_del_button; + QPushButton *_show_button; + std::list _row_show_button; }; } // widgets diff --git a/DSView/stylesheet.qss b/DSView/stylesheet.qss index c901688c..5751426e 100644 --- a/DSView/stylesheet.qss +++ b/DSView/stylesheet.qss @@ -261,4 +261,24 @@ QSlider::add-page:horizontal{ border-radius: 4px; } +/* <<< QTableView */ +QHeaderView::section { + background-color: #646464; + padding: 4px; + font-size: 14pt; + border-style: none; + border-bottom: 1px solid #fffff8; + border-right: 1px solid #fffff8; +} + +QHeaderView::section:horizontal +{ + border-top: 1px solid #fffff8; +} + +QHeaderView::section:vertical +{ + border-left: 1px solid #fffff8; +} + /* <<< QDockWidget */