~ubuntu-branches/ubuntu/karmic/kguitar/karmic

« back to all changes in this revision

Viewing changes to kguitar/trackview.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Loic Pefferkorn
  • Date: 2005-08-19 15:22:41 UTC
  • Revision ID: james.westby@ubuntu.com-20050819152241-n24w9np4vblrm5as
Tags: upstream-0.5
ImportĀ upstreamĀ versionĀ 0.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "trackview.h"
 
2
#include "trackviewcommands.h"
 
3
#include "tabsong.h"
 
4
#include "chord.h"
 
5
#include "rhythmer.h"
 
6
#include "keysig.h"
 
7
#include "timesig.h"
 
8
#include "songview.h"
 
9
#include "fretboard.h"
 
10
#include "settings.h"
 
11
 
 
12
#include <kglobalsettings.h>
 
13
#include <kglobal.h>
 
14
#include <kmessagebox.h>
 
15
#include <klocale.h>
 
16
#include <kpopupmenu.h>
 
17
#include <kxmlgui.h>
 
18
#include <kxmlguiclient.h>
 
19
 
 
20
#include <qwidget.h>
 
21
#include <qpainter.h>
 
22
#include <qpen.h>
 
23
#include <qkeycode.h>
 
24
#include <qcursor.h>
 
25
#include <qstyle.h>
 
26
 
 
27
#include "trackprint.h"
 
28
 
 
29
#include <qspinbox.h>
 
30
#include <qcombobox.h>
 
31
#include <qcheckbox.h>
 
32
 
 
33
#include <stdlib.h>             // required for declaration of abs()
 
34
 
 
35
// LVIFIX: note differences between "old" (in trackview.cpp) and "new" drawing code (in trackprint.cpp):
 
36
// - erase width around tab column numbers is "as tight as possible", while the cursor is a bit wider,
 
37
//   which leads to minor reverse-video artefacts under the cursor
 
38
// - starting bars (very thick and thick one) not implemented
 
39
// - harmonics use a diamond instead of text in the new code
 
40
// - palm muting uses a small cross instead of text in the new code
 
41
 
 
42
// Define if both "old" and "new" drawing code must be used at the same time
 
43
// Undefine to use only the "new" drawing code
 
44
#undef USE_BOTH_OLD_AND_NEW
 
45
// #define USE_BOTH_OLD_AND_NEW
 
46
 
 
47
#ifdef USE_BOTH_OLD_AND_NEW
 
48
#define VERTSPACE                      230 // between top of cell and first line
 
49
#define VERTLINE                        10 // between horizontal tabulature lines
 
50
#define HORDUR                          4
 
51
#define HORCELL                         14 // horizontal size of tab numbers column
 
52
#define TIMESIGSIZE                     14 // horizontal time sig size
 
53
#define ABBRLENGTH                      25 // drum abbreviations horizontal size
 
54
 
 
55
#define BOTTOMDUR   VERTSPACE+VERTLINE*(s+1)
 
56
#endif
 
57
 
 
58
#define NORMAL_FONT_FACTOR              0.8
 
59
#define TIME_SIG_FONT_FACTOR            1.4
 
60
#define SMALL_CAPTION_FONT_FACTOR       0.7
 
61
 
 
62
// definitions for the "new" drawing code layout
 
63
#define TOPSPTB                         3   // top space tabbar in ysteptb units
 
64
#define BOTSPTB                         3   // bottom space tabbar in ysteptb units
 
65
#define ADDSPST                         1.5 // additional top space staff in ystepst units
 
66
#define TOPSPST                         7.5 // top space staff in ystepst units
 
67
#define BOTSPST                         1.5 // bottom space staff in ystepst units
 
68
#define NLINEST                         5   // number of staff lines
 
69
 
 
70
TrackView::TrackView(TabSong *s, KXMLGUIClient *_XMLGUIClient, KCommandHistory *_cmdHist,
 
71
#ifdef WITH_TSE3
 
72
                     TSE3::MidiScheduler *_scheduler,
 
73
#endif
 
74
                     QWidget *parent, const char *name): QGridView(parent, name)
 
75
{
 
76
        setFrameStyle(Panel | Sunken);
 
77
        setBackgroundMode(PaletteBase);
 
78
 
 
79
        setNumCols(1);
 
80
 
 
81
        setFocusPolicy(QWidget::StrongFocus);
 
82
 
 
83
        xmlGUIClient = _XMLGUIClient;
 
84
        cmdHist = _cmdHist;
 
85
 
 
86
        song = s;
 
87
        setCurrentTrack(s->t.first());
 
88
 
 
89
        normalFont = new QFont(KGlobalSettings::generalFont());
 
90
        if (normalFont->pointSize() == -1) {
 
91
                normalFont->setPixelSize((int) ((double) normalFont->pixelSize() * NORMAL_FONT_FACTOR));
 
92
        } else {
 
93
                normalFont->setPointSizeFloat(normalFont->pointSizeFloat() * NORMAL_FONT_FACTOR);
 
94
        }
 
95
 
 
96
        smallCaptionFont = new QFont(*normalFont);
 
97
        if (smallCaptionFont->pointSize() == -1) {
 
98
                smallCaptionFont->setPixelSize((int) ((double) smallCaptionFont->pixelSize() * SMALL_CAPTION_FONT_FACTOR));
 
99
        } else {
 
100
                smallCaptionFont->setPointSizeFloat(smallCaptionFont->pointSizeFloat() * SMALL_CAPTION_FONT_FACTOR);
 
101
        }
 
102
 
 
103
        timeSigFont = new QFont(*normalFont);
 
104
        if (timeSigFont->pointSize() == -1) {
 
105
                timeSigFont->setPixelSize((int) ((double) timeSigFont->pixelSize() * TIME_SIG_FONT_FACTOR));
 
106
        } else {
 
107
                timeSigFont->setPointSizeFloat(timeSigFont->pointSizeFloat() * TIME_SIG_FONT_FACTOR);
 
108
        }
 
109
        timeSigFont->setBold(TRUE);
 
110
 
 
111
        fetaFont   = 0;
 
112
        fetaNrFont = 0;
 
113
        
 
114
        lastnumber = -1;
 
115
        zoomLevel = 10;
 
116
 
 
117
#ifdef WITH_TSE3
 
118
        scheduler = _scheduler;
 
119
#endif
 
120
 
 
121
        playbackCursor = FALSE;
 
122
 
 
123
        trp = new TrackPrint;
 
124
        trp->setOnScreen();
 
125
        const int lw = 1;
 
126
        trp->pLnBl = QPen(Qt::black, lw);
 
127
        trp->pLnWh = QPen(Qt::white, lw);
 
128
 
 
129
        updateRows();           // depends on trp's font metrics
 
130
}
 
131
 
 
132
TrackView::~TrackView()
 
133
{
 
134
        delete normalFont;
 
135
        delete smallCaptionFont;
 
136
        delete timeSigFont;
 
137
        delete trp;
 
138
}
 
139
 
 
140
void TrackView::initFonts(QFont *f4, QFont *f5)
 
141
{
 
142
        fetaFont   = f4;
 
143
        fetaNrFont = f5;
 
144
        trp->initFonts(normalFont, smallCaptionFont, timeSigFont, fetaFont, fetaNrFont);
 
145
}
 
146
 
 
147
void TrackView::selectTrack(TabTrack *trk)
 
148
{
 
149
        setCurrentTrack(trk);
 
150
        updateRows();
 
151
        repaintContents();
 
152
}
 
153
 
 
154
void TrackView::selectBar(uint n)
 
155
{
 
156
        if (n != (uint) curt->xb && n < curt->b.size()) {
 
157
                curt->x = curt->b[n].start;
 
158
                curt->xb = n;
 
159
                ensureCurrentVisible();
 
160
                emit barChanged();
 
161
                emit columnChanged();
 
162
        }
 
163
        lastnumber = -1;
 
164
}
 
