1 //=========================================================
2 //  MusE
3 //  Linux Music Editor
4 //    $Id: ctrlcanvas.h,v 1.7.2.4 2009/06/01 20:15:53 spamatica Exp $
5 //  (C) Copyright 1999 Werner Schweer (ws@seh.de)
6 //
7 //  This program is free software; you can redistribute it and/or
8 //  modify it under the terms of the GNU General Public License
9 //  as published by the Free Software Foundation; version 2 of
10 //  the License, or (at your option) any later version.
11 //
12 //  This program is distributed in the hope that it will be useful,
13 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 //  GNU General Public License for more details.
16 //
17 //  You should have received a copy of the GNU General Public License
18 //  along with this program; if not, write to the Free Software
19 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 //
21 //=========================================================
22 
23 #ifndef __CTRLCANVAS_H__
24 #define __CTRLCANVAS_H__
25 
26 #include <set>
27 
28 #include "type_defs.h"
29 #include "view.h"
30 #include "tools.h"
31 #include "midictrl.h"
32 #include "event.h"
33 #include "citem.h"
34 #include "undo.h"
35 #include "event_tag_list.h"
36 
37 class QWheelEvent;
38 class QMouseEvent;
39 class QEvent;
40 class QWidget;
41 class QLabel;
42 
43 namespace MusECore {
44 class Event;
45 class MidiPart;
46 class MidiTrack;
47 class PartList;
48 }
49 
50 namespace MusEGui {
51 
52 class CtrlPanel;
53 class MidiEditor;
54 class PopupMenu;
55 
56 //---------------------------------------------------------
57 //   CEvent
58 //    ''visual'' Controller Event
59 //---------------------------------------------------------
60 
61 class CEvent : public CItem {
62    private:
63       MusECore::Event _event;
64       int _val;
65       MusECore::Part* _part;
66       int ex;
67 
68    public:
69       CEvent(const MusECore::Event&, MusECore::Part*, int v);
70       CEvent();
71       bool isObjectInRange(const MusECore::Pos&, const MusECore::Pos&) const;
objectIsSelected()72       bool objectIsSelected() const { return _event.selected(); }
73 
val()74       int val() const              { return _val;   }
setVal(int v)75       void setVal(int v)           { _val = v; }
setEX(int v)76       void setEX(int v)            { ex = v; }
77       bool containsPoint(const MusECore::MidiController* mc, const QPoint& p, const int tickstep, const int wh) const;
78       bool containsXRange(int x1, int x2) const;
79       bool intersectsController(const MusECore::MidiController*, const QRect&, const int tickstep, const int windowHeight) const;
EX()80       int EX()                      { return ex; }
81 
event()82       MusECore::Event event() const         { return _event;  }
83       // HACK This returns a clone of the event with the length set to the visual length.
84       //      It should only be used for temporary things like copy/paste and the length
85       //       value should be reset to zero after usage.
86       //      Normally an event's length is ALWAYS zero for all controller events.
87       MusECore::Event eventWithLength() const;
setEvent(const MusECore::Event & e)88       void setEvent(const MusECore::Event& e)     { _event = e;     }
part()89       MusECore::Part* part() const  { return _part;  }
setPart(MusECore::Part * p)90       void setPart(MusECore::Part* p)       { _part = p; }
91       };
92 
93 //---------------------------------------------------------
94 //   CtrlCanvas
95 //---------------------------------------------------------
96 
97 class CtrlCanvas : public MusEGui::View {
98       Q_OBJECT
99 
100       Q_PROPERTY( quint8 bgAlpha READ bgAlpha WRITE setBgAlpha )
101 
102     public:
103 
104       //---------------------------------------------------------
105       //   CtrlCanvasInfoStruct
106       //    Structure for returning info from CtrlCanvas::getCtrlInfo()
107       //---------------------------------------------------------
108 
109       struct CtrlCanvasInfoStruct
110       {
111         int fin_ctrl_num;
112         bool is_newdrum_ctl;
113         int min;
114         int max;
115         int bias;
116 
CtrlCanvasInfoStructCtrlCanvasInfoStruct117         CtrlCanvasInfoStruct() : fin_ctrl_num(0), is_newdrum_ctl(false), min(0), max(127), bias(0) {}
118       };
119 
120     private:
121       MidiEditor* editor;
122       MusECore::MidiTrack* curTrack;
123       MusECore::MidiPart* curPart;
124       MusECore::MidiCtrlValList* ctrl;
125       MusECore::MidiController* _controller;
126       CtrlPanel* _panel;
127       int _cnum;
128       int _dnum; // Current real drum controller number (anote).
129       int _didx; // Current real drum controller index.
130       // For current part.
131       CtrlCanvasInfoStruct _ctrlInfo;
132 
133       int line1x;
134       int line1y;
135       int line2x;
136       int line2y;
137       bool drawLineMode;
138       bool noEvents;
139       bool filterTrack;
140       // Whether we have grabbed the mouse.
141       bool _mouseGrabbed;
142       // The number of times we have called QApplication::setOverrideCursor().
143       // This should always be one or zero, anything else is an error, but unforeseen
144       //  events might cause us to miss a decrement with QApplication::restoreOverrideCursor().
145       int _cursorOverrideCount;
146       quint8 _bgAlpha;
147 
148       QPoint _curDragOffset;
149       unsigned int _dragFirstXPos;
150       //Qt::CursorShape _cursorShape;
151 
152       static const int overlayTextOffsetFromOrg;
153 
154       void applyYOffset(MusECore::Event& e, int yoffset) const;
155 
156       void viewMousePressEvent(QMouseEvent* event);
157       void viewMouseMoveEvent(QMouseEvent*);
158       void viewMouseReleaseEvent(QMouseEvent*);
159       virtual void wheelEvent(QWheelEvent*);
160 
161       virtual void draw(QPainter&, const QRect& rect, const QRegion& = QRegion());
162       virtual void pdraw(QPainter&, const QRect&, const QRegion& = QRegion());
163       virtual void drawOverlay(QPainter&, const QRect&, const QRegion& = QRegion());
164       virtual QRect overlayRect() const;
165 
166       void changeValRamp(int x1, int x2, int y1, int y2);
167       void newValRamp(int x1, int y1, int x2, int y2);
168       void changeVal(int x1, int x2, int y);
169       void newVal(int x1, int y);
170       void newVal(int x1, int y1, int x2, int y2);
171       void deleteVal(int x1, int x2, int y);
172 
173       bool setCurTrackAndPart();
174       void drawMoving(QPainter& p, const QRect& rect, const QRegion& region, const MusECore::MidiPart* part);
175       void pdrawItems(QPainter& p, const QRect& rect, const MusECore::MidiPart* part, bool velo, bool fg);
176       void pFillBackgrounds(QPainter& p, const QRect& rect, const MusECore::MidiPart* part);
177       void pdrawExtraDrumCtrlItems(QPainter& p, const QRect& rect, const MusECore::MidiPart* part, int drum_ctl);
178       void partControllers(
179         const MusECore::MidiPart* part, int num,
180         int* dnum, int* didx,
181         MusECore::MidiController** mc, MusECore::MidiCtrlValList** mcvl,
182         CtrlCanvasInfoStruct* ctrlInfo);
183       // Checks if the current drum pitch requires setting the midi controller and rebuilding the items.
184       // Returns whether setMidiController() and updateItems() were in fact called.
185       bool drumPitchChanged();
186       CEvent* findCurrentItem(const QPoint& p, const int tickstep, const int h);
187       // If show is true, calls QApplication::restoreOverrideCursor() until _cursorOverrideCount-- is <= 0.
188       // If show is false, calls QApplication::setOverrideCursor with a blank cursor.
189       void showCursor(bool show = true);
190       // Sets or resets the _mouseGrabbed flag and grabs or releases the mouse.
191       void setMouseGrab(bool grabbed = false);
192 
193    protected:
194       enum DragMode { DRAG_OFF, DRAG_NEW, DRAG_MOVE_START, DRAG_MOVE,
195             DRAG_DELETE, DRAG_COPY_START, DRAG_COPY,
196             DRAGX_MOVE, DRAGY_MOVE,
197             DRAGX_COPY, DRAGY_COPY,
198             DRAG_RESIZE, DRAG_LASSO_START, DRAG_LASSO,
199             DRAG_PAN, DRAG_ZOOM
200             };
201 
202       enum DragType {
203             MOVE_MOVE, MOVE_COPY
204             };
205 
206       enum ContextIds {
207         ContextIdCancelDrag = 0x01,
208         ContextIdMerge = 0x02,
209         ContextIdMergeCopy = 0x04,
210         ContextIdErase = 0x08,
211         ContextIdEraseWysiwyg = 0x10,
212         ContextIdEraseInclusive = 0x20
213       };
214 
215       CItemList items;
216       // To avoid working directly with a potentially huge number of items
217       //  in the item list, these 'indexing' lists are used instead.
218       CItemList selection;
219       CItemList moving;
220 
221       CEvent* curItem;
222       CEvent* _movingItemUnderCursor;
223 
224       DragMode drag;
225       DragType _dragType;
226       QRect lasso;
227       QPoint start;
228       QPoint _mouseDist;
229       MusEGui::Tool tool;
230       unsigned pos[3];
231       int curDrumPitch;    //Used by the drum-editor to view velocity of only one key (one drum)
232       bool _perNoteVeloMode;
233 
234       // Accumulated operations during drawing etc.
235       MusECore::Undo _operations;
236 
237       void setCursor();
238       void keyPressEvent(QKeyEvent *event);
239       void keyReleaseEvent(QKeyEvent *event);
240       void enterEvent(QEvent*e);
241       void leaveEvent(QEvent*e);
242       QPoint raster(const QPoint&) const;
243 
244       // selection
isSingleSelection()245       bool isSingleSelection()  { return selection.size() == 1; }
246       void deselectAll();
247       void selectItem(CEvent* e);
248       void deselectItem(CEvent* e);
249       void removeSelection(CEvent* e);
250 
251       void setMidiController(int);
252       void updateItems();
253       // Inform the app if local items have changed and their corresponding
254       //  objects need to be updated synchronously in the audio thread.
255       // Returns true if anything changed (or will change).
256       // Uses an internal undo operations list or optionally with a supplied list
257       //  so operations can be chained.
258       bool itemSelectionsChanged(MusECore::Undo* operations = 0, bool deselectAll = false);
259       void updateItemSelections();
260 
261       // moving
262       void startMoving(const QPoint&, int dir, bool rasterize = true);
263       void moveItems(const QPoint&, int dir = 0, bool rasterize = true);
264       void endMoveItems();
265       MusECore::Undo moveCanvasItems(CItemList&, int, int, DragType, bool rasterize = true);
266       bool moveItem(MusECore::Undo&, CItem*, const QPoint&, DragType, bool rasterize = true);
267       // Resets the moving flag of all items in moving list, then clears the list.
268       // Returns true if anything was changed.
269       bool clearMoving();
270       // Resets all mouse operations if detecting missed mouseRelease event (which DOES happen).
271       // Returns true if reset was actually done.
272       bool cancelMouseOps();
273 
274       // Populates a popup menu with items related to drag/drop merging.
275       void populateMergeOptions(PopupMenu* menu);
276 
277       // Merges any dragged items. Merges copies of items if 'copy' is true. Otherwise moves the items.
278       // Returns true if items were merged, and it was successful. False if no items were moving, or error.
279       bool mergeDraggedItems(bool copy);
280 
281    private slots:
282       void songChanged(MusECore::SongChangedStruct_t type);
283       void configChanged();
284       // Returns whether setMidiController() and updateItems() were in fact called, via drumPitchChanged().
285       bool setCurDrumPitch(int);
286 
287    public slots:
288       void setTool(int t);
289       void setPos(int, unsigned, bool adjustScrollbar);
290       void setController(int ctrl);
291       void curPartHasChanged(MusECore::Part*);
292 
293    signals:
294       void followEvent(int);
295       void xposChanged(unsigned);
296       void yposChanged(int);
297       void redirectWheelEvent(QWheelEvent*);
298 
299    public:
300       CtrlCanvas(MidiEditor*, QWidget* parent, int,
301          const char* name = 0, CtrlPanel* pnl = 0);
302       ~CtrlCanvas();
303       void setPanel(CtrlPanel* pnl);
ctrlValList()304       MusECore::MidiCtrlValList* ctrlValList() { return ctrl; }
controller()305       MusECore::MidiController* controller() { return _controller; }
track()306       MusECore::MidiTrack* track() const { return curTrack; }
getCurDrumPitch()307       int getCurDrumPitch() const { return curDrumPitch; }
perNoteVeloMode()308       bool perNoteVeloMode() const { return _perNoteVeloMode; }
309       void setPerNoteVeloMode(bool);
itemsAreSelected()310       bool itemsAreSelected() const { return !selection.empty(); }
311       // Appends given tag list with item objects according to options. Avoids duplicate events or clone events.
312       // Special: We 'abuse' a controller event's length, normally 0, to indicate visual item length.
313       void tagItems(MusECore::TagEventList* tag_list, const MusECore::EventTagOptionsStruct& options) const;
314 
bgAlpha()315       quint8 bgAlpha() const { return _bgAlpha; }
setBgAlpha(const quint8 a)316       void setBgAlpha(const quint8 a) { _bgAlpha = a; }
317 };
318 
319 } // namespace MusEGui
320 
321 #endif
322 
323