Movie window: display cast information
[cinaest] / src / movie-window.vala
index 1eecbd4..42409dd 100644 (file)
@@ -23,10 +23,18 @@ public class MovieWindow : StackableWindow {
        private MovieMenu menu;
        private Gdk.Pixbuf no_poster;
        private MoviePoster.Factory poster_factory;
+       private HBox hbox;
        private Image image;
+       private VBox details;
+       private PannableArea pannable;
+       private Label title_label;
+       private Label rating_label;
+       private Label cast_label;
+       private Label plot;
+       private bool portrait_mode;
 
        public MovieWindow.with_movie (Movie movie, MovieListStore store) {
-               set_title (movie.title);
+               update_title (movie);
 
                // View menu
                menu = new MovieMenu (movie, store, this);
@@ -35,69 +43,197 @@ public class MovieWindow : StackableWindow {
 
                // Poster
                image = new Image ();
-               image.set_size_request (268, 424);
 
-               if (movie.poster != null && movie.poster.pixbuf != null) {
-                       image.pixbuf = movie.poster.pixbuf;
+               title_label = new Label (title_label_markup (movie));
+               title_label.wrap = true;
+               title_label.use_markup = true;
+               title_label.set_alignment (0.0f, 0.0f);
+
+               var header = new HBox (false, 0);
+               header.pack_start (title_label, true, true, 0);
+
+               rating_label = new Label (rating_label_markup (movie));
+               rating_label.use_markup = true;
+               rating_label.set_alignment (0.5f, 0.0f);
+               header.pack_start (rating_label, false, false, MARGIN_DOUBLE);
+
+               cast_label = new Label (cast_label_markup (movie));
+               cast_label.wrap = true;
+               cast_label.use_markup = true;
+               cast_label.set_alignment (0.0f, 0.0f);
+
+               plot = new Label (movie.get_plot ());
+               plot.wrap = true;
+               plot.set_alignment (0.0f, 0.0f);
+
+               details = new VBox (false, MARGIN_DOUBLE);
+               details.pack_start (header, false, false, 0);
+               details.pack_start (cast_label, false, false, 0);
+               details.pack_start (plot, false, false, 0);
+
+               var pannable = new PannableArea ();
+               var eventbox = new EventBox ();
+               eventbox.add (details);
+               eventbox.above_child = true;
+               pannable.add_with_viewport (eventbox);
+
+               hbox = new HBox (false, 0);
+               hbox.pack_start (pannable, true, true, 0);
+
+               portrait_mode = CinaestProgram.orientation.portrait;
+               if (portrait_mode) {
+                       details.pack_start (image, false, false, 0);
+                       details.reorder_child (image, 0);
+                       plot.set_size_request (480 - 2 * MARGIN_DOUBLE, -1);
                } else {
-                       movie.notify.connect (this.on_movie_changed);
-                       if (movie.poster != null && movie.poster.thumbnail != null) {
+                       hbox.pack_start (image, false, false, MARGIN_DOUBLE);
+                       hbox.reorder_child (image, 0);
+                       plot.set_size_request (800 - 288 /* image */ - 3 * MARGIN_DOUBLE, -1);
+                       pannable.set_size_request (-1, 424);
+               }
+
+               hbox.show_all ();
+               add (hbox);
+
+               // Connect signals
+               menu.movie_deleted.connect (() => { destroy (); });
+               Gdk.Screen.get_default ().size_changed.connect (on_orientation_changed);
+               movie.notify.connect (this.on_movie_changed);
+
+               if (movie.poster != null && movie.poster.large != null) {
+                       image.pixbuf = movie.poster.large;
+               } else {
+                       if (movie.poster != null && movie.poster.small != null) {
                                // FIXME
-                               image.pixbuf = movie.poster.thumbnail.scale_simple (244, 400, Gdk.InterpType.BILINEAR);
+                               image.pixbuf = movie.poster.small.scale_simple (288, 400, Gdk.InterpType.HYPER);
                        } else {
                                // FIXME
                                if (no_poster == null) try {
-                                       no_poster = new Gdk.Pixbuf.from_file ("/usr/share/icons/hicolor/124x124/hildon/general_video.png");
+                                       no_poster = new Gdk.Pixbuf.from_file ("/usr/share/icons/hicolor/64x64/hildon/general_no_thumbnail.png");
                                } catch (Error e) {
-                                       critical ("Missing general_video icon: %s\n", e.message);
+                                       critical ("Missing general_no_thumbnail icon: %s\n", e.message);
                                }
                                image.pixbuf = no_poster;
                        }
                        try {
                                poster_factory = MoviePoster.Factory.get_instance ();
-                               poster_factory.queue (movie, receive_poster);
+                               poster_factory.queue (movie, 288, 400, false, receive_poster);
                        } catch (Error e) {
                                warning ("Failed to queue poster request: %s\n", e.message);
                        }
                }
+       }
 
-               // Text area
-               string genres = movie.genres.to_string ();
-               string year = movie.year > 0 ? " (%d)".printf (movie.year) : "";
-               string text = "<b>%s</b>%s".printf (genres, year);
+       private void update_title (Movie movie) {
+               Gdk.Color color;
+               this.ensure_style ();
+               if (this.style.lookup_color ("SecondaryTextColor", out color))
+                       set_markup ("%s <span size=\"small\" fgcolor=\"%s\">(%d)</span>".printf (movie.title, color.to_string (), movie.year));
+               else
+                       set_markup ("%s <small>(%d)</small>".printf (movie.title, movie.year));
+       }
 
-               var label = new Label (text);
-               label.wrap = true;
-               label.use_markup = true;
-               label.set_alignment (0.0f, 0.0f);
+       private string title_label_markup (Movie movie) {
+               Gdk.Color color;
+               this.ensure_style ();
+               string year = "";
+               if (this.style.lookup_color ("SecondaryTextColor", out color)) {
+                       if (movie.year > 0)
+                               year = " <span fgcolor=\"%s\">(%d)</span>".printf (color.to_string (), movie.year);
+                       return "<big><b>%s</b></big>%s\n<span size=\"small\" fgcolor=\"%s\">%s</span>".printf (movie.title, year, color.to_string (), movie.secondary);
+               } else {
+                       if (movie.year > 0)
+                               year = " (%d)".printf (movie.year);
+                       return "<big><b>%s</b></big>%s\n<small>%s</small>".printf (movie.title, year, movie.secondary);
+               }
+       }
 
-               var hbox = new HBox (false, 0);
-               hbox.pack_start (image, false, true, 0);
-               hbox.pack_start (label, true, true, MARGIN_DOUBLE);
+       private string rating_label_markup (Movie movie) {
+               if (movie.rating > 0)
+                       return "<big><b>%d.%d</b></big>".printf (movie.rating / 10, movie.rating % 10);
+               else
+                       return "";
+       }
 
-               var vbox = new VBox (false, 0);
-               vbox.pack_start (hbox, true, true, MARGIN_DOUBLE);
+       private string cast_label_markup (Movie movie) {
+               List<Role> cast = movie.get_cast ();
+               var markup = new StringBuilder ();
+               Gdk.Color color;
+               this.ensure_style ();
+
+               if (this.style.lookup_color ("SecondaryTextColor", out color)) {
+                       foreach (Role role in cast) {
+                               if (markup.len > 0)
+                                       markup.append (",\n");
+                               markup.append_printf ("%s <span size=\"small\" fgcolor=\"%s\">(%s)</span>", display_name (role.actor_name), color.to_string (), role.character);
+                       }
+               } else {
+                       foreach (Role role in cast) {
+                               if (markup.len > 0)
+                                       markup.append (",\n");
+                               markup.append_printf ("%s <small>(%s)</small>", display_name (role.actor_name), role.character);
+                       }
+               }
 
-               add (vbox);
+               return markup.str;
+       }
 
-               // Connect signals
-               menu.movie_deleted.connect (() => { destroy (); });
+       private string display_name (string name) {
+               string[] parts;
+               if (name.has_suffix (")"))
+                       parts = name.ndup (name.length - 4).split (", ");
+               else
+                       parts = name.split (", ");
+               if (parts.length == 2) {
+                       return parts[1] + " " + parts[0];
+               } else {
+                       return name;
+               }
        }
 
        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 == "title") || (spec.name == "year")) {
+                       update_title (movie);
+                       title_label.set_markup (title_label_markup (movie));
+               }
+               if (spec.name == "rating") {
+                       rating_label.set_markup (rating_label_markup (movie));
+               }
+               if ((spec.name == "poster") && (movie.poster != null) && (movie.poster.large != null)) {
+                       image.pixbuf = movie.poster.large;
+               }
+       }
+
+       private void on_orientation_changed (Gdk.Screen screen) {
+               if (CinaestProgram.orientation.portrait == portrait_mode)
+                       return;
+
+               portrait_mode = CinaestProgram.orientation.portrait;
+               if (portrait_mode) {
+                       hbox.remove (image);
+                       details.pack_start (image, false, false, 0);
+                       details.reorder_child (image, 0);
+                       plot.set_size_request (480 - 2 * MARGIN_DOUBLE, -1);
+                       pannable.set_size_request (-1, -1);
+               } else {
+                       details.remove (image);
+                       hbox.pack_start (image, false, false, MARGIN_DOUBLE);
+                       hbox.reorder_child (image, 0);
+                       pannable.set_size_request (-1, 424);
+                       plot.set_size_request (800 - 288 /* image */ - 3 * MARGIN_DOUBLE, -1);
                }
        }
 }