I have added GtkMenu using following code:
// Add popup menu.
gtk_menu_popup( GTK_MENU (widget), NULL, NULL, set_position, NULL,
bevent->button, bevent->time);
And to adjust this GtkMenu under my button i have used this function:
void set_position (GtkMenu *menu, gint *px, gint *py, gboolean *push_in, gpointer data)
{
gint w, h;
GtkBuilder *builder = GetBuilderPointer();
GtkWidget *button = GTK_WIDGET( gtk_builder_get_object( builder, "button_presence"));
gdk_window_get_size (button->window, &w, &h);
gdk_window_get_origin (button->window, px, py);
*py = h;
printf("\n\n w[%d] h[%d] px[%d] py[%d]\n\n", w, h, *px, *py );
*push_in = TRUE;
}
but popup is getting displayed at the end of the whole window not at the end of the button...
Out put of the printf:
w[350] h[400] px[341] py[607]
what is going wrong why it is not giving x, y and height, width of button correctly?
Note: The button widget used in this, is a custom composite widget with (GtkHBox+(GtkImage+GtkLabel)) in it.
I have tried same code with normal label button but still GtkMenu is getting displayed
under root window not under button.
Why this might be happening... i am relay stuck on this...
thnaks,
PP
Ok Let me answer this.... if anyone is facing the same problem he/she can refer this..
To Adjust GtkMenu under GtkButton (Custom Composite Button).. use following set position callback function...
static void
pos_func( GtkMenu *menu,
gint *x,
gint *y,
gboolean *push,
GtkWidget *widget )
{
GtkRequisition req;
gtk_widget_size_request( widget, &req );
gdk_window_get_origin( gtk_widget_get_window( widget ), x, y );
*x += widget->allocation.x;
*y += widget->allocation.y + req.height;
*push = TRUE;
}
This will set position of GtkMenu under GtkButton Widget!
Related
Gtk3 in C: I am trying to create a window that loads a picture from a png/jpeg file. I want the user to be able to resize the window and automatically scale the picture to fit the window.
So here is what I do:
app = gtk_application_new("foo", G_APPLICATION_FLAGS_NONE);
g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
status = g_application_run(G_APPLICATION(app), argc, argv);
then the activate method does:
GtkWidget *window;
window = gtk_application_window_new(app);
gtk_window_set_title(GTK_WINDOW(window), "foo");
gtk_window_set_default_size(GTK_WINDOW(window), 600, 600);
GError *err = NULL;
// Note: original and image are global variables, because I can't
// get user_data for callbacks working. Will sort this out later.
original = gdk_pixbuf_new_from_file("myfile.png", &err);
if (err != NULL) {
fatalf(scope, "Unable to read file: %s\n", err->message);
exit(1);
}
image = gtk_image_new();
gtk_container_add(GTK_CONTAINER(window), image);
gtk_widget_show_all(window);
g_signal_connect(G_OBJECT(window), "configure-event", G_CALLBACK(resize_picture), NULL);
and the resize_picture:
gint w, h;
gtk_window_get_size(window, &w, &h);
GdkPixbuf *resized = gdk_pixbuf_scale_simple(original, w, h, GDK_INTERP_BILINEAR);
gtk_image_set_from_pixbuf(image, resized);
Now the problem is that the GtkImage appears to impose the minimum size on the window. I can enlarge the window, which scales up the picture, but I cannot shrink it. Is there some property I can set on GtkWindow or GtkImage to allow me to do that? Or do I need to use something else than GtkImage?
The solution is to switch to GTK4 and use GtkPicture instead of GtkImage.
GtkPicture has can_shrink property, which solves this problem.
I want to implement custom widgets by subclassing DrawingArea Widget, for this I need to draw using cairo. It seems like in gtk3 there is a new signal called 'draw' introduced. How do I draw inside the widget? Should the map and realize signals also be overrided?
A simple example code would be very helpful. Thanks.
To put it simply, you'll need to override the draw signal which will supply a Cairo context:
gboolean
user_function (GtkWidget *widget,
CairoContext *cr,
gpointer user_data)
Then you can use the CairoContext crto draw the actual contents of the widget.
From the C API:
The GtkDrawingArea widget is used for creating custom user interface
elements. It’s essentially a blank widget; you can draw on it. After
creating a drawing area, the application may want to connect to:
Mouse and button press signals to respond to input from the user. (Use
gtk_widget_add_events() to enable events you wish to receive.)
The “realize” signal to take any necessary actions when the widget is instantiated on a particular display. (Create GDK resources in
response to this signal.)
The “size-allocate” signal to take any necessary actions when the widget changes size.
The “draw” signal to handle redrawing the contents of the widget.
The widget should queue some draws when the widget changes, for example, on size allocate you should use gtk_widget_queue_draw to force the widget to draw itsef again.
Example - Using a drawing area not as sub classing it but the concept remains:
(taken from Gnome C API)
gboolean
draw_callback (GtkWidget *widget, cairo_t *cr, gpointer data)
{
guint width, height;
GdkRGBA color;
GtkStyleContext *context;
context = gtk_widget_get_style_context (widget);
width = gtk_widget_get_allocated_width (widget);
height = gtk_widget_get_allocated_height (widget);
gtk_render_background (context, cr, 0, 0, width, height);
cairo_arc (cr,
width / 2.0, height / 2.0,
MIN (width, height) / 2.0,
0, 2 * G_PI);
gtk_style_context_get_color (context,
gtk_style_context_get_state (context),
&color);
gdk_cairo_set_source_rgba (cr, &color);
cairo_fill (cr);
return FALSE;
}
[...]
GtkWidget *drawing_area = gtk_drawing_area_new ();
gtk_widget_set_size_request (drawing_area, 100, 100);
g_signal_connect (G_OBJECT (drawing_area), "draw",
G_CALLBACK (draw_callback), NULL);
You should also read about Height-for-width Geometry Management in GtkWidget
I've used C because there was no reference to programming language on your question and at the same time it's the original API from which all other are written.
There are some examples about creating Gtk+ custom Widgets on the internet.
I use this code for crop selection:
gboolean mouse_press_callback(GtkWidget *event_box,
GdkEventButton *event,
gpointer data)
{
if (img1buffer == NULL)
return TRUE;
static gint press_x = 0, press_y = 0, rel_x = 0, rel_y = 0;
GtkAllocation ebox;
gint img1_x_offset = 0, img1_y_offset = 0;
gtk_widget_get_allocation(event_box, &ebox);
img1_x_offset = (ebox.width - width) / 2;
img1_y_offset = (ebox.height - height) / 2;
if (event->type == GDK_BUTTON_PRESS)
{
press_x = event->x - img1_x_offset;
press_y = event->y - img1_y_offset;
//g_print ("Event box clicked at coordinates %f,%f\n",
//event->x - img1_x_offset, event->y - img1_y_offset);
}
else if (event->type == GDK_BUTTON_RELEASE)
{
rel_x = event->x - img1_x_offset;
rel_y = event->y - img1_y_offset;
//g_print ("Event box released at coordinates %f,%f\n",
//event->x - img1_x_offset, event->y - img1_y_offset);
dest_x = rel_x < press_x ? rel_x : press_x;
dest_y = rel_y < press_y ? rel_y : press_y;
dest_width = abs(rel_x - press_x);
dest_height = abs(rel_y - press_y);
// mark user selection in image
GdkPixbuf *img1buffer_resized = gdk_pixbuf_scale_simple(img1buffer, width, height, GDK_INTERP_TILES);
gdk_pixbuf_composite(croppic, img1buffer_resized, dest_x, dest_y, dest_width, dest_height, 0, 0, 1, 1, GDK_INTERP_TILES, 170);
gtk_image_set_from_pixbuf(GTK_IMAGE(img1), img1buffer_resized);
}
return TRUE;
}
that in main function:
croppic = gdk_pixbuf_new_from_file("E:/Works for Gov Project/DOC/GUI/logogui1/crop_bg.png", NULL);
img1 = gtk_image_new();
event_box = gtk_event_box_new();
gtk_event_box_set_visible_window(GTK_EVENT_BOX(event_box), FALSE);
gtk_container_add(GTK_CONTAINER(event_box), img1);
gtk_container_add(GTK_CONTAINER(frame1), event_box);
g_signal_connect(G_OBJECT(event_box), "button_press_event", G_CALLBACK(mouse_press_callback), NULL);
g_signal_connect(G_OBJECT(event_box), "button-release-event", G_CALLBACK(mouse_press_callback), NULL);
and "crop_bg.png" is:
But I want to a selection shape similar to in paint software:
What ideas on how to solve this task would you suggest? Or on what resource on the internet can I find help?
You are trying to draw on top of a GtkImage. This isn't the best way to do custom drawing, and as you've noticed, gdk_pixbuf_composite() is rather limited.
Instead, you'll want to do drawing the proper way, using the ::draw signal and cairo. cairo is the vector graphics library that GTK+ 3 uses to draw its own widgets, and the ::draw signal gives you a cairo context to draw with:
gboolean draw(GtkWidget *widget, cairo_t *cr, void *data);
cairo itself is easy to use; it's well documented and has a whole bunch of samples. What you want to do for your purposes is make a dashed stroked rectangle.
In addition, instead of using a GtkImage, you'll want to use GtkDrawingArea. GtkDrawingArea is specifically designed to be drawn on, and with a little extra work can be made to handle your events.
The last piece of the puzzle, then, is how do you start drawing when the mouse events come in? You don't get a cairo_t in button-press-event or button-release-event, so you can't draw there. Indeed, GTK+ is optimized so that it only draws when necessary. To indicate that it's necessary to draw, you can use the gtk_widget_queue_draw() method. There are variations on this method that mark only a subset of the widget to be redrawn (you can get this subset back with cairo_clip_extents() from within the ::draw handler).
Remember that widget coordinates are floating-point; so are cairo coordinates.
Let's demonstrate. I'm going to use global variables for this; you probably don't want to.
gdouble x0, y0;
gdouble x1, y1;
These will store the endpoints of the rectangle. When we press the mouse button, we want to start the drawing:
gboolean button_press_event(GtkWidget *widget, GdkEventButton *e, gpointer data)
{
// ...
x0 = e->x;
y0 = e->y;
x1 = e->x; // start with a zero-sized rectangle
y1 = e->y;
// ...
}
When we move the mouse, we want to change x1 and y1 to the new mouse coordinates, and then update the rectangle. To optimize things, we'll only update the area that changed:
gboolean motion_notify_event(GtkWidget *widget, GdkEventMotion *e, gpointer data)
{
// ...
// first queue both old and new rectangles for drawing
gtk_widget_queue_draw_area(widget,
x0, y0,
MAX(x1, e->x), MAX(y1, e->y));
// then set the new rectangle
x1 = e->x;
y1 = e->y;
// ...
}
You can probably figure out what to do on button-release-event from the above. draw would look something like
gboolean draw(GtkWidget *widget, cairo_t *cr, gpointer data)
{
// ...
cairo_rectangle(cr, x0, y0, x1 - x0, y1 - y0);
// set up a dashed solid-color stroke
cairo_stroke(cr);
// ...
}
Good luck!
I have a GtkMenu Widget and i am adding it to screen on button click,,
but it gets added at mouse location but i want to add it to end edge of button widget like,
+-------+
|BUTTON |
+-------+
+------------+
|Menu Item 1 |
|Menu Item 2 |
+------------+
I am using following code to add popup menu
// Add popup menu.
gtk_menu_popup( GTK_MENU (widget), NULL, NULL, NULL, NULL,
bevent->button, bevent->time);
Ok added this function but popup menu gets added to end of window not at the end of button widget...
void set_position (GtkMenu *menu, gint *px, gint *py, gboolean *push_in, gpointer data)
{
gint w, h;
GtkBuilder *builder = GetBuilderPointer();
GtkWidget *button = GTK_WIDGET( gtk_builder_get_object( builder, "button_presence"));
gdk_window_get_size (button->window, &w, &h);
gdk_window_get_origin (button->window, px, py);
*py = h;
printf("\n\n w[%d] h[%d] px[%d] py[%d]\n\n", w, h, *px, *py );
*push_in = TRUE;
}
Printf gives output like follows,
w[350] h[400] px[341] py[607]
i am not able to retrieve x, y, height, width of button widget...
Note: This button is a custom widget with (GtkHBox+(GtkImage+GtkLabel)) in it.
thanks unwind for your answer.
The fourth argument to gtk_menu_popup() is a pointer to a GtkMenuPositionFunc, which is a callback that you can define. You need to add such a callback, and have it return the desired position, by reading it out of the button widget's GdkWindow.
It's been a while since I did this, but you might also have to read out the parent window's position on-screen, and add the widget's position to them to get the absolute coordinates where you want the menu to pop up.
If I'm writing an application that wants to communicate some information through the use of color, how can I change the background and foreground colors of a given widget? I would like to know how to do this in glade if it's possible, as well as programmatically (to a computed color).
I want to know how to do this to a complex widget as well, for example, an HBox that contains a VBox that contains some Labels.
Ideally this would also include a solution solution that allows me to tint the widget's existing colors, and identify the average colors of any images in use by the theme, so that I can programmatically compensate for any color choices which might make text unreadable or otherwise clashing - but I would be happy if I could just turn a button red.
Example program:
#include <gtk/gtk.h>
static void on_destroy(GtkWidget* widget, gpointer data)
{
gtk_main_quit ();
}
int main (int argc, char* argv[])
{
GtkWidget* window;
GtkWidget* button;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(G_OBJECT (window), "destroy",
G_CALLBACK (on_destroy), NULL);
button = gtk_button_new_with_label("Hello world!");
GdkColor red = {0, 0xffff, 0x0000, 0x0000};
GdkColor green = {0, 0x0000, 0xffff, 0x0000};
GdkColor blue = {0, 0x0000, 0x0000, 0xffff};
gtk_widget_modify_bg(button, GTK_STATE_NORMAL, &red);
gtk_widget_modify_bg(button, GTK_STATE_PRELIGHT, &green);
gtk_widget_modify_bg(button, GTK_STATE_ACTIVE, &blue);
gtk_container_add(GTK_CONTAINER(window), button);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
The best documentation that I know of is the one available here: http://ometer.com/gtk-colors.html
You can always use gtk_widget_override_color () and gtk_widget_override_background_color (). These two functions allow you to change the color of a widget. But it is better to use CSS classes and regions in your widget/container implementation through gtk_style_context_add_class() and gtk_style_context_add_region().
To modify the color of a widget you can initialize a color and use it to modify the color of the widget:
GdkColor color;
gdk_color_parse("#00FF7F", &color);
gtk_widget_modify_bg(widget, GTK_STATE_NORMAL, &color);
To use an image instead of color:
GdkPixbuf *image = NULL;
GdkPixmap *background = NULL;
GtkStyle *style = NULL;
image = gdk_pixbuf_new_from_file ("background.jpg", NULL);
gdk_pixbuf_render_pixmap_and_mask (image, &background, NULL, 0);
style = gtk_style_new ();
style->bg_pixmap [0] = background;
gtk_widget_set_style (GTK_WIDGET(widget), GTK_STYLE (style));