165
 
 
166
void TrackView::setCurrentTrack(TabTrack *trk)
 
167
{
 
168
        curt = trk;
 
169
        emit trackChanged(trk);
 
170
}
 
171
 
 
172
// Set new horizontal zoom level and update display accordingly
 
173
void TrackView::setZoomLevel(int newZoomLevel)
 
174
{
 
175
        if (newZoomLevel > 0) {
 
176
                zoomLevel = newZoomLevel;
 
177
                updateRows();
 
178
                repaintContents();
 
179
        }
 
180
}
 
181
 
 
182
void TrackView::zoomIn()
 
183
{
 
184
        setZoomLevel(zoomLevel - 1);
 
185
}
 
186
 
 
187
void TrackView::zoomOut()
 
188
{
 
189
        setZoomLevel(zoomLevel + 1);
 
190
}
 
191
 
 
192
// Set zoom level dialog
 
193
void TrackView::zoomLevelDialog()
 
194
{
 
195
        // GREYFIX
 
196
}
 
197
 
 
198
void TrackView::updateRows()
 
199
{
 
200
        int ch = (int) ((TOPSPTB + curt->string + BOTSPTB) * trp->ysteptb);
 
201
#ifdef USE_BOTH_OLD_AND_NEW
 
202
        // note: cannot make row height dependent on viewscore without making too many
 
203
        // changes to the "old" drawing code: use fixed height
 
204
        ch += 3 * VERTLINE * 2 + VERTLINE * (curt->string - 1);
 
205
        ch += (int) ((TOPSPST + NLINEST - 1 + BOTSPST) * trp->ystepst);
 
206
        ch += (int) (ADDSPST * trp->ystepst);
 
207
#else
 
208
        if (viewscore && fetaFont) {
 
209
                ch += (int) ((TOPSPST + NLINEST - 1 + BOTSPST) * trp->ystepst);
 
210
                ch += (int) (ADDSPST * trp->ystepst);
 
211
        }
 
212
#endif
 
213
        setNumRows(curt->b.size());
 
214
        setMinimumHeight(ch);
 
215
        setCellHeight(ch);
 
216
//      cout << "TrackView::updateRows()"
 
217
//      << " ch=" << ch
 
218
//      << " nr=" << curt->b.size()
 
219
//      << endl;
 
220
}
 
221
 
 
222
void TrackView::repaintCellNumber(int n)
 
223
{
 
224
        repaintCell(n, 0);
 
225
}
 
226
 
 
227
void TrackView::repaintCurrentCell()
 
228
{
 
229
        repaintCellNumber(curt->xb);
 
230
        emit paneChanged();
 
231
}
 
232
 
 
233
void TrackView::repaintCurrentColumn()
 
234
{
 
235
        //VERTSPACE + (s - i) * VERTLINE - VERTLINE / 2
 
236
 
 
237
        //      int ycoord = 0;
 
238
//      if (rowYPos(curt->xb, &ycoord)) // GREYFIX - what was it all about?
 
239
 
 
240
        // GREYFIX: some crazy things going here about what coordinate
 
241
        // system to use. I'm totally screwed up trying to figure it out,
 
242
        // until I do, just update whole cell.
 
243
 
 
244
//      repaint(selxcoord, cellHeight() * curt->xb - contentsY(), HORCELL + 1, cellHeight());
 
245
 
 
246
        repaintCell(curt->xb, 0);
 
247
//      emit paneChanged();
 
248
}
 
249
 
 
250
// Checks is current bar is fully visible, and, if it's not, tries to
 
251
// do minimal scrolling to ensure the full visibility
 
252
void TrackView::ensureCurrentVisible()
 
253
{
 
254
/*      int ch = cellHeight();
 
255
 
 
256
        if ((curt->xb + 1) * ch > yOffset() + height())
 
257
                setYOffset((curt->xb + 1) * ch - height());
 
258
        else if (curt->xb * ch < yOffset())
 
259
                setYOffset(curt->xb * ch);
 
260
*/ //GREYFIX
 
261
        ensureCellVisible(curt->xb, 0);
 
262
}
 
263
 
 
264
// Process a mouse press of fret "fret" in current column on string
 
265
// "num". Depending on given "button" mouse state flags, additional
 
266
// things may happen.
 
267
void TrackView::melodyEditorPress(int num, int fret, ButtonState button = NoButton)
 
268
{
 
269
        if (button & LeftButton)
 
270
                melodyEditorAction(num, fret, 0);
 
271
        if (button & MidButton)
 
272
                melodyEditorAction(num, fret, 1);
 
273
        if (button & RightButton)
 
274
                melodyEditorAction(num, fret, 2);
 
275
}
 
276
 
 
277
// Execute one of melody editors actions, as defined in
 
278
// globalMelodyEditorAction array
 
279
void TrackView::melodyEditorAction(int num, int fret, int action)
 
280
{
 
281
        // GREYFIX: make it *one* undo transaction
 
282
        switch (Settings::melodyEditorAction(action)) {
 
283
        case 0: // no action
 
284
                break;
 
285
        case 1: // set note
 
286
                setFinger(num, fret);
 
287
                break;
 
288
        case 3: // set 022 power chord
 
289
                setFinger(num + 2, fret + 2);
 
290
        case 2: // set 02 power chord
 
291
                setFinger(num + 1, fret + 2);
 
292
                setFinger(num, fret);
 
293
                break;
 
294
        case 5: // set 0022 power chord
 
295
                setFinger(num + 3, fret + 2);
 
296
                setFinger(num + 2, fret + 2);
 
297
        case 4: // set 00 power chord
 
298
                setFinger(num + 1, fret);
 
299
                setFinger(num, fret);
 
300
                break;
 
301
        case 6: // delete note
 
302
                setFinger(num, NULL_NOTE);
 
303
                break;
 
304
        }
 
305
}
 
306
 
 
307
// Process a mouse release in melody editor. Depending on given
 
308
// "button" mouse state flags, additional things, such as proceeding
 
309
// to next column, may happen.
 
310
void TrackView::melodyEditorRelease(ButtonState button)
 
311
{
 
312
        if (((button & LeftButton)  && (Settings::melodyEditorAdvance(0))) ||
 
313
                ((button & MidButton)   && (Settings::melodyEditorAdvance(1))) ||
 
314
                ((button & RightButton) && (Settings::melodyEditorAdvance(2))))  {
 
315
                if (curt->sel) {
 
316
                        curt->sel = FALSE;
 
317
                        repaintContents();
 
318
                }
 
319
                moveRight();
 
320
        }
 
321
}
 
322
 
 
323
// Add tab number insertion command on current column, string "num",
 
324
// setting fret number "fret". Perform various checks, including
 
325
// no repeats for same insertion.
 
326
void TrackView::setFinger(int num, int fret)
 
327
{
 
328
        if (num < 0 || num >= curt->string)
 
329
                return;
 
330
        if (fret > curt->frets)
 
331
                return;
 
332
        if (curt->c[curt->x].a[num] == fret)
 
333
                return;
 
334
 
 
335
        curt->y = num;
 
336
        cmdHist->addCommand(new InsertTabCommand(this, curt, fret));
 
337
        repaintCurrentColumn();
 
338
        emit columnChanged();
 
339
}
 
340
 
 
341
int TrackView::finger(int num)
 
342
{
 
343
        return curt->c[curt->x].a[num];
 
344
}
 
345
 
 
346
void TrackView::setLength(int l)
 
347
{
 
348
        //only if needed
 
349
        if (curt->c[curt->x].l != l)
 
350
                cmdHist->addCommand(new SetLengthCommand(this, curt, l));
 
351
}
 
352
 
 
353
void TrackView::linkPrev()
 
354
{
 
355
        cmdHist->addCommand(new SetFlagCommand(this, curt, FLAG_ARC));
 
356
        lastnumber = -1;
 
357
}
 
358
 
 
359
void TrackView::addHarmonic()
 
