[xiph-commits] r9631 - in trunk: . planarity
xiphmont at svn.xiph.org
xiphmont at svn.xiph.org
Wed Jul 27 21:00:52 PDT 2005
Author: xiphmont
Date: 2005-07-27 20:59:23 -0700 (Wed, 27 Jul 2005)
New Revision: 9631
Added:
trunk/planarity/
trunk/planarity/Makefile
trunk/planarity/arrange.c
trunk/planarity/arrange.h
trunk/planarity/box.c
trunk/planarity/box.h
trunk/planarity/buttonbar.c
trunk/planarity/buttons.c
trunk/planarity/buttons.h
trunk/planarity/gPlanarity
trunk/planarity/gPlanarity.gz
trunk/planarity/gameboard.c
trunk/planarity/gameboard.h
trunk/planarity/gamestate.c
trunk/planarity/gamestate.h
trunk/planarity/generate.c
trunk/planarity/generate.h
trunk/planarity/graph.c
trunk/planarity/graph.h
trunk/planarity/touch-version
trunk/planarity/version.h
Log:
First Import
Added: trunk/planarity/Makefile
===================================================================
--- trunk/planarity/Makefile 2005-07-26 23:19:44 UTC (rev 9630)
+++ trunk/planarity/Makefile 2005-07-28 03:59:23 UTC (rev 9631)
@@ -0,0 +1,85 @@
+# Fuck Automake
+# Fuck the horse it rode in on
+# and Fuck its little dog Libtool too
+
+TARGET = gPlanarity
+CC = gcc
+LD = gcc
+INSTALL = install
+STRIP = strip
+PREFIX = /usr/local
+BINDIR = $(PREFIX)/bin
+ETCDIR = /etc/$(TARGET)
+MANDIR = $(PREFIX)/man
+
+# the very long, LIBS entry is to build an executable that will
+# work for on most modern linux distros without any of the
+# bleeding-edge GTK 2.7/2.8 libs installed.
+
+SRC = graph.c arrange.c gameboard.c generate.c gamestate.c\
+ buttons.c buttonbar.c box.c
+OBJ = graph.o arrange.o gameboard.o generate.o gamestate.o\
+ buttons.o buttonbar.o box.o
+GCF = `pkg-config --static --cflags "gtk+-2.0 >= 2.7.2"`
+
+# uncomment below for a normal dynamic build
+
+LDF = `pkg-config --static --libs "gtk+-2.0 >= 2.7.2"`
+
+# uncomment below for a build with static Gtk 2.7; this generally
+# requires that all of the Gtk dependencies were built with static
+# dependencies also pointing to the local install
+
+SLDF = `pkg-config --static --libs-only-L "gtk+-2.0 >= 2.7.2"`
+GTK = /usr/local/lib
+EXPAT= /usr/lib/libexpat.a
+XINERAMA = /usr/X11R6/lib/libXinerama.a
+PIXMAN = /usr/lib/libpixman.a
+SLIBS = $(GTK)/libgtk-x11-2.0.a \
+ $(GTK)/libgdk-x11-2.0.a $(GTK)/libgdk_pixbuf-2.0.a \
+ $(GTK)/libpangocairo-1.0.a $(GTK)/libpangoft2-1.0.a \
+ $(GTK)/libpangox-1.0.a $(GTK)/libpangoxft-1.0.a \
+ $(GTK)/libpango-1.0.a $(GTK)/libcairo.a \
+ $(GTK)/libatk-1.0.a $(GTK)/libgmodule-2.0.a \
+ $(GTK)/libgobject-2.0.a $(GTK)/libglib-2.0.a \
+ -lpthread $(EXPAT) -lfreetype -lz -lm -lc \
+ -lXext -lXrandr $(XINERAMA) -lXcursor -lX11 $(PIXMAN) -lXft
+
+all:
+ $(MAKE) target CFLAGS="-O2 -ffast-math $(GCF) $(ADD_DEF)"
+ $(STRIP) $(TARGET)
+
+static:
+ $(MAKE) static-target CFLAGS="-O2 -ffast-math $(GCF) $(ADD_DEF)"
+ $(STRIP) $(TARGET)
+
+debug:
+ $(MAKE) target CFLAGS="-g -Wall -W -Wno-unused-parameter -D__NO_MATH_INLINES $(GCF) $(ADD_DEF)"
+
+profile:
+ $(MAKE) target CFLAGS="-pg -g -O2 -ffast-math $(GCF) $(ADD_DEF)" LIBS="$(LIBS) -lgprof-helper "
+
+clean:
+ rm -f $(OBJ) *.d *.d.* gmon.out $(TARGET)
+
+distclean: clean
+ rm -f *~
+
+%.d: %.c
+ $(CC) -M $(CFLAGS) $< > $@.$$$$; sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; rm -f $@.$$$$
+
+ifeq ($(MAKECMDGOALS),target)
+include $(SRC:.c=.d)
+endif
+
+target: $(OBJ)
+ ./touch-version
+ $(LD) $(OBJ) $(CFLAGS) -o $(TARGET) $(LIBS) $(LDF)
+
+static-target: $(OBJ)
+ ./touch-version
+ $(LD) $(OBJ) $(CFLAGS) -o $(TARGET) $(SLIBS) $(SLDF)
+
+install: target
+ $(INSTALL) -d -m 0755 $(BINDIR)
+ $(INSTALL) -m 0755 $(TARGET) $(BINDIR)
Added: trunk/planarity/arrange.c
===================================================================
--- trunk/planarity/arrange.c 2005-07-26 23:19:44 UTC (rev 9630)
+++ trunk/planarity/arrange.c 2005-07-28 03:59:23 UTC (rev 9631)
@@ -0,0 +1,36 @@
+#include <math.h>
+
+#include "graph.h"
+#include "arrange.h"
+
+void arrange_verticies_circle(int n){
+ vertex *v = get_verticies();
+ int bw=get_board_width();
+ int bh=get_board_height();
+ int radius=min(bw,bh)*.45;
+ int i;
+ for(i=0;i<n;i++){
+ int x = rint( radius * cos( i*M_PI*2./n));
+ int y = rint( radius * sin( i*M_PI*2./n));
+ move_vertex(v,x+(bw>>1),y+(bh>>1));
+ v=v->next;
+ }
+}
+
+void arrange_verticies_mesh(int width, int height){
+ vertex *v = get_verticies();
+ int bw=get_board_width();
+ int bh=get_board_height();
+ int spacing=min((float)bw/width,(float)bh/height)*.9;
+ int x,y;
+
+ int xpad=(bw - (width-1)*spacing)/2;
+ int ypad=(bh - (height-1)*spacing)/2;
+
+ for(y=0;y<height;y++){
+ for(x=0;x<width;x++){
+ move_vertex(v,x*spacing+xpad,y*spacing+ypad);
+ v=v->next;
+ }
+ }
+}
Added: trunk/planarity/arrange.h
===================================================================
--- trunk/planarity/arrange.h 2005-07-26 23:19:44 UTC (rev 9630)
+++ trunk/planarity/arrange.h 2005-07-28 03:59:23 UTC (rev 9631)
@@ -0,0 +1,2 @@
+extern void arrange_verticies_circle(int n);
+extern void arrange_verticies_mesh(int width, int height);
Added: trunk/planarity/box.c
===================================================================
--- trunk/planarity/box.c 2005-07-26 23:19:44 UTC (rev 9630)
+++ trunk/planarity/box.c 2005-07-28 03:59:23 UTC (rev 9631)
@@ -0,0 +1,165 @@
+#include <math.h>
+#include <gtk/gtk.h>
+#include "graph.h"
+#include "box.h"
+
+void topbox (cairo_t *c, double w, double h){
+
+ double x0 = B_BORDER+B_RADIUS;
+ double y0 = B_BORDER;
+
+ double x1 = B_BORDER;
+ double y1 = B_BORDER+B_RADIUS;
+
+ double x2 = B_BORDER;
+ double y2 = h-B_BORDER-B_RADIUS;
+
+ double x3 = B_BORDER+B_RADIUS;
+ double y3 = h-B_BORDER;
+
+ double x4 = w/2 - B_HUMP - B_RADIUS;
+ double y4 = h-B_BORDER;
+
+ double x5 = x4+B_RADIUS;
+ double y5 = y4;
+
+
+ double x7 = w/2 + B_HUMP + B_RADIUS;
+ double y7 = h-B_BORDER;
+
+ double x8 = w - B_BORDER -B_RADIUS;
+ double y8 = h-B_BORDER;
+
+ double x9 = w - B_BORDER;
+ double y9 = h-B_BORDER-B_RADIUS;
+
+ double x10 = w - B_BORDER;
+ double y10 = B_BORDER+B_RADIUS;
+
+ double x11 = w - B_BORDER-B_RADIUS;
+ double y11 = B_BORDER;
+
+ cairo_set_line_width(c,B_LINE);
+
+ cairo_move_to (c, x0, y0);
+ cairo_curve_to (c, x1,y0, x1,y0, x1,y1);
+ cairo_line_to (c, x2,y2);
+ cairo_curve_to (c, x2,y3, x2,y3, x3,y3);
+ cairo_line_to (c, x4,y4);
+
+ {
+ double hh = get_board_height()*.5+50;
+
+ double radius = sqrt( (w*.5-x5) * (w*.5-x5) + (hh-y5) * (hh-y5));
+ double siderad = atan( (x5-w*.5)/(hh-y5));
+
+ double xx = sin(siderad+.05)*radius+w*.5;
+ double yy = -cos(siderad+.05)*radius+hh;
+ double x = sin(siderad+.1)*radius+w*.5;
+ double y = -cos(siderad+.1)*radius+hh;
+
+ cairo_curve_to (c, x4+B_RADIUS,y4, xx,yy, x,y);
+ cairo_arc(c,w*.5,hh,radius,-M_PI*.5+siderad+.1,-M_PI*.5-siderad-.1);
+
+ xx = -sin(siderad+.05)*radius+w*.5;
+ yy = -cos(siderad+.05)*radius+hh;
+ xx = -sin(siderad+.1)*radius+w*.5;
+ yy = -cos(siderad+.1)*radius+hh;
+
+ cairo_curve_to (c, xx,yy, x7-B_RADIUS,y7, x7,y7);
+
+ }
+
+ cairo_line_to (c, x8,y8);
+ cairo_curve_to (c, x9,y8, x9,y8, x9,y9);
+ cairo_line_to (c, x10,y10);
+ cairo_curve_to (c, x10,y11, x10,y11, x11,y11);
+ cairo_close_path (c);
+
+ cairo_set_source_rgba (c, B_COLOR);
+ cairo_fill_preserve (c);
+ cairo_set_source_rgba (c, B_LINE_COLOR);
+ cairo_stroke (c);
+
+}
+
+void bottombox (cairo_t *c, double w, double h){
+
+ double x0 = B_BORDER+B_RADIUS;
+ double y0 = h-B_BORDER;
+
+ double x1 = B_BORDER;
+ double y1 = h-B_BORDER-B_RADIUS;
+
+ double x2 = B_BORDER;
+ double y2 = B_BORDER+B_RADIUS;
+
+ double x3 = B_BORDER+B_RADIUS;
+ double y3 = B_BORDER;
+
+ double x4 = w/2 - B_HUMP - B_RADIUS;
+ double y4 = B_BORDER;
+
+ double x5 = x4+B_RADIUS;
+ double y5 = y4;
+
+
+ double x7 = w/2 + B_HUMP + B_RADIUS;
+ double y7 = B_BORDER;
+
+ double x8 = w - B_BORDER -B_RADIUS;
+ double y8 = B_BORDER;
+
+ double x9 = w - B_BORDER;
+ double y9 = B_BORDER+B_RADIUS;
+
+ double x10 = w - B_BORDER;
+ double y10 = h- B_BORDER -B_RADIUS;
+
+ double x11 = w - B_BORDER-B_RADIUS;
+ double y11 = h-B_BORDER;
+
+ cairo_set_line_width(c,B_LINE);
+
+ cairo_move_to (c, x0, y0);
+ cairo_curve_to (c, x1,y0, x1,y0, x1,y1);
+ cairo_line_to (c, x2,y2);
+ cairo_curve_to (c, x2,y3, x2,y3, x3,y3);
+ cairo_line_to (c, x4,y4);
+
+ {
+ double hh = get_board_height()*.5+50;
+
+ double radius = sqrt( (w*.5-x5) * (w*.5-x5) + (y5+hh-h) * (y5+hh-h));
+ double siderad = atan( (x5-w*.5)/(y5+hh-h));
+
+ double xx = sin(siderad+.05)*radius+w*.5;
+ double yy = cos(siderad+.05)*radius-hh+h;
+ double x = sin(siderad+.1)*radius+w*.5;
+ double y = cos(siderad+.1)*radius-hh+h;
+
+ cairo_curve_to (c, x4+B_RADIUS,y4, xx,yy, x,y);
+ cairo_arc_negative(c,w*.5,h-hh,radius,M_PI*.5-siderad-.1,M_PI*.5+siderad+.1);
+
+ xx = -sin(siderad+.05)*radius+w*.5;
+ yy = cos(siderad+.05)*radius-hh+h;
+ xx = -sin(siderad+.1)*radius+w*.5;
+ yy = cos(siderad+.1)*radius-hh+h;
+
+ cairo_curve_to (c, xx,yy, x7-B_RADIUS,y7, x7,y7);
+
+ }
+
+ cairo_line_to (c, x8,y8);
+ cairo_curve_to (c, x9,y8, x9,y8, x9,y9);
+ cairo_line_to (c, x10,y10);
+ cairo_curve_to (c, x10,y11, x10,y11, x11,y11);
+ cairo_close_path (c);
+
+ cairo_set_source_rgba (c, B_COLOR);
+ cairo_fill_preserve (c);
+ cairo_set_source_rgba (c, B_LINE_COLOR);
+ cairo_stroke (c);
+
+}
+
Added: trunk/planarity/box.h
===================================================================
--- trunk/planarity/box.h 2005-07-26 23:19:44 UTC (rev 9630)
+++ trunk/planarity/box.h 2005-07-28 03:59:23 UTC (rev 9631)
@@ -0,0 +1,14 @@
+#define B_LINE 1
+#define B_BORDER 6.5
+#define B_RADIUS 20
+#define B_HUMP 130
+#define B_COLOR .1,.1,.7,.1
+#define B_LINE_COLOR 0, 0,.7,.3
+#define TEXT_COLOR .0,.0,.7,.6
+
+
+#define SCOREHEIGHT 50
+
+
+extern void topbox (cairo_t *c, double w, double h);
+extern void bottombox (cairo_t *c, double w, double h);
Added: trunk/planarity/buttonbar.c
===================================================================
--- trunk/planarity/buttonbar.c 2005-07-26 23:19:44 UTC (rev 9630)
+++ trunk/planarity/buttonbar.c 2005-07-28 03:59:23 UTC (rev 9631)
@@ -0,0 +1,771 @@
+#include <math.h>
+#include <string.h>
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+
+#include "graph.h"
+#include "gameboard.h"
+#include "gamestate.h"
+#include "buttons.h"
+#include "box.h"
+
+
+/************************ the lower button bar *********************/
+
+#define NUMBUTTONS 10
+
+typedef struct {
+ int target_x;
+ int target_x_inactive;
+ int target_x_active;
+
+ int x;
+ int x_inactive;
+ int x_active;
+ int y;
+
+ cairo_surface_t *idle;
+ cairo_surface_t *lit;
+
+ char *rollovertext;
+ cairo_text_extents_t ex;
+
+ int alphad;
+ double alpha;
+
+ int rollover;
+ int press;
+
+ void (*callback)();
+} buttonstate;
+
+static buttonstate states[NUMBUTTONS];
+
+static int width=0;
+static int height=0;
+static int deployed=0;
+static int sweeper=0;
+static gint timer = 0;
+static int checkbutton_deployed=0;
+static int allclear=1; // actually just a shirt-circuit
+static buttonstate *grabbed=0;
+static void (*undeploy_callback)(Gameboard *g);
+
+/*********************** static housekeeping *****************/
+
+/* initialize the rather weird little animation engine */
+static void buttons_initial_placement(int w, int h){
+
+ int count=BUTTON_BORDER;
+ int i;
+
+ width=w;
+ height=h;
+
+ for(i=0;i<BUTTON_LEFT;i++){
+ buttonstate *b=states+i;
+ b->x=0;
+ b->target_x=count;
+ b->x_active=b->target_x_active=count;
+ b->x_inactive=b->target_x_inactive=count-BUTTON_EXPOSE;
+ b->y = h - BUTTON_Y_FROM_BOTTOM;
+ count += BUTTON_SPACING;
+ }
+ count -= BUTTON_SPACING;
+
+ // assumes we will always have at least as many buttons left as right
+ sweeper=count;
+
+ count=width-BUTTON_BORDER;
+ for(i=0;i<BUTTON_RIGHT;i++){
+ buttonstate *b=states+NUMBUTTONS-i-1;
+ b->x=width;
+ b->target_x=count;
+ b->x_active=b->target_x_active=count;
+ b->x_inactive=b->target_x_inactive=count+BUTTON_EXPOSE;
+ b->y = h - BUTTON_Y_FROM_BOTTOM;
+ if(i>0) // special-case the checkbutton
+ count -= BUTTON_SPACING;
+ }
+
+ // special-case the checkbutton
+ states[9].target_x_inactive=states[9].target_x_active+BUTTON_SPACING;
+ states[9].x_inactive=states[9].target_x_inactive;
+ states[9].target_x=states[9].target_x_inactive;
+
+}
+
+/* cache buttons as small surfaces */
+static cairo_surface_t *cache_button(Gameboard *g,
+ void (*draw)(cairo_t *c,
+ double x,
+ double y),
+ double pR,double pG,double pB,double pA,
+ double fR,double fG,double fB,double fA){
+ cairo_surface_t *ret =
+ cairo_surface_create_similar (cairo_get_target (g->wc),
+ CAIRO_CONTENT_COLOR_ALPHA,
+ BUTTON_RADIUS*2+1,
+ BUTTON_RADIUS*2+1);
+
+ cairo_t *c = cairo_create(ret);
+
+ cairo_save(c);
+ cairo_set_operator(c,CAIRO_OPERATOR_CLEAR);
+ cairo_set_source_rgba (c, 1,1,1,1);
+ cairo_paint(c);
+ cairo_restore(c);
+
+ cairo_set_source_rgba(c,fR,fG,fB,fA);
+ cairo_set_line_width(c,BUTTON_LINE_WIDTH);
+ draw(c,BUTTON_RADIUS+.5,BUTTON_RADIUS+.5);
+
+ cairo_set_source_rgba(c,pR,pG,pB,pA);
+ cairo_stroke(c);
+
+ cairo_destroy(c);
+ return ret;
+}
+
+/* determine the x/y/w/h box around a button */
+static GdkRectangle button_box(buttonstate *b){
+ GdkRectangle r;
+
+ int x = b->x - BUTTON_RADIUS-1;
+ int y = b->y - BUTTON_RADIUS-1;
+ r.x=x;
+ r.y=y;
+ r.width = BUTTON_RADIUS*2+2;
+ r.height= BUTTON_RADIUS*2+2;
+
+ return r;
+}
+
+/* determine the x/y/w/h box around the rollover text */
+static GdkRectangle rollover_box(buttonstate *b){
+ GdkRectangle r;
+
+ int x = b->x - b->ex.width/2 + b->ex.x_bearing -2;
+ int y = b->y - BUTTON_RADIUS - BUTTON_TEXT_BORDER + b->ex.y_bearing -2;
+
+ if(x<BUTTON_TEXT_BORDER)x=BUTTON_TEXT_BORDER;
+ if(y<BUTTON_TEXT_BORDER)y=BUTTON_TEXT_BORDER;
+ if(x+b->ex.width >= width - BUTTON_TEXT_BORDER)
+ x = width - BUTTON_TEXT_BORDER - b->ex.width;
+ if(y+b->ex.height >= height - BUTTON_TEXT_BORDER)
+ y = height - BUTTON_TEXT_BORDER - b->ex.height;
+
+ r.x=x;
+ r.y=y;
+ r.width=b->ex.width+5;
+ r.height=b->ex.height+5;
+
+ return r;
+}
+
+/* draw the actual rollover */
+static void stroke_rollover(Gameboard *g, buttonstate *b, cairo_t *c){
+ cairo_matrix_t m;
+
+ cairo_select_font_face (c, "Arial",
+ CAIRO_FONT_SLANT_NORMAL,
+ CAIRO_FONT_WEIGHT_BOLD);
+
+ cairo_matrix_init_scale (&m, BUTTON_TEXT_SIZE);
+ cairo_set_font_matrix (c,&m);
+
+ {
+ GdkRectangle r=rollover_box(b);
+
+ cairo_move_to (c, r.x - b->ex.x_bearing +2, r.y -b->ex.y_bearing+2 );
+
+ cairo_set_line_width(c,3);
+ cairo_set_source_rgba(c,1,1,1,.9);
+ cairo_text_path (c, b->rollovertext);
+ cairo_stroke(c);
+
+ cairo_set_source_rgba(c,BUTTON_TEXT_COLOR);
+ cairo_move_to (c, r.x - b->ex.x_bearing +2, r.y -b->ex.y_bearing+2 );
+
+
+ cairo_show_text (c, b->rollovertext);
+
+ }
+}
+
+/* cache the text extents of a rollover */
+static void rollover_extents(Gameboard *g, buttonstate *b){
+
+ cairo_matrix_t m;
+
+ cairo_t *c = cairo_create(g->foreground);
+ cairo_select_font_face (c, "Arial",
+ CAIRO_FONT_SLANT_NORMAL,
+ CAIRO_FONT_WEIGHT_BOLD);
+
+ cairo_matrix_init_scale (&m, BUTTON_TEXT_SIZE);
+ cairo_set_font_matrix (c,&m);
+
+ cairo_text_extents (c, b->rollovertext, &b->ex);
+
+
+ cairo_destroy(c);
+}
+
+/* request an expose for a button region*/
+static void invalidate_button(Gameboard *g,buttonstate *b){
+ GdkRectangle r;
+
+ r.x=b->x-BUTTON_RADIUS-1;
+ r.y=b->y-BUTTON_RADIUS-1;
+ r.width=BUTTON_RADIUS*2+2;
+ r.height=BUTTON_RADIUS*2+2;
+
+ gdk_window_invalidate_rect(g->w.window,&r,FALSE);
+}
+
+/* request an expose for a rollover region*/
+static void invalidate_rollover(Gameboard *g,buttonstate *b){
+ GdkRectangle r = rollover_box(b);
+ invalidate_button(g,b);
+ gdk_window_invalidate_rect(g->w.window,&r,FALSE);
+}
+
+/* like invalidation, but just expands a rectangular region */
+static void expand_rectangle_button(buttonstate *b,GdkRectangle *r){
+ int x=b->x-BUTTON_RADIUS-1;
+ int y=b->y-BUTTON_RADIUS-1;
+ int x2=x+BUTTON_RADIUS*2+2;
+ int y2=y+BUTTON_RADIUS*2+2;
+
+ int rx2=r->x+r->width;
+ int ry2=r->y+r->height;
+
+ if(r->width==0 || r->height==0){
+ r->x=x;
+ r->y=y;
+ r->width=x2-x;
+ r->height=y2-y;
+ }
+
+ if(x<r->x)
+ r->x=x;
+ if(y<r->y)
+ r->y=y;
+ if(rx2<x2)
+ rx2=x2;
+ r->width=rx2-r->x;
+ if(ry2<y2)
+ ry2=y2;
+ r->height=ry2-r->y;
+}
+
+/* like invalidation, but just expands a rectangular region */
+static void expand_rectangle_rollover(buttonstate *b,GdkRectangle *r){
+ GdkRectangle rr = rollover_box(b);
+ int x=rr.x;
+ int y=rr.y;
+ int x2=x+rr.width;
+ int y2=y+rr.height;
+
+ int rx2=r->x+r->width;
+ int ry2=r->y+r->height;
+
+ if(r->width==0 || r->height==0){
+ r->x=x;
+ r->y=y;
+ r->width=x2-x;
+ r->height=y2-y;
+ }
+
+ if(x<r->x)
+ r->x=x;
+ if(y<r->y)
+ r->y=y;
+ if(rx2<x2)
+ rx2=x2;
+ r->width=rx2-r->x;
+ if(ry2<y2)
+ ry2=y2;
+ r->height=ry2-r->y;
+}
+
+/* do the animation math for one button for one frame */
+static int animate_one(buttonstate *b, GdkRectangle *r){
+ int ret=0;
+ int w2=width/2;
+
+ if(b->target_x>w2 && width-sweeper>b->target_x)
+ b->target_x=width-sweeper;
+ if(b->target_x<w2 && sweeper<b->target_x)
+ b->target_x=sweeper;
+
+ if(b->target_x_active != b->x_active){
+ ret=1;
+ if(b->target_x_active > b->x_active){
+ b->x_active+=BUTTON_DELTA;
+ if(b->x_active>b->target_x_active)
+ b->x_active=b->target_x_active;
+ }else{
+ b->x_active-=BUTTON_DELTA;
+ if(b->x_active<b->target_x_active)
+ b->x_active=b->target_x_active;
+ }
+ }
+
+ if(b->target_x_inactive != b->x_inactive){
+ ret=1;
+ if(b->target_x_inactive > b->x_inactive){
+ b->x_inactive+=BUTTON_DELTA;
+ if(b->x_inactive>b->target_x_inactive)
+ b->x_inactive=b->target_x_inactive;
+ }else{
+ b->x_inactive-=BUTTON_DELTA;
+ if(b->x_inactive<b->target_x_inactive)
+ b->x_inactive=b->target_x_inactive;
+ }
+ }
+
+ if(b->target_x != b->x){
+ ret=1;
+ expand_rectangle_button(b,r);
+ if(b->rollover)
+ expand_rectangle_rollover(b,r);
+
+ if(b->target_x > b->x){
+ b->x+=BUTTON_DELTA;
+ if(b->x>b->target_x)b->x=b->target_x;
+ }else{
+ b->x-=BUTTON_DELTA;
+ if(b->x<b->target_x)b->x=b->target_x;
+ }
+ expand_rectangle_button(b,r);
+ if(b->rollover)
+ expand_rectangle_rollover(b,r);
+ }
+
+ if(b->alphad != b->x_active - b->x){
+ double alpha=0;
+ if(b->x_inactive>b->x_active){
+ if(b->x<=b->x_active)
+ alpha=1.;
+ else if (b->x>=b->x_inactive)
+ alpha=0.;
+ else
+ alpha = (double)(b->x_inactive-b->x)/(b->x_inactive-b->x_active);
+ }else if (b->x_inactive<b->x_active){
+ if(b->x>=b->x_active)
+ alpha=1.;
+ else if (b->x<=b->x_inactive)
+ alpha=0.;
+ else
+ alpha = (double)(b->x_inactive-b->x)/(b->x_inactive-b->x_active);
+ }
+ if(alpha != b->alpha){
+ ret=1;
+ expand_rectangle_button(b,r);
+ b->alpha=alpha;
+ }
+ b->alphad = b->x_active - b->x;
+ }
+ return ret;
+}
+
+/* perform a single frame of animation for all buttons/rollovers */
+static gboolean animate_buttons(gpointer ptr){
+ Gameboard *g=(Gameboard *)ptr;
+ GdkRectangle expose;
+ int ret=0,i;
+
+ if(!g->first_expose)return 1;
+
+ memset(&expose,0,sizeof(expose));
+ for(i=0;i<BUTTON_LEFT;i++)
+ ret|=animate_one(states+i,&expose);
+
+ /* avoid the normal expose event mechanism
+ during the button animations. This direct method is much faster as
+ it won't accidentally combine exposes over long stretches of
+ alpha-blended surfaces. */
+ run_immediate_expose(g,
+ expose.x,
+ expose.y,
+ expose.width,
+ expose.height);
+
+
+
+ memset(&expose,0,sizeof(expose));
+ for(i=BUTTON_LEFT;i<NUMBUTTONS;i++)
+ ret|=animate_one(states+i,&expose);
+
+ run_immediate_expose(g,
+ expose.x,
+ expose.y,
+ expose.width,
+ expose.height);
+
+ if(!ret && timer!=0){
+ g_source_remove(timer);
+ timer=0;
+ }
+ return ret;
+}
+
+/* helper that wraps animate-buttons for removing the buttons at the
+ end of a level */
+static gboolean deanimate_buttons(gpointer ptr){
+ Gameboard *g=(Gameboard *)ptr;
+ int ret=0;
+ sweeper-=BUTTON_DELTA;
+ if(sweeper< -(BUTTON_RADIUS +1)){
+ sweeper= -(BUTTON_RADIUS +1);
+ }else
+ ret=1;
+
+ ret|=animate_buttons(ptr);
+
+ if(!ret)
+ // undeploy finished... call the undeploy callback
+ undeploy_callback(g);
+
+ return ret;
+}
+
+/* the normal expose method for all buttons; called from the master
+ widget's expose */
+void expose_buttons(Gameboard *g,cairo_t *c, int x,int y,int w,int h){
+ int i;
+
+ for(i=0;i<NUMBUTTONS;i++){
+
+ buttonstate *b=states+i;
+ GdkRectangle r = rollover_box(b);
+ GdkRectangle br = button_box(b);
+
+ if(x < br.x+br.width &&
+ y < br.y+br.height &&
+ x+w > br.x &&
+ y+h > br.y) {
+
+ cairo_set_source_surface(c,
+ (b->rollover || b->press ? b->lit : b->idle),
+ br.x,
+ br.y);
+
+ if(b->press)
+ cairo_paint_with_alpha(c,b->alpha);
+ cairo_paint_with_alpha(c,b->alpha);
+
+ }
+
+ if(b->rollover || b->press)
+ if(x < r.x+r.width &&
+ y < r.y+r.height &&
+ x+w > r.x &&
+ y+h > r.y)
+
+ stroke_rollover(g,b,c);
+
+ }
+}
+
+/* match x/y to a button if any */
+static buttonstate *find_button(int x,int y){
+ int i;
+ for(i=0;i<NUMBUTTONS;i++){
+ buttonstate *b=states+i;
+ if( (b->x-x)*(b->x-x) + (b->y-y)*(b->y-y) <= BUTTON_RADIUS*BUTTON_RADIUS+4)
+ if(b->x != b->x_inactive)
+ return b;
+ }
+ return 0;
+}
+
+/* clear all buttons to unpressed/unlit */
+static void button_clear_state(Gameboard *g){
+ int i;
+ if(!allclear){
+ for(i=0;i<NUMBUTTONS;i++){
+ buttonstate *bb=states+i;
+ if(bb->rollover)
+ invalidate_rollover(g,bb);
+ if(bb->press)
+ invalidate_button(g,bb);
+
+ bb->rollover=0;
+ bb->press=0;
+ }
+ }
+ allclear=1;
+ grabbed=0;
+}
+
+/* set a button to pressed or lit */
+static void button_set_state(Gameboard *g, buttonstate *b, int rollover, int press){
+ int i;
+
+ if(b->rollover == rollover && b->press == press)return;
+
+ for(i=0;i<NUMBUTTONS;i++){
+ buttonstate *bb=states+i;
+ if(bb!=b){
+ if(bb->rollover)
+ invalidate_rollover(g,bb);
+ if(bb->press)
+ invalidate_button(g,bb);
+
+ bb->rollover=0;
+ bb->press=0;
+ }else{
+ if(bb->rollover != rollover)
+ invalidate_rollover(g,bb);
+ if(bb->press != press)
+ invalidate_button(g,bb);
+
+ bb->rollover=rollover;
+ bb->press=press;
+ }
+ }
+ allclear=0;
+}
+
+/******************** toplevel abstraction calls *********************/
+
+/* initialize the persistent caches; called once when gameboard is
+ first created */
+void init_buttons(Gameboard *g){
+ int i;
+ memset(states,0,sizeof(states));
+
+ states[0].idle = cache_button(g, path_button_exit,
+ BUTTON_QUIT_IDLE_PATH,
+ BUTTON_QUIT_IDLE_FILL);
+ states[0].lit = cache_button(g, path_button_exit,
+ BUTTON_QUIT_LIT_PATH,
+ BUTTON_QUIT_LIT_FILL);
+
+ states[1].idle = cache_button(g, path_button_back,
+ BUTTON_IDLE_PATH,
+ BUTTON_IDLE_FILL);
+ states[1].lit = cache_button(g, path_button_back,
+ BUTTON_LIT_PATH,
+ BUTTON_LIT_FILL);
+ states[2].idle = cache_button(g, path_button_reset,
+ BUTTON_IDLE_PATH,
+ BUTTON_IDLE_FILL);
+ states[2].lit = cache_button(g, path_button_reset,
+ BUTTON_LIT_PATH,
+ BUTTON_LIT_FILL);
+ states[3].idle = cache_button(g, path_button_pause,
+ BUTTON_IDLE_PATH,
+ BUTTON_IDLE_FILL);
+ states[3].lit = cache_button(g, path_button_pause,
+ BUTTON_LIT_PATH,
+ BUTTON_LIT_FILL);
+ states[4].idle = cache_button(g, path_button_help,
+ BUTTON_IDLE_PATH,
+ BUTTON_IDLE_FILL);
+ states[4].lit = cache_button(g, path_button_help,
+ BUTTON_LIT_PATH,
+ BUTTON_LIT_FILL);
+ states[5].idle = cache_button(g, path_button_expand,
+ BUTTON_IDLE_PATH,
+ BUTTON_IDLE_FILL);
+ states[5].lit = cache_button(g, path_button_expand,
+ BUTTON_LIT_PATH,
+ BUTTON_LIT_FILL);
+ states[6].idle = cache_button(g, path_button_shrink,
+ BUTTON_IDLE_PATH,
+ BUTTON_IDLE_FILL);
+ states[6].lit = cache_button(g, path_button_shrink,
+ BUTTON_LIT_PATH,
+ BUTTON_LIT_FILL);
+ states[7].idle = cache_button(g, path_button_lines,
+ BUTTON_IDLE_PATH,
+ BUTTON_IDLE_FILL);
+ states[7].lit = cache_button(g, path_button_lines,
+ BUTTON_LIT_PATH,
+ BUTTON_LIT_FILL);
+ states[8].idle = cache_button(g, path_button_int,
+ BUTTON_IDLE_PATH,
+ BUTTON_IDLE_FILL);
+ states[8].lit = cache_button(g, path_button_int,
+ BUTTON_LIT_PATH,
+ BUTTON_LIT_FILL);
+ states[9].idle = cache_button(g, path_button_check,
+ BUTTON_CHECK_IDLE_PATH,
+ BUTTON_CHECK_IDLE_FILL);
+ states[9].lit = cache_button(g, path_button_check,
+ BUTTON_CHECK_LIT_PATH,
+ BUTTON_CHECK_LIT_FILL);
+
+ states[0].rollovertext="exit gPlanarity";
+ states[1].rollovertext="back to menu";
+ states[2].rollovertext="reset board";
+ states[3].rollovertext="pause";
+ states[4].rollovertext="help / about";
+ states[5].rollovertext="expand";
+ states[6].rollovertext="shrink";
+ states[7].rollovertext="hide/show lines";
+ states[8].rollovertext="mark intersections";
+ states[9].rollovertext="click when finished!";
+
+ states[0].callback = quit;
+ states[2].callback = reset_board;
+ states[5].callback = expand;
+ states[6].callback = shrink;
+ states[7].callback = hide_show_lines;
+ states[8].callback = mark_intersections;
+ states[9].callback = finish_board;
+
+ for(i=0;i<NUMBUTTONS;i++)
+ rollover_extents(g,states+i);
+}
+
+/* effects animated 'rollout' of buttons when level begins */
+void deploy_buttons(Gameboard *g){
+ if(!deployed ){
+ buttons_initial_placement(get_board_width(),get_board_height());
+ timer = g_timeout_add(BUTTON_ANIM_INTERVAL, animate_buttons, (gpointer)g);
+ deployed=1;
+ checkbutton_deployed=0;
+ }
+
+}
+
+/* effects animated rollout of 'check' button */
+void deploy_check(Gameboard *g){
+ if(deployed && !checkbutton_deployed){
+ int i;
+ for(i=BUTTON_LEFT;i<NUMBUTTONS-1;i++){
+ states[i].target_x-=BUTTON_SPACING;
+ states[i].target_x_active-=BUTTON_SPACING;
+ states[i].target_x_inactive-=BUTTON_SPACING;
+ }
+ states[9].target_x=states[9].target_x_active;
+ if(timer!=0)
+ g_source_remove(timer);
+ timer = g_timeout_add(BUTTON_ANIM_INTERVAL, animate_buttons, (gpointer)g);
+ checkbutton_deployed=1;
+ }
+}
+
+/* effects animated rollback of 'check' button */
+void undeploy_check(Gameboard *g){
+ if(checkbutton_deployed){
+ int i;
+ for(i=BUTTON_LEFT;i<NUMBUTTONS-1;i++){
+ states[i].target_x+=BUTTON_SPACING;
+ states[i].target_x_active+=BUTTON_SPACING;
+ states[i].target_x_inactive+=BUTTON_SPACING;
+ }
+ states[9].target_x=states[9].target_x_inactive;
+ if(timer!=0)
+ g_source_remove(timer);
+ timer = g_timeout_add(BUTTON_ANIM_INTERVAL, animate_buttons, (gpointer)g);
+ checkbutton_deployed=0;
+ }
+}
+
+/* effects animated rollback of buttons at end of level */
+void undeploy_buttons(Gameboard *g, void (*callback)(Gameboard *g)){
+ if(timer!=0)
+ g_source_remove(timer);
+
+ button_clear_state(g);
+ grabbed=0;
+ deployed=0;
+ undeploy_callback=callback;
+ checkbutton_deployed=0;
+
+ g_timeout_add(BUTTON_ANIM_INTERVAL, deanimate_buttons, (gpointer)g);
+
+
+}
+
+/* resize the button bar; called from master resize in gameboard */
+void resize_buttons(int w,int h){
+ int i;
+ int dx=w-width;
+ int dy=h-height;
+
+ for(i=BUTTON_LEFT;i<NUMBUTTONS;i++){
+ states[i].x+=dx;
+ states[i].target_x+=dx;
+ states[i].x_active+=dx;
+ states[i].target_x_active+=dx;
+ states[i].x_inactive+=dx;
+ states[i].target_x_inactive+=dx;
+ states[i].y+=dy;
+ }
+ width=w;
+}
+
+
+/* handles mouse motion events; called out of gameboard's master
+ motion handler; returns nonzero if it used focus */
+int button_motion_event(Gameboard *g, GdkEventMotion *event, int focusable){
+ buttonstate *b = find_button((int)event->x,(int)event->y);
+
+ if(deployed){
+ if(grabbed){
+ if(grabbed==b)
+ button_set_state(g,grabbed,1,1);
+ else
+ button_set_state(g,grabbed,0,0);
+ return 1;
+ }
+
+ if(focusable && !grabbed){
+
+ if(b){
+ button_set_state(g,b,1,0);
+ return 1;
+ }
+ }
+
+ button_clear_state(g);
+ }
+ return 0;
+}
+
+/* handles mouse button press events; called out of gameboard's master
+ mouse handler. returns nonzero if grabbing focus */
+int button_button_press(Gameboard *g, GdkEventButton *event, int focusable){
+
+ if(deployed){
+ if(focusable && deployed){
+
+ buttonstate *b = find_button((int)event->x,(int)event->y);
+ if(b){
+ button_set_state(g,b,1,1);
+ grabbed = b;
+ return 1;
+ }
+ }
+
+ button_clear_state(g);
+ }
+ return 0;
+}
+
+/* handles mouse button press events; called out of gameboard's master
+ mouse handler. returns nonzero if grabbing focus */
+int button_button_release(Gameboard *g, GdkEventButton *event, int focusable){
+ if(focusable && deployed){
+
+ buttonstate *b = find_button((int)event->x,(int)event->y);
+ if(b && grabbed==b){
+ button_set_state(g,b,1,0);
+
+ if(b->callback)
+ b->callback(g);
+
+
+ }
+ }
+
+ grabbed=0;
+ return 0;
+}
Added: trunk/planarity/buttons.c
===================================================================
--- trunk/planarity/buttons.c 2005-07-26 23:19:44 UTC (rev 9630)
+++ trunk/planarity/buttons.c 2005-07-28 03:59:23 UTC (rev 9631)
@@ -0,0 +1,254 @@
+#include <math.h>
+#include <gtk/gtk.h>
+
+#include "graph.h"
+#include "gameboard.h"
+#include "buttons.h"
+
+
+/************************* simple round icon drawing *********************/
+
+void path_button_help(cairo_t *c, double x, double y){
+
+ cairo_save(c);
+ cairo_translate(c,x,y);
+ cairo_set_fill_rule(c,CAIRO_FILL_RULE_EVEN_ODD);
+ cairo_set_line_width(c,1);
+ cairo_arc(c,0,0,14,0,2*M_PI);
+
+ cairo_move_to(c,-9,-2);
+ cairo_curve_to(c,-8,-7, -4.5,-12, 0,-12);
+ cairo_curve_to(c, 7,-12, 9,-6, 9,-4);
+ cairo_curve_to(c, 9,0 ,6,2, 5,2);
+
+ cairo_curve_to(c, 4,2, 2.5,3, 2.5,6);
+ cairo_line_to(c,-2.5,6);
+
+ cairo_curve_to(c,-2.5,3, -3,1, 0,-1);
+ cairo_curve_to(c, 11,-4, -3,-12, -4,-2);
+ cairo_close_path(c);
+
+ cairo_move_to(c,-2.5,8);
+ cairo_line_to(c,2.5,8);
+ cairo_line_to(c,2.5,12);
+ cairo_line_to(c,-2.5,12);
+ cairo_close_path(c);
+ cairo_fill_preserve(c);
+
+ cairo_restore(c);
+
+}
+
+void path_button_pause(cairo_t *c, double x, double y){
+
+ cairo_save(c);
+ cairo_translate(c,x,y);
+ cairo_set_fill_rule(c,CAIRO_FILL_RULE_EVEN_ODD);
+ cairo_set_line_width(c,1);
+ cairo_arc(c,0,0,14,0,2*M_PI);
+
+ cairo_rectangle(c,-7,-9,5,18);
+ cairo_rectangle(c,2,-9,5,18);
+ cairo_fill_preserve(c);
+ cairo_restore(c);
+
+}
+
+void path_button_exit(cairo_t *c, double x, double y){
+
+ cairo_save(c);
+ cairo_translate(c,x,y);
+ cairo_set_fill_rule(c,CAIRO_FILL_RULE_EVEN_ODD);
+ cairo_set_line_width(c,1);
+ cairo_arc(c,0,0,14,0,2*M_PI);
+
+ cairo_move_to(c,-6,-9.5);
+ cairo_line_to(c,0,-3.5);
+ cairo_line_to(c,6,-9.5);
+ cairo_line_to(c,9.5,-6);
+ cairo_line_to(c,3.5,0);
+ cairo_line_to(c,9.5,6);
+ cairo_line_to(c,6,9.5);
+ cairo_line_to(c,0,3.5);
+ cairo_line_to(c,-6,9.5);
+ cairo_line_to(c,-9.5,6);
+ cairo_line_to(c,-3.5,0);
+ cairo_line_to(c,-9.5,-6);
+ cairo_close_path(c);
+
+ cairo_fill_preserve(c);
+ cairo_restore(c);
+
+}
+
+void path_button_back(cairo_t *c, double x, double y){
+
+ cairo_save(c);
+ cairo_translate(c,x,y);
+ cairo_set_fill_rule(c,CAIRO_FILL_RULE_EVEN_ODD);
+ cairo_set_line_width(c,1);
+
+ cairo_arc(c,0,0,14,0,2*M_PI);
+
+ cairo_move_to(c,0,-11);
+ cairo_line_to(c,-9,0);
+ cairo_line_to(c,-3,0);
+ cairo_line_to(c,-3,10);
+ cairo_line_to(c,3,10);
+ cairo_line_to(c,3,0);
+ cairo_line_to(c,9,0);
+ cairo_close_path(c);
+
+ cairo_fill_preserve(c);
+ cairo_restore(c);
+
+}
+
+void path_button_reset(cairo_t *c, double x, double y){
+
+ cairo_save(c);
+ cairo_translate(c,x,y);
+ cairo_set_fill_rule(c,CAIRO_FILL_RULE_EVEN_ODD);
+ cairo_set_line_width(c,1);
+
+ cairo_arc(c,0,0,14,0,2*M_PI);
+
+ cairo_move_to(c,-11,-5);
+ cairo_line_to(c,-12,1);
+ cairo_line_to(c,-6,1);
+ cairo_line_to(c,0, 11);
+ cairo_line_to(c,6,1);
+ cairo_line_to(c,12,1);
+ cairo_line_to(c,11,-5);
+ cairo_line_to(c,4,-5);
+ cairo_line_to(c,0,2);
+ cairo_line_to(c,-4,-5);
+ cairo_close_path(c);
+
+ cairo_fill_preserve(c);
+ cairo_restore(c);
+
+}
+
+void path_button_expand(cairo_t *c, double x, double y){
+
+ cairo_save(c);
+ cairo_translate(c,x,y);
+ cairo_set_fill_rule(c,CAIRO_FILL_RULE_EVEN_ODD);
+ cairo_set_line_width(c,1);
+
+ cairo_arc(c,0,0,14,0,2*M_PI);
+
+ cairo_move_to(c,-8.5,-3);
+ cairo_line_to(c,-2.5,-3);
+ cairo_line_to(c,-3,-8.5);
+ cairo_line_to(c,3, -8.5);
+ cairo_line_to(c,3,-3);
+ cairo_line_to(c,8.5,-3);
+ cairo_line_to(c,8.5,3);
+ cairo_line_to(c,3,3);
+ cairo_line_to(c,3,8.5);
+ cairo_line_to(c,-3,8.5);
+ cairo_line_to(c,-3,3);
+ cairo_line_to(c,-8.5,3);
+ cairo_close_path(c);
+
+ cairo_fill_preserve(c);
+ cairo_restore(c);
+
+}
+
+void path_button_shrink(cairo_t *c, double x, double y){
+
+ cairo_save(c);
+ cairo_translate(c,x,y);
+ cairo_set_fill_rule(c,CAIRO_FILL_RULE_EVEN_ODD);
+ cairo_set_line_width(c,1);
+
+ cairo_arc(c,0,0,14,0,2*M_PI);
+
+ cairo_move_to(c,-10,-3);
+ cairo_line_to(c,10,-3);
+ cairo_line_to(c,10,3);
+ cairo_line_to(c,-10,3);
+ cairo_close_path(c);
+
+ cairo_fill_preserve(c);
+ cairo_restore(c);
+
+}
+
+void path_button_lines(cairo_t *c, double x, double y){
+
+ cairo_save(c);
+ cairo_translate(c,x,y);
+ cairo_set_fill_rule(c,CAIRO_FILL_RULE_EVEN_ODD);
+ cairo_set_line_width(c,1);
+
+ cairo_arc(c,0,0,14,0,2*M_PI);
+
+ cairo_move_to(c,6,-4);
+ cairo_arc(c,0,-4,6,0,2*M_PI);
+
+ cairo_move_to(c,0,2);
+ cairo_line_to(c,0,10);
+ cairo_close_path(c);
+
+ cairo_move_to(c,2.68328,5.36656-4);
+ cairo_rel_line_to(c,4,8);
+ cairo_close_path(c);
+
+ cairo_move_to(c,-2.68328,5.36656-4);
+ cairo_rel_line_to(c,-4,8);
+ cairo_close_path(c);
+
+ cairo_fill_preserve(c);
+ cairo_restore(c);
+
+}
+
+void path_button_int(cairo_t *c, double x, double y){
+
+ cairo_save(c);
+ cairo_translate(c,x,y);
+ cairo_set_fill_rule(c,CAIRO_FILL_RULE_EVEN_ODD);
+ cairo_set_line_width(c,1);
+
+ cairo_arc(c,0,0,14,0,2*M_PI);
+
+ cairo_move_to(c,8,0);
+ cairo_line_to(c,0,8);
+ cairo_line_to(c,-8,0);
+ cairo_line_to(c,0,-8);
+
+ cairo_close_path(c);
+
+ cairo_fill_preserve(c);
+ cairo_restore(c);
+
+}
+
+void path_button_check(cairo_t *c, double x, double y){
+
+ cairo_save(c);
+ cairo_translate(c,x,y);
+ cairo_set_fill_rule(c,CAIRO_FILL_RULE_EVEN_ODD);
+ cairo_set_line_width(c,1);
+
+ cairo_arc(c,0,0,14,0,2*M_PI);
+
+ cairo_move_to(c,8,-8);
+ cairo_curve_to(c, 7,-7, 11,-7.3, 10,-6);
+ cairo_line_to(c,0,9);
+ cairo_curve_to(c, -1,9.1, -2,11, -3,10);
+ cairo_line_to(c,-11,4);
+ cairo_curve_to(c, -12,3, -10,.5, -9,1);
+ cairo_line_to(c,-3,3);
+
+ cairo_close_path(c);
+
+ cairo_fill_preserve(c);
+ cairo_restore(c);
+
+}
+
Added: trunk/planarity/buttons.h
===================================================================
--- trunk/planarity/buttons.h 2005-07-26 23:19:44 UTC (rev 9630)
+++ trunk/planarity/buttons.h 2005-07-28 03:59:23 UTC (rev 9631)
@@ -0,0 +1,59 @@
+extern void go_buttons(Gameboard *g);
+extern void init_buttons(Gameboard *g);
+extern void expose_buttons(Gameboard *g,cairo_t *c,int x, int y, int w, int h);
+extern void deploy_buttons(Gameboard *g);
+extern void undeploy_buttons(Gameboard *g, void (*callback)());
+extern void resize_buttons(int w,int h);
+extern void deploy_check(Gameboard *g);
+extern void undeploy_check(Gameboard *g);
+
+extern int button_motion_event(Gameboard *g, GdkEventMotion *event, int focusable);
+extern int button_button_press(Gameboard *g, GdkEventButton *event, int focusable);
+extern int button_button_release(Gameboard *g, GdkEventButton *event, int focusable);
+
+
+
+extern void path_button_help(cairo_t *c, double x, double y);
+extern void path_button_back(cairo_t *c, double x, double y);
+extern void path_button_reset(cairo_t *c, double x, double y);
+extern void path_button_pause(cairo_t *c, double x, double y);
+extern void path_button_exit(cairo_t *c, double x, double y);
+extern void path_button_expand(cairo_t *c, double x, double y);
+extern void path_button_shrink(cairo_t *c, double x, double y);
+extern void path_button_lines(cairo_t *c, double x, double y);
+extern void path_button_int(cairo_t *c, double x, double y);
+extern void path_button_check(cairo_t *c, double x, double y);
+
+
+#define BUTTON_QUIT_IDLE_FILL .7,.1,.1,.3
+#define BUTTON_QUIT_IDLE_PATH .7,.1,.1,.6
+
+#define BUTTON_QUIT_LIT_FILL .7,.1,.1,.5
+#define BUTTON_QUIT_LIT_PATH .7,.1,.1,.6
+
+#define BUTTON_IDLE_FILL .1,.1,.7,.3
+#define BUTTON_IDLE_PATH .1,.1,.7,.6
+
+#define BUTTON_LIT_FILL .1,.1,.7,.6
+#define BUTTON_LIT_PATH .1,.1,.7,.6
+
+#define BUTTON_CHECK_IDLE_FILL .1,.5,.1,.3
+#define BUTTON_CHECK_IDLE_PATH .1,.5,.1,.6
+
+#define BUTTON_CHECK_LIT_FILL .1,.5,.1,.6
+#define BUTTON_CHECK_LIT_PATH .1,.5,.1,.6
+
+#define BUTTON_RADIUS 14
+#define BUTTON_Y_FROM_BOTTOM 25
+#define BUTTON_LINE_WIDTH 1
+#define BUTTON_TEXT_BORDER 15
+#define BUTTON_TEXT_COLOR .1,.1,.7,.8
+#define BUTTON_TEXT_SIZE 15.,18.
+
+#define BUTTON_ANIM_INTERVAL 15
+#define BUTTON_LEFT 5
+#define BUTTON_RIGHT 5
+#define BUTTON_BORDER 35
+#define BUTTON_SPACING 35
+#define BUTTON_EXPOSE 50
+#define BUTTON_DELTA 3
Added: trunk/planarity/gPlanarity
===================================================================
(Binary files differ)
Property changes on: trunk/planarity/gPlanarity
___________________________________________________________________
Name: svn:executable
+
Name: svn:mime-type
+ application/octet-stream
Added: trunk/planarity/gPlanarity.gz
===================================================================
(Binary files differ)
Property changes on: trunk/planarity/gPlanarity.gz
___________________________________________________________________
Name: svn:executable
+
Name: svn:mime-type
+ application/octet-stream
Added: trunk/planarity/gameboard.c
===================================================================
--- trunk/planarity/gameboard.c 2005-07-26 23:19:44 UTC (rev 9630)
+++ trunk/planarity/gameboard.c 2005-07-28 03:59:23 UTC (rev 9631)
@@ -0,0 +1,1060 @@
+#include <gtk/gtk.h>
+#include <gtk/gtkmain.h>
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+#include <stdlib.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "graph.h"
+#include "gameboard.h"
+#include "gamestate.h"
+#include "buttons.h"
+#include "box.h"
+
+static GtkWidgetClass *parent_class = NULL;
+
+/* vertex area and draw operations ***********************************/
+
+// invalidate the box around a single vertex
+static void invalidate_region_vertex_off(GtkWidget *widget,
+ vertex *v, int dx, int dy){
+ if(v){
+ GdkRectangle r;
+ r.x = v->x - V_RADIUS - V_LINE + dx;
+ r.y = v->y - V_RADIUS - V_LINE + dy;
+ r.width = (V_RADIUS + V_LINE)*2;
+ r.height = (V_RADIUS + V_LINE)*2;
+
+ gdk_window_invalidate_rect (widget->window, &r, FALSE);
+ }
+}
+
+void invalidate_region_vertex(Gameboard *g, vertex *v){
+ invalidate_region_vertex_off(&g->w,v,0,0);
+}
+
+// invalidate the box around a single line
+static void invalidate_region_edges(GtkWidget *widget, vertex *v){
+ GdkRectangle r;
+
+ if(v){
+ edge_list *el=v->edges;
+ while (el){
+ edge *e=el->edge;
+ r.x = min(e->A->x,e->B->x) - E_LINE;
+ r.y = min(e->A->y,e->B->y) - E_LINE;
+ r.width = labs(e->B->x - e->A->x) + 1 + E_LINE*2;
+ r.height = labs(e->B->y - e->A->y) + 1 + E_LINE*2;
+ gdk_window_invalidate_rect (widget->window, &r, FALSE);
+ el=el->next;
+ }
+ }
+}
+
+// invalidate the vertex and attached verticies
+static void invalidate_region_attached(GtkWidget *widget, vertex *v){
+ if(v){
+ edge_list *el=v->edges;
+ while (el){
+ edge *e=el->edge;
+ if(e->A != v)invalidate_region_vertex(GAMEBOARD(widget),e->A);
+ if(e->B != v)invalidate_region_vertex(GAMEBOARD(widget),e->B);
+ el=el->next;
+ }
+ invalidate_region_vertex(GAMEBOARD(widget),v);
+ }
+}
+
+// invalidate the selection box plus enough area to catch any verticies
+static void invalidate_region_selection(GtkWidget *widget){
+ Gameboard *g = GAMEBOARD (widget);
+ GdkRectangle r;
+ r.x = g->selectionx - (V_RADIUS + V_LINE)*2;
+ r.y = g->selectiony - (V_RADIUS + V_LINE)*2;
+ r.width = g->selectionw + (V_RADIUS + V_LINE)*4;
+ r.height = g->selectionh + (V_RADIUS + V_LINE)*4;
+
+ gdk_window_invalidate_rect (widget->window, &r, FALSE);
+}
+
+// invalidate the selection box plus enough area to catch any verticies
+static void invalidate_region_verticies_selection(GtkWidget *widget){
+ Gameboard *g = GAMEBOARD (widget);
+ vertex *v=get_verticies();
+ while(v){
+ if(v->selected)
+ invalidate_region_vertex_off(widget,v,g->dragx,g->dragy);
+ v=v->next;
+ }
+}
+
+static cairo_surface_t *cache_vertex(Gameboard *g){
+ cairo_surface_t *ret=
+ cairo_surface_create_similar (cairo_get_target (g->wc),
+ CAIRO_CONTENT_COLOR_ALPHA,
+ (V_RADIUS+V_LINE)*2,
+ (V_RADIUS+V_LINE)*2);
+ cairo_t *c = cairo_create(ret);
+
+ cairo_set_line_width(c,V_LINE);
+ cairo_arc(c,V_RADIUS+V_LINE,V_RADIUS+V_LINE,V_RADIUS,0,2*M_PI);
+ cairo_set_source_rgb(c,V_FILL_IDLE_COLOR);
+ cairo_fill_preserve(c);
+ cairo_set_source_rgb(c,V_LINE_COLOR);
+ cairo_stroke(c);
+
+ cairo_destroy(c);
+ return ret;
+}
+
+static cairo_surface_t *cache_vertex_sel(Gameboard *g){
+ cairo_surface_t *ret=
+ cairo_surface_create_similar (cairo_get_target (g->wc),
+ CAIRO_CONTENT_COLOR_ALPHA,
+ (V_RADIUS+V_LINE)*2,
+ (V_RADIUS+V_LINE)*2);
+ cairo_t *c = cairo_create(ret);
+
+ cairo_set_line_width(c,V_LINE);
+ cairo_arc(c,V_RADIUS+V_LINE,V_RADIUS+V_LINE,V_RADIUS,0,2*M_PI);
+ cairo_set_source_rgb(c,V_FILL_LIT_COLOR);
+ cairo_fill_preserve(c);
+ cairo_set_source_rgb(c,V_LINE_COLOR);
+ cairo_stroke(c);
+ cairo_arc(c,V_RADIUS+V_LINE,V_RADIUS+V_LINE,V_RADIUS*.5,0,2*M_PI);
+ cairo_set_source_rgb(c,V_FILL_IDLE_COLOR);
+ cairo_fill(c);
+
+ cairo_destroy(c);
+ return ret;
+}
+
+static cairo_surface_t *cache_vertex_grabbed(Gameboard *g){
+ cairo_surface_t *ret=
+ cairo_surface_create_similar (cairo_get_target (g->wc),
+ CAIRO_CONTENT_COLOR_ALPHA,
+ (V_RADIUS+V_LINE)*2,
+ (V_RADIUS+V_LINE)*2);
+ cairo_t *c = cairo_create(ret);
+
+ cairo_set_line_width(c,V_LINE);
+ cairo_arc(c,V_RADIUS+V_LINE,V_RADIUS+V_LINE,V_RADIUS,0,2*M_PI);
+ cairo_set_source_rgb(c,V_FILL_LIT_COLOR);
+ cairo_fill_preserve(c);
+ cairo_set_source_rgb(c,V_LINE_COLOR);
+ cairo_stroke(c);
+ cairo_arc(c,V_RADIUS+V_LINE,V_RADIUS+V_LINE,V_RADIUS*.5,0,2*M_PI);
+ cairo_set_source_rgb(c,V_FILL_ADJ_COLOR);
+ cairo_fill(c);
+
+ cairo_destroy(c);
+ return ret;
+}
+
+static cairo_surface_t *cache_vertex_lit(Gameboard *g){
+ cairo_surface_t *ret=
+ cairo_surface_create_similar (cairo_get_target (g->wc),
+ CAIRO_CONTENT_COLOR_ALPHA,
+ (V_RADIUS+V_LINE)*2,
+ (V_RADIUS+V_LINE)*2);
+ cairo_t *c = cairo_create(ret);
+
+ cairo_set_line_width(c,V_LINE);
+ cairo_arc(c,V_RADIUS+V_LINE,V_RADIUS+V_LINE,V_RADIUS,0,2*M_PI);
+ cairo_set_source_rgb(c,V_FILL_LIT_COLOR);
+ cairo_fill_preserve(c);
+ cairo_set_source_rgb(c,V_LINE_COLOR);
+ cairo_stroke(c);
+
+ cairo_destroy(c);
+ return ret;
+}
+
+static cairo_surface_t *cache_vertex_attached(Gameboard *g){
+ cairo_surface_t *ret=
+ cairo_surface_create_similar (cairo_get_target (g->wc),
+ CAIRO_CONTENT_COLOR_ALPHA,
+ (V_RADIUS+V_LINE)*2,
+ (V_RADIUS+V_LINE)*2);
+ cairo_t *c = cairo_create(ret);
+
+ cairo_set_line_width(c,V_LINE);
+ cairo_arc(c,V_RADIUS+V_LINE,V_RADIUS+V_LINE,V_RADIUS,0,2*M_PI);
+ cairo_set_source_rgb(c,V_FILL_ADJ_COLOR);
+ cairo_fill_preserve(c);
+ cairo_set_source_rgb(c,V_LINE_COLOR);
+ cairo_stroke(c);
+
+ cairo_destroy(c);
+ return ret;
+}
+
+static cairo_surface_t *cache_vertex_ghost(Gameboard *g){
+ cairo_surface_t *ret=
+ cairo_surface_create_similar (cairo_get_target (g->wc),
+ CAIRO_CONTENT_COLOR_ALPHA,
+ (V_RADIUS+V_LINE)*2,
+ (V_RADIUS+V_LINE)*2);
+ cairo_t *c = cairo_create(ret);
+
+ cairo_set_line_width(c,V_LINE);
+ cairo_arc(c,V_RADIUS+V_LINE,V_RADIUS+V_LINE,V_RADIUS,0,2*M_PI);
+ cairo_set_source_rgba(c,V_LINE_COLOR,.2);
+ cairo_fill_preserve(c);
+ cairo_set_source_rgba(c,V_LINE_COLOR,.4);
+ cairo_stroke(c);
+
+ cairo_destroy(c);
+ return ret;
+}
+
+
+static void draw_vertex(cairo_t *c,vertex *v,cairo_surface_t *s){
+ cairo_set_source_surface(c,
+ s,
+ v->x-V_LINE-V_RADIUS,
+ v->y-V_LINE-V_RADIUS);
+ cairo_paint(c);
+}
+
+static void setup_background_edge(cairo_t *c){
+ cairo_set_line_width(c,E_LINE);
+ cairo_set_source_rgba(c,E_LINE_B_COLOR);
+}
+
+static void setup_foreground_edge(cairo_t *c){
+ cairo_set_line_width(c,E_LINE);
+ cairo_set_source_rgba(c,E_LINE_F_COLOR);
+}
+
+static void draw_edge(cairo_t *c,edge *e){
+ cairo_move_to(c,e->A->x,e->A->y);
+ cairo_line_to(c,e->B->x,e->B->y);
+}
+
+static void finish_edge(cairo_t *c){
+ cairo_stroke(c);
+}
+
+static void draw_selection_rectangle(Gameboard *g,cairo_t *c){
+ cairo_set_source_rgba(c,SELECTBOX_COLOR);
+ cairo_rectangle(c,g->selectionx,
+ g->selectiony,
+ g->selectionw,
+ g->selectionh);
+ cairo_fill(c);
+}
+
+static void midground_draw(Gameboard *g,cairo_t *c,int x,int y,int w,int h){
+ /* Edges attached to the grabbed vertex are drawn here; they're the
+ inactive edges. */
+ if(g->grabbed_vertex && !g->hide_lines){
+ edge_list *el=g->grabbed_vertex->edges;
+ setup_foreground_edge(c);
+ while(el){
+ edge *e=el->edge;
+ /* no need to check rectangle; if they're to be drawn, they'll
+ always be in the rect */
+ draw_edge(c,e);
+ el=el->next;
+ }
+ finish_edge(c);
+ }
+
+ /* verticies are drawn in the foreground */
+ {
+ vertex *v = get_verticies();
+ int clipx = x-V_RADIUS;
+ int clipw = x+w+V_RADIUS;
+ int clipy = y-V_RADIUS;
+ int cliph = y+h+V_RADIUS;
+
+ while(v){
+
+ /* is the vertex in the expose rectangle? */
+ if(v->x>=clipx && v->x<=clipw &&
+ v->y>=clipy && v->y<=cliph){
+
+ if(v == g->grabbed_vertex && !g->group_drag) {
+ draw_vertex(c,v,g->vertex_grabbed);
+ } else if( v->selected ){
+ draw_vertex(c,v,g->vertex_sel);
+ } else if ( v == g->lit_vertex){
+ draw_vertex(c,v,g->vertex_lit);
+ } else if (v->attached_to_grabbed && !g->group_drag){
+ draw_vertex(c,v,g->vertex_attached);
+ }else
+ draw_vertex(c,v,g->vertex);
+ }
+
+ v=v->next;
+ }
+ }
+}
+
+static void background_draw(Gameboard *g,cairo_t *c){
+ int width=get_board_width();
+ int height=get_board_height();
+ edge *e=get_edges();
+
+ cairo_set_source_rgb(c,1,1,1);
+ cairo_paint(c);
+
+ if(!g->hide_lines){
+ setup_background_edge(c);
+ while(e){
+ if(e->active){
+ draw_edge(c,e);
+ }
+ e=e->next;
+ }
+ finish_edge(c);
+ }
+
+ // if there's a a group drag in progress, midground is drawn here
+ if(g->group_drag)
+ midground_draw(g,c,0,0,width,height);
+
+}
+
+static void background_addv(Gameboard *g,cairo_t *c, vertex *v){
+ edge_list *el=v->edges;
+
+ if(!g->hide_lines){
+ setup_background_edge(c);
+ while(el){
+ edge *e=el->edge;
+
+ if(e->active)
+ draw_edge(c,e);
+
+ el=el->next;
+ }
+ finish_edge(c);
+ }
+}
+
+static void foreground_draw(Gameboard *g,cairo_t *c,
+ int x,int y,int width,int height){
+ /* if a group drag is in progress, draw the group ghosted in the foreground */
+
+ if(g->group_drag){
+ vertex *v = get_verticies();
+ while(v){
+
+ if( v->selected ){
+ vertex tv;
+ tv.x=v->x+g->dragx;
+ tv.y=v->y+g->dragy;
+ draw_vertex(c,&tv,g->vertex_ghost);
+ }
+
+ v=v->next;
+ }
+ }else
+ midground_draw(g,c,x,y,width,height);
+
+ if(g->selection_grab)
+ draw_selection_rectangle(g,c);
+}
+
+static void update_background(GtkWidget *widget){
+ Gameboard *g = GAMEBOARD (widget);
+ GdkRectangle r;
+ cairo_t *c = cairo_create(g->background);
+
+ g->delayed_background=0;
+
+ // render the far background plane
+ background_draw(g,c);
+ cairo_destroy(c);
+
+ r.x=0;
+ r.y=0;
+ r.width=widget->allocation.width;
+ r.height=widget->allocation.height;
+
+ gdk_window_invalidate_rect (widget->window, &r, FALSE);
+
+}
+
+void update_full(Gameboard *g){
+ update_background(&g->w);
+}
+
+// also updates score
+static void update_background_addv(GtkWidget *widget, vertex *v){
+ Gameboard *g = GAMEBOARD (widget);
+ cairo_t *c = cairo_create(g->background);
+
+ g->delayed_background=0;
+
+ // render the far background plane
+ background_addv(g,c,v);
+ cairo_destroy(c);
+
+ invalidate_region_attached(widget,v);
+}
+
+static void update_background_delayed(GtkWidget *widget){
+ Gameboard *g = GAMEBOARD (widget);
+ g->delayed_background=1;
+}
+
+static void check_lit(GtkWidget *widget,int x, int y){
+ Gameboard *g = GAMEBOARD (widget);
+ vertex *v = find_vertex(x,y);
+ if(v!=g->lit_vertex){
+ invalidate_region_vertex(g,v);
+ invalidate_region_vertex(g,g->lit_vertex);
+ g->lit_vertex = v;
+ }
+}
+
+static void score_update(Gameboard *g){
+ /* Score, level, intersections */
+ char level_string[160];
+ char score_string[160];
+ char int_string[160];
+ char obj_string[160];
+ cairo_text_extents_t extentsL;
+ cairo_text_extents_t extentsS;
+ cairo_text_extents_t extentsO;
+ cairo_text_extents_t extentsI;
+ cairo_matrix_t m;
+
+ cairo_t *c = cairo_create(g->forescore);
+
+ if(get_num_intersections() <= get_objective()){
+ deploy_check(g);
+ }else{
+ undeploy_check(g);
+ }
+
+
+ // clear the pane
+ cairo_save(c);
+ cairo_set_operator(c,CAIRO_OPERATOR_CLEAR);
+ cairo_set_source_rgba (c, 1,1,1,1);
+ cairo_paint(c);
+ cairo_restore(c);
+
+ topbox(c,get_board_width(),SCOREHEIGHT);
+
+ cairo_select_font_face (c, "Arial",
+ CAIRO_FONT_SLANT_NORMAL,
+ CAIRO_FONT_WEIGHT_BOLD);
+
+ cairo_matrix_init_scale (&m, 12.,15.);
+ cairo_set_font_matrix (c,&m);
+ cairo_set_source_rgba (c, TEXT_COLOR);
+
+ snprintf(level_string,160,"Level %d: \"%s\"",get_level()+1,get_level_string());
+ snprintf(score_string,160,"Score: %d",get_score());
+ snprintf(int_string,160,"Intersections: %d",get_num_intersections());
+ snprintf(obj_string,160,"Objective: %s",get_objective_string());
+
+ cairo_text_extents (c, level_string, &extentsL);
+ cairo_text_extents (c, obj_string, &extentsO);
+ cairo_text_extents (c, int_string, &extentsI);
+ cairo_text_extents (c, score_string, &extentsS);
+
+ /*
+ text_h = extentsL.height;
+ text_h = max(text_h,extentsO.height);
+ text_h = max(text_h,extentsI.height);
+ text_h = max(text_h,extentsS.height);
+ */
+
+ int ty1 = 23;
+ int ty2 = 38;
+
+ cairo_move_to (c, 15, ty1);
+ cairo_show_text (c, int_string);
+ cairo_move_to (c, 15, ty2);
+ cairo_show_text (c, score_string);
+
+ cairo_move_to (c, get_board_width()-extentsL.width-15, ty1);
+ cairo_show_text (c, level_string);
+ cairo_move_to (c, get_board_width()-extentsO.width-15, ty2);
+ cairo_show_text (c, obj_string);
+
+ cairo_destroy(c);
+
+ // slightly lazy
+ {
+ GdkRectangle r;
+ r.x=0;
+ r.y=0;
+ r.width=get_board_width();
+ r.height = SCOREHEIGHT;
+ gdk_window_invalidate_rect (g->w.window, &r, FALSE);
+ }
+}
+
+static gint mouse_motion(GtkWidget *widget,
+ GdkEventMotion *event){
+ Gameboard *g = GAMEBOARD (widget);
+
+ if(g->button_grabbed){
+ g->button_grabbed =
+ button_motion_event(g,event,
+ (!g->lit_vertex && !g->grabbed_vertex && !g->selection_grab));
+ }
+
+ if(!g->button_grabbed){
+ if(g->grabbed_vertex){
+ int x = (int)event->x;
+ int y = (int)event->y;
+ g->dragx = x-g->grabx;
+ g->dragy = y-g->graby;
+
+ invalidate_region_vertex(g,g->grabbed_vertex);
+ invalidate_region_edges(widget,g->grabbed_vertex);
+ move_vertex(g->grabbed_vertex,x+g->graboffx,y+g->graboffy);
+ invalidate_region_vertex(g,g->grabbed_vertex);
+ invalidate_region_edges(widget,g->grabbed_vertex);
+ }else if (g->selection_grab){
+ invalidate_region_selection(widget);
+
+ g->selectionx = min(g->grabx, event->x);
+ g->selectionw = labs(g->grabx - event->x);
+ g->selectiony = min(g->graby, event->y);
+ g->selectionh = labs(g->graby - event->y);
+ select_verticies(g->selectionx,g->selectiony,
+ g->selectionx+g->selectionw-1,
+ g->selectiony+g->selectionh-1);
+
+ invalidate_region_selection(widget);
+ }else if(g->group_drag){
+ invalidate_region_verticies_selection(widget);
+ g->dragx = event->x - g->grabx;
+ g->dragy = event->y - g->graby;
+
+ // if this puts any of the dragged offscreen adjust the drag back
+ // onscreen. It will avoid confusing/concerning users
+ {
+ vertex *v=get_verticies();
+ int w=get_board_width();
+ int h=get_board_height();
+
+ while(v){
+ if(v->selected){
+ if(v->x + g->dragx >= w)
+ g->dragx=w - v->x -1;
+ if(v->x + g->dragx < 0 )
+ g->dragx= -v->x;
+ if(v->y + g->dragy >= h)
+ g->dragy=h - v->y -1;
+ if(v->y + g->dragy < 0 )
+ g->dragy= -v->y;
+ }
+ v=v->next;
+ }
+ }
+
+ invalidate_region_verticies_selection(widget);
+ }else{
+ check_lit(widget, (int)event->x,(int)event->y);
+
+ button_motion_event(g,event,
+ (!g->lit_vertex && !g->grabbed_vertex && !g->selection_grab));
+
+ }
+ }
+ return TRUE;
+}
+
+static gboolean button_press (GtkWidget *widget,
+ GdkEventButton *event){
+ Gameboard *g = GAMEBOARD (widget);
+
+ vertex *v = find_vertex((int)event->x,(int)event->y);
+ g->button_grabbed=0;
+
+ if(!g->group_drag && event->state&GDK_SHIFT_MASK){
+ if(v){
+ if(v->selected){
+ v->selected=0;
+ g->selection_active--;
+ }else{
+ v->selected=1;
+ g->selection_active++;
+ }
+ invalidate_region_vertex(g,g->lit_vertex);
+ }else{
+ // addending group drag
+ g->selection_grab=1;
+ g->grabx = (int)event->x;
+ g->graby = (int)event->y;
+ g->selectionx = g->grabx;
+ g->selectionw = 0;
+ g->selectiony = g->graby;
+ g->selectionh = 0;
+ }
+ }else{
+
+ if(g->selection_active){
+ vertex *v = find_vertex((int)event->x,(int)event->y);
+ if(v && v->selected){
+ // group drag
+ g->group_drag=1;
+ g->grabx = (int)event->x;
+ g->graby = (int)event->y;
+ g->dragx = 0;
+ g->dragy = 0;
+ // put the verticies into the background for faster update
+ update_background(widget);
+ }else{
+
+ if(button_button_press(g,event,1)){
+ g->button_grabbed=1;
+ }else{
+ deselect_verticies();
+ update_background(widget);
+ g->selection_active=0;
+ g->group_drag=0;
+ check_lit(widget,event->x,event->y);
+ button_press(widget,event);
+ }
+ }
+
+ }else if(g->lit_vertex){
+ // vertex grab
+ g->grabbed_vertex = g->lit_vertex;
+ g->grabx = (int)event->x;
+ g->graby = (int)event->y;
+ g->graboffx = g->grabbed_vertex->x-g->grabx;
+ g->graboffy = g->grabbed_vertex->y-g->graby;
+
+ grab_vertex(g->grabbed_vertex);
+ invalidate_region_attached(widget,g->grabbed_vertex);
+ invalidate_region_edges(widget,g->grabbed_vertex);
+
+ update_background_delayed(widget);
+ }else{
+
+ if(button_button_press(g,event,1)){
+ g->button_grabbed=1;
+ }else{
+ // selection grab;
+ g->selection_grab=1;
+ g->grabx = (int)event->x;
+ g->graby = (int)event->y;
+ g->selectionx = g->grabx;
+ g->selectionw = 0;
+ g->selectiony = g->graby;
+ g->selectionh = 0;
+ }
+ }
+ }
+
+ if(!g->button_grabbed)
+ hide_intersections(g);
+
+ return TRUE;
+}
+
+static gboolean button_release (GtkWidget *widget,
+ GdkEventButton *event){
+ Gameboard *g = GAMEBOARD (widget);
+
+ button_button_release(g,event,1);
+
+ if(g->grabbed_vertex){
+ ungrab_vertex(g->grabbed_vertex);
+ update_background_addv(widget,g->grabbed_vertex);
+ score_update(g);
+ g->grabbed_vertex = 0;
+ }
+
+ if(g->selection_grab){
+ invalidate_region_selection(widget);
+ g->selection_grab=0;
+ // are there selected verticies? Avoid accidentally misgrabbing one.
+ if(num_selected_verticies()<=1){
+ g->selection_active=0;
+ deselect_verticies(); // could have grabbed just one
+ }else{
+ commit_volatile_selection();
+ g->selection_active=num_selected_verticies();
+ }
+ }
+
+ if(g->group_drag){
+ move_selected_verticies(g->dragx,g->dragy);
+ update_background(widget); // cheating
+ g->group_drag=0;
+ }
+
+ mouse_motion(widget,(GdkEventMotion *)event); // the cast is safe in
+ // this case
+
+ return TRUE;
+}
+
+static void size_request (GtkWidget *widget,GtkRequisition *requisition){
+
+ requisition->width = get_board_width();
+ requisition->height = get_board_height();
+
+}
+
+static void gameboard_init (Gameboard *g){
+
+ // instance initialization
+
+
+}
+
+static void gameboard_destroy (GtkObject *object){
+ if (GTK_OBJECT_CLASS (parent_class)->destroy)
+ (*GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+}
+
+static void draw_intersection(cairo_t *c,double x, double y){
+ cairo_move_to(c,x-INTERSECTION_RADIUS,y);
+ cairo_rel_line_to(c,INTERSECTION_RADIUS,-INTERSECTION_RADIUS);
+ cairo_rel_line_to(c,INTERSECTION_RADIUS,INTERSECTION_RADIUS);
+ cairo_rel_line_to(c,-INTERSECTION_RADIUS,INTERSECTION_RADIUS);
+ cairo_close_path(c);
+}
+static void expose_intersections(Gameboard *g,cairo_t *c,
+ int x,int y,int w,int h){
+
+ if(g->show_intersections){
+ cairo_set_source_rgba (c, INTERSECTION_COLOR);
+ cairo_set_line_width(c, INTERSECTION_LINE_WIDTH);
+
+ double xx=x-(INTERSECTION_LINE_WIDTH*.5 + INTERSECTION_RADIUS);
+ double x2=w+x+(INTERSECTION_LINE_WIDTH + INTERSECTION_RADIUS*2);
+ double yy=y-(INTERSECTION_LINE_WIDTH*.5 + INTERSECTION_RADIUS);
+ double y2=h+y+(INTERSECTION_LINE_WIDTH + INTERSECTION_RADIUS*2);
+
+ // walk the intersection list of all edges; draw if paired is a higher pointer
+ edge *e=get_edges();
+ while(e){
+ intersection *i = e->i.next;
+ while(i){
+ if(i->paired > i){
+ double ix=i->x, iy=i->y;
+
+ if(ix >= xx && ix <= x2 && iy >= yy && iy <= y2)
+ draw_intersection(c,ix,iy);
+ }
+ i=i->next;
+ }
+ e=e->next;
+ }
+ cairo_stroke(c);
+ }
+}
+
+void run_immediate_expose(Gameboard *g,
+ int x, int y, int w, int h){
+
+ if (w==0 || h==0) return;
+
+ //fprintf(stderr,"(%d) %d/%d %d/%d\n",g->first_expose,x,w,y,h);
+
+ cairo_t *c = cairo_create(g->foreground);
+
+ // copy background to foreground draw buffer
+ cairo_set_source_surface(c,g->background,0,0);
+ cairo_rectangle(c,x,y,w,h);
+ cairo_fill(c);
+ foreground_draw(g,c,x,y,w,h);
+
+ // copy in any of the score or button surfaces?
+ if(y<SCOREHEIGHT){
+ cairo_set_source_surface(c,g->forescore,0,0);
+ cairo_rectangle(c, x,y,w,
+ min(SCOREHEIGHT-y,h));
+ cairo_fill(c);
+ }
+ if(y+h>g->w.allocation.height-SCOREHEIGHT){
+ cairo_set_source_surface(c,g->forebutton,0,g->w.allocation.height-SCOREHEIGHT);
+ cairo_rectangle(c, x,y,w,h);
+ cairo_fill(c);
+ }
+ expose_buttons(g,c,x,y,w,h);
+
+ expose_intersections(g,c,x,y,w,h);
+
+ cairo_destroy(c);
+
+ // blit to window
+ cairo_set_source_surface(g->wc,g->foreground,0,0);
+ cairo_rectangle(g->wc,x,y,w,h);
+ cairo_fill(g->wc);
+
+ if(g->delayed_background)update_background(&g->w);
+ g->first_expose=1;
+ //gdk_window_process_all_updates();
+}
+
+static gint gameboard_expose (GtkWidget *widget,
+ GdkEventExpose *event){
+
+ Gameboard *g = GAMEBOARD (widget);
+ run_immediate_expose(g,event->area.x,event->area.y,
+ event->area.width,event->area.height);
+ return FALSE;
+}
+
+static void paint_bottom_box (Gameboard *g){
+ cairo_t *c = cairo_create(g->forebutton);
+
+ cairo_save(c);
+ cairo_set_operator(c,CAIRO_OPERATOR_CLEAR);
+ cairo_set_source_rgba (c, 1,1,1,1);
+ cairo_paint(c);
+ cairo_restore(c);
+
+ bottombox(c,g->w.allocation.width,SCOREHEIGHT);
+ cairo_destroy(c);
+}
+
+static void gameboard_realize (GtkWidget *widget){
+ Gameboard *g = GAMEBOARD (widget);
+ GdkWindowAttr attributes;
+ gint attributes_mask;
+
+ GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
+
+ attributes.x = widget->allocation.x;
+ attributes.y = widget->allocation.y;
+ attributes.width = widget->allocation.width;
+ attributes.height = widget->allocation.height;
+ attributes.wclass = GDK_INPUT_OUTPUT;
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.event_mask =
+ gtk_widget_get_events (widget) |
+ GDK_EXPOSURE_MASK|
+ GDK_POINTER_MOTION_MASK|
+ GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK|
+ GDK_KEY_PRESS_MASK |
+ GDK_KEY_RELEASE_MASK |
+ GDK_STRUCTURE_MASK;
+ attributes.visual = gtk_widget_get_visual (widget);
+ attributes.colormap = gtk_widget_get_colormap (widget);
+ attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+ widget->window = gdk_window_new (widget->parent->window,
+ &attributes, attributes_mask);
+ gtk_style_attach (widget->style, widget->window);
+ gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
+ gdk_window_set_user_data (widget->window, widget);
+ gtk_widget_set_double_buffered (widget, FALSE);
+
+ g->wc = gdk_cairo_create(widget->window);
+
+ g->forescore =
+ cairo_surface_create_similar (cairo_get_target (g->wc),
+ CAIRO_CONTENT_COLOR_ALPHA,
+ widget->allocation.width,
+ SCOREHEIGHT);
+
+ g->forebutton =
+ cairo_surface_create_similar (cairo_get_target (g->wc),
+ CAIRO_CONTENT_COLOR_ALPHA,
+ widget->allocation.width,
+ SCOREHEIGHT);
+
+ g->background =
+ cairo_surface_create_similar (cairo_get_target (g->wc),
+ CAIRO_CONTENT_COLOR,
+ widget->allocation.width,
+ widget->allocation.height);
+ g->foreground =
+ cairo_surface_create_similar (cairo_get_target (g->wc),
+ CAIRO_CONTENT_COLOR,
+ widget->allocation.width,
+ widget->allocation.height);
+
+ // cache the vertex images that are drawn in quantity; the blit with
+ // alpha is much faster than the render
+
+ g->vertex = cache_vertex(g);
+ g->vertex_lit = cache_vertex_lit(g);
+ g->vertex_attached = cache_vertex_attached(g);
+ g->vertex_grabbed = cache_vertex_grabbed(g);
+ g->vertex_sel = cache_vertex_sel(g);
+ g->vertex_ghost = cache_vertex_ghost(g);
+
+ update_background(widget);
+ score_update(g);
+ paint_bottom_box(g);
+ init_buttons(g);
+}
+
+static void gameboard_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation){
+ Gameboard *g = GAMEBOARD (widget);
+ widget->allocation = *allocation;
+
+ if (GTK_WIDGET_REALIZED (widget)){
+ int oldw=get_board_width();
+ int oldh=get_board_height();
+
+ gdk_window_move_resize (widget->window, allocation->x, allocation->y,
+ allocation->width, allocation->height);
+
+
+ if (g->forescore)
+ cairo_surface_destroy(g->forescore);
+ if (g->forebutton)
+ cairo_surface_destroy(g->forebutton);
+ if (g->background)
+ cairo_surface_destroy(g->background);
+ if (g->foreground)
+ cairo_surface_destroy(g->foreground);
+
+ g->background =
+ cairo_surface_create_similar (cairo_get_target (g->wc),
+ CAIRO_CONTENT_COLOR, // don't need alpha
+ widget->allocation.width,
+ widget->allocation.height);
+ g->forescore =
+ cairo_surface_create_similar (cairo_get_target (g->wc),
+ CAIRO_CONTENT_COLOR_ALPHA,
+ widget->allocation.width,
+ SCOREHEIGHT);
+ g->forebutton =
+ cairo_surface_create_similar (cairo_get_target (g->wc),
+ CAIRO_CONTENT_COLOR_ALPHA,
+ widget->allocation.width,
+ SCOREHEIGHT);
+
+ g->foreground =
+ cairo_surface_create_similar (cairo_get_target (g->wc),
+ CAIRO_CONTENT_COLOR, // don't need alpha
+ widget->allocation.width,
+ widget->allocation.height);
+
+ // recenter all the verticies; doesn't require recomputation
+ {
+ vertex *v=get_verticies();
+ int xd=(widget->allocation.width-oldw)*.5;
+ int yd=(widget->allocation.height-oldh)*.5;
+
+ while(v){
+ v->x+=xd;
+ v->y+=yd;
+ v=v->next;
+ }
+ }
+
+ // also verifies all verticies are onscreen
+ resize_board(allocation->width,allocation->height);
+
+ update_background(widget);
+ paint_bottom_box(g);
+ score_update(g);
+ resize_buttons(widget->allocation.width,widget->allocation.height);
+ }
+}
+
+static void gameboard_class_init (GameboardClass * class) {
+
+ GtkObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+
+ object_class = (GtkObjectClass *) class;
+ widget_class = (GtkWidgetClass *) class;
+
+ parent_class = gtk_type_class (GTK_TYPE_WIDGET);
+
+ object_class->destroy = gameboard_destroy;
+
+ widget_class->realize = gameboard_realize;
+ widget_class->expose_event = gameboard_expose;
+ widget_class->size_request = size_request;
+ widget_class->size_allocate = gameboard_size_allocate;
+ widget_class->button_press_event = button_press;
+ widget_class->button_release_event = button_release;
+ widget_class->motion_notify_event = mouse_motion;
+
+}
+
+GType gameboard_get_type (void){
+
+ static GType gameboard_type = 0;
+
+ if (!gameboard_type)
+ {
+ static const GTypeInfo gameboard_info = {
+ sizeof (GameboardClass),
+ NULL,
+ NULL,
+ (GClassInitFunc) gameboard_class_init,
+ NULL,
+ NULL,
+ sizeof (Gameboard),
+ 0,
+ (GInstanceInitFunc) gameboard_init,
+ 0
+ };
+
+ gameboard_type = g_type_register_static (GTK_TYPE_WIDGET, "Gameboard",
+ &gameboard_info, 0);
+ }
+
+ return gameboard_type;
+}
+
+Gameboard *gameboard_new (void) {
+ GtkWidget *g = GTK_WIDGET (g_object_new (GAMEBOARD_TYPE, NULL));
+ Gameboard *gb = GAMEBOARD (g);
+ return gb;
+}
+
+void gameboard_reset (Gameboard *g) {
+ g->lit_vertex=0;
+ g->grabbed_vertex=0;
+ g->delayed_background=0;
+
+ g->group_drag=0;
+ g->button_grabbed=0;
+ g->selection_grab=0;
+ g->selection_active=0;
+
+ update_background(&g->w);
+ score_update(g);
+}
+
+void hide_lines(Gameboard *g){
+ g->hide_lines=1;
+ update_background(&g->w);
+}
+
+void show_lines(Gameboard *g){
+ g->hide_lines=0;
+ update_background(&g->w);
+}
+
+int get_hide_lines(Gameboard *g){
+ return g->hide_lines;
+}
+
+void show_intersections(Gameboard *g){
+ if(!g->show_intersections){
+ g->show_intersections=1;
+ update_background(&g->w);
+ }else{
+ hide_intersections(g);
+ }
+}
+
+void hide_intersections(Gameboard *g){
+ if(g->show_intersections){
+ g->show_intersections=0;
+ update_background(&g->w);
+ }
+}
+
+int selected(Gameboard *g){
+ return g->selection_active;
+}
Added: trunk/planarity/gameboard.h
===================================================================
--- trunk/planarity/gameboard.h 2005-07-26 23:19:44 UTC (rev 9630)
+++ trunk/planarity/gameboard.h 2005-07-28 03:59:23 UTC (rev 9631)
@@ -0,0 +1,96 @@
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtkcontainer.h>
+#include <gtk/gtksignal.h>
+#include <gtk/gtkdrawingarea.h>
+
+
+#define V_RADIUS 8
+#define V_LINE 2
+#define V_LINE_COLOR 0, 0, 0
+#define V_FILL_IDLE_COLOR .2,.2, 1
+#define V_FILL_LIT_COLOR 1, 1, 1
+#define V_FILL_ADJ_COLOR 1,.2,.2
+
+#define E_LINE 1.5
+#define E_LINE_F_COLOR 0, 0, 0, 1
+#define E_LINE_B_COLOR .5,.5,.5, 1
+#define SELECTBOX_COLOR .2,.8,.8,.3
+
+#define INTERSECTION_COLOR 1,.1,.1,.8
+#define INTERSECTION_RADIUS 6
+#define INTERSECTION_LINE_WIDTH 2
+
+G_BEGIN_DECLS
+
+#define GAMEBOARD_TYPE (gameboard_get_type ())
+#define GAMEBOARD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GAMEBOARD_TYPE, Gameboard))
+#define GAMEBOARD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GAMEBOARD_TYPE, GameboardClass))
+#define IS_GAMEBOARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GAMEBOARD_TYPE))
+#define IS_GAMEBOARD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GAMEBOARD_TYPE))
+
+typedef struct _Gameboard Gameboard;
+typedef struct _GameboardClass GameboardClass;
+
+struct _Gameboard{
+ GtkWidget w;
+
+ cairo_t *wc;
+ cairo_surface_t *vertex;
+ cairo_surface_t *vertex_lit;
+ cairo_surface_t *vertex_grabbed;
+ cairo_surface_t *vertex_attached;
+ cairo_surface_t *vertex_sel;
+ cairo_surface_t *vertex_ghost;
+ cairo_surface_t *forescore;
+ cairo_surface_t *forebutton;
+ cairo_surface_t *background;
+ cairo_surface_t *foreground;
+ int delayed_background;
+
+ vertex *grabbed_vertex;
+ vertex *lit_vertex;
+ int group_drag;
+ int button_grabbed;
+
+ int grabx;
+ int graby;
+ int dragx;
+ int dragy;
+ int graboffx;
+ int graboffy;
+
+ int selection_grab;
+ int selection_active;
+ int selectionx;
+ int selectiony;
+ int selectionw;
+ int selectionh;
+
+ int hide_lines;
+
+ int first_expose;
+ int show_intersections;
+};
+
+struct _GameboardClass{
+ GtkWidgetClass parent_class;
+ void (* gameboard) (Gameboard *m);
+};
+
+GType gameboard_get_type (void);
+Gameboard* gameboard_new (void);
+
+G_END_DECLS
+
+extern void main_board(int argc, char *argv[]);
+extern void run_immediate_expose(Gameboard *g,int x, int y, int w, int h);
+extern void gameboard_reset(Gameboard *g);
+extern void hide_lines(Gameboard *g);
+extern void show_lines(Gameboard *g);
+extern int get_hide_lines(Gameboard *g);
+extern void show_intersections(Gameboard *g);
+extern void hide_intersections(Gameboard *g);
+extern void invalidate_region_vertex(Gameboard *g, vertex *v);
+extern int selected(Gameboard *g);
+extern void update_full(Gameboard *g);
Added: trunk/planarity/gamestate.c
===================================================================
--- trunk/planarity/gamestate.c 2005-07-26 23:19:44 UTC (rev 9630)
+++ trunk/planarity/gamestate.c 2005-07-28 03:59:23 UTC (rev 9631)
@@ -0,0 +1,233 @@
+#include <math.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+#include "graph.h"
+#include "gameboard.h"
+#include "generate.h"
+#include "gamestate.h"
+#include "buttons.h"
+
+Gameboard *gameboard;
+
+static int width=800;
+static int height=640;
+
+static int level=0;
+static int score=0;
+
+static int initial_intersections;
+static int objective=0;
+static int objective_lessthan=0;
+
+static gboolean key_press(GtkWidget *w,GdkEventKey *event,gpointer in){
+
+ if(event->keyval == GDK_q && event->state&GDK_CONTROL_MASK)
+ gtk_main_quit();
+
+ return FALSE;
+}
+
+void resize_board(int x, int y){
+ width=x;
+ height=y;
+ check_verticies();
+}
+
+int get_board_width(){
+ return width;
+}
+
+int get_board_height(){
+ return height;
+}
+
+void setup_board(){
+ generate_mesh_1(level);
+ impress_location();
+ initial_intersections = get_num_intersections();
+ gameboard_reset(gameboard);
+
+ //gdk_flush();
+ deploy_buttons(gameboard);
+}
+
+#define RESET_DELTA 2;
+
+void reset_board(){
+ int flag=1;
+ int hide_state = get_hide_lines(gameboard);
+ hide_lines(gameboard);
+
+ vertex *v=get_verticies();
+ while(v){
+ deactivate_vertex(v);
+ v=v->next;
+ }
+
+ while(flag){
+ flag=0;
+
+ v=get_verticies();
+ while(v){
+ if(v->x != v->orig_x || v->y != v->orig_y){
+ flag=1;
+
+ invalidate_region_vertex(gameboard,v);
+ if(v->x<v->orig_x){
+ v->x+=RESET_DELTA;
+ if(v->x>v->orig_x)v->x=v->orig_x;
+ }else{
+ v->x-=RESET_DELTA;
+ if(v->x<v->orig_x)v->x=v->orig_x;
+ }
+ if(v->y<v->orig_y){
+ v->y+=RESET_DELTA;
+ if(v->y>v->orig_y)v->y=v->orig_y;
+ }else{
+ v->y-=RESET_DELTA;
+ if(v->y<v->orig_y)v->y=v->orig_y;
+ }
+ invalidate_region_vertex(gameboard,v);
+ }
+ v=v->next;
+ }
+ gdk_window_process_all_updates();
+ gdk_flush();
+
+ }
+
+ v=get_verticies();
+ while(v){
+ activate_vertex(v);
+ v=v->next;
+ }
+
+ if(!hide_state)show_lines(gameboard);
+ if(get_num_intersections() <= get_objective()){
+ deploy_check(gameboard);
+ }else{
+ undeploy_check(gameboard);
+ }
+ update_full(gameboard);
+ // reset timer
+}
+
+void scale(double scale){
+ int x=get_board_width()/2;
+ int y=get_board_height()/2;
+ int sel = selected(gameboard);
+ // if selected, expand from center of selected mass
+ if(sel){
+ vertex *v=get_verticies();
+ double xac=0;
+ double yac=0;
+ while(v){
+ if(v->selected){
+ xac+=v->x;
+ yac+=v->y;
+ }
+ v=v->next;
+ }
+ x = xac / selected(gameboard);
+ y = yac / selected(gameboard);
+ }
+
+ vertex *v=get_verticies();
+ while(v){
+
+ if(!sel || v->selected){
+ int nx = rint((v->x - x)*scale+x);
+ int ny = rint((v->y - y)*scale+y);
+
+ if(nx<0)nx=0;
+ if(nx>=width)nx=width-1;
+ if(ny<0)ny=0;
+ if(ny>=height)ny=height-1;
+
+ deactivate_vertex(v);
+ v->x = nx;
+ v->y = ny;
+ }
+ v=v->next;
+ }
+
+ v=get_verticies();
+ while(v){
+ activate_vertex(v);
+ v=v->next;
+ }
+
+ update_full(gameboard);
+}
+
+void expand(){
+ scale(1.2);
+}
+
+void shrink(){
+ scale(.8);
+}
+
+void hide_show_lines(){
+ if(get_hide_lines(gameboard))
+ show_lines(gameboard);
+ else
+ hide_lines(gameboard);
+}
+
+void mark_intersections(){
+ show_intersections(gameboard);
+}
+
+void finish_board(){
+ if(get_num_intersections()<=initial_intersections){
+ score+=initial_intersections;
+ level++;
+ undeploy_buttons(gameboard,setup_board);
+ }
+}
+
+void quit(){
+ undeploy_buttons(gameboard,gtk_main_quit);
+}
+
+int get_score(){
+ return score + initial_intersections-get_num_intersections();
+}
+
+int get_objective(){
+ return objective;
+}
+
+char *get_objective_string(){
+ return "zero intersections";
+}
+
+int get_level(){
+ return level;
+}
+
+char *get_level_string(){
+ return "\"original level\"";
+}
+
+int main(int argc, char *argv[]){
+ GtkWidget *window;
+ gtk_init (&argc, &argv);
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ g_signal_connect (G_OBJECT (window), "delete-event",
+ G_CALLBACK (gtk_main_quit), NULL);
+ g_signal_connect (G_OBJECT (window), "key-press-event",
+ G_CALLBACK (key_press), window);
+
+ gameboard = gameboard_new ();
+
+ gtk_container_add (GTK_CONTAINER (window), GTK_WIDGET(gameboard));
+ gtk_widget_show_all (window);
+
+ setup_board(gameboard);
+
+ gtk_main ();
+ return 0;
+}
Added: trunk/planarity/gamestate.h
===================================================================
--- trunk/planarity/gamestate.h 2005-07-26 23:19:44 UTC (rev 9630)
+++ trunk/planarity/gamestate.h 2005-07-28 03:59:23 UTC (rev 9631)
@@ -0,0 +1,17 @@
+
+extern void resize_board(int x, int y);
+extern int get_board_width();
+extern int get_board_height();
+extern void setup_board();
+extern void finish_board();
+extern void hide_show_lines();
+extern void mark_intersections();
+extern void reset_board();
+extern void expand();
+extern void shrink();
+extern int get_score();
+extern int get_objective();
+extern char *get_objective_string();
+extern int get_level();
+extern char *get_level_string();
+extern void quit();
Added: trunk/planarity/generate.c
===================================================================
--- trunk/planarity/generate.c 2005-07-26 23:19:44 UTC (rev 9630)
+++ trunk/planarity/generate.c 2005-07-28 03:59:23 UTC (rev 9631)
@@ -0,0 +1,227 @@
+#include <stdlib.h>
+#include <string.h>
+
+#include "graph.h"
+#include "generate.h"
+#include "arrange.h"
+
+typedef struct {
+ vertex **v;
+ int width;
+ int height;
+} mesh;
+
+typedef struct {
+ int vnum[8];
+ vertex *center;
+ mesh *m;
+} neighbors_grid;
+
+typedef struct {
+ int vnum[8];
+ int num;
+} neighbors_list;
+
+static void populate_neighbors(int vnum, mesh *m,
+ neighbors_grid *ng){
+ int width = m->width;
+ int y = vnum/width;
+ int x = vnum - (y*width);
+ int i;
+
+ for(i=0;i<8;i++)ng->vnum[i]=-1;
+
+
+ ng->center = m->v[vnum];
+ ng->m = m;
+
+ if(y-1 >= 0){
+ if(x-1 >= 0) ng->vnum[0]= (y-1)*width+(x-1);
+ ng->vnum[1]= (y-1)*width+x;
+ if(x+1 < m->width) ng->vnum[2]= (y-1)*width+(x+1);
+ }
+
+ if(x-1 >= 0) ng->vnum[3]= y*width+(x-1);
+ if(x+1 < m->width) ng->vnum[4]= y*width+(x+1);
+
+ if(y+1 < m->height){
+ if(x-1 >= 0) ng->vnum[5]= (y+1)*width+(x-1);
+ ng->vnum[6]= (y+1)*width+x;
+ if(x+1 < m->width) ng->vnum[7]= (y+1)*width+(x+1);
+ }
+
+}
+
+// eliminate from neighbor structs the verticies that already have at
+// least one edge
+static void filter_spanned_neighbors(neighbors_grid *ng,
+ neighbors_list *nl){
+ int i;
+ int count=0;
+ for(i=0;i<8;i++)
+ if(ng->vnum[i]==-1 || ng->m->v[ng->vnum[i]]->edges){
+ ng->vnum[i]=-1;
+ }else{
+ nl->vnum[count++]=ng->vnum[i];
+ }
+ nl->num=count;
+
+}
+
+// eliminate from neighbor struct any verticies to which we can't make
+// an edge without crossing another edge. Only 0,2,5,7 possible.
+static void filter_intersections(neighbors_grid *ng){
+ int i;
+ for(i=0;i<8;i++){
+ switch(i){
+ case 0:
+ if(ng->vnum[1] != -1 &&
+ ng->vnum[3] != -1 &&
+ exists_edge(ng->m->v[ng->vnum[1]],
+ ng->m->v[ng->vnum[3]]))
+ ng->vnum[i]=-1;
+ break;
+
+ case 2:
+ if(ng->vnum[1] != -1 &&
+ ng->vnum[4] != -1 &&
+ exists_edge(ng->m->v[ng->vnum[1]],
+ ng->m->v[ng->vnum[4]]))
+ ng->vnum[i]=-1;
+ break;
+
+ case 5:
+ if(ng->vnum[3] != -1 &&
+ ng->vnum[6] != -1 &&
+ exists_edge(ng->m->v[ng->vnum[3]],
+ ng->m->v[ng->vnum[6]]))
+ ng->vnum[i]=-1;
+ break;
+
+ case 7:
+ if(ng->vnum[4] != -1 &&
+ ng->vnum[6] != -1 &&
+ exists_edge(ng->m->v[ng->vnum[4]],
+ ng->m->v[ng->vnum[6]]))
+ ng->vnum[i]=-1;
+ break;
+ }
+ }
+}
+
+// eliminate verticies we've already connected to
+static void filter_edges(neighbors_grid *ng,
+ neighbors_list *nl){
+
+ vertex *v=ng->center;
+ int count=0,i;
+ for(i=0;i<8;i++){
+ if(ng->vnum[i]!=-1){
+ if(!exists_edge(v,ng->m->v[ng->vnum[i]]))
+ nl->vnum[count++]=ng->vnum[i];
+ else
+ ng->vnum[i]=-1;
+ }
+ }
+ nl->num=count;
+}
+
+static void random_populate(int current, mesh *m, int min_connect, float prob){
+ int num_edges=0,i;
+ neighbors_grid ng;
+ neighbors_list nl;
+ populate_neighbors(current, m, &ng);
+ filter_intersections(&ng);
+ filter_edges(&ng,&nl);
+
+ {
+ edge_list *el=m->v[current]->edges;
+ while(el){
+ num_edges++;
+ el=el->next;
+ }
+ }
+
+ while(num_edges<min_connect && nl.num){
+ int choice = random() % nl.num;
+ add_edge(m->v[current], m->v[nl.vnum[choice]]);
+ num_edges++;
+ filter_intersections(&ng);
+ filter_edges(&ng,&nl);
+ }
+
+ for(i=0;i<nl.num;i++)
+ if(random()<RAND_MAX*prob){
+ num_edges++;
+ add_edge(m->v[current], m->v[nl.vnum[i]]);
+ }
+}
+
+static void span_depth_first(int current, mesh *m){
+ neighbors_grid ng;
+ neighbors_list nl;
+
+ while(1){
+ populate_neighbors(current, m, &ng);
+ // don't reverse the order of the next two
+ filter_intersections(&ng);
+ filter_spanned_neighbors(&ng,&nl);
+ if(nl.num == 0) break;
+
+ {
+ int choice = random() % nl.num;
+ add_edge(m->v[current], m->v[nl.vnum[choice]]);
+
+ span_depth_first(nl.vnum[choice], m);
+ }
+ }
+}
+
+void generate_mesh_1(int order){
+ int flag=0;
+ mesh m;
+ m.width=3;
+ m.height=2;
+ vertex *vlist;
+
+ {
+ while(order--){
+ if(flag){
+ flag=0;
+ m.width+=2;
+ }else{
+ flag=1;
+ m.height+=1;
+ }
+ }
+ }
+
+ vlist=new_board(m.width * m.height);
+
+ /* a flat vector is easier to address while building the mesh */
+ {
+ int i;
+ vertex *v=vlist;
+ m.v=alloca(m.width*m.height * sizeof(*m.v));
+ for(i=0;i<m.width*m.height;i++){
+ m.v[i]=v;
+ v=v->next;
+ }
+ }
+
+ /* first walk a random spanning tree */
+ span_depth_first(0, &m);
+
+ /* now iterate the whole mesh adding random edges */
+ {
+ int i;
+ for(i=0;i<m.width*m.height;i++)
+ random_populate(i, &m, 2, .25);
+ }
+
+ randomize_verticies(vlist);
+ arrange_verticies_circle(m.width*m.height);
+
+ //arrange_verticies_mesh(m.width,m.height);
+}
+
Added: trunk/planarity/generate.h
===================================================================
--- trunk/planarity/generate.h 2005-07-26 23:19:44 UTC (rev 9630)
+++ trunk/planarity/generate.h 2005-07-28 03:59:23 UTC (rev 9631)
@@ -0,0 +1 @@
+extern void generate_mesh_1(int order);
Added: trunk/planarity/graph.c
===================================================================
--- trunk/planarity/graph.c 2005-07-26 23:19:44 UTC (rev 9630)
+++ trunk/planarity/graph.c 2005-07-28 03:59:23 UTC (rev 9631)
@@ -0,0 +1,704 @@
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "graph.h"
+#include "gameboard.h"
+#define CHUNK 64
+
+/* mesh/board state */
+static vertex *verticies=0;
+static vertex *vertex_pool=0;
+static edge *edges=0;
+static edge *edge_pool=0;
+static edge_list *edge_list_pool=0;
+static intersection *intersection_pool=0;
+
+static int active_intersections=0;
+static int reported_intersections=0;
+
+static int num_edges=0;
+static int num_edges_active=0;
+
+
+/************************ edge list maint operations ********************/
+static void add_edge_to_list(vertex *v, edge *e){
+ edge_list *ret;
+
+ if(edge_list_pool==0){
+ int i;
+ edge_list_pool = calloc(CHUNK,sizeof(*edge_list_pool));
+ for(i=0;i<CHUNK-1;i++) /* last addition's next points to nothing */
+ edge_list_pool[i].next=edge_list_pool+i+1;
+ }
+
+ ret=edge_list_pool;
+ edge_list_pool=ret->next;
+
+ ret->edge=e;
+ ret->next=v->edges;
+ v->edges=ret;
+}
+
+static void release_edge_list(vertex *v){
+ edge_list *el=v->edges;
+
+ if(el){
+ edge_list *end=el;
+ while(end->next)end=end->next;
+
+ end->next = edge_list_pool;
+ edge_list_pool = el;
+
+ v->edges=0;
+ }
+}
+
+/************************ intersection maint operations ********************/
+
+static intersection *new_intersection(){
+ intersection *ret;
+
+ if(intersection_pool==0){
+ int i;
+ intersection_pool = calloc(CHUNK,sizeof(*intersection_pool));
+ for(i=0;i<CHUNK-1;i++) /* last addition's next points to nothing */
+ intersection_pool[i].next=intersection_pool+i+1;
+ }
+
+ ret=intersection_pool;
+ intersection_pool=ret->next;
+ return ret;
+}
+
+static void add_paired_intersection(edge *a, edge *b, double x, double y){
+ intersection *A=new_intersection();
+ intersection *B=new_intersection();
+
+ A->paired=B;
+ B->paired=A;
+
+ A->next=a->i.next;
+ if(A->next)
+ A->next->prev=A;
+ A->prev=&(a->i);
+ a->i.next=A;
+
+ B->next=b->i.next;
+ if(B->next)
+ B->next->prev=B;
+ B->prev=&(b->i);
+ b->i.next=B;
+
+ A->x=B->x=x;
+ A->y=B->y=y;
+}
+
+static void release_intersection(intersection *i){
+ memset(i,0,sizeof(*i));
+ i->next=intersection_pool;
+ intersection_pool=i;
+}
+
+static void release_intersection_list(edge *e){
+ intersection *i=e->i.next;
+
+ while(i!=0){
+ intersection *next=i->next;
+ release_intersection(i);
+ i=next;
+ }
+ e->i.next=0;
+}
+
+static int release_paired_intersection_list(edge *e){
+ intersection *i=e->i.next;
+ int count=0;
+
+ while(i){
+ intersection *next=i->next;
+ intersection *j=i->paired;
+
+ j->prev->next=j->next;
+ if(j->next)
+ j->next->prev=j->prev;
+
+ release_intersection(i);
+ release_intersection(j);
+ i=next;
+ count++;
+ }
+ e->i.next=0;
+ return count;
+}
+
+/************************ edge maint operations ******************************/
+/* also adds to the edge list */
+edge *add_edge(vertex *A, vertex *B){
+ edge *ret;
+
+ if(edge_pool==0){
+ int i;
+ edge_pool = calloc(CHUNK,sizeof(*edge_pool));
+ for(i=0;i<CHUNK-1;i++) /* last addition's next points to nothing */
+ edge_pool[i].next=edge_pool+i+1;
+ }
+
+ ret=edge_pool;
+ edge_pool=ret->next;
+
+ ret->A=A;
+ ret->B=B;
+ ret->active=0;
+ ret->foreground=0;
+ ret->i.next=0;
+ ret->next=edges;
+ edges=ret;
+
+ add_edge_to_list(A,ret);
+ add_edge_to_list(B,ret);
+
+ num_edges++;
+
+ return ret;
+}
+
+static void release_edges(){
+ edge *e = edges;
+
+ while(e){
+ edge *next=e->next;
+ release_intersection_list(e);
+ e->next=edge_pool;
+ edge_pool=e;
+ e=next;
+ }
+ edges=0;
+ num_edges=0;
+ num_edges_active=0;
+}
+
+static int intersects(vertex *L1, vertex *L2, vertex *M1, vertex *M2, double *xo, double *yo){
+ /* y = ax + b */
+ float La=0;
+ float Lb=0;
+ float Ma=0;
+ float Mb=0;
+
+ // but first, edges that share a vertex don't intersect by definition
+ if(L1==M1) return 0;
+ if(L1==M2) return 0;
+ if(L2==M1) return 0;
+ if(L2==M2) return 0;
+
+ if(L1->x != L2->x){
+ La = (float)(L2->y - L1->y) / (L2->x - L1->x);
+ Lb = (L1->y - L1->x * La);
+ }
+
+ if(M1->x != M2->x){
+ Ma = (float)(M2->y - M1->y) / (M2->x - M1->x);
+ Mb = (M1->y - M1->x * Ma);
+ }
+
+ if(L1->x == L2->x){
+ // L is vertical line
+
+ if(M1->x == M2->x){
+ // M is also a vertical line
+
+ if(L1->x == M1->x){
+ // L and M vertical on same x, overlap?
+ if(M1->y > L1->y &&
+ M1->y > L2->y &&
+ M2->y > L1->y &&
+ M2->y > L2->y) return 0;
+ if(M1->y < L1->y &&
+ M1->y < L2->y &&
+ M2->y < L1->y &&
+ M2->y < L2->y) return 0;
+
+ {
+ double y1=max( min(M1->y,M2->y), min(L1->y, L2->y));
+ double y2=min( max(M1->y,M2->y), max(L1->y, L2->y));
+
+ *xo = M1->x;
+ *yo = (y1+y2)*.5;
+
+ }
+
+ }else
+ // L and M vertical, different x
+ return 0;
+
+ }else{
+ // L vertical, M not vertical
+ float y = Ma*L1->x + Mb;
+
+ if(y < L1->y && y < L2->y) return 0;
+ if(y > L1->y && y > L2->y) return 0;
+ if(y < M1->y && y < M2->y) return 0;
+ if(y > M1->y && y > M2->y) return 0;
+
+ *xo = L1->x;
+ *yo=y;
+
+ }
+ }else{
+
+ if(M1->x == M2->x){
+ // M vertical, L not vertical
+ float y = La*M1->x + Lb;
+
+ if(y < L1->y && y < L2->y) return 0;
+ if(y > L1->y && y > L2->y) return 0;
+ if(y < M1->y && y < M2->y) return 0;
+ if(y > M1->y && y > M2->y) return 0;
+
+ *xo = M1->x;
+ *yo=y;
+
+ }else{
+
+ // L and M both have non-infinite slope
+ if(La == Ma){
+ //L and M have the same slope
+ if(Mb != Lb) return 0;
+
+ // two segments on same line...
+ if(M1->x > L1->x &&
+ M1->x > L2->x &&
+ M2->x > L1->x &&
+ M2->x > L2->x) return 0;
+ if(M1->x < L1->x &&
+ M1->x < L2->x &&
+ M2->x < L1->x &&
+ M2->x < L2->x) return 0;
+
+ {
+ double x1=max( min(M1->x,M2->x), min(L1->x, L2->x));
+ double x2=min( max(M1->x,M2->x), max(L1->x, L2->x));
+ double y1=max( min(M1->y,M2->y), min(L1->y, L2->y));
+ double y2=min( max(M1->y,M2->y), max(L1->y, L2->y));
+
+ *xo = (x1+x2)*.5;
+ *yo = (y1+y2)*.5;
+
+ }
+
+
+ }else{
+ // finally typical case: L and M have different non-infinite slopes
+ float x = (Mb-Lb) / (La - Ma);
+
+ if(x < L1->x && x < L2->x) return 0;
+ if(x > L1->x && x > L2->x) return 0;
+ if(x < M1->x && x < M2->x) return 0;
+ if(x > M1->x && x > M2->x) return 0;
+
+ *xo = x;
+ *yo = La*x + Lb;
+ }
+ }
+ }
+
+ return 1;
+}
+
+static void activate_edge(edge *e){
+ /* computes all intersections */
+ if(!e->active && e->A->active && e->B->active){
+ edge *test=edges;
+ while(test){
+ if(test != e && test->active){
+ double x,y;
+ if(intersects(e->A,e->B,test->A,test->B,&x,&y)){
+ add_paired_intersection(e,test,x,y);
+ active_intersections++;
+
+ }
+ }
+ test=test->next;
+ }
+ e->active=1;
+ num_edges_active++;
+ if(num_edges_active == num_edges)
+ reported_intersections = active_intersections;
+ }
+}
+
+static void deactivate_edge(edge *e){
+ /* releases all associated intersections */
+ if(e->active){
+ active_intersections -=
+ release_paired_intersection_list(e);
+ num_edges_active--;
+ e->active=0;
+ }
+}
+
+int exists_edge(vertex *a, vertex *b){
+ edge_list *el=a->edges;
+ while(el){
+ if(el->edge->A == b) return 1;
+ if(el->edge->B == b) return 1;
+ el=el->next;
+ }
+ return 0;
+}
+
+/*********************** vertex maint operations *************************/
+static vertex *get_vertex(){
+ vertex *ret;
+
+ if(vertex_pool==0){
+ int i;
+ vertex_pool = calloc(CHUNK,sizeof(*vertex_pool));
+ for(i=0;i<CHUNK-1;i++) /* last addition's next points to nothing */
+ vertex_pool[i].next=vertex_pool+i+1;
+ }
+
+ ret=vertex_pool;
+ vertex_pool=ret->next;
+
+ ret->x=0;
+ ret->y=0;
+ ret->active=0;
+ ret->selected=0;
+ ret->selected_volatile=0;
+ ret->grabbed=0;
+ ret->attached_to_grabbed=0;
+ ret->edges=0;
+ ret->next=0;
+ return ret;
+}
+
+static void release_vertex(vertex *v){
+ release_edge_list(v);
+ v->next=vertex_pool;
+ vertex_pool=v;
+}
+
+static void set_num_verticies(int num){
+ /* do it the simple way; release all, link anew */
+ vertex *v=verticies;
+
+ while(v){
+ vertex *next=v->next;
+ release_vertex(v);
+ v=next;
+ }
+ verticies=0;
+ release_edges();
+
+ while(num--){
+ v=get_vertex();
+ v->next=verticies;
+ verticies=v;
+ }
+}
+
+void activate_vertex(vertex *v){
+ edge_list *el=v->edges;
+ v->active=1;
+ while(el){
+ activate_edge(el->edge);
+ el=el->next;
+ }
+}
+
+void deactivate_vertex(vertex *v){
+ edge_list *el=v->edges;
+ while(el){
+ edge_list *next=el->next;
+ deactivate_edge(el->edge);
+ el=next;
+ }
+ v->active=0;
+}
+
+void grab_vertex(vertex *v){
+ edge_list *el=v->edges;
+ deactivate_vertex(v);
+ while(el){
+ edge_list *next=el->next;
+ edge *e=el->edge;
+ vertex *other=(e->A==v?e->B:e->A);
+ other->attached_to_grabbed=1;
+ el=next;
+ }
+ v->grabbed=1;
+}
+
+void ungrab_vertex(vertex *v){
+ edge_list *el=v->edges;
+ activate_vertex(v);
+ while(el){
+ edge_list *next=el->next;
+ edge *e=el->edge;
+ vertex *other=(e->A==v?e->B:e->A);
+ other->attached_to_grabbed=0;
+ el=next;
+ }
+ v->grabbed=0;
+}
+
+vertex *find_vertex(int x, int y){
+ vertex *v = verticies;
+ vertex *match = 0;
+
+ while(v){
+ vertex *next=v->next;
+ int xd=x-v->x;
+ int yd=y-v->y;
+ if(xd*xd + yd*yd <= V_RADIUS_SQ) match=v;
+ v=next;
+ }
+
+ return match;
+}
+
+static void check_vertex_helper(vertex *v, int reactivate){
+ int flag=0;
+
+ if(v->x>=get_board_width()){
+ v->x=get_board_width()-1;
+ flag=1;
+ }
+ if(v->x<0){
+ v->x=0;
+ flag=1;
+ }
+ if(v->y>=get_board_height()){
+ v->y=get_board_height()-1;
+ flag=0;
+ }
+ if(v->y<0){
+ v->y=0;
+ flag=1;
+ }
+ if(flag){
+ if(v->edges){
+ deactivate_vertex(v);
+ if(reactivate)activate_vertex(v);
+ }
+ }
+}
+
+static void check_vertex(vertex *v){
+ check_vertex_helper(v,1);
+}
+
+void check_verticies(){
+ vertex *v=verticies;
+ while(v){
+ vertex *next=v->next;
+ check_vertex_helper(v,0);
+ v=next;
+ }
+
+ v=verticies;
+ while(v){
+ vertex *next=v->next;
+ activate_vertex(v);
+ v=next;
+ }
+}
+
+void move_vertex(vertex *v, int x, int y){
+ if(!v->grabbed) deactivate_vertex(v);
+ v->x=x;
+ v->y=y;
+ check_vertex_helper(v,0);
+ if(!v->grabbed) activate_vertex(v);
+}
+
+// tenative selection; must be confirmed if next call should not clear
+void select_verticies(int x1, int y1, int x2, int y2){
+ vertex *v = verticies;
+
+ if(x1>x2){
+ int temp=x1;
+ x1=x2;
+ x2=temp;
+ }
+
+ if(y1>y2){
+ int temp=y1;
+ y1=y2;
+ y2=temp;
+ }
+ x1-=V_RADIUS;
+ x2+=V_RADIUS;
+ y1-=V_RADIUS;
+ y2+=V_RADIUS;
+
+ while(v){
+ vertex *next=v->next;
+ if(v->selected_volatile)v->selected=0;
+
+ if(!v->selected){
+ if(v->x>=x1 && v->x<=x2 && v->y>=y1 && v->y<=y2){
+ v->selected=1;
+ v->selected_volatile=1;
+ }
+ }
+
+ v=next;
+ }
+}
+
+int num_selected_verticies(){
+ vertex *v = verticies;
+ int count=0;
+ while(v){
+ if(v->selected)count++;
+ v=v->next;
+ }
+ return count;
+}
+
+void deselect_verticies(){
+ vertex *v = verticies;
+
+ while(v){
+ v->selected=0;
+ v->selected_volatile=0;
+ v=v->next;
+ }
+
+}
+
+void commit_volatile_selection(){
+ vertex *v = verticies;
+
+ while(v){
+ v->selected_volatile=0;
+ v=v->next;
+ }
+}
+
+void move_selected_verticies(int dx, int dy){
+ vertex *v = verticies;
+ /* deactivate selected verticies */
+ while(v){
+ vertex *next=v->next;
+ if(v->selected)
+ deactivate_vertex(v);
+ v=next;
+ }
+
+ /* move selected verticies and reactivate */
+ v=verticies;
+ while(v){
+ vertex *next=v->next;
+ if(v->selected){
+ v->x+=dx;
+ v->y+=dy;
+ check_vertex(v);
+ activate_vertex(v);
+ }
+ v=next;
+ }
+
+}
+
+void scale_verticies(float amount){
+ vertex *v=verticies;
+ int x=get_board_width()/2;
+ int y=get_board_height()/2;
+
+ while(v){
+ vertex *next=v->next;
+ deactivate_vertex(v);
+ v->x=rint((v->x-x)*amount)+x;
+ v->y=rint((v->y-y)*amount)+y;
+ v=next;
+ }
+
+ v=verticies;
+ while(v){
+ vertex *next=v->next;
+ check_vertex(v);
+ activate_vertex(v);
+ v=next;
+ }
+}
+
+static vertex *split_vertex_list(vertex *v){
+ vertex *half=v;
+ vertex *prevhalf=v;
+
+ while(v){
+ v=v->next;
+ if(v)v=v->next;
+ prevhalf=half;
+ half=half->next;
+ }
+
+ prevhalf->next=0;
+ return half;
+}
+
+static vertex *randomize_helper(vertex *v){
+ vertex *w=split_vertex_list(v);
+ if(w){
+ vertex *a = randomize_helper(v);
+ vertex *b = randomize_helper(w);
+ v=0;
+ w=0;
+
+ while(a && b){
+ if(random()&1){
+ // pull off head of a
+ if(w)
+ w=w->next=a;
+ else
+ v=w=a;
+ a=a->next;
+ }else{
+ // pull off head of b
+ if(w)
+ w=w->next=b;
+ else
+ v=w=b;
+ b=b->next;
+ }
+ }
+ if(a)
+ w->next=a;
+ if(b)
+ w->next=b;
+ }
+ return v;
+}
+
+void randomize_verticies(){
+ verticies=randomize_helper(verticies);
+}
+
+int get_num_intersections(){
+ return reported_intersections;
+}
+
+vertex *get_verticies(){
+ return verticies;
+}
+
+edge *get_edges(){
+ return edges;
+}
+
+vertex *new_board(int num_v){
+ set_num_verticies(num_v);
+ return verticies;
+}
+
+void impress_location(){
+ vertex *v=verticies;
+ while(v){
+ v->orig_x=v->x;
+ v->orig_y=v->y;
+ v=v->next;
+ }
+}
Added: trunk/planarity/graph.h
===================================================================
--- trunk/planarity/graph.h 2005-07-26 23:19:44 UTC (rev 9630)
+++ trunk/planarity/graph.h 2005-07-28 03:59:23 UTC (rev 9631)
@@ -0,0 +1,71 @@
+/* graph abstraction */
+
+#define V_RADIUS_SQ (V_RADIUS*V_RADIUS)
+#define min(a,b) ((a)<(b)?(a):(b))
+#define max(a,b) ((a)>(b)?(a):(b))
+
+
+typedef struct vertex {
+ int x;
+ int y;
+ int orig_x;
+ int orig_y;
+
+ int active;
+ int selected_volatile;
+ int selected;
+ int grabbed;
+ int attached_to_grabbed;
+ struct edge_list *edges;
+ struct vertex *next;
+} vertex;
+
+typedef struct intersection {
+ struct intersection *prev;
+ struct intersection *next;
+ struct intersection *paired;
+ double x;
+ double y;
+} intersection;
+
+typedef struct edge{
+ vertex *A;
+ vertex *B;
+
+ int active;
+ int foreground;
+
+ intersection i; // correct, not a pointer
+ struct edge *next;
+} edge;
+
+typedef struct edge_list{
+ edge *edge;
+ struct edge_list *next;
+} edge_list;
+
+extern void resize_board(int x, int y);
+extern vertex *new_board(int num_v);
+extern vertex *find_vertex(int x, int y);
+extern void move_vertex(vertex *v, int x, int y);
+extern void grab_vertex(vertex *v);
+extern void ungrab_vertex(vertex *v);
+extern void activate_vertex(vertex *v);
+extern void deactivate_vertex(vertex *v);
+extern void select_verticies(int x1, int y1, int x2, int y2);
+extern void deselect_verticies();
+extern void move_selected_verticies(int dx, int dy);
+extern void scale_verticies(float amount);
+extern void randomize_verticies();
+extern edge *add_edge(vertex *A, vertex *B);
+extern int exists_edge(vertex *a, vertex *b);
+extern int get_board_width();
+extern int get_board_height();
+extern vertex *get_verticies();
+extern edge *get_edges();
+extern int num_selected_verticies();
+extern int get_num_intersections();
+extern int get_max_intersections();
+extern void check_verticies();
+extern void impress_location();
+extern void commit_volatile_selection();
Added: trunk/planarity/touch-version
===================================================================
--- trunk/planarity/touch-version 2005-07-26 23:19:44 UTC (rev 9630)
+++ trunk/planarity/touch-version 2005-07-28 03:59:23 UTC (rev 9631)
@@ -0,0 +1,21 @@
+#!/usr/bin/perl
+
+if(open F,"version.h"){
+ $line=<F>;
+ close F;
+
+ if(open F,">version.h"){
+
+ print F "$line";
+ chomp($line=`date`);
+ print F "/* DO NOT EDIT: Automated versioning hack [$line] */\n";
+ close F;
+ 0;
+ }else{
+ print "touch-version: Failed to write new version.h\n";
+ 1;
+ }
+}else{
+ print "touch-version: Failed to open version.h\n";
+ 1;
+}
Property changes on: trunk/planarity/touch-version
___________________________________________________________________
Name: svn:executable
+
Added: trunk/planarity/version.h
===================================================================
--- trunk/planarity/version.h 2005-07-26 23:19:44 UTC (rev 9630)
+++ trunk/planarity/version.h 2005-07-28 03:59:23 UTC (rev 9631)
@@ -0,0 +1,2 @@
+/* DO NOT EDIT: Automated versioning hack [Thu Jul 21 05:46:15 EDT 2005] */
+/* DO NOT EDIT: Automated versioning hack [Wed Jul 27 23:28:33 EDT 2005] */
More information about the commits
mailing list