annotate base/Selection.cpp @ 305:fc656505c573

* Add labelling option for instants inserted through tapping (closes FR#1674184) Needs some refinement still, but it's almost functionally complete
author Chris Cannam
date Mon, 08 Oct 2007 14:44:38 +0000
parents 5877d68815c7
children 70a232b1f12a
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@300 175 void
Chris@300 176 MultiSelection::getExtents(size_t &startFrame, size_t &endFrame) const
Chris@300 177 {
Chris@300 178 startFrame = 0;
Chris@300 179 endFrame = 0;
Chris@300 180
Chris@300 181 for (SelectionList::const_iterator i = m_selections.begin();
Chris@300 182 i != m_selections.end(); ++i) {
Chris@300 183
Chris@300 184 if (i == m_selections.begin() || i->getStartFrame() < startFrame) {
Chris@300 185 startFrame = i->getStartFrame();
Chris@300 186 }
Chris@300 187
Chris@300 188 if (i == m_selections.begin() || i->getEndFrame() > endFrame) {
Chris@300 189 endFrame = i->getEndFrame();
Chris@300 190 }
Chris@300 191 }
Chris@300 192 }
Chris@300 193
Chris@24 194 Selection
Chris@36 195 MultiSelection::getContainingSelection(size_t frame, bool defaultToFollowing) const
Chris@24 196 {
Chris@24 197 // This scales very badly with the number of selections, but it's
Chris@24 198 // more efficient for very small numbers of selections than a more
Chris@24 199 // scalable method, and I think that may be what we need
Chris@24 200
Chris@24 201 for (SelectionList::const_iterator i = m_selections.begin();
Chris@24 202 i != m_selections.end(); ++i) {
Chris@24 203
Chris@24 204 if (i->contains(frame)) return *i;
Chris@24 205
Chris@24 206 if (i->getStartFrame() > frame) {
Chris@24 207 if (defaultToFollowing) return *i;
Chris@24 208 else return Selection();
Chris@24 209 }
Chris@24 210 }
Chris@24 211
Chris@24 212 return Selection();
Chris@24 213 }
Chris@46 214
Chris@46 215 QString
Chris@46 216 MultiSelection::toXmlString(QString indent,
Chris@46 217 QString extraAttributes) const
Chris@46 218 {
Chris@46 219 QString s;
Chris@46 220 s += indent + QString("<selections %1>\n").arg(extraAttributes);
Chris@46 221 for (SelectionList::iterator i = m_selections.begin();
Chris@46 222 i != m_selections.end(); ++i) {
Chris@46 223 s += indent + QString(" <selection start=\"%1\" end=\"%2\"/>\n")
Chris@46 224 .arg(i->getStartFrame()).arg(i->getEndFrame());
Chris@46 225 }
Chris@46 226 s += indent + "</selections>\n";
Chris@46 227 return s;
Chris@46 228 }
Chris@46 229