annotate data/model/RelativelyFineZoomConstraint.cpp @ 1552:05c3fbaec8ea

Introduce RelativelyFineZoomConstraint, which encodes more-or-less the scheme that was already used for the horizontal thumbwheel in the pane (which overrode the layers' own zoom constraints unless they said they couldn't support any other)
author Chris Cannam
date Wed, 10 Oct 2018 14:32:34 +0100
parents
children
rev   line source
Chris@1552 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@1552 2
Chris@1552 3 /*
Chris@1552 4 Sonic Visualiser
Chris@1552 5 An audio file viewer and annotation editor.
Chris@1552 6 Centre for Digital Music, Queen Mary, University of London.
Chris@1552 7
Chris@1552 8 This program is free software; you can redistribute it and/or
Chris@1552 9 modify it under the terms of the GNU General Public License as
Chris@1552 10 published by the Free Software Foundation; either version 2 of the
Chris@1552 11 License, or (at your option) any later version. See the file
Chris@1552 12 COPYING included with this distribution for more information.
Chris@1552 13 */
Chris@1552 14
Chris@1552 15 #include "RelativelyFineZoomConstraint.h"
Chris@1552 16
Chris@1552 17 #include <vector>
Chris@1552 18 #include <algorithm>
Chris@1552 19 #include <iostream>
Chris@1552 20
Chris@1552 21 using namespace std;
Chris@1552 22
Chris@1552 23 ZoomLevel
Chris@1552 24 RelativelyFineZoomConstraint::getNearestZoomLevel(ZoomLevel requested,
Chris@1552 25 RoundingDirection dir) const
Chris@1552 26 {
Chris@1552 27 static vector<int> levels;
Chris@1552 28
Chris@1552 29 int maxLevel = getMaxZoomLevel().level;
Chris@1552 30
Chris@1552 31 if (levels.empty()) {
Chris@1552 32 int level = 1;
Chris@1552 33 while (level <= maxLevel) {
Chris@1552 34 // cerr << level << " ";
Chris@1552 35 levels.push_back(level);
Chris@1552 36 int step = level / 10;
Chris@1552 37 int pwr = 0;
Chris@1552 38 while (step > 0) {
Chris@1552 39 ++pwr;
Chris@1552 40 step /= 2;
Chris@1552 41 }
Chris@1552 42 step = (1 << pwr);
Chris@1552 43 level += step;
Chris@1552 44 }
Chris@1552 45 // cerr << endl;
Chris@1552 46 }
Chris@1552 47
Chris@1552 48 RoundingDirection effective = dir;
Chris@1552 49 if (requested.zone == ZoomLevel::PixelsPerFrame) {
Chris@1552 50 if (dir == RoundUp) effective = RoundDown;
Chris@1552 51 else if (dir == RoundDown) effective = RoundUp;
Chris@1552 52 }
Chris@1552 53
Chris@1552 54 // iterator pointing to first level that is >= requested
Chris@1552 55 auto i = lower_bound(levels.begin(), levels.end(), requested.level);
Chris@1552 56
Chris@1552 57 ZoomLevel newLevel(requested);
Chris@1552 58
Chris@1552 59 if (i == levels.end()) {
Chris@1552 60 newLevel.level = maxLevel;
Chris@1552 61
Chris@1552 62 } else if (*i == requested.level) {
Chris@1552 63 newLevel.level = requested.level;
Chris@1552 64
Chris@1552 65 } else if (effective == RoundUp) {
Chris@1552 66 newLevel.level = *i;
Chris@1552 67
Chris@1552 68 } else if (effective == RoundDown) {
Chris@1552 69 if (i != levels.begin()) {
Chris@1552 70 --i;
Chris@1552 71 }
Chris@1552 72 newLevel.level = *i;
Chris@1552 73
Chris@1552 74 } else { // RoundNearest
Chris@1552 75 if (i != levels.begin()) {
Chris@1552 76 auto j = i;
Chris@1552 77 --j;
Chris@1552 78 if (requested.level - *j < *i - requested.level) {
Chris@1552 79 newLevel.level = *j;
Chris@1552 80 } else {
Chris@1552 81 newLevel.level = *i;
Chris@1552 82 }
Chris@1552 83 }
Chris@1552 84 }
Chris@1552 85
Chris@1552 86 // canonicalise
Chris@1552 87 if (newLevel.level == 1) {
Chris@1552 88 newLevel.zone = ZoomLevel::FramesPerPixel;
Chris@1552 89 }
Chris@1552 90
Chris@1552 91 using namespace std::rel_ops;
Chris@1552 92 if (newLevel > getMaxZoomLevel()) {
Chris@1552 93 newLevel = getMaxZoomLevel();
Chris@1552 94 } else if (newLevel < getMinZoomLevel()) {
Chris@1552 95 newLevel = getMinZoomLevel();
Chris@1552 96 }
Chris@1552 97
Chris@1552 98 return newLevel;
Chris@1552 99 }
Chris@1552 100
Chris@1552 101