snapmodel.cpp 4.71 KB
Newer Older
1 2 3 4 5
/***************************************************************************
 *   Copyright (C) 2017 by Nicolas Carion                                  *
 *   This file is part of Kdenlive. See www.kdenlive.org.                  *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
6
 *   it under the terms of the GNU General Public License as published by  *
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) version 3 or any later version accepted by the       *
 *   membership of KDE e.V. (or its successor approved  by the membership  *
 *   of KDE e.V.), which shall act as a proxy defined in Section 14 of     *
 *   version 3 of the license.                                             *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
 ***************************************************************************/
#include "snapmodel.hpp"
#include <QDebug>
Nicolas Carion's avatar
Nicolas Carion committed
23
#include <climits>
Nicolas Carion's avatar
Nicolas Carion committed
24
#include <cstdlib>
25

26 27 28 29

SnapInterface::SnapInterface() = default;
SnapInterface::~SnapInterface() = default;

Nicolas Carion's avatar
linting  
Nicolas Carion committed
30
SnapModel::SnapModel() = default;
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52

void SnapModel::addPoint(int position)
{
    if (m_snaps.count(position) == 0) {
        m_snaps[position] = 1;
    } else {
        m_snaps[position]++;
    }
}

void SnapModel::removePoint(int position)
{
    Q_ASSERT(m_snaps.count(position) > 0);
    if (m_snaps[position] == 1) {
        m_snaps.erase(position);
    } else {
        m_snaps[position]--;
    }
}

int SnapModel::getClosestPoint(int position)
{
Nicolas Carion's avatar
Nicolas Carion committed
53
    if (m_snaps.empty()) {
54 55 56 57 58 59 60 61 62 63 64
        return -1;
    }
    auto it = m_snaps.lower_bound(position);
    long long int prev = INT_MIN, next = INT_MAX;
    if (it != m_snaps.end()) {
        next = (*it).first;
    }
    if (it != m_snaps.begin()) {
        --it;
        prev = (*it).first;
    }
Nicolas Carion's avatar
Nicolas Carion committed
65
    if (std::llabs((long long)position - prev) < std::llabs((long long)position - next)) {
66 67 68 69 70
        return (int)prev;
    }
    return (int)next;
}

71 72
int SnapModel::getNextPoint(int position)
{
Nicolas Carion's avatar
Nicolas Carion committed
73
    if (m_snaps.empty()) {
74 75 76 77 78 79 80 81 82 83 84 85
        return position;
    }
    auto it = m_snaps.lower_bound(position + 1);
    long long int next = position;
    if (it != m_snaps.end()) {
        next = (*it).first;
    }
    return (int)next;
}

int SnapModel::getPreviousPoint(int position)
{
Nicolas Carion's avatar
Nicolas Carion committed
86
    if (m_snaps.empty()) {
87 88 89 90 91 92 93 94 95 96 97
        return 0;
    }
    auto it = m_snaps.lower_bound(position);
    long long int prev = 0;
    if (it != m_snaps.begin()) {
        --it;
        prev = (*it).first;
    }
    return (int)prev;
}

Nicolas Carion's avatar
Nicolas Carion committed
98
void SnapModel::ignore(const std::vector<int> &pts)
99 100
{
    for (int pt : pts) {
101 102
        removePoint(pt);
        m_ignore.push_back(pt);
103 104 105 106 107
    }
}

void SnapModel::unIgnore()
{
Nicolas Carion's avatar
Nicolas Carion committed
108
    for (const auto &pt : m_ignore) {
109
        addPoint(pt);
110 111 112
    }
    m_ignore.clear();
}
113 114 115

int SnapModel::proposeSize(int in, int out, int size, bool right, int maxSnapDist)
{
Nicolas Carion's avatar
Nicolas Carion committed
116
    ignore({in, out});
117 118 119 120 121 122 123 124 125 126 127
    int proposed_size = -1;
    if (right) {
        int target_pos = in + size - 1;
        int snapped_pos = getClosestPoint(target_pos);
        if (snapped_pos != -1 && qAbs(target_pos - snapped_pos) <= maxSnapDist) {
            proposed_size = snapped_pos - in;
        }
    } else {
        int target_pos = out + 1 - size;
        int snapped_pos = getClosestPoint(target_pos);
        if (snapped_pos != -1 && qAbs(target_pos - snapped_pos) <= maxSnapDist) {
128
            proposed_size = out - snapped_pos;
129 130 131 132 133
        }
    }
    unIgnore();
    return proposed_size;
}
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154

int SnapModel::proposeSize(int in, int out, const std::vector<int> boundaries, int size, bool right, int maxSnapDist)
{
    ignore(boundaries);
    int proposed_size = -1;
    if (right) {
        int target_pos = in + size - 1;
        int snapped_pos = getClosestPoint(target_pos);
        if (snapped_pos != -1 && qAbs(target_pos - snapped_pos) <= maxSnapDist) {
            proposed_size = snapped_pos - in;
        }
    } else {
        int target_pos = out + 1 - size;
        int snapped_pos = getClosestPoint(target_pos);
        if (snapped_pos != -1 && qAbs(target_pos - snapped_pos) <= maxSnapDist) {
            proposed_size = out - snapped_pos;
        }
    }
    unIgnore();
    return proposed_size;
}