48
48
namespace Banshee.ClutterFlow
51
public class ClutterFlowView : Clutter.Embed
51
public class ClutterFlowView : Clutter.Embed
54
54
#region Active/Current Album Related
55
public event EventHandler UpdatedAlbum;
57
private AlbumInfo activeAlbum = null;
58
public AlbumInfo ActiveAlbum {
59
get { return activeAlbum; }
60
protected set { activeAlbum = value; }
62
private int activeIndex = -1;
63
public int ActiveIndex {
64
get { return activeIndex; }
65
protected set { activeIndex = value; }
67
public int ActiveModelIndex {
69
int ret = AlbumLoader.ConvertIndexToModelIndex (ActiveIndex);
70
Hyena.Log.DebugFormat ("ActiveModelIndex_get will return {0}", ret);
74
public AlbumInfo CurrentAlbum {
75
get { return albumLoader.CurrentAlbum; }
77
public int CurrentIndex {
78
get { return albumLoader.CurrentIndex; }
80
public int CurrentModelIndex {
81
get { return AlbumLoader.ConvertIndexToModelIndex (CurrentIndex); }
55
public event EventHandler UpdatedAlbum;
57
private AlbumInfo activeAlbum = null;
58
public AlbumInfo ActiveAlbum {
59
get { return activeAlbum; }
60
protected set { activeAlbum = value; }
62
private int activeIndex = -1;
63
public int ActiveIndex {
64
get { return activeIndex; }
65
protected set { activeIndex = value; }
67
public int ActiveModelIndex {
69
int ret = AlbumLoader.ConvertIndexToModelIndex (ActiveIndex);
70
Hyena.Log.DebugFormat ("ActiveModelIndex_get will return {0}", ret);
75
public AlbumInfo CurrentAlbum {
77
var album_actor = cover_manager.CurrentCover as ClutterFlowAlbum;
78
if (album_actor != null) {
79
return album_actor.Album;
86
public int CurrentIndex {
88
var album_actor = cover_manager.CurrentCover as ClutterFlowAlbum;
89
if (album_actor != null) {
90
return album_actor.Index;
97
public int CurrentModelIndex {
98
get { return AlbumLoader.ConvertIndexToModelIndex (CurrentIndex); }
86
private AlbumLoader albumLoader;
87
public AlbumLoader AlbumLoader {
88
get { return albumLoader; }
90
private CoverManager coverManager;
91
public CoverManager CoverManager {
92
get { return coverManager; }
103
private AlbumLoader album_loader;
104
public AlbumLoader AlbumLoader {
105
get { return album_loader; }
107
private CoverManager cover_manager;
108
public CoverManager CoverManager {
109
get { return cover_manager; }
112
private int model_count;
95
114
public virtual IListModel<AlbumInfo> Model {
96
get { return albumLoader.Model; }
115
get { return album_loader.Model; }
99
118
public void SetModel (FilterListModel<AlbumInfo> value)
101
albumLoader.Model = value;
120
if (value != album_loader.Model) {
121
if (album_loader.Model != null) {
122
album_loader.Model.Cleared -= OnModelClearedHandler;
123
album_loader.Model.Reloaded -= OnModelReloadedHandler;
126
album_loader.Model = value;
128
if (album_loader.Model != null) {
129
album_loader.Model.Cleared += OnModelClearedHandler;
130
album_loader.Model.Reloaded += OnModelReloadedHandler;
131
model_count = album_loader.Model.Count;
133
CoverManager.ReloadCovers ();
103
137
protected bool attached = false;
104
138
public bool Attached {
105
139
get { return attached; }
109
143
#region User Interface & Interaction
110
private bool dragging = false; // wether or not we are currently dragging the viewport around
111
private double mouse_x, mouse_y;
112
private float drag_x0, drag_y0; // initial coordinates when the mouse button was pressed down
113
private int start_index;
115
private float drag_sens = 0.3f;
116
public float DragSensitivity {
117
get { return drag_sens; }
119
if (value<0.01f) value = 0.01f;
120
if (value>2.0f) value = 2.0f;
126
private ClutterFlowSlider slider;
127
public ClutterFlowSlider Slider {
128
get { return slider; }
130
private ClutterWidgetBar widget_bar;
131
public ClutterWidgetBar WidgetBar {
132
get { return widget_bar; }
134
private PartyModeButton pm_button;
135
public PartyModeButton PMButton {
136
get { return pm_button; }
138
private FullscreenButton fs_button;
139
public FullscreenButton FSButton {
140
get { return fs_button; }
142
private SortButton sort_button;
143
public SortButton SortButton {
144
get { return sort_button; }
146
private CoverCaption caption_cover;
147
public CoverCaption LabelCover {
148
get { return caption_cover; }
150
private TrackCaption caption_track;
151
public TrackCaption LabelTrack {
152
get { return caption_track; }
155
public bool LabelCoverIsVisible {
156
set { if (value) caption_cover.ShowAll(); else caption_cover.HideAll(); }
158
public bool LabelTrackIsVisible {
159
set { if (value) caption_track.ShowAll(); else caption_track.HideAll(); }
163
private const float rotSens = 0.00001f;
164
private const float viewportMaxAngleX = 10; // maximum X viewport angle
165
private const float viewportMinAngleX = -30; // maximum X viewport angle
166
private const float viewportMaxAngleY = -15; // maximum Y viewport angle
167
private float viewportAngleX = -5f; // current X viewport angle
168
public float ViewportAngleX {
169
get { return viewportAngleX; }
171
if (value!=viewportAngleX) {
172
viewportAngleX = value;
173
if (viewportAngleX < viewportMinAngleX) viewportAngleX = viewportMinAngleX;
174
if (viewportAngleX > viewportMaxAngleX) viewportAngleX = viewportMaxAngleX;
176
if (viewportAngleX < -1f && viewportAngleX > -9f)
177
coverManager.SetRotation(RotateAxis.Y, -5f, coverManager.Width*0.5f,coverManager.Height*0.5f,coverManager.Behaviour.ZFar);
179
coverManager.SetRotation(RotateAxis.X, viewportAngleX, coverManager.Width*0.5f,coverManager.Height*0.5f,coverManager.Behaviour.ZFar);
184
private float viewportAngleY = 0; // current Y viewport angle
185
public float ViewportAngleY {
186
get { return viewportAngleY; }
188
if (value!=viewportAngleY) {
189
viewportAngleY = value;
190
if (viewportAngleY < viewportMaxAngleY) viewportAngleY = viewportMaxAngleY;
191
if (viewportAngleY > -viewportMaxAngleY) viewportAngleY = -viewportMaxAngleY;
193
if (viewportAngleY > -4f && viewportAngleY < 4f)
194
coverManager.SetRotation(RotateAxis.Y, 0, coverManager.Width*0.5f,coverManager.Height*0.5f,coverManager.Behaviour.ZFar);
196
coverManager.SetRotation(RotateAxis.Y, viewportAngleY, coverManager.Width*0.5f,coverManager.Height*0.5f,coverManager.Behaviour.ZFar);
203
#region Initialisation
144
private bool dragging = false; // wether or not we are currently dragging the viewport around
145
private double mouse_x, mouse_y;
146
private float drag_x0, drag_y0; // initial coordinates when the mouse button was pressed down
147
private int start_index;
149
private float drag_sens = 0.3f;
150
public float DragSensitivity {
151
get { return drag_sens; }
163
private ClutterFlowSlider slider;
164
public ClutterFlowSlider Slider {
165
get { return slider; }
167
private ClutterWidgetBar widget_bar;
168
public ClutterWidgetBar WidgetBar {
169
get { return widget_bar; }
171
private PartyModeButton pm_button;
172
public PartyModeButton PMButton {
173
get { return pm_button; }
175
private FullscreenButton fs_button;
176
public FullscreenButton FSButton {
177
get { return fs_button; }
179
private SortButton sort_button;
180
public SortButton SortButton {
181
get { return sort_button; }
183
private CoverCaption caption_cover;
184
public CoverCaption LabelCover {
185
get { return caption_cover; }
187
private TrackCaption caption_track;
188
public TrackCaption LabelTrack {
189
get { return caption_track; }
192
public bool LabelCoverIsVisible {
195
caption_cover.ShowAll();
197
caption_cover.HideAll();
201
public bool LabelTrackIsVisible {
203
caption_track.ShowAll();
205
caption_track.HideAll();
211
private const float rotSens = 0.00001f;
212
private const float viewportMaxAngleX = 10; // maximum X viewport angle
213
private const float viewportMinAngleX = -30; // maximum X viewport angle
214
private const float viewportMaxAngleY = -15; // maximum Y viewport angle
215
private float viewportAngleX = -5f; // current X viewport angle
216
public float ViewportAngleX {
217
get { return viewportAngleX; }
219
if (value != viewportAngleX) {
220
viewportAngleX = value;
221
if (viewportAngleX < viewportMinAngleX) {
222
viewportAngleX = viewportMinAngleX;
224
if (viewportAngleX > viewportMaxAngleX) {
225
viewportAngleX = viewportMaxAngleX;
228
if (viewportAngleX < -1f && viewportAngleX > -9f) {
229
cover_manager.SetRotation(RotateAxis.Y, -5f, cover_manager.Width*0.5f,cover_manager.Height*0.5f,cover_manager.Behaviour.ZFar);
231
cover_manager.SetRotation(RotateAxis.X, viewportAngleX, cover_manager.Width*0.5f,cover_manager.Height*0.5f,cover_manager.Behaviour.ZFar);
236
private float viewportAngleY = 0; // current Y viewport angle
237
public float ViewportAngleY {
238
get { return viewportAngleY; }
240
if (value != viewportAngleY) {
241
viewportAngleY = value;
242
if (viewportAngleY < viewportMaxAngleY) {
243
viewportAngleY = viewportMaxAngleY;
245
if (viewportAngleY > -viewportMaxAngleY) {
246
viewportAngleY = -viewportMaxAngleY;
249
if (viewportAngleY > -4f && viewportAngleY < 4f) {
250
cover_manager.SetRotation(RotateAxis.Y, 0, cover_manager.Width*0.5f,cover_manager.Height*0.5f,cover_manager.Behaviour.ZFar);
252
cover_manager.SetRotation(RotateAxis.Y, viewportAngleY, cover_manager.Width*0.5f,cover_manager.Height*0.5f,cover_manager.Behaviour.ZFar);
260
#region Initialisation
204
261
public ClutterFlowView () : base ()
206
SetSizeRequest (300, 200);
207
Clutter.Global.MotionEventsEnabled = true;
263
SetSizeRequest (300, 200);
264
Clutter.Global.MotionEventsEnabled = true;
209
coverManager = new CoverManager();
210
albumLoader = new AlbumLoader (coverManager);
266
album_loader = new AlbumLoader ();
267
cover_manager = new CoverManager (album_loader, GetDefaultSurface, ClutterFlowSchemas.TextureSize.Get ());
220
public void AttachEvents ()
277
private void AttachEvents ()
226
284
Stage.AllocationChanged += HandleAllocationChanged;
249
307
protected bool disposed = false;
250
308
public override void Dispose ()
257
316
AlbumLoader.Dispose ();
258
317
CoverManager.Dispose ();
264
protected void SetupViewport ()
266
Stage.Color = new Clutter.Color (0x00, 0x00, 0x00, 0xff);
267
coverManager.SetRotation (RotateAxis.X, viewportAngleX, Stage.Width/2, Stage.Height/2,0);
268
Stage.Add (coverManager);
321
protected void SetupViewport ()
323
Stage.Color = new Clutter.Color (0x00, 0x00, 0x00, 0xff);
324
cover_manager.SetRotation (RotateAxis.X, viewportAngleX, Stage.Width/2, Stage.Height/2,0);
325
Stage.Add (cover_manager);
272
coverManager.EmptyActor.SetToPb(
273
IconThemeUtils.LoadIcon (coverManager.TextureSize, "gtk-stop", "clutterflow-large.png")
327
cover_manager.EmptyActor.SetToPb (
328
IconThemeUtils.LoadIcon (cover_manager.TextureSize, "gtk-stop", "clutterflow-large.png")
275
CoverManager.DoubleClickTime = (uint) Gtk.Settings.GetForScreen(this.Screen).DoubleClickTime;
276
coverManager.LowerBottom ();
277
coverManager.Show ();
280
protected void SetupSlider ()
282
slider = new ClutterFlowSlider (400, 40, coverManager);
286
protected void SetupLabels () {
287
caption_cover = new CoverCaption (coverManager, "Sans Bold 10", new Clutter.Color(1.0f,1.0f,1.0f,1.0f));
288
Stage.Add (caption_cover);
290
caption_track = new TrackCaption (coverManager, "Sans Bold 10", new Clutter.Color(1.0f,1.0f,1.0f,1.0f));
291
Stage.Add (caption_track);
294
protected void SetupWidgetBar ()
296
pm_button = new PartyModeButton ();
297
fs_button = new FullscreenButton ();
298
sort_button = new SortButton ();
300
widget_bar = new ClutterWidgetBar (new Actor[] { pm_button, fs_button, sort_button });
301
widget_bar.ShowAll ();
302
Stage.Add (widget_bar);
303
widget_bar.SetPosition (5, 5);
308
//Update all elements:
309
protected void RedrawInterface ()
312
caption_cover.Update ();
313
caption_track.Update ();
315
widget_bar.SetPosition (5, 5);
319
//Update the coverStage position:
320
protected void RedrawViewport ()
322
coverManager.UpdateBehaviour();
323
coverManager.SetRotation(RotateAxis.X, viewportAngleX, coverManager.Width*0.5f, coverManager.Height*0.5f,0);
324
if (!coverManager.IsVisible) coverManager.Show();
325
coverManager.LowerBottom();
329
#region Event Handling
331
protected override void OnSizeAllocated (Gdk.Rectangle allocation)
333
base.OnSizeAllocated (allocation);
338
private void HandleAllocationChanged (object o, AllocationChangedArgs args)
344
private void HandleActorActivated (ClutterFlowAlbum actor, EventArgs e)
349
private void HandleButtonPressEvent(object o, Clutter.ButtonPressEventArgs args)
351
Clutter.EventHelper.GetCoords (args.Event, out drag_x0, out drag_y0);
355
void HandleButtonReleaseEvent (object o, Clutter.ButtonReleaseEventArgs args)
357
//if (args.Event.Button==1 && !dragging && coverManager.CurrentCover!=null && ActiveAlbum != CurrentAlbum)
359
if (dragging) Clutter.Ungrab.Pointer ();
364
private void HandleMotionEvent (object o, Clutter.MotionEventArgs args)
366
if ((args.Event.ModifierState.value__ & Clutter.ModifierType.Button1Mask.value__)!=0) {
367
float drag_x; float drag_y;
368
Clutter.EventHelper.GetCoords (args.Event, out drag_x, out drag_y);
370
if (Math.Abs(drag_x0 - drag_x) > 2 && Math.Abs(drag_y0 - drag_y) > 2) {
371
start_index = CoverManager.TargetIndex;
372
Clutter.Grab.Pointer (Stage);
376
if ((args.Event.ModifierState.value__ & Clutter.ModifierType.ControlMask.value__)!=0) {
377
if (!dragging) Clutter.Grab.Pointer (Stage);
378
ViewportAngleY += (float) (mouse_x - args.Event.X)*rotSens;
379
ViewportAngleX += (float) (mouse_y - args.Event.Y)*rotSens;
381
CoverManager.TargetIndex = start_index + (int) ((drag_x0 - drag_x)*drag_sens);
385
if (dragging) Clutter.Ungrab.Pointer ();
388
mouse_x = args.Event.X;
389
mouse_y = args.Event.Y;
391
args.RetVal = dragging;
394
private void HandleScroll (object o, Clutter.ScrollEventArgs args)
396
if (args.Event.Direction==Clutter.ScrollDirection.Down
397
|| args.Event.Direction==Clutter.ScrollDirection.Left)
403
public void Scroll (bool Backward)
405
if (Backward) coverManager.TargetIndex--;
406
else coverManager.TargetIndex++;
409
public void UpdateAlbum ()
411
UpdateAlbum (albumLoader.CurrentActor);
414
public void UpdateAlbum (ClutterFlowAlbum actor)
416
ActiveAlbum = actor.Album;
417
ActiveIndex = actor.Index;
418
if (UpdatedAlbum!=null) UpdatedAlbum (ActiveAlbum, EventArgs.Empty);
330
CoverManager.DoubleClickTime = (uint) Gtk.Settings.GetForScreen (this.Screen).DoubleClickTime;
331
cover_manager.LowerBottom ();
332
cover_manager.Show ();
335
protected void SetupSlider ()
337
slider = new ClutterFlowSlider (400, 40, cover_manager);
341
protected void SetupLabels () {
342
caption_cover = new CoverCaption (cover_manager, "Sans Bold 10", new Clutter.Color(1.0f,1.0f,1.0f,1.0f));
343
Stage.Add (caption_cover);
345
caption_track = new TrackCaption (cover_manager, "Sans Bold 10", new Clutter.Color(1.0f,1.0f,1.0f,1.0f));
346
Stage.Add (caption_track);
349
protected void SetupWidgetBar ()
351
pm_button = new PartyModeButton ();
352
fs_button = new FullscreenButton ();
353
sort_button = new SortButton ();
355
widget_bar = new ClutterWidgetBar (new Actor[] { pm_button, fs_button, sort_button });
356
widget_bar.ShowAll ();
357
Stage.Add (widget_bar);
358
widget_bar.SetPosition (5, 5);
363
//Update all elements:
364
protected void RedrawInterface ()
367
caption_cover.Update ();
368
caption_track.Update ();
370
widget_bar.SetPosition (5, 5);
374
//Update the coverStage position:
375
protected void RedrawViewport ()
377
cover_manager.UpdateBehaviour ();
378
cover_manager.SetRotation (RotateAxis.X, viewportAngleX, cover_manager.Width*0.5f, cover_manager.Height*0.5f,0);
379
if (!cover_manager.IsVisible) {
380
cover_manager.Show ();
382
cover_manager.LowerBottom ();
386
protected Cairo.ImageSurface GetDefaultSurface ()
388
Cairo.ImageSurface surface = new Cairo.ImageSurface(Cairo.Format.ARGB32, CoverManager.TextureSize, CoverManager.TextureSize);
389
Cairo.Context context = new Cairo.Context(surface);
390
Gdk.CairoHelper.SetSourcePixbuf(context, IconThemeUtils.LoadIcon (CoverManager.TextureSize, "media-optical", "browser-album-cover"), 0, 0);
392
//((IDisposable) context.Target).Dispose();
393
((IDisposable) context).Dispose();
398
#region Event Handling
400
protected override void OnSizeAllocated (Gdk.Rectangle allocation)
402
base.OnSizeAllocated (allocation);
407
private void HandleAllocationChanged (object o, AllocationChangedArgs args)
413
private void HandleActorActivated (ClutterFlowBaseActor actor, EventArgs e)
415
var album_actor = actor as ClutterFlowAlbum;
416
if (album_actor != null) {
417
UpdateAlbum (album_actor);
421
private void HandleButtonPressEvent (object o, Clutter.ButtonPressEventArgs args)
423
Clutter.EventHelper.GetCoords (args.Event, out drag_x0, out drag_y0);
427
void HandleButtonReleaseEvent (object o, Clutter.ButtonReleaseEventArgs args)
429
//if (args.Event.Button==1 && !dragging && coverManager.CurrentCover!=null && ActiveAlbum != CurrentAlbum)
432
Clutter.Ungrab.Pointer ();
438
private void HandleMotionEvent (object o, Clutter.MotionEventArgs args)
440
if ((args.Event.ModifierState.value__ & Clutter.ModifierType.Button1Mask.value__) != 0) {
441
float drag_x; float drag_y;
442
Clutter.EventHelper.GetCoords (args.Event, out drag_x, out drag_y);
444
if (Math.Abs(drag_x0 - drag_x) > 2 && Math.Abs(drag_y0 - drag_y) > 2) {
445
start_index = CoverManager.TargetIndex;
446
Clutter.Grab.Pointer (Stage);
450
if ((args.Event.ModifierState.value__ & Clutter.ModifierType.ControlMask.value__)!=0) {
452
Clutter.Grab.Pointer (Stage);
454
ViewportAngleY += (float) (mouse_x - args.Event.X)*rotSens;
455
ViewportAngleX += (float) (mouse_y - args.Event.Y)*rotSens;
457
CoverManager.TargetIndex = start_index + (int) ((drag_x0 - drag_x)*drag_sens);
462
Clutter.Ungrab.Pointer ();
466
mouse_x = args.Event.X;
467
mouse_y = args.Event.Y;
469
args.RetVal = dragging;
472
private void HandleScroll (object o, Clutter.ScrollEventArgs args)
474
if (args.Event.Direction == Clutter.ScrollDirection.Down
475
|| args.Event.Direction == Clutter.ScrollDirection.Left) {
482
public void Scroll (bool Backward)
485
cover_manager.TargetIndex--;
487
cover_manager.TargetIndex++;
491
private void ScrollTo (string key)
493
ClutterFlowBaseActor actor = null;
494
album_loader.Cache.TryGetValue (key, out actor);
495
if (actor != null && cover_manager.Covers.Contains (actor)) {
496
cover_manager.TargetIndex = actor.Index;
500
public void ScrollTo (AlbumInfo album)
502
cover_manager.Timeline.Timeout = 500; //give 'm some time to load the song etc.
503
ScrollTo (ClutterFlowAlbum.CreateCacheKey (album));
507
public void UpdateAlbum ()
509
UpdateAlbum (cover_manager.CurrentCover as ClutterFlowAlbum);
512
public void UpdateAlbum (ClutterFlowAlbum actor)
514
ActiveAlbum = actor.Album;
515
ActiveIndex = actor.Index;
516
if (UpdatedAlbum != null) {
517
UpdatedAlbum (ActiveAlbum, EventArgs.Empty);
521
protected void OnModelClearedHandler (object o, EventArgs args)
523
CoverManager.ReloadCovers ();
526
protected void OnModelReloadedHandler (object o, EventArgs args)
528
if (model_count != album_loader.Model.Count) {
529
model_count = album_loader.Model.Count;
530
CoverManager.ReloadCovers ();