Merge lp:~victored/noise/new-album-view into lp:~elementary-apps/noise/trunk

Proposed by Victor Martinez
Status: Merged
Approved by: Corentin Noël
Approved revision: 1518
Merged at revision: 1540
Proposed branch: lp:~victored/noise/new-album-view
Merge into: lp:~elementary-apps/noise/trunk
Diff against target: 966 lines (+477/-266) (has conflicts)
14 files modified
core/Utils/Icons.vala (+0/-12)
core/Utils/PixbufUtils.vala (+14/-64)
images/CMakeLists.txt (+5/-0)
plugins/Devices/CDRom/CDView.vala (+1/-1)
src/CMakeLists.txt (+79/-0)
src/Objects/CoverartCache.vala (+2/-4)
src/Views/GridView/GridLayout.vala (+0/-160)
src/Views/GridView/GridView.vala (+6/-16)
src/Widgets/FastView/FastGrid.vala (+7/-5)
src/Widgets/FastView/FastGridModel.vala (+3/-1)
src/Widgets/FastView/TileView/ImageUtils.vala (+51/-0)
src/Widgets/FastView/TileView/TileRenderer.vala (+234/-0)
src/Widgets/FastView/TileView/TileView.vala (+70/-0)
src/Widgets/InfoPanel.vala (+5/-3)
Text conflict in images/CMakeLists.txt
Text conflict in src/CMakeLists.txt
To merge this branch: bzr merge lp:~victored/noise/new-album-view
Reviewer Review Type Date Requested Status
elementary Apps team Pending
Review via email: mp+180679@code.launchpad.net

Commit message

Add fancier album view by using a custom cell renderer in GtkIconView.

Please note that the code used for "smart spacing" has been removed as it only worked before GTK+ 3.4.3. New bugs in GTK+ prevent us from keeping this code around.

Description of the change

As you may have seen, the "smart spacing" code from the album view does not work with new GTK+ versions, due to some bugs in GtkIconView we have not been able to work around. This branch removes that code for the time being and adds a custom cell renderer that makes our icon view more similar to the one used by Shotwell.

To post a comment you must log in.
Revision history for this message
Victor Martinez (victored) wrote :

Please note this code is not supposed to work correctly on Luna, but on GTK+ 3.8 or newer (Ubuntu 13.04).

Revision history for this message
David Gomes (davidgomes) wrote :

We'll merge this when we have Saucy builds and are officially using GTK+ 3.8+-

lp:~victored/noise/new-album-view updated
1518. By Victor Martinez

Fix coding style issue

Revision history for this message
Rico Tzschichholz (ricotz) wrote :

