1 /*
2  * Copyright (C) 2019-2021 Alexandros Theodotou <alex at zrythm dot org>
3  *
4  * This file is part of Zrythm
5  *
6  * Zrythm is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Affero General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Zrythm 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 Affero General Public License for more details.
15  *
16  * You should have received a copy of the GNU Affero General Public License
17  * along with Zrythm.  If not, see <https://www.gnu.org/licenses/>.
18  */
19 
20 #include "audio/automation_track.h"
21 #include "audio/channel_track.h"
22 #include "audio/port_connections_manager.h"
23 #include "gui/widgets/port_connection_row.h"
24 #include "gui/widgets/inspector_port.h"
25 #include "gui/widgets/port_connections_popover.h"
26 #include "gui/widgets/port_selector_popover.h"
27 #include "plugins/plugin.h"
28 #include "project.h"
29 #include "utils/flags.h"
30 #include "utils/gtk.h"
31 #include "utils/resources.h"
32 
33 #include <gtk/gtk.h>
34 #include <glib/gi18n.h>
35 
G_DEFINE_TYPE(PortConnectionsPopoverWidget,port_connections_popover_widget,GTK_TYPE_POPOVER)36 G_DEFINE_TYPE (
37   PortConnectionsPopoverWidget,
38   port_connections_popover_widget,
39   GTK_TYPE_POPOVER)
40 
41 static void
42 on_add_clicked (
43   GtkButton *                    btn,
44   PortConnectionsPopoverWidget * self)
45 {
46   PortSelectorPopoverWidget * psp =
47     port_selector_popover_widget_new (
48       self, self->port);
49   gtk_popover_set_relative_to (
50     GTK_POPOVER (psp), GTK_WIDGET (btn));
51   gtk_popover_set_position (
52     GTK_POPOVER (psp), GTK_POS_RIGHT);
53   gtk_widget_show_all (GTK_WIDGET (psp));
54 }
55 
56 void
port_connections_popover_widget_refresh(PortConnectionsPopoverWidget * self)57 port_connections_popover_widget_refresh (
58   PortConnectionsPopoverWidget * self)
59 {
60   z_gtk_container_destroy_all_children (
61     GTK_CONTAINER (self->ports_box));
62 
63   /* set title and add ports */
64   if (self->port->id.flow == FLOW_INPUT)
65     {
66       if (GTK_IS_LABEL (self->title))
67         {
68           gtk_label_set_text (
69             self->title, _("INPUTS"));
70         }
71 
72       GPtrArray * srcs = g_ptr_array_new ();
73       int num_srcs =
74         port_connections_manager_get_sources_or_dests (
75           PORT_CONNECTIONS_MGR, srcs,
76           &self->port->id, true);
77       for (int i = 0; num_srcs; i++)
78         {
79           PortConnection * conn =
80             g_ptr_array_index (srcs, i);
81           if (!conn->locked)
82             {
83               PortConnectionRowWidget * pcr =
84                 port_connection_row_widget_new (
85                   self, conn, true);
86               gtk_container_add (
87                 GTK_CONTAINER (self->ports_box),
88                 GTK_WIDGET (pcr));
89             }
90         }
91       g_ptr_array_unref (srcs);
92     }
93   else if (self->port->id.flow ==
94              FLOW_OUTPUT)
95     {
96       if (GTK_IS_LABEL (self->title))
97         {
98           gtk_label_set_text (
99             self->title, _("OUTPUTS"));
100         }
101 
102       GPtrArray * dests = g_ptr_array_new ();
103       int num_dests =
104         port_connections_manager_get_sources_or_dests (
105           PORT_CONNECTIONS_MGR, dests,
106           &self->port->id, false);
107       for (int i = 0; i < num_dests; i++)
108         {
109           PortConnection * conn =
110             g_ptr_array_index (dests, i);
111           if (!conn->locked)
112             {
113               PortConnectionRowWidget * pcr =
114                 port_connection_row_widget_new (
115                   self, conn, false);
116               gtk_container_add (
117                 GTK_CONTAINER (self->ports_box),
118                 GTK_WIDGET (pcr));
119             }
120         }
121       g_ptr_array_unref (dests);
122     }
123 }
124 
125 /**
126  * Creates the popover.
127  *
128  * @param owner Owner widget to pop up at.
129  * @param port Owner port.
130  */
131 PortConnectionsPopoverWidget *
port_connections_popover_widget_new(GtkWidget * owner,Port * port)132 port_connections_popover_widget_new (
133   GtkWidget * owner,
134   Port *      port)
135 {
136   g_return_val_if_fail (
137     GTK_IS_WIDGET (owner) && IS_PORT (port), NULL);
138 
139   PortConnectionsPopoverWidget * self =
140     g_object_new (
141       PORT_CONNECTIONS_POPOVER_WIDGET_TYPE, NULL);
142 
143   self->port = port;
144   gtk_popover_set_relative_to (
145     GTK_POPOVER (self),
146     GTK_WIDGET (owner));
147 
148   port_connections_popover_widget_refresh (self);
149 
150   return self;
151 }
152 
153 static void
finalize(PortConnectionsPopoverWidget * self)154 finalize (
155   PortConnectionsPopoverWidget * self)
156 {
157   G_OBJECT_CLASS (
158     port_connections_popover_widget_parent_class)->
159       finalize (G_OBJECT (self));
160 }
161 
162 static void
port_connections_popover_widget_class_init(PortConnectionsPopoverWidgetClass * _klass)163 port_connections_popover_widget_class_init (
164   PortConnectionsPopoverWidgetClass * _klass)
165 {
166   GObjectClass * oklass = G_OBJECT_CLASS (_klass);
167   oklass->finalize =
168     (GObjectFinalizeFunc) finalize;
169 }
170 
171 static void
port_connections_popover_widget_init(PortConnectionsPopoverWidget * self)172 port_connections_popover_widget_init (
173   PortConnectionsPopoverWidget * self)
174 {
175   /* create all */
176   self->main_box =
177     GTK_BOX (
178       gtk_box_new (GTK_ORIENTATION_VERTICAL, 2));
179   gtk_widget_set_visible (
180     GTK_WIDGET (self->main_box), 1);
181   self->title =
182     GTK_LABEL (gtk_label_new (""));
183   gtk_widget_set_visible (
184     GTK_WIDGET (self->title), 1);
185   self->ports_box =
186     GTK_BOX (
187       gtk_box_new (GTK_ORIENTATION_VERTICAL, 1));
188   gtk_widget_set_visible (
189     GTK_WIDGET (self->ports_box), 1);
190 
191   self->add =
192     GTK_BUTTON (gtk_button_new ());
193   gtk_widget_set_visible (
194     GTK_WIDGET (self->add), true);
195   GtkWidget * btn_box =
196     gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
197   gtk_widget_set_visible (btn_box, true);
198   GtkWidget * img =
199     gtk_image_new_from_icon_name (
200       "add", GTK_ICON_SIZE_BUTTON);
201   gtk_widget_set_visible (img, true);
202   gtk_box_pack_start (
203     GTK_BOX (btn_box), img,
204     F_NO_EXPAND, F_NO_FILL, 0);
205   GtkWidget * lbl =
206     gtk_label_new (_("Add"));
207   gtk_widget_set_visible (lbl, 1);
208   gtk_box_pack_end (
209     GTK_BOX (btn_box), lbl,
210     1, 1, 0);
211   gtk_container_add (
212     GTK_CONTAINER (self->add),
213     btn_box);
214   g_signal_connect (
215     G_OBJECT (self->add), "clicked",
216     G_CALLBACK (on_add_clicked), self);
217 
218   GtkWidget * separator =
219     gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
220   gtk_widget_set_visible (separator, 1);
221 
222   /* add to each other */
223   gtk_box_pack_start (
224     self->main_box, GTK_WIDGET (self->title),
225     F_NO_EXPAND,  F_NO_FILL, 0);
226   gtk_box_pack_start (
227     self->main_box, separator,
228     F_NO_EXPAND, F_NO_FILL, 0);
229   gtk_box_pack_start (
230     self->main_box, GTK_WIDGET (self->ports_box),
231     F_NO_EXPAND, F_NO_FILL, 0);
232   gtk_box_pack_start (
233     self->main_box, GTK_WIDGET (self->add),
234     F_NO_EXPAND, F_NO_FILL, 0);
235 
236   /* add to popover */
237   gtk_container_add (
238     GTK_CONTAINER (self),
239     GTK_WIDGET (self->main_box));
240   /*g_object_ref (self);*/
241 }
242