360
{
 
361
        if (curt->c[curt->x].a[curt->y] >= 0)
 
362
                cmdHist->addCommand(new AddFXCommand(this, curt, EFFECT_HARMONIC));
 
363
        lastnumber = -1;
 
364
}
 
365
 
 
366
void TrackView::addArtHarm()
 
367
{
 
368
        if (curt->c[curt->x].a[curt->y] >= 0)
 
369
                cmdHist->addCommand(new AddFXCommand(this, curt, EFFECT_ARTHARM));
 
370
        lastnumber = -1;
 
371
}
 
372
 
 
373
void TrackView::addLegato()
 
374
{
 
375
        if (curt->c[curt->x].a[curt->y] >= 0)
 
376
                cmdHist->addCommand(new AddFXCommand(this, curt, EFFECT_LEGATO));
 
377
        lastnumber = -1;
 
378
}
 
379
 
 
380
void TrackView::addSlide()
 
381
{
 
382
        if (curt->c[curt->x].a[curt->y] >= 0)
 
383
                cmdHist->addCommand(new AddFXCommand(this, curt, EFFECT_SLIDE));
 
384
        lastnumber = -1;
 
385
}
 
386
 
 
387
void TrackView::addLetRing()
 
388
{
 
389
        if (curt->c[curt->x].a[curt->y] >= 0)
 
390
                cmdHist->addCommand(new AddFXCommand(this, curt, EFFECT_LETRING));
 
391
        else
 
392
                cmdHist->addCommand(new AddFXCommand(this, curt, EFFECT_STOPRING));
 
393
        lastnumber = -1;
 
394
}
 
395
 
 
396
// Call the chord constructor dialog and may be parse something from it
 
397
void TrackView::insertChord()
 
398
{
 
399
        int a[MAX_STRINGS];
 
400
 
 
401
        ChordSelector cs(
 
402
#ifdef WITH_TSE3
 
403
                         scheduler,
 
404
#endif
 
405
                         curt);
 
406
 
 
407
        for (int i = 0; i < curt->string; i++)
 
408
                cs.setApp(i, curt->c[curt->x].a[i]);
 
409
 
 
410
        // required to detect chord from tabulature
 
411
        cs.detectChord();
 
412
 
 
413
        int i;
 
414
 
 
415
        // set fingering right if frets > 5
 
416
        for (i = 0; i < curt->string; i++)
 
417
                a[i] = cs.app(i);
 
418
        cs.fng->setFingering(a);
 
419
 
 
420
        if (cs.exec()) {
 
421
                for (i = 0; i < curt->string; i++)
 
422
                        a[i] = cs.app(i);
 
423
                cmdHist->addCommand(new InsertStrumCommand(this, curt, cs.scheme(), a));
 
424
        }
 
425
 
 
426
        lastnumber = -1;
 
427
}
 
428
 
 
429
// Call rhythm construction dialog and may be parse something from it
 
430
void TrackView::rhythmer()
 
431
{
 
432
#ifdef WITH_TSE3
 
433
        Rhythmer r(scheduler);
 
434
#else
 
435
        Rhythmer r;
 
436
#endif
 
437
 
 
438
        if (r.exec())
 
439
                cmdHist->addCommand(new InsertRhythm(this, curt, r.quantized));
 
440
 
 
441
        lastnumber = -1;
 
442
}
 
443
 
 
444
// Determine horizontal offset between two columns - n and n+1
 
445
 
 
446
int TrackView::horizDelta(uint n)
 
447
{
 
448
#ifdef USE_BOTH_OLD_AND_NEW
 
449
        int res = curt->c[n].fullDuration() * HORCELL / zoomLevel;
 
450
//      if (res < HORCELL)
 
451
//              res = HORCELL;
 
452
#else
 
453
        int res = trp->colWidth(n, curt);       // LVIFIX: zoomLevel
 
454
#endif
 
455
        return res;
 
456
}
 
457
 
 
458
#ifdef USE_BOTH_OLD_AND_NEW
 
459
void TrackView::drawLetRing(QPainter *p, int x, int y)
 
460
{
 
461
        p->setPen(SolidLine);
 
462
        p->drawLine(x, y, x - HORCELL / 3, y - VERTLINE / 3);
 
463
        p->drawLine(x, y, x - HORCELL / 3, y + VERTLINE / 3);
 
464
        p->setPen(NoPen);
 
465
}
 
466
#endif
 
467
 
 
468
void TrackView::paintCell(QPainter *p, int row, int /*col*/)
 