If noise doesn't work as expected with gtk+3.0 < 3.8 after this change then the dependency should have been bumped.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'core/Utils/Icons.vala'
2--- core/Utils/Icons.vala 2013-02-26 21:56:08 +0000
3+++ core/Utils/Icons.vala 2013-09-26 03:02:55 +0000
4@@ -33,15 +33,8 @@
5 * A place to store icon information and pixbufs.
6 */
7 public class Noise.Icons {
8-
9- /**
10- * Size of the cover art used in the album view
11- **/
12- public const int ALBUM_VIEW_IMAGE_SIZE = 168;
13 public const int DEFAULT_ALBUM_ART_SIZE = 138;
14
15- public static Gdk.Pixbuf DEFAULT_ALBUM_SHADOW_PIXBUF { get; private set; }
16-
17 public static Icon DEFAULT_ALBUM_ART { get; private set; default = new Icon ("albumart"); }
18 public static Icon DEFAULT_ALBUM_ART_2 { get; private set; default = new Icon ("albumart_2"); }
19 public static Icon MUSIC_FOLDER { get; private set; default = new Icon ("folder-music"); }
20@@ -83,11 +76,6 @@
21 public static Icon LIST_ADD_SYMBOLIC { get; private set; default = new Icon ("list-add-symbolic"); }
22 public static Icon REFRESH_SYMBOLIC { get; private set; default = new Icon ("view-refresh-symbolic"); }
23
24- static construct {
25- var default_shadow = new Icon ("albumart-shadow");
26- DEFAULT_ALBUM_SHADOW_PIXBUF = default_shadow.render_at_size (ALBUM_VIEW_IMAGE_SIZE);
27- }
28-
29 /**
30 * This is needed until vala really supports initialization of static members.
31 * See https://bugzilla.gnome.org/show_bug.cgi?id=543189
32
33=== modified file 'core/Utils/PixbufUtils.vala'
34--- core/Utils/PixbufUtils.vala 2013-06-12 18:04:28 +0000
35+++ core/Utils/PixbufUtils.vala 2013-09-26 03:02:55 +0000
36@@ -22,75 +22,25 @@
37 */
38
39 namespace Noise.PixbufUtils {
40-
41- /**
42- * @param pixbuf original image
43- * @param stretch whether to strech the image inside the square or keep the original dimensions
44- * @return original pixbuf + drop shadow
45- **/
46- public Gdk.Pixbuf? get_pixbuf_shadow (Gdk.Pixbuf pixbuf, int surface_size, bool stretch = true) {
47- const int SHADOW_SIZE = 15;
48-
49- int S_WIDTH = (stretch)? surface_size: pixbuf.width;
50- int S_HEIGHT = (stretch)? surface_size : pixbuf.height;
51-
52- var buffer_surface = new Granite.Drawing.BufferSurface (S_WIDTH, S_HEIGHT);
53-
54- // paint shadow
55- buffer_surface.context.rectangle (0, 0, S_WIDTH, S_HEIGHT);
56-
57- if (stretch)
58- Gdk.cairo_set_source_pixbuf (buffer_surface.context,
59- Icons.DEFAULT_ALBUM_SHADOW_PIXBUF.scale_simple (S_WIDTH, S_HEIGHT, Gdk.InterpType.BILINEAR), 0, 0);
60- else
61- Gdk.cairo_set_source_pixbuf (buffer_surface.context, Icons.DEFAULT_ALBUM_SHADOW_PIXBUF, 0, 0);
62-
63- buffer_surface.context.paint();
64-
65- S_WIDTH -= 2 * SHADOW_SIZE;
66- S_HEIGHT -= 2 * SHADOW_SIZE;
67-
68- // paint original pixbuf
69- var source_pixbuf = pixbuf;
70- if (pixbuf.width != S_WIDTH || pixbuf.height != S_HEIGHT)
71- source_pixbuf = pixbuf.scale_simple (S_WIDTH, S_HEIGHT, Gdk.InterpType.BILINEAR);
72-
73- Gdk.cairo_set_source_pixbuf (buffer_surface.context, source_pixbuf,
74- SHADOW_SIZE, SHADOW_SIZE - 2); // 2px vertical offset
75- buffer_surface.context.paint();
76-
77- return buffer_surface.load_to_pixbuf();
78- }
79-
80 /**
81 * @param surface_size size of the new pixbuf. Set a value of 0 to use the pixbuf's default size.
82 **/
83- public Gdk.Pixbuf? render_pixbuf_shadow (Gdk.Pixbuf pixbuf,
84- int surface_size = Icons.ALBUM_VIEW_IMAGE_SIZE,
85- int shadow_size = 5, double alpha = 0.75)
86- {
87- int S_WIDTH = (surface_size > 0)? surface_size : pixbuf.width;
88- int S_HEIGHT = (surface_size > 0)? surface_size : pixbuf.height;
89-
90- var buffer_surface = new Granite.Drawing.BufferSurface (S_WIDTH, S_HEIGHT);
91-
92- S_WIDTH -= 2 * shadow_size;
93- S_HEIGHT -= 2 * shadow_size;
94-
95- buffer_surface.context.rectangle (shadow_size, shadow_size, S_WIDTH, S_HEIGHT);
96+ public Gdk.Pixbuf? render_pixbuf_shadow (Gdk.Pixbuf pixbuf, int shadow_size = 5, double alpha = 0.75) {
97+ int width = pixbuf.width;
98+ int height = pixbuf.height;
99+ int shadow_padding = 2 * shadow_size;
100+
101+ var buffer_surface = new Granite.Drawing.BufferSurface (width + shadow_padding,
102+ height + shadow_padding);
103+
104+ buffer_surface.context.rectangle (shadow_size, shadow_size, width, height);
105 buffer_surface.context.set_source_rgba (0, 0, 0, alpha);
106- buffer_surface.context.fill();
107-
108+ buffer_surface.context.fill ();
109 buffer_surface.fast_blur (2, 3);
110-
111- Gdk.cairo_set_source_pixbuf (buffer_surface.context,
112- pixbuf.scale_simple (S_WIDTH, S_HEIGHT, Gdk.InterpType.BILINEAR),
113- shadow_size,
114- shadow_size);
115-
116- buffer_surface.context.paint();
117-
118- return buffer_surface.load_to_pixbuf();
119+ Gdk.cairo_set_source_pixbuf (buffer_surface.context, pixbuf, shadow_size, shadow_size);
120+ buffer_surface.context.paint ();
121+
122+ return buffer_surface.load_to_pixbuf ();
123 }
124
125 public async Gdk.Pixbuf? get_pixbuf_from_file_async (File file, Cancellable? c = null) throws Error {
126
127=== modified file 'images/CMakeLists.txt'
128--- images/CMakeLists.txt 2013-09-16 07:12:31 +0000
129+++ images/CMakeLists.txt 2013-09-26 03:02:55 +0000
130@@ -21,9 +21,14 @@
131 # Default album image and album shadow. These would not be found by the icon renderer if
132 # they were installed to the hicolor sub-directory, since their dimensions are not the ones
133 # GTK+ expects to find in a normal icon theme. They work fine in the root icon dir though.
134+<<<<<<< TREE
135 set (GENERIC_IMAGES
136 icons/albumart.svg
137 icons/albumart-shadow.png
138+=======
139+set(GENERIC_IMAGES
140+ icons/albumart.svg
141+>>>>>>> MERGE-SOURCE
142 )
143
144 install (FILES ${GENERIC_IMAGES} DESTINATION ${ICON_DIR})
145
146=== removed file 'images/icons/albumart-shadow.png'
147Binary files images/icons/albumart-shadow.png 2013-07-12 19:29:23 +0000 and images/icons/albumart-shadow.png 1970-01-01 00:00:00 +0000 differ
148=== modified file 'plugins/Devices/CDRom/CDView.vala'
149--- plugins/Devices/CDRom/CDView.vala 2013-04-29 18:26:03 +0000
150+++ plugins/Devices/CDRom/CDView.vala 2013-09-26 03:02:55 +0000
151@@ -57,7 +57,7 @@
152 }
153
154 var default_pix = Icons.DEFAULT_ALBUM_ART.render_at_size (Icons.DEFAULT_ALBUM_ART_SIZE);
155- default_pix = PixbufUtils.get_pixbuf_shadow (default_pix, Icons.ALBUM_VIEW_IMAGE_SIZE);
156+ default_pix = PixbufUtils.render_pixbuf_shadow (default_pix);
157
158 album_image = new Gtk.Image.from_pixbuf (default_pix);
159 album_image.halign = Gtk.Align.CENTER;
160
161=== modified file 'src/CMakeLists.txt'
162--- src/CMakeLists.txt 2013-09-16 07:12:31 +0000
163+++ src/CMakeLists.txt 2013-09-26 03:02:55 +0000
164@@ -1,3 +1,4 @@
165+<<<<<<< TREE
166 set (CLIENT_SOURCE
167 main.vala
168 Noise.vala
169@@ -71,6 +72,84 @@
170 Dialogs/SetMusicFolderConfirmation.vala
171 Dialogs/TransferFromDeviceDialog.vala
172 Dialogs/SyncWarningDialog.vala
173+=======
174+set(CLIENT_SOURCE
175+ main.vala
176+ Noise.vala
177+ LibraryWindow.vala
178+ LocalLibrary.vala
179+ PlaybackManager.vala
180+ FileOperator.vala
181+ Objects/LyricFetcher.vala
182+ Objects/MediaInfo.vala
183+ Objects/AlbumInfo.vala
184+ Objects/ArtistInfo.vala
185+ Objects/TrackInfo.vala
186+ Objects/MediaArtCache.vala
187+ Objects/CoverartCache.vala
188+ Objects/MediaKeyListener.vala
189+ Widgets/NavigationArrows.vala
190+ Widgets/SmartAlbumRenderer.vala
191+ Widgets/TopDisplay.vala
192+ Widgets/InfoPanel.vala
193+ Widgets/EmbeddedAlert.vala
194+ Widgets/SimpleOptionChooser.vala
195+ Widgets/PresetList.vala
196+ Widgets/SideBar.vala
197+ Widgets/SourceListView.vala
198+ Widgets/StatusBar.vala
199+ Widgets/RatingWidget.vala
200+ Widgets/SpaceWidget.vala
201+ Widgets/FixedBin.vala
202+ Widgets/ViewSelector.vala
203+ Widgets/FastView/TileView/ImageUtils.vala
204+ Widgets/FastView/TileView/TileRenderer.vala
205+ Widgets/FastView/TileView/TileView.vala
206+ Widgets/FastView/FastGrid.vala
207+ Widgets/FastView/FastGridModel.vala
208+ Widgets/FastView/FastList.vala
209+ Widgets/FastView/FastListModel.vala
210+ DataBase/DataBaseManager.vala
211+ DataBase/DataBaseUpdater.vala
212+ DataBase/Tables.vala
213+ GStreamer/GStreamerTagger.vala
214+ GStreamer/Streamer.vala
215+ GStreamer/CoverImport.vala
216+ Views/ViewContainer.vala
217+ Views/Wrappers/ViewWrapper.vala
218+ Views/Wrappers/MusicViewWrapper.vala
219+ Views/Wrappers/DeviceViewWrapper.vala
220+ Views/Wrappers/PlaylistViewWrapper.vala
221+ Views/Wrappers/ReadOnlyPlaylistViewWrapper.vala
222+ Views/DeviceView.vala
223+ Views/DeviceSummaryWidget.vala
224+ Views/ContentView.vala
225+ Views/ViewTextOverlay.vala
226+ Views/GridView/GridLayout.vala
227+ Views/GridView/GridView.vala
228+ Views/GridView/PopupListView.vala
229+ Views/ListView/ListView.vala
230+ Views/ListView/ColumnBrowser/BrowserColumnModel.vala
231+ Views/ListView/ColumnBrowser/BrowserColumn.vala
232+ Views/ListView/ColumnBrowser/ColumnBrowser.vala
233+ Views/ListView/ColumnBrowser/MusicColumnBrowser.vala
234+ Views/ListView/Lists/ListColumn.vala
235+ Views/ListView/Lists/TreeViewSetup.vala
236+ Views/ListView/Lists/CellDataFunctionHelper.vala
237+ Views/ListView/Lists/GenericList.vala
238+ Views/ListView/Lists/MusicListView.vala
239+ Dialogs/EqualizerWindow.vala
240+ Dialogs/SmartPlaylistEditor.vala
241+ Dialogs/PreferencesWindow.vala
242+ Dialogs/InstallGstreamerPluginsDialog.vala
243+ Dialogs/MediaEditor.vala
244+ Dialogs/FileNotFoundDialog.vala
245+ Dialogs/RemoveFilesDialog.vala
246+ Dialogs/NotImportedWindow.vala
247+ Dialogs/SetMusicFolderConfirmation.vala
248+ Dialogs/TransferFromDeviceDialog.vala
249+ Dialogs/SyncWarningDialog.vala
250+>>>>>>> MERGE-SOURCE
251 )
252
253 set (CLIENT_VALAC_OPTIONS
254
255=== modified file 'src/Objects/CoverartCache.vala'
256--- src/Objects/CoverartCache.vala 2012-11-03 18:52:31 +0000
257+++ src/Objects/CoverartCache.vala 2013-09-26 03:02:55 +0000
258@@ -55,11 +55,9 @@
259 default_image = filter_func (default_pix);
260 }
261
262- /**
263- * Adds a shadow to every image.
264- */
265 protected override Gdk.Pixbuf? filter_func (Gdk.Pixbuf pix) {
266- return PixbufUtils.get_pixbuf_shadow (pix, Icons.ALBUM_VIEW_IMAGE_SIZE);
267+ int size = Icons.DEFAULT_ALBUM_ART_SIZE;
268+ return pix.scale_simple (size, size, Gdk.InterpType.BILINEAR);
269 }
270
271 protected override string get_key (Media m) {
272
273=== modified file 'src/Views/GridView/GridLayout.vala'
274--- src/Views/GridView/GridLayout.vala 2013-05-22 20:42:53 +0000
275+++ src/Views/GridView/GridLayout.vala 2013-09-26 03:02:55 +0000
276@@ -17,23 +17,11 @@
277 */
278
279 public abstract class Noise.GridLayout : ViewTextOverlay {
280-
281 public ViewWrapper parent_view_wrapper { get; protected set; }
282
283 private FastGrid icon_view;
284 private Gtk.ScrolledWindow scroll;
285
286- // Spacing Workarounds
287-#if !GTK_ICON_VIEW_BUG_IS_FIXED
288- private Gtk.EventBox vpadding_box;
289- private Gtk.EventBox hpadding_box;
290-#endif
291-
292- private const string STYLESHEET = "*:selected{background-color:@transparent;}";
293- private const int ITEM_PADDING = 0;
294- private const int MIN_SPACING = 6;
295- private const int ITEM_WIDTH = Icons.ALBUM_VIEW_IMAGE_SIZE;
296-
297 public GridLayout (ViewWrapper view_wrapper) {
298 parent_view_wrapper = view_wrapper;
299 build_ui ();
300@@ -88,59 +76,7 @@
301
302 icon_view.set_columns (-1);
303
304-// Should be defined for GTK+ 3.4.3 or later
305-#if !GTK_ICON_VIEW_BUG_IS_FIXED
306-
307- var wrapper_vbox = new Gtk.Box (Gtk.Orientation.VERTICAL, 0);
308- var wrapper_hbox = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0);
309-
310- vpadding_box = new Gtk.EventBox();
311- hpadding_box = new Gtk.EventBox();
312-
313- vpadding_box.get_style_context().add_class(Gtk.STYLE_CLASS_VIEW);
314- hpadding_box.get_style_context().add_class(Gtk.STYLE_CLASS_VIEW);
315- this.get_style_context().add_class(Gtk.STYLE_CLASS_VIEW);
316-
317- vpadding_box.get_style_context().add_class (Granite.StyleClass.CONTENT_VIEW);
318- hpadding_box.get_style_context().add_class (Granite.StyleClass.CONTENT_VIEW);
319- this.get_style_context().add_class (Granite.StyleClass.CONTENT_VIEW);
320-
321- vpadding_box.set_size_request (-1, MIN_SPACING + ITEM_PADDING);
322- hpadding_box.set_size_request (MIN_SPACING + ITEM_PADDING, -1);
323-
324- vpadding_box.button_press_event.connect ( () => {
325- item_activated (null);
326- return false;
327- });
328-
329- hpadding_box.button_press_event.connect ( () => {
330- item_activated (null);
331- return false;
332- });
333-
334-
335- wrapper_vbox.pack_start (vpadding_box, false, false, 0);
336- wrapper_vbox.pack_start (wrapper_hbox, true, true, 0);
337- wrapper_hbox.pack_start (hpadding_box, false, false, 0);
338- wrapper_hbox.pack_start (icon_view, true, true, 0);
339-
340- scroll.add_with_viewport (wrapper_vbox);
341-
342- icon_view.margin = 0;
343-
344-#else
345-
346 scroll.add (icon_view);
347- icon_view.margin = MIN_SPACING;
348-
349-#endif
350-
351-
352- icon_view.item_width = ITEM_WIDTH;
353- icon_view.item_padding = ITEM_PADDING;
354- icon_view.spacing = 0;
355- icon_view.row_spacing = MIN_SPACING;
356- icon_view.column_spacing = MIN_SPACING;
357
358 icon_view.add_events (Gdk.EventMask.POINTER_MOTION_MASK);
359 icon_view.motion_notify_event.connect (on_motion_notify);
360@@ -150,24 +86,9 @@
361 icon_view.button_release_event.connect (on_button_release);
362 icon_view.item_activated.connect (on_item_activated);
363
364- int MIN_N_ITEMS = 2; // we will allocate horizontal space for at least two items
365- int TOTAL_ITEM_WIDTH = ITEM_WIDTH + 2 * ITEM_PADDING;
366- int TOTAL_MARGIN = MIN_N_ITEMS * (MIN_SPACING + ITEM_PADDING);
367- int MIDDLE_SPACE = MIN_N_ITEMS * MIN_SPACING;
368-
369- scroll.min_content_width = MIN_N_ITEMS * TOTAL_ITEM_WIDTH + TOTAL_MARGIN + MIDDLE_SPACE;
370-
371- set_theming ();
372- scroll.get_hadjustment ().changed.connect (on_resize);
373-
374 show_all ();
375 }
376
377- private void set_theming () {
378- // Change background color
379- Granite.Widgets.Utils.set_theming (icon_view, STYLESHEET, null, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
380- }
381-
382 private void on_item_activated (Gtk.TreePath? path) {
383 if (path == null)
384 item_activated (null);
385@@ -218,85 +139,4 @@
386 set_cursor ((int)ev.x, (int)ev.y);
387 return false;
388 }
389-
390-
391- /**
392- * Smart spacing
393- */
394- private bool waiting_resize = false;
395-
396- private void on_resize () {
397- if (waiting_resize)
398- return;
399-
400- waiting_resize = true;
401-
402- int priority = parent_view_wrapper.is_current_wrapper ? Priority.HIGH_IDLE : Priority.LOW;
403-
404- Idle.add_full (priority , () => {
405- update_spacing ();
406- waiting_resize = false;
407- return false;
408- });
409- }
410-
411- private int get_current_width () {
412- return (int) scroll.get_hadjustment ().page_size;
413- }
414-
415- private void update_spacing () {
416- if (!visible)
417- return;
418-
419- int new_width = get_current_width ();
420-
421- int TOTAL_WIDTH = new_width; // width of view wrapper, not scrolled window!
422- int TOTAL_ITEM_WIDTH = ITEM_WIDTH + 2 * ITEM_PADDING;
423-
424- // Calculate the number of columns
425- float n = (float)(TOTAL_WIDTH - MIN_SPACING) / (float)(TOTAL_ITEM_WIDTH + MIN_SPACING);
426- int n_columns = (int) GLib.Math.truncf (n);
427-
428- if (n_columns < 1)
429- return;
430-
431- icon_view.set_columns (n_columns);
432-
433- // We don't want to adjust the spacing if the row is not full
434- if (icon_view.get_table ().size () < n_columns)
435- return;
436-
437- // You're not supposed to understand this.
438- float spacing = (float)(TOTAL_WIDTH - n_columns * (ITEM_WIDTH + 1) - 2 * n_columns * ITEM_PADDING) / (float)(n_columns + 1);
439- int new_spacing = (int) GLib.Math.roundf (spacing);
440-
441- if (new_spacing < 0)
442- return;
443-
444- if (TOTAL_WIDTH < 750)
445- -- new_spacing;
446-
447- // apply new spacing
448- set_spacing (new_spacing);
449- }
450-
451- private void set_spacing (int spacing) {
452- if (spacing < 0)
453- return;
454-
455- int item_offset = ITEM_PADDING / icon_view.columns;
456- int item_spacing = spacing - ((item_offset > 0) ? item_offset : 1);
457-
458- icon_view.set_column_spacing (item_spacing);
459- icon_view.set_row_spacing (item_spacing);
460-
461- int margin_width = spacing + ITEM_PADDING;
462-
463-#if GTK_ICON_VIEW_BUG_IS_FIXED
464- icon_view.set_margin (margin_width);
465-#else
466- vpadding_box.set_size_request (-1, margin_width);
467- hpadding_box.set_size_request (margin_width, -1);
468-#endif
469- }
470 }
471
472=== modified file 'src/Views/GridView/GridView.vala'
473--- src/Views/GridView/GridView.vala 2013-06-02 17:35:04 +0000
474+++ src/Views/GridView/GridView.vala 2013-09-26 03:02:55 +0000
475@@ -18,10 +18,6 @@
476 */
477
478 public class Noise.GridView : ContentView, GridLayout {
479-
480- private string TEXT_MARKUP = "%s\n<span foreground=\"#999\">%s</span>";
481- private string TOOLTIP_MARKUP = "<span size=\"large\"><b>%s</b></span>\n%s";
482-
483 // The window used to present album contents
484 private static PopupListView? _popup = null;
485 public PopupListView popup_list_view {
486@@ -329,22 +325,16 @@
487 // replace the current album-related media fields.
488 return CoverartCache.instance.get_album_cover (album);
489
490- case FastGrid.Column.MARKUP:
491- string name = album.get_display_name ();
492- string artist = album.get_display_artist ();
493-
494- if (name.length > 25)
495- name = name.substring (0, 21) + "…";
496- if (artist.length > 25)
497- artist = artist.substring (0, 21) + "…";
498-
499- return Markup.printf_escaped (TEXT_MARKUP, name, artist);
500+ case FastGrid.Column.TITLE:
501+ return album.get_display_name ();
502+
503+ case FastGrid.Column.SUBTITLE:
504+ return album.get_display_artist ();
505
506 case FastGrid.Column.TOOLTIP:
507 string name = album.get_display_name ();
508 string artist = album.get_display_artist ();
509-
510- return Markup.printf_escaped (TOOLTIP_MARKUP, name, artist);
511+ return Markup.printf_escaped ("<span size=\"large\"><b>%s</b></span>\n%s", name, artist);
512 }
513
514 assert_not_reached ();
515
516=== modified file 'src/Widgets/FastView/FastGrid.vala'
517--- src/Widgets/FastView/FastGrid.vala 2013-05-22 20:42:53 +0000
518+++ src/Widgets/FastView/FastGrid.vala 2013-09-26 03:02:55 +0000
519@@ -21,11 +21,12 @@
520
521 using Gtk;
522
523-public class Noise.FastGrid : IconView {
524+public class Noise.FastGrid : Widgets.TileView {
525
526 public enum Column {
527 PIXBUF,
528- MARKUP,
529+ TITLE,
530+ SUBTITLE,
531 TOOLTIP,
532 N_COLUMNS
533 }
534@@ -50,9 +51,10 @@
535 set_table (table, true);
536 set_model (fm);
537
538- set_pixbuf_column (Column.PIXBUF);
539- set_markup_column (Column.MARKUP);
540- set_tooltip_column (Column.TOOLTIP);
541+ image_column = Column.PIXBUF;
542+ title_column = Column.TITLE;
543+ subtitle_column = Column.SUBTITLE;
544+ tooltip_column = Column.TOOLTIP;
545 }
546
547 public void set_search_func (ViewSearchFunc func) {
548
549=== modified file 'src/Widgets/FastView/FastGridModel.vala'
550--- src/Widgets/FastView/FastGridModel.vala 2012-10-27 16:25:32 +0000
551+++ src/Widgets/FastView/FastGridModel.vala 2013-09-26 03:02:55 +0000
552@@ -28,6 +28,8 @@
553 return typeof(string);
554 else if(col == 2)
555 return typeof(string);
556+ else if(col == 3)
557+ return typeof(string);
558 else
559 return typeof(GLib.Object);
560 }
561@@ -49,7 +51,7 @@
562 }
563
564 public int get_n_columns () {
565- return 4;
566+ return 5;
567 }
568
569 public TreePath? get_path (TreeIter iter) {
570
571=== added directory 'src/Widgets/FastView/TileView'
572=== added file 'src/Widgets/FastView/TileView/ImageUtils.vala'
573--- src/Widgets/FastView/TileView/ImageUtils.vala 1970-01-01 00:00:00 +0000
574+++ src/Widgets/FastView/TileView/ImageUtils.vala 2013-09-26 03:02:55 +0000
575@@ -0,0 +1,51 @@
576+/**
577+ * Copyright 2009-2013 Yorba Foundation
578+ *
579+ * This software is licensed under the GNU Lesser General Public License
580+ * (version 3 or later). See the COPYING file in this distribution.
581+ *
582+ * (Code taken from Shotwell Photo Manager: shotwell/src/util/image.vala)
583+ */
584+
585+namespace Noise.ImageUtils {
586+ internal void shift_colors (Gdk.Pixbuf pixbuf, int red, int green, int blue, int alpha) {
587+ assert (red >= -255 && red <= 255);
588+ assert (green >= -255 && green <= 255);
589+ assert (blue >= -255 && blue <= 255);
590+ assert (alpha >= -255 && alpha <= 255);
591+
592+ int width = pixbuf.get_width ();
593+ int height = pixbuf.get_height ();
594+ int rowstride = pixbuf.get_rowstride ();
595+ int channels = pixbuf.get_n_channels ();
596+ uchar *pixels = pixbuf.get_pixels ();
597+
598+ assert (channels >= 3);
599+ assert (pixbuf.get_colorspace () == Gdk.Colorspace.RGB);
600+ assert (pixbuf.get_bits_per_sample () == 8);
601+
602+ for (int y = 0; y < height; y++) {
603+ int y_offset = y * rowstride;
604+
605+ for (int x = 0; x < width; x++) {
606+ int offset = y_offset + (x * channels);
607+
608+ if (red != 0)
609+ pixels[offset] = shift_color_byte (pixels[offset], red);
610+
611+ if (green != 0)
612+ pixels[offset + 1] = shift_color_byte (pixels[offset + 1], green);
613+
614+ if (blue != 0)
615+ pixels[offset + 2] = shift_color_byte (pixels[offset + 2], blue);
616+
617+ if (alpha != 0 && channels >= 4)
618+ pixels[offset + 3] = shift_color_byte (pixels[offset + 3], alpha);
619+ }
620+ }
621+ }
622+
623+ internal inline uchar shift_color_byte (int b, int shift) {
624+ return (uchar) (b + shift).clamp (0, 255);
625+ }
626+}
627
628=== added file 'src/Widgets/FastView/TileView/TileRenderer.vala'
629--- src/Widgets/FastView/TileView/TileRenderer.vala 1970-01-01 00:00:00 +0000
630+++ src/Widgets/FastView/TileView/TileRenderer.vala 2013-09-26 03:02:55 +0000
631@@ -0,0 +1,234 @@
632+/**
633+ * Copyright 2013 elementary
634+ *
635+ * This software is licensed under the GNU Lesser General Public License
636+ * (version 3 or later). See the COPYING file in this distribution.
637+ */
638+
639+internal class Noise.Widgets.TileRenderer : Gtk.CellRenderer {
640+ public Gdk.Pixbuf pixbuf { get; set; }
641+ public string title { get; set; }
642+ public string subtitle { get; set; }
643+
644+ private const int BRIGHTEN_SHIFT = 0x18;
645+ private const int IMAGE_SHADOW_MARGIN = 12;
646+ private const int IMAGE_SHADOW_RADIUS = 4;
647+ private const double IMAGE_SHADOW_ALPHA = 0.65;
648+
649+ private int last_image_width = 0;
650+ private int last_image_height = 0;
651+ private Granite.Drawing.BufferSurface shadow_buffer;
652+ private Pango.Rectangle title_text_logical_rect;
653+ private Pango.Rectangle subtitle_text_logical_rect;
654+ private Pango.Layout title_text_layout;
655+ private Pango.Layout subtitle_text_layout;
656+ private Gtk.Border margin;
657+ private Gtk.Border padding;
658+ private Gtk.Border border;
659+
660+ [Deprecated (replacement = "Gtk.CellRenderer.get_preferred_size", since = "")]
661+ public override void get_size (Gtk.Widget widget, Gdk.Rectangle? cell_area,
662+ out int x_offset, out int y_offset,
663+ out int width, out int height)
664+ {
665+ x_offset = y_offset = width = height = 0;
666+ }
667+
668+ public override Gtk.SizeRequestMode get_request_mode () {
669+ return Gtk.SizeRequestMode.HEIGHT_FOR_WIDTH;
670+ }
671+
672+ public override void get_preferred_width (Gtk.Widget widget,
673+ out int minimum_size,
674+ out int natural_size)
675+ {
676+ update_layout_properties (widget);
677+
678+ int width = compute_total_image_width ()
679+ + margin.left + margin.right
680+ + padding.left + padding.right
681+ + border.left + border.right
682+ + 2 * (int) xpad;
683+
684+ minimum_size = natural_size = width;
685+ }
686+
687+ public override void get_preferred_height_for_width (Gtk.Widget widget, int width,
688+ out int minimum_height,
689+ out int natural_height)
690+ {
691+ update_layout_properties (widget);
692+
693+ int height = compute_total_image_height ()
694+ + title_text_logical_rect.height
695+ + subtitle_text_logical_rect.height
696+ + margin.top + margin.bottom
697+ + padding.top + padding.bottom
698+ + border.top + border.bottom
699+ + 2 * (int) ypad;
700+
701+ minimum_height = natural_height = height;
702+ }
703+
704+ public override void render (Cairo.Context cr, Gtk.Widget widget, Gdk.Rectangle bg_area,
705+ Gdk.Rectangle cell_area, Gtk.CellRendererState flags)
706+ {
707+ update_layout_properties (widget);
708+
709+ Gdk.Rectangle aligned_area = get_aligned_area (widget, flags, cell_area);
710+
711+ int x = aligned_area.x;
712+ int y = aligned_area.y;
713+ int width = aligned_area.width;
714+ int height = aligned_area.height;
715+
716+ // Apply margin
717+ x += margin.right;
718+ y += margin.top;
719+ width -= margin.left + margin.right;
720+ height -= margin.top + margin.bottom;
721+
722+ var ctx = widget.get_style_context ();
723+
724+ // Apply border width and padding offsets
725+ x += border.right + padding.right;
726+ y += border.top + padding.top;
727+
728+ width -= border.left + border.right + padding.left + padding.right;
729+ height -= border.top + border.bottom + padding.top + padding.bottom;
730+
731+ render_image (ctx, cr, x, ref y, width, flags);
732+ render_title (ctx, cr, x, ref y, width);
733+ render_subtitle (ctx, cr, x, y, width);
734+ }
735+
736+ private void render_image (Gtk.StyleContext ctx, Cairo.Context cr, int x,
737+ ref int y, int width, Gtk.CellRendererState flags)
738+ {
739+ int image_width = compute_total_image_width ();
740+ int image_height = compute_total_image_height ();
741+ int offset = IMAGE_SHADOW_MARGIN;
742+
743+ // this cell renderer is not optimized for pixbufs of different dimensions
744+ if (shadow_buffer == null || image_width != last_image_width
745+ || image_height != last_image_height)
746+ {
747+ shadow_buffer = new Granite.Drawing.BufferSurface (image_width, image_height);
748+
749+ var context = shadow_buffer.context;
750+ context.rectangle (offset, offset, pixbuf.width, pixbuf.height);
751+ context.set_source_rgba (0, 0, 0, IMAGE_SHADOW_ALPHA);
752+ context.fill ();
753+ shadow_buffer.exponential_blur (IMAGE_SHADOW_RADIUS);
754+
755+ last_image_width = image_width;
756+ last_image_height = image_height;
757+ }
758+
759+ x += (width - image_width) / 2;
760+
761+ cr.set_source_surface (shadow_buffer.surface, x, y);
762+ cr.paint ();
763+
764+ Gdk.Pixbuf image;
765+ if (should_brighten_image (flags))
766+ image = get_brightened_pixbuf (pixbuf);
767+ else
768+ image = pixbuf;
769+
770+ ctx.render_icon (cr, image, x + offset, y + offset);
771+
772+ if (should_draw_highlight (flags)) {
773+ ctx.add_class (Gtk.STYLE_CLASS_IMAGE);
774+ ctx.render_frame (cr, x + offset - border.left,
775+ y + offset - border.top,
776+ pixbuf.width + border.left + border.right,
777+ pixbuf.height + border.top + border.bottom);
778+ }
779+
780+ y += image_height;
781+ }
782+
783+ private void render_title (Gtk.StyleContext ctx, Cairo.Context cr, int x,
784+ ref int y, int width)
785+ {
786+ // Center title layout horizontally
787+ int offset = (width - title_text_logical_rect.width) / 2;
788+ x += title_text_logical_rect.x + int.max (0, offset);
789+
790+ ctx.add_class ("title-text");
791+ ctx.render_layout (cr, x, y, title_text_layout);
792+ ctx.remove_class ("title-text");
793+
794+ y += title_text_logical_rect.height;
795+ }
796+
797+ private void render_subtitle (Gtk.StyleContext ctx, Cairo.Context cr, int x,
798+ int y, int width)
799+ {
800+ // Center title layout horizontally
801+ int offset = (width - subtitle_text_logical_rect.width) / 2;
802+ x += subtitle_text_logical_rect.x + int.max (0, offset);
803+
804+ ctx.render_layout (cr, x, y, subtitle_text_layout);
805+ }
806+
807+ private void update_layout_properties (Gtk.Widget widget) {
808+ var ctx = widget.get_style_context ();
809+ var state = ctx.get_state ();
810+
811+ ctx.save ();
812+ ctx.add_class (Gtk.STYLE_CLASS_IMAGE);
813+ margin = ctx.get_margin (state);
814+ padding = ctx.get_padding (state);
815+ border = ctx.get_border (state);
816+
817+ subtitle_text_layout = widget.create_pango_layout (subtitle);
818+ unowned Pango.FontDescription font_description;
819+ ctx.get (state, Gtk.STYLE_PROPERTY_FONT, out font_description);
820+ subtitle_text_layout.set_font_description (font_description);
821+ subtitle_text_layout.set_ellipsize (Pango.EllipsizeMode.END);
822+ subtitle_text_layout.set_alignment (Pango.Alignment.LEFT);
823+ int text_width = pixbuf.width * Pango.SCALE;
824+ subtitle_text_layout.set_width (text_width);
825+
826+ ctx.add_class ("title-text");
827+ title_text_layout = widget.create_pango_layout (title);
828+ ctx.get (state, Gtk.STYLE_PROPERTY_FONT, out font_description);
829+ title_text_layout.set_font_description (font_description);
830+ title_text_layout.set_width (text_width);
831+ title_text_layout.set_ellipsize (Pango.EllipsizeMode.END);
832+ title_text_layout.set_alignment (Pango.Alignment.LEFT);
833+ ctx.restore ();
834+
835+ Pango.Rectangle ink_rect;
836+ title_text_layout.get_pixel_extents (out ink_rect, out title_text_logical_rect);
837+ subtitle_text_layout.get_pixel_extents (out ink_rect, out subtitle_text_logical_rect);
838+ }
839+
840+ private int compute_total_image_width () {
841+ return pixbuf != null ? pixbuf.width + 2 * IMAGE_SHADOW_MARGIN : 0;
842+ }
843+
844+ private int compute_total_image_height () {
845+ return pixbuf != null ? pixbuf.height + 2 * IMAGE_SHADOW_MARGIN : 0;
846+ }
847+
848+ private static bool should_brighten_image (Gtk.CellRendererState flags) {
849+ return (flags & Gtk.CellRendererState.PRELIT) != 0;
850+ }
851+
852+ private static bool should_draw_highlight (Gtk.CellRendererState flags) {
853+ return (flags & Gtk.CellRendererState.SELECTED) != 0;
854+ }
855+
856+ private static Gdk.Pixbuf? get_brightened_pixbuf (Gdk.Pixbuf pixbuf) {
857+ if (pixbuf == null)
858+ return null;
859+
860+ // create a new lightened pixbuf to display
861+ var brightened = pixbuf.copy ();
862+ ImageUtils.shift_colors (brightened, BRIGHTEN_SHIFT, BRIGHTEN_SHIFT, BRIGHTEN_SHIFT, 0);
863+ return brightened;
864+ }
865+}
866
867=== added file 'src/Widgets/FastView/TileView/TileView.vala'
868--- src/Widgets/FastView/TileView/TileView.vala 1970-01-01 00:00:00 +0000
869+++ src/Widgets/FastView/TileView/TileView.vala 2013-09-26 03:02:55 +0000
870@@ -0,0 +1,70 @@
871+/**
872+ * Copyright 2013 elementary
873+ *
874+ * This software is licensed under the GNU Lesser General Public License
875+ * (version 3 or later). See the COPYING file in this distribution.
876+ */
877+
878+public class Noise.Widgets.TileView : Gtk.IconView {
879+ private const string STYLESHEET = """
880+ /* general background color and texture */
881+ .tile-view {
882+ color: alpha(@fg_color, 0.95);
883+ background-color: @base_color;
884+ }
885+
886+ /* workaround: suppress default cell borders for icon view */
887+ .tile-view.cell {
888+ background-image: none;
889+ background-color: @transparent;
890+ border-width: 0;
891+ border-style: solid;
892+ border-color: @transparent;
893+ box-shadow: inset 0 0 @transparent;
894+ }
895+
896+ /* image selection frame */
897+ .tile-view.cell.image {
898+ border-width: 3px;
899+ border-radius: 3px;
900+ border-color: alpha(@selected_bg_color, 0.95);
901+ }
902+
903+ /* apply bold font to titles */
904+ .tile-view.cell.title-text {
905+ font-weight: bold;
906+ color: @fg_color;
907+ }
908+ """;
909+
910+ private Gtk.CellRenderer cell_renderer = new TileRenderer ();
911+
912+ public int image_column {
913+ set {
914+ add_attribute (cell_renderer, "pixbuf", value);
915+ }
916+ }
917+
918+ public int title_column {
919+ set {
920+ add_attribute (cell_renderer, "title", value);
921+ }
922+ }
923+
924+ public int subtitle_column {
925+ set {
926+ add_attribute (cell_renderer, "subtitle", value);
927+ }
928+ }
929+
930+ public TileView () {
931+ pack_start (cell_renderer, false);
932+ apply_default_theme ();
933+ }
934+
935+ private void apply_default_theme () {
936+ get_style_context ().remove_class (Gtk.STYLE_CLASS_VIEW);
937+ Granite.Widgets.Utils.set_theming (this, STYLESHEET, "tile-view",
938+ Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
939+ }
940+}
941
942=== modified file 'src/Widgets/InfoPanel.vala'
943--- src/Widgets/InfoPanel.vala 2013-02-26 21:56:08 +0000
944+++ src/Widgets/InfoPanel.vala 2013-09-26 03:02:55 +0000
945@@ -63,7 +63,6 @@
946 title = new Gtk.Label("");
947 artist = new Gtk.Label("");
948 coverArt = new Gtk.Image();
949- coverArt.set_size_request (Icons.ALBUM_VIEW_IMAGE_SIZE, Icons.ALBUM_VIEW_IMAGE_SIZE);
950 rating = new Granite.Widgets.Rating (true, Gtk.IconSize.MENU, true); // centered = true
951 album = new Gtk.Label("");
952 year_label = new Gtk.Label("");
953@@ -138,8 +137,11 @@
954 }
955
956 private void update_cover_art () {
957- if (current_media != null)
958- coverArt.set_from_pixbuf (CoverartCache.instance.get_cover (current_media));
959+ if (current_media != null) {
960+ var cover_art = CoverartCache.instance.get_cover (current_media);
961+ var cover_art_with_shadow = PixbufUtils.render_pixbuf_shadow (cover_art);
962+ coverArt.set_from_pixbuf (cover_art_with_shadow);
963+ }
964 }
965
966 private void ratingChanged (int new_rating) {

Subscribers

People subscribed via source and target branches