"Fossies" - the Fresh Open Source Software Archive

Member "qt-creator-opensource-src-4.15.1/src/plugins/qmldesigner/components/curveeditor/curveeditormodel.cpp" (8 Jun 2021, 11762 Bytes) of package /linux/misc/qt-creator-opensource-src-4.15.1.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "curveeditormodel.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: opensource-src-4.15.0_vs_opensource-src-4.15.1.

    1 /****************************************************************************
    2 **
    3 ** Copyright (C) 2019 The Qt Company Ltd.
    4 ** Contact: https://www.qt.io/licensing/
    5 **
    6 ** This file is part of the Qt Design Tooling
    7 **
    8 ** Commercial License Usage
    9 ** Licensees holding valid commercial Qt licenses may use this file in
   10 ** accordance with the commercial license agreement provided with the
   11 ** Software or, alternatively, in accordance with the terms contained in
   12 ** a written agreement between you and The Qt Company. For licensing terms
   13 ** and conditions see https://www.qt.io/terms-conditions. For further
   14 ** information use the contact form at https://www.qt.io/contact-us.
   15 **
   16 ** GNU General Public License Usage
   17 ** Alternatively, this file may be used under the terms of the GNU
   18 ** General Public License version 3 as published by the Free Software
   19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
   20 ** included in the packaging of this file. Please review the following
   21 ** information to ensure the GNU General Public License requirements will
   22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
   23 **
   24 ****************************************************************************/
   25 
   26 #include "curveeditormodel.h"
   27 #include "curveeditorstyle.h"
   28 #include "detail/treeview.h"
   29 #include "treeitem.h"
   30 
   31 #include "detail/graphicsview.h"
   32 #include "detail/selectionmodel.h"
   33 
   34 #include "easingcurve.h"
   35 #include "qmltimeline.h"
   36 
   37 #include <bindingproperty.h>
   38 #include <nodeabstractproperty.h>
   39 #include <theme.h>
   40 #include <variantproperty.h>
   41 
   42 namespace QmlDesigner {
   43 
   44 CurveEditorModel::CurveEditorModel(QObject *parent)
   45     : TreeModel(parent)
   46     , m_minTime(CurveEditorStyle::defaultTimeMin)
   47     , m_maxTime(CurveEditorStyle::defaultTimeMax)
   48 {}
   49 
   50 CurveEditorModel::~CurveEditorModel() {}
   51 
   52 double CurveEditorModel::minimumTime() const
   53 {
   54     return m_minTime;
   55 }
   56 
   57 double CurveEditorModel::maximumTime() const
   58 {
   59     return m_maxTime;
   60 }
   61 
   62 CurveEditorStyle CurveEditorModel::style() const
   63 {
   64     // Pseudo auto generated. See: CurveEditorStyleDialog
   65     CurveEditorStyle out;
   66     out.backgroundBrush = QmlDesigner::Theme::getColor(QmlDesigner::Theme::DSsectionHeadBackground);
   67     out.backgroundAlternateBrush = QmlDesigner::Theme::getColor(QmlDesigner::Theme::DSpanelBackground);
   68     out.fontColor = QmlDesigner::Theme::getColor(QmlDesigner::Theme::DStextColor);
   69     out.gridColor = QColor(114, 116, 118);
   70     out.canvasMargin = 15;
   71     out.zoomInWidth = 99;
   72     out.zoomInHeight = 99;
   73     out.timeAxisHeight = 60;
   74     out.timeOffsetLeft = 10;
   75     out.timeOffsetRight = 10;
   76     out.rangeBarColor = QmlDesigner::Theme::getColor(Theme::DScontrolBackground);
   77     out.rangeBarCapsColor = QmlDesigner::Theme::getColor(
   78         QmlDesigner::Theme::QmlDesigner_HighlightColor);
   79     out.valueAxisWidth = 60;
   80     out.valueOffsetTop = 10;
   81     out.valueOffsetBottom = 10;
   82     out.handleStyle.size = 10;
   83     out.handleStyle.lineWidth = 1;
   84     out.handleStyle.color = QColor(255, 255, 255);
   85     out.handleStyle.selectionColor = QColor(255, 255, 255);
   86     out.keyframeStyle.size = 14;
   87     out.keyframeStyle.color = QColor(172, 210, 255);
   88     out.keyframeStyle.selectionColor = QColor(255, 255, 255);
   89     out.curveStyle.width = 2;
   90     out.curveStyle.color = QColor(0, 200, 0);
   91     out.curveStyle.selectionColor = QColor(255, 255, 255);
   92     out.treeItemStyle.margins = 0;
   93     out.playhead.width = 20;
   94     out.playhead.radius = 4;
   95     out.playhead.color = QColor(200, 200, 0);
   96     return out;
   97 }
   98 
   99 void CurveEditorModel::setTimeline(const QmlDesigner::QmlTimeline &timeline)
  100 {
  101     m_minTime = timeline.startKeyframe();
  102     m_maxTime = timeline.endKeyframe();
  103     std::vector<TreeItem *> items;
  104     for (auto &&target : timeline.allTargets()) {
  105         if (TreeItem *item = createTopLevelItem(timeline, target))
  106             items.push_back(item);
  107     }
  108 
  109     reset(items);
  110 }
  111 
  112 void CurveEditorModel::setCurrentFrame(int frame)
  113 {
  114     if (graphicsView())
  115         graphicsView()->setCurrentFrame(frame, false);
  116 }
  117 
  118 void CurveEditorModel::setMinimumTime(double time)
  119 {
  120     m_minTime = time;
  121     emit commitStartFrame(static_cast<int>(m_minTime));
  122 }
  123 
  124 void CurveEditorModel::setMaximumTime(double time)
  125 {
  126     m_maxTime = time;
  127     emit commitEndFrame(static_cast<int>(m_maxTime));
  128 }
  129 
  130 void CurveEditorModel::setCurve(unsigned int id, const AnimationCurve &curve)
  131 {
  132     if (TreeItem *item = find(id)) {
  133         if (PropertyTreeItem *propertyItem = item->asPropertyItem()) {
  134             propertyItem->setCurve(curve);
  135             emit curveChanged(propertyItem);
  136         }
  137     }
  138 }
  139 
  140 void CurveEditorModel::setLocked(TreeItem *item, bool val)
  141 {
  142     item->setLocked(val);
  143 
  144     if (auto *gview = graphicsView())
  145         gview->setLocked(item);
  146 
  147     if (auto *tview = treeView())
  148         tview->viewport()->update();
  149 
  150     emit curveChanged(item);
  151 }
  152 
  153 void CurveEditorModel::setPinned(TreeItem *item, bool val)
  154 {
  155     item->setPinned(val);
  156 
  157     if (auto *gview = graphicsView())
  158         gview->setPinned(item);
  159 
  160     if (auto *tview = treeView())
  161         tview->viewport()->update();
  162 
  163     emit curveChanged(item);
  164 }
  165 
  166 bool contains(const std::vector<TreeItem::Path> &selection, const TreeItem::Path &path)
  167 {
  168     for (auto &&sel : selection)
  169         if (path == sel)
  170             return true;
  171 
  172     return false;
  173 }
  174 
  175 void CurveEditorModel::reset(const std::vector<TreeItem *> &items)
  176 {
  177     std::vector<TreeItem::Path> sel;
  178     if (SelectionModel *sm = selectionModel())
  179         sel = sm->selectedPaths();
  180 
  181     beginResetModel();
  182 
  183     initialize();
  184 
  185     unsigned int counter = 0;
  186     std::vector<CurveItem *> pinned;
  187 
  188     for (auto *item : items) {
  189         item->setId(++counter);
  190         root()->addChild(item);
  191         if (auto *nti = item->asNodeItem()) {
  192             for (auto *pti : nti->properties()) {
  193                 if (pti->pinned() && !contains(sel, pti->path()))
  194                     pinned.push_back(TreeModel::curveItem(pti));
  195             }
  196         }
  197     }
  198 
  199     endResetModel();
  200 
  201     graphicsView()->reset(pinned);
  202 
  203     if (SelectionModel *sm = selectionModel())
  204         sm->selectPaths(sel);
  205 }
  206 
  207 PropertyTreeItem::ValueType typeFrom(const QmlDesigner::QmlTimelineKeyframeGroup &group)
  208 {
  209     if (group.valueType() == QmlDesigner::TypeName("double")
  210         || group.valueType() == QmlDesigner::TypeName("real")
  211         || group.valueType() == QmlDesigner::TypeName("float"))
  212         return PropertyTreeItem::ValueType::Double;
  213 
  214     if (group.valueType() == QmlDesigner::TypeName("boolean")
  215         || group.valueType() == QmlDesigner::TypeName("bool"))
  216         return PropertyTreeItem::ValueType::Bool;
  217 
  218     if (group.valueType() == QmlDesigner::TypeName("integer")
  219         || group.valueType() == QmlDesigner::TypeName("int"))
  220         return PropertyTreeItem::ValueType::Integer;
  221 
  222     // Ignoring: QColor / HAlignment / VAlignment
  223     return PropertyTreeItem::ValueType::Undefined;
  224 }
  225 
  226 std::vector<QString> parentIds(const QmlDesigner::ModelNode &node)
  227 {
  228     if (!node.hasParentProperty())
  229         return {};
  230 
  231     std::vector<QString> out;
  232 
  233     QmlDesigner::ModelNode parent = node.parentProperty().parentModelNode();
  234     while (parent.isValid()) {
  235         out.push_back(parent.id());
  236 
  237         if (parent.hasParentProperty())
  238             parent = parent.parentProperty().parentModelNode();
  239         else
  240             break;
  241     }
  242     return out;
  243 }
  244 
  245 TreeItem *CurveEditorModel::createTopLevelItem(const QmlDesigner::QmlTimeline &timeline,
  246                                                const QmlDesigner::ModelNode &node)
  247 {
  248     if (!node.isValid())
  249         return nullptr;
  250 
  251     auto *nodeItem = new NodeTreeItem(node.id(), node.typeIcon(), parentIds(node));
  252     if (node.hasAuxiliaryData("locked"))
  253         nodeItem->setLocked(true);
  254 
  255     for (auto &&grp : timeline.keyframeGroupsForTarget(node)) {
  256         if (grp.isValid()) {
  257             AnimationCurve curve = createAnimationCurve(grp);
  258             if (!curve.isEmpty()) {
  259                 QString name = QString::fromUtf8(grp.propertyName());
  260                 auto propertyItem = new PropertyTreeItem(name, curve, typeFrom(grp));
  261 
  262                 QmlDesigner::ModelNode target = grp.modelNode();
  263                 if (target.hasAuxiliaryData("locked"))
  264                     propertyItem->setLocked(true);
  265 
  266                 if (target.hasAuxiliaryData("pinned"))
  267                     propertyItem->setPinned(true);
  268 
  269                 nodeItem->addChild(propertyItem);
  270             }
  271         }
  272     }
  273 
  274     if (!nodeItem->hasChildren()) {
  275         delete nodeItem;
  276         nodeItem = nullptr;
  277     }
  278 
  279     return nodeItem;
  280 }
  281 
  282 AnimationCurve CurveEditorModel::createAnimationCurve(const QmlDesigner::QmlTimelineKeyframeGroup &group)
  283 {
  284     switch (typeFrom(group)) {
  285     case PropertyTreeItem::ValueType::Bool:
  286         return createDoubleCurve(group);
  287 
  288     case PropertyTreeItem::ValueType::Integer:
  289         return createDoubleCurve(group);
  290 
  291     case PropertyTreeItem::ValueType::Double:
  292         return createDoubleCurve(group);
  293 
  294     default:
  295         return AnimationCurve();
  296     }
  297 }
  298 
  299 std::vector<Keyframe> createKeyframes(QList<QmlDesigner::ModelNode> nodes)
  300 {
  301     auto byTime = [](const auto &a, const auto &b) {
  302         return a.variantProperty("frame").value().toDouble()
  303                < b.variantProperty("frame").value().toDouble();
  304     };
  305     std::sort(nodes.begin(), nodes.end(), byTime);
  306 
  307     std::vector<Keyframe> frames;
  308     for (auto &&node : nodes) {
  309         QVariant timeVariant = node.variantProperty("frame").value();
  310         QVariant valueVariant = node.variantProperty("value").value();
  311         if (!timeVariant.isValid() || !valueVariant.isValid())
  312             continue;
  313 
  314         QPointF position(timeVariant.toDouble(), valueVariant.toDouble());
  315 
  316         auto keyframe = Keyframe(position);
  317 
  318         if (node.hasBindingProperty("easing.bezierCurve")) {
  319             QmlDesigner::EasingCurve ecurve;
  320             ecurve.fromString(node.bindingProperty("easing.bezierCurve").expression());
  321             keyframe.setData(static_cast<QEasingCurve>(ecurve));
  322         }
  323         frames.push_back(keyframe);
  324     }
  325     return frames;
  326 }
  327 
  328 std::vector<Keyframe> resolveSmallCurves(const std::vector<Keyframe> &frames)
  329 {
  330     std::vector<Keyframe> out;
  331     for (auto &&frame : frames) {
  332         if (frame.hasData() && !out.empty()) {
  333             QEasingCurve curve = frame.data().toEasingCurve();
  334             // One-segment-curve: Since (0,0) is implicit => 3
  335             if (curve.toCubicSpline().count() == 3) {
  336                 Keyframe &previous = out.back();
  337 #if 0
  338                 // Do not resolve when two adjacent keyframes have the same value.
  339                 if (qFuzzyCompare(previous.position().y(), frame.position().y())) {
  340                     out.push_back(frame);
  341                     continue;
  342                 }
  343 #endif
  344                 AnimationCurve acurve(curve, previous.position(), frame.position());
  345                 previous.setRightHandle(acurve.keyframeAt(0).rightHandle());
  346                 out.push_back(acurve.keyframeAt(1));
  347                 continue;
  348             }
  349         }
  350         out.push_back(frame);
  351     }
  352     return out;
  353 }
  354 
  355 AnimationCurve CurveEditorModel::createDoubleCurve(const QmlDesigner::QmlTimelineKeyframeGroup &group)
  356 {
  357     std::vector<Keyframe> keyframes = createKeyframes(group.keyframePositions());
  358     keyframes = resolveSmallCurves(keyframes);
  359 
  360     QString str;
  361     QmlDesigner::ModelNode target = group.modelNode();
  362     if (target.hasAuxiliaryData("unified"))
  363         str = target.auxiliaryData("unified").toString();
  364 
  365     if (str.size() == static_cast<int>(keyframes.size())) {
  366         for (int i = 0; i < str.size(); ++i) {
  367             if (str.at(i) == '1')
  368                 keyframes[static_cast<size_t>(i)].setUnified(true);
  369         }
  370     }
  371 
  372     return AnimationCurve(keyframes);
  373 }
  374 
  375 } // End namespace QmlDesigner.