]> git.sesse.net Git - kdenlive/blob - src/geometryval.cpp
remove debug
[kdenlive] / src / geometryval.cpp
1 /***************************************************************************
2                           geomeytrval.cpp  -  description
3                              -------------------
4     begin                : 03 Aug 2008
5     copyright            : (C) 2008 by Marco Gittler
6     email                : g.marco@freenet.de
7  ***************************************************************************/
8
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17
18 #include "geometryval.h"
19 #include "graphicsscenerectmove.h"
20 #include "kdenlivesettings.h"
21
22 #include <KDebug>
23
24 #include <QGraphicsView>
25 #include <QVBoxLayout>
26 #include <QGraphicsRectItem>
27 #include <QMenu>
28 #include <QInputDialog>
29
30
31 Geometryval::Geometryval(const MltVideoProfile profile, Timecode t, QPoint frame_size, int startPoint, QWidget* parent) :
32         QWidget(parent),
33         m_profile(profile),
34         m_paramRect(NULL),
35         m_geom(NULL),
36         m_path(NULL),
37         m_fixedMode(false),
38         m_frameSize(frame_size),
39         m_startPoint(startPoint),
40         m_timePos(t)
41 {
42     setupUi(this);
43     toolbarlayout->addWidget(&m_timePos);
44     toolbarlayout->insertStretch(-1);
45
46     QVBoxLayout* vbox = new QVBoxLayout(widget);
47     m_sceneview = new QGraphicsView(this);
48     m_sceneview->setBackgroundBrush(QBrush(Qt::black));
49     vbox->addWidget(m_sceneview);
50     vbox->setContentsMargins(0, 0, 0, 0);
51
52     QVBoxLayout* vbox2 = new QVBoxLayout(keyframeWidget);
53     m_helper = new KeyframeHelper(this);
54     vbox2->addWidget(m_helper);
55     vbox2->setContentsMargins(0, 0, 0, 0);
56
57     connect(m_helper, SIGNAL(positionChanged(int)), this, SLOT(slotPositionChanged(int)));
58     connect(m_helper, SIGNAL(keyframeMoved(int)), this, SLOT(slotKeyframeMoved(int)));
59     connect(m_helper, SIGNAL(addKeyframe(int)), this, SLOT(slotAddFrame(int)));
60     connect(m_helper, SIGNAL(removeKeyframe(int)), this, SLOT(slotDeleteFrame(int)));
61
62     m_scene = new GraphicsSceneRectMove(this);
63     m_scene->setTool(TITLE_SELECT);
64     m_sceneview->setScene(m_scene);
65     m_dar = (m_profile.height * m_profile.display_aspect_num / (double) m_profile.display_aspect_den) / (double) m_profile.width;
66
67     m_realWidth = (int)(profile.height * profile.display_aspect_num / (double) profile.display_aspect_den);
68     QGraphicsRectItem *frameBorder = new QGraphicsRectItem(QRectF(0, 0, m_realWidth, profile.height));
69     frameBorder->setZValue(-1100);
70     frameBorder->setBrush(QColor(255, 255, 0, 30));
71     frameBorder->setPen(QPen(QBrush(QColor(255, 255, 255, 255)), 1.0, Qt::DashLine));
72     m_scene->addItem(frameBorder);
73
74     buttonNext->setIcon(KIcon("media-skip-forward"));
75     buttonNext->setToolTip(i18n("Go to next keyframe"));
76     buttonPrevious->setIcon(KIcon("media-skip-backward"));
77     buttonPrevious->setToolTip(i18n("Go to previous keyframe"));
78     buttonAdd->setIcon(KIcon("document-new"));
79     buttonAdd->setToolTip(i18n("Add keyframe"));
80     buttonDelete->setIcon(KIcon("edit-delete"));
81     buttonDelete->setToolTip(i18n("Delete keyframe"));
82
83     m_configMenu = new QMenu(i18n("Misc..."), this);
84     buttonMenu->setMenu(m_configMenu);
85     buttonMenu->setPopupMode(QToolButton::MenuButtonPopup);
86
87     m_editOptions = m_configMenu->addAction(KIcon("system-run"), i18n("Show/Hide options"));
88     m_editOptions->setCheckable(true);
89     buttonMenu->setDefaultAction(m_editOptions);
90     connect(m_editOptions, SIGNAL(triggered()), this, SLOT(slotSwitchOptions()));
91     slotSwitchOptions();
92
93     m_reset = m_configMenu->addAction(KIcon("view-refresh"), i18n("Reset"), this, SLOT(slotResetPosition()));
94
95     m_syncAction = m_configMenu->addAction(i18n("Sync timeline cursor"), this, SLOT(slotSyncCursor()));
96     m_syncAction->setCheckable(true);
97     m_syncAction->setChecked(KdenliveSettings::transitionfollowcursor());
98
99     //scene->setSceneRect(0, 0, profile.width * 2, profile.height * 2);
100     //view->fitInView(m_frameBorder, Qt::KeepAspectRatio);
101     const double sc = 100.0 / profile.height * 0.8;
102     QRectF srect = m_sceneview->sceneRect();
103     m_sceneview->setSceneRect(srect.x(), -srect.height() / 3 + 10, srect.width(), srect.height() + srect.height() / 3 * 2 - 10);
104     m_scene->setZoom(sc);
105     m_sceneview->centerOn(frameBorder);
106     m_sceneview->setMouseTracking(true);
107     connect(buttonNext , SIGNAL(clicked()) , this , SLOT(slotNextFrame()));
108     connect(buttonPrevious , SIGNAL(clicked()) , this , SLOT(slotPreviousFrame()));
109     connect(buttonDelete , SIGNAL(clicked()) , this , SLOT(slotDeleteFrame()));
110     connect(buttonAdd , SIGNAL(clicked()) , this , SLOT(slotAddFrame()));
111     connect(m_scene, SIGNAL(actionFinished()), this, SLOT(slotUpdateTransitionProperties()));
112
113     buttonhcenter->setIcon(KIcon("kdenlive-align-hor"));
114     buttonhcenter->setToolTip(i18n("Align item horizontally"));
115     buttonvcenter->setIcon(KIcon("kdenlive-align-vert"));
116     buttonvcenter->setToolTip(i18n("Align item vertically"));
117     buttontop->setIcon(KIcon("kdenlive-align-top"));
118     buttontop->setToolTip(i18n("Align item to top"));
119     buttonbottom->setIcon(KIcon("kdenlive-align-bottom"));
120     buttonbottom->setToolTip(i18n("Align item to bottom"));
121     buttonright->setIcon(KIcon("kdenlive-align-right"));
122     buttonright->setToolTip(i18n("Align item to right"));
123     buttonleft->setIcon(KIcon("kdenlive-align-left"));
124     buttonleft->setToolTip(i18n("Align item to left"));
125
126     connect(buttonhcenter, SIGNAL(clicked()), this, SLOT(slotAlignHCenter()));
127     connect(buttonvcenter, SIGNAL(clicked()), this, SLOT(slotAlignVCenter()));
128     connect(buttontop, SIGNAL(clicked()), this, SLOT(slotAlignTop()));
129     connect(buttonbottom, SIGNAL(clicked()), this, SLOT(slotAlignBottom()));
130     connect(buttonright, SIGNAL(clicked()), this, SLOT(slotAlignRight()));
131     connect(buttonleft, SIGNAL(clicked()), this, SLOT(slotAlignLeft()));
132     connect(spinX, SIGNAL(valueChanged(int)), this, SLOT(slotGeometryX(int)));
133     connect(spinY, SIGNAL(valueChanged(int)), this, SLOT(slotGeometryY(int)));
134     connect(spinWidth, SIGNAL(valueChanged(int)), this, SLOT(slotGeometryWidth(int)));
135     connect(spinHeight, SIGNAL(valueChanged(int)), this, SLOT(slotGeometryHeight(int)));
136     connect(spinResize, SIGNAL(editingFinished()), this, SLOT(slotResizeCustom()));
137     connect(buttonResize, SIGNAL(clicked()), this, SLOT(slotResizeOriginal()));
138
139     connect(this, SIGNAL(parameterChanged()), this, SLOT(slotUpdateGeometry()));
140 }
141
142
143 Geometryval::~Geometryval()
144 {
145     m_scene->disconnect();
146     delete m_syncAction;
147     delete m_configMenu;
148     delete m_paramRect;
149     delete m_path;
150     delete m_helper;
151     delete m_geom;
152     delete m_sceneview;
153     delete m_scene;
154 }
155
156
157 void Geometryval::slotAlignHCenter()
158 {
159     if (!keyframeSelected())
160         return;
161     m_paramRect->setPos((m_realWidth - m_paramRect->rect().width()) / 2, m_paramRect->pos().y());
162     slotUpdateTransitionProperties();
163 }
164
165 void Geometryval::slotAlignVCenter()
166 {
167     if (!keyframeSelected())
168         return;
169     m_paramRect->setPos(m_paramRect->pos().x(), (m_profile.height - m_paramRect->rect().height()) / 2);
170     slotUpdateTransitionProperties();
171 }
172
173 void Geometryval::slotAlignTop()
174 {
175     if (!keyframeSelected())
176         return;
177     m_paramRect->setPos(m_paramRect->pos().x(), 0);
178     slotUpdateTransitionProperties();
179 }
180
181 void Geometryval::slotAlignBottom()
182 {
183     if (!keyframeSelected())
184         return;
185     m_paramRect->setPos(m_paramRect->pos().x(), m_profile.height - m_paramRect->rect().height());
186     slotUpdateTransitionProperties();
187 }
188
189 void Geometryval::slotAlignLeft()
190 {
191     if (!keyframeSelected())
192         return;
193     m_paramRect->setPos(0, m_paramRect->pos().y());
194     slotUpdateTransitionProperties();
195 }
196
197 void Geometryval::slotAlignRight()
198 {
199     if (!keyframeSelected())
200         return;
201     m_paramRect->setPos(m_realWidth - m_paramRect->rect().width(), m_paramRect->pos().y());
202     slotUpdateTransitionProperties();
203 }
204
205 void Geometryval::slotResizeOriginal()
206 {
207     if (!keyframeSelected())
208         return;
209     if (m_frameSize.isNull())
210         m_paramRect->setRect(0, 0, m_realWidth, m_profile.height);
211     else
212         m_paramRect->setRect(0, 0, m_frameSize.x(), m_frameSize.y());
213     slotUpdateTransitionProperties();
214 }
215
216 void Geometryval::slotResizeCustom()
217 {
218     if (!keyframeSelected())
219         return;
220     int value = spinResize->value();
221     m_paramRect->setRect(0, 0, m_realWidth * value / 100, m_profile.height * value / 100);
222     slotUpdateTransitionProperties();
223 }
224
225 void Geometryval::slotTransparencyChanged(int transp)
226 {
227     int pos = m_timePos.getValue();
228     Mlt::GeometryItem item;
229     int error = m_geom->fetch(&item, pos);
230     if (error || item.key() == false) {
231         // no keyframe under cursor
232         return;
233     }
234     item.mix(transp);
235     m_paramRect->setBrush(QColor(255, 0, 0, transp));
236     m_geom->insert(item);
237     emit parameterChanged();
238 }
239
240 void Geometryval::slotSyncCursor()
241 {
242     KdenliveSettings::setTransitionfollowcursor(m_syncAction->isChecked());
243 }
244
245 void Geometryval::updateTimecodeFormat()
246 {
247     m_timePos.slotUpdateTimeCodeFormat();
248 }
249
250 void Geometryval::slotPositionChanged(int pos, bool seek)
251 {
252     if (pos == -1) {
253         pos = m_timePos.getValue();
254     }
255     if (seek && KdenliveSettings::transitionfollowcursor()) emit seekToPos(pos + m_startPoint);
256     m_timePos.setValue(pos);
257     //spinPos->setValue(pos);
258     m_helper->blockSignals(true);
259     m_helper->setValue(pos);
260     m_helper->blockSignals(false);
261     Mlt::GeometryItem item;
262     int error = m_geom->fetch(&item, pos);
263     if (error || item.key() == false) {
264         // no keyframe under cursor, adjust buttons
265         buttonAdd->setEnabled(true);
266         buttonDelete->setEnabled(false);
267         widget->setEnabled(false);
268         spinTransp->setEnabled(false);
269         frameOptions->setEnabled(false);
270         m_reset->setEnabled(false);
271     } else {
272         buttonAdd->setEnabled(false);
273         buttonDelete->setEnabled(true);
274         widget->setEnabled(true);
275         spinTransp->setEnabled(true);
276         frameOptions->setEnabled(true);
277         m_reset->setEnabled(true);
278     }
279
280     m_paramRect->setPos(item.x() * m_dar, item.y());
281     m_paramRect->setRect(0, 0, item.w() * m_dar, item.h());
282     spinTransp->setValue(item.mix());
283     m_paramRect->setBrush(QColor(255, 0, 0, item.mix()));
284     slotUpdateGeometry();
285 }
286
287 void Geometryval::slotDeleteFrame(int pos)
288 {
289     // check there is more than one keyframe
290     Mlt::GeometryItem item;
291     int frame = m_timePos.getValue();
292
293     if (pos == -1) pos = frame;
294     int error = m_geom->next_key(&item, pos + 1);
295     if (error) {
296         error = m_geom->prev_key(&item, pos - 1);
297         if (error || item.frame() == pos) return;
298     }
299
300     m_geom->remove(frame);
301     buttonAdd->setEnabled(true);
302     buttonDelete->setEnabled(false);
303     widget->setEnabled(false);
304     spinTransp->setEnabled(false);
305     frameOptions->setEnabled(false);
306     m_reset->setEnabled(false);
307     m_helper->update();
308     slotPositionChanged(pos, false);
309     updateTransitionPath();
310     emit parameterChanged();
311 }
312
313 void Geometryval::slotAddFrame(int pos)
314 {
315     int frame = m_timePos.getValue();
316     if (pos == -1) pos = frame;
317     Mlt::GeometryItem item;
318     item.frame(pos);
319     QRectF r = m_paramRect->rect().normalized();
320     QPointF rectpos = m_paramRect->pos();
321     item.x(rectpos.x() / m_dar);
322     item.y(rectpos.y());
323     item.w(r.width() / m_dar);
324     item.h(r.height());
325     item.mix(spinTransp->value());
326     m_geom->insert(item);
327     buttonAdd->setEnabled(false);
328     buttonDelete->setEnabled(true);
329     widget->setEnabled(true);
330     spinTransp->setEnabled(true);
331     frameOptions->setEnabled(true);
332     m_reset->setEnabled(true);
333     m_helper->update();
334     emit parameterChanged();
335 }
336
337 void Geometryval::slotNextFrame()
338 {
339     Mlt::GeometryItem item;
340     int error = m_geom->next_key(&item, m_helper->value() + 1);
341     int pos;
342     kDebug() << "// SEEK TO NEXT KFR: " << error;
343     if (error) {
344         // Go to end
345         pos = m_helper->frameLength;
346     } else pos = item.frame();
347     m_timePos.setValue(pos);
348     slotPositionChanged();
349 }
350
351 void Geometryval::slotPreviousFrame()
352 {
353     Mlt::GeometryItem item;
354     int error = m_geom->prev_key(&item, m_helper->value() - 1);
355     kDebug() << "// SEEK TO NEXT KFR: " << error;
356     if (error) return;
357     int pos = item.frame();
358     m_timePos.setValue(pos);
359     slotPositionChanged();
360 }
361
362
363 QString Geometryval::getValue() const
364 {
365     return m_geom->serialise();
366 }
367
368 void Geometryval::setupParam(const QDomElement par, int minFrame, int maxFrame)
369 {
370     QString val = par.attribute("value");
371     if (par.attribute("fixed") == "1") {
372         m_fixedMode = true;
373         buttonPrevious->setHidden(true);
374         buttonNext->setHidden(true);
375         buttonDelete->setHidden(true);
376         buttonAdd->setHidden(true);
377         spinTransp->setMaximum(500);
378         label_pos->setHidden(true);
379         m_helper->setHidden(true);
380         m_timePos.setHidden(true);
381     }
382     if (par.attribute("opacity") == "false") {
383         label_opacity->setHidden(true);
384         spinTransp->setHidden(true);
385     }
386     char *tmp = (char *) qstrdup(val.toUtf8().data());
387     if (m_geom) m_geom->parse(tmp, maxFrame - minFrame, m_profile.width, m_profile.height);
388     else m_geom = new Mlt::Geometry(tmp, maxFrame - minFrame, m_profile.width, m_profile.height);
389     delete[] tmp;
390
391     //kDebug() << " / / UPDATING TRANSITION VALUE: " << m_geom->serialise();
392     //read param her and set rect
393     if (!m_fixedMode) {
394         m_helper->setKeyGeometry(m_geom, maxFrame - minFrame - 1);
395         m_helper->update();
396         /*QDomDocument doc;
397         doc.appendChild(doc.importNode(par, true));
398         kDebug() << "IMPORTED TRANS: " << doc.toString();*/
399         if (m_path == NULL) {
400             m_path = new QGraphicsPathItem();
401             m_path->setPen(QPen(Qt::red));
402             m_scene->addItem(m_path);
403         }
404         updateTransitionPath();
405     }
406     Mlt::GeometryItem item;
407
408     m_geom->fetch(&item, 0);
409     delete m_paramRect;
410     m_paramRect = new QGraphicsRectItem(QRectF(0, 0, item.w() * m_dar, item.h()));
411     m_paramRect->setPos(item.x() * m_dar, item.y());
412     m_paramRect->setZValue(0);
413     m_paramRect->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
414
415     m_paramRect->setPen(QPen(QBrush(QColor(255, 0, 0, 255)), 1.0));
416     m_scene->addItem(m_paramRect);
417     slotPositionChanged(0, false);
418     slotUpdateGeometry();
419     if (!m_fixedMode) {
420         m_timePos.setRange(0, maxFrame - minFrame - 1);
421         connect(&m_timePos, SIGNAL(editingFinished()), this , SLOT(slotPositionChanged()));
422     }
423     connect(spinTransp, SIGNAL(valueChanged(int)), this , SLOT(slotTransparencyChanged(int)));
424 }
425
426 void Geometryval::updateTransitionPath()
427 {
428     if (m_fixedMode) return;
429     Mlt::GeometryItem item;
430     int pos = 0;
431     int counter = 0;
432     QPainterPath path;
433     while (true) {
434         if (m_geom->next_key(&item, pos) == 1) break;
435         pos = item.frame();
436         if (counter == 0) {
437             path.moveTo(item.x() * m_dar + item.w() * m_dar / 2, item.y() + item.h() / 2);
438         } else {
439             path.lineTo(item.x() * m_dar + item.w() * m_dar / 2, item.y() + item.h() / 2);
440         }
441         counter++;
442         pos++;
443     }
444     m_path->setPath(path);
445 }
446
447 void Geometryval::slotUpdateTransitionProperties()
448 {
449     int pos = m_timePos.getValue();
450     Mlt::GeometryItem item;
451     int error = m_geom->next_key(&item, pos);
452     if (error || item.frame() != pos) {
453         // no keyframe under cursor
454         return;
455     }
456     QRectF r = m_paramRect->rect().normalized();
457     QPointF rectpos = m_paramRect->pos();
458     item.x(rectpos.x() / m_dar);
459     item.y(rectpos.y());
460     item.w(r.width() / m_dar);
461     item.h(r.height());
462     m_geom->insert(item);
463     updateTransitionPath();
464     emit parameterChanged();
465 }
466
467 void Geometryval::slotResetPosition()
468 {
469     spinX->setValue(0);
470     spinY->setValue(0);
471
472     if (m_frameSize.isNull()) {
473         spinWidth->setValue(m_realWidth);
474         spinHeight->setValue(m_profile.height);
475     } else {
476         spinWidth->setValue(m_frameSize.x());
477         spinHeight->setValue(m_frameSize.y());
478     }
479 }
480
481 void Geometryval::setFrameSize(QPoint p)
482 {
483     m_frameSize = p;
484 }
485
486
487 void Geometryval::slotKeyframeMoved(int pos)
488 {
489     slotPositionChanged(pos);
490     slotUpdateTransitionProperties();
491 }
492
493 void Geometryval::slotSwitchOptions()
494 {
495     if (frameOptions->isHidden()) {
496         frameOptions->setHidden(false);
497         m_editOptions->setChecked(true);
498     } else {
499         frameOptions->setHidden(true);
500         m_editOptions->setChecked(false);
501     }
502     //adjustSize();
503 }
504
505 void Geometryval::slotGeometryX(int value)
506 {
507     if (!keyframeSelected())
508         return;
509     m_paramRect->setPos(value, spinY->value());
510     slotUpdateTransitionProperties();
511 }
512
513 void Geometryval::slotGeometryY(int value)
514 {
515     if (!keyframeSelected())
516         return;
517     m_paramRect->setPos(spinX->value(), value);
518     slotUpdateTransitionProperties();
519 }
520
521 void Geometryval::slotGeometryWidth(int value)
522 {
523     if (!keyframeSelected())
524         return;
525     m_paramRect->setRect(0, 0, value, spinHeight->value());
526     slotUpdateTransitionProperties();
527 }
528
529 void Geometryval::slotGeometryHeight(int value)
530 {
531     if (!keyframeSelected())
532         return;
533     m_paramRect->setRect(0, 0, spinWidth->value(), value);
534     slotUpdateTransitionProperties();
535 }
536
537 void Geometryval::slotUpdateGeometry()
538 {
539     QRectF r = m_paramRect->rect().normalized();
540
541     spinX->blockSignals(true);
542     spinY->blockSignals(true);
543     spinWidth->blockSignals(true);
544     spinHeight->blockSignals(true);
545     spinResize->blockSignals(true);
546
547     spinX->setValue(m_paramRect->pos().x());
548     spinY->setValue(m_paramRect->pos().y());
549     spinWidth->setValue(r.width());
550     spinHeight->setValue(r.height());
551     spinResize->setValue(m_paramRect->rect().width() * 100 / m_realWidth);
552
553     spinX->blockSignals(false);
554     spinY->blockSignals(false);
555     spinWidth->blockSignals(false);
556     spinHeight->blockSignals(false);
557     spinResize->blockSignals(false);
558 }
559
560 bool Geometryval::keyframeSelected()
561 {
562     Mlt::GeometryItem item;
563     int pos = m_timePos.getValue();
564     if (m_geom->fetch(&item, pos) || item.key() == false) return false;
565     return true;
566 }
567
568
569