Forum > GTK
Creating own widget in GTK
(1/1)
yyttyy:
The question will be very big! I'm a newbie and I'm currently writing a mini-project. I needed a button widget for it, but the standard widget didn't suit me, because I needed a button with my own style. I was looking for tutorials on creating my own widget and creating my own button. I found something, but widgets are implemented differently everywhere. I also found something about creating a button, but it wasn't a separate widget, just a single button implementation that didn't allow me to make multiple buttons(and I needed several). But thanks to this tutorial, I realized that it's best to use the cairo library to draw the context (image) inside the button. In short, here's what I managed to write:
Something like a header for types, and so on:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---unit ButtonWidgetHeader; interface uses glib2, gdk2pixbuf, gdk2, gtk2, Cairo; type button_widget_state = (state_button_normal, state_button_hovered, state_button_pressed); type PGtkButtonWidget = ^TGtkButtonWidget; TGtkButtonWidget = record button_widget : TGtkFixed; state : button_widget_state; drawing_box : PGtkWidget; end; type PGtkButtonWidgetClass = ^TGtkButtonWidgetClass; TGtkButtonWidgetClass = record parent_class : TGtkFixedClass; press_button : procedure (button_widget : PGtkButtonWidget);cdecl; release_button : procedure (button_widget : PGtkButtonWidget);cdecl; end; function GTK_TYPE_BUTTON_WIDGET() : GType;function GTK_BUTTON_WIDGET(obj : gpointer) : PGtkButtonWidget;function GTK_IS_BUTTON_WIDGET(obj : gpointer) : gboolean; implementation function GTK_TYPE_BUTTON_WIDGET() : GType;begin GTK_TYPE_BUTTON_WIDGET := gtk_button_get_type();end; function GTK_BUTTON_WIDGET(obj : gpointer) : PGtkButtonWidget;begin GTK_BUTTON_WIDGET := PGtkButtonWidget(G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_BUTTON_WIDGET))end; function GTK_IS_BUTTON_WIDGET(obj : gpointer) : gboolean;begin GTK_IS_BUTTON_WIDGET := G_TYPE_CHECK_INSTANCE_TYPE(obj, gtk_button_get_type());end; end.
And the widget itself:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---unit ButtonWidget; interface uses glib2, gdk2pixbuf, gdk2, gtk2, Cairo, ButtonWidgetHeader in '/home/yarik/Desktop/ButtonWidgetUnit(Incorrectly)/' + 'ButtonWidgetHeader.pp', Header in '/home/yarik/Desktop/Zhuzhculator/Prog/Units/Header/Header.pp'; function gtk_button_widget_new(pathnorm, pathhover, pathpress, pathmask : PathArr; width, height : integer) : PGtkWidget; implementation procedure gtk_button_widget_class_init(class : PGtkButtonWidgetClass); cdecl; forward;procedure gtk_button_widget_init(button_widget : PGtkButtonWidget); cdecl; forward;procedure move_cursor(widget : PGtkWidget; event : PGdkEventCrossing; user_data : gpointer);cdecl; forward;procedure press_cursor(widget : PGtkWidget; event : PGdkEventButton; user_data : gpointer);cdecl; forward; procedure gtk_button_widget_unrealize(widget : PGtkWidget); cdecl; forward; procedure gtk_button_widget_update(button_widget : PGtkButtonWidget); forward;procedure button_context_create(button_widget : PGtkButtonWidget; width, height : integer); forward;procedure button_images_init(); forward; type button_signals = (PRESS_BUTTON_SIGNAL, RELEASE_BUTTON_SIGNAL); button_images = (image_button_normal, image_button_hovered, image_button_pressed, image_button_mask); button_pathes = (path_button_normal, path_button_hovered, path_button_pressed, path_button_mask);var date_type : GType = 0; button_widget_signals : array [button_signals] of guint = (0, 0); button_widget_images : array [button_images] of Pcairo_surface_t; button_widget_pathes : array [button_pathes] of PathArr; parent_class : PGtkWidgetClass = nil; function gtk_button_get_type() : GType;const date_info : TGTypeInfo = (class_size : SizeOf(TGtkButtonWidgetClass); base_init : nil; base_finalize : nil; class_init : TGClassInitFunc (@gtk_button_widget_class_init); class_finalize : nil; class_data : nil; instance_size : SizeOf(TGtkButtonWidget); n_preallocs : 0; instance_init : TGInstanceInitFunc (@gtk_button_widget_init););begin if (date_type = 0) then date_type := g_type_register_static( GTK_TYPE_EVENT_BOX, 'GtkButtonWidget', @date_info, 0 ); gtk_button_get_type := date_type;end; procedure gtk_button_widget_class_init(class : PGtkButtonWidgetClass);cdecl;var widget_class : PGtkWidgetClass;begin widget_class := GTK_WIDGET_CLASS(class); widget_class^.unrealize := @gtk_button_widget_unrealize; button_widget_signals[PRESS_BUTTON_SIGNAL] := g_signal_new( 'press_button', G_OBJECT_CLASS_TYPE(G_OBJECT_CLASS(class)), G_SIGNAL_RUN_FIRST, @class^.press_button - pointer(class), nil, nil, @g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); button_widget_signals[RELEASE_BUTTON_SIGNAL] := g_signal_new( 'release_button', G_OBJECT_CLASS_TYPE(G_OBJECT_CLASS(class)), G_SIGNAL_RUN_FIRST, @class^.release_button - pointer(class), nil, nil, @g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);end; procedure gtk_button_widget_init(button_widget : PGtkButtonWidget);cdecl;begin button_widget^.state := state_button_normal; button_widget^.drawing_box := gtk_drawing_area_new(); gtk_widget_realize(GTK_WIDGET(button_widget)); button_widget^.drawing_box^.window := gdk_window_new(GTK_WIDGET(button_widget)^.window, nil, 0); gtk_widget_realize(button_widget^.drawing_box); gtk_widget_show(button_widget^.drawing_box); gtk_container_add(GTK_CONTAINER(button_widget), button_widget^.drawing_box); gtk_widget_set_events (GTK_WIDGET(button_widget), GDK_ENTER_NOTIFY_MASK or GDK_LEAVE_NOTIFY_MASK); g_signal_connect (G_OBJECT(button_widget), 'button-press-event', G_CALLBACK(@press_cursor), nil); g_signal_connect (G_OBJECT(button_widget), 'button-release-event', G_CALLBACK(@press_cursor), nil); g_signal_connect (G_OBJECT(button_widget), 'enter-notify-event', G_CALLBACK(@move_cursor), nil); g_signal_connect (G_OBJECT(button_widget), 'leave-notify-event', G_CALLBACK(@move_cursor), nil);end; procedure move_cursor(widget : PGtkWidget; event : PGdkEventCrossing; user_data : gpointer);cdecl;//const // hand_cursor : PGdkCursor = nil;begin if (event^._type = GDK_ENTER_NOTIFY) then begin // if (hand_cursor = nil) then // begin // hand_cursor := gdk_cursor_new(GDK_HAND2); // gdk_window_set_cursor(widget^.window, hand_cursor) // end; GTK_BUTTON_WIDGET(widget)^.state := state_button_hovered; gtk_widget_queue_draw(GTK_BUTTON_WIDGET(widget)^.drawing_box); end; if (event^._type = GDK_LEAVE_NOTIFY) then begin GTK_BUTTON_WIDGET(widget)^.state := state_button_normal; gtk_widget_queue_draw(GTK_BUTTON_WIDGET(widget)^.drawing_box); end; gtk_button_widget_update(GTK_BUTTON_WIDGET(widget));end; procedure press_cursor(widget : PGtkWidget; event : PGdkEventButton; user_data : gpointer);cdecl;begin if (event^._type = GDK_BUTTON_PRESS) then begin g_signal_emit(GTK_BUTTON_WIDGET(widget), button_widget_signals[PRESS_BUTTON_SIGNAL], 0); GTK_BUTTON_WIDGET(widget)^.state := state_button_pressed; gtk_widget_queue_draw(GTK_BUTTON_WIDGET(widget)^.drawing_box); end; if (event^._type = GDK_BUTTON_RELEASE) then begin g_signal_emit(GTK_BUTTON_WIDGET(widget), button_widget_signals[RELEASE_BUTTON_SIGNAL], 0); GTK_BUTTON_WIDGET(widget)^.state := state_button_hovered; end; gtk_button_widget_update(GTK_BUTTON_WIDGET(widget));end; procedure gtk_button_widget_unrealize(widget : PGtkWidget);cdecl;var button_widget : PGtkButtonWidget;begin if(widget = nil) then; exit; if(GTK_IS_BUTTON_WIDGET(widget) = false) then exit; button_widget := GTK_BUTTON_WIDGET(widget); if(button_widget^.drawing_box <> nil) then g_free(button_widget^.drawing_box); if(GTK_OBJECT_CLASS(parent_class)^.destroy <> nil) then GTK_OBJECT_CLASS(parent_class)^.destroy(GTK_OBJECT(widget))end; function gtk_button_widget_new(pathnorm, pathhover, pathpress, pathmask : PathArr; width, height : integer) : PGtkWidget;var button_widget : PGtkButtonWidget;begin button_widget := g_object_new(GTK_TYPE_BUTTON_WIDGET, nil); button_widget_pathes[path_button_normal] := pathnorm; button_widget_pathes[path_button_hovered] := pathhover; button_widget_pathes[path_button_pressed] := pathpress; button_widget_pathes[path_button_mask] := pathmask; button_images_init(); button_context_create(button_widget, width, height); gtk_button_widget_update(button_widget); gtk_button_widget_new := GTK_WIDGET(button_widget);end; procedure button_images_init();begin button_widget_images[image_button_normal] := cairo_image_surface_create_from_png( @button_widget_pathes[path_button_normal]); button_widget_images[image_button_hovered] := cairo_image_surface_create_from_png( @button_widget_pathes[path_button_hovered]); button_widget_images[image_button_pressed] := cairo_image_surface_create_from_png( @button_widget_pathes[path_button_pressed]); button_widget_images[image_button_mask] := cairo_image_surface_create_from_png( @button_widget_pathes[path_button_mask]);end; procedure button_context_create(button_widget : PGtkButtonWidget; width, height : integer);var mask_pixmap : PGdkPixmap; context : Pcairo_t;begin mask_pixmap := gdk_pixmap_new(nil, width, height, 1); context := gdk_cairo_create(mask_pixmap); cairo_set_source_surface(context, button_widget_images[image_button_mask], 0, 0); cairo_paint(context); cairo_destroy(context); gtk_widget_shape_combine_mask(button_widget^.drawing_box, mask_pixmap, 0, 0); gtk_widget_set_size_request(button_widget^.drawing_box, width, height);end; procedure gtk_button_widget_update(button_widget : PGtkButtonWidget);var cr : Pcairo_t;begin cr := gdk_cairo_create(button_widget^.drawing_box^.window); case button_widget^.state of state_button_normal: cairo_set_source_surface(cr, button_widget_images[image_button_normal], 0, 0); state_button_hovered: cairo_set_source_surface(cr, button_widget_images[image_button_hovered], 0, 0); state_button_pressed: cairo_set_source_surface(cr, button_widget_images[image_button_pressed], 0, 0); end; cairo_paint(cr); cairo_destroy(cr);end; end.
When creating a button with the button_widget_new (...) there are such errors:
(ZhuzhMain:11860): Gtk-CRITICAL **: 12:52:58.972: IA__gtk_widget_shape_combine_mask: assertion 'GTK_IS_WIDGET (widget)' failed
(ZhuzhMain:11860): Gtk-CRITICAL **: 12:52:58.972: IA__gtk_widget_set_size_request: assertion 'GTK_IS_WIDGET (widget)' failed
An unhandled exception occurred at $000000000043C7D8:
EAccessViolation: Access violation
$000000000043C7D8
$000000000043C67D
$0000000000409A0B
I tried everything, but I don't understand what the problem is. Maybe I'm writing absolutely the wrong thing. Knowledgeable people please help!
Navigation
[0] Message Index