Supporters update.
[dcpomatic.git] / src / wx / timecode.cc
1 /*
2     Copyright (C) 2013-2018 Carl Hetherington <cth@carlh.net>
3
4     This file is part of DCP-o-matic.
5
6     DCP-o-matic is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     DCP-o-matic is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
18
19 */
20
21
22 #include "dcpomatic_button.h"
23 #include "timecode.h"
24 #include "wx_util.h"
25 #include "lib/util.h"
26
27
28 using std::string;
29
30
31 TimecodeBase::TimecodeBase (wxWindow* parent, bool set_button)
32         : wxPanel (parent)
33         , _set_button (0)
34 {
35         auto const s = TimecodeBase::size (parent);
36
37         wxTextValidator validator (wxFILTER_INCLUDE_CHAR_LIST);
38         wxArrayString list;
39
40         wxString n (wxT ("0123456789"));
41         for (size_t i = 0; i < n.Length(); ++i) {
42                 list.Add (n[i]);
43         }
44
45         validator.SetIncludes (list);
46
47         _sizer = new wxBoxSizer (wxHORIZONTAL);
48
49         std::vector<wxTextCtrl*> controls;
50
51         _editable = new wxPanel (this);
52         auto editable_sizer = new wxBoxSizer (wxHORIZONTAL);
53         _hours = new wxTextCtrl (_editable, wxID_ANY, wxT(""), wxDefaultPosition, s, 0, validator);
54         controls.push_back(_hours);
55         _minutes = new wxTextCtrl (_editable, wxID_ANY, wxT(""), wxDefaultPosition, s, 0, validator);
56         controls.push_back(_minutes);
57         _seconds = new wxTextCtrl (_editable, wxID_ANY, wxT(""), wxDefaultPosition, s, 0, validator);
58         controls.push_back(_seconds);
59         _frames = new wxTextCtrl (_editable, wxID_ANY, wxT(""), wxDefaultPosition, s, 0, validator);
60         controls.push_back(_frames);
61
62         if (parent->GetLayoutDirection() == wxLayout_RightToLeft) {
63                 std::reverse(controls.begin(), controls.end());
64         }
65
66         for (auto i = controls.begin(); i != controls.end(); ++i) {
67                 (*i)->SetMaxLength(2);
68                 editable_sizer->Add(*i);
69                 if (std::next(i) != controls.end()) {
70                         add_label_to_sizer(editable_sizer, _editable, wxT (":"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL);
71                 }
72         }
73
74         if (set_button) {
75                 _set_button = new Button (_editable, _("Set"), wxDefaultPosition, small_button_size(parent, _("Set")));
76                 editable_sizer->Add (_set_button, 0, wxLEFT | wxRIGHT, 8);
77         }
78         _editable->SetSizerAndFit (editable_sizer);
79         _sizer->Add (_editable);
80
81         _fixed = add_label_to_sizer (_sizer, this, wxT ("42"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL);
82
83         _hours->Bind      (wxEVT_TEXT,   boost::bind (&TimecodeBase::changed, this));
84         _minutes->Bind    (wxEVT_TEXT,   boost::bind (&TimecodeBase::changed, this));
85         _seconds->Bind    (wxEVT_TEXT,   boost::bind (&TimecodeBase::changed, this));
86         _frames->Bind     (wxEVT_TEXT,   boost::bind (&TimecodeBase::changed, this));
87         if (_set_button) {
88                 _set_button->Bind (wxEVT_BUTTON, boost::bind (&TimecodeBase::set_clicked, this));
89                 _set_button->Enable (false);
90         }
91
92         set_editable (true);
93
94         SetSizerAndFit (_sizer);
95 }
96
97 void
98 TimecodeBase::set_focus ()
99 {
100         _hours->SetFocus ();
101 }
102
103 void
104 TimecodeBase::clear ()
105 {
106         checked_set (_hours, wxT (""));
107         checked_set (_minutes, wxT (""));
108         checked_set (_seconds, wxT (""));
109         checked_set (_frames, wxT (""));
110         checked_set (_fixed, wxT (""));
111 }
112
113 void
114 TimecodeBase::changed ()
115 {
116         if (_set_button && !_ignore_changed) {
117                 _set_button->Enable (true);
118         }
119 }
120
121 void
122 TimecodeBase::set_clicked ()
123 {
124         Changed ();
125         if (_set_button) {
126                 _set_button->Enable (false);
127         }
128
129         _ignore_changed = true;
130         if (_hours->GetValue().IsEmpty()) {
131                 _hours->SetValue(wxT("0"));
132         }
133         if (_minutes->GetValue().IsEmpty()) {
134                 _minutes->SetValue(wxT("0"));
135         }
136         if (_seconds->GetValue().IsEmpty()) {
137                 _seconds->SetValue(wxT("0"));
138         }
139         if (_frames->GetValue().IsEmpty()) {
140                 _frames->SetValue(wxT("0"));
141         }
142         _ignore_changed = false;
143 }
144
145 void
146 TimecodeBase::set_editable (bool e)
147 {
148         _editable->Show (e);
149         _fixed->Show (!e);
150         _sizer->Layout ();
151 }
152
153 wxSize
154 TimecodeBase::size (wxWindow* parent)
155 {
156         wxClientDC dc (parent);
157 #ifdef DCPOMATIC_OSX
158         auto size = dc.GetTextExtent(wxT("999"));
159 #else
160         auto size = dc.GetTextExtent(wxT("99999"));
161 #endif
162         size.SetHeight (-1);
163         return size;
164 }