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 double aspect = (double) profile.sample_aspect_num / profile.sample_aspect_den * profile.width / profile.height;
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() {
107 int pos = ui.spinPos->value();
108 Mlt::GeometryItem item;
109 int error = m_geom->fetch(&item, pos);
110 if (error || item.key() == false) {
111 // no keyframe under cursor
114 paramRect->setPos((m_profile.width - paramRect->rect().width()) / 2, (m_profile.height - paramRect->rect().height()) / 2);
115 slotUpdateTransitionProperties();
118 void Geometryval::slotAlignHCenter() {
119 int pos = ui.spinPos->value();
120 Mlt::GeometryItem item;
121 int error = m_geom->fetch(&item, pos);
122 if (error || item.key() == false) {
123 // no keyframe under cursor
126 paramRect->setPos((m_profile.width - paramRect->rect().width()) / 2, paramRect->pos().y());
127 slotUpdateTransitionProperties();
130 void Geometryval::slotAlignVCenter() {
131 int pos = ui.spinPos->value();
132 Mlt::GeometryItem item;
133 int error = m_geom->fetch(&item, pos);
134 if (error || item.key() == false) {
135 // no keyframe under cursor
138 paramRect->setPos(paramRect->pos().x(), (m_profile.height - paramRect->rect().height()) / 2);
139 slotUpdateTransitionProperties();
142 void Geometryval::slotAlignTop() {
143 int pos = ui.spinPos->value();
144 Mlt::GeometryItem item;
145 int error = m_geom->fetch(&item, pos);
146 if (error || item.key() == false) {
147 // no keyframe under cursor
150 paramRect->setPos(paramRect->pos().x(), 0);
151 slotUpdateTransitionProperties();
154 void Geometryval::slotAlignBottom() {
155 int pos = ui.spinPos->value();
156 Mlt::GeometryItem item;
157 int error = m_geom->fetch(&item, pos);
158 if (error || item.key() == false) {
159 // no keyframe under cursor
162 paramRect->setPos(paramRect->pos().x(), m_profile.height - paramRect->rect().height());
163 slotUpdateTransitionProperties();
166 void Geometryval::slotAlignLeft() {
167 int pos = ui.spinPos->value();
168 Mlt::GeometryItem item;
169 int error = m_geom->fetch(&item, pos);
170 if (error || item.key() == false) {
171 // no keyframe under cursor
174 paramRect->setPos(0, paramRect->pos().y());
175 slotUpdateTransitionProperties();
178 void Geometryval::slotAlignRight() {
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(m_profile.width - paramRect->rect().width(), paramRect->pos().y());
187 slotUpdateTransitionProperties();
190 void Geometryval::slotResize50() {
191 int pos = ui.spinPos->value();
192 Mlt::GeometryItem item;
193 int error = m_geom->fetch(&item, pos);
194 if (error || item.key() == false) {
195 // no keyframe under cursor
198 paramRect->setRect(0, 0, m_profile.width / 2, m_profile.height / 2);
199 slotUpdateTransitionProperties();
202 void Geometryval::slotResize100() {
203 int pos = ui.spinPos->value();
204 Mlt::GeometryItem item;
205 int error = m_geom->fetch(&item, pos);
206 if (error || item.key() == false) {
207 // no keyframe under cursor
210 paramRect->setRect(0, 0, m_profile.width, m_profile.height);
211 slotUpdateTransitionProperties();
214 void Geometryval::slotResize200() {
215 int pos = ui.spinPos->value();
216 Mlt::GeometryItem item;
217 int error = m_geom->fetch(&item, pos);
218 if (error || item.key() == false) {
219 // no keyframe under cursor
222 paramRect->setRect(0, 0, m_profile.width * 2, m_profile.height * 2);
223 slotUpdateTransitionProperties();
226 void Geometryval::slotTransparencyChanged(int transp) {
227 int pos = ui.spinPos->value();
228 Mlt::GeometryItem item;
229 int error = m_geom->fetch(&item, pos);
230 if (error || item.key() == false) {
231 // no keyframe under cursor
235 paramRect->setBrush(QColor(255, 0, 0, transp));
236 m_geom->insert(item);
237 emit parameterChanged();
240 void Geometryval::slotSyncCursor() {
241 KdenliveSettings::setTransitionfollowcursor(m_syncAction->isChecked());
244 void Geometryval::slotPositionChanged(int pos, bool seek) {
245 if (seek && KdenliveSettings::transitionfollowcursor()) emit seekToPos(pos);
246 ui.spinPos->setValue(pos);
247 m_helper->setValue(pos);
248 Mlt::GeometryItem item;
249 int error = m_geom->fetch(&item, pos);
250 if (error || item.key() == false) {
251 // no keyframe under cursor, adjust buttons
252 ui.buttonAdd->setEnabled(true);
253 ui.buttonDelete->setEnabled(false);
254 ui.widget->setEnabled(false);
255 ui.spinTransp->setEnabled(false);
256 m_scaleMenu->setEnabled(false);
257 m_alignMenu->setEnabled(false);
259 ui.buttonAdd->setEnabled(false);
260 ui.buttonDelete->setEnabled(true);
261 ui.widget->setEnabled(true);
262 ui.spinTransp->setEnabled(true);
263 m_scaleMenu->setEnabled(true);
264 m_alignMenu->setEnabled(true);
266 paramRect->setPos(item.x(), item.y());
267 paramRect->setRect(0, 0, item.w(), item.h());
268 ui.spinTransp->setValue(item.mix());
269 paramRect->setBrush(QColor(255, 0, 0, item.mix()));
272 void Geometryval::slotDeleteFrame() {
273 // check there is more than one keyframe
274 Mlt::GeometryItem item;
275 const int pos = ui.spinPos->value();
276 int error = m_geom->next_key(&item, pos + 1);
278 error = m_geom->prev_key(&item, pos - 1);
279 if (error || item.frame() == pos) return;
282 m_geom->remove(ui.spinPos->value());
283 ui.buttonAdd->setEnabled(true);
284 ui.buttonDelete->setEnabled(false);
285 ui.widget->setEnabled(false);
286 ui.spinTransp->setEnabled(false);
287 m_scaleMenu->setEnabled(false);
288 m_alignMenu->setEnabled(false);
290 slotPositionChanged(pos, false);
291 updateTransitionPath();
292 emit parameterChanged();
295 void Geometryval::slotAddFrame() {
296 int pos = ui.spinPos->value();
297 Mlt::GeometryItem item;
299 item.x(paramRect->pos().x());
300 item.y(paramRect->pos().y());
301 item.w(paramRect->rect().width());
302 item.h(paramRect->rect().height());
303 item.mix(ui.spinTransp->value());
304 m_geom->insert(item);
305 ui.buttonAdd->setEnabled(false);
306 ui.buttonDelete->setEnabled(true);
307 ui.widget->setEnabled(true);
308 ui.spinTransp->setEnabled(true);
309 m_scaleMenu->setEnabled(true);
310 m_alignMenu->setEnabled(true);
312 emit parameterChanged();
315 void Geometryval::slotNextFrame() {
316 Mlt::GeometryItem item;
317 int error = m_geom->next_key(&item, m_helper->value() + 1);
318 kDebug() << "// SEEK TO NEXT KFR: " << error;
321 ui.spinPos->setValue(ui.spinPos->maximum());
324 int pos = item.frame();
325 ui.spinPos->setValue(pos);
328 void Geometryval::slotPreviousFrame() {
329 Mlt::GeometryItem item;
330 int error = m_geom->prev_key(&item, m_helper->value() - 1);
331 kDebug() << "// SEEK TO NEXT KFR: " << error;
333 int pos = item.frame();
334 ui.spinPos->setValue(pos);
338 QDomElement Geometryval::getParamDesc() {
339 param.setAttribute("value", m_geom->serialise());
340 kDebug() << " / / UPDATING TRANSITION VALUE: " << param.attribute("value");
344 void Geometryval::setupParam(const QDomElement& par, int minFrame, int maxFrame) {
346 QString val = par.attribute("value");
347 if (par.attribute("fixed") == "1") {
349 ui.buttonPrevious->setHidden(true);
350 ui.buttonNext->setHidden(true);
351 ui.buttonDelete->setHidden(true);
352 ui.buttonAdd->setHidden(true);
353 ui.spinTransp->setMaximum(500);
354 ui.label_pos->setHidden(true);
355 m_helper->setHidden(true);
356 ui.spinPos->setHidden(true);
358 char *tmp = (char *) qstrdup(val.toUtf8().data());
359 if (m_geom) m_geom->parse(tmp, maxFrame - minFrame, m_profile.width, m_profile.height);
360 else m_geom = new Mlt::Geometry(tmp, maxFrame - minFrame, m_profile.width, m_profile.height);
363 //kDebug() << " / / UPDATING TRANSITION VALUE: " << m_geom->serialise();
364 //read param her and set rect
366 m_helper->setKeyGeometry(m_geom, maxFrame - minFrame - 1);
369 doc.appendChild(doc.importNode(par, true));
370 kDebug() << "IMPORTED TRANS: " << doc.toString();*/
371 ui.spinPos->setMaximum(maxFrame - minFrame - 1);
372 if (m_path == NULL) {
373 m_path = new QGraphicsPathItem();
374 m_path->setPen(QPen(Qt::red));
375 scene->addItem(m_path);
377 updateTransitionPath();
379 Mlt::GeometryItem item;
381 m_geom->fetch(&item, 0);
382 if (paramRect) delete paramRect;
383 paramRect = new QGraphicsRectItem(QRectF(0, 0, item.w(), item.h()));
384 paramRect->setPos(item.x(), item.y());
385 paramRect->setZValue(0);
387 paramRect->setPen(QPen(QBrush(QColor(255, 0, 0, 255)), 1.0));
388 scene->addItem(paramRect);
389 slotPositionChanged(0, false);
391 connect(ui.spinPos, SIGNAL(valueChanged(int)), this , SLOT(slotPositionChanged(int)));
393 connect(ui.spinTransp, SIGNAL(valueChanged(int)), this , SLOT(slotTransparencyChanged(int)));
396 void Geometryval::updateTransitionPath() {
397 if (m_fixedMode) return;
398 Mlt::GeometryItem item;
403 if (m_geom->next_key(&item, pos) == 1) break;
406 path.moveTo(item.x() + item.w() / 2, item.y() + item.h() / 2);
408 path.lineTo(item.x() + item.w() / 2, item.y() + item.h() / 2);
413 m_path->setPath(path);
416 void Geometryval::slotUpdateTransitionProperties() {
417 int pos = ui.spinPos->value();
418 Mlt::GeometryItem item;
419 int error = m_geom->next_key(&item, pos);
420 if (error || item.frame() != pos) {
421 // no keyframe under cursor
424 item.x(paramRect->pos().x());
425 item.y(paramRect->pos().y());
426 item.w(paramRect->rect().width());
427 item.h(paramRect->rect().height());
428 m_geom->insert(item);
429 updateTransitionPath();
430 emit parameterChanged();