1 // Licensed GNU LGPL v3 or later: http://www.gnu.org/licenses/lgpl.html
2
3 #include "smmorphgridview.hh"
4 #include "smmorphplan.hh"
5 #include "smcomboboxoperator.hh"
6 #include "smutils.hh"
7 #include "smoperatorlayout.hh"
8
9 using namespace SpectMorph;
10
11 using std::string;
12 using std::vector;
13 using std::set;
14
MorphGridControlUI(MorphGridView * morph_grid_view,MorphGrid * morph_grid,Widget * body_widget,ControlXYType ctl_xy)15 MorphGridControlUI::MorphGridControlUI (MorphGridView *morph_grid_view, MorphGrid *morph_grid, Widget *body_widget, ControlXYType ctl_xy) :
16 morph_grid (morph_grid),
17 morph_grid_view (morph_grid_view),
18 ctl_xy (ctl_xy)
19 {
20 MorphGrid::ControlType control_type = (ctl_xy == CONTROL_X) ?
21 morph_grid->x_control_type() :
22 morph_grid->y_control_type();
23
24 MorphOperator *control_op = (ctl_xy == CONTROL_X) ? morph_grid->x_control_op() : morph_grid->y_control_op();
25 combobox = cv_control.create_combobox (body_widget, morph_grid, control_type, control_op);
26
27 connect (cv_control.signal_control_changed, this, &MorphGridControlUI::on_control_changed);
28
29 title = new Label (body_widget, ctl_xy == CONTROL_X ? "X Value" : "Y Value");
30 slider = new Slider (body_widget, 0);
31 label = new Label (body_widget, "");
32
33 /* restore slider value from operator */
34 if (ctl_xy == CONTROL_X)
35 slider->set_value ((morph_grid->x_morphing() + 1) / 2);
36 else
37 slider->set_value ((morph_grid->y_morphing() + 1) / 2);
38
39 connect (slider->signal_value_changed, this, &MorphGridControlUI::on_slider_changed);
40
41 // initial slider state
42 on_control_changed();
43 }
44
45 void
on_slider_changed(double value)46 MorphGridControlUI::on_slider_changed (double value)
47 {
48 value = value * 2 - 1;
49
50 if (ctl_xy == CONTROL_X)
51 morph_grid->set_x_morphing (value);
52 else
53 morph_grid->set_y_morphing (value);
54
55 morph_grid_view->signal_grid_params_changed();
56 }
57
58 void
on_control_changed()59 MorphGridControlUI::on_control_changed()
60 {
61 if (ctl_xy == CONTROL_X)
62 {
63 morph_grid->set_x_control_type_and_op (cv_control.control_type(), cv_control.op());
64 }
65 else
66 {
67 morph_grid->set_y_control_type_and_op (cv_control.control_type(), cv_control.op());
68 }
69 bool control_gui = cv_control.control_type() == MorphOperator::CONTROL_GUI;
70
71 title->set_enabled (control_gui);
72 label->set_enabled (control_gui);
73 slider->set_enabled (control_gui);
74 }
75
76
77
MorphGridView(Widget * parent,MorphGrid * morph_grid,MorphPlanWindow * morph_plan_window)78 MorphGridView::MorphGridView (Widget *parent, MorphGrid *morph_grid, MorphPlanWindow *morph_plan_window) :
79 MorphOperatorView (parent, morph_grid, morph_plan_window),
80 morph_grid (morph_grid)
81 {
82 OperatorLayout op_layout;
83
84 // Width
85 Label *width_title = new Label (body_widget, "Width");
86 Slider *width_slider = new Slider (body_widget, 0);
87 width_slider->set_int_range (1, 7);
88 width_label = new Label (body_widget, "0");
89
90 op_layout.add_row (2, width_title, width_slider, width_label);
91
92 width_slider->set_int_value (morph_grid->width());
93
94 connect (width_slider->signal_int_value_changed, [=] (int width) {
95 morph_grid->set_width (width);
96 signal_grid_params_changed();
97 });
98
99 // Height
100 Label *height_title = new Label (body_widget, "Height");
101 Slider *height_slider = new Slider (body_widget, 0);
102 height_slider->set_int_range (1, 7);
103 height_label = new Label (body_widget, "0");
104
105 op_layout.add_row (2, height_title, height_slider, height_label);
106
107 height_slider->set_int_value (morph_grid->height());
108
109 connect (height_slider->signal_int_value_changed, [=] (int height) {
110 morph_grid->set_height (height);
111 signal_grid_params_changed();
112 });
113
114 // X Control
115 x_ui = new MorphGridControlUI (this, morph_grid, body_widget, MorphGridControlUI::CONTROL_X);
116 op_layout.add_row (3, new Label (body_widget, "X Control"), x_ui->combobox);
117
118 // Y Control
119 y_ui = new MorphGridControlUI (this, morph_grid, body_widget, MorphGridControlUI::CONTROL_Y);
120 op_layout.add_row (3, new Label (body_widget, "Y Control"), y_ui->combobox);
121
122 // X Value
123 op_layout.add_row (2, x_ui->title, x_ui->slider, x_ui->label);
124
125 // Y Value
126 op_layout.add_row (2, y_ui->title, y_ui->slider, y_ui->label);
127
128 // Grid
129 grid_widget = new MorphGridWidget (body_widget, morph_grid, this);
130 op_layout.add_fixed (30, 30, grid_widget);
131
132 connect (grid_widget->signal_selection_changed, this, &MorphGridView::on_selection_changed);
133
134 // Source
135 auto input_op_filter = ComboBoxOperator::make_filter (morph_grid, MorphOperator::OUTPUT_AUDIO);
136 op_title = new Label (body_widget, "Source");
137 op_combobox = new ComboBoxOperator (body_widget, morph_grid->morph_plan(), input_op_filter);
138 op_layout.add_row (3, op_title, op_combobox);
139
140 connect (op_combobox->signal_item_changed, this, &MorphGridView::on_operator_changed);
141
142 // Volume
143 delta_db_title = new Label (body_widget, "Volume");
144 delta_db_slider = new Slider (body_widget, 0.5);
145 delta_db_label = new Label (body_widget, string_locale_printf ("%.1f dB", 0.0));
146
147 op_layout.add_row (2, delta_db_title, delta_db_slider, delta_db_label);
148
149 connect (delta_db_slider->signal_value_changed, this, &MorphGridView::on_delta_db_changed);
150
151 // state updates to perform if some grid parameter changes
152 connect (signal_grid_params_changed, this, &MorphGridView::on_grid_params_changed);
153 connect (grid_widget->signal_grid_params_changed, this, &MorphGridView::on_grid_params_changed);
154
155 // Global
156 connect (morph_grid->morph_plan()->signal_index_changed, this, &MorphGridView::on_index_changed);
157
158 on_index_changed(); // add instruments to op_combobox
159 on_grid_params_changed(); // initial morphing slider/label setup
160 on_selection_changed(); // initial selection
161
162 op_layout.activate();
163 }
164
165 double
view_height()166 MorphGridView::view_height()
167 {
168 return 56;
169 }
170
171 void
on_grid_params_changed()172 MorphGridView::on_grid_params_changed()
173 {
174 width_label->set_text (string_printf ("%d", morph_grid->width()));
175 height_label->set_text (string_printf ("%d", morph_grid->height()));
176 x_ui->slider->set_value ((morph_grid->x_morphing() + 1) / 2);
177 y_ui->slider->set_value ((morph_grid->y_morphing() + 1) / 2);
178 x_ui->label->set_text (string_locale_printf ("%.2f", morph_grid->x_morphing()));
179 y_ui->label->set_text (string_locale_printf ("%.2f", morph_grid->y_morphing()));
180 }
181
182 void
on_operator_changed()183 MorphGridView::on_operator_changed()
184 {
185 if (morph_grid->has_selection())
186 {
187 MorphGridNode node = morph_grid->input_node (morph_grid->selected_x(), morph_grid->selected_y());
188
189 node.op = op_combobox->active();
190 node.smset = morph_grid->morph_plan()->index()->label_to_smset (op_combobox->active_str_choice());
191
192 morph_grid->set_input_node (morph_grid->selected_x(), morph_grid->selected_y(), node);
193
194 signal_grid_params_changed();
195 }
196 }
197
198 void
update_db_label(double db)199 MorphGridView::update_db_label (double db)
200 {
201 delta_db_label->set_text (string_locale_printf ("%.1f dB", db));
202 }
203
204 void
on_delta_db_changed(double new_value)205 MorphGridView::on_delta_db_changed (double new_value)
206 {
207 const double db = (new_value * 2 - 1) * 48;
208
209 update_db_label (db);
210
211 if (morph_grid->has_selection())
212 {
213 MorphGridNode node = morph_grid->input_node (morph_grid->selected_x(), morph_grid->selected_y());
214
215 node.delta_db = db;
216
217 morph_grid->set_input_node (morph_grid->selected_x(), morph_grid->selected_y(), node);
218 }
219 }
220
221 void
on_selection_changed()222 MorphGridView::on_selection_changed()
223 {
224 op_title->set_enabled (morph_grid->has_selection());
225 op_combobox->set_enabled (morph_grid->has_selection());
226 delta_db_title->set_enabled (morph_grid->has_selection());
227 delta_db_slider->set_enabled (morph_grid->has_selection());
228 delta_db_label->set_enabled (morph_grid->has_selection());
229
230 if (morph_grid->has_selection())
231 {
232 MorphGridNode node = morph_grid->input_node (morph_grid->selected_x(), morph_grid->selected_y());
233
234 if (node.smset != "")
235 {
236 g_assert (node.op == NULL);
237 string label = morph_grid->morph_plan()->index()->smset_to_label (node.smset);
238 op_combobox->set_active_str_choice (label);
239 }
240 else
241 {
242 op_combobox->set_active (node.op);
243 }
244 delta_db_slider->set_value ((node.delta_db / 48 + 1) / 2);
245 update_db_label (node.delta_db);
246 }
247 }
248
249 void
on_index_changed()250 MorphGridView::on_index_changed()
251 {
252 op_combobox->clear_str_choices();
253
254 set<string> smset_set;
255 auto groups = morph_grid->morph_plan()->index()->groups();
256 for (auto group : groups)
257 {
258 op_combobox->add_str_headline (group.group);
259 for (auto instrument : group.instruments)
260 {
261 op_combobox->add_str_choice (instrument.label);
262 smset_set.insert (instrument.smset);
263 }
264 }
265 op_combobox->set_op_headline ("Sources");
266
267 for (int x = 0; x < morph_grid->width(); x++)
268 {
269 for (int y = 0; y < morph_grid->height(); y++)
270 {
271 MorphGridNode node = morph_grid->input_node (x, y);
272
273 if (node.smset != "" && !smset_set.count (node.smset))
274 {
275 // instrument not present in new index, remove
276 // (probably should not be done in gui code)
277 node.smset = "";
278 morph_grid->set_input_node (x, y, node);
279 }
280 }
281 }
282 }
283