Basics of better audio stream labelling in the audio mapping view (#849).
authorCarl Hetherington <cth@carlh.net>
Wed, 1 Jun 2016 11:28:00 +0000 (12:28 +0100)
committerCarl Hetherington <cth@carlh.net>
Wed, 1 Jun 2016 11:28:00 +0000 (12:28 +0100)
ChangeLog
src/lib/ffmpeg_examiner.cc
src/lib/ffmpeg_examiner.h
src/wx/audio_mapping_view.cc
src/wx/audio_mapping_view.h
src/wx/audio_panel.cc

index 943aac2c0a9a8950f8aa16552ac46a5bbee9ecc5..81a22db737320defaa7b09e424239eb69740fa1e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2016-06-01  c.hetherington  <cth@carlh.net>
+
+       * Basics of better audio stream labelling in the audio
+       mapping view (#849).
+
 2016-06-01  Carl Hetherington  <cth@carlh.net>
 
        * Updated cs_CZ translation from Tomáš Begeni.
index f98c478e7f46f2039b3cd7113444b9c81ea93b42..06154cc8c66dfeaada4e6fe5a555e5c5b10becfc 100644 (file)
@@ -67,7 +67,7 @@ FFmpegExaminer::FFmpegExaminer (shared_ptr<const FFmpegContent> c, shared_ptr<Jo
                        _audio_streams.push_back (
                                shared_ptr<FFmpegAudioStream> (
                                        new FFmpegAudioStream (
-                                               audio_stream_name (s),
+                                               stream_name (s),
                                                s->id,
                                                s->codec->sample_rate,
                                                (double (_format_context->duration) / AV_TIME_BASE) * s->codec->sample_rate,
@@ -345,22 +345,6 @@ FFmpegExaminer::sample_aspect_ratio () const
        return double (sar.num) / sar.den;
 }
 
-string
-FFmpegExaminer::audio_stream_name (AVStream* s) const
-{
-       SafeStringStream n;
-
-       n << stream_name (s);
-
-       if (!n.str().empty()) {
-               n << "; ";
-       }
-
-       n << s->codec->channels << " channels";
-
-       return n.str ();
-}
-
 string
 FFmpegExaminer::subtitle_stream_name (AVStream* s) const
 {
index f338723b73b2a8968cdfcf7196ff6c101554b972..c3dde84fe11b0bc46227e9949f4c8ccb4c4b6488 100644 (file)
@@ -77,7 +77,6 @@ private:
        void subtitle_packet (AVCodecContext *, boost::shared_ptr<FFmpegSubtitleStream>);
 
        std::string stream_name (AVStream* s) const;
-       std::string audio_stream_name (AVStream* s) const;
        std::string subtitle_stream_name (AVStream* s) const;
        boost::optional<ContentTime> frame_time (AVStream* s) const;
 
index 8d39a40ff91c7de810f6a70854e922d0da694df2..46560e094258f92b15bc3cedd08fe034262081b9 100644 (file)
 #include <wx/wx.h>
 #include <wx/renderer.h>
 #include <wx/grid.h>
+#include <wx/graphics.h>
+#include <boost/foreach.hpp>
 #include <iostream>
 
 using std::cout;
 using std::list;
 using std::string;
+using std::min;
 using std::max;
 using std::vector;
 using boost::shared_ptr;
 
 #define INDICATOR_SIZE 16
+#define LEFT_WIDTH 48
 
 enum {
        ID_off = 1,
@@ -117,6 +121,11 @@ AudioMappingView::AudioMappingView (wxWindow* parent)
        , _last_tooltip_row (0)
        , _last_tooltip_column (0)
 {
+       _left_labels = new wxPanel (this, wxID_ANY);
+       _left_labels->Bind (wxEVT_PAINT, boost::bind (&AudioMappingView::paint_left_labels, this));
+       _top_labels = new wxPanel (this, wxID_ANY);
+       _top_labels->Bind (wxEVT_PAINT, boost::bind (&AudioMappingView::paint_top_labels, this));
+
        _grid = new wxGrid (this, wxID_ANY);
 
        _grid->CreateGrid (0, MAX_DCP_AUDIO_CHANNELS + 1);
@@ -128,9 +137,13 @@ AudioMappingView::AudioMappingView (wxWindow* parent)
        _grid->SetDefaultRenderer (new NoSelectionStringRenderer);
        _grid->AutoSize ();
 
-       _sizer = new wxBoxSizer (wxVERTICAL);
-       _sizer->Add (_grid, 1, wxEXPAND | wxALL);
-       SetSizerAndFit (_sizer);
+       wxSizer* vertical_sizer = new wxBoxSizer (wxVERTICAL);
+       vertical_sizer->Add (_top_labels);
+       wxSizer* horizontal_sizer = new wxBoxSizer (wxHORIZONTAL);
+       horizontal_sizer->Add (_left_labels);
+       horizontal_sizer->Add (_grid, 1, wxEXPAND | wxALL);
+       vertical_sizer->Add (horizontal_sizer);
+       SetSizerAndFit (vertical_sizer);
 
        Bind (wxEVT_GRID_CELL_LEFT_CLICK, boost::bind (&AudioMappingView::left_click, this, _1));
        Bind (wxEVT_GRID_CELL_RIGHT_CLICK, boost::bind (&AudioMappingView::right_click, this, _1));
@@ -329,6 +342,112 @@ AudioMappingView::mouse_moved (wxMouseEvent& ev)
 void
 AudioMappingView::sized (wxSizeEvent& ev)
 {
+       int const top_height = 24;
+
        _grid->AutoSize ();
+       _left_labels->SetMinSize (wxSize (LEFT_WIDTH, _grid->GetSize().GetHeight()));
+       _top_labels->SetMinSize (wxSize (_grid->GetSize().GetWidth() + LEFT_WIDTH, top_height));
        ev.Skip ();
 }
+
+void
+AudioMappingView::paint_left_labels ()
+{
+       wxPaintDC dc (_left_labels);
+
+       wxGraphicsContext* gc = wxGraphicsContext::Create (dc);
+       if (!gc) {
+               return;
+       }
+
+       wxSize const size = dc.GetSize();
+       int const half = size.GetWidth() / 2;
+
+       gc->SetPen (wxPen (wxColour (0, 0, 0)));
+       gc->SetAntialiasMode (wxANTIALIAS_DEFAULT);
+
+       if (_grid->GetNumberRows() > 0) {
+
+               /* Draw a line at the top of the first group */
+               int ypos = _grid->GetColLabelSize() - 1;
+               wxGraphicsPath lines = gc->CreatePath();
+               lines.MoveToPoint (half, ypos);
+               lines.AddLineToPoint (size.GetWidth(), ypos);
+
+               /* And the names of the groups and a line under each */
+               BOOST_FOREACH (Group const & i, _input_groups) {
+                       int const old_ypos = ypos;
+                       ypos += (i.to - i.from + 1) * _grid->GetRowSize(0);
+
+                       dc.SetClippingRegion (0, old_ypos + 2, size.GetWidth(), ypos - 4);
+
+                       dc.SetFont (*wxSWISS_FONT);
+                       wxCoord label_width;
+                       wxCoord label_height;
+                       dc.GetTextExtent (std_to_wx (i.name), &label_width, &label_height);
+
+                       dc.DrawRotatedText (i.name, half + (half - label_height) / 2, (ypos + old_ypos + label_width) / 2, 90);
+                       dc.DestroyClippingRegion ();
+
+                       lines.MoveToPoint (half, ypos);
+                       lines.AddLineToPoint (size.GetWidth(), ypos);
+               }
+
+               gc->StrokePath (lines);
+       }
+
+       /* Overall label */
+       dc.SetFont (wxSWISS_FONT->Bold());
+       wxCoord overall_label_width;
+       wxCoord overall_label_height;
+       dc.GetTextExtent (_("Content"), &overall_label_width, &overall_label_height);
+       dc.DrawRotatedText (
+               _("Content"),
+               (half - overall_label_height) / 2,
+               min (size.GetHeight(), (size.GetHeight() + _grid->GetColLabelSize() + overall_label_width) / 2),
+               90
+               );
+
+       delete gc;
+}
+
+void
+AudioMappingView::paint_top_labels ()
+{
+       wxPaintDC dc (_top_labels);
+       if (_grid->GetNumberCols() == 0) {
+               return;
+       }
+
+       wxGraphicsContext* gc = wxGraphicsContext::Create (dc);
+       if (!gc) {
+               return;
+       }
+
+       wxSize const size = dc.GetSize();
+
+       gc->SetAntialiasMode (wxANTIALIAS_DEFAULT);
+
+       dc.SetFont (wxSWISS_FONT->Bold());
+       wxCoord label_width;
+       wxCoord label_height;
+       dc.GetTextExtent (_("DCP"), &label_width, &label_height);
+
+       dc.DrawText (_("DCP"), (size.GetWidth() + _grid->GetColSize(0) + LEFT_WIDTH - label_width) / 2, (size.GetHeight() - label_height) / 2);
+
+       gc->SetPen (wxPen (wxColour (0, 0, 0)));
+       wxGraphicsPath lines = gc->CreatePath();
+       lines.MoveToPoint (LEFT_WIDTH + _grid->GetColSize(0) - 1, 0);
+       lines.AddLineToPoint (LEFT_WIDTH + _grid->GetColSize(0) - 1, size.GetHeight());
+       lines.MoveToPoint (size.GetWidth() - 1, 0);
+       lines.AddLineToPoint (size.GetWidth() - 1, size.GetHeight());
+       gc->StrokePath (lines);
+
+       delete gc;
+}
+
+void
+AudioMappingView::set_input_groups (vector<Group> const & groups)
+{
+       _input_groups = groups;
+}
index 2a2bacb00f48a757ef3827d6d689afc900b8e1e6..2c4432535c52c7863348055eb416585ff2e5bbae 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2013-2015 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2013-2016 Carl Hetherington <cth@carlh.net>
 
     This file is part of DCP-o-matic.
 
@@ -52,6 +52,24 @@ public:
        void set_input_channels (std::vector<std::string> const & names);
        void set_output_channels (std::vector<std::string> const & names);
 
+       struct Group
+       {
+               Group (int f, int t, std::string n)
+                       : from (f)
+                       , to (t)
+                       , name (n)
+               {}
+
+               /** First channel index (from 0) */
+               int from;
+               /** Last channel index (from 0) */
+               int to;
+               /** Name of this group */
+               std::string name;
+       };
+
+       void set_input_groups (std::vector<Group> const & groups);
+
        boost::signals2::signal<void (AudioMapping)> Changed;
 
 private:
@@ -61,6 +79,8 @@ private:
        void update_cells ();
        void map_values_changed ();
        void sized (wxSizeEvent &);
+       void paint_left_labels ();
+       void paint_top_labels ();
 
        void off ();
        void full ();
@@ -68,13 +88,16 @@ private:
        void edit ();
 
        wxGrid* _grid;
-       wxSizer* _sizer;
+       wxPanel* _left_labels;
+       wxPanel* _top_labels;
        AudioMapping _map;
 
        wxMenu* _menu;
        int _menu_row;
        int _menu_column;
 
+       std::vector<Group> _input_groups;
+
        int _last_tooltip_row;
        int _last_tooltip_column;
 };
index df8c7871ecdbdd0a890406611eb6ebd091de8eba..fa086b8e35ce7f026901035b00852e695b6a5b00 100644 (file)
@@ -25,6 +25,7 @@
 #include "content_panel.h"
 #include "audio_dialog.h"
 #include "lib/config.h"
+#include "lib/ffmpeg_audio_stream.h"
 #include "lib/ffmpeg_content.h"
 #include "lib/cinema_sound_processor.h"
 #include "lib/job_manager.h"
@@ -154,6 +155,16 @@ AudioPanel::film_content_changed (int property)
                if (ac.size() == 1) {
                        _mapping->set (ac.front()->audio->mapping());
                        _mapping->set_input_channels (ac.front()->audio->channel_names ());
+
+                       vector<AudioMappingView::Group> groups;
+                       int c = 0;
+                       BOOST_FOREACH (shared_ptr<const AudioStream> i, ac.front()->audio->streams()) {
+                               shared_ptr<const FFmpegAudioStream> f = dynamic_pointer_cast<const FFmpegAudioStream> (i);
+                               groups.push_back (AudioMappingView::Group (c, c + i->channels() - 1, f ? f->name : ""));
+                               c += i->channels ();
+                       }
+                       _mapping->set_input_groups (groups);
+
                } else {
                        _mapping->set (AudioMapping ());
                }