Commit ae606325 authored by Jim Nelson's avatar Jim Nelson

Photo full-window view available by double-clicking on photo. libgphoto.vapi.

parent 39cf8e6e
......@@ -3,6 +3,8 @@ public class AppWindow : Gtk.Window {
public static const string TITLE = "Shotwell";
public static const string VERSION = "0.0.1";
public static const string DATA_DIR = ".photo";
public static Gdk.Color BG_COLOR = parse_color("#777");
private static AppWindow mainWindow = null;
private static Gtk.UIManager uiManager = null;
......@@ -82,7 +84,6 @@ public class AppWindow : Gtk.Window {
return subdir;
}
private Gtk.Box layout = null;
private Gtk.TreeStore pageTreeStore = null;
private Gtk.TreeView pageTreeView = null;
......@@ -94,13 +95,12 @@ public class AppWindow : Gtk.Window {
construct {
// set up display
title = TITLE;
set_default_size(800, 600);
set_default_size(1024, 768);
destroy += Gtk.main_quit;
pageTreeStore = new Gtk.TreeStore(1, typeof(string));
pageTreeView = new Gtk.TreeView.with_model(pageTreeStore);
pageTreeView.modify_bg(Gtk.StateType.NORMAL, parse_color(CollectionPage.BG_COLOR));
var text = new Gtk.CellRendererText();
text.size_points = 9.0;
......@@ -149,21 +149,12 @@ public class AppWindow : Gtk.Window {
}
collectionPage = new CollectionPage();
//photoPage = new PhotoPage();
photoPage = new PhotoPage();
add_accel_group(uiManager.get_accel_group());
switch_to_collection_page();
create_start_page();
}
public void about_box() {
// TODO: More thorough About box
Gtk.show_about_dialog(this,
"version", VERSION,
"comments", "a photo organizer",
"copyright", "(c) 2009 yorba"
);
}
private void import(File file) {
FileType type = file.query_file_type(FileQueryInfoFlags.NOFOLLOW_SYMLINKS, null);
if(type == FileType.REGULAR) {
......@@ -265,52 +256,62 @@ public class AppWindow : Gtk.Window {
}
public void switch_to_collection_page() {
switch_to_page(collectionPage, collectionPage.get_action_group(),
collectionPage.get_menubar(), collectionPage.get_toolbar());
switch_to_page(collectionPage);
}
public void switch_to_photo_page(PhotoID photoID) {
//photoPage.display_photo(photoID);
switch_to_page(photoPage, photoPage.get_action_group(),
photoPage.get_menubar(), photoPage.get_toolbar());
photoPage.display_photo(photoID);
switch_to_page(photoPage);
}
//private Gtk.ActionGroup oldActionGroup = null;
private void switch_to_page(Gtk.Widget page, Gtk.ActionGroup actionGroup, Gtk.MenuBar menubar,
Gtk.Toolbar toolbar) {
if (layout != null) {
remove(layout);
layout = null;
}
/*
if (oldActionGroup != null) {
remove_accel_group(uiManager.get_accel_group());
uiManager.remove_action_group(oldActionGroup);
oldActionGroup = null;
}
private Gtk.Box layout = null;
private Gtk.Box pageBox = null;
private Gtk.Box clientBox = null;
private Page currentPage = null;
private Gtk.MenuBar currentMenuBar = null;
private void create_start_page() {
currentPage = collectionPage;
uiManager.insert_action_group(actionGroup, 0);
oldActionGroup = actionGroup;
*/
// layout the growable collection page with the toolbar beneath
Gtk.VBox pageBox = new Gtk.VBox(false, 0);
pageBox.pack_start(page, true, true, 0);
pageBox.pack_end(toolbar, false, false, 0);
pageBox = new Gtk.VBox(false, 0);
pageBox.pack_start(collectionPage, true, true, 0);
pageBox.pack_end(currentPage.get_toolbar(), false, false, 0);
// layout the selection tree to the left of the collection/toolbar box
Gtk.HBox clientBox = new Gtk.HBox(false, 0);
clientBox = new Gtk.HBox(false, 0);
clientBox.pack_start(pageTreeView, false, false, 0);
clientBox.pack_end(pageBox, true, true, 0);
currentMenuBar = (Gtk.MenuBar) get_ui_manager().get_widget(currentPage.get_menubar_path());
// layout client beneath menu
layout = new Gtk.VBox(false, 0);
layout.pack_start(menubar, false, false, 0);
layout.pack_start(currentMenuBar, false, false, 0);
layout.pack_end(clientBox, true, true, 0);
add(layout);
show_all();
}
private void switch_to_page(Page page) {
currentPage.switching_from();
pageBox.remove(currentPage);
pageBox.pack_start(page, true, true, 0);
pageBox.remove(currentPage.get_toolbar());
pageBox.pack_end(page.get_toolbar(), false, false, 0);
layout.remove(currentMenuBar);
currentMenuBar = (Gtk.MenuBar) get_ui_manager().get_widget(page.get_menubar_path());
layout.pack_start(currentMenuBar, false, false, 0);
page.switched_to();
layout.show_all();
currentPage = page;
}
}
......@@ -12,7 +12,7 @@ public class CollectionLayout : Gtk.Layout {
private Gee.ArrayList<Thumbnail> thumbnails = new Gee.ArrayList<Thumbnail>();
public CollectionLayout() {
modify_bg(Gtk.StateType.NORMAL, parse_color(CollectionPage.BG_COLOR));
modify_bg(Gtk.StateType.NORMAL, AppWindow.BG_COLOR);
expose_event += on_expose;
size_allocate += on_resize;
}
......
public class CollectionPage : Gtk.ScrolledWindow {
public class CollectionPage : Page {
public static const int THUMB_X_PADDING = 20;
public static const int THUMB_Y_PADDING = 20;
public static const string BG_COLOR = "#777";
// steppings should divide evenly into (Thumbnail.MAX_SCALE - Thumbnail.MIN_SCALE)
public static const int MANUAL_STEPPING = 16;
......@@ -11,45 +10,10 @@ public class CollectionPage : Gtk.ScrolledWindow {
private static const int IMPROVAL_PRIORITY = Priority.LOW;
private static const int IMPROVAL_DELAY_MS = 500;
private static Gtk.IconFactory factory = null;
private static const string STOCK_CLOCKWISE = "shotwell-rotate-clockwise";
private static const string STOCK_COUNTERCLOCKWISE = "shotwell-rotate-counterclockwise";
private static void addStockIcon(File file, string stockID) {
debug("Adding icon %s", file.get_path());
Gdk.Pixbuf pixbuf = null;
try {
pixbuf = new Gdk.Pixbuf.from_file(file.get_path());
} catch (Error err) {
error("%s", err.message);
}
debug("%d %d", pixbuf.width, pixbuf.height);
Gtk.IconSet iconSet = new Gtk.IconSet.from_pixbuf(pixbuf);
factory.add(stockID, iconSet);
}
private static void prepIcons() {
if (factory != null)
return;
factory = new Gtk.IconFactory();
File icons = AppWindow.get_exec_dir().get_child("icons");
addStockIcon(icons.get_child("object-rotate-right.svg"), STOCK_CLOCKWISE);
addStockIcon(icons.get_child("object-rotate-left.svg"), STOCK_COUNTERCLOCKWISE);
factory.add_default();
}
private PhotoTable photoTable = new PhotoTable();
private CollectionLayout layout = new CollectionLayout();
private Gtk.ActionGroup mainActionGroup = new Gtk.ActionGroup("CollectionActionGroup");
private Gtk.ActionGroup contextActionGroup = new Gtk.ActionGroup("CollectionContextActionGroup");
private Gtk.MenuBar menubar = null;
private Gtk.Toolbar toolbar = new Gtk.Toolbar();
private Gtk.HScale slider = null;
private Gtk.ToolButton rotateButton = null;
......@@ -76,20 +40,18 @@ public class CollectionPage : Gtk.ScrolledWindow {
{ "ViewTitle", null, "_Titles", "<Ctrl><Shift>T", "Display the title of each photo", on_display_titles },
{ "Help", null, "_Help", null, null, null },
{ "About", Gtk.STOCK_ABOUT, "_About", null, "About this application", on_about }
{ "About", Gtk.STOCK_ABOUT, "_About", null, "About this application", about_box }
};
// TODO: Mark fields for translation
private const Gtk.ActionEntry[] RIGHT_CLICK_ACTIONS = {
{ "Remove", Gtk.STOCK_DELETE, "_Remove", "Delete", "Remove the selected photos from the library", on_remove },
{ "RotateClockwise", STOCK_CLOCKWISE, "Rotate c_lockwise", "<Ctrl>R", "Rotate the selected photos clockwise", on_rotate_clockwise },
{ "RotateCounterclockwise", STOCK_COUNTERCLOCKWISE, "Rotate c_ounterclockwise", "<Ctrl><Shift>R", "Rotate the selected photos counterclockwise", on_rotate_counterclockwise },
{ "CollectionRotateClockwise", STOCK_CLOCKWISE, "Rotate c_lockwise", "<Ctrl>R", "Rotate the selected photos clockwise", on_rotate_clockwise },
{ "CollectionRotateCounterclockwise", STOCK_COUNTERCLOCKWISE, "Rotate c_ounterclockwise", "<Ctrl><Shift>R", "Rotate the selected photos counterclockwise", on_rotate_counterclockwise },
{ "Mirror", null, "_Mirror", "<Ctrl>M", "Make mirror images of the selected photos", on_mirror }
};
construct {
prepIcons();
// set up action group
mainActionGroup.add_actions(ACTIONS, this);
AppWindow.get_ui_manager().insert_action_group(mainActionGroup, 0);
......@@ -97,9 +59,6 @@ public class CollectionPage : Gtk.ScrolledWindow {
contextActionGroup.add_actions(RIGHT_CLICK_ACTIONS, this);
AppWindow.get_ui_manager().insert_action_group(contextActionGroup, 0);
// this page's menu bar
menubar = (Gtk.MenuBar) AppWindow.get_ui_manager().get_widget("/CollectionMenuBar");
// set up page's toolbar (used by AppWindow for layout)
//
// rotate tool
......@@ -132,9 +91,6 @@ public class CollectionPage : Gtk.ScrolledWindow {
// scrollbar policy
set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC);
AppWindow.get_main_window().key_press_event += on_key_pressed;
AppWindow.get_main_window().key_release_event += on_key_released;
// this schedules thumbnail improvement whenever the window size changes (and new thumbnails
// may be exposed)
size_allocate += schedule_thumbnail_improval;
......@@ -146,8 +102,6 @@ public class CollectionPage : Gtk.ScrolledWindow {
add(layout);
button_press_event += on_click;
File[] photoFiles = photoTable.get_photo_files();
foreach (File file in photoFiles) {
PhotoID photoID = photoTable.get_id(file);
......@@ -161,23 +115,25 @@ public class CollectionPage : Gtk.ScrolledWindow {
show_all();
}
public Gtk.Toolbar get_toolbar() {
public override Gtk.Toolbar get_toolbar() {
return toolbar;
}
public Gtk.MenuBar get_menubar() {
return menubar;
public override string get_menubar_path() {
return "/CollectionMenuBar";
}
public Gtk.ActionGroup get_action_group() {
return mainActionGroup;
public override void switched_to() {
// need to refresh the layout in case any of the thumbnail dimensions were altered while we
// were gone
layout.refresh();
}
public void begin_adding() {
}
public void add_photo(PhotoID photoID, File file) {
Thumbnail thumbnail = new Thumbnail(photoID, file, scale);
Thumbnail thumbnail = Thumbnail.create(photoID, file, scale);
thumbnail.display_title(displayTitles);
thumbnailList.add(thumbnail);
......@@ -330,15 +286,6 @@ public class CollectionPage : Gtk.ScrolledWindow {
return false;
}
private void on_about() {
AppWindow.get_main_window().about_box();
}
private void set_item_sensitive(string path, bool sensitive) {
Gtk.Widget widget = AppWindow.get_ui_manager().get_widget(path);
widget.set_sensitive(sensitive);
}
private void on_edit_menu() {
set_item_sensitive("/CollectionMenuBar/EditMenu/EditSelectAll", get_count() > 0);
set_item_sensitive("/CollectionMenuBar/EditMenu/EditRemove", get_selected_count() > 0);
......@@ -368,21 +315,8 @@ public class CollectionPage : Gtk.ScrolledWindow {
slider.set_value(scaleToSlider(scale));
}
private bool on_click(CollectionPage c, Gdk.EventButton event) {
switch (event.button) {
case 1:
return on_left_click(event);
case 3:
return on_right_click(event);
default:
return false;
}
}
private bool on_left_click(Gdk.EventButton event) {
// only interested in single-clicks presses for now
private override bool on_left_click(Gdk.EventButton event) {
// only interested in single-click and double-clicks for now
if ((event.type != Gdk.EventType.BUTTON_PRESS)
&& (event.type != Gdk.EventType.2BUTTON_PRESS)) {
return false;
......@@ -412,12 +346,10 @@ public class CollectionPage : Gtk.ScrolledWindow {
default: {
if (event.type == Gdk.EventType.2BUTTON_PRESS) {
/*
// switch to full-page view
debug("switching to %s [%d]", thumbnail.get_file().get_path(),
thumbnail.get_photo_id().id);
AppWindow.get_main_window().switch_to_photo_page(thumbnail.get_photo_id());
*/
} else {
// a "raw" single-click deselects all thumbnails and selects the single chosen
unselect_all();
......@@ -433,7 +365,7 @@ public class CollectionPage : Gtk.ScrolledWindow {
return true;
}
private bool on_right_click(Gdk.EventButton event) {
private override bool on_right_click(Gdk.EventButton event) {
// only interested in single-clicks for now
if (event.type != Gdk.EventType.BUTTON_PRESS) {
return false;
......@@ -539,29 +471,16 @@ public class CollectionPage : Gtk.ScrolledWindow {
set_thumb_size(sliderToScale(slider.get_value()));
}
private static const uint KEY_CTRL_L = Gdk.keyval_from_name("Control_L");
private static const uint KEY_CTRL_R = Gdk.keyval_from_name("Control_R");
private static const uint KEY_ALT_L = Gdk.keyval_from_name("Alt_L");
private static const uint KEY_ALT_R = Gdk.keyval_from_name("Alt_R");
private bool on_key_pressed(AppWindow aw, Gdk.EventKey event) {
if ((event.keyval == KEY_CTRL_L) || (event.keyval == KEY_CTRL_R)) {
rotateButton.set_stock_id(STOCK_COUNTERCLOCKWISE);
rotateButton.clicked -= on_rotate_clockwise;
rotateButton.clicked += on_rotate_counterclockwise;
}
return false;
private override void on_ctrl_pressed(Gdk.EventKey event) {
rotateButton.set_stock_id(STOCK_COUNTERCLOCKWISE);
rotateButton.clicked -= on_rotate_clockwise;
rotateButton.clicked += on_rotate_counterclockwise;
}
private bool on_key_released(AppWindow aw, Gdk.EventKey event) {
if ((event.keyval == KEY_CTRL_L) || (event.keyval == KEY_CTRL_R)) {
rotateButton.set_stock_id(STOCK_CLOCKWISE);
rotateButton.clicked -= on_rotate_counterclockwise;
rotateButton.clicked += on_rotate_clockwise;
}
return false;
private override void on_ctrl_released(Gdk.EventKey event) {
rotateButton.set_stock_id(STOCK_CLOCKWISE);
rotateButton.clicked -= on_rotate_counterclockwise;
rotateButton.clicked += on_rotate_clockwise;
}
}
......@@ -204,11 +204,43 @@ public errordomain ExifError {
extern void free(void *ptr);
public uint file_hash(void *key) {
File *file = (File *) key;
return str_hash(file->get_path());
}
public bool file_equal(void *a, void *b) {
File *afile = (File *) a;
File *bfile = (File *) b;
return afile->get_path() == bfile->get_path();
}
public class PhotoExif {
private static Gee.HashMap<File, PhotoExif> cacheMap = null;
private File file;
private Exif.Data exifData = null;
public PhotoExif(File file) {
public static PhotoExif create(File file) {
PhotoExif exif = null;
// for some reason, the static initializer isn't working
if (cacheMap == null) {
cacheMap = new Gee.HashMap<File, PhotoExif>(file_hash, file_equal, direct_equal);
} else {
exif = cacheMap.get(file);
}
if (exif == null) {
exif = new PhotoExif(file);
cacheMap.set(file, exif);
}
return exif;
}
private PhotoExif(File file) {
this.file = file;
}
......
......@@ -14,12 +14,17 @@ SRC_FILES = \
image_util.vala \
CollectionLayout.vala \
PhotoPage.vala \
Exif.vala
Exif.vala \
Page.vala
VAPI_FILES = \
libexif.vapi \
fstream.vapi
fstream.vapi \
libgphoto2.vapi
RESOURCE_FILES = \
photo.ui
VAPI_DIRS = \
.
......@@ -30,7 +35,8 @@ PKGS = \
sqlite3 \
vala-1.0 \
libexif \
fstream
fstream \
libgphoto2
all: $(TARGET)
......
public abstract class Page : Gtk.ScrolledWindow {
public static const uint KEY_CTRL_L = Gdk.keyval_from_name("Control_L");
public static const uint KEY_CTRL_R = Gdk.keyval_from_name("Control_R");
public static const uint KEY_ALT_L = Gdk.keyval_from_name("Alt_L");
public static const uint KEY_ALT_R = Gdk.keyval_from_name("Alt_R");
public static const string STOCK_CLOCKWISE = "shotwell-rotate-clockwise";
public static const string STOCK_COUNTERCLOCKWISE = "shotwell-rotate-counterclockwise";
public static const Gdk.Color BG_COLOR = parse_color("#777");
private static Gtk.IconFactory factory = null;
private static void addStockIcon(File file, string stockID) {
debug("Adding icon %s", file.get_path());
Gdk.Pixbuf pixbuf = null;
try {
pixbuf = new Gdk.Pixbuf.from_file(file.get_path());
} catch (Error err) {
error("%s", err.message);
}
Gtk.IconSet iconSet = new Gtk.IconSet.from_pixbuf(pixbuf);
factory.add(stockID, iconSet);
}
private static void prepIcons() {
if (factory != null)
return;
factory = new Gtk.IconFactory();
File icons = AppWindow.get_exec_dir().get_child("icons");
addStockIcon(icons.get_child("object-rotate-right.svg"), STOCK_CLOCKWISE);
addStockIcon(icons.get_child("object-rotate-left.svg"), STOCK_COUNTERCLOCKWISE);
factory.add_default();
}
construct {
prepIcons();
button_press_event += on_click;
AppWindow.get_main_window().key_press_event += on_key_pressed_internal;
AppWindow.get_main_window().key_release_event += on_key_released_internal;
}
public abstract string get_menubar_path();
public abstract Gtk.Toolbar get_toolbar();
public virtual void switching_from() {
}
public virtual void switched_to() {
}
public void about_box() {
// TODO: More thorough About box
Gtk.show_about_dialog(AppWindow.get_main_window(),
"version", AppWindow.VERSION,
"comments", "a photo organizer",
"copyright", "(c) 2009 yorba",
"website", "http://www.yorba.org"
);
}
public void set_item_sensitive(string path, bool sensitive) {
Gtk.Widget widget = AppWindow.get_ui_manager().get_widget(path);
widget.set_sensitive(sensitive);
}
protected virtual bool on_left_click(Gdk.EventButton event) {
return false;
}
protected virtual bool on_middle_click(Gdk.EventButton event) {
return false;
}
protected virtual bool on_right_click(Gdk.EventButton event) {
return false;
}
private bool on_click(Page p, Gdk.EventButton event) {
switch (event.button) {
case 1:
return on_left_click(event);
case 2:
return on_middle_click(event);
case 3:
return on_right_click(event);
default:
return false;
}
}
protected virtual bool on_key_pressed(Gdk.EventKey event) {
return false;
}
protected virtual bool on_key_released(Gdk.EventKey event) {
return false;
}
protected virtual void on_ctrl_pressed(Gdk.EventKey event) {
}
protected virtual void on_ctrl_released(Gdk.EventKey event) {
}
protected virtual void on_alt_pressed(Gdk.EventKey event) {
}
protected virtual void on_alt_released(Gdk.EventKey event) {
}
private bool on_key_pressed_internal(AppWindow aw, Gdk.EventKey event) {
if ((event.keyval == KEY_CTRL_L) || (event.keyval == KEY_CTRL_R)) {
on_ctrl_pressed(event);
}
if ((event.keyval == KEY_ALT_L) || (event.keyval == KEY_ALT_R)) {
on_alt_pressed(event);
}
return on_key_pressed(event);
}
private bool on_key_released_internal(AppWindow aw, Gdk.EventKey event) {
if ((event.keyval == KEY_CTRL_L) || (event.keyval == KEY_CTRL_R)) {
on_ctrl_released(event);
}
if ((event.keyval == KEY_ALT_L) || (event.keyval == KEY_ALT_R)) {
on_alt_released(event);
}
return on_key_released(event);
}
}
public class PhotoPage : Gtk.ScrolledWindow {
public class PhotoPage : Page {
public static const Gdk.InterpType DEFAULT_INTERP = Gdk.InterpType.BILINEAR;
public static const int IMAGE_BORDER = 4;
private PhotoTable photoTable = new PhotoTable();
private Gtk.Viewport viewport = new Gtk.Viewport(null, null);
private Gtk.ActionGroup actionGroup = new Gtk.ActionGroup("PhotoActionGroup");
private Gtk.MenuBar menubar = null;
private Gtk.Toolbar toolbar = new Gtk.Toolbar();
private Gtk.ToolButton rotateButton = null;
private PhotoID currentPhotoID;
private Gtk.Image image = new Gtk.Image();
private Gtk.Label title = new Gtk.Label(null);
private PhotoExif exif = null;
private Gdk.Pixbuf original = null;
private Exif.Orientation orientation;
private Gdk.Pixbuf rotated = null;
private Dimensions rotatedDim;
private Thumbnail thumbnail = null;
// TODO: Mark fields for translation
private const Gtk.ActionEntry[] ACTIONS = {
{ "File", null, "_File", null, null, null },
{ "Quit", Gtk.STOCK_QUIT, "_Quit", null, "Quit the program", Gtk.main_quit },
{ "PhotoAction", null, "_Photo", null, null, null },
{ "PhotoRotateClockwise", STOCK_CLOCKWISE, "Rotate c_lockwise", "<Ctrl>R", "Rotate the selected photos clockwise", on_rotate_clockwise },
{ "PhotoRotateCounterclockwise", STOCK_COUNTERCLOCKWISE, "Rotate c_ounterclockwise", "<Ctrl><Shift>R", "Rotate the selected photos counterclockwise", on_rotate_counterclockwise },
{ "Mirror", null, "_Mirror", "<Ctrl>M", "Make mirror images of the selected photos", on_mirror },
{ "Help", null, "_Help", null, null, null },
{ "About", Gtk.STOCK_ABOUT, "_About", null, "About this application", null }
{ "About", Gtk.STOCK_ABOUT, "_About", null, "About this application", about_box }
};
construct {
// set up action group
actionGroup.add_actions(ACTIONS, this);
AppWindow.get_ui_manager().insert_action_group(actionGroup, 0);
// set up menu bar
menubar = (Gtk.MenuBar) AppWindow.get_ui_manager().get_widget("/CollectionMenuBar");
// scrollbar policy
set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC);
// set up page's toolbar (used by AppWindow for layout)
//
// rotate tool
rotateButton = new Gtk.ToolButton.from_stock(STOCK_CLOCKWISE);
rotateButton.clicked += on_rotate_clockwise;
toolbar.insert(rotateButton, -1);
title.set_use_underline(false);
title.set_justify(Gtk.Justification.LEFT);
title.set_alignment(0, 0);
// scrollbar policy ... this is important, as if the scrollbars appear will cause a loop
// of on_resize()
set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC);
Gtk.VBox vbox = new Gtk.VBox(false, 0);
vbox.pack_start(image, false, false, 0);
vbox.pack_end(title, false, false, 0);
viewport.add(image);
viewport.modify_bg(Gtk.StateType.NORMAL, AppWindow.BG_COLOR);
add_with_viewport(vbox);
add(viewport);
expose_event += on_expose;
}
public Gtk.Toolbar get_toolbar() {
public override Gtk.Toolbar get_toolbar() {
return toolbar;
}
public Gtk.MenuBar get_menubar() {
return menubar;
}
public Gtk.ActionGroup get_action_group() {
return actionGroup;
public override string get_menubar_path() {
return "/PhotoMenuBar";
}
public void display_photo(PhotoID photoID) {
currentPhotoID = photoID;
File file = photoTable.get_file(photoID);
if (file == null)
return;
assert(file != null);
debug("Loading %s", file.get_path());
Gdk.Pixbuf pixbuf = null;
try {
pixbuf = new Gdk.Pixbuf.from_file(file.get_path());
original = new Gdk.Pixbuf.from_file(file.get_path());
} catch (Error err) {
// TODO: Better error handling
error("%s", err.message);
}
thumbnail = Thumbnail.get_existing(photoID);
exif = PhotoExif.create(file);
orientation = exif.get_orientation();
rotated = rotate_to_exif(original, orientation);
rotatedDim = Dimensions.for_pixbuf(rotated);
repaint(true);
}
private int lastWidth = 0;
private int lastHeight = 0;
private bool repaint(bool force = false) {
int width = viewport.allocation.width - IMAGE_BORDER;
int height = viewport.allocation.height - IMAGE_BORDER;