Remote-canvas handles rects / round-rects directly.
When a rect shape is specified, paint it directly instead of converting to a path, since this might be much cheaper.
This commit is contained in:
parent
d831751b11
commit
490592d96e
4 changed files with 108 additions and 3 deletions
|
@ -93,7 +93,6 @@ QTransform FGCanvasElement::combinedTransform() const
|
|||
_combinedTransform.reset();
|
||||
|
||||
for (LocalProp* tfProp : _propertyRoot->childrenWithName("tf")) {
|
||||
// qDebug() << "tf" << tfProp->index() << qTransformFromCanvas(tfProp);
|
||||
_combinedTransform *= qTransformFromCanvas(tfProp);
|
||||
}
|
||||
|
||||
|
|
|
@ -168,7 +168,20 @@ void FGCanvasPath::doPaint(FGCanvasPaintContext *context) const
|
|||
}
|
||||
|
||||
context->painter()->setPen(_stroke);
|
||||
context->painter()->drawPath(_painterPath);
|
||||
|
||||
switch (_paintType) {
|
||||
case Rect:
|
||||
context->painter()->drawRect(_rect);
|
||||
break;
|
||||
case RoundRect:
|
||||
context->painter()->drawRoundRect(_rect, _roundRectRadius.width(), _roundRectRadius.height());
|
||||
break;
|
||||
|
||||
case Path:
|
||||
context->painter()->drawPath(_painterPath);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void FGCanvasPath::markStyleDirty()
|
||||
|
@ -197,6 +210,23 @@ bool FGCanvasPath::onChildAdded(LocalProp *prop)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (prop->name() == "rect") {
|
||||
_isRect = true;
|
||||
connect(prop, &LocalProp::childAdded, this, &FGCanvasPath::onChildAdded);
|
||||
return true;
|
||||
}
|
||||
|
||||
// handle rect property changes
|
||||
if (prop->parent()->name() == "rect") {
|
||||
connect(prop, &LocalProp::valueChanged, this, &FGCanvasPath::markPathDirty);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (prop->name().startsWith("border-")) {
|
||||
connect(prop, &LocalProp::valueChanged, this, &FGCanvasPath::markPathDirty);
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((prop->name() == "cmd-geo") || (prop->name() == "coord-geo")) {
|
||||
// ignore for now, we let the server-side transform down to cartesian.
|
||||
// if we move that work to client side we could skip sending the cmd/coord data
|
||||
|
@ -250,7 +280,9 @@ void FGCanvasPath::rebuildPath() const
|
|||
std::vector<float> coords;
|
||||
std::vector<int> commands;
|
||||
|
||||
if (_propertyRoot->hasChild("svg")) {
|
||||
if (_isRect) {
|
||||
rebuildFromRect(commands, coords);
|
||||
} else if (_propertyRoot->hasChild("svg")) {
|
||||
if (!rebuildFromSVGData(commands, coords)) {
|
||||
qWarning() << "failed to parse SVG path data" << _propertyRoot->value("svg", QVariant());
|
||||
}
|
||||
|
@ -291,6 +323,64 @@ QByteArrayList splitSVGPathData(QByteArray d)
|
|||
return result;
|
||||
}
|
||||
|
||||
bool hasComplexBorderRadius(const LocalProp* prop)
|
||||
{
|
||||
for (auto childProp : prop->children()) {
|
||||
QByteArray name = childProp->name();
|
||||
if (!name.startsWith("border-") || !name.endsWith("-radius")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (name != "border-radius") {
|
||||
return true;
|
||||
}
|
||||
} // of child prop iteration
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FGCanvasPath::rebuildFromRect(std::vector<int>& commands, std::vector<float>& coords) const
|
||||
{
|
||||
LocalProp* rectProp = _propertyRoot->getWithPath("rect");
|
||||
if (hasComplexBorderRadius(_propertyRoot)) {
|
||||
// build a full path
|
||||
qWarning() << "implement me";
|
||||
_paintType = Path;
|
||||
} else {
|
||||
float top = rectProp->value("top", 0.0).toFloat();
|
||||
float left = rectProp->value("left", 0.0).toFloat();
|
||||
float width = rectProp->value("width", 0.0).toFloat();
|
||||
float height = rectProp->value("height", 0.0).toFloat();
|
||||
|
||||
if (rectProp->hasChild("right")) {
|
||||
width = rectProp->value("right", 0.0).toFloat() - left;
|
||||
}
|
||||
|
||||
if (rectProp->hasChild("bottom")) {
|
||||
height = rectProp->value("bottom", 0.0).toFloat() - top;
|
||||
}
|
||||
|
||||
_rect = QRectF(left, top, width, height);
|
||||
|
||||
if (_propertyRoot->hasChild("border-radius")) {
|
||||
// round-rect
|
||||
float xR = _propertyRoot->value("border-radius", 0.0).toFloat();
|
||||
float yR = xR;
|
||||
if (_propertyRoot->hasChild("border-radius[1]")) {
|
||||
yR = _propertyRoot->value("border-radius[1]", 0.0).toFloat();
|
||||
}
|
||||
|
||||
_roundRectRadius = QSizeF(xR, yR);
|
||||
_paintType = RoundRect;
|
||||
} else {
|
||||
// simple rect
|
||||
_paintType = Rect;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FGCanvasPath::rebuildFromSVGData(std::vector<int>& commands, std::vector<float>& coords) const
|
||||
{
|
||||
QByteArrayList tokens = splitSVGPathData(_propertyRoot->value("svg", QVariant()).toByteArray());
|
||||
|
|
|
@ -26,11 +26,24 @@ private:
|
|||
|
||||
void rebuildPathFromCommands(const std::vector<int>& commands, const std::vector<float>& coords) const;
|
||||
bool rebuildFromSVGData(std::vector<int>& commands, std::vector<float>& coords) const;
|
||||
bool rebuildFromRect(std::vector<int> &commands, std::vector<float> &coords) const;
|
||||
private:
|
||||
enum PaintType
|
||||
{
|
||||
Path,
|
||||
Rect,
|
||||
RoundRect
|
||||
};
|
||||
|
||||
mutable bool _pathDirty = true;
|
||||
mutable QPainterPath _painterPath;
|
||||
mutable bool _penDirty = true;
|
||||
mutable QPen _stroke;
|
||||
bool _isRect = false;
|
||||
|
||||
mutable PaintType _paintType = Path;
|
||||
mutable QRectF _rect;
|
||||
mutable QSizeF _roundRectRadius;
|
||||
};
|
||||
|
||||
#endif // FGCANVASPATH_H
|
||||
|
|
|
@ -81,6 +81,9 @@ public:
|
|||
|
||||
LocalProp* parent() const;
|
||||
|
||||
std::vector<LocalProp*> children() const
|
||||
{ return _children; }
|
||||
|
||||
std::vector<QVariant> valuesOfChildren(const char* name) const;
|
||||
|
||||
std::vector<LocalProp*> childrenWithName(const char* name) const;
|
||||
|
|
Loading…
Add table
Reference in a new issue