37
37
namespace ClutterFlow
39
public delegate void ActorEventHandler<T>(T actor, EventArgs e) where T : ClutterFlowBaseActor;
40
public delegate void ActorEventHandler<T>(T actor, EventArgs e) where T : ClutterFlowBaseActor;
42
public class CoverManager : Clutter.Group {
41
public class CoverManager : Clutter.Group {
45
public event ActorEventHandler<ClutterFlowBaseActor> ActorActivated;
46
internal void InvokeActorActivated (ClutterFlowBaseActor cover)
48
if (ActorActivated!=null) ActorActivated (cover, EventArgs.Empty);
51
public event ActorEventHandler<ClutterFlowBaseActor> NewCurrentCover;
52
protected void InvokeNewCurrentCover (ClutterFlowBaseActor cover)
54
if (NewCurrentCover!=null) NewCurrentCover(cover, EventArgs.Empty);
57
public event EventHandler<EventArgs> CoversChanged;
58
protected void InvokeCoversChanged ()
60
if (CoversChanged!=null) CoversChanged(this, EventArgs.Empty);
63
public event EventHandler<EventArgs> TargetIndexChanged;
64
protected void InvokeTargetIndexChanged ()
66
if (TargetIndexChanged!=null) TargetIndexChanged(this, EventArgs.Empty);
69
public event EventHandler TextureSizeChanged;
70
protected void InvokeTextureSizeChanged ()
72
//TODO use a timeout here, if the function is called mutliple times shortly after another, we don't get endless recalculation
73
if (TextureSizeChanged!=null) TextureSizeChanged (this, EventArgs.Empty);
44
public event ActorEventHandler<ClutterFlowBaseActor> ActorActivated;
45
internal void InvokeActorActivated (ClutterFlowBaseActor cover)
47
var handler = ActorActivated;
48
if (handler != null) {
49
handler (cover, EventArgs.Empty);
53
public event ActorEventHandler<ClutterFlowBaseActor> NewCurrentCover;
54
protected void InvokeNewCurrentCover (ClutterFlowBaseActor cover)
56
var handler = NewCurrentCover;
57
if (handler != null) {
58
handler (cover, EventArgs.Empty);
62
public event EventHandler<EventArgs> CoversChanged;
63
protected void InvokeCoversChanged ()
65
var handler = CoversChanged;
66
if (handler != null) {
67
handler (this, EventArgs.Empty);
71
public event EventHandler<EventArgs> TargetIndexChanged;
72
protected void InvokeTargetIndexChanged ()
74
var handler = TargetIndexChanged;
75
if (handler != null) {
76
handler (this, EventArgs.Empty);
76
80
public event EventHandler<EventArgs> VisibleCoversChanged;
77
81
protected void InvokeVisibleCoversChanged ()
79
if (VisibleCoversChanged!=null) VisibleCoversChanged(this, EventArgs.Empty);
82
public event EventHandler<EventArgs> LetterLookupChanged;
83
protected void InvokeLetterLookupChanged ()
85
if (LetterLookupChanged!=null) LetterLookupChanged(this, EventArgs.Empty);;
83
var handler = VisibleCoversChanged;
84
if (handler != null) {
85
handler (this, EventArgs.Empty);
89
public event EventHandler<EventArgs> LetterLookupChanged;
90
protected void InvokeLetterLookupChanged ()
92
var handler = LetterLookupChanged;
93
if (handler != null) {
94
handler (this, EventArgs.Empty);
91
protected ClutterFlowTimeline timeline;
92
public ClutterFlowTimeline Timeline {
101
private static TextureHolder texture_holder;
102
public static TextureHolder TextureHolder {
103
get { return texture_holder; }
106
protected ClutterFlowTimeline timeline;
107
public ClutterFlowTimeline Timeline {
109
if (timeline == null) {
95
110
timeline = new ClutterFlowTimeline(this);
96
111
timeline.TargetMarkerReached += HandleTargetMarkerReached;
102
protected IActorLoader actorLoader; //Loads the actors (detaches ClutterFlow from Banshee related dependencies)
103
public IActorLoader ActorLoader {
104
get { return actorLoader; }
105
internal set { actorLoader = value; }
108
public Dictionary<AlphabetChars, int> letter_lookup;
109
public Dictionary<AlphabetChars, int> LetterLookup {
110
get { return letter_lookup; }
113
public void ResetLetterLookup () {
114
letter_lookup = new Dictionary<AlphabetChars, int>();
115
foreach (AlphabetChars key in Enum.GetValues(typeof(AlphabetChars)))
116
letter_lookup.Add(key, -1);
118
public void UpdateLetterLookup (ClutterFlowBaseActor actor) {
119
string label = actor.SortLabel.ToUpper ().Normalize (System.Text.NormalizationForm.FormKD);
120
char letter = label.Length>0 ? char.Parse(label.Substring (0,1)) : '?';
117
protected IActorLoader actor_loader; //Loads the actors (detaches ClutterFlow from Banshee related dependencies)
118
public IActorLoader ActorLoader {
119
get { return actor_loader; }
122
public Dictionary<AlphabetChars, int> letter_lookup;
123
public Dictionary<AlphabetChars, int> LetterLookup {
124
get { return letter_lookup; }
127
public void ResetLetterLookup () {
128
letter_lookup = new Dictionary<AlphabetChars, int>();
129
foreach (AlphabetChars key in Enum.GetValues(typeof(AlphabetChars)))
130
letter_lookup.Add(key, -1);
132
public void UpdateLetterLookup (ClutterFlowBaseActor actor) {
133
string label = actor.SortLabel.ToUpper ().Normalize (System.Text.NormalizationForm.FormKD);
134
char letter = label.Length>0 ? char.Parse(label.Substring (0,1)) : '?';
121
135
AlphabetChars key;
122
if (char.IsLetter(letter))
123
key = (AlphabetChars) letter;
125
key = AlphabetChars.unknown;
126
if (letter_lookup.ContainsKey (key) && letter_lookup[key] == -1)
127
letter_lookup[key] = actor.Index;
130
protected FlowBehaviour behaviour;
131
public FlowBehaviour Behaviour {
132
get { return behaviour; }
136
if (char.IsLetter(letter))
137
key = (AlphabetChars) letter;
139
key = AlphabetChars.unknown;
140
if (letter_lookup.ContainsKey (key) && letter_lookup[key] == -1)
141
letter_lookup[key] = actor.Index;
144
protected FlowBehaviour behaviour;
145
public FlowBehaviour Behaviour {
146
get { return behaviour; }
136
150
#region Cover-related fields
138
protected int textureSize = 128;
139
public int TextureSize {
140
get { return textureSize; }
142
if (textureSize!=value) {
144
InvokeTextureSizeChanged ();
149
protected int visibleCovers = 17;
150
public int VisibleCovers {
151
get { return visibleCovers; }
153
if (value!=visibleCovers) {
154
visibleCovers = value;
152
protected int texture_size;
153
public int TextureSize {
154
get { return texture_size; }
155
set { texture_size = value; }
158
protected int visibleCovers = 17;
159
public int VisibleCovers {
160
get { return visibleCovers; }
162
if (value != visibleCovers) {
163
visibleCovers = value;
155
164
InvokeVisibleCoversChanged ();
159
public int HalfVisCovers {
160
get { return (int) ((visibleCovers-1) * 0.5); }
168
public int HalfVisCovers {
169
get { return (int) ((visibleCovers-1) * 0.5); }
164
173
#region Animation duration limits
165
protected static uint maxAnimationSpan = 250; //maximal length of a single step in the animations in ms
166
public static uint MaxAnimationSpan {
167
get { return maxAnimationSpan; }
170
protected static uint minAnimationSpan = 10; //minimal length of a single step in the animations in ms
171
public static uint MinAnimationSpan {
172
get { return minAnimationSpan; }
175
protected static uint doubleClickTime = 200;
176
public static uint DoubleClickTime {
177
get { return doubleClickTime; }
178
set { doubleClickTime = value; }
174
protected static uint maxAnimationSpan = 250; //maximal length of a single step in the animations in ms
175
public static uint MaxAnimationSpan {
176
get { return maxAnimationSpan; }
179
protected static uint minAnimationSpan = 10; //minimal length of a single step in the animations in ms
180
public static uint MinAnimationSpan {
181
get { return minAnimationSpan; }
184
protected static uint doubleClickTime = 200;
185
public static uint DoubleClickTime {
186
get { return doubleClickTime; }
187
set { doubleClickTime = value; }
182
191
#region Target/Current index handling
183
private int target_index = 0; // curent targetted cover index
184
public int TargetIndex {
185
get { return target_index; }
187
if (value >= TotalCovers) value = TotalCovers-1;
188
if (value < 0) value = 0;
189
if (value!=target_index) {
192
private int target_index = 0; // curent targetted cover index
193
public int TargetIndex {
194
get { return target_index; }
196
if (value >= TotalCovers) {
197
value = TotalCovers - 1;
202
if (value != target_index) {
190
203
//Console.WriteLine ("TargetIndex_set to " + value);
191
204
target_index = value;
192
current_cover = null; //to prevent clicks to load the old centered cover!
205
// To prevent clicks to load the old centered cover!
206
current_cover = null;
193
207
InvokeTargetIndexChanged();
198
public ClutterFlowBaseActor TargetActor {
200
if (covers.Count > TargetIndex)
201
return covers[TargetIndex];
212
public ClutterFlowBaseActor TargetActor {
214
if (covers.Count > TargetIndex)
215
return covers[TargetIndex];
207
221
protected ClutterFlowFixedActor empty_actor;
208
222
public ClutterFlowFixedActor EmptyActor {
210
if (empty_actor==null)
211
empty_actor = new ClutterFlowFixedActor (this);
224
if (empty_actor == null)
225
empty_actor = new ClutterFlowFixedActor ((uint)behaviour.CoverWidth);
212
226
return empty_actor;
216
internal List<ClutterFlowBaseActor> covers; // list with cover actors
217
public int TotalCovers { // number of covers or zero if null
230
// list with cover actors
231
private List<ClutterFlowBaseActor> covers;
232
public List<ClutterFlowBaseActor> Covers {
233
get { return covers; }
236
public int TotalCovers {
218
237
get { return (covers != null) ? covers.Count : 0; }
221
private ClutterFlowBaseActor current_cover = null; // currently centered cover
240
// currently centered cover
241
private ClutterFlowBaseActor current_cover = null;
222
242
public ClutterFlowBaseActor CurrentCover {
223
243
get { return current_cover; }
225
if (value!=current_cover) {
245
if (value != current_cover) {
226
246
current_cover = value;
227
247
InvokeNewCurrentCover (current_cover);
269
public void UpdateBehaviour ()
271
if (behaviour!=null && Stage!=null) {
272
behaviour.Height = Stage.Height;
273
behaviour.Width = Stage.Width;
274
//Console.WriteLine ("behaviour.CoverWidth = " + behaviour.CoverWidth + "behaviour.Height = " + behaviour.Height + " behaviour.Width = " + behaviour.Width);
291
public void UpdateBehaviour ()
293
if (behaviour != null && Stage != null) {
294
behaviour.Height = Stage.Height;
295
behaviour.Width = Stage.Width;
296
//Console.WriteLine ("behaviour.CoverWidth = " + behaviour.CoverWidth + "behaviour.Height = " + behaviour.Height + " behaviour.Width = " + behaviour.Width);
278
void HandleTargetMarkerReached(object sender, TargetReachedEventArgs args)
280
if (args.Target==TargetIndex) {
281
if (covers.Count > args.Target)
300
void HandleTargetMarkerReached(object sender, TargetReachedEventArgs args)
302
if (args.Target==TargetIndex) {
303
if (covers.Count > args.Target) {
282
304
CurrentCover = covers[(int) args.Target];
284
306
CurrentCover = null;
288
private uint reload_timeout = 0;
289
internal void ReloadCovers ()
291
if (reload_timeout > 0)
292
GLib.Source.Remove(reload_timeout);
293
reload_timeout = GLib.Timeout.Add (MaxAnimationSpan, new GLib.TimeoutHandler (reload_covers));
296
private bool reload_covers ()
298
if (Timeline!=null) Timeline.Pause ();
300
if (covers!=null && covers.Count!=0) {
301
Console.WriteLine("Reloading Covers");
303
int old_target_index = CurrentCover!=null ? covers.IndexOf (CurrentCover) : 0; // the old current index
304
int new_target_index = 0; // the newly calculated index
305
bool keep_current = false; // wether or not to keep the current cover centered
307
List<ClutterFlowBaseActor> old_covers = new List<ClutterFlowBaseActor>(SafeGetRange(covers, old_target_index - HalfVisCovers - 1, visibleCovers + 2));
308
foreach (ClutterFlowBaseActor actor in covers) {
309
if (actor.Data.ContainsKey ("isOldCover")) actor.Data.Remove ("isOldCover");
311
private uint reload_timeout = 0;
312
public void ReloadCovers ()
314
if (reload_timeout > 0) {
315
GLib.Source.Remove(reload_timeout);
317
reload_timeout = GLib.Timeout.Add (MaxAnimationSpan, new GLib.TimeoutHandler (reload_covers));
320
private bool reload_covers ()
322
if (Timeline != null) {
327
if (covers != null && covers.Count != 0) {
328
Console.WriteLine("ClutterFlow - Reloading Covers");
330
// the old current index
331
int old_target_index = CurrentCover!=null ? covers.IndexOf (CurrentCover) : 0;
332
// the newly calculated index
333
int new_target_index = 0;
334
// whether or not to keep the current cover centered
335
bool keep_current = false;
337
List<ClutterFlowBaseActor> old_covers = new List<ClutterFlowBaseActor> (
338
SafeGetRange (covers, old_target_index - HalfVisCovers - 1, visibleCovers + 2));
339
foreach (ClutterFlowBaseActor actor in covers) {
340
if (actor.Data.ContainsKey ("isOldCover")) {
341
actor.Data.Remove ("isOldCover");
310
343
actor.Index = -1;
311
if (old_covers.Contains (actor))
344
if (old_covers.Contains (actor)) {
312
345
actor.Data.Add ("isOldCover", true);
315
ResetLetterLookup ();
349
ResetLetterLookup ();
316
350
List<ClutterFlowBaseActor> persistent_covers = new List<ClutterFlowBaseActor>();
318
covers = new List<ClutterFlowBaseActor>(actorLoader.GetActors (delegate (ClutterFlowBaseActor actor) {
319
if (actor.Data.ContainsKey ("isOldCover"))
352
covers = actor_loader.GetActors (this);
353
covers.ForEach (delegate (ClutterFlowBaseActor actor) {
354
if (actor.Data.ContainsKey ("isOldCover")) {
320
355
persistent_covers.Add (actor);
321
if (CurrentCover==actor) keep_current = true;
323
UpdateLetterLookup (actor);
325
InvokeLetterLookupChanged ();
327
if (covers.Count==0) {
357
if (CurrentCover==actor) {
361
UpdateLetterLookup (actor);
363
InvokeLetterLookupChanged ();
365
if (covers.Count == 0) {
328
366
InstallEmptyActor ();
329
if (old_covers.Contains(EmptyActor)) {
367
if (old_covers.Contains (EmptyActor)) {
336
//recalculate timeline progression and the target index
337
if (covers.Count > 1) {
339
new_target_index = CurrentCover.Index;
341
if (persistent_covers.Count==0)
374
//recalculate timeline progression and the target index
375
if (covers.Count > 1) {
377
new_target_index = CurrentCover.Index;
379
if (persistent_covers.Count==0) {
342
380
new_target_index = (int) Math.Round(Timeline.Progress * (covers.Count-1));
343
else if (persistent_covers.Count==1)
381
} else if (persistent_covers.Count==1) {
344
382
new_target_index = persistent_covers[0].Index;
346
384
new_target_index = persistent_covers[(int) (((float) persistent_covers.Count * 0.5f) - 1.0f)].Index;
349
388
TargetIndex = new_target_index;
350
389
Timeline.JumpToTarget ();
352
391
//Console.WriteLine ("Timeline progress set to " + Timeline.Progress + " Timeline.RelativeTarget is " + Timeline.RelativeTarget);
354
393
List<ClutterFlowBaseActor> truly_pers = new List<ClutterFlowBaseActor> ();
355
List<ClutterFlowBaseActor> new_covers = new List<ClutterFlowBaseActor>(SafeGetRange(covers, new_target_index - HalfVisCovers - 1, visibleCovers + 2));
394
List<ClutterFlowBaseActor> new_covers = new List<ClutterFlowBaseActor>(SafeGetRange(covers, new_target_index - HalfVisCovers - 1, visibleCovers + 2));
356
395
foreach (ClutterFlowBaseActor actor in persistent_covers) {
358
if (actor.Data.ContainsKey ("isOldCover"))
397
if (actor.Data.ContainsKey ("isOldCover")) {
359
398
actor.Data.Remove ("isOldCover");
360
400
if (new_covers.Contains (actor)) {
361
401
truly_pers.Add (actor);
362
402
new_covers.Remove (actor);