Mercurial > hg > svgui
comparison view/Pane.cpp @ 174:96b8a790730a
* Wire up the Panner widget in the pane, and do some tidying in Pane
author | Chris Cannam |
---|---|
date | Thu, 19 Oct 2006 13:05:39 +0000 |
parents | 9c40dc10c88c |
children | 42118892f428 |
comparison
equal
deleted
inserted
replaced
173:9c40dc10c88c | 174:96b8a790730a |
---|---|
95 | 95 |
96 m_vpan = new Panner; | 96 m_vpan = new Panner; |
97 layout->addWidget(m_vpan, 0, 1); | 97 layout->addWidget(m_vpan, 0, 1); |
98 m_vpan->setFixedWidth(12); | 98 m_vpan->setFixedWidth(12); |
99 m_vpan->setFixedHeight(70); | 99 m_vpan->setFixedHeight(70); |
100 // m_vpan->setRectExtents(0.1, 0.1, 0.4, 0.4); | 100 m_vpan->setAlpha(80, 130); |
101 connect(m_vpan, SIGNAL(rectExtentsChanged(float, float, float, float)), | |
102 this, SLOT(verticalPannerMoved(float, float, float, float))); | |
101 | 103 |
102 m_vthumb = new Thumbwheel(Qt::Vertical); | 104 m_vthumb = new Thumbwheel(Qt::Vertical); |
103 layout->addWidget(m_vthumb, 0, 2); | 105 layout->addWidget(m_vthumb, 0, 2); |
104 m_vthumb->setFixedWidth(16); | 106 m_vthumb->setFixedWidth(16); |
105 m_vthumb->setFixedHeight(70); | 107 m_vthumb->setFixedHeight(70); |
192 << m_vthumb->getValue() << std::endl; | 194 << m_vthumb->getValue() << std::endl; |
193 | 195 |
194 } | 196 } |
195 } | 197 } |
196 | 198 |
199 updateVerticalPanner(); | |
200 | |
197 if (m_manager && m_manager->getZoomWheelsEnabled() && | 201 if (m_manager && m_manager->getZoomWheelsEnabled() && |
198 width() > 120 && height() > 100) { | 202 width() > 120 && height() > 100) { |
199 if (!m_headsUpDisplay->isVisible()) { | 203 if (!m_headsUpDisplay->isVisible()) { |
200 m_headsUpDisplay->show(); | 204 m_headsUpDisplay->show(); |
201 connect(m_manager, SIGNAL(zoomLevelChanged()), | 205 connect(m_manager, SIGNAL(zoomLevelChanged()), |
210 m_headsUpDisplay->hide(); | 214 m_headsUpDisplay->hide(); |
211 if (m_manager) { | 215 if (m_manager) { |
212 disconnect(m_manager, SIGNAL(zoomLevelChanged()), | 216 disconnect(m_manager, SIGNAL(zoomLevelChanged()), |
213 this, SLOT(zoomLevelChanged())); | 217 this, SLOT(zoomLevelChanged())); |
214 } | 218 } |
219 } | |
220 } | |
221 | |
222 void | |
223 Pane::updateVerticalPanner() | |
224 { | |
225 if (!m_vpan || !m_manager || !m_manager->getZoomWheelsEnabled()) return; | |
226 | |
227 float vmin, vmax, dmin, dmax; | |
228 if (getTopLayerDisplayExtents(vmin, vmax, dmin, dmax) && vmax != vmin) { | |
229 float y0 = (dmin - vmin) / (vmax - vmin); | |
230 float y1 = (dmax - vmin) / (vmax - vmin); | |
231 m_vpan->blockSignals(true); | |
232 m_vpan->setRectExtents(0, 1.0 - y1, 1, y1 - y0); | |
233 m_vpan->blockSignals(false); | |
234 m_vpan->show(); | |
235 } else { | |
236 m_vpan->hide(); | |
215 } | 237 } |
216 } | 238 } |
217 | 239 |
218 bool | 240 bool |
219 Pane::shouldIlluminateLocalFeatures(const Layer *layer, QPoint &pos) const | 241 Pane::shouldIlluminateLocalFeatures(const Layer *layer, QPoint &pos) const |
661 if (x > rx - fuzz) closeToRightEdge = true; | 683 if (x > rx - fuzz) closeToRightEdge = true; |
662 | 684 |
663 return selection; | 685 return selection; |
664 } | 686 } |
665 | 687 |
688 bool | |
689 Pane::canTopLayerMoveVertical() | |
690 { | |
691 float vmin, vmax, dmin, dmax; | |
692 if (!getTopLayerDisplayExtents(vmin, vmax, dmin, dmax)) return false; | |
693 if (dmin <= vmin && dmax >= vmax) return false; | |
694 return true; | |
695 } | |
696 | |
697 bool | |
698 Pane::getTopLayerDisplayExtents(float &vmin, float &vmax, | |
699 float &dmin, float &dmax) | |
700 { | |
701 Layer *layer = 0; | |
702 if (getLayerCount() > 0) layer = getLayer(getLayerCount() - 1); | |
703 if (!layer) return false; | |
704 bool vlog; | |
705 QString vunit; | |
706 return (layer->getValueExtents(vmin, vmax, vlog, vunit) && | |
707 layer->getDisplayExtents(dmin, dmax)); | |
708 } | |
709 | |
710 bool | |
711 Pane::setTopLayerDisplayExtents(float dmin, float dmax) | |
712 { | |
713 Layer *layer = 0; | |
714 if (getLayerCount() > 0) layer = getLayer(getLayerCount() - 1); | |
715 if (!layer) return false; | |
716 return layer->setDisplayExtents(dmin, dmax); | |
717 } | |
718 | |
666 void | 719 void |
667 Pane::mousePressEvent(QMouseEvent *e) | 720 Pane::mousePressEvent(QMouseEvent *e) |
668 { | 721 { |
669 if (e->buttons() & Qt::RightButton) { | 722 if (e->buttons() & Qt::RightButton) { |
670 emit rightButtonMenuRequested(mapToGlobal(e->pos())); | 723 emit rightButtonMenuRequested(mapToGlobal(e->pos())); |
690 setCursor(Qt::PointingHandCursor); | 743 setCursor(Qt::PointingHandCursor); |
691 } | 744 } |
692 | 745 |
693 m_navigating = true; | 746 m_navigating = true; |
694 m_dragCentreFrame = m_centreFrame; | 747 m_dragCentreFrame = m_centreFrame; |
695 | |
696 //!!! pull out into function to go with mouse move code | |
697 | |
698 m_dragStartMinValue = 0; | 748 m_dragStartMinValue = 0; |
699 | 749 |
700 Layer *layer = 0; | 750 float vmin, vmax, dmin, dmax; |
701 if (getLayerCount() > 0) layer = getLayer(getLayerCount() - 1); | 751 if (getTopLayerDisplayExtents(vmin, vmax, dmin, dmax)) { |
702 | 752 m_dragStartMinValue = dmin; |
703 if (layer) { | |
704 float min = 0.f, max = 0.f; | |
705 if (layer->getDisplayExtents(min, max)) { | |
706 m_dragStartMinValue = min; | |
707 } | |
708 } | 753 } |
709 | 754 |
710 } else if (mode == ViewManager::SelectMode) { | 755 } else if (mode == ViewManager::SelectMode) { |
711 | 756 |
712 bool closeToLeft = false, closeToRight = false; | 757 bool closeToLeft = false, closeToRight = false; |
795 | 840 |
796 if (m_shiftPressed) { | 841 if (m_shiftPressed) { |
797 | 842 |
798 int x0 = std::min(m_clickPos.x(), m_mousePos.x()); | 843 int x0 = std::min(m_clickPos.x(), m_mousePos.x()); |
799 int x1 = std::max(m_clickPos.x(), m_mousePos.x()); | 844 int x1 = std::max(m_clickPos.x(), m_mousePos.x()); |
800 int w = x1 - x0; | |
801 | 845 |
802 int y0 = std::min(m_clickPos.y(), m_mousePos.y()); | 846 int y0 = std::min(m_clickPos.y(), m_mousePos.y()); |
803 int y1 = std::max(m_clickPos.y(), m_mousePos.y()); | 847 int y1 = std::max(m_clickPos.y(), m_mousePos.y()); |
804 // int h = y1 - y0; | 848 |
805 | 849 zoomToRegion(x0, y0, x1, y1); |
806 long newStartFrame = getFrameForX(x0); | |
807 | |
808 long visibleFrames = getEndFrame() - getStartFrame(); | |
809 if (newStartFrame <= -visibleFrames) { | |
810 newStartFrame = -visibleFrames + 1; | |
811 } | |
812 | |
813 if (newStartFrame >= long(getModelsEndFrame())) { | |
814 newStartFrame = getModelsEndFrame() - 1; | |
815 } | |
816 | |
817 float ratio = float(w) / float(width()); | |
818 // std::cerr << "ratio: " << ratio << std::endl; | |
819 size_t newZoomLevel = (size_t)nearbyint(m_zoomLevel * ratio); | |
820 if (newZoomLevel < 1) newZoomLevel = 1; | |
821 | |
822 // std::cerr << "start: " << m_startFrame << ", level " << m_zoomLevel << std::endl; | |
823 setZoomLevel(getZoomConstraintBlockSize(newZoomLevel)); | |
824 setStartFrame(newStartFrame); | |
825 | |
826 //!!! lots of faff, shouldn't be here | |
827 | |
828 QString unit; | |
829 float min, max; | |
830 bool log; | |
831 Layer *layer = 0; | |
832 for (LayerList::const_iterator i = m_layers.begin(); | |
833 i != m_layers.end(); ++i) { | |
834 if ((*i)->getValueExtents(min, max, log, unit) && | |
835 (*i)->getDisplayExtents(min, max)) { | |
836 layer = *i; | |
837 break; | |
838 } | |
839 } | |
840 | |
841 if (layer) { | |
842 if (log) { | |
843 min = (min < 0.0) ? -log10f(-min) : (min == 0.0) ? 0.0 : log10f(min); | |
844 max = (max < 0.0) ? -log10f(-max) : (max == 0.0) ? 0.0 : log10f(max); | |
845 } | |
846 float rmin = min + ((max - min) * (height() - y1)) / height(); | |
847 float rmax = min + ((max - min) * (height() - y0)) / height(); | |
848 std::cerr << "min: " << min << ", max: " << max << ", y0: " << y0 << ", y1: " << y1 << ", h: " << height() << ", rmin: " << rmin << ", rmax: " << rmax << std::endl; | |
849 if (log) { | |
850 rmin = powf(10, rmin); | |
851 rmax = powf(10, rmax); | |
852 } | |
853 std::cerr << "finally: rmin: " << rmin << ", rmax: " << rmax << " " << unit.toStdString() << std::endl; | |
854 | |
855 layer->setDisplayExtents(rmin, rmax); | |
856 } | |
857 | |
858 //cerr << "mouseReleaseEvent: start frame now " << m_startFrame << endl; | |
859 // update(); | |
860 } | 850 } |
861 | 851 |
862 } else if (mode == ViewManager::SelectMode) { | 852 } else if (mode == ViewManager::SelectMode) { |
863 | 853 |
864 if (m_manager && m_manager->haveInProgressSelection()) { | 854 if (m_manager && m_manager->haveInProgressSelection()) { |
928 } else { | 918 } else { |
929 setCursor(Qt::ArrowCursor); | 919 setCursor(Qt::ArrowCursor); |
930 } | 920 } |
931 } | 921 } |
932 | 922 |
933 //!!! if (mode != ViewManager::DrawMode) { | |
934 | |
935 if (!m_manager->isPlaying()) { | 923 if (!m_manager->isPlaying()) { |
936 | 924 |
937 if (getSelectedLayer()) { | 925 if (getSelectedLayer()) { |
938 | 926 |
939 bool previouslyIdentifying = m_identifyFeatures; | 927 bool previouslyIdentifying = m_identifyFeatures; |
940 m_identifyFeatures = true; | 928 m_identifyFeatures = true; |
941 | 929 |
942 if (m_identifyFeatures != previouslyIdentifying || | 930 if (m_identifyFeatures != previouslyIdentifying || |
943 m_identifyPoint != prevPoint) { | 931 m_identifyPoint != prevPoint) { |
944 update(); | 932 update(); |
945 } | 933 } |
946 } | 934 } |
947 | 935 } |
948 } | |
949 | |
950 // } | |
951 | 936 |
952 return; | 937 return; |
953 } | 938 } |
954 | 939 |
955 if (m_navigating || mode == ViewManager::NavigateMode) { | 940 if (m_navigating || mode == ViewManager::NavigateMode) { |
959 m_mousePos = e->pos(); | 944 m_mousePos = e->pos(); |
960 update(); | 945 update(); |
961 | 946 |
962 } else { | 947 } else { |
963 | 948 |
964 //!!! want to do some cleverness to avoid dragging left/right | 949 dragTopLayer(e); |
965 // at the same time as up/down when the user moves the mouse | |
966 // diagonally. | |
967 // e.g. have horizontal and vertical thresholds and a series | |
968 // of states: unknown, constrained, free | |
969 // | |
970 // -> when the mouse first moves we're in unknown state: | |
971 // what then? the thing we really want to avoid is moving | |
972 // a tiny amount in the wrong direction, because usually | |
973 // the problem is that to move at all is expensive -- so what | |
974 // do we do? | |
975 // | |
976 // -> when it's moved more than say 10px in h or v | |
977 // direction we lock into h or v constrained mode. If it | |
978 // moves more than say 20px in the other direction | |
979 // subsequently, then we switch into free mode. | |
980 | |
981 int xdiff = e->x() - m_clickPos.x(); | |
982 int ydiff = e->y() - m_clickPos.y(); | |
983 int smallThreshold = 10, bigThreshold = 50; | |
984 | |
985 bool canMoveVertical = true; | |
986 bool canMoveHorizontal = true; | |
987 | |
988 //!!! need to test whether the layer is actually draggable | |
989 // vertically before we do any of this | |
990 | |
991 if (m_dragMode == UnresolvedDrag) { | |
992 | |
993 if (abs(ydiff) > smallThreshold && | |
994 abs(ydiff) > abs(xdiff) * 2) { | |
995 m_dragMode = VerticalDrag; | |
996 } else if (abs(xdiff) > smallThreshold && | |
997 abs(xdiff) > abs(ydiff) * 2) { | |
998 m_dragMode = HorizontalDrag; | |
999 } else if (abs(xdiff) > smallThreshold && | |
1000 abs(ydiff) > smallThreshold) { | |
1001 m_dragMode = FreeDrag; | |
1002 } else { | |
1003 // When playing, we don't want to disturb the play | |
1004 // position too easily; when not playing, we don't | |
1005 // want to move up/down too easily | |
1006 if (m_manager && m_manager->isPlaying()) { | |
1007 canMoveHorizontal = false; | |
1008 } else { | |
1009 canMoveVertical = false; | |
1010 } | |
1011 } | |
1012 } | |
1013 | |
1014 if (m_dragMode == VerticalDrag) { | |
1015 if (abs(xdiff) > bigThreshold) m_dragMode = FreeDrag; | |
1016 else canMoveHorizontal = false; | |
1017 } | |
1018 | |
1019 if (m_dragMode == HorizontalDrag) { | |
1020 if (abs(ydiff) > bigThreshold) m_dragMode = FreeDrag; | |
1021 else canMoveVertical = false; | |
1022 } | |
1023 | |
1024 if (canMoveHorizontal) { | |
1025 | |
1026 long frameOff = getFrameForX(e->x()) - getFrameForX(m_clickPos.x()); | |
1027 | |
1028 size_t newCentreFrame = m_dragCentreFrame; | |
1029 | |
1030 if (frameOff < 0) { | |
1031 newCentreFrame -= frameOff; | |
1032 } else if (newCentreFrame >= size_t(frameOff)) { | |
1033 newCentreFrame -= frameOff; | |
1034 } else { | |
1035 newCentreFrame = 0; | |
1036 } | |
1037 | |
1038 if (newCentreFrame >= getModelsEndFrame()) { | |
1039 newCentreFrame = getModelsEndFrame(); | |
1040 if (newCentreFrame > 0) --newCentreFrame; | |
1041 } | |
1042 | |
1043 if (getXForFrame(m_centreFrame) != getXForFrame(newCentreFrame)) { | |
1044 setCentreFrame(newCentreFrame); | |
1045 } | |
1046 } | |
1047 | |
1048 //!!! For drag up/down, we need to: call getValueExtents | |
1049 //and getDisplayExtents and see whether both return true | |
1050 //(we can only drag up/down if they do); and check whether | |
1051 //the ranges returned differ (likewise). Then, we know | |
1052 //the height of the layer, so... | |
1053 | |
1054 //!!! this should have its own function | |
1055 | |
1056 if (canMoveVertical) { | |
1057 | |
1058 Layer *layer = 0; | |
1059 if (getLayerCount() > 0) layer = getLayer(getLayerCount() - 1); | |
1060 | |
1061 if (layer) { | |
1062 | |
1063 float vmin = 0.f, vmax = 0.f; | |
1064 bool vlog = false; | |
1065 QString vunit; | |
1066 | |
1067 float dmin = 0.f, dmax = 0.f; | |
1068 | |
1069 if (layer->getValueExtents(vmin, vmax, vlog, vunit) && | |
1070 layer->getDisplayExtents(dmin, dmax) && | |
1071 (dmin > vmin || dmax < vmax)) { | |
1072 | |
1073 std::cerr << "ydiff = " << ydiff << std::endl; | |
1074 | |
1075 float perpix = (dmax - dmin) / height(); | |
1076 float valdiff = ydiff * perpix; | |
1077 std::cerr << "valdiff = " << valdiff << std::endl; | |
1078 | |
1079 float newmin = m_dragStartMinValue + valdiff; | |
1080 float newmax = m_dragStartMinValue + (dmax - dmin) + valdiff; | |
1081 if (newmin < vmin) { | |
1082 newmax += vmin - newmin; | |
1083 newmin += vmin - newmin; | |
1084 } | |
1085 if (newmax > vmax) { | |
1086 newmin -= newmax - vmax; | |
1087 newmax -= newmax - vmax; | |
1088 } | |
1089 std::cerr << "(" << dmin << ", " << dmax << ") -> (" | |
1090 << newmin << ", " << newmax << ") (drag start " << m_dragStartMinValue << ")" << std::endl; | |
1091 layer->setDisplayExtents(newmin, newmax); | |
1092 } | |
1093 } | |
1094 } | |
1095 } | 950 } |
1096 | 951 |
1097 } else if (mode == ViewManager::SelectMode) { | 952 } else if (mode == ViewManager::SelectMode) { |
1098 | 953 |
1099 int mouseFrame = getFrameForX(e->x()); | 954 dragExtendSelection(e); |
1100 size_t resolution = 1; | |
1101 int snapFrameLeft = mouseFrame; | |
1102 int snapFrameRight = mouseFrame; | |
1103 | |
1104 Layer *layer = getSelectedLayer(); | |
1105 if (layer && !m_shiftPressed) { | |
1106 layer->snapToFeatureFrame(this, snapFrameLeft, | |
1107 resolution, Layer::SnapLeft); | |
1108 layer->snapToFeatureFrame(this, snapFrameRight, | |
1109 resolution, Layer::SnapRight); | |
1110 } | |
1111 | |
1112 // std::cerr << "snap: frame = " << mouseFrame << ", start frame = " << m_selectionStartFrame << ", left = " << snapFrameLeft << ", right = " << snapFrameRight << std::endl; | |
1113 | |
1114 if (snapFrameLeft < 0) snapFrameLeft = 0; | |
1115 if (snapFrameRight < 0) snapFrameRight = 0; | |
1116 | |
1117 size_t min, max; | |
1118 | |
1119 if (m_selectionStartFrame > snapFrameLeft) { | |
1120 min = snapFrameLeft; | |
1121 max = m_selectionStartFrame; | |
1122 } else if (snapFrameRight > m_selectionStartFrame) { | |
1123 min = m_selectionStartFrame; | |
1124 max = snapFrameRight; | |
1125 } else { | |
1126 min = snapFrameLeft; | |
1127 max = snapFrameRight; | |
1128 } | |
1129 | |
1130 if (m_manager) { | |
1131 m_manager->setInProgressSelection(Selection(min, max), | |
1132 !m_resizing && !m_ctrlPressed); | |
1133 } | |
1134 | |
1135 bool doScroll = false; | |
1136 if (!m_manager) doScroll = true; | |
1137 if (!m_manager->isPlaying()) doScroll = true; | |
1138 if (m_followPlay != PlaybackScrollContinuous) doScroll = true; | |
1139 | |
1140 if (doScroll) { | |
1141 int offset = mouseFrame - getStartFrame(); | |
1142 int available = getEndFrame() - getStartFrame(); | |
1143 if (offset >= available * 0.95) { | |
1144 int move = int(offset - available * 0.95) + 1; | |
1145 setCentreFrame(m_centreFrame + move); | |
1146 } else if (offset <= available * 0.10) { | |
1147 int move = int(available * 0.10 - offset) + 1; | |
1148 if (m_centreFrame > move) { | |
1149 setCentreFrame(m_centreFrame - move); | |
1150 } else { | |
1151 setCentreFrame(0); | |
1152 } | |
1153 } | |
1154 } | |
1155 | |
1156 update(); | |
1157 | 955 |
1158 } else if (mode == ViewManager::DrawMode) { | 956 } else if (mode == ViewManager::DrawMode) { |
1159 | 957 |
1160 Layer *layer = getSelectedLayer(); | 958 Layer *layer = getSelectedLayer(); |
1161 if (layer && layer->isLayerEditable()) { | 959 if (layer && layer->isLayerEditable()) { |
1169 if (layer && layer->isLayerEditable()) { | 967 if (layer && layer->isLayerEditable()) { |
1170 layer->editDrag(this, e); | 968 layer->editDrag(this, e); |
1171 } | 969 } |
1172 } | 970 } |
1173 } | 971 } |
972 } | |
973 | |
974 void | |
975 Pane::zoomToRegion(int x0, int y0, int x1, int y1) | |
976 { | |
977 int w = x1 - x0; | |
978 | |
979 long newStartFrame = getFrameForX(x0); | |
980 | |
981 long visibleFrames = getEndFrame() - getStartFrame(); | |
982 if (newStartFrame <= -visibleFrames) { | |
983 newStartFrame = -visibleFrames + 1; | |
984 } | |
985 | |
986 if (newStartFrame >= long(getModelsEndFrame())) { | |
987 newStartFrame = getModelsEndFrame() - 1; | |
988 } | |
989 | |
990 float ratio = float(w) / float(width()); | |
991 // std::cerr << "ratio: " << ratio << std::endl; | |
992 size_t newZoomLevel = (size_t)nearbyint(m_zoomLevel * ratio); | |
993 if (newZoomLevel < 1) newZoomLevel = 1; | |
994 | |
995 // std::cerr << "start: " << m_startFrame << ", level " << m_zoomLevel << std::endl; | |
996 setZoomLevel(getZoomConstraintBlockSize(newZoomLevel)); | |
997 setStartFrame(newStartFrame); | |
998 | |
999 QString unit; | |
1000 float min, max; | |
1001 bool log; | |
1002 Layer *layer = 0; | |
1003 for (LayerList::const_iterator i = m_layers.begin(); | |
1004 i != m_layers.end(); ++i) { | |
1005 if ((*i)->getValueExtents(min, max, log, unit) && | |
1006 (*i)->getDisplayExtents(min, max)) { | |
1007 layer = *i; | |
1008 break; | |
1009 } | |
1010 } | |
1011 | |
1012 if (layer) { | |
1013 if (log) { | |
1014 min = (min < 0.0) ? -log10f(-min) : (min == 0.0) ? 0.0 : log10f(min); | |
1015 max = (max < 0.0) ? -log10f(-max) : (max == 0.0) ? 0.0 : log10f(max); | |
1016 } | |
1017 float rmin = min + ((max - min) * (height() - y1)) / height(); | |
1018 float rmax = min + ((max - min) * (height() - y0)) / height(); | |
1019 std::cerr << "min: " << min << ", max: " << max << ", y0: " << y0 << ", y1: " << y1 << ", h: " << height() << ", rmin: " << rmin << ", rmax: " << rmax << std::endl; | |
1020 if (log) { | |
1021 rmin = powf(10, rmin); | |
1022 rmax = powf(10, rmax); | |
1023 } | |
1024 std::cerr << "finally: rmin: " << rmin << ", rmax: " << rmax << " " << unit.toStdString() << std::endl; | |
1025 | |
1026 layer->setDisplayExtents(rmin, rmax); | |
1027 updateVerticalPanner(); | |
1028 } | |
1029 } | |
1030 | |
1031 void | |
1032 Pane::dragTopLayer(QMouseEvent *e) | |
1033 { | |
1034 // We need to avoid making it too easy to drag both | |
1035 // horizontally and vertically, in the case where the | |
1036 // mouse is moved "mostly" in horizontal or vertical axis | |
1037 // with only a small variation in the other axis. This is | |
1038 // particularly important during playback (when we want to | |
1039 // avoid small horizontal motions) or in slow refresh | |
1040 // layers like spectrogram (when we want to avoid small | |
1041 // vertical motions). | |
1042 // | |
1043 // To this end we have horizontal and vertical thresholds | |
1044 // and a series of states: unresolved, horizontally or | |
1045 // vertically constrained, free. | |
1046 // | |
1047 // When the mouse first moves, we're unresolved: we | |
1048 // restrict ourselves to whichever direction seems safest, | |
1049 // until the mouse has passed a small threshold distance | |
1050 // from the click point. Then we lock in to one of the | |
1051 // constrained modes, based on which axis that distance | |
1052 // was measured in first. Finally, if it turns out we've | |
1053 // also moved more than a certain larger distance in the | |
1054 // other direction as well, we may switch into free mode. | |
1055 // | |
1056 // If the top layer is incapable of being dragged | |
1057 // vertically, the logic is short circuited. | |
1058 | |
1059 int xdiff = e->x() - m_clickPos.x(); | |
1060 int ydiff = e->y() - m_clickPos.y(); | |
1061 int smallThreshold = 10, bigThreshold = 50; | |
1062 | |
1063 bool canMoveVertical = canTopLayerMoveVertical(); | |
1064 bool canMoveHorizontal = true; | |
1065 | |
1066 if (!canMoveHorizontal) { | |
1067 m_dragMode = HorizontalDrag; | |
1068 } | |
1069 | |
1070 if (m_dragMode == UnresolvedDrag) { | |
1071 | |
1072 if (abs(ydiff) > smallThreshold && | |
1073 abs(ydiff) > abs(xdiff) * 2) { | |
1074 m_dragMode = VerticalDrag; | |
1075 } else if (abs(xdiff) > smallThreshold && | |
1076 abs(xdiff) > abs(ydiff) * 2) { | |
1077 m_dragMode = HorizontalDrag; | |
1078 } else if (abs(xdiff) > smallThreshold && | |
1079 abs(ydiff) > smallThreshold) { | |
1080 m_dragMode = FreeDrag; | |
1081 } else { | |
1082 // When playing, we don't want to disturb the play | |
1083 // position too easily; when not playing, we don't | |
1084 // want to move up/down too easily | |
1085 if (m_manager && m_manager->isPlaying()) { | |
1086 canMoveHorizontal = false; | |
1087 } else { | |
1088 canMoveVertical = false; | |
1089 } | |
1090 } | |
1091 } | |
1092 | |
1093 if (m_dragMode == VerticalDrag) { | |
1094 if (abs(xdiff) > bigThreshold) m_dragMode = FreeDrag; | |
1095 else canMoveHorizontal = false; | |
1096 } | |
1097 | |
1098 if (m_dragMode == HorizontalDrag && canMoveVertical) { | |
1099 if (abs(ydiff) > bigThreshold) m_dragMode = FreeDrag; | |
1100 else canMoveVertical = false; | |
1101 } | |
1102 | |
1103 if (canMoveHorizontal) { | |
1104 | |
1105 long frameOff = getFrameForX(e->x()) - getFrameForX(m_clickPos.x()); | |
1106 | |
1107 size_t newCentreFrame = m_dragCentreFrame; | |
1108 | |
1109 if (frameOff < 0) { | |
1110 newCentreFrame -= frameOff; | |
1111 } else if (newCentreFrame >= size_t(frameOff)) { | |
1112 newCentreFrame -= frameOff; | |
1113 } else { | |
1114 newCentreFrame = 0; | |
1115 } | |
1116 | |
1117 if (newCentreFrame >= getModelsEndFrame()) { | |
1118 newCentreFrame = getModelsEndFrame(); | |
1119 if (newCentreFrame > 0) --newCentreFrame; | |
1120 } | |
1121 | |
1122 if (getXForFrame(m_centreFrame) != getXForFrame(newCentreFrame)) { | |
1123 setCentreFrame(newCentreFrame); | |
1124 } | |
1125 } | |
1126 | |
1127 if (canMoveVertical) { | |
1128 | |
1129 float vmin = 0.f, vmax = 0.f; | |
1130 float dmin = 0.f, dmax = 0.f; | |
1131 | |
1132 if (getTopLayerDisplayExtents(vmin, vmax, dmin, dmax)) { | |
1133 | |
1134 std::cerr << "ydiff = " << ydiff << std::endl; | |
1135 | |
1136 float perpix = (dmax - dmin) / height(); | |
1137 float valdiff = ydiff * perpix; | |
1138 std::cerr << "valdiff = " << valdiff << std::endl; | |
1139 | |
1140 float newmin = m_dragStartMinValue + valdiff; | |
1141 float newmax = m_dragStartMinValue + (dmax - dmin) + valdiff; | |
1142 if (newmin < vmin) { | |
1143 newmax += vmin - newmin; | |
1144 newmin += vmin - newmin; | |
1145 } | |
1146 if (newmax > vmax) { | |
1147 newmin -= newmax - vmax; | |
1148 newmax -= newmax - vmax; | |
1149 } | |
1150 std::cerr << "(" << dmin << ", " << dmax << ") -> (" | |
1151 << newmin << ", " << newmax << ") (drag start " << m_dragStartMinValue << ")" << std::endl; | |
1152 | |
1153 setTopLayerDisplayExtents(newmin, newmax); | |
1154 updateVerticalPanner(); | |
1155 } | |
1156 } | |
1157 } | |
1158 | |
1159 void | |
1160 Pane::dragExtendSelection(QMouseEvent *e) | |
1161 { | |
1162 int mouseFrame = getFrameForX(e->x()); | |
1163 size_t resolution = 1; | |
1164 int snapFrameLeft = mouseFrame; | |
1165 int snapFrameRight = mouseFrame; | |
1166 | |
1167 Layer *layer = getSelectedLayer(); | |
1168 if (layer && !m_shiftPressed) { | |
1169 layer->snapToFeatureFrame(this, snapFrameLeft, | |
1170 resolution, Layer::SnapLeft); | |
1171 layer->snapToFeatureFrame(this, snapFrameRight, | |
1172 resolution, Layer::SnapRight); | |
1173 } | |
1174 | |
1175 // std::cerr << "snap: frame = " << mouseFrame << ", start frame = " << m_selectionStartFrame << ", left = " << snapFrameLeft << ", right = " << snapFrameRight << std::endl; | |
1176 | |
1177 if (snapFrameLeft < 0) snapFrameLeft = 0; | |
1178 if (snapFrameRight < 0) snapFrameRight = 0; | |
1179 | |
1180 size_t min, max; | |
1181 | |
1182 if (m_selectionStartFrame > snapFrameLeft) { | |
1183 min = snapFrameLeft; | |
1184 max = m_selectionStartFrame; | |
1185 } else if (snapFrameRight > m_selectionStartFrame) { | |
1186 min = m_selectionStartFrame; | |
1187 max = snapFrameRight; | |
1188 } else { | |
1189 min = snapFrameLeft; | |
1190 max = snapFrameRight; | |
1191 } | |
1192 | |
1193 if (m_manager) { | |
1194 m_manager->setInProgressSelection(Selection(min, max), | |
1195 !m_resizing && !m_ctrlPressed); | |
1196 } | |
1197 | |
1198 bool doScroll = false; | |
1199 if (!m_manager) doScroll = true; | |
1200 if (!m_manager->isPlaying()) doScroll = true; | |
1201 if (m_followPlay != PlaybackScrollContinuous) doScroll = true; | |
1202 | |
1203 if (doScroll) { | |
1204 int offset = mouseFrame - getStartFrame(); | |
1205 int available = getEndFrame() - getStartFrame(); | |
1206 if (offset >= available * 0.95) { | |
1207 int move = int(offset - available * 0.95) + 1; | |
1208 setCentreFrame(m_centreFrame + move); | |
1209 } else if (offset <= available * 0.10) { | |
1210 int move = int(available * 0.10 - offset) + 1; | |
1211 if (m_centreFrame > move) { | |
1212 setCentreFrame(m_centreFrame - move); | |
1213 } else { | |
1214 setCentreFrame(0); | |
1215 } | |
1216 } | |
1217 } | |
1218 | |
1219 update(); | |
1174 } | 1220 } |
1175 | 1221 |
1176 void | 1222 void |
1177 Pane::mouseDoubleClickEvent(QMouseEvent *e) | 1223 Pane::mouseDoubleClickEvent(QMouseEvent *e) |
1178 { | 1224 { |
1344 } | 1390 } |
1345 if (value > max) { | 1391 if (value > max) { |
1346 value = max; | 1392 value = max; |
1347 } | 1393 } |
1348 layer->setVerticalZoomStep(value); | 1394 layer->setVerticalZoomStep(value); |
1395 updateVerticalPanner(); | |
1349 } | 1396 } |
1350 } | 1397 } |
1398 | |
1399 void | |
1400 Pane::verticalPannerMoved(float x0, float y0, float w, float h) | |
1401 { | |
1402 float vmin, vmax, dmin, dmax; | |
1403 if (!getTopLayerDisplayExtents(vmin, vmax, dmin, dmax)) return; | |
1404 float y1 = y0 + h; | |
1405 float newmax = vmin + ((1.0 - y0) * (vmax - vmin)); | |
1406 float newmin = vmin + ((1.0 - y1) * (vmax - vmin)); | |
1407 std::cerr << "verticalPannerMoved: (" << x0 << "," << y0 << "," << w | |
1408 << "," << h << ") -> (" << newmin << "," << newmax << ")" << std::endl; | |
1409 setTopLayerDisplayExtents(newmin, newmax); | |
1410 } | |
1351 | 1411 |
1352 bool | 1412 bool |
1353 Pane::editSelectionStart(QMouseEvent *e) | 1413 Pane::editSelectionStart(QMouseEvent *e) |
1354 { | 1414 { |
1355 if (!m_identifyFeatures || | 1415 if (!m_identifyFeatures || |