Commit 3b70ad9d authored by Jim Nelson's avatar Jim Nelson

Photo organizer ho.

parents
public class AppWindow : Gtk.Window {
public static const string TITLE = "Photo Organizer";
public static const string VERSION = "0.0.1";
private static AppWindow mainWindow = null;
private static string[] args = null;
private static GLib.File execFile = 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 },
{ "Help", null, "_Help", null, null, null },
{ "About", Gtk.STOCK_ABOUT, "_About", null, "About this application", on_about }
};
// drag and drop target entries
private const Gtk.TargetEntry[] TARGET_ENTRIES = {
{ "text/uri-list", 0, 0 }
};
public static AppWindow get_main_window() {
return mainWindow;
}
public static void set_commandline_args(string[] args) {
args = args;
execFile = GLib.File.new_for_commandline_arg(args[0]);
}
public static string[] get_commandline_args() {
return args;
}
public static GLib.File get_exec_file() {
return execFile;
}
public static GLib.File get_exec_dir() {
return execFile.get_parent();
}
private Gtk.UIManager uiManager = new Gtk.UIManager();
private CollectionPage collectionPage = new CollectionPage();
construct {
// set up display
title = TITLE;
set_default_size(800, 600);
destroy += Gtk.main_quit;
// window actions
Gtk.ActionGroup actionGroup = new Gtk.ActionGroup("MainActionGroup");
actionGroup.add_actions(ACTIONS, this);
uiManager.insert_action_group(actionGroup, 0);
GLib.File uiFile = get_exec_dir().get_child("photo.ui");
assert(uiFile != null);
try {
uiManager.add_ui_from_file(uiFile.get_path());
} catch (GLib.Error gle) {
// TODO: Exit app immediately
error("Error loading UI: %s", gle.message);
}
// primary widgets
Gtk.MenuBar menubar = (Gtk.MenuBar) uiManager.get_widget("/MenuBar");
add_accel_group(uiManager.get_accel_group());
// layout widgets in vertical box
Gtk.VBox vbox = new Gtk.VBox(false, 0);
vbox.pack_start(menubar, false, false, 0);
vbox.pack_end(collectionPage, true, true, 0);
add(vbox);
// set up as a drag-and-drop destination
// this.drag_data_received() is called when a drop occurs
Gtk.drag_dest_set(this, Gtk.DestDefaults.ALL, TARGET_ENTRIES, Gdk.DragAction.COPY);
// if this is the first AppWindow, it's the main AppWindow
if (mainWindow == null) {
mainWindow = this;
}
}
private void on_about() {
// 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) {
message("File %s", file.get_path());
collectionPage.add_photo(file);
return;
} else if (type != FileType.DIRECTORY) {
return;
}
import_dir(file);
}
private void import_dir(File dir) {
try {
FileEnumerator enumerator = dir.enumerate_children("*",
FileQueryInfoFlags.NOFOLLOW_SYMLINKS, null);
if (enumerator == null) {
return;
}
for (;;) {
FileInfo info = enumerator.next_file(null);
if (info == null) {
break;
}
File file = dir.get_child(info.get_name());
FileType type = info.get_file_type();
if (type == FileType.REGULAR) {
message("File %s", file.get_path());
collectionPage.add_photo(file);
} else if (type == FileType.DIRECTORY) {
message("Dir %s", file.get_path());
import_dir(file);
} else {
message("Skipped %s", file.get_path());
}
}
} catch (Error err) {
error("%s", err.message);
}
}
public override void drag_data_received(Gdk.DragContext context, int x, int y,
Gtk.SelectionData selectionData, uint info, uint time) {
// grab data and release back to system
string[] uris = selectionData.get_uris();
Gtk.drag_finish(context, true, false, time);
// import
foreach (string uri in uris) {
import(File.new_for_uri(uri));
}
}
}
Gdk.Color parse_color(string color) {
Gdk.Color c;
if (!Gdk.Color.parse(color, out c))
error("can't parse color");
return c;
}
public class CollectionPage : Gtk.ScrolledWindow {
private Gtk.Table layoutTable = new Gtk.Table(0, 0, false);
private List<Thumbnail> thumbnailList = new List<Thumbnail>();
private int currentX = 0;
private int currentY = 0;
private int cols = 1;
private int thumbCount = 0;
construct {
set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC);
size_allocate += on_resize;
Gtk.Viewport viewport = new Gtk.Viewport(null, null);
viewport.add(layoutTable);
viewport.modify_bg(Gtk.StateType.NORMAL, parse_color("#777"));
add(viewport);
}
public CollectionPage() {
}
public void add_photo(File file) {
Thumbnail thumbnail = new Thumbnail(file);
thumbnailList.append(thumbnail);
layoutTable.attach(thumbnail, currentX, currentX + 1, currentY, currentY + 1,
Gtk.AttachOptions.SHRINK | Gtk.AttachOptions.EXPAND,
Gtk.AttachOptions.SHRINK,
20, 20);
if (++currentX >= cols) {
currentX = 0;
currentY++;
}
thumbCount++;
show_all();
}
private void on_resize(CollectionPage s, Gdk.Rectangle allocation) {
int newCols = allocation.width / (Thumbnail.THUMB_WIDTH + 20 + 20);
if (newCols < 1)
newCols = 1;
if (cols == newCols)
return;
int rows = (thumbCount / newCols) + 1;
message("rows=%d cols=%d", rows, newCols);
cols = newCols;
layoutTable.resize(rows, cols);
currentX = 0;
currentY = 0;
foreach (Thumbnail thumbnail in thumbnailList) {
layoutTable.remove(thumbnail);
layoutTable.attach(thumbnail, currentX, currentX + 1, currentY, currentY + 1,
Gtk.AttachOptions.SHRINK | Gtk.AttachOptions.EXPAND,
Gtk.AttachOptions.SHRINK,
20, 20);
if(++currentX >= cols) {
currentX = 0;
currentY++;
}
}
}
}
all: photo
clean:
rm -f photo
photo: main.vala AppWindow.vala CollectionPage.vala Thumbnail.vala Makefile
valac -g --enable-checking --pkg gtk+-2.0 main.vala AppWindow.vala CollectionPage.vala Thumbnail.vala -o photo
public class Thumbnail : Gtk.VBox {
public static const int THUMB_WIDTH = 128;
public static const int THUMB_HEIGHT = 128;
private File file;
private Gtk.Image image;
private Gtk.Label label;
construct {
}
public Thumbnail(File file) {
this.file = file;
Gdk.Pixbuf pixbuf = null;
try {
pixbuf = new Gdk.Pixbuf.from_file(file.get_path());
} catch (Error err) {
error("%s", err.message);
return;
}
pixbuf = scale(pixbuf, THUMB_WIDTH, THUMB_HEIGHT);
label = new Gtk.Label(file.get_basename());
label.set_use_underline(false);
image = new Gtk.Image.from_pixbuf(pixbuf);
pack_start(image, true, true, 0);
pack_end(label, false, false, 4);
}
public Gdk.Pixbuf scale(Gdk.Pixbuf pixbuf, int maxWidth, int maxHeight) {
int width = pixbuf.get_width();
int height = pixbuf.get_height();
int diffWidth = width - maxWidth;
int diffHeight = height - maxHeight;
double ratio = 0.0;
if (diffWidth > diffHeight) {
ratio = (double) maxWidth / (double) width;
} else {
ratio = (double) maxHeight / (double) height;
}
int newWidth = (int) ((double) width * ratio);
int newHeight = (int) ((double) height * ratio);
message("%s %dx%d -> %lf -> %dx%d", file.get_path(), width, height, ratio, newWidth, newHeight);
return pixbuf.scale_simple(newWidth, newHeight, Gdk.InterpType.NEAREST);
}
}
void main(string[] args) {
// init GTK
Gtk.init(ref args);
// set up GLib environment
GLib.Environment.set_application_name(AppWindow.TITLE);
AppWindow.set_commandline_args(args);
// create main application window
AppWindow appWindow = new AppWindow();
// throw it all on the display
appWindow.show_all();
// event loop
Gtk.main();
}
<ui>
<menubar name="MenuBar">
<menu name="FileMenu" action="File">
<menuitem name="FileQuit" action="Quit" />
</menu>
<menu name="HelpMenu" action="Help">
<menuitem name="HelpAbout" action="About" />
</menu>
</menubar>
</ui>
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