469
{
 
470
//      cout << "TrackView::paintCell(row=" << row << ")" << endl;
 
471
 
 
472
        uint bn = row;                      // Drawing only this bar
 
473
 
 
474
        int selx2coord = -1;
 
475
        selxcoord = -1;
 
476
        
 
477
        if (row >= int(curt->b.size())) {
 
478
                kdDebug() << "Drawing the bar out of limits!" << endl;
 
479
                return;
 
480
        }
 
481
 
 
482
        trp->setPainter(p);
 
483
        // LVIFIX: initmetrics may be expensive but depends on p, init only once ?
 
484
        trp->initMetrics();
 
485
        // LVIFIX: do following calculations for the current bar only
 
486
        curt->calcVoices();
 
487
        curt->calcStepAltOct();
 
488
        curt->calcBeams();
 
489
        trp->yposst = 0;
 
490
        trp->xpos = -1;
 
491
        if (viewscore && fetaFont) {
 
492
                trp->initPrStyle(2);
 
493
                trp->yposst = (int) ((TOPSPST + NLINEST - 1 + BOTSPST) * trp->ystepst);
 
494
                trp->drawStLns(width());
 
495
        } else {
 
496
                trp->initPrStyle(0);
 
497
        }
 
498
        trp->ypostb = trp->yposst
 
499
                      + (int) ((TOPSPTB + curt->string - 0.5) * trp->ysteptb);
 
500
#ifdef USE_BOTH_OLD_AND_NEW
 
501
        // force new tabbar position close to old one
 
502
        trp->ypostb = (int) ((TOPSPST + NLINEST - 1) * trp->ystepst)
 
503
                      + (int) (BOTSPST * trp->ystepst)
 
504
                      + (int) ((TOPSPTB + curt->string) * trp->ysteptb);
 
505
#endif
 
506
        trp->drawBarLns(width(), curt);
 
507
//      trp->drawKey(row, curt);        // LVIFIX: make (some more) room between key and time sig
 
508
        bool doDraw = true;
 
509
        bool fbol = true;
 
510
        bool flop = (row == 0);
 
511
        (void) trp->drawKKsigTsig(row, curt, doDraw, fbol, flop);
 
512
        trp->drawBar(row, curt, 0, selxcoord, selx2coord);
 
513
 
 
514
        // connect tabbar and staff with vertical line at end of bar
 
515
        if (viewscore && fetaFont) {
 
516
                p->setPen(trp->pLnBl);
 
517
                p->drawLine(trp->xpos - 1, trp->yposst, trp->xpos - 1, trp->ypostb);
 
518
        }
 
519
 
 
520
        // DEBUG: DRAW VARIOUS GUIDE BORDERS
 
521
 
 
522
//      p->setBrush(NoBrush);
 
523
//      p->setPen(red);
 
524
//      p->drawRect(cellRect());
 
525
//      p->setPen(blue);
 
526
//      p->drawRect(0, TOPSPTB * trp->ysteptb, cellWidth(), curt->string * trp->ysteptb);
 
527
 
 
528
        // DRAW SELECTION
 
529
 
 
530
        p->setRasterOp(Qt::XorROP);
 
531
        p->setBrush(KGlobalSettings::baseColor());
 
532
 
 
533
        const int horcell = (int) (2.6 * trp->br8w);
 
534
        const int vertline = trp->ysteptb;
 
535
        const int vertspace = trp->ypostb;
 
536
 
 
537
        if (playbackCursor) {
 
538
                // Draw MIDI playback cursor
 
539
                if (selxcoord != -1)
 
540
                        p->drawRect(selxcoord - horcell / 2, 0, horcell + 1, cellHeight());
 
541
 
 
542
        } else {
 
543
 
 
544
                // Draw selection between selxcoord and selx2coord (if it exists)
 
545
                if (curt->sel) {
 
546
                        if ((selxcoord != -1) && (selx2coord != -1)) {
 
547
                                int x1 = KMIN(selxcoord, selx2coord);
 
548
                                int wid = abs(selx2coord - selxcoord) + horcell + 1;
 
549
                                p->drawRect(x1 - horcell / 2, 0, wid, cellHeight());
 
550
                        } else if ((selxcoord == -1) && (selx2coord != -1)) {
 
551
                                if (curt->x > curt->lastColumn(bn))
 
552
                                        p->drawRect(selx2coord - horcell / 2, 0, cellWidth(), cellHeight());
 
553
                                else
 
554
                                        p->drawRect(0, 0, selx2coord + horcell / 2 + 1, cellHeight());
 
555
                        } else if ((selxcoord != -1) && (selx2coord == -1)) {
 
556
                                if (curt->xsel > curt->lastColumn(bn))
 
557
                                        p->drawRect(selxcoord - horcell / 2, 0, cellWidth(), cellHeight());
 
558
                                else
 
559
                                        p->drawRect(0, 0, selxcoord + horcell / 2 + 1, cellHeight());
 
560
                        } else { // both are -1
 
561
                                int x1 = KMIN(curt->x, curt->xsel);
 
562
                                int x2 = KMAX(curt->x, curt->xsel);
 
563
                                if ((x1 < curt->b[bn].start) && (x2 > curt->lastColumn(bn)))
 
564
                                        p->drawRect(0, 0, cellWidth(), cellHeight());
 
565
                        }
 
566
                }
 
567
                // Draw original cursor (still inverted)
 
568
                if (selxcoord != -1) {
 
569
                        p->drawRect(selxcoord - horcell / 2,
 
570
                                    vertspace + (0 - curt->y) * vertline - vertline / 2 - 2,
 
571
                                    horcell,
 
572
                                    vertline + 3);
 
573
                }
 
574
        }
 
575
 
 
576
        p->setRasterOp(Qt::CopyROP);
 
577
 
 
578
#ifdef USE_BOTH_OLD_AND_NEW
 
579
        QString tmp;
 
580
        bool ringing[MAX_STRINGS];
 
581
        int trpCnt = 0;                     // triplet count
 
582
        int lastPalmMute = 0;
 
583
 
 
584
        int s = curt->string - 1;
 
585
 
 
586
        for (int i = 0; i <= s; i++) {
 
587
                p->drawLine(0, VERTSPACE + (s - i) * VERTLINE,
 
588
                            width(), VERTSPACE + (s - i) * VERTLINE);
 
589
                ringing[i] = FALSE;
 
590
        }
 
591
 
 
592
        int xpos = 40, lastxpos = 20, xdelta;
 
593
 
 
594
        selxcoord = -1;
 
595
 
 
596
        // Starting bars - very thick and thick one
 
597
 
 
598
        if (bn == 0) {
 
599
                p->setBrush(SolidPattern);
 
600
                p->drawRect(0, VERTSPACE, 5, VERTLINE * s);
 
601
                p->drawRect(8, VERTSPACE, 2, VERTLINE * s);
 
602
        }
 
603
 
 
604
        // Time signature
 
605
 
 
606
        if (curt->showBarSig(bn)) {
 
607
                p->setFont(*timeSigFont);
 
608
                tmp.setNum(curt->b[bn].time1);
 
609
                p->drawText(20, VERTSPACE + VERTLINE * s / 4 - TIMESIGSIZE / 2,
 
610
                                        TIMESIGSIZE, TIMESIGSIZE, AlignCenter, tmp);
 
611
                tmp.setNum(curt->b[bn].time2);
 
612
                p->drawText(20, VERTSPACE + VERTLINE * s * 3 / 4 - TIMESIGSIZE / 2,
 
613
                                        TIMESIGSIZE, TIMESIGSIZE, AlignCenter, tmp);
 
614
        }
 
615
 
 
616
        p->setFont(*normalFont);
 
617
        p->setBrush(KGlobalSettings::baseColor());
 
618
 
 
619
        // Drum abbreviations markings
 
620
 
 
621
        if (curt->trackMode() == TabTrack::DrumTab) {
 
622
                p->setPen(NoPen);
 
623
                for (int i = 0; i <= s; i++) {
 
624
                        p->drawRect(xpos, VERTSPACE + (s - i) * VERTLINE - VERTLINE / 2,
 
625
                                                ABBRLENGTH, VERTLINE + 1);
 
626
                        p->drawText(xpos, VERTSPACE + (s - i) * VERTLINE - VERTLINE / 2,
 
627
                                                ABBRLENGTH, VERTLINE, AlignCenter, drum_abbr[curt->tune[i]]);
 
628
                }
 
629
                xpos += ABBRLENGTH + 10; lastxpos += ABBRLENGTH + 10;
 
630
                p->setPen(SolidLine);
 
631
        }
 
632
 
 
633
        for (int t = curt->b[bn].start; t <= curt->lastColumn(bn); t++) {
 
634
 
 
635
                // triplet handling:
 
636
                // - reset after third note of triplet
 
637
                // - count notes while inside triplet
 
638
                if (trpCnt >= 3) {
 
639
                        trpCnt = 0;
 
640
                }
 
641
                if (curt->c[t].flags & FLAG_TRIPLET) {
 
642
                        trpCnt++;
 
643
                } else {
 
644
                        trpCnt = 0;
 
645
                }
 
646
 
 
647
                // Drawing duration marks
 
648
 
 
649
                // Draw connection with previous, if applicable
 
650
                if ((t > 0) && (t > curt->b[bn].start) && (curt->c[t - 1].l == curt->c[t].l))
 
651
                        xdelta = lastxpos + HORCELL / 2;
 
652
                else
 
653
                        xdelta = xpos + HORCELL / 2 + HORDUR;
 
654
 
 
655
                switch (curt->c[t].l) {
 
656
                case 15:  // 1/32
 
657
                        p->drawLine(xpos + HORCELL / 2, BOTTOMDUR + VERTLINE - 4,
 
658
                                                xdelta, BOTTOMDUR + VERTLINE - 4);
 
659
                case 30:  // 1/16
 
660
                        p->drawLine(xpos + HORCELL / 2, BOTTOMDUR + VERTLINE - 2,
 
661
                                                xdelta, BOTTOMDUR + VERTLINE - 2);
 
662
                case 60:  // 1/8
 
663
                        p->drawLine(xpos + HORCELL / 2, BOTTOMDUR + VERTLINE,
 
664
                                                xdelta, BOTTOMDUR + VERTLINE);
 
665
                case 120: { // 1/4 - a long vertical line, so we need to find the highest note
 
666
                        int i;
 
667
                        for (i = s; ((i >= 0) && (curt->c[t].a[i] == -1)); i--);
 
668
 
 
669
                        // If it's an empty measure at all - draw the vertical line from bottom
 
670
                        if (i < 0)  i = s / 2;
 
671
 
 
672
                        p->drawLine(xpos + HORCELL / 2, VERTSPACE + VERTLINE * (s - i) + VERTLINE / 2,
 
673
                                                xpos + HORCELL / 2, BOTTOMDUR + VERTLINE);
 
674
                }
 
675
                case 240: // 1/2
 
676
                        p->drawLine(xpos + HORCELL / 2, BOTTOMDUR + 3,
 
677
                                                xpos + HORCELL / 2, BOTTOMDUR + VERTLINE);
 
678
                case 480:; // whole
 
679
                }
 
680
 
 
681
                // Draw dot
 
682
 
 
683
                if (curt->c[t].flags & FLAG_DOT)
 
684
                        p->drawRect(xpos + HORCELL / 2 + 3, BOTTOMDUR + 5, 2, 2);
 
685
 
 
686
                // Draw triplet - GREYFIX: ugly code, needs to be fixed
 
687
                // somehow... Ideally, triplets should be drawn in a second
 
688
                // loop, after everything else would be done.
 
689
 
 
690
                /*
 
691
                if (curt->c[t].flags & FLAG_TRIPLET) {
 
692
                        if ((curt->c.size() >= t + 1) && (t) &&
 
693
                                (curt->c[t - 1].flags & FLAG_TRIPLET) &&
 
694
                                (curt->c[t + 1].flags & FLAG_TRIPLET) &&
 
695
                                (curt->c[t - 1].l == curt->c[t].l) &&
 
696
                                (curt->c[t + 1].l == curt->c[t].l)) {
 
697
                                p->drawLine(lastxpos + HORCELL / 2, BOTTOMDUR + VERTLINE + 5,
 
698
                                                        xpos * 2 - lastxpos + HORCELL / 2, BOTTOMDUR + VERTLINE + 5);
 
699
                                p->drawLine(lastxpos + HORCELL / 2, BOTTOMDUR + VERTLINE + 2,
 
700
                                                        lastxpos + HORCELL / 2, BOTTOMDUR + VERTLINE + 5);
 
701
                                p->drawLine(xpos * 2 - lastxpos + HORCELL / 2, BOTTOMDUR + VERTLINE + 2,
 
702
                                                        xpos * 2 - lastxpos + HORCELL / 2, BOTTOMDUR + VERTLINE + 5);
 
703
                                p->setFont(*smallCaptionFont);
 
704
                                p->drawText(xpos, BOTTOMDUR + VERTLINE + 7, HORCELL, VERTLINE, AlignHCenter | AlignTop, "3");
 
705
                                p->setFont(*normalFont);
 
706
                        } else {
 
707
                                if (!(((curt->c.size() >= t + 2) &&
 
708
                                           (curt->c[t + 1].flags & FLAG_TRIPLET) &&
 
709
                                           (curt->c[t + 2].flags & FLAG_TRIPLET) &&
 
710
                                           (curt->c[t + 1].l == curt->c[t].l) &&
 
711
                                           (curt->c[t + 2].l == curt->c[t].l)) ||
 
712
                                          ((t >= 2) &&
 
713
                                           (curt->c[t - 1].flags & FLAG_TRIPLET) &&
 
714
                                           (curt->c[t - 2].flags & FLAG_TRIPLET) &&
 
715
                                           (curt->c[t - 1].l == curt->c[t].l) &&
 
716
                                           (curt->c[t - 2].l == curt->c[t].l)))) {
 
717
                                        p->setFont(*smallCaptionFont);
 
718
                                        p->drawText(xpos, BOTTOMDUR + VERTLINE + 7, HORCELL, VERTLINE, AlignHCenter | AlignTop, "3");
 
719
                                        p->setFont(*normalFont);
 
720
                                }
 
721
                        }
 
722
                }
 
723
                */
 
724
 
 
725
                // Length of interval to next column - adjusted if dotted
 
726
                // calculated here because it is required by triplet code
 
727
 
 
728
                xdelta = horizDelta(t);
 
729
 
 
730
                // Draw triplet - improved (? :-)) code
 
731
                if ((trpCnt == 1) || (trpCnt == 2)) {
 
732
                        // draw horizontal line to next note
 
733
                        p->drawLine(xpos + HORCELL / 2, BOTTOMDUR + VERTLINE + 5,
 
734
                                                xpos + HORCELL / 2 + xdelta, BOTTOMDUR + VERTLINE + 5);
 
735
                }
 
736
                if ((trpCnt == 1) || (trpCnt == 3)) {
 
737
                        // draw vertical line
 
738
                        p->drawLine(xpos + HORCELL / 2, BOTTOMDUR + VERTLINE + 2,
 
739
                                                xpos + HORCELL / 2, BOTTOMDUR + VERTLINE + 5);
 
740
                }
 
741
                if (trpCnt == 2) {
 
742
                        // draw "3"
 
743
                        p->setFont(*smallCaptionFont);
 
744
                        p->drawText(xpos, BOTTOMDUR + VERTLINE + 7, HORCELL, VERTLINE, AlignHCenter | AlignTop, "3");
 
745
                        p->setFont(*normalFont);
 
746
                }
 
747
 
 
748
                // Draw arcs to backward note
 
749
 
 
750
                if (curt->c[t].flags & FLAG_ARC)
 
751
                        p->drawArc(lastxpos + HORCELL / 2, BOTTOMDUR + 9,
 
752
                                           xpos - lastxpos, 10, 0, -180 * 16);
 
753
 
 
754
                // Draw palm muting
 
755
 
 
756
                if (curt->c[t].flags & FLAG_PM) {
 
757
                        if (lastPalmMute == 0)  {     // start drawing with "P.M."
 
758
                                p->setFont(*smallCaptionFont);
 
759
                                p->drawText(xpos, VERTSPACE / 2, VERTLINE * 2, VERTLINE,
 
760
                                                        AlignCenter, "P.M.");
 
761
                                p->setFont(*normalFont);
 
762
                                lastPalmMute = 1;
 
763
                        } else if (lastPalmMute == 1) {
 
764
                                p->drawLine(lastxpos + VERTLINE * 2, VERTSPACE / 2 + VERTLINE / 2,
 
765
                                                        xpos + HORCELL / 2, VERTSPACE / 2 + VERTLINE / 2);
 
766
                                lastPalmMute = 2;
 
767
                        } else {
 
768
                                p->drawLine(lastxpos + HORCELL / 2, VERTSPACE / 2 + VERTLINE / 2,
 
769
                                                        xpos + HORCELL / 2, VERTSPACE / 2 + VERTLINE / 2);
 
770
                        }
 
771
                } else {
 
772
                        if (lastPalmMute == 2) {
 
773
                                p->drawLine(lastxpos + HORCELL / 2, VERTSPACE / 2 + VERTLINE / 2,
 
774
                                            lastxpos + HORCELL / 2, VERTSPACE / 2 + VERTLINE);
 
775
                        }
 
776
                        lastPalmMute = 0;
 
777
                }
 
778
 
 
779
                // Draw the number column
 
780
 
 
781
                p->setPen(NoPen);
 
782
                for (int i = 0; i <= s; i++) {
 
783
                        if (curt->c[t].a[i] != -1) {
 
784
                                if (curt->c[t].a[i] == DEAD_NOTE)
 
785
                                        tmp = "X";
 
786
                                else
 
787
                                        tmp.setNum(curt->c[t].a[i]);
 
788
                                p->drawRect(xpos, VERTSPACE + (s - i) * VERTLINE - VERTLINE / 2,
 
789
                                                        HORCELL, VERTLINE);
 
790
                                p->drawText(xpos, VERTSPACE + (s - i) * VERTLINE - VERTLINE / 2,
 
791
                                                        HORCELL, VERTLINE, AlignCenter, tmp);
 
792
                                if (ringing[i]) {
 
793
                                        drawLetRing(p, xpos, VERTSPACE + (s - i) * VERTLINE);
 
794
                                        ringing[i] = FALSE;
 
795
                                }
 
796
                        }
 
797
                        if ((curt->c[t].a[i] == -1)
 
798
                             && (curt->c[t].e[i] == EFFECT_STOPRING)) {
 
799
                                if (ringing[i]) {
 
800
                                        drawLetRing(p, xpos, VERTSPACE + (s - i) * VERTLINE);
 
801
                                        ringing[i] = FALSE;
 
802
                                }
 
803
                        }
 
804
 
 
805
                        if (t == curt->x)
 
806
                                selxcoord = xpos;
 
807
 
 
808
                        if (t == curt->xsel)
 
809
                                selx2coord = xpos;
 
810
 
 
811
                        // Draw effects
 
812
                        // GREYFIX - use lastxpos, not xdelta
 
813
 
 
814
                        switch (curt->c[t].e[i]) {
 
815
                        case EFFECT_HARMONIC:
 
816
                                p->setFont(*smallCaptionFont);
 
817
                                p->drawText(xpos + VERTLINE + 2, VERTSPACE + (s - i) * VERTLINE - VERTLINE * 2 / 3,
 
818
                                                        HORCELL, VERTLINE, AlignCenter, "H");
 
819
                                p->setFont(*normalFont);
 
820
                                break;
 
821
                        case EFFECT_ARTHARM:
 
822
                                p->setFont(*smallCaptionFont);
 
823
                                p->drawText(xpos + VERTLINE + 2, VERTSPACE + (s - i) * VERTLINE - VERTLINE * 2 / 3,
 
824
                                                        HORCELL * 2, VERTLINE, AlignCenter, "AH");
 
825
                                p->setFont(*normalFont);
 
826
                                break;
 
827
                        case EFFECT_LEGATO:
 
828
                                p->setPen(SolidLine);
 
829
                                p->drawArc(xpos + HORCELL, VERTSPACE + (s - i) * VERTLINE - VERTLINE / 2,
 
830
                                                   xdelta - HORCELL, 10, 0, 180 * 16);
 
831
                                if ((t < curt->c.size() - 1) && (curt->c[t + 1].a[i] >= 0)) {
 
832
                                        p->setFont(*smallCaptionFont);
 
833
                                        if (curt->c[t + 1].a[i] > curt->c[t].a[i]) {
 
834
                                                p->drawText(xpos + xdelta / 2 - HORCELL / 2, VERTSPACE + (s - i) * VERTLINE - VERTLINE / 3,
 
835
                                                                        HORCELL * 2, VERTLINE, AlignCenter, "HO");
 
836
                                        } else if (curt->c[t + 1].a[i] < curt->c[t].a[i]) {
 
837
                                                p->drawText(xpos + xdelta / 2 - HORCELL / 2, VERTSPACE + (s - i) * VERTLINE - VERTLINE / 3,
 
838
                                                                        HORCELL * 2, VERTLINE, AlignCenter, "PO");
 
839
                                        }
 
840
                                        p->setFont(*normalFont);
 
841
                                }
 
842
                                p->setPen(NoPen);
 
843
                                break;
 
844
                        case EFFECT_SLIDE:
 
845
                                p->setPen(SolidLine);
 
846
                                if ((t < curt->c.size() - 1) && (curt->c[t + 1].a[i] >= 0)) {
 
847
                                        if (curt->c[t + 1].a[i] > curt->c[t].a[i]) {
 
848
                                                p->drawLine(xpos + HORCELL + 2, VERTSPACE + (s - i) * VERTLINE + VERTLINE / 2 - 1,
 
849
                                                                        xpos + xdelta, VERTSPACE + (s - i) * VERTLINE - VERTLINE / 2 + 1);
 
850
                                        } else {
 
851
                                                p->drawLine(xpos + HORCELL + 2, VERTSPACE + (s - i) * VERTLINE - VERTLINE / 2 + 1,
 
852
                                                                        xpos + xdelta, VERTSPACE + (s - i) * VERTLINE + VERTLINE / 2 - 1);
 
853
                                        }
 
854
                                }
 
855
                                p->setPen(NoPen);
 
856
                                break;
 
857
                        case EFFECT_LETRING:
 
858
                                ringing[i] = TRUE;
 
859
                                break;
 
860
                        }
 
861
                }
 
862
 
 
863
                p->setPen(SolidLine);
 
864
 
 
865
                lastxpos = xpos;
 
866
                xpos += xdelta;
 
867
        }
 
868
 
 
869
        // Show notes still ringing at end of bar
 
870
        for (int i = 0; i <= s; i++) {
 
871
                if (ringing[i]) {
 
872
                        drawLetRing(p, xpos - HORCELL / 3, VERTSPACE + (s - i) * VERTLINE);
 
873
                        ringing[i] = FALSE;
 
874
                }
 
875
        }
 
876
 
 
877
        // End bar with vertical line
 
878
        p->setPen(SolidLine);
 
879
        p->drawRect(xpos, VERTSPACE, 1, VERTLINE * s);
 
880
 
 
881
        // Draw original cursor (still inverted)
 
882
        p->setRasterOp(Qt::XorROP);
 
883
//      p->setBrush(KGlobalSettings::highlightColor());
 
884
        if (selxcoord != -1) {
 
885
                p->drawRect(selxcoord, VERTSPACE + (s - curt->y) * VERTLINE - VERTLINE / 2 - 1,
 
886
                                        HORCELL + 1, VERTLINE + 2);
 
887
        }
 
888
 
 
889
//      p->setBrush(KGlobalSettings::baseColor());
 
890
        p->setRasterOp(Qt::CopyROP);
 
891
        p->setBrush(SolidPattern);
 
892
#endif // USE_BOTH_OLD_AND_NEW
 
893
}
 
