File indexing completed on 2024-04-28 04:52:27

0001 /*
0002     SPDX-FileCopyrightText: 2017 Nicolas Carion
0003     SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0004 */
0005 #include "snapmodel.hpp"
0006 #include <QDebug>
0007 #include <climits>
0008 #include <cstdlib>
0009 
0010 SnapInterface::SnapInterface() = default;
0011 SnapInterface::~SnapInterface() = default;
0012 
0013 SnapModel::SnapModel() = default;
0014 
0015 void SnapModel::addPoint(int position)
0016 {
0017     if (m_snaps.count(position) == 0) {
0018         m_snaps[position] = 1;
0019     } else {
0020         m_snaps[position]++;
0021     }
0022 }
0023 
0024 void SnapModel::removePoint(int position)
0025 {
0026     Q_ASSERT(m_snaps.count(position) > 0);
0027     if (m_snaps[position] == 1) {
0028         m_snaps.erase(position);
0029     } else {
0030         m_snaps[position]--;
0031     }
0032 }
0033 
0034 int SnapModel::getClosestPoint(int position)
0035 {
0036     if (m_snaps.empty()) {
0037         return -1;
0038     }
0039     auto it = m_snaps.lower_bound(position);
0040     long long int prev = INT_MIN, next = INT_MAX;
0041     if (it != m_snaps.end()) {
0042         next = (*it).first;
0043     }
0044     if (it != m_snaps.begin()) {
0045         --it;
0046         prev = (*it).first;
0047     }
0048     if (std::llabs(position - prev) < std::llabs(position - next)) {
0049         return int(prev);
0050     }
0051     return int(next);
0052 }
0053 
0054 int SnapModel::getNextPoint(int position)
0055 {
0056     if (m_snaps.empty()) {
0057         return position;
0058     }
0059     auto it = m_snaps.lower_bound(position + 1);
0060     long long int next = position;
0061     if (it != m_snaps.end()) {
0062         next = (*it).first;
0063     }
0064     return int(next);
0065 }
0066 
0067 int SnapModel::getPreviousPoint(int position)
0068 {
0069     if (m_snaps.empty()) {
0070         return 0;
0071     }
0072     auto it = m_snaps.lower_bound(position);
0073     long long int prev = 0;
0074     if (it != m_snaps.begin()) {
0075         --it;
0076         prev = (*it).first;
0077     }
0078     return int(prev);
0079 }
0080 
0081 void SnapModel::ignore(const std::vector<int> &pts)
0082 {
0083     for (int pt : pts) {
0084         removePoint(pt);
0085         m_ignore.push_back(pt);
0086     }
0087 }
0088 
0089 void SnapModel::unIgnore()
0090 {
0091     for (const auto &pt : m_ignore) {
0092         addPoint(pt);
0093     }
0094     m_ignore.clear();
0095 }
0096 
0097 int SnapModel::proposeSize(int in, int out, int size, bool right, int maxSnapDist)
0098 {
0099     ignore({in, out});
0100     int proposed_size = -1;
0101     if (right) {
0102         int target_pos = in + size - 1;
0103         int snapped_pos = getClosestPoint(target_pos);
0104         if (snapped_pos != -1 && qAbs(target_pos - snapped_pos) <= maxSnapDist) {
0105             proposed_size = snapped_pos - in;
0106         }
0107     } else {
0108         int target_pos = out + 1 - size;
0109         int snapped_pos = getClosestPoint(target_pos);
0110         if (snapped_pos != -1 && qAbs(target_pos - snapped_pos) <= maxSnapDist) {
0111             proposed_size = out - snapped_pos;
0112         }
0113     }
0114     unIgnore();
0115     return proposed_size;
0116 }
0117 
0118 int SnapModel::proposeSize(int in, int out, const std::vector<int> &boundaries, int size, bool right, int maxSnapDist)
0119 {
0120     ignore(boundaries);
0121     int proposed_size = -1;
0122     if (right) {
0123         int target_pos = in + size - 1;
0124         int snapped_pos = getClosestPoint(target_pos);
0125         if (snapped_pos != -1 && qAbs(target_pos - snapped_pos) <= maxSnapDist) {
0126             proposed_size = snapped_pos - in;
0127         }
0128     } else {
0129         int target_pos = out + 1 - size;
0130         int snapped_pos = getClosestPoint(target_pos);
0131         if (snapped_pos != -1 && qAbs(target_pos - snapped_pos) <= maxSnapDist) {
0132             proposed_size = out - snapped_pos;
0133         }
0134     }
0135     unIgnore();
0136     return proposed_size;
0137 }