From aa6cf09a74f2683008653d134988c13ba903a659 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 4 Aug 2010 23:57:08 +0200 Subject: [PATCH] Movie list view: add poster view mode, shows a 5x2 poster grid --- src/movie-list-menu.vala | 10 ++++ src/movie-list-store.vala | 28 ++++++++-- src/movie-list-view.vala | 124 +++++++++++++++++++++++++++++++++++--------- src/movie-list-window.vala | 31 +++-------- src/movie-window.vala | 20 +++---- src/movie.vala | 10 +++- 6 files changed, 160 insertions(+), 63 deletions(-) diff --git a/src/movie-list-menu.vala b/src/movie-list-menu.vala index ea5cc4b..dc7fa18 100644 --- a/src/movie-list-menu.vala +++ b/src/movie-list-menu.vala @@ -26,6 +26,7 @@ public class MovieListMenu : AppMenu { private Hildon.Button filter_year; private Hildon.Button filter_rating; private Hildon.Button filter_genres; + private Gtk.Button poster_view; private Gtk.Button delete_movies; private Gtk.Button import_movies; @@ -71,6 +72,7 @@ public class MovieListMenu : AppMenu { filter_year = new Hildon.Button.with_text (SizeType.FINGER_HEIGHT, ButtonArrangement.VERTICAL, _("Filter by year"), _("Off")); filter_rating = new Hildon.Button.with_text (SizeType.FINGER_HEIGHT, ButtonArrangement.VERTICAL, _("Filter by rating"), _("Off")); filter_genres = new Hildon.Button.with_text (SizeType.FINGER_HEIGHT, ButtonArrangement.VERTICAL, _("Filter by genres"), _("Off")); + poster_view = new Gtk.Button.with_label (_("Poster view")); delete_movies = new Gtk.Button.with_label (_("Delete movies")); import_movies = new Gtk.Button.with_label (_("Import movies")); var settings = new Gtk.Button.with_label (_("Settings")); @@ -83,6 +85,7 @@ public class MovieListMenu : AppMenu { filter_year.clicked.connect (on_filter_year_clicked); filter_rating.clicked.connect (on_filter_rating_clicked); filter_genres.clicked.connect (on_filter_genres_clicked); + poster_view.clicked.connect (on_poster_view_clicked); delete_movies.clicked.connect (() => { movie_list_window.on_delete_movies_clicked (); }); import_movies.clicked.connect (on_import_movies_clicked); settings.clicked.connect (on_settings_clicked); @@ -90,6 +93,7 @@ public class MovieListMenu : AppMenu { append (filter_year); append (filter_rating); append (filter_genres); + append (poster_view); append (delete_movies); append (import_movies); append (settings); @@ -203,6 +207,12 @@ public class MovieListMenu : AppMenu { } } + public void on_poster_view_clicked (Gtk.Button button) { + var poster_mode = movie_list_window.get_movie_list_view ().poster_mode; + movie_list_window.get_movie_list_view ().poster_mode = !poster_mode; + poster_view.set_label (poster_mode ? _("Poster view") : _("List view")); + } + public void on_import_movies_clicked (Gtk.Button button) { var dialog = new Gtk.Dialog (); dialog.set_transient_for (movie_list_window); diff --git a/src/movie-list-store.vala b/src/movie-list-store.vala index 852690f..cd26e0e 100644 --- a/src/movie-list-store.vala +++ b/src/movie-list-store.vala @@ -24,6 +24,7 @@ public class MovieListStore : ListStore, TreeModel { YEAR, RATING, POSTER, + ICON, MOVIE, MARKUP, N_COLUMNS @@ -33,6 +34,7 @@ public class MovieListStore : ListStore, TreeModel { typeof (int), typeof (string), typeof (Gdk.Pixbuf), + typeof (Gdk.Pixbuf), typeof (Movie), typeof (string) }; @@ -182,16 +184,25 @@ public class MovieListStore : ListStore, TreeModel { foreach (Movie movie in movies) { add (movie, out iter); try { - poster_factory.queue_thumbnail (movie, 64, 64, false, receive_poster_thumbnail); + poster_factory.queue_thumbnail (movie, Poster.ICON_WIDTH, Poster.ICON_HEIGHT, false, receive_poster_icon); + poster_factory.queue_thumbnail (movie, Poster.SMALL_WIDTH, Poster.SMALL_HEIGHT, false, receive_poster_small); } catch (Error e) { warning ("Failed to queue poster request: %s\n", e.message); } } } - private void receive_poster_thumbnail (Gdk.Pixbuf pixbuf, Movie movie) { + private void receive_poster_icon (Gdk.Pixbuf pixbuf, Movie movie) { + var poster = new Poster (); + poster.icon = pixbuf; + movie.poster = poster; + } + + private void receive_poster_small (Gdk.Pixbuf pixbuf, Movie movie) { var poster = new Poster (); - poster.thumbnail = pixbuf; + if (movie.poster != null && movie.poster.icon != null) + poster.icon = movie.poster.icon; + poster.small = pixbuf; movie.poster = poster; } @@ -247,8 +258,15 @@ public class MovieListStore : ListStore, TreeModel { break; case Columns.POSTER: - if ((movie.poster != null) && (movie.poster.thumbnail != null)) - value.set_object (movie.poster.thumbnail); + if ((movie.poster != null) && (movie.poster.small != null)) + value.set_object (movie.poster.small); + else + value.set_object (no_poster); + break; + + case Columns.ICON: + if ((movie.poster != null) && (movie.poster.icon != null)) + value.set_object (movie.poster.icon); else value.set_object (no_poster); break; diff --git a/src/movie-list-view.vala b/src/movie-list-view.vala index 87e67c1..d21b965 100644 --- a/src/movie-list-view.vala +++ b/src/movie-list-view.vala @@ -22,6 +22,7 @@ using Hildon; public class MovieListView : PannableArea { public MovieListStore store; TreeView tree; + IconView icons; private bool more_movies_available; private CellRendererText title_renderer; @@ -29,23 +30,29 @@ public class MovieListView : PannableArea { private CellRendererText rating_renderer; private CellRendererText date_renderer; - public signal void movie_activated (Movie movie); - - public MovieListView (Gtk.Window window, bool show_date = false) { - store = new MovieListStore (); - - Gdk.Color color; - window.ensure_style (); - if (window.style.lookup_color ("SecondaryTextColor", out color)) { - store.year_markup = "(%%d)".printf (color.to_string ()); + private bool poster_mode_; + public bool poster_mode { + get { + return poster_mode_; + } + set { + if (value & !poster_mode_) { + remove (tree); + add (icons); + } else if (!value & poster_mode_) { + remove (icons); + add (tree); + } + poster_mode_ = value; } + } + + public signal void movie_activated (Movie movie); + private Gtk.TreeView create_treeview (Gtk.Window window, bool show_date) { // Tree View - tree = (TreeView) Hildon.gtk_tree_view_new_with_model (UIMode.NORMAL, store); + var tree = (TreeView) Hildon.gtk_tree_view_new_with_model (UIMode.NORMAL, store); tree.set_headers_visible (false); - - add (tree); - tree.set_rules_hint (true); // Tree selection object @@ -65,7 +72,7 @@ public class MovieListView : PannableArea { pixbuf_renderer.width = 64; pixbuf_renderer.xalign = 0.0f; title_column.pack_start (pixbuf_renderer, false); - title_column.add_attribute (pixbuf_renderer, "pixbuf", MovieListStore.Columns.POSTER); + title_column.add_attribute (pixbuf_renderer, "pixbuf", MovieListStore.Columns.ICON); // Add text to column var vbox_renderer = new CellRendererVBox (); @@ -89,9 +96,6 @@ public class MovieListView : PannableArea { tree.append_column (title_column); - // Sort by title - store.set_sort_column_id (MovieListStore.Columns.TITLE, SortType.ASCENDING); - // Year column var year_column = new TreeViewColumn (); year_column.set_title (_("Year")); @@ -128,29 +132,67 @@ public class MovieListView : PannableArea { rating_column.set_cell_data_func (vbox_renderer, rating_data_func); tree.append_column (rating_column); + tree.show (); + return tree; + } + + private Gtk.IconView create_iconview () { + var iconview = (Gtk.IconView) Hildon.gtk_icon_view_new_with_model (Hildon.UIMode.NORMAL, store); + iconview.set_column_spacing (0); + iconview.set_pixbuf_column (MovieListStore.Columns.POSTER); + iconview.margin = 0; + iconview.item_width = Poster.SMALL_WIDTH; + iconview.column_spacing = Hildon.MARGIN_HALF; + iconview.row_spacing = Hildon.MARGIN_HALF; + iconview.show (); + + return iconview; + } + + public MovieListView (Gtk.Window window, bool show_date = false) { + store = new MovieListStore (); + + // Sort by title + store.set_sort_column_id (MovieListStore.Columns.TITLE, SortType.ASCENDING); + + Gdk.Color color; + window.ensure_style (); + if (window.style.lookup_color ("SecondaryTextColor", out color)) { + store.year_markup = "(%%d)".printf (color.to_string ()); + } + + tree = create_treeview (window, show_date); + + icons = create_iconview (); + + add (tree); // Connect signals get_vadjustment ().value_changed.connect (on_adjustment_value_changed); tree.row_activated.connect (on_row_activated); + icons.item_activated.connect (on_item_activated); store.search_finished.connect (on_search_finished); } + construct { + hscrollbar_policy = Gtk.PolicyType.NEVER; + } + public void set_hildon_ui_mode (UIMode mode) { var selection = tree.get_selection (); if (mode == UIMode.NORMAL) { selection.set_mode (SelectionMode.NONE); + icons.set_selection_mode (SelectionMode.NONE); } Hildon.gtk_tree_view_set_ui_mode (tree, mode); + Hildon.gtk_icon_view_set_ui_mode (icons, mode); if (mode == UIMode.EDIT) { selection.set_mode (SelectionMode.MULTIPLE); + icons.set_selection_mode (SelectionMode.MULTIPLE); } } - public unowned TreeSelection get_selection () { - return tree.get_selection (); - } - private Pango.AttrList get_attributes (Gtk.Window window, string font_name, string color_name) { Pango.AttrList attr_list = new Pango.AttrList (); var style = Gtk.rc_get_style_by_paths (Gtk.Settings.get_default (), font_name, null, typeof (void)); @@ -167,6 +209,37 @@ public class MovieListView : PannableArea { return attr_list; } + public void unselect_all () { + tree.get_selection ().unselect_all (); + icons.unselect_all (); + } + + public List get_selected_movies () { + var movies = new List (); + List paths; + + if (poster_mode_) + paths = icons.get_selected_items (); + else + paths = tree.get_selection ().get_selected_rows (null); + + // get selected movies from the store + foreach (TreePath path in paths) { + TreeIter iter; + + if (store.get_iter (out iter, path)) { + Movie movie; + + store.get (iter, MovieListStore.Columns.MOVIE, out movie); + if (movie != null) { + movies.append (movie); + } + } + } + + return movies; + } + // TODO: after scrolling down 80% of the list, load more // results if available. private void on_adjustment_value_changed () { @@ -180,12 +253,15 @@ public class MovieListView : PannableArea { } private void on_row_activated (TreeView tree, TreePath path, TreeViewColumn column) { - TreeModel model = tree.model; + on_item_activated (path); + } + + private void on_item_activated (TreePath path) { TreeIter iter; - if (model.get_iter (out iter, path)) { + if (store.get_iter (out iter, path)) { Movie movie; - model.get (iter, MovieListStore.Columns.MOVIE, out movie); + store.get (iter, MovieListStore.Columns.MOVIE, out movie); movie_activated (movie); } } diff --git a/src/movie-list-window.vala b/src/movie-list-window.vala index acc9bce..133451a 100644 --- a/src/movie-list-window.vala +++ b/src/movie-list-window.vala @@ -161,13 +161,12 @@ public class MovieListWindow : StackableWindow { edit_toolbar.show (); movie_list.set_hildon_ui_mode (UIMode.EDIT); - var selection = movie_list.get_selection (); - selection.unselect_all (); + movie_list.unselect_all (); } private void on_delete_button_clicked () { - var selection = movie_list.get_selection (); - int count = selection.count_selected_rows (); + var movies = movie_list.get_selected_movies (); + int count = (int) movies.length (); if (count == 0) { Banner.show_information (this, null, _("No movies selected")); leave_edit_mode (); @@ -178,25 +177,7 @@ public class MovieListWindow : StackableWindow { var res = dialog.run (); if (res == Gtk.ResponseType.OK) { - weak TreeModel model; - var rows = selection.get_selected_rows (out model); - - var movies = new List (); - - // get selected movies from the store - foreach (TreePath path in rows) { - TreeIter iter; - - if (model.get_iter (out iter, path)) { - Movie movie; - - model.get (iter, MovieListStore.Columns.MOVIE, out movie); - if (movie != null) { - movies.append (movie); - } - } - } - // and remove them + // Remove selected movies foreach (Movie movie in movies) { store.remove (movie); } @@ -295,5 +276,9 @@ public class MovieListWindow : StackableWindow { no_movies.show (); } } + + public unowned MovieListView get_movie_list_view () { + return movie_list; + } } diff --git a/src/movie-window.vala b/src/movie-window.vala index 0aef805..82a2511 100644 --- a/src/movie-window.vala +++ b/src/movie-window.vala @@ -41,13 +41,13 @@ public class MovieWindow : StackableWindow { // Poster image = new Image (); - if (movie.poster != null && movie.poster.pixbuf != null) { - image.pixbuf = movie.poster.pixbuf; + if (movie.poster != null && movie.poster.large != null) { + image.pixbuf = movie.poster.large; } else { movie.notify.connect (this.on_movie_changed); - if (movie.poster != null && movie.poster.thumbnail != null) { + if (movie.poster != null && movie.poster.icon != null) { // FIXME - image.pixbuf = movie.poster.thumbnail.scale_simple (268, 424, Gdk.InterpType.BILINEAR); + image.pixbuf = movie.poster.icon.scale_simple (268, 424, Gdk.InterpType.BILINEAR); } else { // FIXME if (no_poster == null) try { @@ -123,17 +123,19 @@ public class MovieWindow : StackableWindow { private void receive_poster (Gdk.Pixbuf pixbuf, Movie movie) { var poster = new Poster(); - poster.pixbuf = pixbuf; - if (movie.poster != null) - poster.thumbnail = movie.poster.thumbnail; + poster.large = pixbuf; + if (movie.poster != null) { + poster.icon = movie.poster.icon; + poster.small = movie.poster.small; + } movie.poster = poster; } private void on_movie_changed (GLib.Object source, GLib.ParamSpec spec) { var movie = (Movie) source; - if ((spec.name == "poster") && (movie.poster != null) && (movie.poster.pixbuf != null)) { - image.pixbuf = movie.poster.pixbuf; + if ((spec.name == "poster") && (movie.poster != null) && (movie.poster.large != null)) { + image.pixbuf = movie.poster.large; } } diff --git a/src/movie.vala b/src/movie.vala index 5571802..1751a31 100644 --- a/src/movie.vala +++ b/src/movie.vala @@ -17,8 +17,14 @@ */ public class Poster : Object { - public Gdk.Pixbuf pixbuf; - public Gdk.Pixbuf thumbnail; + public const int SMALL_WIDTH = (800 - 2*Hildon.MARGIN_DOUBLE - 4*Hildon.MARGIN_HALF)/5; + public const int SMALL_HEIGHT = (420 - Hildon.MARGIN_HALF)/2; + public const int ICON_WIDTH = 46; + public const int ICON_HEIGHT = 64; + + public Gdk.Pixbuf large; + public Gdk.Pixbuf small; + public Gdk.Pixbuf icon; } public class Movie : Object { -- 1.7.9.5