forked from qt-creator/qt-creator
QmlProfiler: display binding loops
Change-Id: Ib553f67b25e614bd210959ce82bc970daa228fdb Reviewed-by: Kai Koehne <kai.koehne@nokia.com>
This commit is contained in:
@@ -71,6 +71,7 @@ QmlEventData::QmlEventData()
|
|||||||
timePerCall = 0;
|
timePerCall = 0;
|
||||||
percentOfTime = 0;
|
percentOfTime = 0;
|
||||||
medianTime = 0;
|
medianTime = 0;
|
||||||
|
isBindingLoop = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QmlEventData::~QmlEventData()
|
QmlEventData::~QmlEventData()
|
||||||
@@ -99,6 +100,7 @@ QmlEventData &QmlEventData::operator=(const QmlEventData &ref)
|
|||||||
percentOfTime = ref.percentOfTime;
|
percentOfTime = ref.percentOfTime;
|
||||||
medianTime = ref.medianTime;
|
medianTime = ref.medianTime;
|
||||||
eventId = ref.eventId;
|
eventId = ref.eventId;
|
||||||
|
isBindingLoop = ref.isBindingLoop;
|
||||||
|
|
||||||
qDeleteAll(parentHash.values());
|
qDeleteAll(parentHash.values());
|
||||||
parentHash.clear();
|
parentHash.clear();
|
||||||
@@ -182,6 +184,8 @@ struct QmlEventStartTimeData {
|
|||||||
// animation-related data
|
// animation-related data
|
||||||
int frameRate;
|
int frameRate;
|
||||||
int animationCount;
|
int animationCount;
|
||||||
|
|
||||||
|
int bindingLoopHead;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct QmlEventTypeCount {
|
struct QmlEventTypeCount {
|
||||||
@@ -790,6 +794,9 @@ void QmlProfilerEventList::compileStatistics(qint64 startTime, qint64 endTime)
|
|||||||
iter.key()->medianTime = iter.value().at(iter.value().count()/2);
|
iter.key()->medianTime = iter.value().at(iter.value().count()/2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// find binding loops
|
||||||
|
findBindingLoops(startTime, endTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlProfilerEventList::prepareForDisplay()
|
void QmlProfilerEventList::prepareForDisplay()
|
||||||
@@ -1063,6 +1070,59 @@ void QmlProfilerEventList::finishedRewritingDetails()
|
|||||||
emit reloadDetailLabels();
|
emit reloadDetailLabels();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QmlProfilerEventList::findBindingLoops(qint64 startTime, qint64 endTime)
|
||||||
|
{
|
||||||
|
// first clear existing data
|
||||||
|
foreach (QmlEventData *event, d->m_eventDescriptions.values()) {
|
||||||
|
event->isBindingLoop = false;
|
||||||
|
foreach (QmlEventSub *parentEvent, event->parentHash.values())
|
||||||
|
parentEvent->inLoopPath = false;
|
||||||
|
foreach (QmlEventSub *childEvent, event->childrenHash.values())
|
||||||
|
childEvent->inLoopPath = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList <QmlEventData *> stackRefs;
|
||||||
|
QList <QmlEventStartTimeData *> stack;
|
||||||
|
int fromIndex = findFirstIndex(startTime);
|
||||||
|
int toIndex = findLastIndex(endTime);
|
||||||
|
|
||||||
|
for (int i = 0; i < d->m_startTimeSortedList.count(); i++) {
|
||||||
|
QmlEventData *currentEvent = d->m_startTimeSortedList[i].description;
|
||||||
|
QmlEventStartTimeData *inTimeEvent = &d->m_startTimeSortedList[i];
|
||||||
|
inTimeEvent->bindingLoopHead = -1;
|
||||||
|
|
||||||
|
// managing call stack
|
||||||
|
for (int j = stack.count() - 1; j >= 0; j--) {
|
||||||
|
if (stack[j]->startTime + stack[j]->length < inTimeEvent->startTime) {
|
||||||
|
stack.removeAt(j);
|
||||||
|
stackRefs.removeAt(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool loopDetected = stackRefs.contains(currentEvent);
|
||||||
|
stack << inTimeEvent;
|
||||||
|
stackRefs << currentEvent;
|
||||||
|
|
||||||
|
if (loopDetected) {
|
||||||
|
if (i >= fromIndex && i <= toIndex) {
|
||||||
|
// for the statistics
|
||||||
|
currentEvent->isBindingLoop = true;
|
||||||
|
for (int j = stackRefs.indexOf(currentEvent); j < stackRefs.count()-1; j++) {
|
||||||
|
QmlEventSub *nextEventSub = stackRefs[j]->childrenHash.value(stackRefs[j+1]->eventHashStr);
|
||||||
|
nextEventSub->inLoopPath = true;
|
||||||
|
QmlEventSub *prevEventSub = stackRefs[j+1]->parentHash.value(stackRefs[j]->eventHashStr);
|
||||||
|
prevEventSub->inLoopPath = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// use crossed references to find index in starttimesortedlist
|
||||||
|
QmlEventStartTimeData *head = stack[stackRefs.indexOf(currentEvent)];
|
||||||
|
inTimeEvent->bindingLoopHead = d->m_endTimeSortedList[head->endTimeIndex].startTimeIndex;
|
||||||
|
d->m_startTimeSortedList[inTimeEvent->bindingLoopHead].bindingLoopHead = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// get list of events between A and B:
|
// get list of events between A and B:
|
||||||
// find fist event with endtime after A -> aa
|
// find fist event with endtime after A -> aa
|
||||||
// find last event with starttime before B -> bb
|
// find last event with starttime before B -> bb
|
||||||
@@ -1689,10 +1749,16 @@ QString QmlProfilerEventList::getDetails(int index) const
|
|||||||
return d->m_startTimeSortedList[index].description->details;
|
return d->m_startTimeSortedList[index].description->details;
|
||||||
}
|
}
|
||||||
|
|
||||||
int QmlProfilerEventList::getEventId(int index) const {
|
int QmlProfilerEventList::getEventId(int index) const
|
||||||
|
{
|
||||||
return d->m_startTimeSortedList[index].description->eventId;
|
return d->m_startTimeSortedList[index].description->eventId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int QmlProfilerEventList::getBindingLoopDest(int index) const
|
||||||
|
{
|
||||||
|
return d->m_startTimeSortedList[index].bindingLoopHead;
|
||||||
|
}
|
||||||
|
|
||||||
int QmlProfilerEventList::getFramerate(int index) const
|
int QmlProfilerEventList::getFramerate(int index) const
|
||||||
{
|
{
|
||||||
return d->m_startTimeSortedList[index].frameRate;
|
return d->m_startTimeSortedList[index].frameRate;
|
||||||
|
|||||||
@@ -65,16 +65,18 @@ struct QMLJSDEBUGCLIENT_EXPORT QmlEventData
|
|||||||
double percentOfTime;
|
double percentOfTime;
|
||||||
qint64 medianTime;
|
qint64 medianTime;
|
||||||
int eventId;
|
int eventId;
|
||||||
|
bool isBindingLoop;
|
||||||
|
|
||||||
QmlEventData &operator=(const QmlEventData &ref);
|
QmlEventData &operator=(const QmlEventData &ref);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct QMLJSDEBUGCLIENT_EXPORT QmlEventSub {
|
struct QMLJSDEBUGCLIENT_EXPORT QmlEventSub {
|
||||||
QmlEventSub(QmlEventData *from) : reference(from), duration(0), calls(0) {}
|
QmlEventSub(QmlEventData *from) : reference(from), duration(0), calls(0), inLoopPath(false) {}
|
||||||
QmlEventSub(QmlEventSub *from) : reference(from->reference), duration(from->duration), calls(from->calls) {}
|
QmlEventSub(QmlEventSub *from) : reference(from->reference), duration(from->duration), calls(from->calls), inLoopPath(from->inLoopPath) {}
|
||||||
QmlEventData *reference;
|
QmlEventData *reference;
|
||||||
qint64 duration;
|
qint64 duration;
|
||||||
qint64 calls;
|
qint64 calls;
|
||||||
|
bool inLoopPath;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct QMLJSDEBUGCLIENT_EXPORT QV8EventData
|
struct QMLJSDEBUGCLIENT_EXPORT QV8EventData
|
||||||
@@ -142,11 +144,13 @@ public:
|
|||||||
Q_INVOKABLE int getColumn(int index) const;
|
Q_INVOKABLE int getColumn(int index) const;
|
||||||
Q_INVOKABLE QString getDetails(int index) const;
|
Q_INVOKABLE QString getDetails(int index) const;
|
||||||
Q_INVOKABLE int getEventId(int index) const;
|
Q_INVOKABLE int getEventId(int index) const;
|
||||||
|
Q_INVOKABLE int getBindingLoopDest(int index) const;
|
||||||
Q_INVOKABLE int getFramerate(int index) const;
|
Q_INVOKABLE int getFramerate(int index) const;
|
||||||
Q_INVOKABLE int getAnimationCount(int index) const;
|
Q_INVOKABLE int getAnimationCount(int index) const;
|
||||||
Q_INVOKABLE int getMaximumAnimationCount() const;
|
Q_INVOKABLE int getMaximumAnimationCount() const;
|
||||||
Q_INVOKABLE int getMinimumAnimationCount() const;
|
Q_INVOKABLE int getMinimumAnimationCount() const;
|
||||||
|
|
||||||
|
|
||||||
// per-type data
|
// per-type data
|
||||||
Q_INVOKABLE int uniqueEventsOfType(int type) const;
|
Q_INVOKABLE int uniqueEventsOfType(int type) const;
|
||||||
Q_INVOKABLE int maxNestingForType(int type) const;
|
Q_INVOKABLE int maxNestingForType(int type) const;
|
||||||
@@ -206,6 +210,8 @@ private:
|
|||||||
void prepareForDisplay();
|
void prepareForDisplay();
|
||||||
void linkEndsToStarts();
|
void linkEndsToStarts();
|
||||||
void reloadDetails();
|
void reloadDetails();
|
||||||
|
void findBindingLoops(qint64 startTime, qint64 endTime);
|
||||||
|
bool checkBindingLoop(QmlEventData *from, QmlEventData *current, QList<QmlEventData *>visited);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class QmlProfilerEventListPrivate;
|
class QmlProfilerEventListPrivate;
|
||||||
|
|||||||
@@ -269,6 +269,7 @@ Rectangle {
|
|||||||
rangeDetails.file = "";
|
rangeDetails.file = "";
|
||||||
rangeDetails.line = -1;
|
rangeDetails.line = -1;
|
||||||
rangeDetails.column = 0;
|
rangeDetails.column = 0;
|
||||||
|
rangeDetails.isBindingLoop = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectNextWithId( eventId )
|
function selectNextWithId( eventId )
|
||||||
@@ -424,6 +425,7 @@ Rectangle {
|
|||||||
rangeDetails.line = qmlEventList.getLine(selectedItem);
|
rangeDetails.line = qmlEventList.getLine(selectedItem);
|
||||||
rangeDetails.column = qmlEventList.getColumn(selectedItem);
|
rangeDetails.column = qmlEventList.getColumn(selectedItem);
|
||||||
rangeDetails.type = root.names[qmlEventList.getType(selectedItem)];
|
rangeDetails.type = root.names[qmlEventList.getType(selectedItem)];
|
||||||
|
rangeDetails.isBindingLoop = qmlEventList.getBindingLoopDest(selectedItem)!==-1;
|
||||||
|
|
||||||
rangeDetails.visible = true;
|
rangeDetails.visible = true;
|
||||||
|
|
||||||
|
|||||||
@@ -95,6 +95,21 @@ function drawData(canvas, ctxt, region)
|
|||||||
highest[ty] = xx+eventWidth;
|
highest[ty] = xx+eventWidth;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// binding loops
|
||||||
|
ctxt.strokeStyle = "orange";
|
||||||
|
ctxt.lineWidth = 2;
|
||||||
|
var radius = 1;
|
||||||
|
for (var ii = 0; ii < qmlEventList.count(); ++ii) {
|
||||||
|
if (qmlEventList.getBindingLoopDest(ii) >= 0) {
|
||||||
|
var xcenter = Math.round(qmlEventList.getStartTime(ii) +
|
||||||
|
qmlEventList.getDuration(ii) -
|
||||||
|
qmlEventList.traceStartTime()) * spacing;
|
||||||
|
var ycenter = Math.round(bump + qmlEventList.getType(ii) * blockHeight + blockHeight/2);
|
||||||
|
ctxt.arc(xcenter, ycenter, radius, 0, 2*Math.PI, true);
|
||||||
|
ctxt.stroke();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawTimeBar(canvas, ctxt, region)
|
function drawTimeBar(canvas, ctxt, region)
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ Item {
|
|||||||
property string file
|
property string file
|
||||||
property int line
|
property int line
|
||||||
property int column
|
property int column
|
||||||
|
property bool isBindingLoop
|
||||||
|
|
||||||
property bool locked: view.selectionLocked
|
property bool locked: view.selectionLocked
|
||||||
|
|
||||||
@@ -153,6 +154,11 @@ Item {
|
|||||||
return (file.length !== 0) ? (file + ":" + rangeDetails.line) : "";
|
return (file.length !== 0) ? (file + ":" + rangeDetails.line) : "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Detail {
|
||||||
|
visible: isBindingLoop
|
||||||
|
opacity: content.length != 0 ? 1 : 0
|
||||||
|
label: qsTr("Binding loop detected")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,6 +54,16 @@ using namespace QmlJsDebugClient;
|
|||||||
namespace QmlProfiler {
|
namespace QmlProfiler {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
|
struct Colors {
|
||||||
|
Colors () {
|
||||||
|
this->bindingLoopBackground = QColor("orange").lighter();
|
||||||
|
}
|
||||||
|
|
||||||
|
QColor bindingLoopBackground;
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_GLOBAL_STATIC(Colors, colors)
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
class EventsViewItem : public QStandardItem
|
class EventsViewItem : public QStandardItem
|
||||||
@@ -531,6 +541,11 @@ void QmlProfilerEventsMainView::QmlProfilerEventsMainViewPrivate::buildModelFrom
|
|||||||
newRow.at(0)->setData(QVariant(binding->location.line),LineRole);
|
newRow.at(0)->setData(QVariant(binding->location.line),LineRole);
|
||||||
newRow.at(0)->setData(QVariant(binding->location.column),ColumnRole);
|
newRow.at(0)->setData(QVariant(binding->location.column),ColumnRole);
|
||||||
newRow.at(0)->setData(QVariant(binding->eventId),EventIdRole);
|
newRow.at(0)->setData(QVariant(binding->eventId),EventIdRole);
|
||||||
|
if (binding->isBindingLoop)
|
||||||
|
foreach (QStandardItem *item, newRow) {
|
||||||
|
item->setBackground(colors()->bindingLoopBackground);
|
||||||
|
item->setToolTip(tr("Binding loop detected"));
|
||||||
|
}
|
||||||
|
|
||||||
// append
|
// append
|
||||||
parentItem->appendRow(newRow);
|
parentItem->appendRow(newRow);
|
||||||
@@ -877,6 +892,11 @@ void QmlProfilerEventsParentsAndChildrenView::rebuildTree(void *eventList)
|
|||||||
newRow.at(0)->setData(QVariant(event->reference->eventId), EventIdRole);
|
newRow.at(0)->setData(QVariant(event->reference->eventId), EventIdRole);
|
||||||
newRow.at(2)->setData(QVariant(event->duration));
|
newRow.at(2)->setData(QVariant(event->duration));
|
||||||
newRow.at(3)->setData(QVariant(event->calls));
|
newRow.at(3)->setData(QVariant(event->calls));
|
||||||
|
if (event->inLoopPath)
|
||||||
|
foreach (QStandardItem *item, newRow) {
|
||||||
|
item->setBackground(colors()->bindingLoopBackground);
|
||||||
|
item->setToolTip(tr("Part of binding loop"));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
QV8EventSub *event = v8List->at(index);
|
QV8EventSub *event = v8List->at(index);
|
||||||
newRow << new EventsViewItem(event->reference->displayName);
|
newRow << new EventsViewItem(event->reference->displayName);
|
||||||
|
|||||||
@@ -107,9 +107,10 @@ void TimelineView::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget
|
|||||||
|
|
||||||
int firstIndex = m_eventList->findFirstIndex(m_startTime);
|
int firstIndex = m_eventList->findFirstIndex(m_startTime);
|
||||||
int lastIndex = m_eventList->findLastIndex(m_endTime);
|
int lastIndex = m_eventList->findLastIndex(m_endTime);
|
||||||
drawItemsToPainter(p, firstIndex, lastIndex);
|
|
||||||
|
|
||||||
drawSelectionBoxes(p);
|
drawItemsToPainter(p, firstIndex, lastIndex);
|
||||||
|
drawSelectionBoxes(p, firstIndex, lastIndex);
|
||||||
|
drawBindingLoopMarkers(p, firstIndex, lastIndex);
|
||||||
|
|
||||||
m_lastStartTime = m_startTime;
|
m_lastStartTime = m_startTime;
|
||||||
m_lastEndTime = m_endTime;
|
m_lastEndTime = m_endTime;
|
||||||
@@ -166,13 +167,11 @@ void TimelineView::drawItemsToPainter(QPainter *p, int fromIndex, int toIndex)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimelineView::drawSelectionBoxes(QPainter *p)
|
void TimelineView::drawSelectionBoxes(QPainter *p, int fromIndex, int toIndex)
|
||||||
{
|
{
|
||||||
if (m_selectedItem == -1)
|
if (m_selectedItem == -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int fromIndex = m_eventList->findFirstIndex(m_startTime);
|
|
||||||
int toIndex = m_eventList->findLastIndex(m_endTime);
|
|
||||||
int id = m_eventList->getEventId(m_selectedItem);
|
int id = m_eventList->getEventId(m_selectedItem);
|
||||||
|
|
||||||
p->setBrush(Qt::transparent);
|
p->setBrush(Qt::transparent);
|
||||||
@@ -216,6 +215,74 @@ void TimelineView::drawSelectionBoxes(QPainter *p)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TimelineView::drawBindingLoopMarkers(QPainter *p, int fromIndex, int toIndex)
|
||||||
|
{
|
||||||
|
int destindex;
|
||||||
|
int xfrom, xto, eventType;
|
||||||
|
int yfrom, yto;
|
||||||
|
int radius = DefaultRowHeight / 3;
|
||||||
|
QPen shadowPen = QPen(QColor("grey"),2);
|
||||||
|
QPen markerPen = QPen(QColor("orange"),2);
|
||||||
|
QBrush shadowBrush = QBrush(QColor("grey"));
|
||||||
|
QBrush markerBrush = QBrush(QColor("orange"));
|
||||||
|
|
||||||
|
p->save();
|
||||||
|
for (int i = fromIndex; i <= toIndex; i++) {
|
||||||
|
destindex = m_eventList->getBindingLoopDest(i);
|
||||||
|
if (destindex >= 0) {
|
||||||
|
// from
|
||||||
|
xfrom = (m_eventList->getStartTime(i) + m_eventList->getDuration(i)/2 -
|
||||||
|
m_startTime) * m_spacing;
|
||||||
|
eventType = m_eventList->getType(i);
|
||||||
|
if (m_rowsExpanded[eventType])
|
||||||
|
yfrom = m_rowStarts[eventType] + DefaultRowHeight*
|
||||||
|
(m_eventList->eventPosInType(i) + 1);
|
||||||
|
else
|
||||||
|
yfrom = m_rowStarts[eventType] + DefaultRowHeight*m_eventList->getNestingLevel(i);
|
||||||
|
|
||||||
|
yfrom += DefaultRowHeight / 2;
|
||||||
|
|
||||||
|
// to
|
||||||
|
xto = (m_eventList->getStartTime(destindex) + m_eventList->getDuration(destindex)/2 -
|
||||||
|
m_startTime) * m_spacing;
|
||||||
|
eventType = m_eventList->getType(destindex);
|
||||||
|
if (m_rowsExpanded[eventType])
|
||||||
|
yto = m_rowStarts[eventType] + DefaultRowHeight*
|
||||||
|
(m_eventList->eventPosInType(destindex) + 1);
|
||||||
|
else
|
||||||
|
yto = m_rowStarts[eventType] + DefaultRowHeight *
|
||||||
|
m_eventList->getNestingLevel(destindex);
|
||||||
|
|
||||||
|
yto += DefaultRowHeight / 2;
|
||||||
|
|
||||||
|
// radius
|
||||||
|
int eventWidth = m_eventList->getDuration(i) * m_spacing;
|
||||||
|
radius = 5;
|
||||||
|
if (radius * 2 > eventWidth)
|
||||||
|
radius = eventWidth / 2;
|
||||||
|
if (radius < 2)
|
||||||
|
radius = 2;
|
||||||
|
|
||||||
|
// shadow
|
||||||
|
int shadowoffset = 2;
|
||||||
|
p->setPen(shadowPen);
|
||||||
|
p->setBrush(shadowBrush);
|
||||||
|
p->drawEllipse(QPoint(xfrom, yfrom + shadowoffset), radius, radius);
|
||||||
|
p->drawEllipse(QPoint(xto, yto + shadowoffset), radius, radius);
|
||||||
|
p->drawLine(QPoint(xfrom, yfrom + shadowoffset), QPoint(xto, yto + shadowoffset));
|
||||||
|
|
||||||
|
|
||||||
|
// marker
|
||||||
|
p->setPen(markerPen);
|
||||||
|
p->setBrush(markerBrush);
|
||||||
|
p->drawEllipse(QPoint(xfrom, yfrom), radius, radius);
|
||||||
|
p->drawEllipse(QPoint(xto, yto), radius, radius);
|
||||||
|
p->drawLine(QPoint(xfrom, yfrom), QPoint(xto, yto));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p->restore();
|
||||||
|
}
|
||||||
|
|
||||||
void TimelineView::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
void TimelineView::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||||
{
|
{
|
||||||
// special case: if there is a drag area below me, don't accept the
|
// special case: if there is a drag area below me, don't accept the
|
||||||
|
|||||||
@@ -182,7 +182,8 @@ protected:
|
|||||||
private:
|
private:
|
||||||
QColor colorForItem(int itemIndex);
|
QColor colorForItem(int itemIndex);
|
||||||
void drawItemsToPainter(QPainter *p, int fromIndex, int toIndex);
|
void drawItemsToPainter(QPainter *p, int fromIndex, int toIndex);
|
||||||
void drawSelectionBoxes(QPainter *p);
|
void drawSelectionBoxes(QPainter *p, int fromIndex, int toIndex);
|
||||||
|
void drawBindingLoopMarkers(QPainter *p, int fromIndex, int toIndex);
|
||||||
|
|
||||||
void manageClicked();
|
void manageClicked();
|
||||||
void manageHovered(int x, int y);
|
void manageHovered(int x, int y);
|
||||||
|
|||||||
Reference in New Issue
Block a user