ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SIDPlayer/src/main.cpp
(Generate patch)

Comparing SIDPlayer/src/main.cpp (file contents):
Revision 1.1 by cebix, 2000-07-28T12:42:30Z vs.
Revision 1.5 by cebix, 2001-04-01T12:13:49Z

# Line 1 | Line 1
1   /*
2 < *  main.cpp - SIDPlayer main program
2 > *  main.cpp - SIDPlayer common routines
3   *
4 < *  SIDPlayer (C) Copyright 1996-2000 Christian Bauer
4 > *  SIDPlayer (C) Copyright 1996-2001 Christian Bauer
5   *
6   *  This program is free software; you can redistribute it and/or modify
7   *  it under the terms of the GNU General Public License as published by
# Line 20 | Line 20
20  
21   #include "sys.h"
22  
23 #include <AppKit.h>
24 #include <InterfaceKit.h>
25 #include <support/UTF8.h>
26 #include <storage/Path.h>
27 #include <media/SoundPlayer.h>
23   #include <stdio.h>
24   #include <string.h>
25 < #include <unistd.h>
25 >
26 > #if defined(__BEOS__)
27 > #include <support/UTF8.h>
28 > #endif
29  
30   #include "main.h"
31   #include "prefs.h"
34 #include "prefs_window.h"
32   #include "mem.h"
33   #include "cpu.h"
34   #include "sid.h"
# Line 40 | Line 37
37  
38   // Global variables
39   uint32 f_rand_seed = 1;
40 + int number_of_songs, current_song;
41 + char module_name[64];
42 + char author_name[64];
43 + char copyright_info[64];
44  
45   // Flag: PSID file loaded and ready
46   static bool psid_loaded = false;
47  
48   // Data from PSID header
48 static int number_of_songs;             // Total number of songs in module
49   static uint16 init_adr;                 // C64 init routine address
50   uint16 play_adr;                                // C64 replay routine address
51   static uint32 speed_flags;              // Speed flags (1 bit/song)
52 char module_name[64];                   // Module name
53 char author_name[64];                   // Author name
54 char copyright_info[64];                // Copyright info
55
56 // Currently played song number (0..n)
57 static int current_song;
58
59
60 // Message codes
61 const uint32 MSG_NEW_MODULE = 'load';
62 const uint32 MSG_NEW_SONG = 'song';
63 const uint32 MSG_SHOW_PREFS = 'pref';
64 const uint32 MSG_PLAY_PAUSE = 'plpa';
65 const uint32 MSG_STOP = 'stop';
66 const uint32 MSG_NEXT = 'next';
67 const uint32 MSG_PREV = 'prev';
68
69
70 class MainWindow;
71 class SpeedSlider;
72
73 // Application object
74 class SIDPlayer : public BApplication {
75 public:
76        SIDPlayer();
77        virtual ~SIDPlayer();
78        virtual void ArgvReceived(int32 argc, char **argv);
79        virtual void RefsReceived(BMessage *msg);
80        virtual void MessageReceived(BMessage *msg);
81        virtual void ReadyToRun(void);
82        virtual void AboutRequested(void);
83
84 private:
85        static void buffer_proc(void *cookie, void *buffer, size_t size, const media_raw_audio_format &format);
86
87        MainWindow *main_window;
88        PrefsWindow *prefs_window;
89        BSoundPlayer player;
90        bool player_stopped;
91 };
92
93
94 // Main window object
95 class MainWindow : public BWindow {
96 public:
97        MainWindow();
98        virtual bool QuitRequested(void);
99        virtual void MessageReceived(BMessage *msg);
100
101 private:
102        BStringView *make_name_display(BRect frame, char *label_text, BView *parent);
103
104        rgb_color fill_color;
105
106        BStringView *name_view;
107        BStringView *author_view;
108        BStringView *copyright_view;
109        BStringView *position_view;
110        SpeedSlider *speed_slider;
111 };
112
113
114 // Top view object (handles drag&drop)
115 class TopView : public BView {
116 public:
117        TopView(BRect frame, const char *name, uint32 resizingMode, uint32 flags);
118        virtual void MessageReceived(BMessage *msg);
119        virtual void KeyDown(const char *bytes, int32 numBytes);
120 };
121
122
123 // Buttons
124 class PlayPauseButton : public BButton {
125 public:
126        PlayPauseButton(BRect frame, BMessage *msg);
127        virtual void Draw(BRect update);
128 };
129
130 class StopButton : public BButton {
131 public:
132        StopButton(BRect frame, BMessage *msg);
133        virtual void Draw(BRect update);
134 };
135
136 class NextButton : public BButton {
137 public:
138        NextButton(BRect frame, BMessage *msg);
139        virtual void Draw(BRect update);
140 };
141
142 class PrevButton : public BButton {
143 public:
144        PrevButton(BRect frame, BMessage *msg);
145        virtual void Draw(BRect update);
146 };
147
148
149 // Speed slider
150 class SpeedSlider : public BSlider {
151 public:
152        SpeedSlider(BRect frame, const char *name) : BSlider(frame, name, "Speed", NULL, -100, 100, B_TRIANGLE_THUMB)
153        {
154                SetHashMarks(B_HASH_MARKS_TOP);
155                SetHashMarkCount(3);
156                const rgb_color bar_color = {128, 128, 216, 0};
157                SetBarColor(bar_color);
158                SetValue(0);
159        }
160        virtual ~SpeedSlider() {}
161        virtual void SetValue(int32 value)
162        {
163                int percent = value < 0 ? 100 + value / 2 : 100 + value;
164                sprintf(status, "%d%%", percent);
165                SIDAdjustSpeed(percent);
166                BSlider::SetValue(value);
167        }
168        virtual char *UpdateText(void) const
169        {
170                return status;
171        }
52  
173 private:
174        mutable char status[32];
175 };
53  
54  
55   /*
56   *  Init everything
57   */
58  
59 < void InitAll(void)
59 > void InitAll(int &argc, char **&argv)
60   {
61 <        PrefsInit(0, NULL);
61 >        PrefsInit(argc, argv);
62          MemoryInit();
63          SIDInit();
64          CPUInit();
# Line 209 | Line 86 | bool LoadPSIDHeader(const char *file, ui
86   {
87          // Read header
88          memset(p, 0, PSID_MAX_HEADER_LENGTH);
89 <        int fd = open(file, O_RDONLY);
90 <        if (fd < 0)
89 >        FILE *f = fopen(file, "rb");
90 >        if (f == NULL)
91                  return false;
92 <        ssize_t actual = read(fd, p, PSID_MAX_HEADER_LENGTH);
93 <        close(fd);
92 >        size_t actual = fread(p, 1, PSID_MAX_HEADER_LENGTH, f);
93 >        fclose(f);
94          return actual >= PSID_MIN_HEADER_LENGTH;
95   }
96  
# Line 227 | Line 104 | bool IsPSIDHeader(const uint8 *p)
104          // Check signature and version
105          uint32 id = read_psid_32(p, PSID_ID);
106          uint16 version = read_psid_16(p, PSID_VERSION);
107 <        return id == 'PSID' && (version == 1 || version == 2);
107 >        return id == 0x50534944 && (version == 1 || version == 2);
108   }
109  
110  
# Line 254 | Line 131 | bool IsPSIDFile(const char *file)
131   bool LoadPSIDFile(const char *file)
132   {
133          // Open file
134 <        int fd = open(file, O_RDONLY);
135 <        if (fd < 0)
134 >        FILE *f = fopen(file, "rb");
135 >        if (f == NULL)
136                  return false;
137  
138          // Clear C64 RAM
# Line 264 | Line 141 | bool LoadPSIDFile(const char *file)
141  
142          // Load and check header
143          uint8 header[PSID_MAX_HEADER_LENGTH];
144 <        ssize_t actual = read(fd, header, PSID_MAX_HEADER_LENGTH);
145 <        if (actual < 0 || !IsPSIDHeader(header)) {
146 <                close(fd);
144 >        memset(header, 0, PSID_MAX_HEADER_LENGTH);
145 >        size_t actual = fread(header, 1, PSID_MAX_HEADER_LENGTH, f);
146 >        if (actual < PSID_MIN_HEADER_LENGTH || !IsPSIDHeader(header)) {
147 >                fclose(f);
148                  return false;
149          }
150  
# Line 285 | Line 163 | bool LoadPSIDFile(const char *file)
163  
164          speed_flags = read_psid_32(header, PSID_SPEED);
165  
166 + #if defined(__BEOS__)
167          int32 sl = 32, dl = 64, state = 0;
168          convert_to_utf8(B_ISO1_CONVERSION, (char *)(header + PSID_NAME), &sl, module_name, &dl, &state);
169          sl = 32, dl = 64, state = 0;
# Line 294 | Line 173 | bool LoadPSIDFile(const char *file)
173          module_name[63] = 0;
174          author_name[63] = 0;
175          copyright_info[63] = 0;
176 + #else
177 +        strncpy(module_name, (char *)(header + PSID_NAME), 32);
178 +        strncpy(author_name, (char *)(header + PSID_AUTHOR), 32);
179 +        strncpy(copyright_info, (char *)(header + PSID_COPYRIGHT), 32);
180 +        module_name[32] = 0;
181 +        author_name[32] = 0;
182 +        copyright_info[32] = 0;
183 + #endif
184  
185          // Seek to start of module data
186 <        lseek(fd, read_psid_16(header, PSID_LENGTH), SEEK_SET);
186 >        fseek(f, read_psid_16(header, PSID_LENGTH), SEEK_SET);
187  
188          // Find load address
189          uint16 load_adr = read_psid_16(header, PSID_START);
190          if (load_adr == 0) {    // Load address is at start of module data
191 <                uint8 hi, lo;
192 <                read(fd, &lo, 1);
306 <                read(fd, &hi, 1);
191 >                uint8 lo = fgetc(f);
192 >                uint8 hi = fgetc(f);
193                  load_adr = (hi << 8) | lo;
194          }
195          if (init_adr == 0)              // Init routine address is equal to load address
196                  init_adr = load_adr;
197  
198          // Load module data to C64 RAM
199 <        read(fd, ram + load_adr, RAM_SIZE - load_adr);
200 <        close(fd);
199 >        fread(ram + load_adr, 1, RAM_SIZE - load_adr, f);
200 >        fclose(f);
201  
202          // Select default song
203          SelectSong(current_song);
# Line 331 | Line 217 | bool LoadPSIDFile(const char *file)
217  
218  
219   /*
220 + *  PSID file loaded and ready?
221 + */
222 +
223 + bool IsPSIDLoaded(void)
224 + {
225 +        return psid_loaded;
226 + }
227 +
228 +
229 + /*
230   *  Select song for playing
231   */
232  
# Line 353 | Line 249 | void SelectSong(int num)
249          // Execute init routine
250          CPUExecute(init_adr, current_song, 0, 0, 1000000);
251   }
356
357
358 /*
359 *  Application constructor
360 */
361
362 #if B_HOST_IS_LENDIAN
363 const media_raw_audio_format audio_format = {44100.0, 2, media_raw_audio_format::B_AUDIO_SHORT, B_MEDIA_LITTLE_ENDIAN, 4096};
364 #else
365 const media_raw_audio_format audio_format = {44100.0, 2, media_raw_audio_format::B_AUDIO_SHORT, B_MEDIA_BIG_ENDIAN, 4096};
366 #endif
367
368 SIDPlayer::SIDPlayer() : BApplication("application/x-vnd.cebix-SIDPlayer"), player(&audio_format, "SIDPlayer", buffer_proc)
369 {
370        main_window = NULL;
371        player.SetHasData(true);
372        player_stopped = true;
373 }
374
375
376 /*
377 *  Application destructor
378 */
379
380 SIDPlayer::~SIDPlayer()
381 {
382        main_window = NULL;
383        prefs_window = NULL;
384        player.Stop();
385        player_stopped = true;
386 }
387
388
389 /*
390 *  Shell arguments received
391 */
392
393 void SIDPlayer::ArgvReceived(int32 argc, char **argv)
394 {
395        if (argc >= 2) {
396                player.Stop();
397                LoadPSIDFile(argv[1]);
398                player.Start();
399                player_stopped = false;
400                if (main_window)
401                        main_window->PostMessage(MSG_NEW_MODULE);
402        }
403 }
404
405
406 /*
407 *  Tracker arguments received
408 */
409
410 void SIDPlayer::RefsReceived(BMessage *msg)
411 {
412        entry_ref the_ref;
413        if (msg->FindRef("refs", &the_ref) == B_NO_ERROR) {
414                BEntry the_entry;
415                if (the_entry.SetTo(&the_ref) == B_NO_ERROR) {
416                        if (the_entry.IsFile()) {
417                                BPath the_path;
418                                the_entry.GetPath(&the_path);
419                                player.Stop();
420                                LoadPSIDFile(the_path.Path());
421                                player.Start();
422                                player_stopped = false;
423                                if (main_window)
424                                        main_window->PostMessage(MSG_NEW_MODULE);
425                        }
426                }
427        }
428 }
429
430
431 /*
432 *  Message received
433 */
434
435 void SIDPlayer::MessageReceived(BMessage *msg)
436 {
437        switch (msg->what) {
438
439                case B_SIMPLE_DATA:     // Dropped message
440                        RefsReceived(msg);
441                        break;
442
443                case MSG_SHOW_PREFS:
444                        if (!prefs_window_open)
445                                prefs_window = new PrefsWindow();
446                        else if (prefs_window)
447                                prefs_window->Activate(true);
448                        break;
449
450                case MSG_PLAY_PAUSE:
451                        if (player_stopped) {
452                                player.Start();
453                                player_stopped = false;
454                        } else {
455                                player.Stop();
456                                player_stopped = true;
457                        }
458                        break;
459
460                case MSG_STOP:
461                        player.Stop();
462                        player_stopped = true;
463                        SelectSong(current_song);
464                        main_window->PostMessage(MSG_NEW_SONG);
465                        break;
466
467                case MSG_NEXT:
468                        if (current_song < number_of_songs-1) {
469                                player.Stop();
470                                SelectSong(current_song + 1);
471                                main_window->PostMessage(MSG_NEW_SONG);
472                                if (!player_stopped)
473                                        player.Start();
474                        }
475                        break;
476
477                case MSG_PREV:
478                        if (current_song > 0) {
479                                player.Stop();
480                                SelectSong(current_song - 1);
481                                main_window->PostMessage(MSG_NEW_SONG);
482                                if (!player_stopped)
483                                        player.Start();
484                        }
485                        break;
486
487                default:
488                        BApplication::MessageReceived(msg);
489                        break;
490        }
491 }
492
493
494 /*
495 *  Arguments processed, open player window
496 */
497
498 void SIDPlayer::ReadyToRun(void)
499 {
500        main_window = new MainWindow();
501        if (psid_loaded)
502                main_window->PostMessage(MSG_NEW_MODULE);
503 }
504
505
506 /*
507 *  Show About window
508 */
509
510 void AboutWindow(void)
511 {
512        BAlert *theAlert = new BAlert("",
513                        "SIDPlayer\nVersion 4.0\n\n"
514                        "Copyright " B_UTF8_COPYRIGHT " 1996-2000 Christian Bauer\n"
515                        "E-mail: Christian.Bauer@uni-mainz.de\n"
516                        "http://www.uni-mainz.de/~bauec002/\n\n"
517                        "SIDPlayer comes with ABSOLUTELY NO\n"
518                        "WARRANTY. This is free software, and\n"
519                        "you are welcome to redistribute it\n"
520                        "under the terms of the GNU General\n"
521                        "Public License.\n",
522                        "OK", NULL, NULL, B_WIDTH_FROM_LABEL);
523
524        BTextView *theText = theAlert->TextView();
525        if (theText) {
526                theText->SetStylable(true);
527                theText->Select(0, 9);
528                BFont ourFont;
529                theText->SetFontAndColor(be_bold_font);
530                theText->GetFontAndColor(2, &ourFont, NULL);
531                ourFont.SetSize(24);
532                theText->SetFontAndColor(&ourFont);
533        }
534        theAlert->Go();
535 }
536
537 void SIDPlayer::AboutRequested(void)
538 {
539        AboutWindow();
540 }
541
542
543 /*
544 *  SoundPlayer buffer procedure
545 */
546
547 void SIDPlayer::buffer_proc(void *cookie, void *buffer, size_t size, const media_raw_audio_format &format)
548 {
549        SIDCalcBuffer((uint8 *)buffer, size);
550 }
551
552
553 /*
554 *  Main window constructor
555 */
556
557 MainWindow::MainWindow() : BWindow(BRect(0, 0, 284, 96), "SIDPlayer", B_TITLED_WINDOW, B_NOT_ZOOMABLE | B_NOT_RESIZABLE | B_ASYNCHRONOUS_CONTROLS)
558 {
559        fill_color = ui_color(B_PANEL_BACKGROUND_COLOR);
560        BRect b = Bounds();
561
562        // Move window to right position
563        Lock();
564        MoveTo(80, 80);
565
566        // Create menu bar
567        BMenuBar *bar = new BMenuBar(BRect(0, 0, b.right, b.bottom), "menubar");
568        BMenu *menu = new BMenu("File");
569        menu->AddItem(new BMenuItem("About SIDPlayer" B_UTF8_ELLIPSIS, new BMessage(B_ABOUT_REQUESTED)));
570        menu->AddItem(new BSeparatorItem());
571        menu->AddItem(new BMenuItem("Sound Control" B_UTF8_ELLIPSIS, new BMessage(MSG_SHOW_PREFS), 'P'));
572        menu->AddItem(new BSeparatorItem());
573        menu->AddItem(new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED), 'Q'));
574        menu->SetTargetForItems(be_app);
575        bar->AddItem(menu);
576        AddChild(bar);
577        SetKeyMenuBar(bar);
578        float menu_height = bar->Bounds().Height();
579
580        // Resize window to fit menu bar
581        ResizeBy(0, menu_height);
582
583        // Light gray background
584        TopView *top = new TopView(BRect(0, menu_height, b.right, b.bottom + menu_height), "main", B_FOLLOW_NONE, B_WILL_DRAW);
585        AddChild(top);
586        top->SetViewColor(fill_color);
587
588        // Name/author/copyright display
589        name_view = make_name_display(BRect(0, 5, 279, 21), "Name", top);
590        author_view = make_name_display(BRect(0, 25, 279, 41), "Author", top);
591        copyright_view = make_name_display(BRect(0, 45, 279, 61), "Copyright", top);
592
593        // Buttons
594        top->AddChild(new PlayPauseButton(BRect(6, 67, 36, 91), new BMessage(MSG_PLAY_PAUSE)));
595        top->AddChild(new StopButton(BRect(37, 67, 67, 91), new BMessage(MSG_STOP)));
596        top->AddChild(new PrevButton(BRect(68, 67, 98, 91), new BMessage(MSG_PREV)));
597        top->AddChild(new NextButton(BRect(99, 67, 129, 91), new BMessage(MSG_NEXT)));
598
599        // Position indicator
600        top->AddChild(position_view = new BStringView(BRect(134, 72, 193, 85), "position", ""));
601        position_view->SetViewColor(fill_color);
602
603        // Speed slider
604        top->AddChild(speed_slider = new SpeedSlider(BRect(194, 62, 279, 63), "speed"));
605
606        // Show window
607        top->MakeFocus();
608        Unlock();
609        Show();
610 }
611
612
613 /*
614 *  Create name display field
615 */
616
617 BStringView *MainWindow::make_name_display(BRect frame, char *label_text, BView *parent)
618 {
619        // Label to the left of the display field
620        BRect label_rect = frame;
621        label_rect.right = label_rect.left + 65;
622
623        BStringView *label = new BStringView(label_rect, "", label_text);
624        parent->AddChild(label);
625        label->SetViewColor(fill_color);
626        label->SetLowColor(fill_color);
627        label->SetAlignment(B_ALIGN_RIGHT);
628        label->SetFont(be_bold_font);
629
630        // Box around display field
631        BRect frame_rect = frame;
632        frame_rect.left += 70;
633
634        BBox *box = new BBox(frame_rect);
635        parent->AddChild(box);
636        box->SetViewColor(fill_color);
637        box->SetLowColor(fill_color);
638
639        // The display field
640        BRect textview_rect = frame_rect;
641        textview_rect.OffsetTo(0, 0);
642        textview_rect.InsetBy(4, 2);
643
644        BStringView *text = new BStringView(textview_rect, "", "");
645        box->AddChild(text);
646        text->SetViewColor(fill_color);
647        text->SetLowColor(fill_color);
648        text->SetFont(be_plain_font);
649        return text;
650 }
651
652
653 /*
654 *  Main window closed, quit program
655 */
656
657 bool MainWindow::QuitRequested(void)
658 {
659        be_app->PostMessage(B_QUIT_REQUESTED);
660        return true;
661 }
662
663
664 /*
665 *  Message received
666 */
667
668 void MainWindow::MessageReceived(BMessage *msg)
669 {
670        switch (msg->what) {
671                case MSG_NEW_MODULE:
672                        // Update text views
673                        Lock();
674                        name_view->SetText(module_name);
675                        author_view->SetText(author_name);
676                        copyright_view->SetText(copyright_info);
677                        Unlock();
678                        // falls through
679
680                case MSG_NEW_SONG:
681                        // Update position indicator and speed slider
682                        if (number_of_songs > 0) {
683                                char str[16];
684                                sprintf(str, "Song %d/%d", current_song + 1, number_of_songs);
685                                position_view->SetText(str);
686                        }
687                        speed_slider->SetValue(0);
688                        break;
689
690                case MSG_SHOW_PREFS:
691                case MSG_PLAY_PAUSE:
692                case MSG_STOP:
693                case MSG_NEXT:
694                case MSG_PREV:
695                        be_app->PostMessage(msg);
696                        break;
697
698                default:
699                        BWindow::MessageReceived(msg);
700                        break;
701        }
702 }
703
704
705 /*
706 *  TopView handles dropped messages (load new PSID module) and keypresses
707 */
708
709 TopView::TopView(BRect frame, const char *name, uint32 resizingMode, uint32 flags)
710 : BView(frame, name, resizingMode, flags) {}
711
712 void TopView::MessageReceived(BMessage *msg)
713 {
714        if (msg->what == B_SIMPLE_DATA)
715                be_app->PostMessage(msg);
716        else
717                BView::MessageReceived(msg);
718 }
719
720 void TopView::KeyDown(const char *bytes, int32 numBytes)
721 {
722        BMessage *msg = Window()->CurrentMessage();
723        uint32 modifiers = 0;
724        msg->FindInt32("modifiers", (int32 *)&modifiers);
725
726        switch (bytes[0]) {
727                case 'p':
728                case 'P':
729                        Window()->PostMessage(MSG_PLAY_PAUSE);
730                        break;
731
732                case B_ESCAPE:
733                case B_SPACE:
734                case 's':
735                case 'S':
736                        Window()->PostMessage(MSG_STOP);
737                        break;
738
739                case B_LEFT_ARROW:
740                        Window()->PostMessage(MSG_PREV);
741                        break;
742
743                case B_RIGHT_ARROW:
744                case 'n':
745                case 'N':
746                        Window()->PostMessage(MSG_NEXT);
747                        break;
748
749                case 'q':
750                case 'Q':
751                        be_app->PostMessage(B_QUIT_REQUESTED);
752                        break;
753        }
754 }
755
756
757 /*
758 *  Play/Pause button
759 */
760
761 PlayPauseButton::PlayPauseButton(BRect frame, BMessage *msg) : BButton(frame, "play", "", msg) {};
762
763 void PlayPauseButton::Draw(BRect update)
764 {
765        // First draw normal button
766        BButton::Draw(update);
767
768        // Then draw play/pause image on top of it
769        if (Value())
770                SetHighColor(255, 255, 255);
771        else
772                SetHighColor(0, 0, 0);
773
774        FillRect(BRect(11, 8, 13, 16));
775        FillTriangle(BPoint(16, 8), BPoint(16, 16), BPoint(20, 12));
776 }
777
778
779 /*
780 *  Stop button
781 */
782
783 StopButton::StopButton(BRect frame, BMessage *msg) : BButton(frame, "stop", "", msg) {};
784
785 void StopButton::Draw(BRect update)
786 {
787        // First draw normal button
788        BButton::Draw(update);
789
790        // Then draw stop image on top of it
791        if (Value())
792                SetHighColor(255, 255, 255);
793        else
794                SetHighColor(0, 0, 0);
795
796        FillRect(BRect(11, 8, 20, 16));
797 }
798
799
800 /*
801 *  "Next" button
802 */
803
804 NextButton::NextButton(BRect frame, BMessage *msg) : BButton(frame, "next", "", msg) {};
805
806 void NextButton::Draw(BRect update)
807 {
808        // First draw normal button
809        BButton::Draw(update);
810
811        // Then draw "next" image on top of it
812        if (Value())
813                SetHighColor(255, 255, 255);
814        else
815                SetHighColor(0, 0, 0);
816
817        FillTriangle(BPoint(12, 8), BPoint(12, 16), BPoint(16, 12));
818        FillRect(BRect(17, 8, 19, 16));
819 }
820
821
822 /*
823 *  "Prev" button
824 */
825
826 PrevButton::PrevButton(BRect frame, BMessage *msg) : BButton(frame, "prev", "", msg) {};
827
828 void PrevButton::Draw(BRect update)
829 {
830        // First draw normal button
831        BButton::Draw(update);
832
833        // Then draw "prev" image on top of it
834        if (Value())
835                SetHighColor(255, 255, 255);
836        else
837                SetHighColor(0, 0, 0);
838
839        FillRect(BRect(12, 8, 14, 16));
840        FillTriangle(BPoint(19, 8), BPoint(19, 16), BPoint(15, 12));
841 }
842
843
844 /*
845 *  Main program
846 */
847
848 int main(int argc, char **argv)
849 {
850        InitAll();
851        SIDPlayer *the_app = new SIDPlayer();
852        the_app->Run();
853        delete the_app;
854        ExitAll();
855        return 0;
856 }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines