spek

Acoustic spectrum analyser https://github.com/alexkay/spek spek.cc
git clone http://git.hanabi.in/repos/spek.git
Log | Files | Refs | README

spek-window.cc (10902B)


      1 #include <wx/aboutdlg.h>
      2 #include <wx/artprov.h>
      3 #include <wx/dnd.h>
      4 #include <wx/filename.h>
      5 #include <wx/protocol/http.h>
      6 #include <wx/sstream.h>
      7 
      8 // WX on WIN doesn't like it when pthread.h is included first.
      9 #include <pthread.h>
     10 
     11 #include <spek-utils.h>
     12 
     13 #include "spek-artwork.h"
     14 #include "spek-preferences-dialog.h"
     15 #include "spek-preferences.h"
     16 #include "spek-spectrogram.h"
     17 
     18 #include "spek-window.h"
     19 
     20 DECLARE_EVENT_TYPE(SPEK_NOTIFY_EVENT, -1)
     21 DEFINE_EVENT_TYPE(SPEK_NOTIFY_EVENT)
     22 
     23 BEGIN_EVENT_TABLE(SpekWindow, wxFrame)
     24     EVT_MENU(wxID_OPEN, SpekWindow::on_open)
     25     EVT_MENU(wxID_SAVE, SpekWindow::on_save)
     26     EVT_MENU(wxID_EXIT, SpekWindow::on_exit)
     27     EVT_MENU(wxID_PREFERENCES, SpekWindow::on_preferences)
     28     EVT_MENU(wxID_HELP, SpekWindow::on_help)
     29     EVT_MENU(wxID_ABOUT, SpekWindow::on_about)
     30     EVT_COMMAND(-1, SPEK_NOTIFY_EVENT, SpekWindow::on_notify)
     31 END_EVENT_TABLE()
     32 
     33 // Forward declarations.
     34 static void * check_version(void *);
     35 
     36 class SpekDropTarget : public wxFileDropTarget
     37 {
     38 public:
     39     SpekDropTarget(SpekWindow *window) : wxFileDropTarget(), window(window) {}
     40 
     41 protected:
     42     virtual bool OnDropFiles(wxCoord, wxCoord, const wxArrayString& filenames){
     43         if (filenames.GetCount() == 1) {
     44             window->open(filenames[0]);
     45             return true;
     46         }
     47         return false;
     48     }
     49 
     50 private:
     51     SpekWindow *window;
     52 };
     53 
     54 SpekWindow::SpekWindow(const wxString& path) :
     55     wxFrame(NULL, -1, wxEmptyString, wxDefaultPosition, wxSize(640, 480)), path(path)
     56 {
     57     this->description = _("Spek - Acoustic Spectrum Analyser");
     58     SetTitle(this->description);
     59 
     60 #ifndef OS_OSX
     61     SetIcons(wxArtProvider::GetIconBundle(ART_SPEK, wxART_FRAME_ICON));
     62 #endif
     63 
     64     wxMenuBar *menu = new wxMenuBar();
     65 
     66     wxMenu *menu_file = new wxMenu();
     67     wxMenuItem *menu_file_open = new wxMenuItem(menu_file, wxID_OPEN);
     68     menu_file->Append(menu_file_open);
     69     wxMenuItem *menu_file_save = new wxMenuItem(menu_file, wxID_SAVE);
     70     menu_file->Append(menu_file_save);
     71     menu_file->AppendSeparator();
     72     menu_file->Append(wxID_EXIT);
     73     menu->Append(menu_file, _("&File"));
     74 
     75     wxMenu *menu_edit = new wxMenu();
     76     wxMenuItem *menu_edit_prefs = new wxMenuItem(menu_edit, wxID_PREFERENCES);
     77     menu_edit_prefs->SetItemLabel(menu_edit_prefs->GetItemLabelText() + "\tCtrl-E");
     78     menu_edit->Append(menu_edit_prefs);
     79     menu->Append(menu_edit, _("&Edit"));
     80 
     81     wxMenu *menu_help = new wxMenu();
     82     wxMenuItem *menu_help_contents = new wxMenuItem(
     83         menu_help, wxID_HELP, wxString(_("&Help")) + "\tF1");
     84     menu_help->Append(menu_help_contents);
     85     wxMenuItem *menu_help_about = new wxMenuItem(menu_help, wxID_ABOUT);
     86     menu_help_about->SetItemLabel(menu_help_about->GetItemLabelText() + "\tShift-F1");
     87     menu_help->Append(menu_help_about);
     88     menu->Append(menu_help, _("&Help"));
     89 
     90     SetMenuBar(menu);
     91 
     92     wxToolBar *toolbar = CreateToolBar();
     93     toolbar->AddTool(
     94         wxID_OPEN,
     95         wxEmptyString,
     96         wxArtProvider::GetBitmap(ART_OPEN, wxART_TOOLBAR),
     97         menu_file_open->GetItemLabelText()
     98     );
     99     toolbar->AddTool(
    100         wxID_SAVE,
    101         wxEmptyString,
    102         wxArtProvider::GetBitmap(ART_SAVE, wxART_TOOLBAR),
    103         menu_file_save->GetItemLabelText()
    104     );
    105     toolbar->AddStretchableSpace();
    106     toolbar->AddTool(
    107         wxID_HELP,
    108         wxEmptyString,
    109         wxArtProvider::GetBitmap(ART_HELP, wxART_TOOLBAR),
    110         _("Help")
    111     );
    112     toolbar->Realize();
    113 
    114     wxSizer *sizer = new wxBoxSizer(wxVERTICAL);
    115 
    116     // wxInfoBar is too limited, construct a custom one.
    117     wxPanel *info_bar = new wxPanel(this);
    118     info_bar->Hide();
    119     info_bar->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOTEXT));
    120     info_bar->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOBK));
    121     wxSizer *info_sizer = new wxBoxSizer(wxHORIZONTAL);
    122     wxStaticText *label = new wxStaticText(
    123         info_bar, -1, _("A new version of Spek is available, click to download."));
    124     label->SetCursor(*new wxCursor(wxCURSOR_HAND));
    125     label->Connect(wxEVT_LEFT_DOWN, wxCommandEventHandler(SpekWindow::on_visit));
    126     // This second Connect() handles clicks on the border
    127     info_bar->Connect(wxEVT_LEFT_DOWN, wxCommandEventHandler(SpekWindow::on_visit));
    128     info_sizer->Add(label, 1, wxALIGN_CENTER_VERTICAL | wxALL, 6);
    129     wxBitmapButton *button = new wxBitmapButton(
    130         info_bar, -1, wxArtProvider::GetBitmap(ART_CLOSE, wxART_BUTTON),
    131         wxDefaultPosition, wxDefaultSize, wxNO_BORDER);
    132     button->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(SpekWindow::on_close));
    133     info_sizer->Add(button, 0, wxALIGN_CENTER_VERTICAL);
    134     info_bar->SetSizer(info_sizer);
    135     sizer->Add(info_bar, 0, wxEXPAND);
    136 
    137     this->spectrogram = new SpekSpectrogram(this);
    138     sizer->Add(this->spectrogram, 1, wxEXPAND);
    139 
    140     this->cur_dir = wxGetHomeDir();
    141 
    142     if (!path.IsEmpty()) {
    143         open(path);
    144     }
    145 
    146     SetDropTarget(new SpekDropTarget(this));
    147 
    148     SetSizer(sizer);
    149 
    150     pthread_t thread;
    151     pthread_create(&thread, NULL, &check_version, this);
    152 }
    153 
    154 void SpekWindow::open(const wxString& path)
    155 {
    156     wxFileName file_name(path);
    157     if (file_name.FileExists()) {
    158         this->path = path;
    159         wxString full_name = file_name.GetFullName();
    160         // TRANSLATORS: window title, %s is replaced with the file name
    161         wxString title = wxString::Format(_("Spek - %s"), full_name.c_str());
    162         SetTitle(title);
    163 
    164         this->spectrogram->open(path);
    165     }
    166 }
    167 
    168 // TODO: s/audio/media/
    169 static const char *audio_extensions[] = {
    170     "3gp",
    171     "aac",
    172     "aif",
    173     "aifc",
    174     "aiff",
    175     "amr",
    176     "awb",
    177     "ape",
    178     "au",
    179     "dts",
    180     "flac",
    181     "flv",
    182     "gsm",
    183     "m4a",
    184     "m4p",
    185     "mp3",
    186     "mp4",
    187     "mp+",
    188     "mpc",
    189     "mpp",
    190     "oga",
    191     "ogg",
    192     "opus",
    193     "ra",
    194     "ram",
    195     "snd",
    196     "wav",
    197     "wma",
    198     "wv",
    199     NULL
    200 };
    201 
    202 void SpekWindow::on_open(wxCommandEvent&)
    203 {
    204     static wxString filters = wxEmptyString;
    205     static int filter_index = 1;
    206 
    207     if (filters.IsEmpty()) {
    208         filters.Alloc(1024);
    209         filters += _("All files");
    210         filters += "|*.*|";
    211         filters += _("Audio files");
    212         filters += "|";
    213         for (int i = 0; audio_extensions[i]; ++i) {
    214             if (i) {
    215                 filters += ";";
    216             }
    217             filters += "*.";
    218             filters += wxString::FromAscii(audio_extensions[i]);
    219         }
    220         filters.Shrink();
    221     }
    222 
    223     wxFileDialog *dlg = new wxFileDialog(
    224         this,
    225         _("Open File"),
    226         this->cur_dir,
    227         wxEmptyString,
    228         filters,
    229         wxFD_OPEN
    230     );
    231     dlg->SetFilterIndex(filter_index);
    232 
    233     if (dlg->ShowModal() == wxID_OK) {
    234         this->cur_dir = dlg->GetDirectory();
    235         filter_index = dlg->GetFilterIndex();
    236         open(dlg->GetPath());
    237     }
    238 
    239     dlg->Destroy();
    240 }
    241 
    242 void SpekWindow::on_save(wxCommandEvent&)
    243 {
    244     static wxString filters = wxEmptyString;
    245 
    246     if (filters.IsEmpty()) {
    247         filters = _("PNG images");
    248         filters += "|*.png";
    249     }
    250 
    251     wxFileDialog *dlg = new wxFileDialog(
    252         this,
    253         _("Save Spectrogram"),
    254         this->cur_dir,
    255         wxEmptyString,
    256         filters,
    257         wxFD_SAVE | wxFD_OVERWRITE_PROMPT
    258     );
    259 
    260     // Suggested name is <file_name>.png
    261     wxString name = _("Untitled");
    262     if (!this->path.IsEmpty()) {
    263         wxFileName file_name(this->path);
    264         name = file_name.GetFullName();
    265     }
    266     name += ".png";
    267     dlg->SetFilename(name);
    268 
    269     if (dlg->ShowModal() == wxID_OK) {
    270         this->cur_dir = dlg->GetDirectory();
    271         this->spectrogram->save(dlg->GetPath());
    272     }
    273 
    274     dlg->Destroy();
    275 }
    276 
    277 void SpekWindow::on_exit(wxCommandEvent&)
    278 {
    279     Close(true);
    280 }
    281 
    282 void SpekWindow::on_preferences(wxCommandEvent&)
    283 {
    284     SpekPreferencesDialog dlg(this);
    285     dlg.ShowModal();
    286 }
    287 
    288 void SpekWindow::on_help(wxCommandEvent&)
    289 {
    290     wxLaunchDefaultBrowser(
    291         wxString::Format("http://spek.cc/man-%s.html", PACKAGE_VERSION)
    292     );
    293 }
    294 
    295 void SpekWindow::on_about(wxCommandEvent&)
    296 {
    297     wxAboutDialogInfo info;
    298     info.AddDeveloper("Alexander Kojevnikov");
    299     info.AddDeveloper("Andreas Cadhalpun");
    300     info.AddDeveloper("Colin Watson");
    301     info.AddDeveloper("Daniel Hams");
    302     info.AddDeveloper("Fabian Deutsch");
    303     info.AddDeveloper("Jonathan Gonzalez V");
    304     info.AddDeveloper("Simon Ruderich");
    305     info.AddDeveloper("Stefan Kost");
    306     info.AddDeveloper("Thibault North");
    307     info.AddArtist("Olga Vasylevska");
    308     // TRANSLATORS: Add your name here
    309     wxString translator = _("translator-credits");
    310     if (translator != "translator-credits") {
    311         info.AddTranslator(translator);
    312     }
    313     info.SetName("Spek");
    314     info.SetVersion(PACKAGE_VERSION);
    315     info.SetCopyright(_("Copyright (c) 2010-2013 Alexander Kojevnikov and contributors"));
    316     info.SetDescription(this->description);
    317 #ifdef OS_UNIX
    318     info.SetWebSite("http://spek.cc/", _("Spek Website"));
    319     info.SetIcon(wxArtProvider::GetIcon("spek", wxART_OTHER, wxSize(128, 128)));
    320 #endif
    321     wxAboutBox(info);
    322 }
    323 
    324 void SpekWindow::on_notify(wxCommandEvent&)
    325 {
    326     this->GetSizer()->Show((size_t)0);
    327     this->Layout();
    328 }
    329 
    330 void SpekWindow::on_visit(wxCommandEvent&)
    331 {
    332     wxLaunchDefaultBrowser("http://spek.cc");
    333 }
    334 
    335 void SpekWindow::on_close(wxCommandEvent& event)
    336 {
    337     wxWindow *self = ((wxWindow *)event.GetEventObject())->GetGrandParent();
    338     self->GetSizer()->Hide((size_t)0);
    339     self->Layout();
    340 }
    341 
    342 static void * check_version(void *p)
    343 {
    344     // Does the user want to check for updates?
    345     SpekPreferences& prefs = SpekPreferences::get();
    346     if (!prefs.get_check_update()) {
    347         return NULL;
    348     }
    349 
    350     // Calculate the number of days since 0001-01-01, borrowed from GLib.
    351     wxDateTime now = wxDateTime::Now();
    352     int year = now.GetYear() - 1;
    353     int days = year * 365;
    354     days += (year >>= 2); // divide by 4 and add
    355     days -= (year /= 25); // divides original # years by 100
    356     days += year >> 2; // divides by 4, which divides original by 400
    357     days += now.GetDayOfYear();
    358 
    359     // When was the last update?
    360     int diff = days - prefs.get_last_update();
    361     if (diff < 7) {
    362         return NULL;
    363     }
    364 
    365     // Get the version number.
    366     wxString version;
    367     wxHTTP http;
    368     if (http.Connect("spek.cc")) {
    369         wxInputStream *stream = http.GetInputStream("/version");
    370         if (stream) {
    371             wxStringOutputStream out(&version);
    372             stream->Read(out);
    373             version.Trim();
    374             delete stream;
    375         }
    376     }
    377 
    378     if (version.IsEmpty()) {
    379         return NULL;
    380     }
    381 
    382     if (1 == spek_vercmp(version.mb_str(wxConvLibc), PACKAGE_VERSION)) {
    383         SpekWindow *self = (SpekWindow *)p;
    384         wxCommandEvent event(SPEK_NOTIFY_EVENT, -1);
    385         event.SetEventObject(self);
    386         wxPostEvent(self, event);
    387     }
    388 
    389     // Update the preferences.
    390     prefs.set_check_update(true);
    391     prefs.set_last_update(days);
    392     return NULL;
    393 }