...
 
Commits (3)
  • Eoin O'Neill's avatar
    Fix: Properly Maintain Selection of Keyframes When Inserting / Removing Hold Frames. · 68a0cf3e
    Eoin O'Neill authored
    Related Feature: Preserve multi-frame selection when active frame changes. Useful
    for preserving the users selection on scrub, but also less error-prone when dealing
    with modifying the user selection while concurrent "switch-time" operation is running.
    
    Insert Keyframe Bug:
    BUG:404519
    
    Maintain Multiframe Selection Wishlist:
    BUG:388779
    
    (commit cherry-picked from krita/4.3 d76c59fc)
    68a0cf3e
  • Eoin O'Neill's avatar
    Fix Loading Group Node Opacity Keyframes. · 55790590
    Eoin O'Neill authored
    Original Cause: KraLoadVisitor::visit(KisGroupLayer*) wasn't calling loadNodeKeyframes,
    resulting in loss of data on load.
    
    BUG:424539
    (cherry picked from commit f7a80c5d)
    55790590
  • Eoin O'Neill's avatar
    Fix KRA Saving Failure When Audio File is Missing · 25dcdecf
    Eoin O'Neill authored
    When audio file is moved after assignment, saving would fail because the file couldn't be found.
    Instead of failing to save, Krita should save the user's desired file path regardless, and missing files
    should be handled on next load.
    
    BUG:422890
    (cherry picked from commit cc3745ed)
    25dcdecf
......@@ -878,7 +878,7 @@ bool TimelineFramesModel::insertFrames(int dstColumn, const QList<int> &dstRows,
return true;
}
bool TimelineFramesModel::insertHoldFrames(QModelIndexList selectedIndexes, int count)
bool TimelineFramesModel::insertHoldFrames(const QModelIndexList &selectedIndexes, int count)
{
if (selectedIndexes.isEmpty() || count == 0) return true;
......
......@@ -65,7 +65,7 @@ public:
bool insertFrames(int dstColumn, const QList<int> &dstRows, int count, int timing = 1);
bool insertHoldFrames(QModelIndexList selectedIndexes, int count);
bool insertHoldFrames(const QModelIndexList &selectedIndexes, int count);
QString audioChannelFileName() const;
void setAudioChannelFileName(const QString &fileName);
......
......@@ -759,6 +759,7 @@ void TimelineFramesView::slotDataChanged(const QModelIndex &topLeft, const QMode
return;
}
if (selectionModel()->selectedIndexes().count() > 1) return;
if (selectedColumn == -1) {
selectedColumn = index.column();
......@@ -1557,12 +1558,47 @@ void TimelineFramesView::insertOrRemoveHoldFrames(int count, bool entireColumn)
m_d->model->insertHoldFrames(indexes, count);
// Fan selection based on insertion or deletion.
// This should allow better UI/UX for insertion of keyframes or hold frames.
fanSelectedFrames(indexes, count);
// bulk adding frames can add too many
// trim timeline to clean up extra frames that might have been added
slotUpdateInfiniteFramesCount();
}
}
void TimelineFramesView::fanSelectedFrames(const QModelIndexList &selection, int count, bool ignoreKeyless) {
QMap<int, QList<int>> indexMap;
QList<QModelIndex> selectedIndices = selection;
foreach (const QModelIndex &index, selectedIndices) {
if (!indexMap.contains(index.row())) {
indexMap.insert(index.row(), QList<int>());
}
if (m_d->model->data(index, TimelineFramesModel::FrameExistsRole).value<bool>() || !ignoreKeyless) {
indexMap[index.row()] << index.column();
}
}
selectionModel()->clearSelection();
KisSignalsBlocker blockSig(selectionModel());
foreach (const int &layer, indexMap.keys()) {
QList<int>::const_iterator it;
int progressIndex = 0;
std::sort(indexMap[layer].begin(), indexMap[layer].end());
for (it = indexMap[layer].constBegin(); it != indexMap[layer].constEnd(); it++) {
const int offsetColumn = *it + (progressIndex * count);
selectionModel()->select(model()->index(layer, offsetColumn), QItemSelectionModel::Select);
progressIndex++;
}
}
}
void TimelineFramesView::insertOrRemoveMultipleHoldFrames(bool insertion, bool entireColumn)
{
bool ok = false;
......
......@@ -164,6 +164,7 @@ private:
void insertOrRemoveHoldFrames(int count, bool entireColumn = false);
void insertOrRemoveMultipleHoldFrames(bool insertion, bool entireColumn = false);
void fanSelectedFrames(const QModelIndexList &selection, int count, bool ignoreKeyless = true);
void cutCopyImpl(bool entireColumn, bool copy);
......
......@@ -231,6 +231,8 @@ bool KisKraLoadVisitor::visit(KisPaintLayer *layer)
bool KisKraLoadVisitor::visit(KisGroupLayer *layer)
{
loadNodeKeyframes(layer);
if (*layer->colorSpace() != *m_image->colorSpace()) {
layer->resetCache(m_image->colorSpace());
}
......
......@@ -1244,7 +1244,7 @@ void KisKraLoader::loadAudio(const KoXmlElement& elem, KisImageSP image)
fileName = QDir::toNativeSeparators(fileName);
QDir baseDirectory = QFileInfo(m_d->document->localFilePath()).absoluteDir();
fileName = baseDirectory.absoluteFilePath(fileName);
fileName = QDir::cleanPath( baseDirectory.filePath(fileName) );
QFileInfo info(fileName);
......
......@@ -22,6 +22,8 @@
#include "kis_kra_save_visitor.h"
#include "kis_kra_savexml_visitor.h"
#include <QApplication>
#include <QMessageBox>
#include <QDomDocument>
#include <QDomElement>
#include <QString>
......@@ -45,6 +47,7 @@
#include <kis_annotation.h>
#include <kis_image.h>
#include <kis_image_animation_interface.h>
#include <KisImportExportManager.h>
#include <kis_group_layer.h>
#include <kis_layer.h>
#include <kis_adjustment_layer.h>
......@@ -511,12 +514,8 @@ bool KisKraSaver::saveAudio(QDomDocument& doc, QDomElement& element)
{
const KisImageAnimationInterface *interface = m_d->doc->image()->animationInterface();
QString fileName = interface->audioChannelFileName();
if (fileName.isEmpty()) return true;
if (!QFileInfo::exists(fileName)) {
m_d->errorMessages << i18n("Audio channel file %1 doesn't exist!", fileName);
return false;
}
if (fileName.isEmpty()) return true;
const QDir documentDir = QFileInfo(m_d->filename).absoluteDir();
KIS_ASSERT_RECOVER_RETURN_VALUE(documentDir.exists(), false);
......