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) :
39 QVBoxLayout* vbox = new QVBoxLayout(ui.widget);
40 QGraphicsView *view = new QGraphicsView(this);
41 view->setBackgroundBrush(QBrush(Qt::black));
42 vbox->addWidget(view);
43 vbox->setContentsMargins(0, 0, 0, 0);
45 QVBoxLayout* vbox2 = new QVBoxLayout(ui.keyframeWidget);
46 m_helper = new KeyframeHelper(this);
47 vbox2->addWidget(m_helper);
48 vbox2->setContentsMargins(0, 0, 0, 0);
50 connect(m_helper, SIGNAL(positionChanged(int)), this, SLOT(slotPositionChanged(int)));
52 scene = new GraphicsSceneRectMove(this);
53 scene->setTool(TITLE_SELECT);
54 view->setScene(scene);
55 QGraphicsRectItem *m_frameBorder = new QGraphicsRectItem(QRectF(0, 0, profile.width, profile.height));
56 m_frameBorder->setZValue(-1100);
57 m_frameBorder->setBrush(QColor(255, 255, 0, 30));
58 m_frameBorder->setPen(QPen(QBrush(QColor(255, 255, 255, 255)), 1.0, Qt::DashLine));
59 scene->addItem(m_frameBorder);
61 ui.buttonNext->setIcon(KIcon("media-skip-forward"));
62 ui.buttonNext->setToolTip(i18n("Go to next keyframe"));
63 ui.buttonPrevious->setIcon(KIcon("media-skip-backward"));
64 ui.buttonPrevious->setToolTip(i18n("Go to previous keyframe"));
65 ui.buttonAdd->setIcon(KIcon("document-new"));
66 ui.buttonAdd->setToolTip(i18n("Add keyframe"));
67 ui.buttonDelete->setIcon(KIcon("edit-delete"));
68 ui.buttonDelete->setToolTip(i18n("Delete keyframe"));
70 QMenu *configMenu = new QMenu(i18n("Misc..."), this);
71 ui.buttonMenu->setIcon(KIcon("system-run"));
72 ui.buttonMenu->setMenu(configMenu);
73 ui.buttonMenu->setPopupMode(QToolButton::QToolButton::InstantPopup);
76 m_scaleMenu = new QMenu(i18n("Resize..."), this);
77 configMenu->addMenu(m_scaleMenu);
78 m_scaleMenu->addAction(i18n("50%"), this, SLOT(slotResize50()));
79 m_scaleMenu->addAction(i18n("100%"), this, SLOT(slotResize100()));
80 m_scaleMenu->addAction(i18n("200%"), this, SLOT(slotResize200()));
83 m_alignMenu = new QMenu(i18n("Align..."), this);
84 configMenu->addMenu(m_alignMenu);
85 m_alignMenu->addAction(i18n("Center"), this, SLOT(slotAlignCenter()));
86 m_alignMenu->addAction(i18n("Hor. Center"), this, SLOT(slotAlignHCenter()));
87 m_alignMenu->addAction(i18n("Vert. Center"), this, SLOT(slotAlignVCenter()));
88 m_alignMenu->addAction(i18n("Right"), this, SLOT(slotAlignRight()));
89 m_alignMenu->addAction(i18n("Left"), this, SLOT(slotAlignLeft()));
90 m_alignMenu->addAction(i18n("Top"), this, SLOT(slotAlignTop()));
91 m_alignMenu->addAction(i18n("Bottom"), this, SLOT(slotAlignBottom()));
94 m_syncAction = configMenu->addAction(i18n("Sync timeline cursor"), this, SLOT(slotSyncCursor()));
95 m_syncAction->setCheckable(true);
96 m_syncAction->setChecked(KdenliveSettings::transitionfollowcursor());
98 //scene->setSceneRect(0, 0, profile.width * 2, profile.height * 2);
99 //view->fitInView(m_frameBorder, Qt::KeepAspectRatio);
100 const double sc = 100.0 / profile.height * 0.8;
101 QRectF srect = view->sceneRect();
102 view->setSceneRect(srect.x(), -srect.height() / 3 + 10, srect.width(), srect.height() + srect.height() / 3 * 2 - 10);
104 view->centerOn(m_frameBorder);
105 connect(ui.buttonNext , SIGNAL(clicked()) , this , SLOT(slotNextFrame()));
106 connect(ui.buttonPrevious , SIGNAL(clicked()) , this , SLOT(slotPreviousFrame()));
107 connect(ui.buttonDelete , SIGNAL(clicked()) , this , SLOT(slotDeleteFrame()));
108 connect(ui.buttonAdd , SIGNAL(clicked()) , this , SLOT(slotAddFrame()));
109 connect(scene, SIGNAL(actionFinished()), this, SLOT(slotUpdateTransitionProperties()));
112 void Geometryval::slotAlignCenter()
114 int pos = ui.spinPos->value();
115 Mlt::GeometryItem item;
116 int error = m_geom->fetch(&item, pos);
117 if (error || item.key() == false) {
118 // no keyframe under cursor
121 paramRect->setPos((m_profile.width - paramRect->rect().width()) / 2, (m_profile.height - paramRect->rect().height()) / 2);
122 slotUpdateTransitionProperties();
125 void Geometryval::slotAlignHCenter()
127 int pos = ui.spinPos->value();
128 Mlt::GeometryItem item;
129 int error = m_geom->fetch(&item, pos);
130 if (error || item.key() == false) {
131 // no keyframe under cursor
134 paramRect->setPos((m_profile.width - paramRect->rect().width()) / 2, paramRect->pos().y());
135 slotUpdateTransitionProperties();
138 void Geometryval::slotAlignVCenter()
140 int pos = ui.spinPos->value();
141 Mlt::GeometryItem item;
142 int error = m_geom->fetch(&item, pos);
143 if (error || item.key() == false) {
144 // no keyframe under cursor
147 paramRect->setPos(paramRect->pos().x(), (m_profile.height - paramRect->rect().height()) / 2);
148 slotUpdateTransitionProperties();
151 void Geometryval::slotAlignTop()
153 int pos = ui.spinPos->value();
154 Mlt::GeometryItem item;
155 int error = m_geom->fetch(&item, pos);
156 if (error || item.key() == false) {
157 // no keyframe under cursor
160 paramRect->setPos(paramRect->pos().x(), 0);
161 slotUpdateTransitionProperties();
164 void Geometryval::slotAlignBottom()
166 int pos = ui.spinPos->value();
167 Mlt::GeometryItem item;
168 int error = m_geom->fetch(&item, pos);
169 if (error || item.key() == false) {
170 // no keyframe under cursor
173 paramRect->setPos(paramRect->pos().x(), m_profile.height - paramRect->rect().height());
174 slotUpdateTransitionProperties();
177 void Geometryval::slotAlignLeft()
179 int pos = ui.spinPos->value();
180 Mlt::GeometryItem item;
181 int error = m_geom->fetch(&item, pos);
182 if (error || item.key() == false) {
183 // no keyframe under cursor
186 paramRect->setPos(0, paramRect->pos().y());
187 slotUpdateTransitionProperties();
190 void Geometryval::slotAlignRight()
192 int pos = ui.spinPos->value();
193 Mlt::GeometryItem item;
194 int error = m_geom->fetch(&item, pos);
195 if (error || item.key() == false) {
196 // no keyframe under cursor
199 paramRect->setPos(m_profile.width - paramRect->rect().width(), paramRect->pos().y());
200 slotUpdateTransitionProperties();
203 void Geometryval::slotResize50()
205 int pos = ui.spinPos->value();
206 Mlt::GeometryItem item;
207 int error = m_geom->fetch(&item, pos);
208 if (error || item.key() == false) {
209 // no keyframe under cursor
212 paramRect->setRect(0, 0, m_profile.width / 2, m_profile.height / 2);
213 slotUpdateTransitionProperties();
216 void Geometryval::slotResize100()
218 int pos = ui.spinPos->value();
219 Mlt::GeometryItem item;
220 int error = m_geom->fetch(&item, pos);
221 if (error || item.key() == false) {
222 // no keyframe under cursor
225 paramRect->setRect(0, 0, m_profile.width, m_profile.height);
226 slotUpdateTransitionProperties();
229 void Geometryval::slotResize200()
231 int pos = ui.spinPos->value();
232 Mlt::GeometryItem item;
233 int error = m_geom->fetch(&item, pos);
234 if (error || item.key() == false) {
235 // no keyframe under cursor
238 paramRect->setRect(0, 0, m_profile.width * 2, m_profile.height * 2);
239 slotUpdateTransitionProperties();
242 void Geometryval::slotTransparencyChanged(int transp)
244 int pos = ui.spinPos->value();
245 Mlt::GeometryItem item;
246 int error = m_geom->fetch(&item, pos);
247 if (error || item.key() == false) {
248 // no keyframe under cursor
252 paramRect->setBrush(QColor(255, 0, 0, transp));
253 m_geom->insert(item);
254 emit parameterChanged();
257 void Geometryval::slotSyncCursor()
259 KdenliveSettings::setTransitionfollowcursor(m_syncAction->isChecked());
262 void Geometryval::slotPositionChanged(int pos, bool seek)
264 if (seek && KdenliveSettings::transitionfollowcursor()) emit seekToPos(pos);
265 ui.spinPos->setValue(pos);
266 m_helper->setValue(pos);
267 Mlt::GeometryItem item;
268 int error = m_geom->fetch(&item, pos);
269 if (error || item.key() == false) {
270 // no keyframe under cursor, adjust buttons
271 ui.buttonAdd->setEnabled(true);
272 ui.buttonDelete->setEnabled(false);
273 ui.widget->setEnabled(false);
274 ui.spinTransp->setEnabled(false);
275 m_scaleMenu->setEnabled(false);
276 m_alignMenu->setEnabled(false);
278 ui.buttonAdd->setEnabled(false);
279 ui.buttonDelete->setEnabled(true);
280 ui.widget->setEnabled(true);
281 ui.spinTransp->setEnabled(true);
282 m_scaleMenu->setEnabled(true);
283 m_alignMenu->setEnabled(true);
285 paramRect->setPos(item.x(), item.y());
286 paramRect->setRect(0, 0, item.w(), item.h());
287 ui.spinTransp->setValue(item.mix());
288 paramRect->setBrush(QColor(255, 0, 0, item.mix()));
291 void Geometryval::slotDeleteFrame()
293 // check there is more than one keyframe
294 Mlt::GeometryItem item;
295 const int pos = ui.spinPos->value();
296 int error = m_geom->next_key(&item, pos + 1);
298 error = m_geom->prev_key(&item, pos - 1);
299 if (error || item.frame() == pos) return;
302 m_geom->remove(ui.spinPos->value());
303 ui.buttonAdd->setEnabled(true);
304 ui.buttonDelete->setEnabled(false);
305 ui.widget->setEnabled(false);
306 ui.spinTransp->setEnabled(false);
307 m_scaleMenu->setEnabled(false);
308 m_alignMenu->setEnabled(false);
310 slotPositionChanged(pos, false);
311 updateTransitionPath();
312 emit parameterChanged();
315 void Geometryval::slotAddFrame()
317 int pos = ui.spinPos->value();
318 Mlt::GeometryItem item;
320 item.x(paramRect->pos().x());
321 item.y(paramRect->pos().y());
322 item.w(paramRect->rect().width());
323 item.h(paramRect->rect().height());
324 item.mix(ui.spinTransp->value());
325 m_geom->insert(item);
326 ui.buttonAdd->setEnabled(false);
327 ui.buttonDelete->setEnabled(true);
328 ui.widget->setEnabled(true);
329 ui.spinTransp->setEnabled(true);
330 m_scaleMenu->setEnabled(true);
331 m_alignMenu->setEnabled(true);
333 emit parameterChanged();
336 void Geometryval::slotNextFrame()
338 Mlt::GeometryItem item;
339 int error = m_geom->next_key(&item, m_helper->value() + 1);
340 kDebug() << "// SEEK TO NEXT KFR: " << error;
343 ui.spinPos->setValue(ui.spinPos->maximum());
346 int pos = item.frame();
347 ui.spinPos->setValue(pos);
350 void Geometryval::slotPreviousFrame()
352 Mlt::GeometryItem item;
353 int error = m_geom->prev_key(&item, m_helper->value() - 1);
354 kDebug() << "// SEEK TO NEXT KFR: " << error;
356 int pos = item.frame();
357 ui.spinPos->setValue(pos);
361 QDomElement Geometryval::getParamDesc()
363 param.setAttribute("value", m_geom->serialise());
364 kDebug() << " / / UPDATING TRANSITION VALUE: " << param.attribute("value");
368 void Geometryval::setupParam(const QDomElement& par, int minFrame, int maxFrame)
371 QString val = par.attribute("value");
372 if (par.attribute("fixed") == "1") {
374 ui.buttonPrevious->setHidden(true);
375 ui.buttonNext->setHidden(true);
376 ui.buttonDelete->setHidden(true);
377 ui.buttonAdd->setHidden(true);
378 ui.spinTransp->setMaximum(500);
379 ui.label_pos->setHidden(true);
380 m_helper->setHidden(true);
381 ui.spinPos->setHidden(true);
383 char *tmp = (char *) qstrdup(val.toUtf8().data());
384 if (m_geom) m_geom->parse(tmp, maxFrame - minFrame, m_profile.width, m_profile.height);
385 else m_geom = new Mlt::Geometry(tmp, maxFrame - minFrame, m_profile.width, m_profile.height);
388 //kDebug() << " / / UPDATING TRANSITION VALUE: " << m_geom->serialise();
389 //read param her and set rect
391 m_helper->setKeyGeometry(m_geom, maxFrame - minFrame - 1);
394 doc.appendChild(doc.importNode(par, true));
395 kDebug() << "IMPORTED TRANS: " << doc.toString();*/
396 ui.spinPos->setMaximum(maxFrame - minFrame - 1);
397 if (m_path == NULL) {
398 m_path = new QGraphicsPathItem();
399 m_path->setPen(QPen(Qt::red));
400 scene->addItem(m_path);
402 updateTransitionPath();
404 Mlt::GeometryItem item;
406 m_geom->fetch(&item, 0);
407 if (paramRect) delete paramRect;
408 paramRect = new QGraphicsRectItem(QRectF(0, 0, item.w(), item.h()));
409 paramRect->setPos(item.x(), item.y());
410 paramRect->setZValue(0);
412 paramRect->setPen(QPen(QBrush(QColor(255, 0, 0, 255)), 1.0));
413 scene->addItem(paramRect);
414 slotPositionChanged(0, false);
416 connect(ui.spinPos, SIGNAL(valueChanged(int)), this , SLOT(slotPositionChanged(int)));
418 connect(ui.spinTransp, SIGNAL(valueChanged(int)), this , SLOT(slotTransparencyChanged(int)));
421 void Geometryval::updateTransitionPath()
423 if (m_fixedMode) return;
424 Mlt::GeometryItem item;
429 if (m_geom->next_key(&item, pos) == 1) break;
432 path.moveTo(item.x() + item.w() / 2, item.y() + item.h() / 2);
434 path.lineTo(item.x() + item.w() / 2, item.y() + item.h() / 2);
439 m_path->setPath(path);
442 void Geometryval::slotUpdateTransitionProperties()
444 int pos = ui.spinPos->value();
445 Mlt::GeometryItem item;
446 int error = m_geom->next_key(&item, pos);
447 if (error || item.frame() != pos) {
448 // no keyframe under cursor
451 item.x(paramRect->pos().x());
452 item.y(paramRect->pos().y());
453 item.w(paramRect->rect().width());
454 item.h(paramRect->rect().height());
455 m_geom->insert(item);
456 updateTransitionPath();
457 emit parameterChanged();