894
 
 
895
void TrackView::resizeEvent(QResizeEvent *e)
 
896
{
 
897
        QGridView::resizeEvent(e); // GREYFIX ? Is it C++-correct?
 
898
        setCellWidth(width() - 2 - QStyle::PM_ScrollBarExtent);
 
899
}
 
900
 
 
901
bool TrackView::moveFinger(int from, int dir)
 
902
{
 
903
        int n0 = curt->c[curt->x].a[from];
 
904
        int n = n0;
 
905
        if (n < 0)
 
906
                return FALSE;
 
907
 
 
908
        int to = from;
 
909
 
 
910
        do {
 
911
                to += dir;
 
912
                if ((to < 0) || (to >= curt->string))
 
913
                        return FALSE;
 
914
                n = n0 + curt->tune[from] - curt->tune[to];
 
915
                if ((n < 0) || (n > curt->frets))
 
916
                        return FALSE;
 
917
        } while (curt->c[curt->x].a[to] != -1);
 
918
 
 
919
        cmdHist->addCommand(new MoveFingerCommand(this, curt, from, to, n));
 
920
        emit columnChanged();
 
921
 
 
922
        return TRUE;
 
923
}
 
924
 
 
925
// LVIFIX: eventually KGuitar should support changing the key at the start
 
