Workaround compiler warnings and gtk+ deprecations
[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 // workaround GtkEntry not having target set to const for some reason
32 static gchar entries_type[] = "GTK_LIST_BOX_ROW"; 
33 static const GtkTargetEntry entries[] = { { entries_type, GTK_TARGET_SAME_APP, 0 } };
34
35 static vtt_fx *dragged_effect = NULL;
36 static GtkWidget *dragged_list_box = NULL;
37
38 void panel_begin_drag(GtkWidget* widget, GdkDragContext *context, gpointer data) {
39         dragged_effect = (vtt_fx *) data;
40
41         GtkWidget *row = gtk_widget_get_ancestor(widget, GTK_TYPE_LIST_BOX_ROW);
42         dragged_list_box = gtk_widget_get_ancestor(row, GTK_TYPE_LIST_BOX);
43         GtkAllocation allocation;
44         gtk_widget_get_allocation(row, &allocation);
45         cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, allocation.width, allocation.height);
46         cairo_t *cr = cairo_create(surface);
47
48         gtk_style_context_add_class(gtk_widget_get_style_context(row), "dragging");
49         gtk_widget_draw(row, cr);
50         gtk_style_context_remove_class (gtk_widget_get_style_context(row), "dragging");
51
52         int x, y;
53         gtk_widget_translate_coordinates(widget, row, 0, 0, &x, &y);
54         cairo_surface_set_device_offset(surface, -x, -y);
55         gtk_drag_set_icon_surface(context, surface);
56
57         cairo_destroy(cr);
58         cairo_surface_destroy(surface);
59 }
60
61 void panel_get_drag_data(GtkWidget *widget, GdkDragContext *context, GtkSelectionData *selection_data, guint info, guint time, gpointer data) {
62         gtk_selection_data_set(selection_data, gdk_atom_intern_static_string("GTK_LIST_BOX_ROW"), 32, (const guchar *) &widget, sizeof(gpointer));
63 }
64
65 void panel_receive_drag_data(GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint32 time, gpointer data) {
66         int pos = gtk_list_box_row_get_index(GTK_LIST_BOX_ROW(widget));
67         GtkWidget* list_box = gtk_widget_get_ancestor(widget, GTK_TYPE_LIST_BOX);
68         GtkWidget* row = GTK_WIDGET((gpointer)* (gpointer*) gtk_selection_data_get_data(selection_data));
69         GtkWidget* source = gtk_widget_get_ancestor(row, GTK_TYPE_LIST_BOX_ROW);
70
71         if (list_box == dragged_list_box) {
72                 if (source != widget) {
73                         g_object_ref (source);
74                         gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent (source)), source);
75                         gtk_list_box_insert(GTK_LIST_BOX(gtk_widget_get_parent (widget)), source, pos);
76                         if (dragged_effect) {
77                                 vtt_class *vtt=(vtt_class*) dragged_effect->get_vtt();
78                                 vtt->effect_move(dragged_effect, pos);
79                         }
80                         g_object_unref (source);
81                 }
82         } else {
83                 tx_note("Effects can be reordered within the\nsame <b>FX</b> or <b>Stereo FX</b> queue only.");
84         }
85         dragged_effect = NULL;
86         dragged_list_box = NULL;
87 }
88
89 void tX_panel :: minimize(GtkWidget *w, tX_panel *p) {
90         if (!p->client_hidden) {
91                 gtk_widget_hide(p->minimize_button);
92                 gtk_widget_show(p->maximize_button);
93                 gtk_widget_hide(p->clientframe);
94                 p->client_hidden=1;
95         } else {
96                 gtk_widget_hide(p->maximize_button);
97                 gtk_widget_show(p->minimize_button);
98                 gtk_widget_show(p->clientframe);
99                 p->client_hidden=0;
100         }
101
102         if (p->controlbox) {
103                 gtk_widget_queue_draw(p->controlbox);
104         }
105 }
106
107 void tX_panel_make_label_bold(GtkWidget *widget) {
108         char label[4096];
109         snprintf(label, sizeof(label), "<b>%s</b>", gtk_label_get_text(GTK_LABEL(widget)));
110         gtk_label_set_markup(GTK_LABEL (widget), label);
111 }
112
113 void tX_panel_make_tooltip(GtkWidget *widget, vtt_fx* effect) {
114         char label[4096];
115         snprintf(label, sizeof(label), "%s\n\nDrag this handle to reorder effects queue.", effect->get_info_string());
116         gtk_widget_set_tooltip_text(widget, label);
117 }
118
119 tX_panel :: tX_panel (const char *name, GtkWidget* controlbox, GCallback close_callback, vtt_fx *effect) {
120         client_hidden=0;
121         this->controlbox = controlbox;
122         add_drywet_button = NULL;
123         remove_drywet_button = NULL;
124
125         list_box_row = gtk_list_box_row_new();
126
127         drag_handle = gtk_event_box_new();
128
129         labelbutton=gtk_label_new(name);
130         gtk_widget_set_halign(labelbutton, GTK_ALIGN_START);
131         tX_panel_make_label_bold(labelbutton);
132         gtk_container_add(GTK_CONTAINER(drag_handle), labelbutton);
133
134         topbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
135         g_object_set(topbox, "margin-start", 10, "margin-end", 0,  "border-width", 0, NULL);
136         gtk_container_add_with_properties(GTK_CONTAINER (topbox), drag_handle, "expand", TRUE, NULL);
137
138         minimize_button=create_top_button(MINIMIZE);
139         gtk_container_add(GTK_CONTAINER(topbox), minimize_button);
140         maximize_button=create_top_button(MAXIMIZE);
141         gtk_container_add(GTK_CONTAINER(topbox), maximize_button);
142
143         if (close_callback) {
144                 close_button = create_top_button(FX_CLOSE);
145                 gtk_widget_set_name(close_button, "close");
146                 g_object_set(close_button, "border-width", 0, NULL);
147                 gtk_container_add(GTK_CONTAINER(topbox), close_button);
148         } else {
149                 close_button = NULL;
150         }
151
152         gtk_container_set_border_width(GTK_CONTAINER(topbox), 0);
153
154         mainbox=gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
155         gtk_container_add(GTK_CONTAINER(list_box_row), mainbox);
156
157         clientbox=gtk_box_new(GTK_ORIENTATION_VERTICAL, 2);
158         clientframe=gtk_frame_new((char *) NULL);
159         gtk_container_set_border_width( GTK_CONTAINER(clientframe), 0);
160         gtk_container_add(GTK_CONTAINER(clientframe), clientbox);
161
162         gtk_box_pack_start(GTK_BOX(mainbox), topbox, WID_FIX);
163         gtk_box_pack_start(GTK_BOX(mainbox), clientframe, WID_FIX);
164
165         gtk_widget_show(labelbutton);
166         gtk_widget_show(minimize_button);
167         gtk_widget_show(topbox);
168         gtk_widget_show(clientbox);
169         gtk_widget_show(clientframe);
170         gtk_widget_show(mainbox);
171         gtk_widget_show(list_box_row);
172         gtk_widget_show(drag_handle);
173
174         if (close_callback) {
175                 gtk_widget_show(close_button);
176                 g_signal_connect(G_OBJECT(close_button), "clicked", (GCallback) close_callback, (gpointer) effect);
177         }
178
179         if (effect) {
180                 tX_panel_make_tooltip(drag_handle, effect);
181
182                 if (effect->has_drywet_feature() != NOT_DRYWET_CAPABLE) {
183                         add_drywet_button = create_top_button(ADD_DRYWET);
184                         remove_drywet_button = create_top_button(REMOVE_DRYWET);
185                 }
186
187                 gtk_drag_source_set(drag_handle, GDK_BUTTON1_MASK, entries, 1, GDK_ACTION_MOVE);
188                 g_signal_connect(drag_handle, "drag-begin", G_CALLBACK(panel_begin_drag), effect);
189                 g_signal_connect(drag_handle, "drag-data-get", G_CALLBACK(panel_get_drag_data), NULL);
190
191                 gtk_drag_dest_set(list_box_row, GTK_DEST_DEFAULT_ALL, entries, 1, GDK_ACTION_MOVE);
192                 g_signal_connect(list_box_row, "drag-data-received", G_CALLBACK(panel_receive_drag_data), (gpointer) effect);
193         }
194
195         g_signal_connect(G_OBJECT(minimize_button), "clicked", (GCallback) tX_panel::minimize, (void *) this);
196         g_signal_connect(G_OBJECT(maximize_button), "clicked", (GCallback) tX_panel::minimize, (void *) this);
197
198 }
199
200 void tX_panel :: add_client_widget(GtkWidget *w)
201 {
202         gtk_box_pack_start(GTK_BOX(clientbox), w, WID_FIX);
203         gtk_widget_show(w);
204 }
205
206
207 tX_panel :: ~tX_panel()
208 {
209         gtk_widget_destroy(clientbox);
210         gtk_widget_destroy(clientframe);
211         gtk_widget_destroy(topbox);
212         gtk_widget_destroy(mainbox);
213 }