/* Create an object for the pegs that get moved around in the game. * *WeimplementtheGdkPaintableinterfaceforthem,sowecanuseGtkPicture *objectsforthewholesweputthepegsinto.
*/ #define SOLITAIRE_TYPE_PEG (solitaire_peg_get_type ())
G_DECLARE_FINAL_TYPE (SolitairePeg, solitaire_peg, SOLITAIRE, PEG, GObject)
/* Declare the struct. */ struct _SolitairePeg
{
GObject parent_instance;
/* Here, we implement the functionality required by the GdkPaintable interface */ staticvoid
solitaire_peg_snapshot (GdkPaintable *paintable,
GdkSnapshot *snapshot, double width, double height)
{ /* The snapshot function is the only function we need to implement. *Itdoestheactualdrawingofthepaintable.
*/
gtk_snapshot_append_color (snapshot,
&(GdkRGBA) { 0.6, 0.3, 0.0, 1.0 },
&GRAPHENE_RECT_INIT (0, 0, width, height));
}
static GdkPaintableFlags
solitaire_peg_get_flags (GdkPaintable *paintable)
{ /* The flags are very useful to let GTK know that this image *isnevergoingtochange. *Thisallowsmanyoptimizationsandshouldthereforealways *beset.
*/ return GDK_PAINTABLE_STATIC_CONTENTS | GDK_PAINTABLE_STATIC_SIZE;
}
/* When defining the GType, we need to implement the GdkPaintable interface */
G_DEFINE_TYPE_WITH_CODE (SolitairePeg, solitaire_peg, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
solitaire_peg_paintable_init))
/* Here's the boilerplate for the GObject declaration. *Wedon'tneedtodoanythingspecialhere,becausewekeepno *dataofourown.
*/ staticvoid
solitaire_peg_class_init (SolitairePegClass *klass)
{
}
staticint
check_move (GtkGrid *grid, int x, int y, int dx, int dy)
{
GtkWidget *image; /* We have a peg at x, y. *Checkifwecanmovethepegtox+2*dx,y+2*dy
*/
image = gtk_grid_get_child_at (grid, x + dx, y + dy); if (!GTK_IS_IMAGE (image) ||
!SOLITAIRE_IS_PEG (gtk_image_get_paintable (GTK_IMAGE (image)))) return0;
image = gtk_grid_get_child_at (grid, x + 2*dx, y + 2*dy); if (!GTK_IMAGE (image) ||
SOLITAIRE_IS_PEG (gtk_image_get_paintable (GTK_IMAGE (image)))) return0;
return1;
}
staticvoid
check_for_end (GtkGrid *grid)
{
GtkWidget *image; int x, y; int pegs; int moves;
pegs = 0;
moves = 0; for (x = 0; x < 7; x++)
{ for (y = 0; y < 7; y++)
{
image = gtk_grid_get_child_at (grid, x, y); if (GTK_IS_IMAGE (image) &&
SOLITAIRE_IS_PEG (gtk_image_get_paintable (GTK_IMAGE (image))))
{
pegs++;
moves += check_move (grid, x, y, 1, 0);
moves += check_move (grid, x, y, -1, 0);
moves += check_move (grid, x, y, 0, 1);
moves += check_move (grid, x, y, 0, -1);
}
/* This notifies us that the drag has begun. *Wecannowsetuptheiconandthewidgetfortheongoingdrag.
*/ staticvoid
drag_begin (GtkDragSource *source,
GdkDrag *drag,
GtkWidget *image)
{
GdkPaintable *paintable = gtk_image_get_paintable (GTK_IMAGE (image));
/* We guaranteed in the drag_prepare function above that we *onlystartadragifapegisavailable. *Solet'smakesurewedidnotscrewthatup.
*/
g_assert (SOLITAIRE_IS_PEG (paintable));
/* We use the peg as the drag icon.
*/
gtk_drag_source_set_icon (source, paintable, -2, -2);
/* We also attach it to the drag operation as custom user data, *sothatwecangetitbacklaterifthedragfails.
*/
g_object_set_data (G_OBJECT (drag), "the peg", paintable);
/* Because we are busy dragging the peg, we want to unset it *ontheimage.
*/
gtk_image_clear (GTK_IMAGE (image));
}
/* This is called once a drag operation has ended (successfully or not). *Wewanttoundowhatwedidindrag_begin()aboveandreact *toapotentialmoveofthepeg.
*/ staticvoid
drag_end (GtkDragSource *source,
GdkDrag *drag,
gboolean delete_data,
GtkWidget *image)
{
SolitairePeg *peg;
/* If the drag was successful, we should now delete the peg. *Wedidthisindrag_begin()abovetoprepareforthedrag,so *there'snoneedtodoanythinganymore.
*/ if (delete_data) return;
/* However, if the drag did not succeed, we need to undo what *wedidindrag_begin()andreinsertthepeghere. *Becauseweuseditasthedragdata
*/
peg = g_object_get_data (G_OBJECT (drag), "the peg");
gtk_image_set_from_paintable (GTK_IMAGE (image), GDK_PAINTABLE (peg));
}
/* Whenever a new drop operation starts, we need to check if we can *acceptit. *Thedefaultcheckunfortunatelyisnotgoodenough,becauseitonly *checksthedatatype.Butwealsoneedtocheckifourimagecan *evenacceptdata.
*/ static gboolean
drop_accept (GtkDropTarget *target,
GdkDrop *drop,
GtkWidget *image)
{ /* First, check the drop is actually trying to drop a peg */ if (!gdk_content_formats_contain_gtype (gdk_drop_get_formats (drop), SOLITAIRE_TYPE_PEG)) returnFALSE;
/* If the image already contains a peg, we cannot accept another one */ if (SOLITAIRE_IS_PEG (gtk_image_get_paintable (GTK_IMAGE (image)))) returnFALSE;
grid = GTK_GRID (gtk_widget_get_parent (image)); /* The value contains the data in the type we demanded. *WedemandedaSolitairePeg,sothat'swhatweget.
*/
peg = g_value_get_object (value);
/* Make sure this was a legal move. */ /* First, figure out the image's position in the grid. */
gtk_grid_query_child (grid,
image,
&image_x, &image_y,
NULL, NULL);
/* If the peg was not moved 2 spaces horizontally or vertically, *thiswasnotavalidjump.Rejectit.
*/ if (!((ABS (image_x - peg->x) == 2 && image_y == peg->y) ||
(ABS (image_y - peg->y) == 2 && image_x == peg->x))) returnFALSE;
/* Get the widget that was jumped over
*/
jumped = gtk_grid_get_child_at (grid,
(image_x + peg->x) / 2,
(image_y + peg->y) / 2); /* If the jumped widget does not have a peg in it, this move *isn'tvalid.
*/ if (!SOLITAIRE_IS_PEG (gtk_image_get_paintable (GTK_IMAGE (jumped)))) returnFALSE;
/* Finally, we know it's a legal move. */
/* Clear the peg of the jumped-over image */
gtk_image_clear (GTK_IMAGE (jumped));
/* Add the peg to this image */
solitaire_peg_set_position (peg, image_x, image_y);
gtk_image_set_from_paintable (GTK_IMAGE (image), GDK_PAINTABLE (peg));
/* Maybe we have something to celebrate */
check_for_end (grid);
/* Set up the drop target. *Thisismoreinvolved,becausethegamelogicgoeshere.
*/
/* First we specify the data we accept: pegs. *Andweonlywantmoves.
*/
target = gtk_drop_target_new (SOLITAIRE_TYPE_PEG, GDK_ACTION_MOVE); /* Then we connect our signals.
*/
g_signal_connect (target, "accept", G_CALLBACK (drop_accept), image);
g_signal_connect (target, "drop", G_CALLBACK (drop_drop), image); /* Finally, like above, we add it to the widget.
*/
gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (target));
}
}
if (!gtk_widget_get_visible (window))
gtk_widget_set_visible (window, TRUE); else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}
Messung V0.5 in Prozent
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.1Bemerkung:
(vorverarbeitet am 2026-07-02)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.