926
// of a new bar. For the time being, we don't: the key is the same for the
 
927
// whole track and is stored in the first bar
 
928
 
 
929
void TrackView::keySig()
 
930
{
 
931
        int oldsig = curt->b[0].keysig;
 
932
        if ((oldsig <= -8) || (8 <= oldsig)) {
 
933
                // LVIFIX: report error ???
 
934
                oldsig = 0;
 
935
        }
 
936
 
 
937
        SetKeySig sks(oldsig);
 
938
 
 
939
        if (sks.exec()) {
 
940
                curt->b[0].keysig = sks.keySignature();
 
941
                // LVIFIX: undo info
 
942
        }
 
943
 
 
944
        updateRows();
 
945
        lastnumber = -1;
 
946
}
 
947
 
 
948
void TrackView::timeSig()
 
949
{
 
950
        SetTimeSig sts(curt->b[curt->xb].time1, curt->b[curt->xb].time2);
 
951
 
 
952
        if (sts.exec())
 
953
                cmdHist->addCommand(new SetTimeSigCommand(this, curt, sts.toend->isChecked(),
 
954
                                                          sts.time1(), sts.time2()));
 
955
 
 
956
        lastnumber = -1;
 
957
}
 
958
 
 
959
void TrackView::keyLeft()
 
960
{
 
961
        if (curt->sel) {
 
962
                curt->sel = FALSE;
 
963
                repaintContents();
 
964
        } else {
 
965
                moveLeft();
 
966
        }
 
967
}
 
968
 
 
969
void TrackView::keyRight()
 
970
{
 
971
        if (curt->sel) {
 
972
                curt->sel = FALSE;
 
973
                repaintContents();
 
974
        } else {
 
975
                moveRight();
 
976
        }
 
977
}
 
978
 
 
979
void TrackView::keyLeftBar()
 
