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 #ifndef _U2_GSEQUENCE_LINE_VIEW_H_
23 #define _U2_GSEQUENCE_LINE_VIEW_H_
24 
25 #include <QFlag>
26 #include <QFocusEvent>
27 #include <QHBoxLayout>
28 #include <QMenu>
29 #include <QMouseEvent>
30 #include <QPainter>
31 #include <QPixmap>
32 #include <QScopedPointer>
33 #include <QToolButton>
34 #include <QWheelEvent>
35 #include <QWidget>
36 
37 #include <U2Core/U2Region.h>
38 
39 #include <U2Gui/SelectionModificationHelper.h>
40 #include <U2Gui/WidgetWithLocalToolbar.h>
41 
42 namespace U2 {
43 
44 class DNASequenceSelection;
45 class LRegionsSelection;
46 class GScrollBar;
47 class GSequenceLineViewRenderArea;
48 class GObject;
49 class GObjectViewOpConstraints;
50 class SequenceObjectContext;
51 class U2SequenceObject;
52 
53 enum GSLV_UpdateFlag {
54     GSLV_UF_NeedCompleteRedraw = 1 << 0,
55     GSLV_UF_ViewResized = 1 << 1,
56     GSLV_UF_VisibleRangeChanged = 1 << 2,
57     GSLV_UF_SelectionChanged = 1 << 3,
58     GSLV_UF_FocusChanged = 1 << 4,
59     GSLV_UF_FrameChanged = 1 << 5,
60     GSLV_UF_AnnotationsChanged = 1 << 6
61 };
62 
63 enum GSLV_FeatureFlag {
64     /** If set the view can show any requested custom range. Same with Zooming. */
65     GSLV_FF_SupportsCustomRange = 0x1
66 };
67 
68 typedef QFlags<GSLV_UpdateFlag> GSLV_UpdateFlags;
69 typedef QFlags<GSLV_FeatureFlag> GSLV_FeatureFlags;
70 
71 // single-line sequence view
72 class U2VIEW_EXPORT GSequenceLineView : public WidgetWithLocalToolbar {
73     Q_OBJECT
74 public:
75     GSequenceLineView(QWidget *p, SequenceObjectContext *ctx);
76 
getVisibleRange()77     const U2Region &getVisibleRange() const {
78         return visibleRange;
79     }
80 
getSequenceContext()81     SequenceObjectContext *getSequenceContext() const {
82         return ctx;
83     }
84 
getRenderArea()85     GSequenceLineViewRenderArea *getRenderArea() const {
86         return renderArea;
87     }
88 
getLastPressPos()89     qint64 getLastPressPos() const {
90         return lastPressPos;
91     }
92 
93     virtual void setStartPos(qint64 pos);
94 
95     virtual void setCenterPos(qint64 pos);
96 
getSequenceLength()97     qint64 getSequenceLength() const {
98         return seqLen;
99     }
100 
addUpdateFlags(GSLV_UpdateFlags newFlags)101     virtual void addUpdateFlags(GSLV_UpdateFlags newFlags) {
102         lastUpdateFlags |= newFlags;
103     }
104 
clearUpdateFlags()105     virtual void clearUpdateFlags() {
106         lastUpdateFlags = 0;
107     }
108 
getUpdateFlags()109     GSLV_UpdateFlags getUpdateFlags() const {
110         return lastUpdateFlags;
111     }
112 
113     virtual void setFrameView(GSequenceLineView *frameView);
114 
getFrameView()115     virtual GSequenceLineView *getFrameView() const {
116         return frameView;
117     }
118 
119     virtual void setCoherentRangeView(GSequenceLineView *rangeView);
120 
getConherentRangeView()121     virtual GSequenceLineView *getConherentRangeView() const {
122         return coherentRangeView;
123     }
124 
125     // [0..seqLen)
126     virtual void setVisibleRange(const U2Region &reg, bool signal = true);
127 
getZoomInAction()128     virtual QAction *getZoomInAction() const {
129         return coherentRangeView == nullptr ? nullptr : coherentRangeView->getZoomInAction();
130     }
131 
getZoomOutAction()132     virtual QAction *getZoomOutAction() const {
133         return coherentRangeView == nullptr ? nullptr : coherentRangeView->getZoomOutAction();
134     }
135 
getZoomToSelectionAction()136     virtual QAction *getZoomToSelectionAction() const {
137         return coherentRangeView == nullptr ? nullptr : coherentRangeView->getZoomToSelectionAction();
138     }
139 
getZoomToSequenceAction()140     virtual QAction *getZoomToSequenceAction() const {
141         return coherentRangeView == nullptr ? nullptr : coherentRangeView->getZoomToSequenceAction();
142     }
143 
144     virtual U2SequenceObject *getSequenceObject() const;
145 
buildPopupMenu(QMenu & m)146     virtual void buildPopupMenu(QMenu &m) {
147         Q_UNUSED(m);
148     }
149 
isWidgetOnlyObject(GObject * o)150     virtual bool isWidgetOnlyObject(GObject *o) const {
151         Q_UNUSED(o);
152         return false;
153     }
154 
155     virtual bool eventFilter(QObject *watched, QEvent *event);
156 
157 signals:
158     void si_visibleRangeChanged();
159     void si_centerPosition(qint64 pos);
160 
161 protected:
162     void resizeEvent(QResizeEvent *e);
163     void mousePressEvent(QMouseEvent *me);
164     void mouseReleaseEvent(QMouseEvent *me);
165     void mouseMoveEvent(QMouseEvent *me);
166     void mouseDoubleClickEvent(QMouseEvent *me);
167     void wheelEvent(QWheelEvent *we);
168     void focusInEvent(QFocusEvent *fe);
169     void focusOutEvent(QFocusEvent *fe);
170     void keyPressEvent(QKeyEvent *e);
171     virtual void onVisibleRangeChanged(bool signal = true);
172 
173 public slots:
sl_centerPosition(int pos)174     void sl_centerPosition(int pos) {
175         setCenterPos(pos);
176     }
177 
178 protected slots:
179     virtual void sl_onScrollBarMoved(int pos);
180     virtual void sl_onDNASelectionChanged(LRegionsSelection *thiz, const QVector<U2Region> &added, const QVector<U2Region> &removed);
181     virtual void sl_sequenceChanged();
182     void sl_onFrameRangeChanged();
183     void sl_onCoherentRangeViewRangeChanged();
184     void sl_onLocalCenteringRequest(qint64 pos);
185     void completeUpdate();
186 
187 protected:
188     QPoint toRenderAreaPoint(const QPoint &p) const;
189 
190     /**
191      * Returns a valid Y-range to react to mouse events for the given 'pos'.
192      * Normally this is a whole vertical range of the widget area, but in some widgets, like DetView it may be a limited space.
193      * Reason for this is that DetView is a 'multi-line', while all methods inside GSequenceLineView are 'single-line'.
194      * Uses 'renderArea' local coordinates.
195      */
196     virtual U2Region getCapturingRenderAreaYRegionForPos(qint64 pos) const;
197 
198     virtual void updateScrollBar();
199     virtual void setSelection(const U2Region &r);
200     void addSelection(const U2Region &r);
201     virtual void updateCursorShapeOnMouseMove(const QPoint &p);
202     virtual void moveBorder(const QPoint &p);
203     virtual void pack();
204     virtual qint64 getSingleStep() const;
205     virtual qint64 getPageStep() const;
206     void autoScrolling(const QPoint &areaPoint);
207     virtual void resizeSelection(const QPoint &areaPoint);
208     void cancelSelectionResizing();
209     void changeSelectionOnScrollbarMoving(const U2Region &newSelection);
210     void changeSelection(QVector<U2Region> &regions, const U2Region &newSelection);
211 
212     SequenceObjectContext *ctx;
213     GSequenceLineViewRenderArea *renderArea;
214     U2Region visibleRange;
215     GScrollBar *scrollBar;
216     qint64 lastPressPos;
217     U2Region resizableRegion;
218     QList<U2Region> overlappedRegions;
219     qint64 seqLen;
220     GSLV_UpdateFlags lastUpdateFlags;
221     GSLV_FeatureFlags featureFlags;
222     GSequenceLineView *frameView;
223     GSequenceLineView *coherentRangeView;
224     double coefScrollBarMapping;
225 
226     // special flag setup by child classes that tells to this class do or skip
227     // any changes to selection on mouse ops
228     bool ignoreMouseSelectionEvents;
229     bool singleBaseSelection;
230     bool isSelectionResizing;
231 };
232 
233 class U2VIEW_EXPORT GSequenceLineViewRenderArea : public QWidget {
234     Q_OBJECT
235 public:
236     GSequenceLineViewRenderArea(GSequenceLineView *p);
237 
238     /** Returns in-sequence base index by the current on-screen coordinate. */
239     virtual qint64 coordToPos(const QPoint &coord) const;
240 
241     /** Returns a minimal on-screen X coordinate of the given sequence position. */
242     virtual int posToCoord(qint64 pos, bool useVirtualSpace = false) const;
243 
244     /** Returns number of pixels per-base. */
245     virtual double getCurrentScale() const;
246 
247     /** Returns width in pixels required to draw a single text character using sequenceFont. */
getCharWidth()248     int getCharWidth() const {
249         return charWidth;
250     }
251 
252 protected:
253     void paintEvent(QPaintEvent *e) override;
254 
255     virtual void drawAll(QPaintDevice *pd) = 0;
256     void drawFrame(QPainter &p);
257     virtual void drawFocus(QPainter &p);
258 
259     void updateFontMetrics();
260 
261     /** Returns a cached pixmap used to render the whole area. */
getCachedPixmap()262     QPixmap *getCachedPixmap() const {
263         return cachedView.data();
264     }
265 
266     GSequenceLineView *view;
267     QScopedPointer<QPixmap> cachedView;
268 
269     //! VIEW_RENDERER_REFACTORING: the following parameters should be stored only in renderer (until they cannot be modified in view).
270     //! Currently they are doubled in SequenceViewRenderer class.
271     // per char and per line metrics
272     QFont sequenceFont;
273     QFont smallSequenceFont;
274     QFont rulerFont;
275 
276     int charWidth = 0;
277     int smallCharWidth = 0;
278 
279     int lineHeight = 0;
280     int yCharOffset = 0;
281     int xCharOffset = 0;
282 };
283 
284 }  // namespace U2
285 
286 #endif
287