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) {
32 QVBoxLayout* vbox = new QVBoxLayout(ui.widget);
33 QGraphicsView *view = new QGraphicsView(this);
34 view->setBackgroundBrush(QBrush(Qt::black));
35 vbox->addWidget(view);
36 vbox->setContentsMargins(0, 0, 0, 0);
38 QVBoxLayout* vbox2 = new QVBoxLayout(ui.keyframeWidget);
39 m_helper = new KeyframeHelper(this);
40 vbox2->addWidget(m_helper);
41 vbox2->setContentsMargins(0, 0, 0, 0);
43 connect(m_helper, SIGNAL(positionChanged(int)), this, SLOT(slotPositionChanged(int)));
45 scene = new GraphicsSceneRectMove(this);
46 scene->setTool(TITLE_SELECT);
47 view->setScene(scene);
48 QGraphicsRectItem *m_frameBorder = new QGraphicsRectItem(QRectF(0, 0, profile.width, profile.height));
49 m_frameBorder->setZValue(-1100);
50 m_frameBorder->setBrush(QColor(255, 255, 0, 30));
51 m_frameBorder->setPen(QPen(QBrush(QColor(255, 255, 255, 255)), 1.0, Qt::DashLine));
52 scene->addItem(m_frameBorder);
54 ui.buttonNext->setIcon(KIcon("media-skip-forward"));
55 ui.buttonNext->setToolTip(i18n("Go to next keyframe"));
56 ui.buttonPrevious->setIcon(KIcon("media-skip-backward"));
57 ui.buttonPrevious->setToolTip(i18n("Go to previous keyframe"));
58 ui.buttonAdd->setIcon(KIcon("document-new"));
59 ui.buttonAdd->setToolTip(i18n("Add keyframe"));
60 ui.buttonDelete->setIcon(KIcon("edit-delete"));
61 ui.buttonDelete->setToolTip(i18n("Delete keyframe"));
63 QMenu *configMenu = new QMenu(i18n("Misc..."), this);
64 ui.buttonMenu->setIcon(KIcon("system-run"));
65 ui.buttonMenu->setMenu(configMenu);
66 ui.buttonMenu->setPopupMode(QToolButton::QToolButton::InstantPopup);
69 m_scaleMenu = new QMenu(i18n("Resize..."), this);
70 configMenu->addMenu(m_scaleMenu);
71 m_scaleMenu->addAction(i18n("50%"), this, SLOT(slotResize50()));
72 m_scaleMenu->addAction(i18n("100%"), this, SLOT(slotResize100()));
73 m_scaleMenu->addAction(i18n("200%"), this, SLOT(slotResize200()));
76 m_alignMenu = new QMenu(i18n("Align..."), this);
77 configMenu->addMenu(m_alignMenu);
78 m_alignMenu->addAction(i18n("Center"), this, SLOT(slotAlignCenter()));
79 m_alignMenu->addAction(i18n("Hor. Center"), this, SLOT(slotAlignHCenter()));
80 m_alignMenu->addAction(i18n("Vert. Center"), this, SLOT(slotAlignVCenter()));
81 m_alignMenu->addAction(i18n("Right"), this, SLOT(slotAlignRight()));
82 m_alignMenu->addAction(i18n("Left"), this, SLOT(slotAlignLeft()));
83 m_alignMenu->addAction(i18n("Top"), this, SLOT(slotAlignTop()));
84 m_alignMenu->addAction(i18n("Bottom"), this, SLOT(slotAlignBottom()));
87 m_syncAction = configMenu->addAction(i18n("Sync timeline cursor"), this, SLOT(slotSyncCursor()));
88 m_syncAction->setCheckable(true);
89 m_syncAction->setChecked(KdenliveSettings::transitionfollowcursor());
91 //scene->setSceneRect(0, 0, profile.width * 2, profile.height * 2);
92 //view->fitInView(m_frameBorder, Qt::KeepAspectRatio);
93 const double sc = 100.0 / profile.height * 0.8;
94 QRectF srect = view->sceneRect();
95 view->setSceneRect(srect.x(), -srect.height() / 3 + 10, srect.width(), srect.height() + srect.height() / 3 * 2 - 10);
97 view->centerOn(m_frameBorder);
98 connect(ui.buttonNext , SIGNAL(clicked()) , this , SLOT(slotNextFrame()));
99 connect(ui.buttonPrevious , SIGNAL(clicked()) , this , SLOT(slotPreviousFrame()));
100 connect(ui.buttonDelete , SIGNAL(clicked()) , this , SLOT(slotDeleteFrame()));
101 connect(ui.buttonAdd , SIGNAL(clicked()) , this , SLOT(slotAddFrame()));
102 connect(scene, SIGNAL(actionFinished()), this, SLOT(slotUpdateTransitionProperties()));
105 void Geometryval::slotAlignCenter() {
106 int pos = ui.spinPos->value();
107 Mlt::GeometryItem item;
108 int error = m_geom->fetch(&item, pos);
109 if (error || item.key() == false) {
110 // no keyframe under cursor
113 paramRect->setPos((m_profile.width - paramRect->rect().width()) / 2, (m_profile.height - paramRect->rect().height()) / 2);
114 slotUpdateTransitionProperties();
117 void Geometryval::slotAlignHCenter() {
118 int pos = ui.spinPos->value();
119 Mlt::GeometryItem item;
120 int error = m_geom->fetch(&item, pos);
121 if (error || item.key() == false) {
122 // no keyframe under cursor
125 paramRect->setPos((m_profile.width - paramRect->rect().width()) / 2, paramRect->pos().y());
126 slotUpdateTransitionProperties();
129 void Geometryval::slotAlignVCenter() {
130 int pos = ui.spinPos->value();
131 Mlt::GeometryItem item;
132 int error = m_geom->fetch(&item, pos);
133 if (error || item.key() == false) {
134 // no keyframe under cursor
137 paramRect->setPos(paramRect->pos().x(), (m_profile.height - paramRect->rect().height()) / 2);
138 slotUpdateTransitionProperties();
141 void Geometryval::slotAlignTop() {
142 int pos = ui.spinPos->value();
143 Mlt::GeometryItem item;
144 int error = m_geom->fetch(&item, pos);
145 if (error || item.key() == false) {
146 // no keyframe under cursor
149 paramRect->setPos(paramRect->pos().x(), 0);
150 slotUpdateTransitionProperties();
153 void Geometryval::slotAlignBottom() {
154 int pos = ui.spinPos->value();
155 Mlt::GeometryItem item;
156 int error = m_geom->fetch(&item, pos);
157 if (error || item.key() == false) {
158 // no keyframe under cursor
161 paramRect->setPos(paramRect->pos().x(), m_profile.height - paramRect->rect().height());
162 slotUpdateTransitionProperties();
165 void Geometryval::slotAlignLeft() {
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(0, paramRect->pos().y());
174 slotUpdateTransitionProperties();
177 void Geometryval::slotAlignRight() {
178 int pos = ui.spinPos->value();
179 Mlt::GeometryItem item;
180 int error = m_geom->fetch(&item, pos);
181 if (error || item.key() == false) {
182 // no keyframe under cursor
185 paramRect->setPos(m_profile.width - paramRect->rect().width(), paramRect->pos().y());
186 slotUpdateTransitionProperties();
189 void Geometryval::slotResize50() {
190 int pos = ui.spinPos->value();
191 Mlt::GeometryItem item;
192 int error = m_geom->fetch(&item, pos);
193 if (error || item.key() == false) {
194 // no keyframe under cursor
197 paramRect->setRect(0, 0, m_profile.width / 2, m_profile.height / 2);
198 slotUpdateTransitionProperties();
201 void Geometryval::slotResize100() {
202 int pos = ui.spinPos->value();
203 Mlt::GeometryItem item;
204 int error = m_geom->fetch(&item, pos);
205 if (error || item.key() == false) {
206 // no keyframe under cursor
209 paramRect->setRect(0, 0, m_profile.width, m_profile.height);
210 slotUpdateTransitionProperties();
213 void Geometryval::slotResize200() {
214 int pos = ui.spinPos->value();
215 Mlt::GeometryItem item;
216 int error = m_geom->fetch(&item, pos);
217 if (error || item.key() == false) {
218 // no keyframe under cursor
221 paramRect->setRect(0, 0, m_profile.width * 2, m_profile.height * 2);
222 slotUpdateTransitionProperties();
225 void Geometryval::slotTransparencyChanged(int transp) {
226 int pos = ui.spinPos->value();
227 Mlt::GeometryItem item;
228 int error = m_geom->fetch(&item, pos);
229 if (error || item.key() == false) {
230 // no keyframe under cursor
234 paramRect->setBrush(QColor(255, 0, 0, transp));
235 m_geom->insert(item);
236 emit parameterChanged();
239 void Geometryval::slotSyncCursor() {
240 KdenliveSettings::setTransitionfollowcursor(m_syncAction->isChecked());
243 void Geometryval::slotPositionChanged(int pos, bool seek) {
244 if (seek && KdenliveSettings::transitionfollowcursor()) emit seekToPos(pos);
245 ui.spinPos->setValue(pos);
246 m_helper->setValue(pos);
247 Mlt::GeometryItem item;
248 int error = m_geom->fetch(&item, pos);
249 if (error || item.key() == false) {
250 // no keyframe under cursor, adjust buttons
251 ui.buttonAdd->setEnabled(true);
252 ui.buttonDelete->setEnabled(false);
253 ui.widget->setEnabled(false);
254 ui.spinTransp->setEnabled(false);
255 m_scaleMenu->setEnabled(false);
256 m_alignMenu->setEnabled(false);
258 ui.buttonAdd->setEnabled(false);
259 ui.buttonDelete->setEnabled(true);
260 ui.widget->setEnabled(true);
261 ui.spinTransp->setEnabled(true);
262 m_scaleMenu->setEnabled(true);
263 m_alignMenu->setEnabled(true);
265 paramRect->setPos(item.x(), item.y());
266 paramRect->setRect(0, 0, item.w(), item.h());
267 ui.spinTransp->setValue(item.mix());
268 paramRect->setBrush(QColor(255, 0, 0, item.mix()));
271 void Geometryval::slotDeleteFrame() {
272 // check there is more than one keyframe
273 Mlt::GeometryItem item;
274 const int pos = ui.spinPos->value();
275 int error = m_geom->next_key(&item, pos + 1);
277 error = m_geom->prev_key(&item, pos - 1);
278 if (error || item.frame() == pos) return;
281 m_geom->remove(ui.spinPos->value());
282 ui.buttonAdd->setEnabled(true);
283 ui.buttonDelete->setEnabled(false);
284 ui.widget->setEnabled(false);
285 ui.spinTransp->setEnabled(false);
286 m_scaleMenu->setEnabled(false);
287 m_alignMenu->setEnabled(false);
289 slotPositionChanged(pos, false);
290 updateTransitionPath();
291 emit parameterChanged();
294 void Geometryval::slotAddFrame() {
295 int pos = ui.spinPos->value();
296 Mlt::GeometryItem item;
298 item.x(paramRect->pos().x());
299 item.y(paramRect->pos().y());
300 item.w(paramRect->rect().width());
301 item.h(paramRect->rect().height());
302 item.mix(ui.spinTransp->value());
303 m_geom->insert(item);
304 ui.buttonAdd->setEnabled(false);
305 ui.buttonDelete->setEnabled(true);
306 ui.widget->setEnabled(true);
307 ui.spinTransp->setEnabled(true);
308 m_scaleMenu->setEnabled(true);
309 m_alignMenu->setEnabled(true);
311 emit parameterChanged();
314 void Geometryval::slotNextFrame() {
315 Mlt::GeometryItem item;
316 int error = m_geom->next_key(&item, m_helper->value() + 1);
317 kDebug() << "// SEEK TO NEXT KFR: " << error;
320 ui.spinPos->setValue(ui.spinPos->maximum());
323 int pos = item.frame();
324 ui.spinPos->setValue(pos);
327 void Geometryval::slotPreviousFrame() {
328 Mlt::GeometryItem item;
329 int error = m_geom->prev_key(&item, m_helper->value() - 1);
330 kDebug() << "// SEEK TO NEXT KFR: " << error;
332 int pos = item.frame();
333 ui.spinPos->setValue(pos);
337 QDomElement Geometryval::getParamDesc() {
338 param.setAttribute("value", m_geom->serialise());
339 kDebug() << " / / UPDATING TRANSITION VALUE: " << param.attribute("value");
343 void Geometryval::setupParam(const QDomElement& par, int minFrame, int maxFrame) {
345 QString val = par.attribute("value");
346 if (par.attribute("fixed") == "1") {
348 ui.buttonPrevious->setHidden(true);
349 ui.buttonNext->setHidden(true);
350 ui.buttonDelete->setHidden(true);
351 ui.buttonAdd->setHidden(true);
352 ui.spinTransp->setMaximum(500);
353 ui.label_pos->setHidden(true);
354 m_helper->setHidden(true);
355 ui.spinPos->setHidden(true);
357 char *tmp = (char *) qstrdup(val.toUtf8().data());
358 if (m_geom) m_geom->parse(tmp, maxFrame - minFrame, m_profile.width, m_profile.height);
359 else m_geom = new Mlt::Geometry(tmp, maxFrame - minFrame, m_profile.width, m_profile.height);
362 //kDebug() << " / / UPDATING TRANSITION VALUE: " << m_geom->serialise();
363 //read param her and set rect
365 m_helper->setKeyGeometry(m_geom, maxFrame - minFrame - 1);
368 doc.appendChild(doc.importNode(par, true));
369 kDebug() << "IMPORTED TRANS: " << doc.toString();*/
370 ui.spinPos->setMaximum(maxFrame - minFrame - 1);
371 if (m_path == NULL) {
372 m_path = new QGraphicsPathItem();
373 m_path->setPen(QPen(Qt::red));
374 scene->addItem(m_path);
376 updateTransitionPath();
378 Mlt::GeometryItem item;
380 m_geom->fetch(&item, 0);
381 if (paramRect) delete paramRect;
382 paramRect = new QGraphicsRectItem(QRectF(0, 0, item.w(), item.h()));
383 paramRect->setPos(item.x(), item.y());
384 paramRect->setZValue(0);
386 paramRect->setPen(QPen(QBrush(QColor(255, 0, 0, 255)), 1.0));
387 scene->addItem(paramRect);
388 slotPositionChanged(0, false);
390 connect(ui.spinPos, SIGNAL(valueChanged(int)), this , SLOT(slotPositionChanged(int)));
392 connect(ui.spinTransp, SIGNAL(valueChanged(int)), this , SLOT(slotTransparencyChanged(int)));
395 void Geometryval::updateTransitionPath() {
396 if (m_fixedMode) return;
397 Mlt::GeometryItem item;
402 if (m_geom->next_key(&item, pos) == 1) break;
405 path.moveTo(item.x() + item.w() / 2, item.y() + item.h() / 2);
407 path.lineTo(item.x() + item.w() / 2, item.y() + item.h() / 2);
412 m_path->setPath(path);
415 void Geometryval::slotUpdateTransitionProperties() {
416 int pos = ui.spinPos->value();
417 Mlt::GeometryItem item;
418 int error = m_geom->next_key(&item, pos);
419 if (error || item.frame() != pos) {
420 // no keyframe under cursor
423 item.x(paramRect->pos().x());
424 item.y(paramRect->pos().y());
425 item.w(paramRect->rect().width());
426 item.h(paramRect->rect().height());
427 m_geom->insert(item);
428 updateTransitionPath();
429 emit parameterChanged();