980
{
 
981
        if (curt->sel) {
 
982
                curt->sel = FALSE;
 
983
                repaintContents();
 
984
        } else {
 
985
                moveLeftBar();
 
986
        }
 
987
}
 
988
 
 
989
void TrackView::keyRightBar()
 
990
{
 
991
        if (curt->sel) {
 
992
                curt->sel = FALSE;
 
993
                repaintContents();
 
994
        } else {
 
995
                moveRightBar();
 
996
        }
 
997
}
 
998
 
 
999
void TrackView::keyHome()
 
1000
{
 
1001
        if (curt->sel) {
 
1002
                curt->sel = FALSE;
 
1003
                repaintContents();
 
1004
        } else {
 
1005
                moveHome();
 
1006
        }
 
1007
}
 
1008
 
 
1009
void TrackView::keyEnd()
 
1010
{
 
1011
        if (curt->sel) {
 
1012
                curt->sel = FALSE;
 
1013
                repaintContents();
 
1014
        } else {
 
1015
                moveEnd();
 
1016
        }
 
1017
}
 
1018
 
 
1019
void TrackView::keyCtrlHome()
 
1020
{
 
1021
        if (curt->sel) {
 
1022
                curt->sel = FALSE;
 
1023
                repaintContents();
 
1024
        } else {
 
1025
                moveCtrlHome();
 
1026
        }
 
1027
}
 
1028
 
 
1029
void TrackView::keyCtrlEnd()
 
1030
{
 
1031
        if (curt->sel) {
 
1032
                curt->sel = FALSE;
 
1033
                repaintContents();
 
1034
        } else {
 
1035
                moveCtrlEnd();
 
1036
        }
 
1037
}
 
1038
 
 
1039
void TrackView::moveLeft()
 
1040
{
 
1041
        if (curt->x > 0) {
 
1042
                if (curt->b[curt->xb].start == curt->x) {
 
1043
                        curt->x--;
 
1044
                        repaintCurrentCell();
 
1045
                        curt->xb--;
 
1046
                        ensureCurrentVisible();
 
1047
                        emit barChanged();
 
1048
                } else {
 
1049
                        curt->x--;
 
1050
                }
 
1051
                repaintCurrentCell();
 
1052
                emit columnChanged();
 
1053
        }
 
1054
        lastnumber = -1;
 
1055
}
 
1056
 
 
1057
void TrackView::moveRight()
 
1058
{
 
1059
        if (((uint) (curt->x + 1)) == curt->c.size()) {
 
1060
                cmdHist->addCommand(new AddColumnCommand(this, curt));
 
1061
                emit columnChanged();
 
1062
        } else {
 
1063
                if (curt->b.size() == (uint) curt->xb + 1)
 
1064
                        curt->x++;
 
1065
                else {
 
1066
                        if (curt->b[curt->xb + 1].start == curt->x + 1) {
 
1067
                                curt->x++;
 
1068
                                repaintCurrentCell();
 
1069
                                curt->xb++;
 
1070
                                ensureCurrentVisible();
 
1071
                                emit barChanged();
 
1072
                        } else {
 
1073
                                curt->x++;
 
1074
                        }
 
1075
                }
 
1076
                repaintCurrentCell();
 
1077
                emit columnChanged();
 
1078
        }
 
1079
        lastnumber = -1;
 
1080
}
 
1081
 
 
1082
void TrackView::moveLeftBar()
 
1083
{
 
1084
        if (curt->x > curt->b[curt->xb].start) {
 
1085
                moveHome(); 
 
1086
        } else {
 
1087
                moveLeft();
 
1088
                moveHome();
 
1089
        }
 
1090
}
 
1091
 
 
1092
void TrackView::moveRightBar()
 
1093
{
 
1094
        if (curt->x == curt->lastColumn(curt->xb)) {
 
1095
                moveRight();
 
1096
        } else if (curt->x == curt->b[curt->xb].start) {
 
1097
                moveEnd();
 
1098
                moveRight();
 
1099
        } else {
 
1100
                moveEnd();
 
1101
        }
 
1102
}
 
1103
 
 
1104
void TrackView::moveHome()
 
1105
{
 
1106
        curt->x = curt->b[curt->xb].start;
 
1107
        repaintCurrentCell();
 
1108
        emit columnChanged();
 
1109
}
 
1110
 
 
1111
void TrackView::moveEnd()
 
1112
{
 
1113
        curt->x = curt->lastColumn(curt->xb);
 
1114
        repaintCurrentCell();
 
1115
        emit columnChanged();
 
1116
}
 
1117
 
 
1118
void TrackView::moveCtrlHome()
 
1119
{
 
1120
        curt->x = 0;
 
1121
        curt->xb = 0;
 
1122
        ensureCurrentVisible();
 
1123
        repaintContents();
 
1124
        emit barChanged();
 
1125
        emit columnChanged();
 
1126
}
 
1127
 
 
1128
void TrackView::moveCtrlEnd()
 
1129
{
 
1130
        curt->x = curt->c.size() - 1;
 
1131
        curt->xb = curt->b.size() - 1;
 
1132
        ensureCurrentVisible();
 
1133
        repaintContents();
 
1134
        emit barChanged();
 
1135
        emit columnChanged();
 
1136
}
 
1137
 
 
1138
void TrackView::selectLeft()
 
1139
{
 
1140
        if (!curt->sel) {
 
1141
                curt->sel = TRUE;
 
1142
                curt->xsel = curt->x;
 
1143
                repaintCurrentCell();
 
1144
        } else {
 
1145
                moveLeft();
 
1146
        }
 
1147
}
 
1148
 
 
1149
void TrackView::selectRight()
 
1150
{
 
1151
        if (!curt->sel) {
 
1152
                curt->sel = TRUE;
 
1153
                curt->xsel = curt->x;
 
1154
                repaintCurrentCell();
 
1155
        } else {
 
1156
                moveRight();
 
1157
        }
 
1158
}
 
1159
 
 
1160
void TrackView::moveUp()
 
1161
{
 
1162
        if (curt->y+1 < curt->string) {
 
1163
                curt->y++;
 
1164
                if (curt->sel)
 
1165
                        repaintCurrentCell();
 
1166
                else
 
1167
                        repaintCurrentColumn();
 
1168
        }
 
1169
        lastnumber = -1;
 
1170
}
 
1171
 
 
1172
void TrackView::transposeUp()
 
1173
{
 
1174
        if (curt->y+1 < curt->string)
 
1175
                moveFinger(curt->y, 1);
 
1176
        lastnumber = -1;
 
1177
}
 
1178
 
 
1179
void TrackView::moveDown()
 
1180
{
 
1181
        if (curt->y > 0) {
 
1182
                curt->y--;
 
1183
                if (curt->sel)
 
1184
                        repaintCurrentCell();
 
1185
                else
 
1186
                        repaintCurrentColumn();
 
1187
        }
 
1188
        lastnumber = -1;
 
1189
}
 
1190
 
 
1191
void TrackView::transposeDown()
 
1192
{
 
1193
        if (curt->y > 0)
 
1194
                moveFinger(curt->y, -1);
 
1195
        lastnumber = -1;
 
1196
}
 
1197
 
 
1198
void TrackView::deadNote()
 
1199
{
 
1200
        cmdHist->addCommand(new SetFlagCommand(this, curt, DEAD_NOTE));
 
1201
        emit columnChanged();
 
1202
        lastnumber = -1;
 
1203
}
 
1204
 
 
1205
void TrackView::deleteNote()
 
1206
{
 
1207
        if (curt->c[curt->x].a[curt->y] != -1) {
 
1208
                cmdHist->addCommand(new DeleteNoteCommand(this, curt));
 
1209
                emit columnChanged();
 
1210
        }
 
1211
        lastnumber = -1;
 
1212
}
 
1213
 
 
1214
void TrackView::deleteColumn()
 
1215
{
 
1216
        cmdHist->addCommand(new DeleteColumnCommand(this, curt));
 
1217
        emit columnChanged();
 
1218
        lastnumber = -1;
 
1219
}
 
