Recognizes if input is ogg or not.
[xiph.git] / planarity / gameboard_logic_mouse.c
blobfe27971b40b4b07bbf4e149446c20381e2faf11f
1 /*
3 * gPlanarity:
4 * The geeky little puzzle game with a big noodly crunch!
5 *
6 * gPlanarity copyright (C) 2005 Monty <monty@xiph.org>
7 * Original Flash game by John Tantalo <john.tantalo@case.edu>
8 * Original game concept by Mary Radcliffe
10 * gPlanarity is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
13 * any later version.
15 * gPlanarity is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with Postfish; see the file COPYING. If not, write to the
22 * Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
27 #define _GNU_SOURCE
28 #include <gtk/gtk.h>
29 #include <gtk/gtkmain.h>
30 #include <gdk/gdk.h>
31 #include <gdk/gdkx.h>
32 #include <stdlib.h>
33 #include <math.h>
34 #include <stdio.h>
35 #include <string.h>
37 #include "graph.h"
38 #include "gameboard.h"
39 #include "dialog_level.h"
41 /* does the given x/y fall inside an on-screen vertex? */
42 static void check_lit(Gameboard *g,int x, int y){
43 vertex *v = find_vertex(&g->g,x,y);
44 if(v!=g->lit_vertex){
45 invalidate_vertex(g,v);
46 invalidate_vertex(g,g->lit_vertex);
47 g->lit_vertex = v;
51 /* toplevel mouse motion handler */
52 gint mouse_motion(GtkWidget *widget,
53 GdkEventMotion *event){
54 Gameboard *g = GAMEBOARD (widget);
56 /* the level selection dialog implements its own icon mouse management */
57 if(g->level_dialog_active)
58 level_mouse_motion(g,(int)event->x,(int)event->y);
60 /* similarly, if a vertex is grabbed, the only thing that can
61 happen is that we're dragging that vertex */
63 if(g->grabbed_vertex){
64 int x = (int)event->x;
65 int y = (int)event->y;
66 g->dragx = x-g->grabx;
67 g->dragy = y-g->graby;
69 invalidate_vertex(g,g->grabbed_vertex);
70 invalidate_edges(widget,g->grabbed_vertex,0,0);
71 move_vertex(&g->g,g->grabbed_vertex,x+g->graboffx,y+g->graboffy);
72 invalidate_vertex(g,g->grabbed_vertex);
73 invalidate_edges(widget,g->grabbed_vertex,0,0);
74 return TRUE;
78 /* if the selection is grabbed, we can only be dragging a selection box */
79 if (g->selection_grab){
80 invalidate_selection(widget);
82 g->selectionx = min(g->grabx, event->x);
83 g->selectionw = labs(g->grabx - event->x);
84 g->selectiony = min(g->graby, event->y);
85 g->selectionh = labs(g->graby - event->y);
86 select_verticies(&g->g,
87 g->selectionx,g->selectiony,
88 g->selectionx+g->selectionw-1,
89 g->selectiony+g->selectionh-1);
91 invalidate_selection(widget);
92 return TRUE;
95 /* if a selected vertex is grabbed (group drag) we're dragging
96 the whole selection and its lines */
98 if(g->group_drag){
99 invalidate_verticies_selection(widget);
100 g->dragx = event->x - g->grabx;
101 g->dragy = event->y - g->graby;
103 /* don't allow the drag to put a vertex offscreen; bound the drag at the edge */
105 vertex *v=g->g.verticies;
106 int w=g->g.width;
107 int h=g->g.height;
109 while(v){
110 if(v->selected){
111 if(v->x + g->dragx >= w)
112 g->dragx=w - v->x -1;
113 if(v->x + g->dragx < 0 )
114 g->dragx= -v->x;
115 if(v->y + g->dragy >= h)
116 g->dragy=h - v->y -1;
117 if(v->y + g->dragy < 0 )
118 g->dragy= -v->y;
120 v=v->next;
124 invalidate_verticies_selection(widget);
125 return TRUE;
128 /* A vertex rollover has priority over a button rollover. However,
129 a button grab disallows a rollover, as does the curtain. */
130 if(!g->pushed_curtain && !g->button_grabbed)
131 check_lit(g, (int)event->x,(int)event->y);
133 /* handle button rollovers and ongoing grabs; other grabs are
134 already disallowed, but also verify a vertex rollover isn't
135 already active (and that buttons are currently hot) */
136 if(!g->lit_vertex && g->b.buttons_ready){
137 buttonstate *b = find_button(g,(int)event->x,(int)event->y);
139 if(g->b.grabbed){
140 /* a button is grabbed; a rollover sees only the grabbed
141 button */
142 if(g->b.grabbed==b)
143 button_set_state(g,b,1,1);
144 else
145 button_set_state(g,g->b.grabbed,0,0);
146 }else{
147 /* no button is grabbed; any button may see a rollover */
148 if(b)
149 button_set_state(g,b,1,0);
150 else
151 button_clear_state(g);
155 return TRUE;
158 /* toplevel mouse button press handler */
159 gboolean mouse_press (GtkWidget *widget,
160 GdkEventButton *event){
162 if(event->type == GDK_BUTTON_PRESS){ // filter out doubleclicks
164 Gameboard *g = GAMEBOARD (widget);
166 vertex *v = find_vertex(&g->g,(int)event->x,(int)event->y);
167 buttonstate *b = find_button(g,(int)event->x,(int)event->y);
168 int old_intersections = g->show_intersections;
170 /* the level selection dialog implements its own icon mouse management */
171 if(g->level_dialog_active)
172 level_mouse_press(g,(int)event->x,(int)event->y);
174 button_clear_state(g);
175 g->button_grabbed=0;
176 set_show_intersections(g,0);
178 /* presses that affect board elements other than buttons can only
179 happen when the curtain isn't pushed. */
180 if(!g->pushed_curtain){
182 /* case: shift-click addition of a single new vertex to selection */
183 if(v && event->state&GDK_SHIFT_MASK){
184 if(v->selected){
185 v->selected=0;
186 g->selection_active--;
187 }else{
188 v->selected=1;
189 g->selection_active++;
191 invalidate_vertex(g,g->lit_vertex);
192 return TRUE;
195 /* case: shift-click drag of an additional region to add to selection */
196 if(event->state&GDK_SHIFT_MASK){
197 g->selection_grab=1;
198 g->grabx = (int)event->x;
199 g->graby = (int)event->y;
200 g->selectionx = g->grabx;
201 g->selectionw = 0;
202 g->selectiony = g->graby;
203 g->selectionh = 0;
204 return TRUE;
207 /* case: drag the selected group of verticies to new location */
208 if(g->selection_active && v && v->selected){
209 g->group_drag=1;
210 g->grabx = (int)event->x;
211 g->graby = (int)event->y;
212 g->dragx = 0;
213 g->dragy = 0;
214 // highlight vertex immediately; update the background after the
215 // vertex change
216 grab_selected(&g->g);
217 invalidate_verticies_selection(widget);
218 fade_cancel(g);
219 update_full_delayed(g);
220 return TRUE;
223 /* if selection is active, we got this far, and we're not about to
224 take action based on pointing at a button, selection should be
225 inactivated */
226 if(g->selection_active && (g->lit_vertex || !b)){
227 deselect_verticies(&g->g);
228 g->selection_active=0;
229 g->group_drag=0;
230 // potentially pull verticies out of background (can happen if
231 // mouse went offscreen during a grab)
232 update_full(g);
235 /* case: grab/drag a single unselected vertex */
236 if(g->lit_vertex){
237 g->grabbed_vertex = g->lit_vertex;
238 g->grabx = (int)event->x;
239 g->graby = (int)event->y;
240 g->graboffx = g->grabbed_vertex->x-g->grabx;
241 g->graboffy = g->grabbed_vertex->y-g->graby;
243 grab_vertex(&g->g,g->grabbed_vertex);
244 invalidate_attached(widget,g->grabbed_vertex);
245 invalidate_edges(widget,g->grabbed_vertex,0,0);
246 fade_cancel(g);
247 // highlight vertex immediately; update the background after the
248 // vertex change
249 update_full_delayed(g);
250 return TRUE;
254 /* case: button click */
255 if(b){
256 // if intersections were visible, a button press is the only
257 // click that wouldn't auto-hide them, so restore the flag to
258 // its state before entry.
259 g->show_intersections=old_intersections;
261 button_set_state(g,b,1,1);
262 g->b.grabbed = b;
263 return TRUE;
266 /* clicking anywhere else wtith no modifiers initiates a new
267 selection drag (assuming curtain isn't pushed) */
268 if(!g->pushed_curtain){
269 g->selection_grab=1;
270 g->grabx = (int)event->x;
271 g->graby = (int)event->y;
272 g->selectionx = g->grabx;
273 g->selectionw = 0;
274 g->selectiony = g->graby;
275 g->selectionh = 0;
276 return TRUE;
280 return TRUE;
283 /* toplevel mouse button release handler */
284 gboolean mouse_release (GtkWidget *widget,
285 GdkEventButton *event){
286 Gameboard *g = GAMEBOARD (widget);
288 /* case: button grabbed */
289 if(g->b.grabbed){
290 buttonstate *b = find_button(g,(int)event->x,(int)event->y);
291 if(b && g->b.grabbed==b){
292 button_set_state(g,b,1,0);
293 if(b->callback)
294 b->callback(g);
296 g->b.grabbed=0;
299 /* if the curtain is pushed, no sense checking for other grabs */
300 if(!g->pushed_curtain){
302 /* case: release a grabbed vertex */
303 if(g->grabbed_vertex){
304 ungrab_vertex(&g->g,g->grabbed_vertex);
305 update_add_vertex(g,g->grabbed_vertex);
306 fade_attached(g,g->grabbed_vertex);
307 update_score(g);
308 g->grabbed_vertex = 0;
310 if(g->g.active_intersections<=g->g.objective)
311 deploy_check(g);
312 else
313 undeploy_check(g);
317 /* case: release a selection grab */
318 if(g->selection_grab){
319 invalidate_selection(widget);
320 g->selection_grab=0;
322 /* are there selected verticies? If only one was selected, that's
323 usually due to an accidental drag while clicking. Treat a
324 single-vertex drag select as a nil selection */
325 if(num_selected_verticies(&g->g)<=1){
326 g->selection_active=0;
327 deselect_verticies(&g->g); // could have grabbed just one
328 }else{
329 commit_volatile_selection(&g->g);
330 g->selection_active=num_selected_verticies(&g->g);
334 /* case: release a group drag */
335 if(g->group_drag){
336 move_selected_verticies(&g->g,g->dragx,g->dragy);
337 fade_grabbed(g);
338 update_add_selgroup(g);
339 ungrab_verticies(&g->g);
340 update_score(g);
342 g->group_drag=0;
344 if(g->g.active_intersections<=g->g.objective)
345 deploy_check(g);
346 else
347 undeploy_check(g);
351 /* a release may result in a new mouse-over; look for it */
352 mouse_motion(widget,(GdkEventMotion *)event); // the cast is safe in this case
354 return TRUE;