1 //////////////////////////////////////////////////////////////////////////////
2 // BSD 3-Clause License
3 //
4 // Copyright (c) 2019, The Regents of the University of California
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions are met:
9 //
10 // * Redistributions of source code must retain the above copyright notice, this
11 // list of conditions and the following disclaimer.
12 //
13 // * Redistributions in binary form must reproduce the above copyright notice,
14 // this list of conditions and the following disclaimer in the documentation
15 // and/or other materials provided with the distribution.
16 //
17 // * Neither the name of the copyright holder nor the names of its
18 // contributors may be used to endorse or promote products derived from
19 // this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 // POSSIBILITY OF SUCH DAMAGE.
32
33 #include "congestionSetupDialog.h"
34
35 #include <QColor>
36 #include <QColorDialog>
37 #include <QLinearGradient>
38 #include <QListWidgetItem>
39 #include <QPalette>
40 #include <map>
41 #include <string>
42
43 #include "db.h"
44 #include "gui/gui.h"
45
46 namespace gui {
47
48 CongestionSetupDialog::ColorRangeMap CongestionSetupDialog::_color_ranges
49 = {{2, {CongestionBandInfo("blue", "0"), CongestionBandInfo("red", "1")}},
50 {3,
51 {CongestionBandInfo("blue", "0"),
52 CongestionBandInfo("yellow", "0.5"),
53 CongestionBandInfo("red", "1")}},
54 {4,
55 {CongestionBandInfo("blue", "0"),
56 CongestionBandInfo("green", "0.33"),
57 CongestionBandInfo("yellow", "0.66"),
58 CongestionBandInfo("red", "1")}},
59 {5,
60 {CongestionBandInfo("blue", "0"),
61 CongestionBandInfo("cyan", "0.25"),
62 CongestionBandInfo("green", "0.5"),
63 CongestionBandInfo("yellow", "0.75"),
64 CongestionBandInfo("red", "1")}}};
65
CongestionSetupDialog(QWidget * parent)66 CongestionSetupDialog::CongestionSetupDialog(QWidget* parent) : QDialog(parent)
67 {
68 setupUi(this);
69 std::vector<QString> labels = getColorNames(2);
70 QListWidgetItem* lower_bound_item = new QListWidgetItem(labels[0]);
71 lower_bound_item->setBackground(QBrush(Qt::blue));
72 QListWidgetItem* upper_bound_item = new QListWidgetItem(labels[1]);
73 upper_bound_item->setBackground(QBrush(Qt::red));
74 colorRangeListWidget->clear();
75 colorRangeListWidget->addItem(lower_bound_item);
76 colorRangeListWidget->addItem(upper_bound_item);
77
78 congestionButton->setStyleSheet(
79 "QPushButton { background-color: qlineargradient(x1:0 y1:0, x2:1 y2:0, "
80 "stop:0 blue, stop:1 red); }");
81
82 colorRangeListWidget->setStyleSheet(
83 "QListView::item:selected {background : none; border: solid 2px "
84 "red;}");
85
86 colorRangeListWidget->setSelectionMode(QAbstractItemView::NoSelection);
87
88 connect(colorRangeListWidget,
89 SIGNAL(itemDoubleClicked(QListWidgetItem*)),
90 this,
91 SLOT(colorIntervalItemDblClicked(QListWidgetItem*)));
92
93 connect(spinBox,
94 SIGNAL(valueChanged(int)),
95 this,
96 SLOT(colorIntervalChanged(int)));
97 connect(startCongestionSpinBox,
98 SIGNAL(valueChanged(int)),
99 this,
100 SLOT(congestionBandChanged(int)));
101 connect(endCongestionSpinBox,
102 SIGNAL(valueChanged(int)),
103 this,
104 SLOT(congestionBandChanged(int)));
105 connect(applyButton, SIGNAL(pressed()), this, SLOT(saveState()));
106 connect(
107 applyButton, SIGNAL(clicked()), this, SIGNAL(applyCongestionRequested()));
108 min_congestion_ = startCongestionSpinBox->value();
109 max_congestion_ = endCongestionSpinBox->value();
110
111 cong_dir_index_ = BOTH_DIR;
112
113 colors_.push_back(_color_ranges[2][0].band_color_);
114 colors_.push_back(_color_ranges[2][1].band_color_);
115 }
116
saveState()117 void CongestionSetupDialog::saveState()
118 {
119 // Update the dialog state
120 min_congestion_ = startCongestionSpinBox->value();
121 max_congestion_ = endCongestionSpinBox->value();
122 colors_.clear();
123 int row = 0;
124 while (row < colorRangeListWidget->count()) {
125 colors_.push_back(colorRangeListWidget->item(row++)->background().color());
126 }
127 cong_dir_index_ = BOTH_DIR;
128 if (horCongDir->isChecked())
129 cong_dir_index_ = HORIZONTAL_DIR;
130 else if (verCongDir->isChecked())
131 cong_dir_index_ = VERTICAL_DIR;
132 }
133
accept()134 void CongestionSetupDialog::accept()
135 {
136 saveState();
137 QDialog::accept();
138 emit congestionSetupChanged();
139 }
140
reject()141 void CongestionSetupDialog::reject()
142 {
143 // reset the dialog state
144 startCongestionSpinBox->setValue(min_congestion_);
145 endCongestionSpinBox->setValue(max_congestion_);
146 int row = 0;
147 spinBox->setValue(colors_.size());
148 std::string color_sheet_value;
149 colorRangeListWidget->clear();
150 std::vector<QString> color_labels = getColorNames(spinBox->value());
151
152 for (auto& color_data : _color_ranges[spinBox->value()]) {
153 QListWidgetItem* item = new QListWidgetItem(color_labels[row]);
154 item->setBackground(QBrush(colors_[row]));
155 colorRangeListWidget->addItem(item);
156 color_sheet_value = color_sheet_value
157 + "stop:" + color_data.color_style_sheet_ + " "
158 + colors_[row++].name().toStdString() + ", ";
159 }
160
161 color_sheet_value = color_sheet_value.substr(0, color_sheet_value.size() - 2);
162 updateCongestionButtonStyleSheet(color_sheet_value);
163
164 if (cong_dir_index_ == BOTH_DIR) {
165 bothCongDir->setChecked(true);
166 horCongDir->setChecked(false);
167 verCongDir->setChecked(false);
168 } else if (cong_dir_index_ == HORIZONTAL_DIR) {
169 bothCongDir->setChecked(false);
170 horCongDir->setChecked(true);
171 verCongDir->setChecked(false);
172 } else {
173 bothCongDir->setChecked(false);
174 horCongDir->setChecked(false);
175 verCongDir->setChecked(true);
176 }
177 QDialog::reject();
178 }
179
updateCongestionButtonStyleSheet(const std::string & color_values)180 void CongestionSetupDialog::updateCongestionButtonStyleSheet(
181 const std::string& color_values)
182 {
183 std::string new_style_sheet(
184 "QPushButton { background-color: qlineargradient(x1:0 y1:0, x2:1 y2:0, ");
185 new_style_sheet += color_values;
186 new_style_sheet += "); }";
187 congestionButton->setStyleSheet(new_style_sheet.c_str());
188 }
189
colorIntervalChanged(int value)190 void CongestionSetupDialog::colorIntervalChanged(int value)
191 {
192 std::string color_sheet_value;
193 colorRangeListWidget->clear();
194 std::vector<QString> color_labels = getColorNames(value);
195 int row = 0;
196 for (auto& color_data : CongestionSetupDialog::_color_ranges[value]) {
197 QListWidgetItem* item = new QListWidgetItem(color_labels[row++]);
198 item->setBackground(QBrush(color_data.band_color_));
199 colorRangeListWidget->addItem(item);
200 color_sheet_value = color_sheet_value
201 + "stop:" + color_data.color_style_sheet_ + " "
202 + color_data.band_color_.name().toStdString() + ", ";
203 }
204
205 color_sheet_value = color_sheet_value.substr(0, color_sheet_value.size() - 2);
206 updateCongestionButtonStyleSheet(color_sheet_value);
207 }
208
congestionBandChanged(int value)209 void CongestionSetupDialog::congestionBandChanged(int value)
210 {
211 std::vector<QString> color_labels = getColorNames(spinBox->value());
212 int row = 0;
213 for (auto& color_label : color_labels) {
214 QListWidgetItem* item = colorRangeListWidget->item(row++);
215 item->setText(color_label);
216 }
217 }
218
colorIntervalItemDblClicked(QListWidgetItem * item)219 void CongestionSetupDialog::colorIntervalItemDblClicked(QListWidgetItem* item)
220 {
221 auto prev_color = item->background().color();
222 QColor new_color = QColorDialog::getColor(prev_color, this);
223 if (new_color.isValid()) {
224 item->setBackground(QBrush(new_color));
225 std::string color_sheet_value;
226 int row = 0;
227 for (auto& color_data :
228 CongestionSetupDialog::_color_ranges[spinBox->value()]) {
229 QListWidgetItem* item = colorRangeListWidget->item(row++);
230 color_sheet_value
231 = color_sheet_value + "stop:" + color_data.color_style_sheet_ + " "
232 + item->background().color().name().toStdString() + ", ";
233 }
234
235 color_sheet_value
236 = color_sheet_value.substr(0, color_sheet_value.size() - 2);
237 updateCongestionButtonStyleSheet(color_sheet_value);
238 }
239 return;
240 }
241
getCongestionButtonStyleSheetColors()242 std::string CongestionSetupDialog::getCongestionButtonStyleSheetColors()
243 {
244 std::string color_sheet_value;
245 int value = spinBox->value();
246 int row = 0;
247 for (auto& color_data : CongestionSetupDialog::_color_ranges[value]) {
248 QListWidgetItem* item = colorRangeListWidget->item(row++);
249 color_sheet_value = color_sheet_value
250 + "stop:" + color_data.band_color_.name().toStdString()
251 + " " + item->background().color().name().toStdString()
252 + ", ";
253 }
254
255 color_sheet_value = color_sheet_value.substr(0, color_sheet_value.size() - 2);
256 return color_sheet_value;
257 }
258
getColorNames(int band_index)259 std::vector<QString> CongestionSetupDialog::getColorNames(int band_index)
260 {
261 std::vector<QString> labels;
262 QString label;
263 auto color_data = _color_ranges[band_index];
264 unsigned int index = 0;
265 int min_congestion = getMinCongestionValue();
266 int max_congestion = getMaxCongestionValue();
267 int percent_step = (max_congestion - min_congestion) / spinBox->value();
268 while (index < color_data.size() - 1) {
269 label = QString::number(min_congestion + percent_step * index)
270 + "% <= Usage < "
271 + QString::number(min_congestion + percent_step * (index + 1))
272 + "%";
273 labels.push_back(label);
274 ++index;
275 }
276 label = QString("Usage >= ")
277 + QString::number(min_congestion + percent_step * (index + 1)) + "%";
278 labels.push_back(label);
279 return labels;
280 }
281
getCongestionColorForPercentage(float congestion_percent,int alpha) const282 QColor CongestionSetupDialog::getCongestionColorForPercentage(
283 float congestion_percent,
284 int alpha) const
285 {
286 auto& color_data_vec = _color_ranges[colors_.size()];
287 int min_congestion = getMinCongestionValue();
288 int max_congestion = getMaxCongestionValue();
289 if (congestion_percent >= max_congestion)
290 return color_data_vec.rbegin()->band_color_;
291
292 int index = 0;
293 int step = (max_congestion - min_congestion) / spinBox->value();
294 while (index < colors_.size()) {
295 if (congestion_percent <= (min_congestion + step * index))
296 break;
297 ++index;
298 }
299
300 QColor min_color = colors_[index - 1];
301 QColor max_color = colors_[index];
302
303 int band_llimit = min_congestion + (step * (index - 1));
304 int band_ulimit = min_congestion + (step * index);
305
306 float band_percent
307 = (congestion_percent - band_llimit) / (band_ulimit - band_llimit);
308
309 int red_val = std::min(
310 255,
311 min_color.red()
312 + std::abs(int(band_percent * (max_color.red() - min_color.red()))));
313 int green_val = std::min(
314 255,
315 min_color.green()
316 + std::abs(
317 int(band_percent * (max_color.green() - min_color.green()))));
318 int blue_val
319 = std::min(255,
320 min_color.blue()
321 + std::abs(int(band_percent
322 * (max_color.blue() - min_color.blue()))));
323 QColor congestion_color;
324
325 congestion_color.setRed(red_val);
326 congestion_color.setGreen(green_val);
327 congestion_color.setBlue(blue_val);
328
329 congestion_color.setAlpha(alpha);
330
331 return congestion_color;
332 }
333
334 } // namespace gui
335