Alex: Added the new sources for terminatorX 3.5
[terminatorX.git] / src / tX_widget.c
1 /*
2     terminatorX - realtime audio scratching software
3     Copyright (C) 1999  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, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  
19     File: tX_widget.c
20  
21     Description: This contains the implementation of the tx_widget.
22                  This file is based on the GTK+ widget example from
23                  the GTK+ 1.2 tutorial.
24 */    
25
26 #define FR_SIZE 3
27 #define DBL_FR_SIZE 6
28
29 #include <math.h>
30
31 #include <gtk/gtkwindow.h>
32 #include "tX_widget.h"
33 #include "tX_types.h"
34 #include <malloc.h>
35
36 #ifndef WIN32
37 #include <unistd.h>
38 #endif
39
40 #ifdef __cplusplus
41 extern "C" {
42 #endif /* __cplusplus */
43
44 #define TX_DEFAULT_SIZE_X 200
45 #define TX_DEFAULT_SIZE_Y 100
46
47 /* pre dec */
48 static void gtk_tx_class_init (GtkTxClass *);
49 static void gtk_tx_init (GtkTx *tx);
50 GtkWidget* gtk_tx_new (int16_t *wavdata, int wavsamples);
51 static void gtk_tx_destroy (GtkObject *object);
52 void gtk_tx_set_data(GtkTx *tx, int16_t *wavdata, int wavsamples);
53 static void gtk_tx_realize (GtkWidget *widget);
54 static void gtk_tx_size_request (GtkWidget *widget, GtkRequisition *requisition);
55 static void gtk_tx_size_allocate (GtkWidget *widget, GtkAllocation *allocation);
56 static gint gtk_tx_expose (GtkWidget *widget, GdkEventExpose *event);
57 static void gtk_tx_update (GtkTx *tx);
58 static void gtk_tx_prepare (GtkWidget *widget);
59
60 /* Local data */
61
62 static GtkWidgetClass *parent_class = NULL;
63
64 guint
65 gtk_tx_get_type ()
66 {
67   static guint tx_type = 0;
68
69   if (!tx_type)
70     {
71       GtkTypeInfo tx_info =
72       {
73         "GtkTx",
74         sizeof (GtkTx),
75         sizeof (GtkTxClass),
76         (GtkClassInitFunc) gtk_tx_class_init,
77         (GtkObjectInitFunc) gtk_tx_init,
78         (GtkArgSetFunc) NULL,
79         (GtkArgGetFunc) NULL,
80       };
81
82       tx_type = gtk_type_unique (gtk_widget_get_type (), &tx_info);
83     }
84
85   return tx_type;
86 }
87
88 static void
89 gtk_tx_class_init (GtkTxClass *gclass)
90 {
91   GtkObjectClass *object_class;
92   GtkWidgetClass *widget_class;
93
94   object_class = (GtkObjectClass*) gclass;
95   widget_class = (GtkWidgetClass*) gclass;
96
97   parent_class = gtk_type_class (gtk_widget_get_type ());
98
99   object_class->destroy = gtk_tx_destroy;
100
101   widget_class->realize = gtk_tx_realize;
102   widget_class->expose_event = gtk_tx_expose;
103   widget_class->size_request = gtk_tx_size_request;
104   widget_class->size_allocate = gtk_tx_size_allocate;
105 //  widget_class->button_press_event = gtk_tx_button_press;
106 //  widget_class->button_release_event = gtk_tx_button_release;
107 //  widget_class->motion_notify_event = gtk_tx_motion_notify;
108 }
109
110 void gtk_tx_mk_col(GtkTx *tx, GdkColor *col, float r, float g, float b)
111 {
112         float max=65535.0;
113         
114         col->red=(gint) (r*max);
115         col->green=(gint) (g*max);
116         col->blue=(gint) (b*max);
117 //      printf("r: %8i, g: %8i, b: %8i\n", col->red, col->green, col->blue);
118         gdk_colormap_alloc_color (gtk_widget_get_colormap (GTK_WIDGET(tx)), col, 1, 1);         
119 }
120
121 static void
122 gtk_tx_init (GtkTx *tx)
123 {
124         GdkColormap *priv;
125                 
126         tx->disp_data=NULL;
127         
128         tx->data=NULL;
129         tx->samples=0;
130         
131         tx->do_showframe=0;
132         
133         priv=gdk_colormap_new(gtk_widget_get_visual(GTK_WIDGET(tx)), 6);
134         gtk_widget_set_colormap(GTK_WIDGET(tx), priv);
135
136         gtk_tx_mk_col(tx, &tx->bg, 0, 0, 0);
137
138         gtk_tx_mk_col(tx, &tx->fg, 0, 1, 0);    
139
140         gtk_tx_mk_col(tx, &tx->busy_fg, 1, 1, 1);
141         gtk_tx_mk_col(tx, &tx->busy_bg, 1, 0.4, 0.4);
142
143         gtk_tx_mk_col(tx, &tx->mute_fg, 0, 1, 1);
144         gtk_tx_mk_col(tx, &tx->mute_bg, 0, 0, 1);       
145         gtk_tx_mk_col(tx, &tx->framecol, 1,0,0);
146 }
147
148 GtkWidget*
149 gtk_tx_new (int16_t *wavdata, int wavsamples)
150 {
151   GtkTx *tx;
152
153   tx = gtk_type_new (gtk_tx_get_type ());
154
155   tx->data=wavdata;
156   tx->samples=wavsamples;
157
158 //  gtk_tx_prepare(GTK_WIDGET(tx));     
159
160   return GTK_WIDGET (tx);
161 }
162
163 static void
164 gtk_tx_destroy (GtkObject *object)
165 {
166   g_return_if_fail (object != NULL);
167   g_return_if_fail (GTK_IS_TX (object));
168
169   if (GTK_OBJECT_CLASS (parent_class)->destroy)
170     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
171 }
172
173
174 void gtk_tx_set_data(GtkTx *tx, int16_t *wavdata, int wavsamples)
175 {
176         g_return_if_fail (tx != NULL);
177         g_return_if_fail (GTK_IS_TX (tx));
178         
179         tx->data=wavdata;
180         tx->samples=wavsamples;
181         
182         gtk_tx_prepare(GTK_WIDGET(tx));         
183         gtk_tx_update(tx);
184 }
185
186 static void
187 gtk_tx_realize (GtkWidget *widget)
188 {
189   GtkTx *tx;
190   GdkWindowAttr attributes;
191   gint attributes_mask;
192
193   g_return_if_fail (widget != NULL);
194   g_return_if_fail (GTK_IS_TX (widget));
195
196   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
197   tx = GTK_TX (widget);
198
199   attributes.x = widget->allocation.x;
200   attributes.y = widget->allocation.y;
201   attributes.width = widget->allocation.width;
202   attributes.height = widget->allocation.height;
203   attributes.wclass = GDK_INPUT_OUTPUT;
204   attributes.window_type = GDK_WINDOW_CHILD;
205   attributes.event_mask = gtk_widget_get_events (widget) | 
206     GDK_EXPOSURE_MASK;
207   attributes.visual = gtk_widget_get_visual (widget);
208   attributes.colormap = gtk_widget_get_colormap (widget);
209   
210   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
211
212   widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
213
214   widget->style = gtk_style_attach (widget->style, widget->window);
215
216   gdk_window_set_user_data (widget->window, widget);
217
218   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
219 }
220
221 static void 
222 gtk_tx_size_request (GtkWidget *widget, GtkRequisition *requisition)
223 {
224         requisition->width = TX_DEFAULT_SIZE_X;
225         requisition->height = TX_DEFAULT_SIZE_Y;
226 }
227
228 static void
229 gtk_tx_prepare (GtkWidget *widget)
230 {
231         int x, sample;
232         f_prec temp;
233         int16_t *ptr;
234         int16_t value;
235                 
236         GtkTx *tx;
237
238         g_return_if_fail (widget != NULL);
239         g_return_if_fail (GTK_IS_TX (widget));
240         
241         tx=GTK_TX(widget);
242         
243         tx->spp=tx->samples/(widget->allocation.width-DBL_FR_SIZE);
244         tx->yc=widget->allocation.height/2;
245         
246         if (tx->disp_data) free (tx->disp_data);
247         
248         if (tx->data)
249         {
250
251         tx->disp_data =(int16_t*) malloc((widget->allocation.width-DBL_FR_SIZE) * sizeof(int16_t));
252
253         if (tx->disp_data)
254         for (x=0, ptr=tx->disp_data; x< widget->allocation.width-DBL_FR_SIZE; ptr++,x++)
255         {
256                 value=tx->data[x*tx->spp];
257                 for (sample=x*tx->spp; sample<(x+1)*tx->spp; sample++)
258                 {
259                         value=(value+tx->data[sample])/2;
260                 }
261                 temp=((f_prec) value)/32767.0;
262                 tx->disp_data[x]=(int) (temp * (f_prec) (tx->yc-FR_SIZE));
263         }
264         
265         }       
266         else tx->disp_data = NULL;
267 }
268
269 static void
270 gtk_tx_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
271 {
272   GtkTx *tx;
273
274   g_return_if_fail (widget != NULL);
275   g_return_if_fail (GTK_IS_TX (widget));
276   g_return_if_fail (allocation != NULL);
277
278   widget->allocation = *allocation;
279
280   gtk_tx_prepare(widget);
281
282   if (GTK_WIDGET_REALIZED (widget))
283     {
284       tx = GTK_TX (widget);
285
286       gdk_window_move_resize (widget->window,
287                               allocation->x, allocation->y,
288                               allocation->width, allocation->height);
289
290     }
291 }
292
293 static gint gtk_tx_expose (GtkWidget *widget, GdkEventExpose *event)
294 {
295   GtkTx *tx;
296   gint x, pos;
297
298   g_return_val_if_fail (widget != NULL, FALSE);
299   g_return_val_if_fail (GTK_IS_TX (widget), FALSE);
300   g_return_val_if_fail (event != NULL, FALSE);
301
302   if (event->count > 0)
303     return FALSE;
304   
305   tx = GTK_TX (widget);
306
307   gdk_gc_set_foreground(widget->style->fg_gc[widget->state], &tx->bg);
308   
309   gdk_draw_rectangle(widget->window, widget->style->fg_gc[widget->state], 1, 0, 0, widget->allocation.width,widget->allocation.height); 
310
311   gdk_gc_set_foreground(widget->style->fg_gc[widget->state], &tx->fg);
312
313   if (tx->disp_data)
314   {
315         for (x=FR_SIZE, pos=0; x< widget->allocation.width-FR_SIZE; x++, pos++)
316         {
317                 gdk_draw_line (widget->window,
318                      widget->style->fg_gc[widget->state],
319                      x,
320                      tx->yc-tx->disp_data[pos],
321                      x,
322                      tx->yc+tx->disp_data[pos]);
323         }       
324   }
325   else
326   {
327   gdk_draw_line (widget->window,
328                      widget->style->fg_gc[widget->state],
329                      FR_SIZE,
330                      tx->yc,
331                      widget->allocation.width-FR_SIZE,
332                      tx->yc);
333   }
334   
335   gtk_tx_show_frame(tx, tx->do_showframe);
336   return FALSE;
337 }
338
339 static void
340 gtk_tx_update (GtkTx *tx)
341 {
342   g_return_if_fail (tx != NULL);
343   g_return_if_fail (GTK_IS_TX (tx));
344
345   gtk_widget_draw (GTK_WIDGET(tx), NULL);
346 }
347
348 void
349 gtk_tx_prepare_pos_display(GtkTx *tx)
350 {
351         tx->lastpos=-1;
352 }
353
354 void
355 gtk_tx_update_pos_display(GtkTx *tx, int sample, int mute)
356 {
357         GtkWidget *widget;
358         GdkWindow *window;
359         GdkGC *gc;
360 //      GdkColor *fg;
361 //      GdkColor *bg;
362
363         int current_x, x, y, yc, ymax;
364
365         /* Don't update if not required */
366
367         current_x=sample/tx->spp+FR_SIZE;
368         
369         if ((current_x==tx->lastpos) && (tx->lastmute==mute))return;
370         tx->lastmute=mute;
371
372         /* speedup + easyness */
373
374         widget = GTK_WIDGET(tx);
375         window = widget->window;
376         
377         if (current_x>widget->allocation.width-FR_SIZE-2) return;
378         
379         gc = widget->style->fg_gc[widget->state];
380         yc = tx->yc;
381         ymax=widget->allocation.height-FR_SIZE-1;
382         
383         /* Clean up last pos */
384         
385         x=tx->lastpos;
386
387         if (x>=0)
388         {       
389                 gdk_gc_set_foreground(gc, &tx->bg);
390                 gdk_draw_line(window, gc, x, FR_SIZE, x, ymax);  
391         
392                 gdk_gc_set_foreground(gc, &tx->fg);
393                 y=tx->disp_data[x-FR_SIZE];
394                 gdk_draw_line(window, gc, x, yc+y, x, yc-y);            
395         }
396         /* store current_pos */
397                 
398         tx->lastpos=current_x;
399
400         /* draw current_pos */
401
402         x=current_x;
403
404         if (mute) gdk_gc_set_foreground(gc, &tx->mute_bg);
405         else gdk_gc_set_foreground(gc, &tx->busy_bg);
406         
407         gdk_draw_line(window, gc, x, FR_SIZE, x, ymax);  
408 }
409
410 void gtk_tx_cleanup_pos_display(GtkTx *tx)
411 {
412         GtkWidget *widget;
413         GdkWindow *window;
414         GdkGC *gc;
415         int x, y, ymax, yc;
416
417         widget = GTK_WIDGET(tx);
418         window = widget->window;
419         gc = widget->style->fg_gc[widget->state];
420         yc = tx->yc;
421         ymax=widget->allocation.height-FR_SIZE-1;
422                                 
423         x=tx->lastpos;
424
425         if (x>=0)
426         {       
427                 gdk_gc_set_foreground(gc, &tx->bg);
428                 gdk_draw_line(window, gc, x, FR_SIZE, x, ymax);  
429         
430                 gdk_gc_set_foreground(gc, &tx->fg);
431                 y=tx->disp_data[x-FR_SIZE];
432                 gdk_draw_line(window, gc, x, yc+y, x, yc-y);            
433         }
434 }
435
436 void gtk_tx_show_frame(GtkTx *tx, int show)
437 {
438         GtkWidget *widget;
439         GdkWindow *window;
440         GdkGC *gc;
441         int i;
442
443         widget = GTK_WIDGET(tx);
444         window = widget->window;
445         gc = widget->style->fg_gc[widget->state];
446         
447
448         tx->do_showframe=show;
449
450         if (show)
451         {
452                 gdk_gc_set_foreground(gc, &tx->framecol);
453         }
454         else
455         {
456                 gdk_gc_set_foreground(gc, &tx->bg);
457         }
458         
459         for (i=0; i<FR_SIZE; i++)
460         {
461                 gdk_draw_rectangle(window, gc, 0, i, i, widget->allocation.width-(2*i+1), widget->allocation.height-(2*i+1));
462         }
463 }
464
465 #ifdef __cplusplus
466 }
467 #endif /* __cplusplus */