Merge lp:~victored/noise/new-album-view into lp:~elementary-apps/noise/trunk
- new-album-view
- Merge into trunk
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 | ||||
Related bugs: |
|
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.
Victor Martinez (victored) wrote : | # |
David Gomes (davidgomes) wrote : | # |
We'll merge this when we have Saucy builds and are officially using GTK+ 3.8+-
- 1518. By Victor Martinez
-
Fix coding style issue
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
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' |
147 | Binary 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) { |
Please note this code is not supposed to work correctly on Luna, but on GTK+ 3.8 or newer (Ubuntu 13.04).