[cairo-commit] cairo-demo/gtk_slide COPYING, NONE, 1.1 ChangeLog,
NONE, 1.1 Makefile, NONE, 1.1 README, NONE, 1.1 cairo_custom.c,
NONE, 1.1 cairo_custom.h, NONE, 1.1 gtk_slide.c, NONE,
1.1 puzzle.c, NONE, 1.1 puzzle.h, NONE, 1.1
Behdad Esfahbod
commit at pdx.freedesktop.org
Thu Aug 11 23:55:18 PDT 2005
- Previous message: [cairo-commit] cairo-demo/gtk_slide - New directory,NONE,NONE
- Next message: [cairo-commit] cairo-demo/gtkcairo_slide COPYING, 1.1,
NONE ChangeLog, 1.10, NONE Makefile, 1.3, NONE README, 1.2,
NONE cairo_custom.c, 1.5, NONE cairo_custom.h, 1.5,
NONE gtkcairo_slide.c, 1.5, NONE puzzle.c, 1.9, NONE puzzle.h,
1.1, NONE
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
Committed by: behdad
Update of /cvs/cairo/cairo-demo/gtk_slide
In directory gabe:/tmp/cvs-serv26486
Added Files:
COPYING ChangeLog Makefile README cairo_custom.c
cairo_custom.h gtk_slide.c puzzle.c puzzle.h
Log Message:
2005-08-12 Behdad Esfahbod <behdad at behdad.org>
* *: port to Gtk+ >= 2.7 instead of GtkCairo. Change the
name everywhere (in filenames too) to reflect this change.
(used to be in gtkcairo_slide)
--- NEW FILE: COPYING ---
(This appears to be a binary file; contents omitted.)
--- NEW FILE: ChangeLog ---
2005-08-12 Behdad Esfahbod <behdad at behdad.org>
* *: port to Gtk+ >= 2.7 instead of GtkCairo. Change the
name everywhere (in filenames too) to reflect this change.
2005-08-08 Ãyvind KolÃ¥s <pippin at freedesktop.org>
* puzzle.c: updated to work with newer cairo api.
2005-04-29 Ãyvind KolÃ¥s <pippin at freedesktop.org>
* gtk_slide.c: reordered functions, made game easier and added
welcome scroll/splash.
2005-01-20 Carl Worth <cworth at cworth.org>
* puzzle.c: Add include of stdio.h now that cairo.h doesn't
provide it.
2004-11-11 Oeyvind Kolaas <pippin at freedesktop.org>
* *.[ch]: reindentation to GNU coding style, and general code
cleanups.
2004-06-23 OEyvind Kolaas <pippin at freedesktop.org>
* puzzle.c : moved the font selection out of the loop drawing the
pieces, this leads to a speedup making gtk_slide useable.
2004-05-13 OEyvind Kolaas <pippin at freedesktop.org>
* *.[ch] : removed gdk_cairo_set_color, replaced with
gtk_cairo_set_gdk_color from GtkCairo
2004-05-11 OEyvind Kolaas <pippin at freedesktop.org>
* *.[ch] : replacing ct with cr
2004-03-01 OEyvind Kolaas <pippin at freedesktop.org>
* cairo_custom.[ch], puzzle.c : replaced cairo_set_gtk_color with
gdk_cairo_set_color
2004-02-15 OEyvind Kolaas <pippin at freedesktop.org>
* gtk_slide.c : removed superflous cairo_save/cairo_restor pairs
2004-02-14 OEyvind Kolaas <pippin at freedesktop.org>
Initial import
--- NEW FILE: Makefile ---
SRCS = $(wildcard *.c)
OBJS = $(SRCS:.c=.o)
LIBS +=`pkg-config --libs gtk+-2.0`
CFLAGS +=`pkg-config --cflags gtk+-2.0` -g
CC = gcc
all: dep gtk_slide
gtk_slide: $(OBJS)
$(CC) -o $@ $(OBJS) $(LIBS) $(LDFLAGS)
@echo
clean:
rm -f *~ gtk_slide .depend *.o *.orig
dep:
$(MAKE) .depend
.depend: $(SRCS) *.c *.h
$(CC) -MM $(CFLAGS) $(SRCS) 1>.depend
--- NEW FILE: README ---
gtk_slide
==============
Custom GTK+ widget and application, demonstrating Cairo support
A cairo implementation of the classic sliding block puzzle, where you're supposed
to slide the blocks into a configuration where the blocks are numbered incrementally.
Implementation
==============
GtkSlide is well behaved and creates a puzzle widget that is derived from the
GtkDrawingArea widget, this is the proper object oriented way of deriving a
custom widget from GtkDrawingArea. Most other examples use the api directly.
Dependencies
============
GtkSlide depends on Gtk+ >= 2.7, and it's dependencies
2004 (c) Øyvind Kolås, pippin at freedesktop.org
--- NEW FILE: cairo_custom.c ---
#include "cairo_custom.h"
void
cairo_rectangle_round (cairo_t *cr,
double x0, double y0,
double width, double height,
double radius)
{
double x1,y1;
x1=x0+width;
y1=y0+height;
if (!width || !height)
return;
if (width/2<radius)
{
if (height/2<radius)
{
cairo_move_to (cr, x0, (y0 + y1)/2);
cairo_curve_to (cr, x0 ,y0, x0, y0, (x0 + x1)/2, y0);
cairo_curve_to (cr, x1, y0, x1, y0, x1, (y0 + y1)/2);
cairo_curve_to (cr, x1, y1, x1, y1, (x1 + x0)/2, y1);
cairo_curve_to (cr, x0, y1, x0, y1, x0, (y0 + y1)/2);
}
else
{
cairo_move_to (cr, x0, y0 + radius);
cairo_curve_to (cr, x0 ,y0, x0, y0, (x0 + x1)/2, y0);
cairo_curve_to (cr, x1, y0, x1, y0, x1, y0 + radius);
cairo_line_to (cr, x1 , y1 - radius);
cairo_curve_to (cr, x1, y1, x1, y1, (x1 + x0)/2, y1);
cairo_curve_to (cr, x0, y1, x0, y1, x0, y1- radius);
}
}
else
{
if (height/2<radius)
{
cairo_move_to (cr, x0, (y0 + y1)/2);
cairo_curve_to (cr, x0 , y0, x0 , y0, x0 + radius, y0);
cairo_line_to (cr, x1 - radius, y0);
cairo_curve_to (cr, x1, y0, x1, y0, x1, (y0 + y1)/2);
cairo_curve_to (cr, x1, y1, x1, y1, x1 - radius, y1);
cairo_line_to (cr, x0 + radius, y1);
cairo_curve_to (cr, x0, y1, x0, y1, x0, (y0 + y1)/2);
}
else
{
cairo_move_to (cr, x0, y0 + radius);
cairo_curve_to (cr, x0 , y0, x0 , y0, x0 + radius, y0);
cairo_line_to (cr, x1 - radius, y0);
cairo_curve_to (cr, x1, y0, x1, y0, x1, y0 + radius);
cairo_line_to (cr, x1 , y1 - radius);
cairo_curve_to (cr, x1, y1, x1, y1, x1 - radius, y1);
cairo_line_to (cr, x0 + radius, y1);
cairo_curve_to (cr, x0, y1, x0, y1, x0, y1- radius);
}
}
cairo_close_path (cr);
}
void
cairo_edgeline (cairo_t *cr,
double x0,
double y0,
double x1,
double y1,
double backoff)
{
y0 = y0 - 1;
y1 = y1 + 1;
cairo_move_to (cr, x0, y0);
if (y1 > y0 + backoff / 2)
{
cairo_curve_to (cr, x0, (y0 + y1) / 2, x1, (y0 + y1) / 2, x1, y1);
}
else
{
cairo_curve_to (cr, x0,
y0 + (backoff / 4 + (y0 + backoff / 2 - y1)), x1,
y1 - (backoff / 4 + (y0 + backoff / 2 - y1)), x1,
y1);
}
}
--- NEW FILE: cairo_custom.h ---
#ifndef CAIRO_CUSTOM_H
#define CAIRO_CUSTOM_H
#include <cairo.h>
void
cairo_rectangle_round (cairo_t * cr,
double x0,
double y0,
double width,
double height,
double radius);
void
cairo_edgeline (cairo_t * cr,
double x0,
double y0,
double x1,
double y1,
double backoff);
#endif /* CAIRO_CUSTOM_H */
--- NEW FILE: gtk_slide.c ---
/* Gtk Slide, a sample game built around the puzzle widget */
/* since the puzzle widget leaves the drawing behavior in a sane state, we can hook up the menu / score
* display on top of it, this might be considered an evil hack, but might make some programming easier
*/
#include <gtk/gtk.h>
#include "puzzle.h"
#define INITIAL_WIDTH 200
#define INITIAL_HEIGHT 210
GtkWidget *puzzle_window;
GtkWidget *puzzle;
GList *messages = NULL;
double y_pos = 0.0;
double y_inc = 0.1;
double fade = 0.0;
int rows = 3;
int cols = 3;
int shuffles = 15;
gboolean update_messages (gpointer data)
{
if (messages)
{
y_pos += y_inc;
if (y_pos > 1.0)
{
char *msg = messages->data;
messages = g_list_remove (messages, msg);
g_free (msg);
y_pos = 0.0;
}
gtk_widget_queue_draw (puzzle);
}
return TRUE;
}
void add_message (const char *message)
{
messages = g_list_append (messages, g_strdup(message));
}
static GtkWidget *
puzzle_window_new (void);
gint
main (gint argc,
gchar *argv[])
{
gtk_init (&argc, &argv);
puzzle_window = puzzle_window_new ();
gtk_widget_show (puzzle_window);
add_message ("");
add_message ("Gtk Slide");
add_message ("");
add_message ("order the boxes");
g_timeout_add (100, update_messages ,puzzle);
gtk_main ();
return 0;
}
static void paint_status (GtkWidget *wdiget,
GdkEventExpose *eev,
gpointer user_data);
static void
puzzle_solved (GtkWidget *widget,
gpointer data);
static GtkWidget *
puzzle_window_new (void) {
GtkWidget *self;
GtkWidget *vbox;
self = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (self), "Sliding Gtk Puzzle");
g_signal_connect (G_OBJECT (self), "delete-event",
G_CALLBACK (gtk_main_quit), NULL);
vbox = gtk_vbox_new (FALSE, 0);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 0);
puzzle = puzzle_new ();
g_signal_connect (G_OBJECT (puzzle), "expose-event",
G_CALLBACK (paint_status), NULL);
g_object_set (G_OBJECT (puzzle), "rows", rows, NULL);
g_object_set (G_OBJECT (puzzle), "cols", cols, NULL);
g_object_set (G_OBJECT (puzzle), "shuffles", shuffles, NULL);
gtk_widget_set_usize (GTK_WIDGET (puzzle), INITIAL_WIDTH, INITIAL_HEIGHT);
g_signal_connect (G_OBJECT (puzzle), "puzzle_solved",
G_CALLBACK (puzzle_solved), puzzle);
gtk_container_add (GTK_CONTAINER (vbox), puzzle);
gtk_container_add (GTK_CONTAINER (self), vbox);
gtk_widget_show_all (vbox);
return self;
}
static void paint_status (GtkWidget *widget,
GdkEventExpose *eev,
gpointer user_data)
{
cairo_t *cr;
double w = widget->allocation.width;
double h = widget->allocation.height;
if (!messages) /* bail out early, if nothing to paint */
return;
cr = gdk_cairo_create (widget->window);
{
if (fade>0.01)
{
cairo_set_source_rgba (cr, 0,0,0, fade);
cairo_rectangle (cr, 0, 0, w*1.0, h*1.0);
cairo_fill (cr);
}
#define FONT_HEIGHT 0.1
#define LINE_HEIGHT 1.3
cairo_set_font_size (cr, h*FONT_HEIGHT);
cairo_select_font_face (cr, "Sans", 0, 0);
{
GList *item = messages;
double x,y;
/*
char utf8[42];
snprintf (utf8, 42, "%iÃ%i @%i", cols, rows, shuffles);
*/
y = FONT_HEIGHT * LINE_HEIGHT - y_pos * FONT_HEIGHT * LINE_HEIGHT;
while (item)
{
cairo_text_extents_t extents;
const char *utf8;
utf8 = item->data;
cairo_text_extents (cr, utf8, &extents);
x = 0.5 - (extents.width / 2 + extents.x_bearing) / w;
cairo_move_to (cr, w*x, h*y);
cairo_text_path (cr, utf8);
cairo_save (cr);
{
cairo_set_source_rgba (cr, 0,0,0,0.2);
cairo_set_line_width (cr, h*0.02);
cairo_stroke (cr);
}
cairo_restore (cr);
cairo_set_source_rgba (cr, 1,1,1,1.0);
cairo_fill (cr);
y+= FONT_HEIGHT * LINE_HEIGHT;
item = g_list_next (item);
}
}
}
cairo_destroy (cr);
}
static void
puzzle_solved (GtkWidget *widget,
gpointer data)
{
GtkWidget *dialog;
GtkWidget *label;
GtkWidget *parent;
parent = gtk_widget_get_toplevel (widget);
dialog = gtk_dialog_new_with_buttons ("GtkSlide - solved",
GTK_WINDOW (parent),
GTK_DIALOG_MODAL,
GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
NULL);
label = gtk_label_new ("You solved the puzzle!");
gtk_misc_set_padding (GTK_MISC (label), 20, 20);
gtk_widget_show (label);
gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), label);
gtk_widget_show (dialog);
gtk_dialog_run (GTK_DIALOG (dialog));
gtk_main_quit ();
}
--- NEW FILE: puzzle.c ---
#include <stdio.h>
#include <stdlib.h>
#include <gtk/gtk.h>
#include "cairo_custom.h"
#include "puzzle.h"
#include "math.h" /* floor() fabs() */
/** game specific functions, defined at end of this file */
static void
board_init (GtkWidget *widget);
static int
query_pos (Puzzle *puzzle,
gint x,
gint y);
static void
push_block (Puzzle *puzzle,
gint block_no,
gdouble xdelta,
gdouble ydelta);
static void
draw_board (Puzzle *puzzle,
cairo_t *cr);
static gint
board_solved (Puzzle *puzzle);
/** drawing_area derived widget **/
static GObjectClass *parent_class = NULL;
typedef struct
{
double x;
double y;
char label[16];
} PuzzleItem;
struct _Puzzle {
GtkDrawingArea drawing_area;
double ratio_x;
double ratio_y;
double cursorx;
double cursory;
PuzzleItem *item;
gint grabbed;
gint rows;
gint cols;
gint shuffles;
};
struct _PuzzleClass {
GtkDrawingAreaClass parent_class;
};
enum {
PUZZLE_SOLVED_SIGNAL,
LAST_SIGNAL
};
enum {
PUZZLE_ROWS=1,
PUZZLE_COLS,
PUZZLE_SHUFFLES
};
static void
set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *psec)
{
Puzzle *puzzle = PUZZLE (object);
switch (property_id)
{
case PUZZLE_COLS:
puzzle->cols = g_value_get_int (value);
board_init (GTK_WIDGET (puzzle));
break;
case PUZZLE_ROWS:
puzzle->rows = g_value_get_int (value);
board_init (GTK_WIDGET (puzzle));
break;
case PUZZLE_SHUFFLES:
puzzle->shuffles = g_value_get_int (value);
board_init (GTK_WIDGET (puzzle));
break;
default:
g_assert (FALSE);
break;
}
}
static void
get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
Puzzle *puzzle = PUZZLE (object);
switch (property_id)
{
case PUZZLE_ROWS:
g_value_set_int (value, puzzle->rows);
break;
case PUZZLE_COLS:
g_value_set_int (value, puzzle->rows);
break;
case PUZZLE_SHUFFLES:
g_value_set_int (value, puzzle->shuffles);
break;
default:
g_assert (FALSE);
break;
}
}
static void
finalize (GObject *object)
{
Puzzle *puzzle = PUZZLE (object);
if (puzzle->item)
{
free (puzzle->item);
}
parent_class->finalize (object);
}
static gint puzzle_signals[LAST_SIGNAL] = { 0 };
static void
puzzle_class_init (PuzzleClass * class)
{
GObjectClass *gobject_class;
gobject_class = G_OBJECT_CLASS (class);
parent_class = g_type_class_peek (GTK_TYPE_DRAWING_AREA);
gobject_class->finalize = finalize;
gobject_class->get_property = get_property;
gobject_class->set_property = set_property;
g_object_class_install_property (gobject_class,
PUZZLE_ROWS,
g_param_spec_int ("rows",
"Number of rows",
"",
0,
20,
0,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PUZZLE_COLS,
g_param_spec_int ("cols",
"Number of cols",
"",
0,
20,
0,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PUZZLE_SHUFFLES,
g_param_spec_int ("shuffles",
"Number of moves shuffling board, (approximate)",
"",
0,
1000000,
0,
G_PARAM_READWRITE));
puzzle_signals[PUZZLE_SOLVED_SIGNAL] =
g_signal_new ("puzzle_solved",
G_TYPE_FROM_CLASS (gobject_class),
G_SIGNAL_RUN_FIRST, 0, NULL, NULL,
g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, NULL);
}
static void
puzzle_init (Puzzle * puzzle)
{
puzzle->cursorx = 0;
puzzle->cursory = 0;
puzzle->rows = 4;
puzzle->cols = 4;
puzzle->shuffles = 200;
puzzle->grabbed = -1;
puzzle->ratio_x = 1;
puzzle->ratio_y = 1;
board_init (GTK_WIDGET (puzzle));
gtk_widget_show_all (GTK_WIDGET (puzzle));
}
GType
puzzle_get_type (void)
{
static GType ge_type = 0;
if (!ge_type)
{
static const GTypeInfo ge_info =
{
sizeof (PuzzleClass),
NULL,
NULL,
(GClassInitFunc) puzzle_class_init,
NULL,
NULL,
sizeof (Puzzle),
0,
(GInstanceInitFunc) puzzle_init,
};
ge_type = g_type_register_static (GTK_TYPE_DRAWING_AREA,
"Puzzle",
&ge_info,
0);
}
return ge_type;
}
/* prototypes for event functions registered with the object */
static gboolean event_press (GtkWidget *widget,
GdkEventButton *bev,
gpointer user_data);
static gboolean event_release (GtkWidget *widget,
GdkEventButton *bev,
gpointer user_data);
static gboolean event_motion (GtkWidget *widget,
GdkEventMotion *mev,
gpointer user_data);
static void puzzle_class_init (PuzzleClass *class);
/* prototpe for the redraw callback we register with drawing_area */
static void paint (GtkDrawingArea *drawing_area,
GdkEventExpose *eev,
gpointer user_data);
GtkWidget *
puzzle_new (void)
{
GtkWidget *widget = GTK_WIDGET (g_object_new (puzzle_get_type (), NULL));
Puzzle *puzzle = PUZZLE (widget);
gtk_widget_set_events (widget,
GDK_EXPOSURE_MASK |
GDK_POINTER_MOTION_HINT_MASK | /* since we do dragging, let the ui update request redraw events */
GDK_BUTTON1_MOTION_MASK |
GDK_BUTTON2_MOTION_MASK |
GDK_BUTTON3_MOTION_MASK |
GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK);
gtk_widget_set_size_request (widget, 256, 256);
g_signal_connect (G_OBJECT (widget), "expose-event",
G_CALLBACK (paint), puzzle);
g_signal_connect (G_OBJECT (widget), "motion_notify_event",
G_CALLBACK (event_motion), puzzle);
g_signal_connect (G_OBJECT (widget), "button_press_event",
G_CALLBACK (event_press), puzzle);
g_signal_connect (G_OBJECT (widget), "button_release_event",
G_CALLBACK (event_release), puzzle);
return widget;
}
/* the actually user interface event functions */
static gboolean
event_press (GtkWidget *widget,
GdkEventButton *bev,
gpointer user_data)
{
Puzzle *puzzle = PUZZLE (user_data);
puzzle->cursorx = bev->x;
puzzle->cursory = bev->y;
switch (bev->button)
{
case 1:
puzzle->grabbed = query_pos (puzzle, bev->x, bev->y);
/* request a redraw, since we've changed the state of our widget */
gtk_widget_queue_draw (GTK_WIDGET (puzzle));
break;
}
return FALSE;
}
static gboolean
event_release (GtkWidget * widget,
GdkEventButton * bev, gpointer user_data) {
Puzzle *puzzle = PUZZLE (user_data);
switch (bev->button)
{
case 1:
puzzle->grabbed = -1;
/* request a redraw, since we've changed the state of our widget */
gtk_widget_queue_draw (GTK_WIDGET (puzzle));
break;
}
return FALSE;
}
static gboolean
event_motion (GtkWidget *widget,
GdkEventMotion *mev,
gpointer user_data)
{
Puzzle *puzzle = PUZZLE (user_data);
if (puzzle->grabbed>=0)
{
double xdelta = (mev->x-puzzle->cursorx) / puzzle->ratio_x;
double ydelta = (mev->y-puzzle->cursory) / puzzle->ratio_y;
push_block (puzzle, puzzle->grabbed, xdelta, ydelta);
if (board_solved (puzzle))
{
g_signal_emit (G_OBJECT (puzzle),
puzzle_signals
[PUZZLE_SOLVED_SIGNAL], 0);
}
/* request a redraw, since we've changed the state of our widget */
gtk_widget_queue_draw (GTK_WIDGET (puzzle));
puzzle->cursorx = mev->x;
puzzle->cursory = mev->y;
}
return FALSE;
}
/* actual paint function */
static void
paint (GtkDrawingArea *drawing_area,
GdkEventExpose *eev,
gpointer user_data)
{
GtkWidget *widget = GTK_WIDGET (drawing_area);
Puzzle *puzzle = PUZZLE (drawing_area);
cairo_t *cr = gdk_cairo_create (widget->window);
puzzle->ratio_x = (double) widget->allocation.width/puzzle->cols;
puzzle->ratio_y = (double) widget->allocation.height/puzzle->rows;
draw_board (puzzle, cr);
if (cairo_status (cr))
{
fprintf (stderr, "Cairo is unhappy: %s\n",
cairo_status_to_string (cairo_status (cr)));
}
cairo_destroy (cr);
/* since we are requesting motion hints,. make sure another motion
event is delivered after redrawing the ui */
gdk_window_get_pointer (widget->window, NULL, NULL, NULL);
}
/*************************************************************************/
/*** end of GtkDrawingArea example, actual game logic follows ***/
/*************************************************************************/
static void
get_empty (Puzzle *puzzle,
gint *col,
gint *row);
static int
get_at (Puzzle *puzzle,
gint col,
gint row);
/* shuffle an initialized board (important, do not
shuffle a board where the coordinates have changed
since initialization, since the shuffeling presumes that
the order haven't changed.
*/
#include <assert.h>
static
void puzzle_shuffle (Puzzle *puzzle,
gint shuffles)
{
while (shuffles--)
{
gint empty_x;
gint empty_y;
gint block_no;
gint direction = g_random_int_range (0, 5);
get_empty (puzzle, &empty_x, &empty_y);
switch (direction)
{
case 0:
if ((block_no=get_at (puzzle, empty_x-1, empty_y))>=0)
{
push_block (puzzle, block_no, 0.5, 0 );
push_block (puzzle, block_no, 0.5, 0 );
}
break;
case 1:
if ((block_no=get_at (puzzle, empty_x+1, empty_y))>=0)
{
push_block (puzzle, block_no, -0.5, 0 );
push_block (puzzle, block_no, -0.5, 0 );
}
break;
case 2:
if ((block_no=get_at (puzzle, empty_x, empty_y-1))>=0)
{
push_block (puzzle, block_no, 0, 0.5);
push_block (puzzle, block_no, 0, 0.5);
}
break;
case 3:
if ((block_no=get_at (puzzle, empty_x, empty_y+1))>=0)
{
push_block (puzzle, block_no, 0, -0.5);
push_block (puzzle, block_no, 0, -0.5);
}
break;
}
}
}
static void
get_empty (Puzzle *puzzle,
gint *col,
gint *row)
{
if (!col || !row)
return;
for (*row=0; *row < puzzle->rows; (*row)++)
for (*col=0; *col < puzzle->cols; (*col)++)
{
gint item_no;
gint found=0;
for (item_no=0;item_no< puzzle->cols*puzzle->rows-1; item_no++)
{
if (puzzle->item[item_no].x == *col && puzzle->item[item_no].y == *row)
found++;
}
if (!found)
return;
}
}
static int
get_at (Puzzle *puzzle,
gint col,
gint row)
{
gint item_no;
for (item_no=0;item_no< puzzle->cols*puzzle->rows-1; item_no++)
{
if (puzzle->item[item_no].x == col &&
puzzle->item[item_no].y == row)
return item_no;
}
return -1;
}
/* initialize a board of specified size */
static void
board_init (GtkWidget *widget)
{
Puzzle *puzzle = PUZZLE (widget);
gint row, col;
if (puzzle->item)
{
free (puzzle->item);
}
puzzle->item = malloc (sizeof (PuzzleItem) * puzzle->rows * puzzle->cols);
for (row=0;row<puzzle->rows;row++)
{
for (col=0;col<puzzle->cols;col++)
{
if (col==puzzle->cols-1 && row==puzzle->rows-1)
{
puzzle->item[row*puzzle->cols + col].x=col;
puzzle->item[row*puzzle->cols + col].y=row;
sprintf (puzzle->item[row*puzzle->cols + col].label, "-");
}
else
{
puzzle->item[row*puzzle->cols + col].x=col;
puzzle->item[row*puzzle->cols + col].y=row;
sprintf (puzzle->item[row*puzzle->cols + col].label, "%i", row*puzzle->cols + col +1);
}
}
}
puzzle_shuffle (puzzle, puzzle->shuffles);
gtk_widget_queue_draw (GTK_WIDGET (puzzle));
}
static gint
board_solved (Puzzle *puzzle)
{
gint item_no=0;
for (item_no=0;item_no<puzzle->rows * puzzle->cols-1;item_no++ )
{
PuzzleItem *item= & (puzzle->item [item_no]);
gint row = item_no/puzzle->cols;
gint col = item_no%puzzle->cols;
if ( item->x != col || item->y != row)
return 0;
}
return 1;
}
/* query which block is at the given mouse coordinates,
returns -1 if no block was found
*/
static gint
query_pos (Puzzle *puzzle,
gint x,
gint y)
{
int item_no;
cairo_t *cr = gdk_cairo_create (GTK_WIDGET (puzzle)->window);
if (!cr)
{
}
cairo_save (cr);
cairo_scale (cr, puzzle->ratio_x, puzzle->ratio_y);
cairo_translate (cr, 0.5, 0.5);
for (item_no=0;item_no<puzzle->rows*puzzle->cols-1;item_no++)
{
PuzzleItem *item = & (puzzle->item [item_no]);
cairo_save (cr);
cairo_rectangle_round (cr, item->x-0.4, item->y-0.4, 0.8, 0.8, 0.4);
if (cairo_in_fill (cr, (x)/ puzzle->ratio_x -0.5, (y) / puzzle->ratio_y -0.5))
{
cairo_restore (cr);
cairo_restore (cr);
return item_no;
}
cairo_restore (cr);
}
cairo_restore (cr);
return -1;
}
static gboolean
item_is_aligned (PuzzleItem *item)
{
return (fabs(floor(item->x)-item->x)<0.01 &&
fabs(floor(item->y)-item->y)<0.01);
}
static void
draw_item (cairo_t *cr,
GtkStyle *style,
PuzzleItem *item,
gboolean grabbed)
{
gboolean aligned = item_is_aligned (item);
cairo_rectangle_round (cr, item->x-0.36, item->y-0.36, 0.8, 0.8, 0.4);
cairo_set_line_width (cr, 0.07);
if (grabbed)
{
gdk_cairo_set_source_color (cr, &style->dark[GTK_STATE_NORMAL]);
}
else
{
if (aligned)
gdk_cairo_set_source_color (cr, &style->dark[GTK_STATE_NORMAL]);
else
gdk_cairo_set_source_color (cr, &style->dark[GTK_STATE_ACTIVE]);
}
cairo_stroke (cr);
cairo_rectangle_round (cr, item->x-0.4, item->y-0.4, 0.8, 0.8, 0.4);
cairo_save (cr);
if (grabbed)
{
gdk_cairo_set_source_color (cr, &style->base[GTK_STATE_SELECTED]);
}
else
{
if (aligned)
gdk_cairo_set_source_color (cr, &style->base[GTK_STATE_NORMAL]);
else
gdk_cairo_set_source_color (cr, &style->base[GTK_STATE_NORMAL]);
}
cairo_fill (cr);
cairo_restore (cr);
if (grabbed)
{
gdk_cairo_set_source_color (cr, &style->mid[GTK_STATE_SELECTED]);
}
else
{
if (aligned)
gdk_cairo_set_source_color (cr, &style->mid[GTK_STATE_NORMAL]);
else
gdk_cairo_set_source_color (cr, &style->dark[GTK_STATE_ACTIVE]);
}
cairo_set_line_width (cr, 0.05);
cairo_stroke (cr);
{
cairo_text_extents_t extents;
cairo_text_extents (cr, item->label, &extents);
cairo_move_to (cr, item->x-extents.width/2 - extents.x_bearing,
item->y - extents.height/2 - extents.y_bearing);
}
if (grabbed)
{
gdk_cairo_set_source_color (cr, &style->text[GTK_STATE_SELECTED]);
}
else
{
if (aligned)
gdk_cairo_set_source_color (cr, &style->text[GTK_STATE_NORMAL]);
else
gdk_cairo_set_source_color (cr, &style->text[GTK_STATE_NORMAL]);
}
cairo_show_text (cr, item->label);
}
/* draw the game board using the provided cairo context
*/
static void
draw_board (Puzzle *puzzle,
cairo_t *cr)
{
int item_no;
GtkStyle *style;
style = GTK_WIDGET (puzzle)->style;
cairo_save (cr);
cairo_select_font_face (cr, "sans", 0, 0);
cairo_set_font_size (cr, 0.35);
cairo_scale (cr, puzzle->ratio_x, puzzle->ratio_y);
cairo_translate (cr, 0.5, 0.5);
for (item_no=0;item_no<puzzle->rows*puzzle->cols-1;item_no++)
draw_item (cr, style, &(puzzle->item [item_no]), item_no == puzzle->grabbed);
cairo_restore (cr);
}
/* returns which block would be pushed by shifting 'block' the given amount
in x direction
return: >=0 block id
-1 none
-2 going off board
*/
static int
who_is_pushed_x (Puzzle *puzzle,
int block_no,
double xdelta)
{
int item_no;
PuzzleItem *block= & (puzzle->item [block_no]);
if (xdelta<0)
{
if (block->x+xdelta<0)
return -2;
for (item_no=0;item_no<puzzle->rows*puzzle->cols-1;item_no++)
{
PuzzleItem *item= & (puzzle->item [item_no]);
if (block->x > item->x && block->x + xdelta - 1 <= item->x
&& item->y < block->y + 1 && item->y > block->y -1 )
{
return item_no;
}
}
}
else
{
if (block->x+xdelta>puzzle->cols-1)
return -2;
for (item_no=0;item_no<puzzle->rows*puzzle->cols-1;item_no++)
{
PuzzleItem *item= & (puzzle->item [item_no]);
if (block->x < item->x && block->x + xdelta + 1 >= item->x
&& item->y < block->y + 1 && item->y > block->y -1 )
{
return item_no;
}
}
}
return -1;
}
/* returns which block would be pushed by shifting 'block' the given amount
in y direction
return: >=0 block id
-1 none
-2 going off board
*/
static int
who_is_pushed_y (Puzzle *puzzle,
gint block_no,
gdouble ydelta)
{
int item_no;
PuzzleItem *block= & (puzzle->item [block_no]);
if (ydelta<0)
{
if (block->y+ydelta<0)
return -2;
for (item_no=0;item_no<puzzle->rows*puzzle->cols-1;item_no++)
{
PuzzleItem *item= & (puzzle->item [item_no]);
if (block->y > item->y && block->y + ydelta - 1 <= item->y
&& item->x < block->x + 1 && item->x > block->x -1 )
{
return item_no;
}
}
}
else
{
if (block->y+ydelta>puzzle->rows-1)
return -2;
for (item_no=0;item_no<puzzle->rows*puzzle->cols-1;item_no++)
{
PuzzleItem *item= & (puzzle->item [item_no]);
if (block->y < item->y && block->y + ydelta + 1 >= item->y
&& item->x < block->x + 1 && item->x > block->x -1 )
{
return item_no;
}
}
}
return -1;
}
/* attempt to push a block the given delta in x and y directions */
static void
push_block (Puzzle *puzzle,
gint block_no,
gdouble xdelta,
gdouble ydelta)
{
PuzzleItem *block= & (puzzle->item [block_no]);
gint pushed_x, pushed_y;
if (floor (block->y)-block->y == 0 && xdelta != 0.0)
{
if (xdelta>=0.9)
xdelta=0.9;
else if (xdelta <= -0.9)
xdelta=-0.9;
pushed_x = who_is_pushed_x (puzzle, block_no, xdelta);
if ( pushed_x == -1 || pushed_x == -2)
{
block->x += xdelta;
if (block->x >= puzzle->cols-1)
{
block->x = puzzle->cols-1;
}
else if (block->x < 0)
{
block->x = 0;
}
return;
}
if (pushed_x >= 0)
{
push_block (puzzle, pushed_x, xdelta, 0);
if (fabs (block->x - puzzle->item[pushed_x].x)>1.0001)
{
if (block->x < puzzle->item[pushed_x].x)
block->x = puzzle->item[pushed_x].x - 1;
else
block->x = puzzle->item[pushed_x].x + 1;
}
}
}
if (floor (block->x)-block->x == 0)
{
if (ydelta>=0.9)
ydelta=0.9;
else if (ydelta <= -0.9)
ydelta=-0.9;
pushed_y = who_is_pushed_y (puzzle, block_no, ydelta);
if (pushed_y == -1 || pushed_y == -2)
{
block->y += ydelta;
if (block->y >= puzzle->rows-1)
{
block->y = puzzle->rows-1;
}
else if (block->y < 0)
{
block->y = 0;
}
return;
}
if (pushed_y >= 0)
{
push_block (puzzle, pushed_y, 0, ydelta);
if (fabs (block->y - puzzle->item[pushed_y].y)>1.0001)
{
if (block->y < puzzle->item[pushed_y].y)
block->y = puzzle->item[pushed_y].y - 1;
else
block->y = puzzle->item[pushed_y].y + 1;
}
}
}
return;
}
--- NEW FILE: puzzle.h ---
#ifndef PUZZLE_H
#define PUZZLE_H
#include <gtk/gtk.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#define PUZZLE(obj) GTK_CHECK_CAST (obj, puzzle_get_type (), Puzzle)
#define PUZZLE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, puzzle_get_type (), PuzzleClass)
#define IS_PUZZLE(obj) GTK_CHECK_TYPE (obj, puzzle_get_type ())
typedef struct _Puzzle Puzzle;
typedef struct _PuzzleClass PuzzleClass;
GtkType puzzle_get_type (void);
GtkWidget *puzzle_new (void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* PUZZLE_H */
- Previous message: [cairo-commit] cairo-demo/gtk_slide - New directory,NONE,NONE
- Next message: [cairo-commit] cairo-demo/gtkcairo_slide COPYING, 1.1,
NONE ChangeLog, 1.10, NONE Makefile, 1.3, NONE README, 1.2,
NONE cairo_custom.c, 1.5, NONE cairo_custom.h, 1.5,
NONE gtkcairo_slide.c, 1.5, NONE puzzle.c, 1.9, NONE puzzle.h,
1.1, NONE
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
More information about the cairo-commit
mailing list