Basics of allowing setup of DCP audio channels.
[dcpomatic.git] / src / wx / audio_mapping_view.cc
1 /*
2     Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <wx/wx.h>
21 #include <wx/renderer.h>
22 #include <wx/grid.h>
23 #include <libdcp/types.h>
24 #include "lib/audio_mapping.h"
25 #include "audio_mapping_view.h"
26 #include "wx_util.h"
27
28 using std::cout;
29 using std::list;
30 using boost::shared_ptr;
31
32 /* This could go away with wxWidgets 2.9, which has an API call
33    to find these values.
34 */
35
36 #ifdef __WXMSW__
37 #define CHECKBOX_WIDTH 16
38 #define CHECKBOX_HEIGHT 16
39 #else
40 #define CHECKBOX_WIDTH 20
41 #define CHECKBOX_HEIGHT 20
42 #endif
43
44 class NoSelectionStringRenderer : public wxGridCellStringRenderer
45 {
46 public:
47         void Draw (wxGrid& grid, wxGridCellAttr& attr, wxDC& dc, const wxRect& rect, int row, int col, bool)
48         {
49                 wxGridCellStringRenderer::Draw (grid, attr, dc, rect, row, col, false);
50         }
51 };
52
53 class CheckBoxRenderer : public wxGridCellRenderer
54 {
55 public:
56
57         void Draw (wxGrid& grid, wxGridCellAttr &, wxDC& dc, const wxRect& rect, int row, int col, bool)
58         {
59 #if wxMAJOR_VERSION == 2 && wxMINOR_VERSION >= 9
60                 dc.SetPen (*wxThePenList->FindOrCreatePen (wxColour (255, 255, 255), 0, wxPENSTYLE_SOLID));
61 #else           
62                 dc.SetPen (*wxThePenList->FindOrCreatePen (wxColour (255, 255, 255), 0, wxSOLID));
63 #endif          
64                 dc.DrawRectangle (rect);
65                 
66                 wxRendererNative::Get().DrawCheckBox (
67                         &grid,
68                         dc, rect,
69                         grid.GetCellValue (row, col) == wxT("1") ? static_cast<int>(wxCONTROL_CHECKED) : 0
70                         );
71         }
72
73         wxSize GetBestSize (wxGrid &, wxGridCellAttr &, wxDC &, int, int)
74         {
75                 return wxSize (CHECKBOX_WIDTH + 4, CHECKBOX_HEIGHT + 4);
76         }
77         
78         wxGridCellRenderer* Clone () const
79         {
80                 return new CheckBoxRenderer;
81         }
82 };
83
84
85 AudioMappingView::AudioMappingView (wxWindow* parent)
86         : wxPanel (parent, wxID_ANY)
87 {
88         _grid = new wxGrid (this, wxID_ANY);
89
90         _grid->CreateGrid (0, 7);
91 #if wxMINOR_VERSION == 9
92         _grid->HideRowLabels ();
93 #else
94         _grid->SetRowLabelSize (0);
95 #endif  
96         _grid->DisableDragRowSize ();
97         _grid->DisableDragColSize ();
98         _grid->EnableEditing (false);
99         _grid->SetCellHighlightPenWidth (0);
100         _grid->SetDefaultRenderer (new NoSelectionStringRenderer);
101
102         set_column_labels ();
103
104         _sizer = new wxBoxSizer (wxVERTICAL);
105         _sizer->Add (_grid, 1, wxEXPAND | wxALL);
106         SetSizerAndFit (_sizer);
107
108         Connect (wxID_ANY, wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler (AudioMappingView::left_click), 0, this);
109 }
110
111 void
112 AudioMappingView::left_click (wxGridEvent& ev)
113 {
114         if (ev.GetCol() == 0) {
115                 return;
116         }
117         
118         if (_grid->GetCellValue (ev.GetRow(), ev.GetCol()) == wxT("1")) {
119                 _grid->SetCellValue (ev.GetRow(), ev.GetCol(), wxT("0"));
120         } else {
121                 _grid->SetCellValue (ev.GetRow(), ev.GetCol(), wxT("1"));
122         }
123
124         _map = AudioMapping ();
125         for (int i = 0; i < _grid->GetNumberRows(); ++i) {
126                 for (int j = 1; j < _grid->GetNumberCols(); ++j) {
127                         if (_grid->GetCellValue (i, j) == wxT ("1")) {
128                                 _map.add (i, static_cast<libdcp::Channel> (j - 1));
129                         }
130                 }
131         }
132
133         Changed (_map);
134 }
135
136 void
137 AudioMappingView::set (AudioMapping map)
138 {
139         _map = map;
140         
141         if (_grid->GetNumberRows ()) {
142                 _grid->DeleteRows (0, _grid->GetNumberRows ());
143         }
144
145         list<int> content_channels = _map.content_channels ();
146         _grid->InsertRows (0, content_channels.size ());
147
148         for (size_t r = 0; r < content_channels.size(); ++r) {
149                 for (int c = 1; c < 7; ++c) {
150                         _grid->SetCellRenderer (r, c, new CheckBoxRenderer);
151                 }
152         }
153         
154         int n = 0;
155         for (list<int>::iterator i = content_channels.begin(); i != content_channels.end(); ++i) {
156                 _grid->SetCellValue (n, 0, wxString::Format (wxT("%d"), *i + 1));
157
158                 list<libdcp::Channel> const d = _map.content_to_dcp (*i);
159                 for (list<libdcp::Channel>::const_iterator j = d.begin(); j != d.end(); ++j) {
160                         int const c = static_cast<int>(*j) + 1;
161                         if (c < _grid->GetNumberCols ()) {
162                                 _grid->SetCellValue (n, c, wxT("1"));
163                         }
164                 }
165                 ++n;
166         }
167 }
168
169 void
170 AudioMappingView::set_channels (int c)
171 {
172         c++;
173
174         if (c < _grid->GetNumberCols ()) {
175                 _grid->DeleteCols (c, _grid->GetNumberCols() - c);
176         } else if (c > _grid->GetNumberCols ()) {
177                 _grid->InsertCols (_grid->GetNumberCols(), c - _grid->GetNumberCols());
178                 set_column_labels ();
179         }
180
181         set (_map);
182 }
183
184 void
185 AudioMappingView::set_column_labels ()
186 {
187         int const c = _grid->GetNumberCols ();
188         
189         _grid->SetColLabelValue (0, _("Content channel"));
190         
191         if (c > 0) {
192                 _grid->SetColLabelValue (1, _("L"));
193         }
194         
195         if (c > 1) {
196                 _grid->SetColLabelValue (2, _("R"));
197         }
198         
199         if (c > 2) {
200                 _grid->SetColLabelValue (3, _("C"));
201         }
202         
203         if (c > 3) {
204                 _grid->SetColLabelValue (4, _("Lfe"));
205         }
206         
207         if (c > 4) {
208                 _grid->SetColLabelValue (5, _("Ls"));
209         }
210         
211         if (c > 5) {
212                 _grid->SetColLabelValue (6, _("Rs"));
213         }
214
215         _grid->AutoSize ();
216 }