1 // Copyright (c) 2016 The SigViewer Development Team
2 // Licensed under the GNU General Public License (GPL)
3 // https://www.gnu.org/licenses/gpl
4
5
6 #include "y_axis_widget_4.h"
7 #include "signal_graphics_item.h"
8 #include "gui/gui_action_factory.h"
9 #include "base/math_utils.h"
10
11 #include <QPaintEvent>
12 #include <QPainter>
13 #include <QPixmap>
14 #include <QDebug>
15 #include <QContextMenuEvent>
16
17 #include <cmath>
18
19 namespace sigviewer
20 {
21
22 //-----------------------------------------------------------------------------
YAxisWidget(QWidget * parent,QSharedPointer<const SignalViewSettings> signal_view_settings)23 YAxisWidget::YAxisWidget (QWidget* parent, QSharedPointer<const SignalViewSettings> signal_view_settings)
24 : QWidget (parent),
25 channel_height_ (0),
26 y_start_ (0),
27 signal_view_settings_ (signal_view_settings),
28 label_color_ (Qt::black)
29 {
30 // nothing to do here
31 }
32
33 //-----------------------------------------------------------------------------
addChannel(ChannelID channel_nr,SignalGraphicsItem const * const signal_item)34 void YAxisWidget::addChannel(ChannelID channel_nr, SignalGraphicsItem const* const signal_item)
35 {
36 if (signal_item)
37 channel_nr2signal_graphics_item_[channel_nr] = signal_item;
38 }
39
40 //-----------------------------------------------------------------------------
removeChannel(ChannelID channel_nr)41 void YAxisWidget::removeChannel(ChannelID channel_nr)
42 {
43 QMap<ChannelID, SignalGraphicsItem const*>::iterator it = channel_nr2signal_graphics_item_.find(channel_nr);
44
45 if (it != channel_nr2signal_graphics_item_.end())
46 {
47 channel_nr2signal_graphics_item_.erase(it);
48 update ();
49 }
50 }
51
52 //-----------------------------------------------------------------------------
changeSignalHeight(unsigned signal_height)53 void YAxisWidget::changeSignalHeight (unsigned signal_height)
54 {
55 channel_height_ = signal_height;
56 update ();
57 }
58
59 //-----------------------------------------------------------------------------
changeYStart(int32 y_start)60 void YAxisWidget::changeYStart(int32 y_start)
61 {
62 y_start_ = y_start;
63 update ();
64 }
65
66 //-----------------------------------------------------------------------------
updateChannel(ChannelID)67 void YAxisWidget::updateChannel (ChannelID)
68 {
69 update ();
70 }
71
72 //-----------------------------------------------------------------------------
enableSeparator(bool enable)73 void YAxisWidget::enableSeparator(bool enable)
74 {
75 enable_separator = enable;
76 update();
77 }
78
79 //-----------------------------------------------------------------------------
changeLabelColor(QColor labelColor)80 void YAxisWidget::changeLabelColor(QColor labelColor)
81 {
82 label_color_ = labelColor;
83 update();
84 }
85
86 //!this section is set to be consistent with label_widget.cpp----------------
paintEvent(QPaintEvent *)87 void YAxisWidget::paintEvent(QPaintEvent*)
88 {
89 bool channel_overlapping = signal_view_settings_->getChannelOverlapping();
90 float64 signal_height = signal_view_settings_->getChannelHeight();
91 if (channel_overlapping)
92 signal_height = (signal_height +
93 (signal_height * (channel_nr2signal_graphics_item_.size() - 1)
94 * (1.0 - signal_view_settings_->getChannelOverlapping())))
95 / channel_nr2signal_graphics_item_.size();
96
97 int32 y_end = y_start_ + height();
98
99 if (signal_height < 1)
100 return;
101
102 QPainter painter (this);
103 painter.translate(0, -y_start_);
104 painter.setPen(label_color_);
105
106 // painter.setPen(QColor(0, 43, 130));
107 // painter.drawLine(width() - 1, y_start_, width() - 1, y_end);
108 // painter.setPen(Qt::black);
109
110 float64 float_y_end = y_end;
111 auto iter = channel_nr2signal_graphics_item_.begin();
112
113 for (float32 float_y = signal_height / 2;
114 float_y < float_y_end && iter != channel_nr2signal_graphics_item_.end();
115 float_y += signal_height, iter++)
116 {
117 paintYAxisLabels (&painter, iter.value()->getYOffset(),
118 iter.value()->getYGridPixelIntervall(),
119 iter.value()->getValueRangeFragment(),
120 iter.value()->getPhysicalDimensionString(),
121 signal_height);
122 painter.translate (0, signal_height);
123 }
124
125 // this is the bottom line
126 if (!channel_overlapping && enable_separator)
127 painter.drawLine (0, 0, width() - 1, 0);
128
129 // if (channel_overlapping)
130 // return;
131
132 // for (float32 float_y = 0;
133 // float_y <= signal_height * channel_nr2signal_graphics_item_.size();
134 // float_y += signal_height)
135 // {
136 // painter.drawLine(0, float_y, width() - 1, float_y);
137 // }
138 }
139
140 //-----------------------------------------------------------------------------
contextMenuEvent(QContextMenuEvent * event)141 void YAxisWidget::contextMenuEvent (QContextMenuEvent* event)
142 {
143 QMenu menu;
144 menu.addAction(GuiActionFactory::getInstance()->getQAction("Channels per Page..."));
145 menu.addSeparator();
146 QAction* visibility_action = menu.addAction("Y Axis");
147 visibility_action->setCheckable (true);
148 visibility_action->setChecked (true);
149 connect (visibility_action, SIGNAL(triggered(bool)), SLOT(setVisible(bool)));
150 menu.exec (event->globalPos());
151 }
152
153 //-------------------------------------------------------------------
paintYAxisLabels(QPainter * painter,float64 offset,float64 y_grid_pixel_intervall,double value_range_fragment,QString const & unit_string,float64 channelHeight)154 void YAxisWidget::paintYAxisLabels (QPainter* painter, float64 offset,
155 float64 y_grid_pixel_intervall,
156 double value_range_fragment,
157 QString const& unit_string, float64 channelHeight)
158 {
159 //Below, 0 is the relative upper border of each channel.
160 //despite being an absolute value, because the painter coordinates are readjusted
161 //automatically every time it moves to a new channel, hence 0 is the
162 //relative position of the upper border of each channel
163 #define UPPER_BORDER 0
164
165 bool channel_overlapping = signal_view_settings_->getChannelOverlapping();
166
167 if (!channel_overlapping && enable_separator)
168 {
169 painter->drawLine (0, UPPER_BORDER, width() - 1, UPPER_BORDER);
170 }
171
172 paintYUnits (painter, unit_string, channelHeight);
173
174 if (y_grid_pixel_intervall < 1)
175 return;
176
177 while (y_grid_pixel_intervall < 11)
178 {
179 y_grid_pixel_intervall *= 2;
180 value_range_fragment *= 2;
181 }
182
183 double value = 0;
184
185 //offset + channelHeight / 2 is the position where 0 is for each channel
186 //However, 0 doesn't necessarily appear in the channel, if we are in
187 //"zero line fitted" mode and if the mean is far from 0.
188
189 //In the following for loop, we are still going to calculate from the position of 0
190 //even if 0 doesn't appear in the channel. Because in "view option" mode, the channel
191 //can be scrolled up and down arbitrarily.
192 for (float64 value_y = offset + channelHeight / 2; value_y < channelHeight;
193 value_y += y_grid_pixel_intervall)
194 {
195 //But we only paint the calibration when they are within the channel height.
196 //This can be dynamic if in the "view option" mode, since channels can be
197 //scolled up and down.
198
199 //Here, value starts with 0 means painter will draw 0 first, and subtract
200 //value_range_fragment from value thereafter, so long as they are within channel
201 //height from UPPER_BORDER
202 if (value_y > UPPER_BORDER)
203 {
204
205 painter->drawLine (width () - 5, value_y, width () - 1, value_y);
206 painter->drawText(0, value_y - 20, width () - 10, 40,
207 Qt::AlignRight | Qt::AlignVCenter,
208 QString::number (value));
209 }
210 value -= value_range_fragment;
211 }
212
213 //We finished painting 0 and all negative numbers, now reset value to 0
214 value = 0;
215 //Now paint the positive numbers
216 for (float64 value_y = offset + channelHeight / 2 - y_grid_pixel_intervall;
217 value_y > UPPER_BORDER; value_y -= y_grid_pixel_intervall)
218 {
219 value += value_range_fragment;
220 //paint only if they position is within the range from UPPER_BORDER to
221 //the bottom (UPPER_BORDER + channelHeight). This can be dynamic when
222 //scrolling the channel.
223 if (value_y < channelHeight)
224 {
225 painter->drawLine (width () - 5, value_y, width () - 1, value_y);
226 painter->drawText(0, value_y - 20, width () - 10, 40,
227 Qt::AlignRight | Qt::AlignVCenter,
228 QString::number (value));
229 }
230 }
231 }
232
233 //-------------------------------------------------------------------
paintYUnits(QPainter * painter,QString const & unit_string,float64 channelHeight)234 void YAxisWidget::paintYUnits (QPainter* painter, QString const& unit_string, float64 channelHeight)
235 {
236 if (unit_string.size() > 4)
237 {
238 painter->rotate(-90);
239 painter->drawText (5, 0, width(), channelHeight,
240 Qt::AlignLeft | Qt::AlignVCenter,
241 unit_string);
242 painter->rotate(90);
243 }
244 else
245 painter->drawText (5, 0, width() - 10, channelHeight,
246 Qt::AlignLeft | Qt::AlignVCenter,
247 unit_string);
248 }
249
250 }
251