Add scaling for image viewer

This commit is contained in:
daleclack 2024-02-19 19:47:46 +08:00
parent c5c130be9f
commit 5cb35ec046
2 changed files with 92 additions and 7 deletions

View File

@ -3,15 +3,16 @@
struct _ImageApp
{
GtkWindow parent_instance;
GtkApplicationWindow parent_instance;
// Child widgets
GtkWidget *main_box, *btn_box;
GtkWidget *image_sw;
GtkWidget *image_scale, *btnopen;
// Context Menu
GtkGesture *gesture;
GtkPopoverMenu *image_menu;
GtkGesture *gesture_click, *gesture_drag;
GtkBuilder *builder;
GtkWidget *image_menu;
// Main Image View
MyImage *image_view;
@ -20,13 +21,71 @@ struct _ImageApp
G_DEFINE_TYPE(ImageApp, image_app, GTK_TYPE_APPLICATION_WINDOW)
static gboolean image_app_change_scale(GtkRange *range, GtkScrollType *scroll,
double scale_value, ImageApp *app)
double scale_value, ImageApp *app)
{
my_image_scale_draw(app->image_view, scale_value);
gtk_range_set_value(range, scale_value);
return TRUE;
}
static void image_app_zoom_in(GSimpleAction *action,
GVariant *parmeter,
gpointer data)
{
// Zoom in: Scale + 0.1
ImageApp *app = IMAGE_APP(data);
double value = gtk_range_get_value(GTK_RANGE(app->image_scale));
value += 0.1;
if (value > 10.0)
{
value = 10.0;
}
gtk_range_set_value(GTK_RANGE(app->image_scale), value);
image_app_change_scale(GTK_RANGE(app->image_scale), NULL, value, app);
}
static void image_app_zoom_out(GSimpleAction *action,
GVariant *parmeter,
gpointer data)
{
// Zoom Out: Scale - 0.1
ImageApp *app = IMAGE_APP(data);
double value = gtk_range_get_value(GTK_RANGE(app->image_scale));
value -= 0.1;
if (value < 0.0)
{
value = 0.0;
}
gtk_range_set_value(GTK_RANGE(app->image_scale), value);
image_app_change_scale(GTK_RANGE(app->image_scale), NULL, value, app);
}
static void image_app_zoom_reset(GSimpleAction *action,
GVariant *parmeter,
gpointer data)
{
// 1:1 Scale=1
ImageApp *app = IMAGE_APP(data);
gtk_range_set_value(GTK_RANGE(app->image_scale), 1.0);
image_app_change_scale(GTK_RANGE(app->image_scale), NULL, 1.0, app);
}
static void gesture_pressed(GtkGesture *gesture,
int n_press,
double x,
double y,
ImageApp *app)
{
GdkRectangle pos;
pos.height = 1;
pos.width = 1;
pos.x = x;
pos.y = y;
// Set popover position and show
gtk_popover_set_pointing_to(GTK_POPOVER(app->image_menu), &pos);
gtk_popover_popup(GTK_POPOVER(app->image_menu));
}
static void image_app_dialog_response(GObject *dialog, GAsyncResult *result, gpointer data)
{
GFile *file;
@ -57,6 +116,16 @@ static void image_app_init(ImageApp *self)
gtk_window_set_default_size(GTK_WINDOW(self), 800, 450);
gtk_window_set_icon_name(GTK_WINDOW(self), "image_app");
// Add action for menu
GActionEntry entries[] =
{
{"zoom_out", image_app_zoom_out, NULL, NULL, NULL},
{"zoom_in", image_app_zoom_in, NULL, NULL, NULL},
{"zoom_reset", image_app_zoom_reset, NULL, NULL, NULL},
};
g_action_map_add_action_entries(G_ACTION_MAP(self), entries,
G_N_ELEMENTS(entries), self);
// Create child widgets
self->main_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
self->btn_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
@ -77,6 +146,20 @@ static void image_app_init(ImageApp *self)
gtk_scale_set_draw_value(GTK_SCALE(self->image_scale), TRUE);
gtk_scale_set_value_pos(GTK_SCALE(self->image_scale), GTK_POS_LEFT);
// Add gesture for context menu
self->gesture_click = gtk_gesture_click_new();
gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(self->gesture_click), GDK_BUTTON_SECONDARY);
gtk_widget_add_controller(GTK_WIDGET(self->image_view), GTK_EVENT_CONTROLLER(self->gesture_click));
g_signal_connect(self->gesture_click, "pressed", G_CALLBACK(gesture_pressed), self);
// Add a menu
self->builder = gtk_builder_new_from_resource("/org/gtk/daleclack/image_appmenu.xml");
GMenuModel *model = G_MENU_MODEL(gtk_builder_get_object(self->builder, "model"));
self->image_menu = gtk_popover_menu_new_from_model(model);
gtk_popover_set_has_arrow(GTK_POPOVER(self->image_menu), FALSE);
gtk_widget_set_parent(self->image_menu, GTK_WIDGET(self->image_view));
gtk_popover_present(GTK_POPOVER(self->image_menu));
// Pack Widgets
gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(self->image_sw), GTK_WIDGET(self->image_view));
gtk_box_append(GTK_BOX(self->main_box), self->image_sw);

View File

@ -20,12 +20,16 @@ static void my_image_draw(GtkDrawingArea *area, cairo_t *cr,
return;
}
width = gdk_pixbuf_get_width(image_view->pixbuf) / (image_view->scale_radio);
height = gdk_pixbuf_get_height(image_view->pixbuf) / (image_view->scale_radio);
// Get width and height for drawing area
gtk_widget_set_size_request(GTK_WIDGET(area), width, height);
gtk_drawing_area_set_content_width(GTK_DRAWING_AREA(data), width);
gtk_drawing_area_set_content_height(GTK_DRAWING_AREA(data), height);
// Scale the image and draw
cairo_set_source_surface(cr, image_view->surface, 0, 0);
cairo_surface_set_device_scale(image_view->surface,
image_view->scale_radio, image_view->scale_radio);
cairo_paint(cr);
@ -68,8 +72,6 @@ void my_image_set_source_pixbuf(MyImage *image, GdkPixbuf *pixbuf)
{
image->surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
}
gtk_drawing_area_set_content_width(GTK_DRAWING_AREA(image), width);
gtk_drawing_area_set_content_height(GTK_DRAWING_AREA(image), height);
cairo_t *cr = cairo_create(image->surface);
gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0);