1 /* cdrdao - write audio CD-Rs in disc-at-once mode
2 *
3 * Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.de>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include <stdio.h>
21 #include <limits.h>
22 #include <math.h>
23 #include <assert.h>
24 #include <iostream>
25
26 #include <gtkmm.h>
27 #include <gnome.h>
28
29 #include "TocEdit.h"
30 #include "SampleDisplay.h"
31 #include "SampleManager.h"
32 #include "TrackManager.h"
33
34 #include "Toc.h"
35 #include "util.h"
36 #include "log.h"
37
38
39 /* XPM data for track marker */
40 #define TRACK_MARKER_XPM_WIDTH 9
41 #define TRACK_MARKER_XPM_HEIGHT 12
42 static const gchar *TRACK_MARKER_XPM_DATA[] = {
43 "9 12 3 1",
44 " c None",
45 "X c #000000000000",
46 ". c #FFFFFFFFFFFF",
47 " ",
48 " XXXXXXX ",
49 " XXXXXXX ",
50 " XXXXXXX ",
51 " XXXXXXX ",
52 " XXXXXXX ",
53 " XXXXXXX ",
54 " XXXXX ",
55 " XXX ",
56 " X ",
57 " X ",
58 " X "};
59
60 /* XPM data for index marker */
61 static const gchar *INDEX_MARKER_XPM_DATA[] = {
62 "9 12 3 1",
63 " c None",
64 "X c #000000000000",
65 ". c #FFFFFFFFFFFF",
66 " ",
67 " XXXXXXX ",
68 " X.....X ",
69 " X.....X ",
70 " X.....X ",
71 " X.....X ",
72 " X.....X ",
73 " X...X ",
74 " X.X ",
75 " X ",
76 " X ",
77 " X "};
78
79 /* XPM data for extend track marker */
80 static const gchar *TRACK_EXTEND_XPM_DATA[] = {
81 "9 12 3 1",
82 " c None",
83 "X c #000000000000",
84 ". c #FFFFFFFFFFFF",
85 "......XX.",
86 ".....XXX.",
87 "....XXXX.",
88 "...XXXXX.",
89 "..XXXXXX.",
90 ".XXXXXXX.",
91 "..XXXXXX.",
92 "...XXXXX.",
93 "....XXXX.",
94 ".....XXX.",
95 "......XX.",
96 "........."};
97
98 /* XPM data for extend track marker */
99 static const gchar *INDEX_EXTEND_XPM_DATA[] = {
100 "9 12 3 1",
101 " c None",
102 "X c #000000000000",
103 ". c #FFFFFFFFFFFF",
104 "......XX.",
105 ".....X.X.",
106 "....X..X.",
107 "...X...X.",
108 "..X....X.",
109 ".X.....X.",
110 "..X....X.",
111 "...X...X.",
112 "....X..X.",
113 ".....X.X.",
114 "......XX.",
115 "........."};
116
117
SampleDisplay()118 SampleDisplay::SampleDisplay():
119 pixmap_(NULL),
120 trackMarkerPixmap_(NULL),
121 indexMarkerPixmap_(NULL),
122 trackMarkerSelectedPixmap_(NULL),
123 indexMarkerSelectedPixmap_(NULL),
124 trackExtendPixmap_(NULL),
125 indexExtendPixmap_(NULL),
126 drawGc_(NULL)
127
128 {
129 adjustment_ = new Gtk::Adjustment(0.0, 0.0, 1.0);
130 adjustment_->signal_value_changed().connect(mem_fun(*this,
131 &SampleDisplay::scrollTo));
132
133 trackManager_ = NULL;
134
135 width_ = height_ = chanHeight_ = lcenter_ = rcenter_ = 0;
136 timeLineHeight_ = timeLineY_ = 0;
137 timeTickWidth_ = 0;
138 timeTickSep_ = 20;
139 sampleStartX_ = sampleEndX_ = sampleWidthX_ = 0;
140 minSample_ = maxSample_ = resolution_ = 0;
141 tocEdit_ = NULL;
142
143 chanSep_ = 10;
144
145 cursorControlExtern_ = false;
146 cursorDrawn_ = false;
147 cursorX_ = 0;
148
149 markerSet_ = false;
150 selectionSet_ = false;
151 regionSet_ = false;
152 dragMode_ = DRAG_NONE;
153
154 pickedTrackMarker_ = NULL;
155 selectedTrack_ = 0;
156 selectedIndex_ = 0;
157
158 signal_expose_event().connect(mem_fun(*this,
159 &SampleDisplay::handleExposeEvent));
160 signal_configure_event().
161 connect(mem_fun(*this, &SampleDisplay::handleConfigureEvent));
162 signal_motion_notify_event().
163 connect(mem_fun(*this, &SampleDisplay::handleMotionNotifyEvent));
164 signal_button_press_event().
165 connect(mem_fun(*this, &SampleDisplay::handleButtonPressEvent));
166 signal_button_release_event().
167 connect(mem_fun(*this, &SampleDisplay::handleButtonReleaseEvent));
168 signal_enter_notify_event().
169 connect(mem_fun(*this, &SampleDisplay::handleEnterEvent));
170 signal_leave_notify_event().
171 connect(mem_fun(*this, &SampleDisplay::handleLeaveEvent));
172
173 set_events(Gdk::EXPOSURE_MASK
174 | Gdk::LEAVE_NOTIFY_MASK
175 | Gdk::ENTER_NOTIFY_MASK
176 | Gdk::BUTTON_PRESS_MASK
177 | Gdk::BUTTON_RELEASE_MASK
178 | Gdk::POINTER_MOTION_MASK
179 | Gdk::POINTER_MOTION_HINT_MASK);
180 }
181
setTocEdit(TocEdit * t)182 void SampleDisplay::setTocEdit(TocEdit *t)
183 {
184 tocEdit_ = t;
185
186 Toc *toc = tocEdit_->toc();
187
188 markerSet_ = false;
189 selectionSet_ = false;
190 regionSet_ = false;
191
192 minSample_ = 0;
193
194 if (toc->length().samples() > 0) {
195 maxSample_ = toc->length().samples() - 1;
196 }
197 else {
198 maxSample_ = 0;
199 }
200 }
201
updateToc(unsigned long smin,unsigned long smax)202 void SampleDisplay::updateToc(unsigned long smin, unsigned long smax)
203 {
204 if (tocEdit_ == NULL)
205 return;
206
207 Toc *toc = tocEdit_->toc();
208
209 if (smin <= smax) {
210 minSample_ = smin;
211 maxSample_ = smax;
212 }
213
214 if (toc->length().samples() == 0) {
215 minSample_ = maxSample_ = 0;
216 }
217 else {
218 if (maxSample_ >= toc->length().samples()) {
219 // adjust 'maxSample_' to reduced length
220 unsigned long len = maxSample_ - minSample_;
221
222 maxSample_ = toc->length().samples() - 1;
223 if (maxSample_ > len) {
224 minSample_ = maxSample_ - len;
225 }
226 else {
227 minSample_ = 0;
228 }
229 }
230 }
231
232 setView(minSample_, maxSample_);
233 }
234
setView(unsigned long start,unsigned long end)235 void SampleDisplay::setView(unsigned long start, unsigned long end)
236 {
237 if (tocEdit_ == NULL)
238 return;
239
240 Toc *toc = tocEdit_->toc();
241
242 if (end < start)
243 end = start;
244
245 unsigned long len = end - start + 1;
246
247 if (len < 3 && toc != NULL) {
248 end = start + 2;
249
250 if (end >= toc->length().samples()) {
251 if (toc->length().samples() != 0)
252 end = toc->length().samples() - 1;
253 else
254 end = 0;
255
256 if (end <= 2)
257 start = 0;
258 else
259 start = end - 2;
260 }
261
262 len = (end == 0 ? 0 : 3);
263 }
264
265 minSample_ = start;
266 maxSample_ = end;
267
268 updateSamples();
269 redraw(0, 0, width_, height_, 0);
270
271 GtkAdjustment *adjust = adjustment_->gobj();
272 if (toc == NULL) {
273 adjust->lower = 0.0;
274 adjust->upper = 1.0;
275 adjust->value = 0.0;
276 adjust->page_size = 0.0;
277 }
278 else {
279 adjust->lower = 0.0;
280 adjust->upper = toc->length().samples();
281 adjust->value = minSample_;
282
283 adjust->step_increment = len / 4;
284 if (adjust->step_increment == 0.0)
285 adjust->step_increment = 1.0;
286
287 adjust->page_increment = len / 1.1;
288 adjust->page_size = len;
289 }
290 adjustment_->changed();
291
292 }
293
getView(unsigned long * start,unsigned long * end)294 void SampleDisplay::getView(unsigned long *start, unsigned long *end)
295 {
296 *start = minSample_;
297 *end = maxSample_;
298 }
299
getSelection(unsigned long * start,unsigned long * end)300 bool SampleDisplay::getSelection(unsigned long *start, unsigned long *end)
301 {
302 if (selectionSet_) {
303 *start = selectionStartSample_;
304 *end = selectionEndSample_;
305 return true;
306 }
307
308 return false;
309 }
310
getMarker(unsigned long * sample)311 int SampleDisplay::getMarker(unsigned long *sample)
312 {
313 if (markerSet_) {
314 *sample = markerSample_;
315 return 1;
316 }
317
318 return 0;
319 }
320
setSelectedTrackMarker(int trackNr,int indexNr)321 void SampleDisplay::setSelectedTrackMarker(int trackNr, int indexNr)
322 {
323 selectedTrack_ = trackNr;
324 selectedIndex_ = indexNr;
325 }
326
setRegion(unsigned long start,unsigned long end)327 void SampleDisplay::setRegion(unsigned long start, unsigned long end)
328 {
329 if (tocEdit_ == NULL)
330 return;
331
332 Toc *toc = tocEdit_->toc();
333
334 if (end <= start || end >= toc->length().samples()) {
335 regionSet_ = false;
336 }
337 else {
338 regionStartSample_ = start;
339 regionEndSample_ = end;
340 regionSet_ = true;
341 }
342
343 setView(minSample_, maxSample_);
344 }
345
clearRegion()346 void SampleDisplay::clearRegion()
347 {
348 bool wasSet = regionSet_;
349 regionSet_ = false;
350 if (wasSet) {
351 setView(minSample_, maxSample_);
352 }
353 }
354
getRegion(unsigned long * start,unsigned long * end)355 int SampleDisplay::getRegion(unsigned long *start, unsigned long *end)
356 {
357 if (regionSet_) {
358 *start = regionStartSample_;
359 *end = regionEndSample_;
360 return 1;
361 }
362
363 return 0;
364 }
365
setCursor(int ctrl,unsigned long sample)366 void SampleDisplay::setCursor(int ctrl, unsigned long sample)
367 {
368 if (ctrl == 0) {
369 cursorControlExtern_ = false;
370 }
371 else {
372 cursorControlExtern_ = true;
373
374 gint x = sample2pixel(sample);
375 if (x >= 0)
376 drawCursor(x);
377 else
378 undrawCursor();
379 }
380 }
381
getColor(const char * colorName,Gdk::Color * color)382 void SampleDisplay::getColor(const char *colorName, Gdk::Color *color)
383 {
384 if (!color->parse(colorName) || !get_colormap()->alloc_color(*color)) {
385 log_message(-1, _("Cannot allocate color \"%s\""), colorName);
386 *color = get_style()->get_black();
387 }
388 }
389
scrollTo()390 void SampleDisplay::scrollTo()
391 {
392 unsigned long minSample, maxSample;
393
394 if (tocEdit_ == NULL)
395 return;
396
397 Toc *toc = tocEdit_->toc();
398 GtkAdjustment *adjust = adjustment_->gobj();
399
400 if (adjust->page_size == 0.0)
401 return;
402
403 minSample = (unsigned long)adjust->value;
404 maxSample = (unsigned long)(adjust->value + adjust->page_size) - 1;
405
406 if (maxSample >= toc->length().samples()) {
407 maxSample = toc->length().samples() - 1;
408 if (maxSample <= (unsigned long)(adjust->page_size - 1))
409 minSample = 0;
410 else
411 minSample = maxSample - (unsigned long)(adjust->page_size - 1);
412 }
413
414 viewModified(minSample, maxSample);
415 }
416
pixel2sample(gint x)417 unsigned long SampleDisplay::pixel2sample(gint x)
418 {
419 if (tocEdit_ == NULL)
420 return 0;
421
422 Toc *toc = tocEdit_->toc();
423 unsigned long sample;
424
425 if (toc->length().lba() == 0)
426 return 0;
427
428 assert(x >= sampleStartX_ && x <= sampleEndX_);
429
430 x -= sampleStartX_;
431
432 double res = maxSample_ - minSample_;
433 res /= sampleWidthX_ - 1;
434
435 sample = (unsigned long)(minSample_ + res * x + 0.5);
436
437 unsigned long round = 75 * 588; // 1 second
438 unsigned long rest;
439
440 if (res >= 2 * round) {
441 if ((rest = sample % round) != 0)
442 sample += round - rest;
443 }
444 else {
445 round = 588; // 1 block
446 if (res >= 2 * round) {
447 if ((rest = sample % round) != 0)
448 sample += round - rest;
449 }
450 }
451
452 if (sample > maxSample_)
453 sample = maxSample_;
454
455 return sample;
456 }
457
sample2pixel(unsigned long sample)458 gint SampleDisplay::sample2pixel(unsigned long sample)
459 {
460 if (sample < minSample_ || sample > maxSample_)
461 return -1;
462
463 unsigned long len = maxSample_ - minSample_;
464 double val = sample - minSample_;
465
466 val *= sampleWidthX_ - 1;
467 val /= len;
468
469 return (gint)(sampleStartX_ + val + 0.5);
470 }
471
handleConfigureEvent(GdkEventConfigure * event)472 bool SampleDisplay::handleConfigureEvent(GdkEventConfigure *event)
473 {
474 Glib::RefPtr<Pango::Context> context = get_pango_context();
475 Pango::FontMetrics metrics = context->get_metrics(get_style()->get_font());
476
477 if (!drawGc_) {
478 Glib::RefPtr<Gdk::Bitmap> mask;
479 // mask = Gdk::Bitmap::create(NULL, get_width(), get_height());
480 Glib::RefPtr<const Gdk::Drawable> window(get_window());
481
482 drawGc_ = Gdk::GC::create(get_window());
483
484 getColor("darkslateblue", &sampleColor_);
485 getColor("red3", &middleLineColor_);
486 getColor("gold2", &cursorColor_);
487 getColor("red", &markerColor_);
488 getColor("#ffc0e0", &selectionBackgroundColor_);
489
490 timeLineHeight_ = ((metrics.get_ascent() + metrics.get_descent())
491 / Pango::SCALE);
492 trackLineHeight_ = ((metrics.get_ascent() + metrics.get_descent())
493 / Pango::SCALE);
494
495 trackMarkerPixmap_ =
496 Gdk::Pixmap::create_from_xpm(window, mask,
497 get_style()->get_white(),
498 TRACK_MARKER_XPM_DATA);
499 indexMarkerPixmap_ =
500 Gdk::Pixmap::create_from_xpm(window, mask,
501 get_style()->get_white(),
502 INDEX_MARKER_XPM_DATA);
503 trackMarkerSelectedPixmap_ =
504 Gdk::Pixmap::create_from_xpm(window, mask,
505 markerColor_,
506 TRACK_MARKER_XPM_DATA);
507 indexMarkerSelectedPixmap_ =
508 Gdk::Pixmap::create_from_xpm(window, mask,
509 markerColor_,
510 INDEX_MARKER_XPM_DATA);
511 trackExtendPixmap_ =
512 Gdk::Pixmap::create_from_xpm(window, mask,
513 get_style()->get_white(),
514 TRACK_EXTEND_XPM_DATA);
515 indexExtendPixmap_ =
516 Gdk::Pixmap::create_from_xpm(window, mask,
517 get_style()->get_white(),
518 INDEX_EXTEND_XPM_DATA);
519
520 trackMarkerWidth_ = ((metrics.get_approximate_digit_width() /
521 Pango::SCALE) * 5) + TRACK_MARKER_XPM_WIDTH + 2;
522 trackManager_ = new TrackManager(TRACK_MARKER_XPM_WIDTH);
523 }
524
525 width_ = get_width();
526 height_ = get_height();
527
528 // Don't even try to do anything smart if we haven't received a
529 // reasonable window size yet. This will keep pixmap_ to NULL. This
530 // is important because during startup we don't control how the
531 // configure_event are timed wrt to gcdmaster bringup.
532 if (width_ <= 1 || height_ <= 1)
533 return true;
534
535 chanHeight_ = (height_ - timeLineHeight_ - trackLineHeight_ - 2) / 2;
536
537 lcenter_ = chanHeight_ / 2 + trackLineHeight_;
538 rcenter_ = lcenter_ + timeLineHeight_ + chanHeight_;
539
540 trackLineY_ = trackLineHeight_ - 1;
541
542 timeLineY_ = chanHeight_ + timeLineHeight_ + trackLineHeight_;
543 timeTickWidth_ = ((metrics.get_approximate_digit_width() /
544 Pango::SCALE) * 13) + 3;
545
546 sampleStartX_ = 10;
547 sampleEndX_ = width_ - 10;
548 sampleWidthX_ = sampleEndX_ - sampleStartX_ + 1;
549
550 pixmap_ = Gdk::Pixmap::create(get_window(), get_width(), get_height(), -1);
551
552 if (width_ > 100 && height_ > 100)
553 updateSamples();
554
555 return true;
556 }
557
558
handleExposeEvent(GdkEventExpose * event)559 bool SampleDisplay::handleExposeEvent (GdkEventExpose *event)
560 {
561 redraw(event->area.x, event->area.y, event->area.width, event->area.height,
562 0);
563
564 return false;
565 }
566
handleButtonPressEvent(GdkEventButton * event)567 bool SampleDisplay::handleButtonPressEvent(GdkEventButton *event)
568 {
569 gint x = (gint)event->x;
570 gint y = (gint)event->y;
571
572 dragMode_ = DRAG_NONE;
573
574 // e.g. if audio is playing
575 if (cursorControlExtern_)
576 return true;
577
578 if (event->button == 1 && x >= sampleStartX_ && x <= sampleEndX_) {
579 if (y > trackLineY_) {
580 dragMode_ = DRAG_SAMPLE_MARKER;
581 dragStart_ = dragEnd_ = x;
582 }
583 else {
584 if ((pickedTrackMarker_ = trackManager_->pick(x - sampleStartX_ + 4,
585 &dragStopMin_,
586 &dragStopMax_)) != NULL) {
587 dragMode_ = DRAG_TRACK_MARKER;
588 dragStart_ = dragEnd_ = x;
589 dragLastX_ = -1;
590 dragStopMin_ += sampleStartX_;
591 dragStopMax_ += sampleStartX_;
592 }
593 }
594
595 }
596
597 return true;
598 }
599
handleButtonReleaseEvent(GdkEventButton * event)600 bool SampleDisplay::handleButtonReleaseEvent(GdkEventButton *event)
601 {
602 gint x = (gint)event->x;
603
604 if (cursorControlExtern_)
605 return false;
606
607 if (x < sampleStartX_) {
608 x = sampleStartX_;
609 }
610 else if (x > sampleEndX_) {
611 x = sampleEndX_;
612 }
613
614 if (event->button == 1 && dragMode_ != DRAG_NONE) {
615 if (dragMode_ == DRAG_SAMPLE_MARKER) {
616 if (dragStart_ - x >= -5 && dragStart_ - x <= 5) {
617 selectionSet_ = false;
618 selectionCleared();
619 markerSet(pixel2sample(dragStart_));
620 }
621 else {
622 selectionSet_ = true;
623 if (x > dragStart_) {
624 selectionStartSample_ = pixel2sample(dragStart_);
625 selectionEndSample_ = pixel2sample(x);
626 selectionStart_ = dragStart_;
627 selectionEnd_ = x;
628 }
629 else {
630 selectionEndSample_ = pixel2sample(dragStart_);
631 selectionStartSample_ = pixel2sample(x);
632 selectionEnd_ = dragStart_;
633 selectionStart_ = x;
634 }
635 selectionSet(selectionStartSample_, selectionEndSample_);
636 }
637 }
638 else if (dragMode_ == DRAG_TRACK_MARKER) {
639 if (dragStart_ - x >= -5 && dragStart_ - x <= 5) {
640 trackManager_->select(pickedTrackMarker_);
641 selectedTrack_ = pickedTrackMarker_->trackNr;
642 selectedIndex_ = pickedTrackMarker_->indexNr;
643 drawTrackLine();
644 trackMarkSelected(pickedTrackMarker_->track, selectedTrack_,
645 selectedIndex_);
646 }
647 else {
648 selectedTrack_ = pickedTrackMarker_->trackNr;
649 selectedIndex_ = pickedTrackMarker_->indexNr;
650 trackMarkMoved(pickedTrackMarker_->track, selectedTrack_,
651 selectedIndex_, pixel2sample(x));
652 }
653 pickedTrackMarker_ = NULL;
654 }
655
656 dragMode_ = DRAG_NONE;
657 drawCursor(x);
658 redraw(0, 0, width_, height_, 0);
659 }
660
661 return true;
662 }
663
handleMotionNotifyEvent(GdkEventMotion * event)664 bool SampleDisplay::handleMotionNotifyEvent (GdkEventMotion *event)
665 {
666 gint x, y;
667 GdkModifierType state;
668
669 if (cursorControlExtern_)
670 return TRUE;
671
672 if (event->is_hint)
673 gdk_window_get_pointer (event->window, &x, &y, &state);
674 else {
675 x = (gint)event->x;
676 y = (gint)event->y;
677 state = (GdkModifierType) event->state;
678 }
679
680
681 if (dragMode_ == DRAG_SAMPLE_MARKER) {
682 gint dw = 0;
683 gint dx = 0;
684
685 if (x < sampleStartX_)
686 x = sampleStartX_;
687 else if (x > sampleEndX_)
688 x = sampleEndX_;
689
690 if (selectionEnd_ > dragStart_) {
691 if (x < selectionEnd_) {
692 redraw(x + 1, 0, selectionEnd_ - x, height_, 0x01);
693 if (x < dragStart_) {
694 dw = dragStart_ - x + 1;
695 dx = x;
696 }
697 }
698 else {
699 dw = x - selectionEnd_;
700 dx = selectionEnd_ + 1;
701 }
702 }
703 else if (selectionEnd_ < dragStart_) {
704 if (x > selectionEnd_) {
705 redraw(selectionEnd_, 0, x - selectionEnd_, height_, 0x01);
706 if (x > dragStart_) {
707 dw = x - dragStart_ + 1;
708 dx = dragStart_;
709 }
710 }
711 else {
712 dw = selectionEnd_ - x;
713 dx = x;
714 }
715 }
716
717 if (dw != 0) {
718 drawGc_->set_foreground(cursorColor_);
719 drawGc_->set_function(Gdk::XOR);
720 get_window()->draw_rectangle(drawGc_, TRUE, dx, 0, dw, height_ - 1);
721 drawGc_->set_function(Gdk::COPY);
722 }
723
724 selectionEnd_ = x;
725 }
726 else if (dragMode_ == DRAG_TRACK_MARKER) {
727 if (x < dragStopMin_)
728 x = dragStopMin_;
729
730 if (x > dragStopMax_)
731 x = dragStopMax_;
732
733 if (dragLastX_ > 0) {
734 drawTrackMarker(2, dragLastX_, 0, 0, 0, 0);
735 }
736 drawTrackMarker(1, x, pickedTrackMarker_->trackNr,
737 pickedTrackMarker_->indexNr, 0, 0);
738 dragLastX_ = x;
739 drawCursor(x);
740 }
741 else {
742 drawCursor(x);
743 }
744
745 return TRUE;
746 }
747
handleEnterEvent(GdkEventCrossing * event)748 bool SampleDisplay::handleEnterEvent(GdkEventCrossing *event)
749 {
750 if (cursorControlExtern_)
751 return true;
752
753 drawCursor((gint)event->x);
754 return true;
755 }
756
handleLeaveEvent(GdkEventCrossing * event)757 bool SampleDisplay::handleLeaveEvent(GdkEventCrossing *event)
758 {
759 if (cursorControlExtern_)
760 return true;
761
762 undrawCursor();
763 return true;
764 }
765
766 // drawMask: 0x01: do not draw cursor
767 // 0x02: do not draw marker
redraw(gint x,gint y,gint width,gint height,int drawMask)768 void SampleDisplay::redraw(gint x, gint y, gint width, gint height,
769 int drawMask)
770 {
771 if (!pixmap_)
772 return;
773
774 get_window()->draw_drawable(drawGc_, pixmap_, x, y, x, y, width, height);
775
776 if ((drawMask & 0x02) == 0)
777 drawMarker();
778
779 if ((drawMask & 0x01) == 0 && cursorDrawn_) {
780 cursorDrawn_ = false;
781 drawCursor(cursorX_);
782 }
783 }
784
drawMarker()785 void SampleDisplay::drawMarker()
786 {
787 if (markerSet_) {
788 drawGc_->set_foreground(markerColor_);
789
790 markerX_ = sample2pixel(markerSample_);
791 if (markerX_ >= 0)
792 get_window()->draw_line(drawGc_, markerX_, trackLineY_,
793 markerX_, height_ - 1);
794 }
795 }
796
setMarker(unsigned long sample)797 void SampleDisplay::setMarker(unsigned long sample)
798 {
799 if (markerSet_)
800 redraw(markerX_, 0, 1, height_, 0x02);
801
802 markerSample_ = sample;
803 markerSet_ = true;
804 drawMarker();
805 }
806
clearMarker()807 void SampleDisplay::clearMarker()
808 {
809 if (markerSet_)
810 redraw(markerX_, 0, 1, height_, 0x02);
811
812 markerSet_ = false;
813 }
814
815
updateSamples()816 void SampleDisplay::updateSamples()
817 {
818 if (tocEdit_ == NULL)
819 return;
820
821 Toc *toc = tocEdit_->toc();
822
823 if (!pixmap_)
824 return;
825
826 gint halfHeight = chanHeight_ / 2;
827
828 drawGc_->set_foreground(get_style()->get_white());
829 pixmap_->draw_rectangle(drawGc_, TRUE, 0, 0, width_, height_);
830
831 long res = (maxSample_ - minSample_ + 1)/sampleWidthX_;
832 long bres = res / tocEdit_->sampleManager()->blocking();
833 gint i;
834 double pos;
835 long j;
836 unsigned long s;
837 short lnegsum, lpossum, rnegsum, rpossum;
838 gint regionStart = -1;
839 gint regionEnd = -1;
840 int regionActive = 0;
841
842 if (regionSet_) {
843 if (regionStartSample_ <= maxSample_ &&
844 regionEndSample_ >= minSample_) {
845
846 if (regionStartSample_ > minSample_)
847 regionStart = sample2pixel(regionStartSample_);
848 else
849 regionStart = sampleStartX_;
850
851 if (regionEndSample_ < maxSample_)
852 regionEnd = sample2pixel(regionEndSample_);
853 else
854 regionEnd = sampleEndX_;
855 }
856
857 if (regionStart >= 0 && regionEnd >= regionStart) {
858 drawGc_->set_foreground(selectionBackgroundColor_);
859 pixmap_->draw_rectangle(drawGc_, TRUE,
860 regionStart, lcenter_ - halfHeight,
861 regionEnd - regionStart + 1, chanHeight_);
862 pixmap_->draw_rectangle(drawGc_, TRUE,
863 regionStart, rcenter_ - halfHeight,
864 regionEnd - regionStart + 1, chanHeight_);
865 }
866 }
867
868 drawGc_->set_foreground(sampleColor_);
869
870 if (bres > 0) {
871 for (s = minSample_, i = sampleStartX_;
872 s < maxSample_ && i <= sampleEndX_;
873 s += res, i++) {
874 lnegsum = lpossum = rnegsum = rpossum = 0;
875
876 if (regionStart != -1 && i >= regionStart && regionActive == 0) {
877 regionActive = 1;
878 drawGc_->set_foreground(markerColor_);
879 }
880 else if (regionActive == 1 && i > regionEnd) {
881 regionActive = 2;
882 drawGc_->set_foreground(sampleColor_);
883 }
884
885 tocEdit_->sampleManager()->getPeak(s, s + res, &lnegsum, &lpossum,
886 &rnegsum, &rpossum);
887
888 pos = double(lnegsum) * halfHeight;
889 pos /= SHRT_MAX;
890 if (pos != 0)
891 pixmap_->draw_line(drawGc_, i, lcenter_, i, lcenter_ - (gint)pos);
892
893 pos = double(lpossum) * halfHeight;
894 pos /= SHRT_MAX;
895 if (pos != 0)
896 pixmap_->draw_line(drawGc_, i, lcenter_, i, lcenter_ - (gint)pos);
897
898 pos = double(rnegsum) * halfHeight;
899 pos /= SHRT_MAX;
900 if (pos != 0)
901 pixmap_->draw_line(drawGc_, i, rcenter_, i, rcenter_ - (gint)pos);
902
903 pos = double(rpossum) * halfHeight;
904 pos /= SHRT_MAX;
905 if (pos != 0)
906 pixmap_->draw_line(drawGc_, i, rcenter_, i, rcenter_ - (gint)pos);
907 }
908 }
909 else if (maxSample_ > 0 && res >= 1) {
910
911 TocReader reader(toc);
912
913 if (reader.openData() == 0) {
914 Sample *sampleBuf = new Sample[tocEdit_->sampleManager()->blocking()];
915 double dres = double(maxSample_ - minSample_ + 1)/double(sampleWidthX_);
916 double ds;
917
918 for (ds = minSample_, i = sampleStartX_;
919 ds < maxSample_ && i <= sampleEndX_;
920 ds += dres, i++) {
921
922 lnegsum = lpossum = rnegsum = rpossum = 0;
923
924 if (reader.seekSample((long)ds) == 0 &&
925 reader.readSamples(sampleBuf, res) == res) {
926 for (j = 0; j < res; j++) {
927 if (sampleBuf[j].left() < lnegsum)
928 lnegsum = sampleBuf[j].left();
929
930 if (sampleBuf[j].left() > lpossum)
931 lpossum = sampleBuf[j].left();
932
933 if (sampleBuf[j].right() < rnegsum)
934 rnegsum = sampleBuf[j].right();
935
936 if (sampleBuf[j].right() > rpossum)
937 rpossum = sampleBuf[j].right();
938 }
939 }
940
941 if (regionStart != -1 && i >= regionStart && regionActive == 0) {
942 regionActive = 1;
943 drawGc_->set_foreground(markerColor_);
944 }
945 else if (regionActive == 1 && i > regionEnd) {
946 regionActive = 2;
947 drawGc_->set_foreground(sampleColor_);
948 }
949
950 pos = double(lnegsum) * halfHeight;
951 pos /= SHRT_MAX;
952 if (pos != 0)
953 pixmap_->draw_line(drawGc_, i, lcenter_, i, lcenter_ - (gint)pos);
954
955 pos = double(lpossum) * halfHeight;
956 pos /= SHRT_MAX;
957 if (pos != 0)
958 pixmap_->draw_line(drawGc_, i, lcenter_, i, lcenter_ - (gint)pos);
959
960 pos = double(rnegsum) * halfHeight;
961 pos /= SHRT_MAX;
962 if (pos != 0)
963 pixmap_->draw_line(drawGc_, i, rcenter_, i, rcenter_ - (gint)pos);
964
965 pos = double(rpossum) * halfHeight;
966 pos /= SHRT_MAX;
967 if (pos != 0)
968 pixmap_->draw_line(drawGc_, i, rcenter_, i, rcenter_ - (gint)pos);
969 }
970
971 delete[] sampleBuf;
972 reader.closeData();
973 }
974 }
975 else if (toc != NULL && maxSample_ > minSample_ + 1) {
976
977 TocReader reader(toc);
978
979 if (reader.openData() == 0) {
980 long len = maxSample_ - minSample_ + 1;
981 Sample *sampleBuf = new Sample[len];
982
983 double pres = double(sampleWidthX_ - 1) / double(len - 1);
984 double di;
985 gint pos1;
986 gint lastPosLeft, lastPosRight;
987
988 if (reader.seekSample(minSample_) == 0 &&
989 reader.readSamples(sampleBuf, len) == len) {
990
991 for (j = 1, di = sampleStartX_ + pres;
992 j < len && di < sampleEndX_ + 1; j++, di += pres) {
993 if (regionStart != -1 && regionActive == 0 &&
994 minSample_ + j - 1 >= regionStartSample_ &&
995 minSample_ + j <= regionEndSample_) {
996 regionActive = 1;
997 drawGc_->set_foreground(markerColor_);
998 }
999 else if (regionActive == 1 && minSample_ + j > regionEndSample_) {
1000 regionActive = 2;
1001 drawGc_->set_foreground(sampleColor_);
1002 }
1003
1004 pos = sampleBuf[j - 1].left() * halfHeight;
1005 pos /= SHRT_MAX;
1006
1007 pos1 = sampleBuf[j].left() * halfHeight;
1008 pos1 /= SHRT_MAX;
1009 lastPosLeft = pos1;
1010
1011 if (pos != 0 || pos1 != 0)
1012 pixmap_->draw_line(drawGc_, long(di - pres), lcenter_ - (gint)pos,
1013 long(di), lcenter_ - pos1);
1014
1015 pos = sampleBuf[j - 1].right() * halfHeight;
1016 pos /= SHRT_MAX;
1017
1018 pos1 = sampleBuf[j].right() * halfHeight;
1019 pos1 /= SHRT_MAX;
1020 lastPosRight = pos1;
1021
1022 if (pos != 0 || pos1 != 0)
1023 pixmap_->draw_line(drawGc_, long(di - pres), rcenter_ - (gint)pos,
1024 long(di), rcenter_ - pos1);
1025
1026 }
1027
1028 if (&pixmap_ == 0)
1029 std::cout << "null !!" << std::endl;
1030
1031 if (0 && (gint)di < sampleEndX_) {
1032 pos = sampleBuf[len -1].left() * halfHeight;
1033 pos /= SHRT_MAX;
1034 if (pos != 0 || lastPosLeft != 0)
1035 pixmap_->draw_line(drawGc_, long(di), lcenter_ - lastPosLeft,
1036 sampleEndX_, lcenter_ - (gint)pos);
1037
1038 pos = sampleBuf[len - 1].right() * halfHeight;
1039 pos /= SHRT_MAX;
1040 if (pos != 0 || lastPosRight != 0)
1041 pixmap_->draw_line(drawGc_, long(di), rcenter_ - lastPosRight,
1042 sampleEndX_, rcenter_ - (gint)pos);
1043 }
1044 }
1045 delete[] sampleBuf;
1046 }
1047
1048 }
1049
1050
1051 drawGc_->set_foreground(middleLineColor_);
1052
1053 pixmap_->draw_line(drawGc_, sampleStartX_, lcenter_, sampleEndX_, lcenter_);
1054 pixmap_->draw_line(drawGc_, sampleStartX_, rcenter_, sampleEndX_, rcenter_);
1055
1056 drawGc_->set_foreground(get_style()->get_black());
1057
1058 pixmap_->draw_line(drawGc_, sampleStartX_ - 1, lcenter_ - halfHeight,
1059 sampleEndX_ + 1, lcenter_ - halfHeight);
1060 pixmap_->draw_line(drawGc_, sampleStartX_ - 1, lcenter_ + halfHeight,
1061 sampleEndX_ + 1, lcenter_ + halfHeight);
1062 pixmap_->draw_line(drawGc_, sampleStartX_ - 1, lcenter_ - halfHeight,
1063 sampleStartX_ - 1, lcenter_ + halfHeight);
1064 pixmap_->draw_line(drawGc_, sampleEndX_ + 1, lcenter_ - halfHeight,
1065 sampleEndX_ + 1, lcenter_ + halfHeight);
1066
1067 pixmap_->draw_line(drawGc_, sampleStartX_ - 1, rcenter_ - halfHeight,
1068 sampleEndX_ + 1, rcenter_ - halfHeight);
1069 pixmap_->draw_line(drawGc_, sampleStartX_ - 1, rcenter_ + halfHeight,
1070 sampleEndX_ + 1, rcenter_ + halfHeight);
1071 pixmap_->draw_line(drawGc_, sampleStartX_ - 1, rcenter_ + halfHeight,
1072 sampleStartX_ - 1, rcenter_ - halfHeight);
1073 pixmap_->draw_line(drawGc_, sampleEndX_ + 1, rcenter_ + halfHeight,
1074 sampleEndX_ + 1, rcenter_ - halfHeight);
1075
1076 drawTimeLine();
1077
1078 trackManager_->update(toc, minSample_, maxSample_, sampleWidthX_);
1079 if (selectedTrack_ > 0) {
1080 trackManager_->select(selectedTrack_, selectedIndex_);
1081 }
1082 drawTrackLine();
1083 }
1084
drawCursor(gint x)1085 void SampleDisplay::drawCursor(gint x)
1086 {
1087 if (!pixmap_)
1088 return;
1089
1090 if (x < sampleStartX_ || x > sampleEndX_)
1091 return;
1092
1093 if (cursorDrawn_ && cursorX_ != x) {
1094 redraw(cursorX_, 0, 1, height_, 0x01);
1095 }
1096
1097 if (!cursorDrawn_ || cursorX_ != x) {
1098 drawGc_->set_foreground(cursorColor_);
1099 get_window()->draw_line(drawGc_, x, trackLineY_, x, height_ - 1);
1100 }
1101
1102 cursorDrawn_ = true;
1103 cursorX_ = x;
1104
1105 if (cursorControlExtern_ == false)
1106 cursorMoved(pixel2sample(x));
1107 }
1108
undrawCursor()1109 void SampleDisplay::undrawCursor()
1110 {
1111 if (cursorDrawn_) {
1112 redraw(cursorX_, 0, 1, height_, 0x01);
1113 cursorDrawn_ = false;
1114 }
1115 }
1116
drawTimeTick(gint x,gint y,unsigned long sample)1117 void SampleDisplay::drawTimeTick(gint x, gint y, unsigned long sample)
1118 {
1119 char buf[50];
1120
1121 if (!pixmap_)
1122 return;
1123
1124 unsigned long min = sample / (60 * 44100);
1125 sample %= 60 * 44100;
1126
1127 unsigned long sec = sample / 44100;
1128 sample %= 44100;
1129
1130 unsigned long frame = sample / 588;
1131 sample %= 588;
1132
1133 sprintf(buf, "%lu:%02lu:%02lu.%03lu", min, sec, frame, sample);
1134
1135 drawGc_->set_foreground(get_style()->get_black());
1136
1137 pixmap_->draw_line(drawGc_, x, y - timeLineHeight_, x, y);
1138
1139 Glib::RefPtr<Pango::Layout> playout =
1140 Pango::Layout::create(get_pango_context());
1141 playout->set_text(buf);
1142 pixmap_->draw_layout(drawGc_, x + 3, y - timeLineHeight_ + 1, playout);
1143 }
1144
drawTimeLine()1145 void SampleDisplay::drawTimeLine()
1146 {
1147 if (tocEdit_ == NULL)
1148 return;
1149
1150 Toc *toc = tocEdit_->toc();
1151
1152 if (toc->length().lba() == 0)
1153 return;
1154
1155 gint sep = timeTickWidth_ + timeTickSep_;
1156 unsigned long maxNofTicks = (sampleWidthX_ + timeTickSep_) / sep;
1157 gint x;
1158
1159 unsigned long len = maxSample_ - minSample_ + 1;
1160 unsigned long dt;
1161 unsigned long dtx;
1162 unsigned long startSample;
1163 unsigned long s;
1164
1165 if ((s = len / (60 * 44100)) > 1) {
1166 dt = 60 * 44100;
1167 }
1168 else if ((s = len / 44100) > 1) {
1169 dt = 44100;
1170 }
1171 else if ((s = len / 588) > 1) {
1172 dt = 588;
1173 }
1174 else {
1175 dt = 1;
1176 s = len;
1177 }
1178
1179 if (s > maxNofTicks) {
1180 dtx = s / maxNofTicks;
1181 if (s % maxNofTicks != 0)
1182 dtx++;
1183 dtx *= dt;
1184 }
1185 else {
1186 dtx = dt;
1187 }
1188
1189 if (dt > 1) {
1190 if (minSample_ % dt == 0) {
1191 startSample = minSample_;
1192 }
1193 else {
1194 startSample = minSample_ / dt;
1195 startSample = startSample * dt + dt;
1196 }
1197 }
1198 else {
1199 startSample = minSample_;
1200 }
1201
1202 for (s = startSample; s < maxSample_; s += dtx) {
1203 x = sample2pixel(s);
1204
1205 if (x + timeTickWidth_ <= sampleEndX_)
1206 drawTimeTick(x, timeLineY_, s);
1207 }
1208 }
1209
1210 // Draws track marker.
1211 // mode: 0: draw on 'pixmap_'
1212 // 1: draw on window
1213 // 2: redraw region at given position
drawTrackMarker(int mode,gint x,int trackNr,int indexNr,int selected,int extend)1214 void SampleDisplay::drawTrackMarker(int mode, gint x, int trackNr,
1215 int indexNr, int selected, int extend)
1216 {
1217 if (mode < 2) {
1218 char buf[20];
1219
1220 sprintf(buf, "%d.%d", trackNr, indexNr);
1221
1222 Glib::RefPtr<Gdk::Pixmap> marker;
1223
1224 if (extend) {
1225 marker = (indexNr == 1 ? trackExtendPixmap_ : indexExtendPixmap_);
1226 }
1227 else {
1228 if (selected)
1229 marker = (indexNr == 1 ? trackMarkerSelectedPixmap_ :
1230 indexMarkerSelectedPixmap_);
1231 else
1232 marker = (indexNr == 1 ? trackMarkerPixmap_ : indexMarkerPixmap_);
1233 }
1234
1235 Glib::RefPtr<Gdk::Window> win = get_window();
1236 Glib::RefPtr<Gdk::Drawable> dr = win;
1237
1238 if (mode == 0)
1239 dr = pixmap_;
1240
1241 if (mode == 0) {
1242 if (selected)
1243 drawGc_->set_foreground(markerColor_);
1244 else
1245 drawGc_->set_foreground(get_style()->get_white());
1246
1247 dr->draw_rectangle(drawGc_, TRUE, x-4, trackLineY_ - trackLineHeight_,
1248 trackMarkerWidth_, trackLineHeight_);
1249 }
1250
1251 drawGc_->set_foreground(get_style()->get_black());
1252
1253 dr->draw_drawable(drawGc_, marker, 0, 0,
1254 x - 4, trackLineY_ - TRACK_MARKER_XPM_HEIGHT,
1255 TRACK_MARKER_XPM_WIDTH, TRACK_MARKER_XPM_HEIGHT);
1256
1257 Glib::RefPtr<Pango::Layout> playout =
1258 Pango::Layout::create(get_pango_context());
1259 playout->set_text(buf);
1260 dr->draw_layout(drawGc_,
1261 x + TRACK_MARKER_XPM_WIDTH / 2 + 2,
1262 trackLineY_ - trackLineHeight_ + 2,
1263 playout);
1264 }
1265 else {
1266 redraw(x - 4, trackLineY_ - trackLineHeight_, trackMarkerWidth_,
1267 trackLineHeight_, 0x03);
1268 }
1269 }
1270
drawTrackLine()1271 void SampleDisplay::drawTrackLine()
1272 {
1273 const TrackManager::Entry *run;
1274 const TrackManager::Entry *selected = NULL;
1275
1276 for (run = trackManager_->first(); run != NULL;
1277 run = trackManager_->next()) {
1278 if (run->selected != 0 && run->extend == 0) {
1279 selected = run;
1280 }
1281 else if (run->indexNr != 1 || run->extend != 0) {
1282 drawTrackMarker(0, sampleStartX_ + run->xpos, run->trackNr, run->indexNr,
1283 0, run->extend);
1284 }
1285 }
1286
1287 for (run = trackManager_->first(); run != NULL;
1288 run = trackManager_->next()) {
1289 if (run->indexNr == 1 && run->selected == 0 && run->extend == 0) {
1290 drawTrackMarker(0, sampleStartX_ + run->xpos, run->trackNr, run->indexNr,
1291 0, run->extend);
1292 }
1293 }
1294
1295 if (selected != NULL)
1296 drawTrackMarker(0, sampleStartX_ + selected->xpos, selected->trackNr,
1297 selected->indexNr, 1, 0);
1298 }
1299
updateTrackMarks()1300 void SampleDisplay::updateTrackMarks()
1301 {
1302 if (tocEdit_ == NULL)
1303 return;
1304
1305 Toc *toc = tocEdit_->toc();
1306
1307 drawGc_->set_foreground(get_style()->get_white());
1308 pixmap_->draw_rectangle(drawGc_, TRUE,
1309 sampleStartX_ - 4, trackLineY_ - trackLineHeight_,
1310 width_ - sampleStartX_, trackLineHeight_);
1311
1312 trackManager_->update(toc, minSample_, maxSample_, sampleWidthX_);
1313 if (selectedTrack_ > 0) {
1314 trackManager_->select(selectedTrack_, selectedIndex_);
1315 }
1316 drawTrackLine();
1317
1318 redraw(0, 0, width_, height_, 0x03);
1319 }
1320