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