OpenCores
URL https://opencores.org/ocsvn/riscv_vhdl/riscv_vhdl/trunk

Subversion Repositories riscv_vhdl

[/] [riscv_vhdl/] [trunk/] [debugger/] [src/] [gui_plugin/] [GnssWidgets/] [PlotWidget.cpp] - Blame information for rev 5

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 5 sergeykhbr
/**
2
 * @file
3
 * @copyright  Copyright 2017 GNSS Sensor Ltd. All right reserved.
4
 * @author     Sergey Khabarov - sergeykhbr@gmail.com
5
 * @brief      Generic Plot drawer widget.
6
 */
7
 
8
#include <math.h>
9
#include "PlotWidget.h"
10
#include "moc_PlotWidget.h"
11
 
12
namespace debugger {
13
 
14
static const int MARGIN = 5;
15
static const char *PLOTS_COLORS[LINES_PER_PLOT_MAX] = {
16
    "#007ACC",      // nice blue color (msvc)
17
    "#40C977",      // green/blue color
18
    "#CA5100",      // nice orange color (msvc)
19
    "#BD63C5",      // violet
20
    "#FFFFFF",      // white color
21
    "#FFFFFF",      // white color
22
    "#FFFFFF",      // white color
23
    "#FFFFFF"       // white color
24
};
25
 
26
PlotWidget::PlotWidget(IGui *igui, QWidget *parent)
27
    : QWidget(parent) {
28
    igui_ = igui;
29
    selectedEpoch = 0;
30
    epochStart = 0;
31
    epochTotal = 0;
32
    lineTotal = 0;
33
    trackLineIdx = 0;
34
    pressed = Qt::NoButton;
35
    waitingResp_ = false;
36
 
37
    setFocusPolicy(Qt::ClickFocus);
38
 
39
    contextMenu = new QMenu(this);
40
    contextMenu->addAction(
41
        tr("Clear zoom"), this, SLOT(slotActionZoomClear()));
42
 
43
    setContextMenuPolicy(Qt::CustomContextMenu);
44
    connect(this, SIGNAL(customContextMenuRequested(const QPoint &)),
45
                  SLOT(slotRightClickMenu(const QPoint &)));
46
 
47
    connect(this, SIGNAL(signalCmdResponse()), SLOT(slotCmdResponse()));
48
 
49
    bkg1 = QColor(Qt::black);
50
    cmd_.make_string("cpi");
51
    groupName = QString("NoGroupName");
52
    groupUnits = QString("clocks");
53
    defaultLineCfg.from_config("{"
54
        "'Name':'NoName',"
55
        "'Format':'%.1f',"
56
        "'RingLength':256,"
57
        "'Color':'#FFFFFF',"
58
        "'FixedMinY':true,"
59
        "'FixedMinYVal':0.0,"
60
        "'FixedMaxY':false,"
61
        "'FixedMaxYVal':0.0}");
62
}
63
 
64
CpiPlot::CpiPlot(IGui *igui, QWidget *parent) : PlotWidget(igui, parent) {
65
    cmd_.make_string("cpi");
66
    groupName = QString("CPI");
67
    groupUnits = QString("clocks");
68
 
69
    defaultLineCfg["Color"].make_string(PLOTS_COLORS[0]);
70
    defaultLineCfg["Name"].make_string("CPI");
71
    defaultLineCfg["Format"].make_string("%.2f");
72
    line_[0] = new LineCommon(defaultLineCfg);
73
    lineTotal = 1;
74
}
75
 
76
BusUtilPlot::BusUtilPlot(IGui *igui, QWidget *parent)
77
    : PlotWidget(igui, parent) {
78
    cmd_.make_string("busutil");
79
    groupName = QString("Bus Utilization");
80
    groupUnits = QString("percentage");
81
 
82
    defaultLineCfg["FixedMaxY"].make_boolean(true);
83
    defaultLineCfg["FixedMaxYVal"].make_floating(100.0);
84
}
85
 
86
 
87
PlotWidget::~PlotWidget() {
88
    for (int i = 0; i < lineTotal; i++) {
89
        delete line_[i];
90
    }
91
}
92
 
93
void PlotWidget::handleResponse(AttributeType *req,
94
                                AttributeType *resp) {
95
    response_ = *resp;
96
    emit signalCmdResponse();
97
    waitingResp_ = false;
98
}
99
 
100
void CpiPlot::slotCmdResponse() {
101
    if (!response_.is_list() || response_.size() != 5) {
102
        return;
103
    }
104
    line_[0]->append(response_[4].to_float());
105
    epochTotal = line_[0]->size();
106
    update();
107
}
108
 
109
void BusUtilPlot::slotCmdResponse() {
110
    if (!response_.is_list()) {
111
        return;
112
    }
113
    int mst_total = static_cast<int>(response_.size());
114
    if (lineTotal < mst_total) {
115
        char tstr[64];
116
        for (int i = lineTotal; i < mst_total; i++) {
117
            RISCV_sprintf(tstr, sizeof(tstr), "mst[%d]", i);
118
            defaultLineCfg["Name"].make_string(tstr);
119
            defaultLineCfg["Color"].make_string(PLOTS_COLORS[i]);
120
            line_[i] = new LineCommon(defaultLineCfg);
121
            line_[i]->setPlotSize(rectPlot.width(), rectPlot.height());
122
        }
123
        lineTotal = mst_total;
124
    }
125
    double wr, rd;
126
    for (int i = 0; i < mst_total; i++) {
127
        const AttributeType &mst = response_[i];
128
        if (!mst.is_list() || mst.size() != 2) {
129
            continue;
130
        }
131
        wr = mst[0u].to_float();
132
        rd = mst[1].to_float();
133
        line_[i]->append(wr + rd);
134
    }
135
    epochTotal = line_[0]->size();
136
    update();
137
}
138
 
139
void PlotWidget::slotUpdateByTimer() {
140
    if (waitingResp_ || pressed) {
141
        return;
142
    }
143
    igui_->registerCommand(static_cast<IGuiCmdHandler *>(this),
144
                            &cmd_, true);
145
    waitingResp_ = true;
146
}
147
 
148
void PlotWidget::renderAll() {
149
    pixmap.fill(bkg1);
150
    QPainter p(&pixmap);
151
 
152
    renderAxis(p);
153
 
154
    p.translate(rectPlot.topLeft());
155
    for (int lineIdx = 0; lineIdx < lineTotal; lineIdx++) {
156
        renderLine(p, line_[lineIdx]);
157
    }
158
 
159
    renderMarker(p);
160
    renderInfoPanel(p);
161
 
162
    p.translate(-rectPlot.topLeft());
163
    renderSelection(p);
164
 
165
    p.end();
166
}
167
 
168
void PlotWidget::renderAxis(QPainter &p) {
169
    p.setRenderHint(QPainter::Antialiasing, true);
170
 
171
    p.setPen(QPen(QColor(0x48,0x3D,0x8B)));  // Color Dark State Blue: #483D8B
172
    p.drawLine(rectPlot.bottomLeft(), rectPlot.bottomRight());
173
    p.drawLine(rectPlot.bottomLeft(), rectPlot.topLeft());
174
 
175
    /** Draw Group name: */
176
    QSize groupTextSize = p.fontMetrics().size(Qt::TextDontClip, groupName);
177
    QPoint groupTextPos = QPoint((width() - groupTextSize.width())/2, 0);
178
    QRect groupTextRect = QRect(groupTextPos, groupTextSize);
179
    p.setPen(QPen(QColor("#BFBFBF")));
180
    p.drawText(groupTextRect, Qt::AlignLeft, groupName);
181
 
182
    /** Draw Y-axis units: */
183
    p.rotate(-90.0);
184
    groupTextSize = p.fontMetrics().size(Qt::TextDontClip, groupUnits);
185
    groupTextPos = QPoint(-(height() + groupTextSize.width())/2, 2);
186
    groupTextRect = QRect(groupTextPos, groupTextSize);
187
    p.drawText(groupTextRect, Qt::AlignLeft, groupUnits);
188
    p.rotate(90.0);
189
}
190
 
191
void PlotWidget::renderLine(QPainter &p, LineCommon *pline) {
192
    bool draw_line = false;
193
    int x, y;
194
    QPoint ptA, ptB;
195
    QRect box(0, 0, 4, 4);
196
    p.setPen(QColor(pline->getColor()));
197
    pline->selectData(epochStart, epochTotal);
198
    for (int i = epochStart; i < epochStart + epochTotal; i++) {
199
        if (!pline->getNext(x, y)) {
200
            draw_line = false;
201
            continue;
202
        }
203
        box.moveTo(x - 2, y - 2);
204
        p.drawRect(box);
205
 
206
        if (!draw_line) {
207
            draw_line = true;
208
            ptA = QPoint(x, y);
209
        } else {
210
            ptB = QPoint(x, y);
211
            p.drawLine(ptA, ptB);
212
            ptA = ptB;
213
        }
214
    }
215
}
216
 
217
void PlotWidget::renderMarker(QPainter &p) {
218
    if (!lineTotal) {
219
        return;
220
    }
221
    LineCommon *pline = line_[trackLineIdx];
222
    int x, y;
223
    p.setPen(Qt::red);
224
    QRect box(0, 0, 6, 6);
225
    if (pline->getXY(selectedEpoch, x, y)) {
226
        /**
227
            Vertial Marker line:
228
        */
229
        p.setPen(QPen(QColor(0xff, 0, 0, 0xa0)));
230
        QPoint ptA(x, 0);
231
        QPoint ptB(x, rectPlot.height());
232
        p.drawLine(ptA, ptB);
233
 
234
        // Marker box
235
        box.moveTo(x - 3, y - 3);
236
        p.drawRect(box);
237
    }
238
}
239
 
240
void PlotWidget::renderSelection(QPainter &p) {
241
    /**
242
        Highlight selection when mouse pressed
243
    */
244
    if (pressed == Qt::MiddleButton) {
245
        p.setCompositionMode(QPainter::CompositionMode_Difference);
246
        QRect rect(QPoint(pressStart.x(), rectPlot.top()),
247
                   QPoint(pressEnd.x(), rectPlot.bottom()));
248
        p.fillRect(rect, Qt::white);
249
    }
250
}
251
 
252
void PlotWidget::renderInfoPanel(QPainter &p) {
253
    char bufName[256];
254
    QFont fontPos;
255
    // Save previous values:
256
    QBrush oldBrush = p.brush();
257
    QPen oldPen = p.pen();
258
    QFont oldFont = p.font();
259
 
260
    fontPos.setPixelSize(10);
261
    p.setFont(fontPos);
262
 
263
    QSize infoNameSize;
264
    QString name;
265
    QString fullString;
266
    fullString.sprintf("idx: %d\n", selectedEpoch);
267
 
268
    // Find the longest 'name : value' string among lines:
269
    int NAME_WIDTH_MAX = rectPlot.width() / 2;
270
    for (int i = 0; i < lineTotal; i++) {
271
        LineCommon *pLine = line_[i];
272
        if (!pLine->getAxisValue(1, selectedEpoch, bufName, sizeof(bufName))) {
273
            continue;
274
        }
275
        name.sprintf("%s: %s\n", pLine->getName(), bufName);
276
        fullString += name;
277
    }
278
    infoNameSize = p.fontMetrics().size(Qt::TextDontClip, fullString);
279
    /** Guard: to avoid wrong formatted string value */
280
    if (infoNameSize.width() > NAME_WIDTH_MAX) {
281
        infoNameSize.setWidth(NAME_WIDTH_MAX);
282
    }
283
 
284
    QPoint posPanel(rectPlot.width() - infoNameSize.width() - 5, 5);
285
 
286
    p.setPen(QPen(QColor("#450020")));
287
    p.setBrush(QBrush(QColor(0xff, 0xef, 0xd5, 0x80)));
288
 
289
    QRect rectPanel(posPanel, infoNameSize);
290
    QRect textPanel = rectPanel;
291
    rectPanel.setWidth(rectPanel.width() + 4);
292
    rectPanel.setLeft(rectPanel.left() - 2);
293
    p.drawRoundedRect(rectPanel, 2, 2);
294
    p.drawText(textPanel, Qt::AlignLeft, fullString);
295
 
296
    // Restore:
297
    p.setBrush(oldBrush);
298
    p.setPen(oldPen);
299
    p.setFont(oldFont);
300
}
301
 
302
int PlotWidget::pix2epoch(QPoint pix) {
303
    pix -= rectPlot.topLeft();
304
    if (pix.x() > rectPlot.width()) {
305
        pix.setX(rectPlot.width());
306
    }
307
    return line_[trackLineIdx]->getNearestByX(pix.x());
308
}
309
 
310
void PlotWidget::resizeEvent(QResizeEvent *ev) {
311
    int w = ev->size().width();
312
    int h = ev->size().height();
313
    if (w == 0 || h == 0) {
314
        return;
315
    }
316
    QSize pixmapSingleSize = QSize(w, h);
317
    rectMargined.setTopLeft(QPoint(MARGIN, MARGIN));
318
    rectMargined.setBottomRight(QPoint(w - MARGIN, h - MARGIN));
319
 
320
    QFontMetrics fm(font());
321
    int font_h = fm.height() + 4;
322
    rectPlot = rectMargined;
323
    rectPlot.setLeft(rectMargined.left() + font_h);
324
    rectPlot.setTop(rectMargined.top() + font_h);
325
    for (int i = 0; i < lineTotal; i++) {
326
        line_[i]->setPlotSize(rectPlot.width(), rectPlot.height());
327
    }
328
 
329
    pixmap = QPixmap(pixmapSingleSize);
330
}
331
 
332
void PlotWidget::paintEvent(QPaintEvent *event) {
333
    renderAll();
334
 
335
    QPainter p(this);
336
    QPoint pos(0,0);
337
    p.drawPixmap(pos, pixmap);
338
    p.end();
339
}
340
 
341
void PlotWidget::mousePressEvent(QMouseEvent *event) {
342
    setFocus();
343
    /** There're 2 methods: buttons() and button():
344
        buttons() is a multiple flag of button()
345
    */
346
    pressed = event->button();
347
    if (pressed != Qt::LeftButton && pressed != Qt::MiddleButton) {
348
        pressed = Qt::NoButton;
349
        return;
350
    }
351
 
352
    selectedEpoch = pix2epoch(event->pos());
353
    pressStart = event->pos();
354
}
355
 
356
void PlotWidget::mouseMoveEvent(QMouseEvent *event) {
357
    if (!event->buttons()) {
358
        return;
359
    }
360
 
361
    if (pressed != Qt::NoButton) {
362
        selectedEpoch = pix2epoch(event->pos());
363
        pressEnd = event->pos();
364
        update();
365
    }
366
}
367
 
368
void PlotWidget::mouseReleaseEvent(QMouseEvent *) {
369
    if (pressed == Qt::MiddleButton) {
370
        /** Warning: changing of epochStart before epochEnd computed
371
         *  will raise an errors
372
         */
373
        int tmpStart = pix2epoch(pressStart);
374
        int tmpEnd = pix2epoch(pressEnd);
375
        if (tmpStart < tmpEnd) {
376
            epochStart = tmpStart;
377
            epochTotal = tmpEnd - epochStart + 1;
378
        } else if (tmpStart > tmpEnd) {
379
            epochStart = tmpEnd;
380
            epochTotal = tmpStart - epochStart + 1;
381
        }
382
    }
383
    pressed = Qt::NoButton;
384
    update();
385
}
386
 
387
void PlotWidget::keyPressEvent(QKeyEvent *event) {
388
    switch (event->key()) {
389
    case Qt::Key_Left:
390
        if (selectedEpoch > epochStart) {
391
            selectedEpoch--;
392
            update();
393
        }
394
        break;
395
    case Qt::Key_Right:
396
        if (selectedEpoch < (epochStart + epochTotal) - 1) {
397
            selectedEpoch++;
398
            update();
399
        }
400
        break;
401
    default:;
402
    }
403
}
404
 
405
 
406
void PlotWidget::slotRightClickMenu(const QPoint &p) {
407
    QPoint globalPos = mapToGlobal(p);
408
    contextMenu->popup(globalPos);
409
}
410
 
411
void PlotWidget::slotActionZoomClear() {
412
    epochStart = 0;
413
    epochTotal = line_[trackLineIdx]->size();
414
    update();
415
}
416
 
417
 
418
double PlotWidget::borderUpValue(double v) {
419
    double tmp;
420
    if (v == 0) {
421
        return 0;
422
    }
423
 
424
    //double border = 1.0;
425
    double x10 = 1.0;
426
    if (v > 1.0) {
427
        tmp = v;
428
        while (tmp > 1.0) {
429
            tmp /= 10.0;
430
            x10 *= 10.0;
431
        }
432
        tmp *= 10.0;
433
        tmp = (double)((int)tmp + 1);
434
        x10 *= tmp;
435
 
436
    } else if (v < 1.0) {
437
    }
438
    return 0.0;
439
}
440
 
441
}  // namespace debugger

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.