Colors customizable - 'w' + 'f' "fix" - Alex
[terminatorX.git] / src / tX_flash.c
1 /*
2     terminatorX - realtime audio scratching software
3     Copyright (C) 1999-2003  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_flash.c
20  
21     Description: This contains the implementation of the tx_flash_flash widget.
22 */    
23
24 #include <math.h>
25
26 #include <gtk/gtkwindow.h>
27 #define IS_TX_FLASH 1
28 #include "tX_flash.h"
29 #include "tX_types.h"
30 #include "tX_global.h"
31 #include <malloc.h>
32
33 #ifndef WIN32
34 #include <unistd.h>
35 #endif
36
37 #ifdef __cplusplus
38 extern "C" {
39 #endif /* __cplusplus */
40
41 #define MAX_VALUE 32767
42 #define RED_BORDER 25000
43 #define TX_FLASH_DEFAULT_SIZE_X 17
44 #define TX_FLASH_DEFAULT_SIZE_Y 30
45 #define DY 5
46 #define DX 5
47 #define DMINIX 2
48 #define S_MINIX 2
49 #define L_MINIX 3
50 #define DLEVEL 3
51 #define MAX_MAX_CYCLES 20;
52
53 /* pre dec */
54 static void gtk_tx_flash_class_init (GtkTxFlashClass *);
55 static void gtk_tx_flash_init (GtkTxFlash *tx_flash);
56 GtkWidget* gtk_tx_flash_new ();
57 static void gtk_tx_flash_destroy (GtkObject *object);
58 static void gtk_tx_flash_realize (GtkWidget *widget);
59 static void gtk_tx_flash_size_request (GtkWidget *widget, GtkRequisition *requisition);
60 static void gtk_tx_flash_size_allocate (GtkWidget *widget, GtkAllocation *allocation);
61 static gint gtk_tx_flash_expose (GtkWidget *widget, GdkEventExpose *event);
62 //static void gtk_tx_flash_prepare (GtkWidget *widget);
63 //static void gtk_tx_flash_set_level(GtkWidget *widget, f_prec new_value);
64
65 /* Local data */
66
67 static GtkWidgetClass *parent_class = NULL;
68
69 guint
70 gtk_tx_flash_get_type ()
71 {
72   static guint tx_flash_type = 0;
73
74   if (!tx_flash_type)
75     {
76       GtkTypeInfo tx_flash_info =
77       {
78         "GtkTxFlash",
79         sizeof (GtkTxFlash),
80         sizeof (GtkTxFlashClass),
81         (GtkClassInitFunc) gtk_tx_flash_class_init,
82         (GtkObjectInitFunc) gtk_tx_flash_init,
83         /* reserved */ NULL,
84         /* reserved */ NULL,
85         /* reserved */ NULL
86       };
87
88       tx_flash_type = gtk_type_unique (gtk_widget_get_type (), &tx_flash_info);
89     }
90
91   return tx_flash_type;
92 }
93
94 static void
95 gtk_tx_flash_class_init (GtkTxFlashClass *gclass)
96 {
97   GtkObjectClass *object_class;
98   GtkWidgetClass *widget_class;
99
100   object_class = (GtkObjectClass*) gclass;
101   widget_class = (GtkWidgetClass*) gclass;
102
103   parent_class = gtk_type_class (gtk_widget_get_type ());
104
105   object_class->destroy = gtk_tx_flash_destroy;
106
107   widget_class->realize = gtk_tx_flash_realize;
108   widget_class->expose_event = gtk_tx_flash_expose;
109   widget_class->size_request = gtk_tx_flash_size_request;
110   widget_class->size_allocate = gtk_tx_flash_size_allocate;
111 //  widget_class->button_press_event = gtk_tx_flash_button_press;
112 //  widget_class->button_release_event = gtk_tx_flash_button_release;
113 //  widget_class->motion_notify_event = gtk_tx_flash_motion_notify;
114 }
115
116 enum {
117         COL_BG,
118         COL_NORM,
119         COL_NORM_HALF,
120         COL_LOUD,
121         COL_LOUD_HALF,
122         NO_COLS
123 };
124
125 /* c=a+(a-b)*x; */
126
127 inline void mk_half(double s, GdkColor *a, GdkColor *b, GdkColor *c)
128 {
129         c->red=a->red-(a->red-b->red)*s;
130         c->green=a->green-(a->green-b->green)*s;
131         c->blue=a->blue-(a->blue-b->blue)*s;
132 }
133
134 void gtk_tx_flash_update_colors(GtkTxFlash *tx)
135 {
136         int i;
137         
138         if (tx->colors_allocated) {
139                 gdk_colormap_free_colors(gtk_widget_get_colormap(GTK_WIDGET(tx)), tx->colors, NO_COLS);
140         }
141         
142         gdk_color_parse(globals.vu_meter_bg, &tx->colors[COL_BG]);
143         gdk_color_parse(globals.vu_meter_loud, &tx->colors[COL_LOUD]);
144         gdk_color_parse(globals.vu_meter_normal, &tx->colors[COL_NORM]);        
145         mk_half(globals.vu_meter_border_intensity, &tx->colors[COL_BG], &tx->colors[COL_LOUD], &tx->colors[COL_LOUD_HALF]);
146         mk_half(globals.vu_meter_border_intensity, &tx->colors[COL_BG], &tx->colors[COL_NORM], &tx->colors[COL_NORM_HALF]);
147
148         for (i=0; i<NO_COLS; i++) {
149                 gdk_colormap_alloc_color(gtk_widget_get_colormap(GTK_WIDGET(tx)), &tx->colors[i], 0, 1);
150         }
151
152         tx->colors_allocated=1;
153 }
154
155 static void
156 gtk_tx_flash_init (GtkTxFlash *tx_flash)
157 {
158         GdkColormap *priv;
159         
160         tx_flash->colors_allocated=0;
161         priv=gdk_colormap_new(gtk_widget_get_visual(GTK_WIDGET(tx_flash)), 6);
162
163         gtk_widget_set_colormap(GTK_WIDGET(tx_flash), priv);
164         gtk_tx_flash_update_colors(tx_flash);
165 }
166
167 GtkWidget*
168 gtk_tx_flash_new ()
169 {
170   GtkTxFlash *tx_flash;
171
172   tx_flash = gtk_type_new (gtk_tx_flash_get_type ());
173
174   return GTK_WIDGET (tx_flash);
175 }
176
177 static void
178 gtk_tx_flash_destroy (GtkObject *object)
179 {
180   g_return_if_fail (object != NULL);
181   g_return_if_fail (GTK_IS_TX_FLASH (object));
182
183   if (GTK_OBJECT_CLASS (parent_class)->destroy)
184     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
185 }
186
187 static void
188 gtk_tx_flash_realize (GtkWidget *widget)
189 {
190   GtkTxFlash *tx_flash;
191   GdkWindowAttr attributes;
192   gint attributes_mask;
193
194   g_return_if_fail (widget != NULL);
195   g_return_if_fail (GTK_IS_TX_FLASH (widget));
196
197   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
198   tx_flash = GTK_TX_FLASH (widget);
199
200   attributes.x = widget->allocation.x;
201   attributes.y = widget->allocation.y;
202   attributes.width = widget->allocation.width;
203   attributes.height = widget->allocation.height;
204   attributes.wclass = GDK_INPUT_OUTPUT;
205   attributes.window_type = GDK_WINDOW_CHILD;
206   attributes.event_mask = gtk_widget_get_events (widget) | 
207     GDK_EXPOSURE_MASK;
208   attributes.visual = gtk_widget_get_visual (widget);
209   attributes.colormap = gtk_widget_get_colormap (widget);
210   
211   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
212
213   widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
214
215   widget->style = gtk_style_attach (widget->style, widget->window);
216
217   gdk_window_set_user_data (widget->window, widget);
218
219   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
220 }
221
222 static void 
223 gtk_tx_flash_size_request (GtkWidget *widget, GtkRequisition *requisition)
224 {
225         requisition->width = TX_FLASH_DEFAULT_SIZE_X;
226         requisition->height = TX_FLASH_DEFAULT_SIZE_Y;
227 }
228
229 static void
230 gtk_tx_flash_prepare (GtkWidget *widget)
231 {
232         GtkTxFlash *tx_flash;
233
234         g_return_if_fail (widget != NULL);
235         g_return_if_fail (GTK_IS_TX_FLASH (widget));
236         
237         tx_flash=GTK_TX_FLASH(widget);
238
239         tx_flash->levels=(widget->allocation.height-(2*DY))/DLEVEL;
240         tx_flash->last_level=0;
241         tx_flash->level_value=MAX_VALUE/(f_prec) tx_flash->levels;
242         tx_flash->red_level=(RED_BORDER/tx_flash->level_value);
243         
244         tx_flash->x1=DMINIX+S_MINIX+2;
245         tx_flash->x2=widget->allocation.width-tx_flash->x1-1;
246         tx_flash->max=0;
247 }
248
249 static void
250 gtk_tx_flash_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
251 {
252   GtkTxFlash *tx_flash;
253
254   g_return_if_fail (widget != NULL);
255   g_return_if_fail (GTK_IS_TX_FLASH (widget));
256   g_return_if_fail (allocation != NULL);
257
258   widget->allocation = *allocation;
259
260   gtk_tx_flash_prepare(widget);
261
262   if (GTK_WIDGET_REALIZED (widget))
263     {
264       tx_flash = GTK_TX_FLASH (widget);
265
266       gdk_window_move_resize (widget->window,
267                               allocation->x, allocation->y,
268                               allocation->width, allocation->height);
269
270     }
271 }
272
273 static void gtk_tx_flash_paint_yourself(GtkWidget *widget)
274 {
275   GtkTxFlash *tx_flash;
276   gint i, x11, x12,x21, x22, y;
277   int long_level;
278
279   tx_flash = GTK_TX_FLASH (widget);
280
281   gdk_gc_set_foreground(widget->style->fg_gc[widget->state], &tx_flash->colors[COL_BG]);
282   
283   gdk_draw_rectangle(widget->window, widget->style->fg_gc[widget->state], 1, 0, 0, widget->allocation.width,widget->allocation.height); 
284
285   gdk_gc_set_foreground(widget->style->fg_gc[widget->state], &tx_flash->colors[COL_NORM_HALF]);
286
287   x12=DMINIX+S_MINIX;
288   x21=widget->allocation.width-1-x12;
289
290   for (i=0, y=widget->allocation.height-DY; i<=tx_flash->levels; y-=DLEVEL, i++)
291   {
292         if (i==0)
293         {
294                 long_level=1;
295         }
296         else if (i==tx_flash->red_level-1)
297         {
298                 long_level=1;
299         }
300         else if (i==tx_flash->red_level)
301         {
302                 long_level=1;
303                 gdk_gc_set_foreground(widget->style->fg_gc[widget->state], &tx_flash->colors[COL_LOUD_HALF]);
304         }
305         else if (i==tx_flash->levels)
306         {
307                 long_level=1;
308         }
309         else long_level=0;
310         
311         if (long_level)
312         {
313                 x11=x12-L_MINIX;
314                 x22=x21+L_MINIX;
315         }
316         else
317         {
318                 x11=x12-S_MINIX;
319                 x22=x21+S_MINIX;                
320         }
321         
322         gdk_draw_line(widget->window, widget->style->fg_gc[widget->state], x11, y, x12, y);
323         gdk_draw_line(widget->window, widget->style->fg_gc[widget->state], x21, y, x22, y);
324   }
325 }
326
327 static gint gtk_tx_flash_expose (GtkWidget *widget, GdkEventExpose *event)
328 {
329
330   g_return_val_if_fail (widget != NULL, FALSE);
331   g_return_val_if_fail (GTK_IS_TX_FLASH (widget), FALSE);
332   g_return_val_if_fail (event != NULL, FALSE);
333
334   if (event->count > 0)
335     return FALSE;
336
337   gtk_tx_flash_prepare(widget);
338   gtk_tx_flash_paint_yourself(widget);  
339
340   return FALSE;
341
342
343 void
344 gtk_tx_flash_set_level(GtkWidget *widget, f_prec new_value)
345 {
346   GtkTxFlash *tx_flash;
347   gint i, y;
348   int new_level;
349   int red=0;
350
351   g_return_if_fail (widget != NULL);
352   g_return_if_fail (GTK_IS_TX_FLASH (widget));
353
354   tx_flash = GTK_TX_FLASH (widget);
355
356   new_level=(int) (new_value/tx_flash->level_value);
357   
358   if (new_level>tx_flash->levels) new_level=tx_flash->levels;
359   
360 //  printf ("%f, %i, %i\n", tx_flash->level_value,new_level, tx_flash->last_level);
361   
362
363   if (new_level>tx_flash->max)
364   {
365         tx_flash->max=new_level;
366         tx_flash->max_cycles=MAX_MAX_CYCLES;
367   }
368   else
369   {
370         tx_flash->max_cycles--;
371   }
372   
373   if (tx_flash->max_cycles <= 0)
374   {     
375         y=widget->allocation.height-(DY+(tx_flash->max)*DLEVEL);
376         gdk_gc_set_foreground(widget->style->fg_gc[widget->state], &tx_flash->colors[COL_BG]);
377         gdk_draw_line(widget->window, widget->style->fg_gc[widget->state], tx_flash->x1, y, tx_flash->x2, y);
378
379         if (tx_flash->max>0)
380         {
381                 tx_flash->max--;
382                 y+=DLEVEL;
383                 if (tx_flash->max>tx_flash->red_level)
384                 {
385                         gdk_gc_set_foreground(widget->style->fg_gc[widget->state], &tx_flash->colors[COL_LOUD]);
386                 }
387                 else
388                 {
389                         gdk_gc_set_foreground(widget->style->fg_gc[widget->state], &tx_flash->colors[COL_NORM]);
390                 }
391                 gdk_draw_line(widget->window, widget->style->fg_gc[widget->state], tx_flash->x1, y, tx_flash->x2, y);   
392         }
393   }
394
395   if (new_level==tx_flash->last_level) return;
396
397   if (new_level<tx_flash->last_level) // make it look more realistic
398   {
399         new_level=tx_flash->last_level*globals.flash_response;
400   }
401   
402   if (new_level>tx_flash->last_level)
403   {
404           gdk_gc_set_foreground(widget->style->fg_gc[widget->state], &tx_flash->colors[COL_NORM]);
405   
406           for (i=tx_flash->last_level, y=widget->allocation.height-(DY+tx_flash->last_level*DLEVEL); i<=new_level; y-=DLEVEL, i++)
407           {
408                 if (!red)
409                 {
410                         if (i>=tx_flash->red_level)
411                         {
412                                 gdk_gc_set_foreground(widget->style->fg_gc[widget->state], &tx_flash->colors[COL_LOUD]);
413                                 red=1;
414                         }
415                 }
416                 gdk_draw_line(widget->window, widget->style->fg_gc[widget->state], tx_flash->x1, y, tx_flash->x2, y);
417           }
418   }
419   else
420   {
421           gdk_gc_set_foreground(widget->style->fg_gc[widget->state], &tx_flash->colors[COL_BG]);
422
423           if (tx_flash->last_level==tx_flash->max)
424           {
425                 i=tx_flash->last_level-1;
426           }
427           else
428           {
429                 i=tx_flash->last_level;
430           }
431
432           for (y=widget->allocation.height-(DY+i*DLEVEL); i>new_level; y+=DLEVEL, i--)
433           {
434                 gdk_draw_line(widget->window, widget->style->fg_gc[widget->state], tx_flash->x1, y, tx_flash->x2, y);
435           }
436   }
437   tx_flash->last_level=new_level;
438 }
439
440 void
441 gtk_tx_flash_clear (GtkWidget *widget)
442 {
443         GtkTxFlash *tx_flash;
444
445         tx_flash = GTK_TX_FLASH (widget);
446         
447         tx_flash->max=0;
448         tx_flash->max_cycles=0;
449         tx_flash->last_level=0;
450         
451         gtk_tx_flash_paint_yourself(widget);
452 }
453
454 #ifdef __cplusplus
455 }
456 #endif /* __cplusplus */