1 /***************************************************************************
2 geomeytrval.cpp - description
5 copyright : (C) 2008 by Marco Gittler
6 email : g.marco@freenet.de
7 ***************************************************************************/
9 /***************************************************************************
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. *
16 ***************************************************************************/
18 #include "geometryval.h"
19 #include "graphicsscenerectmove.h"
20 #include "kdenlivesettings.h"
24 #include <QGraphicsView>
25 #include <QVBoxLayout>
26 #include <QGraphicsRectItem>
30 Geometryval::Geometryval(const MltVideoProfile profile, QWidget* parent): QWidget(parent), m_profile(profile), m_geom(NULL), m_path(NULL), paramRect(NULL), m_fixedMode(false)
33 QVBoxLayout* vbox = new QVBoxLayout(ui.widget);
34 QGraphicsView *view = new QGraphicsView(this);
35 view->setBackgroundBrush(QBrush(Qt::black));
36 vbox->addWidget(view);
37 vbox->setContentsMargins(0, 0, 0, 0);
39 QVBoxLayout* vbox2 = new QVBoxLayout(ui.keyframeWidget);
40 m_helper = new KeyframeHelper(this);
41 vbox2->addWidget(m_helper);
42 vbox2->setContentsMargins(0, 0, 0, 0);
44 connect(m_helper, SIGNAL(positionChanged(int)), this, SLOT(slotPositionChanged(int)));
46 scene = new GraphicsSceneRectMove(this);
47 scene->setTool(TITLE_SELECT);
48 view->setScene(scene);
49 QGraphicsRectItem *m_frameBorder = new QGraphicsRectItem(QRectF(0, 0, profile.width, profile.height));
50 m_frameBorder->setZValue(-1100);
51 m_frameBorder->setBrush(QColor(255, 255, 0, 30));
52 m_frameBorder->setPen(QPen(QBrush(QColor(255, 255, 255, 255)), 1.0, Qt::DashLine));
53 scene->addItem(m_frameBorder);
55 ui.buttonNext->setIcon(KIcon("media-skip-forward"));
56 ui.buttonNext->setToolTip(i18n("Go to next keyframe"));
57 ui.buttonPrevious->setIcon(KIcon("media-skip-backward"));
58 ui.buttonPrevious->setToolTip(i18n("Go to previous keyframe"));
59 ui.buttonAdd->setIcon(KIcon("document-new"));
60 ui.buttonAdd->setToolTip(i18n("Add keyframe"));
61 ui.buttonDelete->setIcon(KIcon("edit-delete"));
62 ui.buttonDelete->setToolTip(i18n("Delete keyframe"));
64 QMenu *configMenu = new QMenu(i18n("Misc..."), this);
65 ui.buttonMenu->setIcon(KIcon("system-run"));
66 ui.buttonMenu->setMenu(configMenu);
67 ui.buttonMenu->setPopupMode(QToolButton::QToolButton::InstantPopup);
70 m_scaleMenu = new QMenu(i18n("Resize..."), this);
71 configMenu->addMenu(m_scaleMenu);
72 m_scaleMenu->addAction(i18n("50%"), this, SLOT(slotResize50()));
73 m_scaleMenu->addAction(i18n("100%"), this, SLOT(slotResize100()));
74 m_scaleMenu->addAction(i18n("200%"), this, SLOT(slotResize200()));
77 m_alignMenu = new QMenu(i18n("Align..."), this);
78 configMenu->addMenu(m_alignMenu);
79 m_alignMenu->addAction(i18n("Center"), this, SLOT(slotAlignCenter()));
80 m_alignMenu->addAction(i18n("Hor. Center"), this, SLOT(slotAlignHCenter()));
81 m_alignMenu->addAction(i18n("Vert. Center"), this, SLOT(slotAlignVCenter()));
82 m_alignMenu->addAction(i18n("Right"), this, SLOT(slotAlignRight()));
83 m_alignMenu->addAction(i18n("Left"), this, SLOT(slotAlignLeft()));
84 m_alignMenu->addAction(i18n("Top"), this, SLOT(slotAlignTop()));
85 m_alignMenu->addAction(i18n("Bottom"), this, SLOT(slotAlignBottom()));
88 m_syncAction = configMenu->addAction(i18n("Sync timeline cursor"), this, SLOT(slotSyncCursor()));
89 m_syncAction->setCheckable(true);
90 m_syncAction->setChecked(KdenliveSettings::transitionfollowcursor());
92 //scene->setSceneRect(0, 0, profile.width * 2, profile.height * 2);
93 //view->fitInView(m_frameBorder, Qt::KeepAspectRatio);
94 const double sc = 100.0 / profile.height * 0.8;
95 QRectF srect = view->sceneRect();
96 view->setSceneRect(srect.x(), -srect.height() / 3 + 10, srect.width(), srect.height() + srect.height() / 3 * 2 - 10);
98 view->centerOn(m_frameBorder);
99 connect(ui.buttonNext , SIGNAL(clicked()) , this , SLOT(slotNextFrame()));
100 connect(ui.buttonPrevious , SIGNAL(clicked()) , this , SLOT(slotPreviousFrame()));
101 connect(ui.buttonDelete , SIGNAL(clicked()) , this , SLOT(slotDeleteFrame()));
102 connect(ui.buttonAdd , SIGNAL(clicked()) , this , SLOT(slotAddFrame()));
103 connect(scene, SIGNAL(actionFinished()), this, SLOT(slotUpdateTransitionProperties()));
106 void Geometryval::slotAlignCenter()
108 int pos = ui.spinPos->value();
109 Mlt::GeometryItem item;
110 int error = m_geom->fetch(&item, pos);
111 if (error || item.key() == false) {
112 // no keyframe under cursor
115 paramRect->setPos((m_profile.width - paramRect->rect().width()) / 2, (m_profile.height - paramRect->rect().height()) / 2);
116 slotUpdateTransitionProperties();
119 void Geometryval::slotAlignHCenter()
121 int pos = ui.spinPos->value();
122 Mlt::GeometryItem item;
123 int error = m_geom->fetch(&item, pos);
124 if (error || item.key() == false) {
125 // no keyframe under cursor
128 paramRect->setPos((m_profile.width - paramRect->rect().width()) / 2, paramRect->pos().y());
129 slotUpdateTransitionProperties();
132 void Geometryval::slotAlignVCenter()
134 int pos = ui.spinPos->value();
135 Mlt::GeometryItem item;
136 int error = m_geom->fetch(&item, pos);
137 if (error || item.key() == false) {
138 // no keyframe under cursor
141 paramRect->setPos(paramRect->pos().x(), (m_profile.height - paramRect->rect().height()) / 2);
142 slotUpdateTransitionProperties();
145 void Geometryval::slotAlignTop()
147 int pos = ui.spinPos->value();
148 Mlt::GeometryItem item;
149 int error = m_geom->fetch(&item, pos);
150 if (error || item.key() == false) {
151 // no keyframe under cursor
154 paramRect->setPos(paramRect->pos().x(), 0);
155 slotUpdateTransitionProperties();
158 void Geometryval::slotAlignBottom()
160 int pos = ui.spinPos->value();
161 Mlt::GeometryItem item;
162 int error = m_geom->fetch(&item, pos);
163 if (error || item.key() == false) {
164 // no keyframe under cursor
167 paramRect->setPos(paramRect->pos().x(), m_profile.height - paramRect->rect().height());
168 slotUpdateTransitionProperties();
171 void Geometryval::slotAlignLeft()
173 int pos = ui.spinPos->value();
174 Mlt::GeometryItem item;
175 int error = m_geom->fetch(&item, pos);
176 if (error || item.key() == false) {
177 // no keyframe under cursor
180 paramRect->setPos(0, paramRect->pos().y());
181 slotUpdateTransitionProperties();
184 void Geometryval::slotAlignRight()
186 int pos = ui.spinPos->value();
187 Mlt::GeometryItem item;
188 int error = m_geom->fetch(&item, pos);
189 if (error || item.key() == false) {
190 // no keyframe under cursor
193 paramRect->setPos(m_profile.width - paramRect->rect().width(), paramRect->pos().y());
194 slotUpdateTransitionProperties();
197 void Geometryval::slotResize50()
199 int pos = ui.spinPos->value();
200 Mlt::GeometryItem item;
201 int error = m_geom->fetch(&item, pos);
202 if (error || item.key() == false) {
203 // no keyframe under cursor
206 paramRect->setRect(0, 0, m_profile.width / 2, m_profile.height / 2);
207 slotUpdateTransitionProperties();
210 void Geometryval::slotResize100()
212 int pos = ui.spinPos->value();
213 Mlt::GeometryItem item;
214 int error = m_geom->fetch(&item, pos);
215 if (error || item.key() == false) {
216 // no keyframe under cursor
219 paramRect->setRect(0, 0, m_profile.width, m_profile.height);
220 slotUpdateTransitionProperties();
223 void Geometryval::slotResize200()
225 int pos = ui.spinPos->value();
226 Mlt::GeometryItem item;
227 int error = m_geom->fetch(&item, pos);
228 if (error || item.key() == false) {
229 // no keyframe under cursor
232 paramRect->setRect(0, 0, m_profile.width * 2, m_profile.height * 2);
233 slotUpdateTransitionProperties();
236 void Geometryval::slotTransparencyChanged(int transp)
238 int pos = ui.spinPos->value();
239 Mlt::GeometryItem item;
240 int error = m_geom->fetch(&item, pos);
241 if (error || item.key() == false) {
242 // no keyframe under cursor
246 paramRect->setBrush(QColor(255, 0, 0, transp));
247 m_geom->insert(item);
248 emit parameterChanged();
251 void Geometryval::slotSyncCursor()
253 KdenliveSettings::setTransitionfollowcursor(m_syncAction->isChecked());
256 void Geometryval::slotPositionChanged(int pos, bool seek)
258 if (seek && KdenliveSettings::transitionfollowcursor()) emit seekToPos(pos);
259 ui.spinPos->setValue(pos);
260 m_helper->setValue(pos);
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 ui.buttonAdd->setEnabled(true);
266 ui.buttonDelete->setEnabled(false);
267 ui.widget->setEnabled(false);
268 ui.spinTransp->setEnabled(false);
269 m_scaleMenu->setEnabled(false);
270 m_alignMenu->setEnabled(false);
272 ui.buttonAdd->setEnabled(false);
273 ui.buttonDelete->setEnabled(true);
274 ui.widget->setEnabled(true);
275 ui.spinTransp->setEnabled(true);
276 m_scaleMenu->setEnabled(true);
277 m_alignMenu->setEnabled(true);
279 paramRect->setPos(item.x(), item.y());
280 paramRect->setRect(0, 0, item.w(), item.h());
281 ui.spinTransp->setValue(item.mix());
282 paramRect->setBrush(QColor(255, 0, 0, item.mix()));
285 void Geometryval::slotDeleteFrame()
287 // check there is more than one keyframe
288 Mlt::GeometryItem item;
289 const int pos = ui.spinPos->value();
290 int error = m_geom->next_key(&item, pos + 1);
292 error = m_geom->prev_key(&item, pos - 1);
293 if (error || item.frame() == pos) return;
296 m_geom->remove(ui.spinPos->value());
297 ui.buttonAdd->setEnabled(true);
298 ui.buttonDelete->setEnabled(false);
299 ui.widget->setEnabled(false);
300 ui.spinTransp->setEnabled(false);
301 m_scaleMenu->setEnabled(false);
302 m_alignMenu->setEnabled(false);
304 slotPositionChanged(pos, false);
305 updateTransitionPath();
306 emit parameterChanged();
309 void Geometryval::slotAddFrame()
311 int pos = ui.spinPos->value();
312 Mlt::GeometryItem item;
314 item.x(paramRect->pos().x());
315 item.y(paramRect->pos().y());
316 item.w(paramRect->rect().width());
317 item.h(paramRect->rect().height());
318 item.mix(ui.spinTransp->value());
319 m_geom->insert(item);
320 ui.buttonAdd->setEnabled(false);
321 ui.buttonDelete->setEnabled(true);
322 ui.widget->setEnabled(true);
323 ui.spinTransp->setEnabled(true);
324 m_scaleMenu->setEnabled(true);
325 m_alignMenu->setEnabled(true);
327 emit parameterChanged();
330 void Geometryval::slotNextFrame()
332 Mlt::GeometryItem item;
333 int error = m_geom->next_key(&item, m_helper->value() + 1);
334 kDebug() << "// SEEK TO NEXT KFR: " << error;
337 ui.spinPos->setValue(ui.spinPos->maximum());
340 int pos = item.frame();
341 ui.spinPos->setValue(pos);
344 void Geometryval::slotPreviousFrame()
346 Mlt::GeometryItem item;
347 int error = m_geom->prev_key(&item, m_helper->value() - 1);
348 kDebug() << "// SEEK TO NEXT KFR: " << error;
350 int pos = item.frame();
351 ui.spinPos->setValue(pos);
355 QDomElement Geometryval::getParamDesc()
357 param.setAttribute("value", m_geom->serialise());
358 kDebug() << " / / UPDATING TRANSITION VALUE: " << param.attribute("value");
362 void Geometryval::setupParam(const QDomElement& par, int minFrame, int maxFrame)
365 QString val = par.attribute("value");
366 if (par.attribute("fixed") == "1") {
368 ui.buttonPrevious->setHidden(true);
369 ui.buttonNext->setHidden(true);
370 ui.buttonDelete->setHidden(true);
371 ui.buttonAdd->setHidden(true);
372 ui.spinTransp->setMaximum(500);
373 ui.label_pos->setHidden(true);
374 m_helper->setHidden(true);
375 ui.spinPos->setHidden(true);
377 char *tmp = (char *) qstrdup(val.toUtf8().data());
378 if (m_geom) m_geom->parse(tmp, maxFrame - minFrame, m_profile.width, m_profile.height);
379 else m_geom = new Mlt::Geometry(tmp, maxFrame - minFrame, m_profile.width, m_profile.height);
382 //kDebug() << " / / UPDATING TRANSITION VALUE: " << m_geom->serialise();
383 //read param her and set rect
385 m_helper->setKeyGeometry(m_geom, maxFrame - minFrame - 1);
388 doc.appendChild(doc.importNode(par, true));
389 kDebug() << "IMPORTED TRANS: " << doc.toString();*/
390 ui.spinPos->setMaximum(maxFrame - minFrame - 1);
391 if (m_path == NULL) {
392 m_path = new QGraphicsPathItem();
393 m_path->setPen(QPen(Qt::red));
394 scene->addItem(m_path);
396 updateTransitionPath();
398 Mlt::GeometryItem item;
400 m_geom->fetch(&item, 0);
401 if (paramRect) delete paramRect;
402 paramRect = new QGraphicsRectItem(QRectF(0, 0, item.w(), item.h()));
403 paramRect->setPos(item.x(), item.y());
404 paramRect->setZValue(0);
406 paramRect->setPen(QPen(QBrush(QColor(255, 0, 0, 255)), 1.0));
407 scene->addItem(paramRect);
408 slotPositionChanged(0, false);
410 connect(ui.spinPos, SIGNAL(valueChanged(int)), this , SLOT(slotPositionChanged(int)));
412 connect(ui.spinTransp, SIGNAL(valueChanged(int)), this , SLOT(slotTransparencyChanged(int)));
415 void Geometryval::updateTransitionPath()
417 if (m_fixedMode) return;
418 Mlt::GeometryItem item;
423 if (m_geom->next_key(&item, pos) == 1) break;
426 path.moveTo(item.x() + item.w() / 2, item.y() + item.h() / 2);
428 path.lineTo(item.x() + item.w() / 2, item.y() + item.h() / 2);
433 m_path->setPath(path);
436 void Geometryval::slotUpdateTransitionProperties()
438 int pos = ui.spinPos->value();
439 Mlt::GeometryItem item;
440 int error = m_geom->next_key(&item, pos);
441 if (error || item.frame() != pos) {
442 // no keyframe under cursor
445 item.x(paramRect->pos().x());
446 item.y(paramRect->pos().y());
447 item.w(paramRect->rect().width());
448 item.h(paramRect->rect().height());
449 m_geom->insert(item);
450 updateTransitionPath();
451 emit parameterChanged();