1 /*  dvdisaster: Additional error correction for optical media.
2  *  Copyright (C) 2004-2015 Carsten Gnoerlich.
3  *
4  *  Email: carsten@dvdisaster.org  -or-  cgnoerlich@fsfe.org
5  *  Project homepage: http://www.dvdisaster.org
6  *
7  *  This file is part of dvdisaster.
8  *
9  *  dvdisaster is free software: you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation, either version 3 of the License, or
12  *  (at your option) any later version.
13  *
14  *  dvdisaster is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with dvdisaster. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #include "dvdisaster.h"
24 
25 /***
26  *** Archimede did not publish his source,
27  *** so we have to write our own routines ;-)
28  */
29 
30 /*
31  * Allocate and fill in the spiral data structure
32  */
33 
CreateSpiral(GdkColor * outline,GdkColor * fill,int start_radius,int segment_size,int n_segments)34 Spiral* CreateSpiral(GdkColor *outline, GdkColor *fill,
35 		     int start_radius, int segment_size, int n_segments)
36 {  Spiral *spiral = g_malloc0(sizeof(Spiral));
37    double a = 0.0;
38    double scale_o = start_radius + segment_size;
39    double ring_expand;
40    int i;
41 
42    spiral->startRadius  = start_radius;
43    spiral->segmentSize  = segment_size;
44    spiral->segmentCount = spiral->segmentClipping = n_segments;
45    spiral->segmentPos   = g_malloc(n_segments * sizeof(double));
46    spiral->segmentColor = g_malloc(n_segments * sizeof(GdkColor*));
47    spiral->outline      = outline;
48    spiral->cursorPos    = -1;
49 
50    for(i=0; i<n_segments; i++)
51    {
52      spiral->segmentPos[i] = a;
53      spiral->segmentColor[i] = fill;
54 
55      ring_expand =  ((double)segment_size * a) / (2.0*M_PI);
56      a += atan((double)segment_size / scale_o);
57      scale_o = (double)start_radius + ring_expand + (double)segment_size;
58    }
59 
60    spiral->diameter = 2.0 * scale_o;
61 
62    return spiral;
63 }
64 
SetSpiralWidget(Spiral * spiral,GtkWidget * widget)65 void SetSpiralWidget(Spiral *spiral, GtkWidget *widget)
66 {  GtkAllocation *al = &widget->allocation;
67 
68    if(!spiral->drawable)
69    {  spiral->drawable     = widget->window;
70       spiral->mx           = al->width/2;
71       spiral->my           = al->height/2;
72    }
73 }
74 
FreeSpiral(Spiral * spiral)75 void FreeSpiral(Spiral *spiral)
76 {  g_free(spiral->segmentPos);
77    g_free(spiral->segmentColor);
78    g_free(spiral);
79 }
80 
81 /*
82  * Fill spiral segments with given color
83  */
84 
FillSpiral(Spiral * spiral,GdkColor * color)85 void FillSpiral(Spiral *spiral, GdkColor *color)
86 {  int i;
87 
88    if(spiral)
89      for(i=0; i<spiral->segmentCount; i++)
90        spiral->segmentColor[i] = color;
91 }
92 
93 /*
94  * Draw the whole spiral
95  */
96 
DrawSpiral(Spiral * spiral)97 void DrawSpiral(Spiral *spiral)
98 {  double a;
99    int xi0,yi0,xo0,yo0;
100    double scale_i,scale_o;
101    int i;
102    GdkPoint points[4];
103 
104    if(!spiral->drawable) return;
105 
106    scale_i = spiral->startRadius;
107    scale_o = spiral->startRadius + spiral->segmentSize;
108    xi0 = spiral->mx + spiral->startRadius;
109    yi0 = yo0 = spiral->my;
110    xo0 = xi0 + spiral->segmentSize;
111 
112    for(a=0.0, i=0; i<spiral->segmentClipping; i++)
113    {  int xi1,yi1,xo1,yo1;
114       double ring_expand = ((double)spiral->segmentSize * a) / (2.0*M_PI);
115 
116       a += atan((double)spiral->segmentSize / scale_o);
117 
118       scale_i = (double)spiral->startRadius + ring_expand;
119       scale_o = scale_i + spiral->segmentSize;
120       xi1 = spiral->mx + scale_i*cos(a);
121       yi1 = spiral->my + scale_i*sin(a);
122       xo1 = spiral->mx + scale_o*cos(a);
123       yo1 = spiral->my + scale_o*sin(a);
124 
125       points[0].x = xi0; points[0].y = yi0;
126       points[1].x = xo0; points[1].y = yo0;
127       points[2].x = xo1; points[2].y = yo1;
128       points[3].x = xi1; points[3].y = yi1;
129 
130       gdk_gc_set_rgb_fg_color(Closure->drawGC, spiral->segmentColor[i]);
131       gdk_draw_polygon(spiral->drawable, Closure->drawGC, TRUE, points, 4);
132       gdk_gc_set_rgb_fg_color(Closure->drawGC, spiral->outline);
133       gdk_draw_polygon(spiral->drawable, Closure->drawGC, FALSE, points, 4);
134 
135       xi0 = xi1; yi0 = yi1;
136       xo0 = xo1; yo0 = yo1;
137    }
138 }
139 
140 /*
141  * Draw just one segment of the spiral
142  */
143 
DrawSpiralSegment(Spiral * spiral,GdkColor * color,int segment)144 void DrawSpiralSegment(Spiral *spiral, GdkColor *color, int segment)
145 {  double a;
146    double scale_i,scale_o,ring_expand;
147    GdkPoint points[4];
148 
149    if(segment<0 || segment>=spiral->segmentClipping)
150      return;
151 
152    a = spiral->segmentPos[segment];
153 
154    ring_expand = ((double)spiral->segmentSize * a) / (2.0*M_PI);
155 
156    scale_i = (double)spiral->startRadius + ring_expand;
157    scale_o = scale_i + spiral->segmentSize;
158    points[0].x = spiral->mx + scale_i*cos(a);
159    points[0].y = spiral->my + scale_i*sin(a);
160    points[1].x = spiral->mx + scale_o*cos(a);
161    points[1].y = spiral->my + scale_o*sin(a);
162 
163    a += atan((double)spiral->segmentSize / scale_o);
164 
165    ring_expand = ((double)spiral->segmentSize * a) / (2.0*M_PI);
166 
167    scale_i = (double)spiral->startRadius + ring_expand;
168    scale_o = scale_i + spiral->segmentSize;
169    points[3].x = spiral->mx + scale_i*cos(a);
170    points[3].y = spiral->my + scale_i*sin(a);
171    points[2].x = spiral->mx + scale_o*cos(a);
172    points[2].y = spiral->my + scale_o*sin(a);
173 
174    spiral->segmentColor[segment] = color;
175    gdk_gc_set_rgb_fg_color(Closure->drawGC, color);
176    gdk_draw_polygon(spiral->drawable, Closure->drawGC, TRUE, points, 4);
177    gdk_gc_set_rgb_fg_color(Closure->drawGC, spiral->outline);
178    gdk_draw_polygon(spiral->drawable, Closure->drawGC, FALSE, points, 4);
179 }
180 
181 /*
182  * Draw a label above or below the spiral
183  */
184 
DrawSpiralLabel(Spiral * spiral,PangoLayout * layout,char * text,GdkColor * color,int x,int line)185 void DrawSpiralLabel(Spiral *spiral, PangoLayout *layout,
186 		     char *text, GdkColor *color, int x, int line)
187 {  GdkDrawable *d = spiral->drawable;
188    int w,h,y;
189 
190    SetText(layout, text, &w, &h);
191    if(line > 0) y = spiral->my + spiral->diameter / 2 + 20 + (line-1) * (10 + h);
192    else         y = spiral->my - spiral->diameter / 2 - 20 - h + (line+1) * (10 + h);
193    gdk_gc_set_rgb_fg_color(Closure->drawGC, color);
194    gdk_draw_rectangle(d, Closure->drawGC, TRUE, x, y+(h-6)/2, 6, 6);
195    gdk_gc_set_rgb_fg_color(Closure->drawGC, Closure->grid);
196    gdk_draw_rectangle(d, Closure->drawGC, FALSE, x, y+(h-6)/2, 6, 6);
197    gdk_gc_set_rgb_fg_color(Closure->drawGC, Closure->foreground);
198    gdk_draw_layout(d, Closure->drawGC, x+10, y, layout);
199 }
200 
201 /*
202  * Move the cursor (a highlighted segment) to a new position.
203  * Moving to segment -1 means to disable the cursor.
204  */
205 
MoveSpiralCursor(Spiral * spiral,int to_segment)206 void MoveSpiralCursor(Spiral *spiral, int to_segment)
207 {
208   if(to_segment == spiral->cursorPos)
209     return;
210 
211   if(to_segment > spiral->segmentClipping)
212     return;
213 
214   /* Erase old cursor */
215 
216   if(spiral->cursorPos >= 0)
217     DrawSpiralSegment(spiral, spiral->colorUnderCursor, spiral->cursorPos);
218 
219   /* Moving to -1 means cursor off */
220 
221   spiral->cursorPos = to_segment;
222 
223   if(to_segment < 0)
224     return;
225 
226   if(to_segment > spiral->segmentCount-1)
227   {  spiral->cursorPos = -1;
228      return;
229   }
230 
231   /* Draw cursor at new place */
232 
233   spiral->colorUnderCursor = spiral->segmentColor[to_segment];
234   DrawSpiralSegment(spiral, Closure->blueSector, to_segment);
235 }
236 
237 /*
238  * Wrapper for moving the spiral cursor from non-GUI thread
239  */
240 
241 typedef struct _cursor_info
242 {  Spiral *spiral;
243    int segment;
244 } cursor_info;
245 
cursor_idle_func(gpointer data)246 static gboolean cursor_idle_func(gpointer data)
247 {  cursor_info *ci = (cursor_info*)data;
248 
249    MoveSpiralCursor(ci->spiral, ci->segment);
250    g_free(ci);
251 
252    return FALSE;
253 }
254 
ChangeSpiralCursor(Spiral * spiral,int segment)255 void ChangeSpiralCursor(Spiral *spiral, int segment)
256 {
257    if(segment != spiral->cursorPos)
258    {  cursor_info *ci = g_malloc(sizeof(cursor_info));
259 
260       ci->spiral  = spiral;
261       ci->segment = segment;
262       g_idle_add(cursor_idle_func, ci);
263    }
264 }
265