189 lines
5.5 KiB
Vala
189 lines
5.5 KiB
Vala
using Gtk;
|
|
using Gdk;
|
|
|
|
public class Tootle.Widgets.ImageAttachment : Gtk.DrawingArea {
|
|
|
|
public Attachment? attachment;
|
|
private bool editable = false;
|
|
private bool fill = false;
|
|
|
|
private Pixbuf? pixbuf = null;
|
|
private static Pixbuf? pixbuf_error;
|
|
private int center_x = 0;
|
|
private int center_y = 0;
|
|
|
|
private Soup.Message? image_request;
|
|
|
|
construct {
|
|
if (pixbuf_error == null)
|
|
pixbuf_error = IconTheme.get_default ().load_icon ("image-missing", 32, IconLookupFlags.GENERIC_FALLBACK);
|
|
|
|
hexpand = true;
|
|
vexpand = true;
|
|
add_events (EventMask.BUTTON_PRESS_MASK);
|
|
draw.connect (on_draw);
|
|
button_press_event.connect (on_clicked);
|
|
}
|
|
|
|
~ImageAttachment () {
|
|
network.cancel_request (image_request);
|
|
}
|
|
|
|
public ImageAttachment (Attachment obj) {
|
|
attachment = obj;
|
|
image_request = network.load_pixbuf (attachment.preview_url, on_ready);
|
|
set_size_request (32, 128);
|
|
show_all ();
|
|
}
|
|
|
|
public ImageAttachment.upload (string uri) {
|
|
halign = Align.START;
|
|
valign = Align.START;
|
|
set_size_request (100, 100);
|
|
show_all ();
|
|
try {
|
|
GLib.File file = File.new_for_uri (uri);
|
|
uint8[] contents;
|
|
file.load_contents (null, out contents, null);
|
|
var type = file.query_info (GLib.FileAttribute.STANDARD_CONTENT_TYPE, 0);
|
|
var mime = type.get_content_type ();
|
|
|
|
info ("Uploading %s (%s)", uri, mime);
|
|
show ();
|
|
|
|
var buffer = new Soup.Buffer.take (contents);
|
|
var multipart = new Soup.Multipart (Soup.FORM_MIME_TYPE_MULTIPART);
|
|
multipart.append_form_file ("file", mime.replace ("/", "."), mime, buffer);
|
|
var url = "%s/api/v1/media".printf (accounts.formal.instance);
|
|
var msg = Soup.Form.request_new_from_multipart (url, multipart);
|
|
|
|
network.queue (msg, (sess, mess) => {
|
|
var root = network.parse (mess);
|
|
attachment = Attachment.parse (root);
|
|
editable = true;
|
|
invalidate ();
|
|
network.load_pixbuf (attachment.preview_url, on_ready);
|
|
info ("Uploaded media: %lld", attachment.id);
|
|
});
|
|
}
|
|
catch (Error e) {
|
|
error (e.message);
|
|
app.error (_("File read error"), _("Can't read file %s: %s").printf (uri, e.message));
|
|
}
|
|
}
|
|
|
|
private void on_ready (Pixbuf? result) {
|
|
if (result == null)
|
|
result = pixbuf_error;
|
|
|
|
pixbuf = result;
|
|
invalidate ();
|
|
}
|
|
|
|
private void invalidate () {
|
|
var w = get_allocated_width ();
|
|
var h = get_allocated_height ();
|
|
if (fill) {
|
|
var h_scaled = (pixbuf.height * w) / pixbuf.width;
|
|
if (h_scaled > pixbuf.height) {
|
|
halign = Align.START;
|
|
set_size_request (pixbuf.width, pixbuf.height);
|
|
}
|
|
else {
|
|
halign = Align.FILL;
|
|
set_size_request (1, h_scaled);
|
|
}
|
|
}
|
|
queue_draw_area (0, 0, w, h);
|
|
}
|
|
|
|
private void calc_center (int w, int h, int size_w, int size_h, Cairo.Context? ctx = null) {
|
|
center_x = w/2 - size_w/2;
|
|
center_y = h/2 - size_h/2;
|
|
|
|
if (ctx != null)
|
|
ctx.translate (center_x, center_y);
|
|
}
|
|
|
|
public void fill_parent () {
|
|
fill = true;
|
|
size_allocate.connect (on_size_changed);
|
|
on_size_changed ();
|
|
}
|
|
|
|
public void on_size_changed () {
|
|
if (fill && pixbuf != null)
|
|
invalidate ();
|
|
}
|
|
|
|
private bool on_draw (Widget widget, Cairo.Context ctx) {
|
|
var w = widget.get_allocated_width ();
|
|
var h = widget.get_allocated_height ();
|
|
if (halign == Align.START) {
|
|
w = pixbuf.width;
|
|
h = pixbuf.height;
|
|
}
|
|
|
|
//Draw frame
|
|
ctx.set_source_rgba (1, 1, 1, 1);
|
|
Drawing.draw_rounded_rect (ctx, 0, 0, w, h, 4);
|
|
ctx.fill ();
|
|
|
|
//Draw image, spinner or an error icon
|
|
if (pixbuf != null) {
|
|
var thumbnail = Drawing.make_pixbuf_thumbnail (pixbuf, w, h, fill);
|
|
Drawing.draw_rounded_rect (ctx, 0, 0, w, h, 4);
|
|
calc_center (w, h, thumbnail.width, thumbnail.height, ctx);
|
|
Gdk.cairo_set_source_pixbuf (ctx, thumbnail, 0, 0);
|
|
ctx.fill ();
|
|
}
|
|
else {
|
|
calc_center (w, h, 32, 32, ctx);
|
|
set_state_flags (StateFlags.CHECKED, false); //Y U NO SPIN
|
|
get_style_context ().render_activity (ctx, 0, 0, 32, 32);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private bool on_clicked (EventButton ev){
|
|
switch (ev.button) {
|
|
case 3:
|
|
return open_menu (ev.button, ev.time);
|
|
case 1:
|
|
Desktop.open_uri (attachment.url);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public virtual bool open_menu (uint button, uint32 time) {
|
|
var menu = new Gtk.Menu ();
|
|
|
|
if (editable && attachment != null) {
|
|
var item_remove = new Gtk.MenuItem.with_label (_("Remove"));
|
|
item_remove.activate.connect (() => destroy ());
|
|
menu.add (item_remove);
|
|
menu.add (new Gtk.SeparatorMenuItem ());
|
|
}
|
|
|
|
var item_open_link = new Gtk.MenuItem.with_label (_("Open in Browser"));
|
|
item_open_link.activate.connect (() => Desktop.open_uri (attachment.url));
|
|
var item_copy_link = new Gtk.MenuItem.with_label (_("Copy Link"));
|
|
item_copy_link.activate.connect (() => Desktop.copy (attachment.url));
|
|
var item_download = new Gtk.MenuItem.with_label (_("Download"));
|
|
item_download.activate.connect (() => Desktop.download_file (attachment.url));
|
|
menu.add (item_open_link);
|
|
if (attachment.type != "unknown")
|
|
menu.add (item_download);
|
|
menu.add (new Gtk.SeparatorMenuItem ());
|
|
menu.add (item_copy_link);
|
|
|
|
menu.show_all ();
|
|
menu.attach_widget = this;
|
|
menu.popup_at_pointer ();
|
|
return true;
|
|
}
|
|
|
|
}
|