annotate base/Selection.cpp @ 167:665342c6ec57

* Add a bit of resistance to pane dragging so as to make it harder to inadvertently drag in the other axis from the one you intended
author Chris Cannam
date Fri, 22 Sep 2006 16:46:10 +0000
parents d397ea0a79f5
children 5877d68815c7
rev   line source
Chris@49 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@8 2
Chris@8 3 /*
Chris@52 4 Sonic Visualiser
Chris@52 5 An audio file viewer and annotation editor.
Chris@52 6 Centre for Digital Music, Queen Mary, University of London.
Chris@52 7 This file copyright 2006 Chris Cannam.
Chris@8 8
Chris@52 9 This program is free software; you can redistribute it and/or
Chris@52 10 modify it under the terms of the GNU General Public License as
Chris@52 11 published by the Free Software Foundation; either version 2 of the
Chris@52 12 License, or (at your option) any later version. See the file
Chris@52 13 COPYING included with this distribution for more information.
Chris@8 14 */
Chris@8 15
Chris@8 16 #include "Selection.h"
Chris@8 17
Chris@8 18 Selection::Selection() :
Chris@8 19 m_startFrame(0),
Chris@8 20 m_endFrame(0)
Chris@8 21 {
Chris@8 22 }
Chris@8 23
Chris@8 24 Selection::Selection(size_t startFrame, size_t endFrame) :
Chris@8 25 m_startFrame(startFrame),
Chris@8 26 m_endFrame(endFrame)
Chris@8 27 {
Chris@8 28 if (m_startFrame > m_endFrame) {
Chris@8 29 size_t tmp = m_endFrame;
Chris@8 30 m_endFrame = m_startFrame;
Chris@8 31 m_startFrame = tmp;
Chris@8 32 }
Chris@8 33 }
Chris@8 34
Chris@8 35 Selection::Selection(const Selection &s) :
Chris@8 36 m_startFrame(s.m_startFrame),
Chris@8 37 m_endFrame(s.m_endFrame)
Chris@8 38 {
Chris@8 39 }
Chris@8 40
Chris@8 41 Selection &
Chris@8 42 Selection::operator=(const Selection &s)
Chris@8 43 {
Chris@8 44 if (this != &s) {
Chris@8 45 m_startFrame = s.m_startFrame;
Chris@8 46 m_endFrame = s.m_endFrame;
Chris@8 47 }
Chris@8 48 return *this;
Chris@8 49 }
Chris@8 50
Chris@8 51 Selection::~Selection()
Chris@8 52 {
Chris@8 53 }
Chris@8 54
Chris@8 55 bool
Chris@8 56 Selection::isEmpty() const
Chris@8 57 {
Chris@8 58 return m_startFrame == m_endFrame;
Chris@8 59 }
Chris@8 60
Chris@8 61 size_t
Chris@8 62 Selection::getStartFrame() const
Chris@8 63 {
Chris@8 64 return m_startFrame;
Chris@8 65 }
Chris@8 66
Chris@8 67 size_t
Chris@8 68 Selection::getEndFrame() const
Chris@8 69 {
Chris@8 70 return m_endFrame;
Chris@8 71 }
Chris@8 72
Chris@8 73 bool
Chris@9 74 Selection::contains(size_t frame) const
Chris@9 75 {
Chris@9 76 return (frame >= m_startFrame) && (frame < m_endFrame);
Chris@9 77 }
Chris@9 78
Chris@9 79 bool
Chris@8 80 Selection::operator<(const Selection &s) const
Chris@8 81 {
Chris@9 82 if (isEmpty()) {
Chris@9 83 if (s.isEmpty()) return false;
Chris@9 84 else return true;
Chris@9 85 } else {
Chris@9 86 if (s.isEmpty()) return false;
Chris@9 87 else return (m_startFrame < s.m_startFrame);
Chris@9 88 }
Chris@8 89 }
Chris@8 90
Chris@8 91 bool
Chris@8 92 Selection::operator==(const Selection &s) const
Chris@8 93 {
Chris@9 94 if (isEmpty()) return s.isEmpty();
Chris@9 95
Chris@8 96 return (m_startFrame == s.m_startFrame &&
Chris@8 97 m_endFrame == s.m_endFrame);
Chris@8 98 }
Chris@8 99
Chris@24 100
Chris@24 101 MultiSelection::MultiSelection()
Chris@24 102 {
Chris@24 103 }
Chris@24 104
Chris@24 105 MultiSelection::~MultiSelection()
Chris@24 106 {
Chris@24 107 }
Chris@24 108
Chris@24 109 const MultiSelection::SelectionList &
Chris@24 110 MultiSelection::getSelections() const
Chris@24 111 {
Chris@24 112 return m_selections;
Chris@24 113 }
Chris@24 114
Chris@24 115 void
Chris@24 116 MultiSelection::setSelection(const Selection &selection)
Chris@24 117 {
Chris@24 118 clearSelections();
Chris@24 119 addSelection(selection);
Chris@24 120 }
Chris@24 121
Chris@24 122 void
Chris@24 123 MultiSelection::addSelection(const Selection &selection)
Chris@24 124 {
Chris@24 125 m_selections.insert(selection);
Chris@24 126
Chris@24 127 // Cope with a sitation where the new selection overlaps one or
Chris@24 128 // more existing ones. This is a terribly inefficient way to do
Chris@24 129 // this, but that probably isn't significant in real life.
Chris@24 130
Chris@24 131 // It's essential for the correct operation of
Chris@24 132 // getContainingSelection that the selections do not overlap, so
Chris@24 133 // this is not just a frill.
Chris@24 134
Chris@24 135 for (SelectionList::iterator i = m_selections.begin();
Chris@24 136 i != m_selections.end(); ) {
Chris@24 137
Chris@24 138 SelectionList::iterator j = i;
Chris@24 139 if (++j == m_selections.end()) break;
Chris@24 140
Chris@24 141 if (i->getEndFrame() >= j->getStartFrame()) {
Chris@24 142 Selection merged(i->getStartFrame(),
Chris@24 143 std::max(i->getEndFrame(), j->getEndFrame()));
Chris@24 144 m_selections.erase(i);
Chris@24 145 m_selections.erase(j);
Chris@24 146 m_selections.insert(merged);
Chris@24 147 i = m_selections.begin();
Chris@24 148 } else {
Chris@24 149 ++i;
Chris@24 150 }
Chris@24 151 }
Chris@24 152 }
Chris@24 153
Chris@24 154 void
Chris@24 155 MultiSelection::removeSelection(const Selection &selection)
Chris@24 156 {
Chris@24 157 //!!! Likewise this needs to cope correctly with the situation
Chris@24 158 //where selection is not one of the original selection set but
Chris@24 159 //simply overlaps one of them (cutting down the original selection
Chris@24 160 //appropriately)
Chris@24 161
Chris@24 162 if (m_selections.find(selection) != m_selections.end()) {
Chris@24 163 m_selections.erase(selection);
Chris@24 164 }
Chris@24 165 }
Chris@24 166
Chris@24 167 void
Chris@24 168 MultiSelection::clearSelections()
Chris@24 169 {
Chris@24 170 if (!m_selections.empty()) {
Chris@24 171 m_selections.clear();
Chris@24 172 }
Chris@24 173 }
Chris@24 174
Chris@24 175 Selection
Chris@36 176 MultiSelection::getContainingSelection(size_t frame, bool defaultToFollowing) const
Chris@24 177 {
Chris@24 178 // This scales very badly with the number of selections, but it's
Chris@24 179 // more efficient for very small numbers of selections than a more
Chris@24 180 // scalable method, and I think that may be what we need
Chris@24 181
Chris@24 182 for (SelectionList::const_iterator i = m_selections.begin();
Chris@24 183 i != m_selections.end(); ++i) {
Chris@24 184
Chris@24 185 if (i->contains(frame)) return *i;
Chris@24 186
Chris@24 187 if (i->getStartFrame() > frame) {
Chris@24 188 if (defaultToFollowing) return *i;
Chris@24 189 else return Selection();
Chris@24 190 }
Chris@24 191 }
Chris@24 192
Chris@24 193 return Selection();
Chris@24 194 }
Chris@46 195
Chris@46 196 QString
Chris@46 197 MultiSelection::toXmlString(QString indent,
Chris@46 198 QString extraAttributes) const
Chris@46 199 {
Chris@46 200 QString s;
Chris@46 201 s += indent + QString("<selections %1>\n").arg(extraAttributes);
Chris@46 202 for (SelectionList::iterator i = m_selections.begin();
Chris@46 203 i != m_selections.end(); ++i) {
Chris@46 204 s += indent + QString(" <selection start=\"%1\" end=\"%2\"/>\n")
Chris@46 205 .arg(i->getStartFrame()).arg(i->getEndFrame());
Chris@46 206 }
Chris@46 207 s += indent + "</selections>\n";
Chris@46 208 return s;
Chris@46 209 }
Chris@46 210