1220
 
 
1221
void TrackView::deleteColumn(QString name)
 
1222
{
 
1223
        cmdHist->addCommand(new DeleteColumnCommand(name, this, curt));
 
1224
        emit columnChanged();
 
1225
}
 
1226
 
 
1227
void TrackView::insertColumn()
 
1228
{
 
1229
        cmdHist->addCommand(new InsertColumnCommand(this, curt));
 
1230
        emit columnChanged();
 
1231
        lastnumber = -1;
 
1232
}
 
1233
 
 
1234
void TrackView::palmMute()
 
1235
{
 
1236
        cmdHist->addCommand(new SetFlagCommand(this, curt, FLAG_PM));
 
1237
        lastnumber = -1;
 
1238
}
 
1239
 
 
1240
void TrackView::dotNote()
 
1241
{
 
1242
        cmdHist->addCommand(new SetFlagCommand(this, curt, FLAG_DOT));
 
1243
        lastnumber = -1;
 
1244
}
 
1245
 
 
1246
void TrackView::tripletNote()
 
1247
{
 
1248
        cmdHist->addCommand(new SetFlagCommand(this, curt, FLAG_TRIPLET));
 
1249
        lastnumber = -1;
 
1250
}
 
1251
 
 
1252
void TrackView::keyPlus()
 
1253
{
 
1254
        if (curt->c[curt->x].l < 480)
 
1255
                setLength(curt->c[curt->x].l * 2);
 
1256
        lastnumber = -1;
 
1257
}
 
1258
 
 
1259
void TrackView::keyMinus()
 
1260
{
 
1261
        if (curt->c[curt->x].l > 15)
 
1262
                setLength(curt->c[curt->x].l / 2);
 
1263
        lastnumber = -1;
 
1264
}
 
1265
 
 
1266
void TrackView::arrangeTracks()
 
1267
{
 
1268
        cmdHist->clear();       // because columns will be changed
 
1269
        curt->arrangeBars();
 
1270
        emit barChanged();
 
1271
        updateRows();
 
1272
        repaintContents();
 
1273
 
 
1274
        emit paneChanged();
 
1275
        emit columnChanged();
 
1276
}
 
1277
 
 
1278
void TrackView::insertTab(int num)
 
1279
{
 
1280
        int totab = num;
 
1281
 
 
1282
        if (curt->c[curt->x].flags & FLAG_ARC)
 
1283
                curt->c[curt->x].flags -= FLAG_ARC;
 
1284
 
 
1285
    // Allow making two-digit fret numbers pressing two keys sequentally
 
1286
        if ((lastnumber != -1) && (lastnumber * 10 + num <= curt->frets)) {
 
1287
                totab = lastnumber * 10 + num;
 
1288
                lastnumber = -1;
 
1289
        } else {
 
1290
                lastnumber = num;
 
1291
        }
 
1292
 
 
1293
        if ((totab <= curt->frets) && (curt->c[curt->x].a[curt->y] != totab))
 
1294
                cmdHist->addCommand(new InsertTabCommand(this, curt, totab));
 
1295
        emit columnChanged();
 
1296
}
 
1297
 
 
1298
void TrackView::arrangeBars()
 
1299
{
 
1300
        song->arrangeBars();
 
1301
        emit barChanged();
 
1302
        emit columnChanged();
 
1303
        updateRows();
 
1304
}
 
1305
 
 
1306
void TrackView::mousePressEvent(QMouseEvent *e)
 
1307
{
 
1308
        lastnumber = -1;
 
1309
 
 
1310
        // RightButton pressed
 
1311
        if (e->button() == RightButton) {
 
1312
                QWidget *tmpWidget = 0;
 
1313
                tmpWidget = xmlGUIClient->factory()->container("trackviewpopup", xmlGUIClient);
 
1314
 
 
1315
                if (!tmpWidget || !tmpWidget->inherits("KPopupMenu")) {
 
1316
                        kdDebug() << "TrackView::mousePressEvent => wrong container widget" << endl;
 
1317
                        return;
 
1318
                }
 
1319
 
 
1320
                KPopupMenu *menu(static_cast<KPopupMenu*>(tmpWidget));
 
1321
                menu->popup(QCursor::pos());
 
1322
        }
 
1323
 
 
1324
        // LeftButton pressed
 
1325
        if (e->button() == LeftButton) {
 
1326
                bool found = FALSE;
 
1327
                QPoint clickpt;
 
1328
 
 
1329
                uint tabrow = rowAt(contentsY() + e->pos().y());
 
1330
 
 
1331
                // Clicks on non-existing rows are not allowed
 
1332
                if (tabrow >= curt->b.size())
 
1333
                        return;
 
1334
 
 
1335
                clickpt.setX(contentsX() + e->pos().x());
 
1336
                clickpt.setY(contentsY() + e->pos().y());
 
1337
 
 
1338
                int xpos = trp->getFirstColOffs(tabrow, curt);
 
1339
                int xdelta = 0;
 
1340
                int lastxpos = 0;
 
1341
 
 
1342
                for (uint j=curt->b[tabrow].start;
 
1343
                         j < (tabrow < curt->b.size()-1 ? curt->b[tabrow+1].start : curt->c.size());
 
1344
                         j++) {
 
1345
 
 
1346
                        // Length of interval to next column - adjusted if dotted
 
1347
                        xdelta = horizDelta(j);
 
1348
 
 
1349
                        // Current column X area is half of the previous duration and
 
1350
                        // half of current duration
 
1351
 
 
1352
                        if ((clickpt.x() >= (lastxpos + xpos) / 2) &&
 
1353
                                (clickpt.x() <= xpos + xdelta / 2)) {
 
1354
                                curt->x = j;
 
1355
                                // We won't calculate xb from x as in updateXB(), but
 
1356
                                // would just use what we know.
 
1357
                                curt->xb = tabrow;
 
1358
 
 
1359
                                const int vertline = trp->ysteptb;
 
1360
                                const int vertspace = trp->ypostb; // LVIFIX: better name, this is not the vertical space but the lowest tab line's y coord
 
1361
                                curt->y = - ((int) (clickpt.y() - vertline / 2 - tabrow * cellHeight()) - vertspace) / vertline;
 
1362
 
 
1363
                                if (curt->y<0)
 
1364
                                        curt->y = 0;
 
1365
                                if (curt->y>=curt->string)
 
1366
                                        curt->y = curt->string-1;
 
1367
 
 
1368
                                curt->sel = FALSE;
 
1369
 
 
1370
                                emit columnChanged();
 
1371
                                emit barChanged();
 
1372
                                found = TRUE;
 
1373
                                break;
 
1374
                        }
 
1375
 
 
1376
                        lastxpos = xpos;
 
1377
                        xpos += xdelta;
 
1378
                }
 
1379
 
 
1380
                if (found)
 
1381
                        repaintContents();
 
1382
        }
 
1383
}
 
1384
 
 
1385
void TrackView::setX(int x)
 
1386
{
 
1387
        if (x < (int) curt->c.size()) {
 
1388
                curt->x = x;
 
1389
                int oldxb = curt->xb;
 
1390
                curt->updateXB();
 
1391
                if (oldxb == curt->xb) {
 
1392
                        repaintCurrentCell();
 
1393
                } else {
 
1394
                        repaintContents();
 
1395
                        ensureCurrentVisible();
 
1396
                }
 
1397
                emit columnChanged();
 
1398
                lastnumber = -1;
 
1399
        }
 
1400
}
 
1401
 
 
1402
void TrackView::setPlaybackCursor(bool pc)
 
1403
{
 
1404
    playbackCursor = pc;
 
1405
        repaintContents();
 
1406
}
 
1407
        
 
1408
void TrackView::viewScore(bool on)
 
1409
{
 
1410
//      cout << "TrackView::viewScore(on=" << on << ")" << endl;
 
1411
        viewscore = on;
 
1412
        updateRows();
 
1413
}