Commit 156db6b8 authored by Jim Nelson's avatar Jim Nelson

#305: Base slideshow functionality.

parent f0174d4d
......@@ -20,15 +20,15 @@ public class FullscreenWindow : Gtk.Window {
private Gtk.Window toolbar_window = new Gtk.Window(Gtk.WindowType.POPUP);
private Gtk.UIManager ui = new Gtk.UIManager();
private PhotoPage photo_page;
private Page page;
private Gtk.ToolButton close_button = new Gtk.ToolButton.from_stock(Gtk.STOCK_LEAVE_FULLSCREEN);
private Gtk.ToggleToolButton pin_button = new Gtk.ToggleToolButton.from_stock(Resources.PIN_TOOLBAR);
private bool is_toolbar_shown = false;
private bool waiting_for_invoke = false;
private time_t left_toolbar_time = 0;
public FullscreenWindow(Gdk.Screen screen, CheckerboardPage controller, Thumbnail start) {
photo_page = new PhotoPage(this);
public FullscreenWindow(Page page) {
this.page = page;
File ui_file = Resources.get_ui("fullscreen.ui");
......@@ -47,7 +47,7 @@ public class FullscreenWindow : Gtk.Window {
if (accel_group != null)
add_accel_group(accel_group);
set_screen(screen);
set_screen(AppWindow.get_instance().get_screen());
set_border_width(0);
pin_button.set_label("Pin Toolbar");
......@@ -57,7 +57,7 @@ public class FullscreenWindow : Gtk.Window {
close_button.set_tooltip_text("Leave fullscreen");
close_button.clicked += on_close;
Gtk.Toolbar toolbar = photo_page.get_toolbar();
Gtk.Toolbar toolbar = page.get_toolbar();
toolbar.set_show_arrow(false);
toolbar.insert(pin_button, -1);
toolbar.insert(close_button, -1);
......@@ -67,7 +67,7 @@ public class FullscreenWindow : Gtk.Window {
toolbar_window.set_border_width(0);
toolbar_window.add(toolbar);
add(photo_page);
add(page);
// need to do this to create a Gdk.Window to set masks
fullscreen();
......@@ -83,15 +83,14 @@ public class FullscreenWindow : Gtk.Window {
// start off with toolbar invoked, as a clue for the user
invoke_toolbar();
photo_page.display(controller, start);
photo_page.switched_to();
page.switched_to();
}
private void on_close() {
toolbar_window.hide();
toolbar_window = null;
photo_page.switching_from();
page.switching_from();
AppWindow.get_instance().end_fullscreen();
}
......@@ -111,15 +110,15 @@ public class FullscreenWindow : Gtk.Window {
}
private bool on_key_pressed(Gdk.EventKey event) {
return (event.is_modifier != 0) ? photo_page.notify_modifier_pressed(event) : false;
return (event.is_modifier != 0) ? page.notify_modifier_pressed(event) : false;
}
private bool on_key_released(Gdk.EventKey event) {
return (event.is_modifier != 0) ? photo_page.notify_modifier_released(event) : false;
return (event.is_modifier != 0) ? page.notify_modifier_released(event) : false;
}
private bool on_configured(Gdk.EventConfigure event) {
return photo_page.notify_configure_event(event);
return page.notify_configure_event(event);
}
private bool is_pointer_in_toolbar() {
......@@ -436,7 +435,8 @@ public class AppWindow : Gtk.Window {
// prepare the default parent and orphan pages
collection_page = new CollectionPage();
events_directory_page = new EventsDirectoryPage();
photo_page = new PhotoPage(this);
photo_page = new PhotoPage();
photo_page.set_container(this);
// create Photo objects for all photos in the database and load into the Photos page
Gee.ArrayList<PhotoID?> photo_ids = photo_table.get_photos();
......@@ -566,36 +566,51 @@ public class AppWindow : Gtk.Window {
}
private void on_fullscreen() {
if (fullscreen_window != null) {
fullscreen_window.present();
return;
}
CheckerboardPage controller = null;
Thumbnail start = null;
if (current_page is CheckerboardPage) {
LayoutItem item = ((CheckerboardPage) current_page).get_fullscreen_photo();
if (item == null) {
debug("No fullscreen photo for this view");
message("No fullscreen photo for this view");
return;
}
// needs to be a thumbnail
assert(item is Thumbnail);
// set up fullscreen view and hide ourselves until it's closed
fullscreen_window = new FullscreenWindow(get_screen(), (CheckerboardPage) current_page,
(Thumbnail) item);
controller = (CheckerboardPage) current_page;
start = (Thumbnail) item;
} else if (current_page is PhotoPage) {
fullscreen_window = new FullscreenWindow(get_screen(), ((PhotoPage) current_page).get_controller(),
((PhotoPage) current_page).get_thumbnail());
controller = ((PhotoPage) current_page).get_controller();
start = ((PhotoPage) current_page).get_thumbnail();
} else {
error("Unable to present fullscreen view for this page");
message("Unable to present fullscreen view for this page");
return;
}
if (controller == null || start == null)
return;
PhotoPage fs_photo = new PhotoPage();
FullscreenWindow fs_window = new FullscreenWindow(fs_photo);
fs_photo.set_container(fs_window);
fs_photo.display(controller, start);
go_fullscreen(fs_window);
}
public void go_fullscreen(FullscreenWindow fullscreen_window) {
// if already fullscreen, use that
if (this.fullscreen_window != null) {
this.fullscreen_window.present();
return;
}
current_page.switching_to_fullscreen();
fullscreen_window.present();
this.fullscreen_window = fullscreen_window;
this.fullscreen_window.present();
hide();
}
......
......@@ -4,6 +4,140 @@
* See the COPYING file in this distribution.
*/
class SlideshowPage : SinglePhotoPage {
public static const int DELAY_SEC = 3;
private static const int CHECK_ADVANCE_MSEC = 250;
private CheckerboardPage controller;
private Thumbnail thumbnail;
private Gtk.Toolbar toolbar = new Gtk.Toolbar();
private Gtk.ToolButton play_pause_button;
private Timer timer = new Timer();
private bool playing = true;
private bool exiting = false;
public SlideshowPage(CheckerboardPage controller, Thumbnail start) {
base("Slideshow");
this.controller = controller;
this.thumbnail = start;
// add toolbar buttons
Gtk.ToolButton previous_button = new Gtk.ToolButton.from_stock(Gtk.STOCK_GO_BACK);
previous_button.set_label("Back");
previous_button.set_tooltip_text("Go to the previous photo");
previous_button.clicked += on_previous;
toolbar.insert(previous_button, -1);
play_pause_button = new Gtk.ToolButton.from_stock(Gtk.STOCK_MEDIA_PAUSE);
play_pause_button.set_label("Pause");
play_pause_button.set_tooltip_text("Pause the slideshow");
play_pause_button.clicked += on_play_pause;
toolbar.insert(play_pause_button, -1);
Gtk.ToolButton next_button = new Gtk.ToolButton.from_stock(Gtk.STOCK_GO_FORWARD);
next_button.set_label("Next");
next_button.set_tooltip_text("Go to the next photo");
next_button.clicked += on_next;
toolbar.insert(next_button, -1);
}
public override Gtk.Toolbar get_toolbar() {
return toolbar;
}
public override void switched_to() {
set_pixbuf(thumbnail.get_photo().get_pixbuf());
Timeout.add(CHECK_ADVANCE_MSEC, auto_advance);
timer.start();
}
public override void switching_from() {
exiting = true;
}
private void on_play_pause() {
if (playing) {
play_pause_button.set_stock_id(Gtk.STOCK_MEDIA_PLAY);
play_pause_button.set_label("Play");
play_pause_button.set_tooltip_text("Continue the slideshow");
} else {
play_pause_button.set_stock_id(Gtk.STOCK_MEDIA_PAUSE);
play_pause_button.set_label("Pause");
play_pause_button.set_tooltip_text("Pause the slideshow");
}
playing = !playing;
// reset the timer
timer.start();
}
private void on_previous() {
thumbnail = (Thumbnail) controller.get_previous_item(thumbnail);
set_pixbuf(thumbnail.get_photo().get_pixbuf());
// reset the timer
timer.start();
}
private void on_next() {
thumbnail = (Thumbnail) controller.get_next_item(thumbnail);
set_pixbuf(thumbnail.get_photo().get_pixbuf());
// reset the timer
timer.start();
}
private bool auto_advance() {
if (exiting)
return false;
if (!playing)
return true;
if ((int) timer.elapsed() < DELAY_SEC)
return true;
on_next();
return true;
}
private override bool key_press_event(Gdk.EventKey event) {
bool handled = true;
switch (Gdk.keyval_name(event.keyval)) {
case "space":
on_play_pause();
break;
case "Left":
case "KP_Left":
on_previous();
break;
case "Right":
case "KP_Right":
on_next();
break;
default:
handled = false;
break;
}
if (handled)
return true;
return (base.key_press_event != null) ? base.key_press_event(event) : true;
}
}
public class CollectionPage : CheckerboardPage {
public static const int SORT_BY_MIN = 0;
public static const int SORT_BY_NAME = 0;
......@@ -63,6 +197,7 @@ public class CollectionPage : CheckerboardPage {
private Gtk.Toolbar toolbar = new Gtk.Toolbar();
private Gtk.HScale slider = null;
private Gtk.ToolButton rotate_button = null;
private Gtk.ToolButton slideshow_button = null;
private int scale = Thumbnail.DEFAULT_SCALE;
private bool improval_scheduled = false;
private bool reschedule_improval = false;
......@@ -84,6 +219,7 @@ public class CollectionPage : CheckerboardPage {
{ "RotateCounterclockwise", Resources.COUNTERCLOCKWISE, "Rotate _Left", "<Ctrl><Shift>R", "Rotate the selected photos counterclockwise", on_rotate_counterclockwise },
{ "Mirror", Resources.MIRROR, "_Mirror", "<Ctrl>M", "Make mirror images of the selected photos", on_mirror },
{ "Revert", Gtk.STOCK_REVERT_TO_SAVED, "Re_vert to Original", null, "Revert to original photo", on_revert },
{ "Slideshow", Gtk.STOCK_MEDIA_PLAY, "_Slideshow", "F5", "Play a slideshow", on_slideshow },
{ "ViewMenu", null, "_View", null, null, on_view_menu },
{ "SortPhotos", Gtk.STOCK_SORT_ASCENDING, "_Sort Photos", null, null, null },
......@@ -140,6 +276,15 @@ public class CollectionPage : CheckerboardPage {
toolbar.insert(rotate_button, -1);
// slideshow button
slideshow_button = new Gtk.ToolButton.from_stock(Gtk.STOCK_MEDIA_PLAY);
slideshow_button.set_label("Slideshow");
slideshow_button.set_tooltip_text("Start a slideshow of these photos");
slideshow_button.sensitive = false;
slideshow_button.clicked += on_slideshow;
toolbar.insert(slideshow_button, -1);
// separator to force slider to right side of toolbar
Gtk.SeparatorToolItem separator = new Gtk.SeparatorToolItem();
separator.set_expand(true);
......@@ -335,12 +480,16 @@ public class CollectionPage : CheckerboardPage {
thumbnail.display_title(display_titles());
add_item(thumbnail);
slideshow_button.sensitive = true;
}
private void on_photo_removed(Photo photo) {
Thumbnail found = get_thumbnail_for_photo(photo);
if (found != null)
remove_item(found);
slideshow_button.sensitive = (get_count() > 0);
}
private void on_thumbnail_altered(Photo photo) {
......@@ -533,8 +682,9 @@ public class CollectionPage : CheckerboardPage {
set_item_sensitive("/CollectionMenuBar/PhotosMenu/RotateCounterclockwise", selected);
set_item_sensitive("/CollectionMenuBar/PhotosMenu/Mirror", selected);
set_item_sensitive("/CollectionMenuBar/PhotosMenu/Revert", selected && revert_possible);
set_item_sensitive("/CollectionMenuBar/PhotosMenu/Slideshow", get_count() > 0);
}
private void on_increase_size() {
increase_thumb_size();
slider.set_value(scale_to_slider(scale));
......@@ -616,6 +766,14 @@ public class CollectionPage : CheckerboardPage {
refresh();
}
private void on_slideshow() {
if (get_count() == 0)
return;
AppWindow.get_instance().go_fullscreen(new FullscreenWindow(new SlideshowPage(this,
(Thumbnail) get_first_item())));
}
private void on_view_menu() {
set_item_sensitive("/CollectionMenuBar/ViewMenu/Fullscreen", get_count() > 0);
}
......
......@@ -92,7 +92,7 @@ public class PhotoPage : SinglePhotoPage {
public static const int CROP_TOOL_WINDOW_SEPARATOR = 8;
private Gtk.Window container;
private Gtk.Window container = null;
private Gtk.Menu context_menu;
private CheckerboardPage controller = null;
private Photo photo = null;
......@@ -140,11 +140,9 @@ public class PhotoPage : SinglePhotoPage {
{ "HelpMenu", null, "_Help", null, null, null }
};
public PhotoPage(Gtk.Window container) {
public PhotoPage() {
base("Photo");
this.container = container;
init_ui("photo.ui", "/PhotoMenuBar", "PhotoActionGroup", ACTIONS);
context_menu = (Gtk.Menu) ui.get_widget("/PhotoContextMenu");
......@@ -182,6 +180,14 @@ public class PhotoPage : SinglePhotoPage {
next_button.clicked += on_next_photo;
toolbar.insert(next_button, -1);
}
public void set_container(Gtk.Window container) {
// this should only be called once
assert(this.container == null);
this.container = container;
// DnD only available in full-window view
if (!(container is FullscreenWindow))
enable_drag_source(Gdk.DragAction.COPY);
......
......@@ -21,6 +21,8 @@
<menuitem name="Mirror" action="Mirror" />
<separator />
<menuitem name="Revert" action="Revert" />
<separator />
<menuitem name="Slideshow" action="Slideshow" />
</menu>
<menu name="ViewMenu" action="ViewMenu">
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment