a8b9bb14b3d010c7632501f2fa516310f611db7f
[terminatorX.git] / src / tX_panel.cc
1 /*
2     terminatorX - realtime audio scratching software
3     Copyright (C) 1999-2020  Alexander K├Ânig
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18 */
19
20 #include "tX_panel.h"
21 #include "tX_vttfx.h"
22 #include "tX_vtt.h"
23 #include "tX_pbutton.h"
24 #include "tX_mastergui.h"
25 #include <string.h>
26 #include <stdio.h>
27
28 #define WID_DYN TRUE, TRUE, 0
29 #define WID_FIX FALSE, FALSE, 0
30
31 static const GtkTargetEntry entries[] = { { "GTK_LIST_BOX_ROW", GTK_TARGET_SAME_APP, 0 } };
32
33 static vtt_fx *dragged_effect = NULL;
34 static GtkWidget *dragged_list_box = NULL;
35
36 void panel_begin_drag(GtkWidget* widget, GdkDragContext *context, gpointer data) {
37         dragged_effect = (vtt_fx *) data;
38
39         GtkWidget *row = gtk_widget_get_ancestor(widget, GTK_TYPE_LIST_BOX_ROW);
40         dragged_list_box = gtk_widget_get_ancestor(row, GTK_TYPE_LIST_BOX);
41         GtkAllocation allocation;
42         gtk_widget_get_allocation(row, &allocation);
43         cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, allocation.width, allocation.height);
44         cairo_t *cr = cairo_create(surface);
45
46         gtk_style_context_add_class(gtk_widget_get_style_context(row), "dragging");
47         gtk_widget_draw(row, cr);
48         gtk_style_context_remove_class (gtk_widget_get_style_context(row), "dragging");
49
50         int x, y;
51         gtk_widget_translate_coordinates(widget, row, 0, 0, &x, &y);
52         cairo_surface_set_device_offset(surface, -x, -y);
53         gtk_drag_set_icon_surface(context, surface);
54
55         cairo_destroy(cr);
56         cairo_surface_destroy(surface);
57 }
58
59 void panel_get_drag_data(GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint time, gpointer data) {
60         gtk_selection_data_set(selection_data, gdk_atom_intern_static_string("GTK_LIST_BOX_ROW"), 32, (const guchar *) &widget, sizeof(gpointer));
61 }
62
63 void panel_receive_drag_data(GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint32 time, gpointer data) {
64         int pos = gtk_list_box_row_get_index(GTK_LIST_BOX_ROW(widget));
65         GtkWidget* list_box = gtk_widget_get_ancestor(widget, GTK_TYPE_LIST_BOX);
66         GtkWidget* row = GTK_WIDGET((gpointer)* (gpointer*) gtk_selection_data_get_data(selection_data));
67         GtkWidget* source = gtk_widget_get_ancestor(row, GTK_TYPE_LIST_BOX_ROW);
68
69         if (list_box == dragged_list_box) {
70                 if (source != widget) {
71                         g_object_ref (source);
72                         gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent (source)), source);
73                         gtk_list_box_insert(GTK_LIST_BOX(gtk_widget_get_parent (widget)), source, pos);
74                         if (dragged_effect) {
75                                 vtt_class *vtt=(vtt_class*) dragged_effect->get_vtt();
76                                 vtt->effect_move(dragged_effect, pos);
77                         }
78                         g_object_unref (source);
79                 }
80         } else {
81                 tx_note("Effects can be reordered within the\nsame <b>FX</b> or <b>Stereo FX</b> queue only.");
82         }
83         dragged_effect = NULL;
84         dragged_list_box = NULL;
85 }
86
87 void tX_panel :: minimize(GtkWidget *w, tX_panel *p) {
88         if (!p->client_hidden) {
89                 gtk_widget_hide(p->minimize_button);
90                 gtk_widget_show(p->maximize_button);
91                 gtk_widget_hide(p->clientframe);
92                 p->client_hidden=1;
93         } else {
94                 gtk_widget_hide(p->maximize_button);
95                 gtk_widget_show(p->minimize_button);
96                 gtk_widget_show(p->clientframe);
97                 p->client_hidden=0;
98         }
99
100         if (p->controlbox) {
101                 gtk_widget_queue_draw(p->controlbox);
102         }
103 }
104
105 void tX_panel_make_label_bold(GtkWidget *widget) {
106         char label[4096];
107         snprintf(label, sizeof(label), "<b>%s</b>", gtk_label_get_text(GTK_LABEL(widget)));
108         gtk_label_set_markup(GTK_LABEL (widget), label);
109 }
110
111 void tX_panel_make_tooltip(GtkWidget *widget, vtt_fx* effect) {
112         char label[4096];
113         snprintf(label, sizeof(label), "%s\n\nDrag this handle to reorder effects queue.", effect->get_info_string());
114         gtk_widget_set_tooltip_text(widget, label);
115 }
116
117 tX_panel :: tX_panel (const char *name, GtkWidget* controlbox, GCallback close_callback, vtt_fx *effect) {
118         client_hidden=0;
119         this->controlbox = controlbox;
120         add_drywet_button = NULL;
121         remove_drywet_button = NULL;
122
123         list_box_row = gtk_list_box_row_new();
124
125         drag_handle = gtk_event_box_new();
126
127         labelbutton=gtk_label_new(name);
128         gtk_widget_set_halign(labelbutton, GTK_ALIGN_START);
129         tX_panel_make_label_bold(labelbutton);
130         gtk_container_add(GTK_CONTAINER(drag_handle), labelbutton);
131
132         topbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
133         g_object_set(topbox, "margin-start", 10, "margin-end", 0,  "border-width", 0, NULL);
134         gtk_container_add_with_properties(GTK_CONTAINER (topbox), drag_handle, "expand", TRUE, NULL);
135
136         minimize_button=create_top_button(MINIMIZE);
137         gtk_container_add(GTK_CONTAINER(topbox), minimize_button);
138         maximize_button=create_top_button(MAXIMIZE);
139         gtk_container_add(GTK_CONTAINER(topbox), maximize_button);
140
141         if (close_callback) {
142                 close_button = create_top_button(FX_CLOSE);
143                 gtk_widget_set_name(close_button, "close");
144                 g_object_set(close_button, "border-width", 0, NULL);
145                 gtk_container_add(GTK_CONTAINER(topbox), close_button);
146         } else {
147                 close_button = NULL;
148         }
149
150         gtk_container_set_border_width(GTK_CONTAINER(topbox), 0);
151
152         mainbox=gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
153         gtk_container_add(GTK_CONTAINER(list_box_row), mainbox);
154
155         clientbox=gtk_box_new(GTK_ORIENTATION_VERTICAL, 2);
156         clientframe=gtk_frame_new((char *) NULL);
157         gtk_container_set_border_width( GTK_CONTAINER(clientframe), 0);
158         gtk_container_add(GTK_CONTAINER(clientframe), clientbox);
159
160         gtk_box_pack_start(GTK_BOX(mainbox), topbox, WID_FIX);
161         gtk_box_pack_start(GTK_BOX(mainbox), clientframe, WID_FIX);
162
163         gtk_widget_show(labelbutton);
164         gtk_widget_show(minimize_button);
165         gtk_widget_show(topbox);
166         gtk_widget_show(clientbox);
167         gtk_widget_show(clientframe);
168         gtk_widget_show(mainbox);
169         gtk_widget_show(list_box_row);
170         gtk_widget_show(drag_handle);
171
172         if (close_callback) {
173                 gtk_widget_show(close_button);
174                 g_signal_connect(G_OBJECT(close_button), "clicked", (GCallback) close_callback, (gpointer) effect);
175         }
176
177         if (effect) {
178                 tX_panel_make_tooltip(drag_handle, effect);
179
180                 if (effect->has_drywet_feature() != NOT_DRYWET_CAPABLE) {
181                         add_drywet_button = create_top_button(ADD_DRYWET);
182                         remove_drywet_button = create_top_button(REMOVE_DRYWET);
183                 }
184
185                 gtk_drag_source_set(drag_handle, GDK_BUTTON1_MASK, entries, 1, GDK_ACTION_MOVE);
186                 g_signal_connect(drag_handle, "drag-begin", G_CALLBACK(panel_begin_drag), effect);
187                 g_signal_connect(drag_handle, "drag-data-get", G_CALLBACK(panel_get_drag_data), NULL);
188
189                 gtk_drag_dest_set(list_box_row, GTK_DEST_DEFAULT_ALL, entries, 1, GDK_ACTION_MOVE);
190                 g_signal_connect(list_box_row, "drag-data-received", G_CALLBACK(panel_receive_drag_data), (gpointer) effect);
191         }
192
193         g_signal_connect(G_OBJECT(minimize_button), "clicked", (GCallback) tX_panel::minimize, (void *) this);
194         g_signal_connect(G_OBJECT(maximize_button), "clicked", (GCallback) tX_panel::minimize, (void *) this);
195
196 }
197
198 void tX_panel :: add_client_widget(GtkWidget *w)
199 {
200         gtk_box_pack_start(GTK_BOX(clientbox), w, WID_FIX);
201         gtk_widget_show(w);
202 }
203
204
205 tX_panel :: ~tX_panel()
206 {
207         gtk_widget_destroy(clientbox);
208         gtk_widget_destroy(clientframe);
209         gtk_widget_destroy(topbox);
210         gtk_widget_destroy(mainbox);
211 }