1 /**
2  * UGENE - Integrated Bioinformatics Tools.
3  * Copyright (C) 2008-2021 UniPro <ugene@unipro.ru>
4  * http://ugene.net
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  * MA 02110-1301, USA.
20  */
21 
22 #include "RowHeightController.h"
23 
24 #include "U2Core/U2SafePoints.h"
25 
26 #include "ScrollController.h"
27 #include "ov_msa/MaCollapseModel.h"
28 #include "ov_msa/MaEditor.h"
29 #include "ov_msa/view_rendering/MaEditorWgt.h"
30 
31 namespace U2 {
32 
RowHeightController(MaEditorWgt * maEditorWgt)33 RowHeightController::RowHeightController(MaEditorWgt *maEditorWgt)
34     : QObject(maEditorWgt),
35       ui(maEditorWgt) {
36 }
37 
getGlobalYPositionByMaRowIndex(int maRowIndex) const38 int RowHeightController::getGlobalYPositionByMaRowIndex(int maRowIndex) const {
39     const MaCollapseModel *collapseModel = ui->getEditor()->getCollapseModel();
40     int viewRowIndex = collapseModel->getViewRowIndexByMaRowIndex(maRowIndex);
41     int offset = 0;
42     for (int viewRow = 0; viewRow < viewRowIndex; viewRow++) {
43         int maRow = collapseModel->getMaRowIndexByViewRowIndex(viewRow);
44         offset += getRowHeightByMaIndex(maRow);
45     }
46     return offset;
47 }
48 
getGlobalYPositionByMaRowIndex(int maRowIndex,const QList<int> & maRowIndexes) const49 int RowHeightController::getGlobalYPositionByMaRowIndex(int maRowIndex, const QList<int> &maRowIndexes) const {
50     int offset = 0;
51     foreach (int currentIndex, maRowIndexes) {
52         if (currentIndex == maRowIndex) {
53             return offset;
54         }
55         offset += getRowHeightByMaIndex(currentIndex);
56     }
57     FAIL(false, 0);
58 }
59 
getGlobalYPositionOfTheFirstVisibleRow(bool countClipped) const60 int RowHeightController::getGlobalYPositionOfTheFirstVisibleRow(bool countClipped) const {
61     return getGlobalYPositionByMaRowIndex(ui->getScrollController()->getFirstVisibleMaRowIndex(countClipped));
62 }
63 
getScreenYPositionOfTheFirstVisibleRow(bool countClipped) const64 int RowHeightController::getScreenYPositionOfTheFirstVisibleRow(bool countClipped) const {
65     const int globalYPositionOfTheFirstVisibleRow = getGlobalYPositionOfTheFirstVisibleRow(countClipped);
66     return globalYPositionOfTheFirstVisibleRow - ui->getScrollController()->getScreenPosition().y();
67 }
68 
getRowHeightByViewRowIndex(int viewRowIndex) const69 int RowHeightController::getRowHeightByViewRowIndex(int viewRowIndex) const {
70     int maRowIndex = ui->getEditor()->getCollapseModel()->getMaRowIndexByViewRowIndex(viewRowIndex);
71     return getRowHeightByMaIndex(maRowIndex);
72 }
73 
getSumOfRowHeightsByMaIndexes(const QList<int> & maRowIndexes) const74 int RowHeightController::getSumOfRowHeightsByMaIndexes(const QList<int> &maRowIndexes) const {
75     int sumHeight = 0;
76     foreach (int maRowIndex, maRowIndexes) {
77         sumHeight += getRowHeightByMaIndex(maRowIndex);
78     }
79     return sumHeight;
80 }
81 
getTotalAlignmentHeight() const82 int RowHeightController::getTotalAlignmentHeight() const {
83     int viewRowCount = ui->getEditor()->getCollapseModel()->getViewRowCount();
84     U2Region globalYRegion = getGlobalYRegionByViewRowsRegion(U2Region(0, viewRowCount));
85     return static_cast<int>(globalYRegion.length);
86 }
87 
getSingleRowHeight() const88 int RowHeightController::getSingleRowHeight() const {
89     const int fontHeight = QFontMetrics(ui->getEditor()->getFont(), ui).height();
90     const float zoomMult = ui->getEditor()->zoomMult;
91     return qRound(fontHeight * zoomMult);
92 }
93 
getMaRowIndexByGlobalYPosition(int y) const94 int RowHeightController::getMaRowIndexByGlobalYPosition(int y) const {
95     int viewRowIndex = getViewRowIndexByGlobalYPosition(y);
96     return ui->getEditor()->getCollapseModel()->getMaRowIndexByViewRowIndex(viewRowIndex);
97 }
98 
getViewRowIndexByGlobalYPosition(int y) const99 int RowHeightController::getViewRowIndexByGlobalYPosition(int y) const {
100     const int viewRowCount = ui->getEditor()->getCollapseModel()->getViewRowCount();
101     int accumulatedHeight = 0;
102     for (int viewRowIndex = 0; viewRowIndex < viewRowCount; viewRowIndex++) {
103         const int rowHeight = getRowHeightByViewRowIndex(viewRowIndex);
104         if (accumulatedHeight + rowHeight <= y) {
105             accumulatedHeight += rowHeight;
106         } else {
107             return viewRowIndex;
108         }
109     }
110     return -1;
111 }
112 
getViewRowIndexByScreenYPosition(int y) const113 int RowHeightController::getViewRowIndexByScreenYPosition(int y) const {
114     return getViewRowIndexByGlobalYPosition(y + ui->getScrollController()->getScreenPosition().y());
115 }
116 
getGlobalYRegionByMaRowIndex(int maRowIndex) const117 U2Region RowHeightController::getGlobalYRegionByMaRowIndex(int maRowIndex) const {
118     int globalYPosition = getGlobalYPositionByMaRowIndex(maRowIndex);
119     int rowHeight = getRowHeightByMaIndex(maRowIndex);
120     return U2Region(globalYPosition, rowHeight);
121 }
122 
getGlobalYRegionByMaRowIndex(int maRowIndex,const QList<int> & maRowIndexes) const123 U2Region RowHeightController::getGlobalYRegionByMaRowIndex(int maRowIndex, const QList<int> &maRowIndexes) const {
124     int globalYPosition = getGlobalYPositionByMaRowIndex(maRowIndex, maRowIndexes);
125     int rowHeight = getRowHeightByMaIndex(maRowIndex);
126     return U2Region(globalYPosition, rowHeight);
127 }
128 
129 // The OUT_OF_RANGE_OFFSET used to build safe coordinates out of the view.
130 // We can't use 0 offset, because the value will overlap with the first or the last row.
131 //
132 // GUI tests notice: GUI tests call RowHeightController to compute initial mouse positioning for overflows.
133 //  In this case the offset must be big enough to skip rubber band.
134 #define OUT_OF_RANGE_OFFSET 5
135 
getGlobalYRegionByViewRowIndex(int viewRowIndex) const136 U2Region RowHeightController::getGlobalYRegionByViewRowIndex(int viewRowIndex) const {
137     MaCollapseModel *collapseModel = ui->getEditor()->getCollapseModel();
138     if (collapseModel->getViewRowCount() == 0) {  // empty alignment.
139         return U2Region(-OUT_OF_RANGE_OFFSET, 0);
140     }
141     int viewRowCount = collapseModel->getViewRowCount();
142     // Return an empty region after the view for viewRowIndexes > maxRows
143     // and a region before the view for viewRowIndex < 0. Use OUT_OF_RANGE_OFFSET for the out of range regions.
144     if (viewRowIndex < 0) {
145         U2Region startOfView = getGlobalYRegionByViewRowIndex(0);
146         return U2Region(startOfView.startPos - OUT_OF_RANGE_OFFSET, 0);
147     } else if (viewRowIndex >= viewRowCount) {
148         U2Region endOfView = getGlobalYRegionByViewRowIndex(viewRowCount - 1);
149         return U2Region(endOfView.endPos() + OUT_OF_RANGE_OFFSET, 0);
150     }
151     int maRow = collapseModel->getMaRowIndexByViewRowIndex(viewRowIndex);
152     return getGlobalYRegionByMaRowIndex(maRow);
153 }
154 
getGlobalYRegionByViewRowsRegion(const U2Region & viewRowsRegion) const155 U2Region RowHeightController::getGlobalYRegionByViewRowsRegion(const U2Region &viewRowsRegion) const {
156     U2Region startPosRegion = getGlobalYRegionByViewRowIndex(viewRowsRegion.startPos);
157     U2Region endPosRegion = getGlobalYRegionByViewRowIndex(viewRowsRegion.endPos() - 1);
158     return U2Region::containingRegion(startPosRegion, endPosRegion);
159 }
160 
getScreenYRegionByViewRowsRegion(const U2Region & viewRowsRegion) const161 U2Region RowHeightController::getScreenYRegionByViewRowsRegion(const U2Region &viewRowsRegion) const {
162     U2Region startPosRegion = getScreenYRegionByViewRowIndex(viewRowsRegion.startPos);
163     U2Region endPosRegion = getScreenYRegionByViewRowIndex(viewRowsRegion.endPos() - 1);
164     return U2Region::containingRegion(startPosRegion, endPosRegion);
165 }
166 
getScreenYRegionByMaRowIndex(int maRowIndex) const167 U2Region RowHeightController::getScreenYRegionByMaRowIndex(int maRowIndex) const {
168     return getScreenYRegionByMaRowIndex(maRowIndex, ui->getScrollController()->getScreenPosition().y());
169 }
170 
getScreenYRegionByMaRowIndex(int maRowIndex,int screenYOrigin) const171 U2Region RowHeightController::getScreenYRegionByMaRowIndex(int maRowIndex, int screenYOrigin) const {
172     U2Region rowRange = getGlobalYRegionByMaRowIndex(maRowIndex);
173     return U2Region(rowRange.startPos - screenYOrigin, rowRange.length);
174 }
175 
mapGlobalToScreen(const U2Region & globalRegion) const176 U2Region RowHeightController::mapGlobalToScreen(const U2Region &globalRegion) const {
177     int screenYOrigin = ui->getScrollController()->getScreenPosition().y();
178     return U2Region(globalRegion.startPos - screenYOrigin, globalRegion.length);
179 }
180 
getScreenYRegionByViewRowIndex(int viewRowIndex) const181 U2Region RowHeightController::getScreenYRegionByViewRowIndex(int viewRowIndex) const {
182     return mapGlobalToScreen(getGlobalYRegionByViewRowIndex(viewRowIndex));
183 }
184 
185 }  // namespace U2
186