summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael R Sweet <michael.r.sweet@gmail.com>2005-11-25 20:40:16 +0000
committerMichael R Sweet <michael.r.sweet@gmail.com>2005-11-25 20:40:16 +0000
commit9e8a88e66cb9e7739542d61e09c803cecc7e6248 (patch)
tree77e793b1f28568c3fc8b8b2cd146f34c66cd89d8
parentfe286dfe7b0ae6827942d40586906431c1d97287 (diff)
Fix mousewheel handler bug (using wrong variable in initial check)
Add sudoku game app (fun for the holidays! :) Use "-Os -g" as the default optimization settings. git-svn-id: file:///fltk/svn/fltk/branches/branch-1.1@4652 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
-rw-r--r--configure.in4
-rw-r--r--src/Fl_mac.cxx2
-rw-r--r--test/Makefile7
-rw-r--r--test/sudoku.app/Contents/Info.plist44
-rw-r--r--test/sudoku.app/Contents/PkgInfo1
-rw-r--r--test/sudoku.app/Contents/Resources/sudoku.icnsbin0 -> 31835 bytes
-rw-r--r--test/sudoku.cxx555
-rw-r--r--test/sudoku.pngbin0 -> 6514 bytes
8 files changed, 610 insertions, 3 deletions
diff --git a/configure.in b/configure.in
index 40d8cea65..8551512e6 100644
--- a/configure.in
+++ b/configure.in
@@ -760,7 +760,7 @@ if test -n "$GCC"; then
# They all seem to make either no difference or enlarge
# the code by a few hundred bytes.
#
- # "-O2" seems to be the best compromise between speed and
+ # "-Os" seems to be the best compromise between speed and
# code size. "-O3" and higher seem to make no effective
# difference in the speed of the code, but does bloat the
# library 10+%.
@@ -769,7 +769,7 @@ if test -n "$GCC"; then
if test "x$with_optim" != x; then
OPTIM="$with_optim $OPTIM"
else
- OPTIM="-O2 $OPTIM"
+ OPTIM="-Os -g $OPTIM"
fi
fi
diff --git a/src/Fl_mac.cxx b/src/Fl_mac.cxx
index ddf23e1e0..a8f13cb34 100644
--- a/src/Fl_mac.cxx
+++ b/src/Fl_mac.cxx
@@ -799,7 +799,7 @@ static pascal OSStatus carbonMousewheelHandler( EventHandlerCallRef nextHandler,
// to me why Apple changed the API on this even though the current API
// supports two wheels just fine. Matthias,
EventRef event;
- if (GetEventKind(event)==11) {
+ if (GetEventKind(ev)==11) {
// if this is a "MightyMouse" event, we need to convert it into a regular
// MouseWheel event
GetEventParameter( ev, kEventParamEventRef, typeEventRef, NULL, sizeof( EventRef ), NULL, &event );
diff --git a/test/Makefile b/test/Makefile
index 2886ed15e..e31c8d45a 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -85,6 +85,7 @@ CPPFILES =\
scroll.cxx \
shape.cxx \
subwindow.cxx \
+ sudoku.cxx \
symbols.cxx \
tabs.cxx \
threads.cxx \
@@ -142,6 +143,7 @@ ALL = \
resizebox$(EXEEXT) \
scroll$(EXEEXT) \
subwindow$(EXEEXT) \
+ sudoku$(EXEEXT) \
symbols$(EXEEXT) \
tabs$(EXEEXT) \
$(THREADS) \
@@ -331,6 +333,11 @@ scroll$(EXEEXT): scroll.o
subwindow$(EXEEXT): subwindow.o
+sudoku$(EXEEXT): sudoku.o
+ echo Linking $@...
+ $(CXX) -I.. $(CXXFLAGS) sudoku.o -o $@ $(LINKFLTK) $(LDLIBS)
+ $(CP) sudoku$(EXEEXT) sudoku.app/Contents/MacOS
+
symbols$(EXEEXT): symbols.o
tabs$(EXEEXT): tabs.o
diff --git a/test/sudoku.app/Contents/Info.plist b/test/sudoku.app/Contents/Info.plist
new file mode 100644
index 000000000..55e42690a
--- /dev/null
+++ b/test/sudoku.app/Contents/Info.plist
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<plist version="0.9">
+ <dict>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+
+ <key>CFBundleExecutable</key>
+ <string>sudoku</string>
+
+ <key>CFBundleIdentifier</key>
+ <string>org.fltk.sudoku</string>
+
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+
+ <key>NSHumanReadableCopyright</key>
+ <string>Copyright 2005 by Michael Sweet</string>
+
+ <key>CFAppleHelpAnchor</key>
+ <string>help</string>
+
+ <key>CFBundleName</key>
+ <string>sudoku</string>
+
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+
+ <key>CFBundleSignature</key>
+ <string>FLSU</string>
+
+ <key>CFBundleIconFile</key>
+ <string>sudoku.icns</string>
+
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+
+ <key>CFBundleGetInfoString</key>
+ <string>1.0, Copyright 2005 by Michael Sweet</string>
+
+ </dict>
+</plist>
diff --git a/test/sudoku.app/Contents/PkgInfo b/test/sudoku.app/Contents/PkgInfo
new file mode 100644
index 000000000..5af7226a1
--- /dev/null
+++ b/test/sudoku.app/Contents/PkgInfo
@@ -0,0 +1 @@
+FLSUFlsu
diff --git a/test/sudoku.app/Contents/Resources/sudoku.icns b/test/sudoku.app/Contents/Resources/sudoku.icns
new file mode 100644
index 000000000..a8a151ae4
--- /dev/null
+++ b/test/sudoku.app/Contents/Resources/sudoku.icns
Binary files differ
diff --git a/test/sudoku.cxx b/test/sudoku.cxx
new file mode 100644
index 000000000..1b9ac0c86
--- /dev/null
+++ b/test/sudoku.cxx
@@ -0,0 +1,555 @@
+//
+// "$Id$"
+//
+// Sudoku game using the Fast Light Tool Kit (FLTK).
+//
+// Copyright 2005 by Michael Sweet.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+// USA.
+//
+// Please report all bugs and problems on the following page:
+//
+// http://www.fltk.org/str.php
+//
+
+#include <FL/Fl.H>
+#include <FL/Enumerations.H>
+#include <FL/Fl_Window.H>
+#include <FL/Fl_Button.H>
+#include <FL/Fl_Group.H>
+#include <FL/fl_ask.H>
+#include <FL/fl_draw.H>
+#include <FL/Fl_Preferences.H>
+#include <FL/Fl_Sys_Menu_Bar.H>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+
+//
+// Default sizes...
+//
+
+#define GROUP_SIZE 160
+#define CELL_SIZE 50
+#define CELL_OFFSET 5
+#ifdef __APPLE__
+# define MENU_OFFSET 0
+#else
+# define MENU_OFFSET 25
+#endif // __APPLE__
+
+
+// Sudoku cell class...
+class SudokuCell : public Fl_Widget {
+ bool readonly_;
+ int value_;
+
+
+ public:
+
+ SudokuCell(int X, int Y, int W, int H);
+ void draw();
+ int handle(int event);
+ void readonly(bool r) { readonly_ = r; redraw(); }
+ bool readonly() const { return readonly_; }
+ void value(int v) { value_ = v; redraw(); }
+ int value() const { return value_; }
+};
+
+// Create a cell widget
+SudokuCell::SudokuCell(int X, int Y, int W, int H)
+ : Fl_Widget(X, Y, W, H, 0) {
+}
+
+
+// Draw cell
+void
+SudokuCell::draw() {
+ // Draw the cell box...
+ if (readonly()) fl_draw_box(FL_UP_BOX, x(), y(), w(), h(), color());
+ else fl_draw_box(FL_DOWN_BOX, x(), y(), w(), h(), color());
+
+ // Draw the cell background...
+ if (Fl::focus() == this) {
+ fl_color(FL_SELECTION_COLOR);
+ fl_rectf(x() + 4, y() + 4, w() - 8, h() - 8);
+ fl_color(fl_contrast(labelcolor(), FL_SELECTION_COLOR));
+ } else fl_color(labelcolor());
+
+ // Draw the cell value...
+ if (value_) {
+ char s[2];
+
+ s[0] = value_ + '0';
+ s[1] = '\0';
+
+ fl_font(FL_HELVETICA_BOLD, h() - 10);
+ fl_draw(s, x(), y(), w(), h(), FL_ALIGN_CENTER);
+ }
+}
+
+
+// Handle events in cell
+int
+SudokuCell::handle(int event) {
+ switch (event) {
+ case FL_FOCUS :
+ if (!readonly()) {
+ Fl::focus(this);
+ redraw();
+ return 1;
+ }
+ break;
+
+ case FL_UNFOCUS :
+ redraw();
+ return 1;
+ break;
+
+ case FL_PUSH :
+ if (!readonly() && Fl::event_inside(this)) {
+ Fl::focus(this);
+ redraw();
+ return 1;
+ }
+ break;
+
+ case FL_KEYDOWN :
+ int key = Fl::event_key() - '0';
+ if (key >= 1 && key <= 9) {
+ value(key);
+ do_callback();
+ return 1;
+ }
+ break;
+ }
+
+ return Fl_Widget::handle(event);
+}
+
+
+// Sudoku window class...
+class Sudoku : public Fl_Window {
+ Fl_Sys_Menu_Bar *menubar_;
+ Fl_Group *grid_;
+ char grid_values_[9][9];
+ SudokuCell *grid_cells_[9][9];
+ Fl_Group *grid_groups_[3][3];
+ int difficulty_;
+
+ static void check_cb(Fl_Widget *widget, void *);
+ static void close_cb(Fl_Widget *widget, void *);
+ static void diff_cb(Fl_Widget *widget, void *d);
+ static void new_cb(Fl_Widget *widget, void *);
+ static void reset_cb(Fl_Widget *widget, void *);
+ static void solve_cb(Fl_Widget *widget, void *);
+
+ static Fl_Preferences prefs_;
+
+ public:
+
+ Sudoku();
+
+ void check_game();
+ void load_game();
+ void new_game();
+ void resize(int X, int Y, int W, int H);
+ void save_game();
+ void solve_game();
+};
+
+
+// Preferences/saved state for game...
+Fl_Preferences Sudoku::prefs_(Fl_Preferences::USER, "fltk.org", "sudoku");
+
+// Create a Sudoku game window...
+Sudoku::Sudoku()
+ : Fl_Window(GROUP_SIZE * 3, GROUP_SIZE * 3 + MENU_OFFSET, "Sudoku")
+{
+ int i, j, k, m;
+ Fl_Group *g;
+ SudokuCell *cell;
+ static Fl_Menu_Item items[] = {
+ { "&Game", 0, 0, 0, FL_SUBMENU },
+ { "&New Game", FL_COMMAND | 'n', new_cb, 0, FL_MENU_DIVIDER },
+ { "&Check Game", FL_COMMAND | 'c', check_cb, 0, 0 },
+ { "&Solve Game", FL_COMMAND | 's', solve_cb, 0, FL_MENU_DIVIDER },
+ { "&Quit", FL_COMMAND | 'q', close_cb, 0, 0 },
+ { 0 },
+ { "&Difficulty", 0, 0, 0, FL_SUBMENU },
+ { "&Easy", FL_COMMAND | '1', diff_cb, (void *)"40", FL_MENU_RADIO },
+ { "&Medium", FL_COMMAND | '2', diff_cb, (void *)"28", FL_MENU_RADIO },
+ { "&Hard", FL_COMMAND | '3', diff_cb, (void *)"16", FL_MENU_RADIO },
+ { 0 },
+ { 0 }
+ };
+
+
+ // Menubar...
+ prefs_.get("difficulty", difficulty_, 40);
+
+ if (difficulty_ == 16) items[9].flags |= FL_MENU_VALUE;
+ else if (difficulty_ == 28) items[8].flags |= FL_MENU_VALUE;
+ else items[7].flags |= FL_MENU_VALUE;
+
+ menubar_ = new Fl_Sys_Menu_Bar(0, 0, 3 * GROUP_SIZE, 25);
+ menubar_->menu(items);
+
+ // Create the grids...
+ grid_ = new Fl_Group(0, MENU_OFFSET, 3 * GROUP_SIZE, 3 * GROUP_SIZE);
+
+ for (i = 0; i < 3; i ++)
+ for (j = 0; j < 3; j ++) {
+ g = new Fl_Group(i * GROUP_SIZE, j * GROUP_SIZE + MENU_OFFSET,
+ GROUP_SIZE, GROUP_SIZE);
+ g->box(FL_BORDER_BOX);
+ g->color(FL_DARK3);
+
+ grid_groups_[i][j] = g;
+
+ for (k = 0; k < 3; k ++)
+ for (m = 0; m < 3; m ++) {
+ cell = new SudokuCell(i * GROUP_SIZE + CELL_OFFSET + k * CELL_SIZE,
+ j * GROUP_SIZE + CELL_OFFSET + m * CELL_SIZE +
+ MENU_OFFSET,
+ CELL_SIZE, CELL_SIZE);
+ cell->callback(reset_cb);
+ grid_cells_[i * 3 + k][j * 3 + m] = cell;
+ }
+
+ g->end();
+ }
+
+ callback(close_cb);
+ resizable(grid_);
+
+ // Restore the previous window dimensions...
+ int X, Y, W, H;
+
+ if (prefs_.get("x", X, -1)) {
+ prefs_.get("y", Y, -1);
+ prefs_.get("width", W, 3 * GROUP_SIZE);
+ prefs_.get("height", H, 3 * GROUP_SIZE + MENU_OFFSET);
+
+ resize(X, X, W, H);
+ }
+
+ // Load the previous game...
+ load_game();
+}
+
+
+// Check for a solution to the game...
+void
+Sudoku::check_cb(Fl_Widget *widget, void *) {
+ ((Sudoku *)(widget->window()))->check_game();
+}
+
+
+// Check if the user has correctly solved the game...
+void
+Sudoku::check_game() {
+ bool empty = false;
+ bool correct = true;
+
+
+ // Check the game for right/wrong answers...
+ for (int i = 0; i < 9; i ++)
+ for (int j = 0; j < 9; j ++) {
+ SudokuCell *cell = grid_cells_[i][j];
+ int val = cell->value();
+
+ if (!val) empty = true;
+
+ if (val && grid_values_[i][j] != val) {
+ cell->color(FL_YELLOW);
+ cell->redraw();
+ correct = false;
+ }
+ }
+
+ if (!empty && correct) {
+ // Success!
+ solve_game();
+ fl_message("Congratulations, you solved the game!");
+ }
+}
+
+
+// Close the window, saving the game first...
+void
+Sudoku::close_cb(Fl_Widget *widget, void *) {
+ Sudoku *s = (Sudoku *)(widget->window() ? widget->window() : widget);
+
+ s->save_game();
+ s->hide();
+}
+
+
+// Set the level of difficulty...
+void
+Sudoku::diff_cb(Fl_Widget *widget, void *d) {
+ Sudoku *s = (Sudoku *)(widget->window() ? widget->window() : widget);
+
+ s->difficulty_ = atoi((char *)d);
+ s->new_game();
+}
+
+
+// Load the game from saved preferences...
+void
+Sudoku::load_game() {
+ // Load the current values and state of each grid...
+ memset(grid_values_, 0, sizeof(grid_values_));
+
+ for (int i = 0; i < 9; i ++)
+ for (int j = 0; j < 9; j ++) {
+ char name[255];
+ int val;
+
+ SudokuCell *cell = grid_cells_[i][j];
+
+ sprintf(name, "value%d.%d", i, j);
+ if (!prefs_.get(name, val, 0)) {
+ i = 9;
+ grid_values_[0][0] = 0;
+ break;
+ }
+
+ grid_values_[i][j] = val;
+
+ sprintf(name, "state%d.%d", i, j);
+ prefs_.get(name, val, 0);
+ cell->value(val);
+
+ sprintf(name, "readonly%d.%d", i, j);
+ prefs_.get(name, val, 0);
+ cell->readonly(val);
+
+ if (val) cell->color(FL_GRAY);
+ else cell->color(FL_LIGHT3);
+ }
+
+ // If we didn't load any values, then create a new game...
+ if (!grid_values_[0][0]) new_game();
+}
+
+
+// Create a new game...
+void
+Sudoku::new_cb(Fl_Widget *widget, void *) {
+ ((Sudoku *)(widget->window()))->new_game();
+}
+
+
+// Create a new game...
+void
+Sudoku::new_game() {
+ int i, j, k, m, t, count;
+
+
+ // Generate a new (valid) Sudoku grid...
+ srand(time(NULL));
+
+ memset(grid_values_, 0, sizeof(grid_values_));
+
+ for (i = 0; i < 9; i += 3) {
+ for (j = 0; j < 9; j += 3) {
+ for (t = 1; t <= 9; t ++) {
+ for (count = 0; count < 20; count ++) {
+ k = i + (rand() % 3);
+ m = j + (rand() % 3);
+ if (!grid_values_[k][m]) {
+ int kk;
+
+ for (kk = 0; kk < k; kk ++)
+ if (grid_values_[kk][m] == t) break;
+
+ if (kk < k) continue;
+
+ int mm;
+
+ for (mm = 0; mm < m; mm ++)
+ if (grid_values_[k][mm] == t) break;
+
+ if (mm < m) continue;
+
+ grid_values_[k][m] = t;
+ break;
+ }
+ }
+
+ if (count == 20) {
+ // Unable to find a valid puzzle so far, so start over...
+ j = 9;
+ i = -3;
+ memset(grid_values_, 0, sizeof(grid_values_));
+ }
+ }
+ }
+ }
+
+ // Start by making all cells editable
+ SudokuCell *cell;
+
+ for (i = 0; i < 9; i ++)
+ for (j = 0; j < 9; j ++) {
+ cell = grid_cells_[i][j];
+
+ cell->value(0);
+ cell->readonly(0);
+ cell->color(FL_LIGHT3);
+ }
+
+ // Show N cells, starting with potential confusing ones...
+ count = difficulty_;
+
+ for (i = 0; i < 8; i ++)
+ for (j = 0; j < 8; j ++) {
+ cell = grid_cells_[i][j];
+
+ for (k = i + 1; k < 9; k ++) {
+ if (grid_values_[i][j] == grid_values_[k][j + 1] &&
+ grid_values_[i][j + 1] == grid_values_[k][j]) {
+ cell->value(grid_values_[i][j]);
+ cell->readonly(1);
+ cell->color(FL_GRAY);
+
+ count --;
+ }
+ }
+
+ for (m = j + 1; m < 9; m ++) {
+ if (!cell->readonly() &&
+ grid_values_[i][j] == grid_values_[i + 1][m] &&
+ grid_values_[i + 1][m] == grid_values_[i][m]) {
+ cell->value(grid_values_[i][j]);
+ cell->readonly(1);
+ cell->color(FL_GRAY);
+
+ count --;
+ }
+ }
+ }
+
+ // Now show random fields...
+ while (count > 0) {
+ i = rand() % 9;
+ j = rand() % 9;
+ cell = grid_cells_[i][j];
+
+ if (!cell->readonly()) {
+ cell->value(grid_values_[i][j]);
+ cell->readonly(1);
+ cell->color(FL_GRAY);
+
+ count --;
+ }
+ }
+}
+
+
+// Reset widget color to gray...
+void
+Sudoku::reset_cb(Fl_Widget *widget, void *) {
+ widget->color(FL_LIGHT3);
+ widget->redraw();
+}
+
+
+// Resize the window...
+void
+Sudoku::resize(int X, int Y, int W, int H) {
+ // Force resizes to keep the proper aspect ratio...
+ int M = H - MENU_OFFSET;
+
+ if (M > W) M = W;
+
+ if (W != M || H != (M + MENU_OFFSET)) {
+ W = M;
+ H = M + MENU_OFFSET;
+ }
+
+ // Resize the window...
+ Fl_Window::resize(X, Y, W, H);
+
+ // Save the new window geometry...
+ prefs_.set("x", X);
+ prefs_.set("y", Y);
+ prefs_.set("width", W);
+ prefs_.set("height", H);
+}
+
+
+// Save the current game state...
+void
+Sudoku::save_game() {
+ // Save the current values and state of each grid...
+ for (int i = 0; i < 9; i ++)
+ for (int j = 0; j < 9; j ++) {
+ char name[255];
+ SudokuCell *cell = grid_cells_[i][j];
+
+ sprintf(name, "value%d.%d", i, j);
+ prefs_.set(name, grid_values_[i][j]);
+
+ sprintf(name, "state%d.%d", i, j);
+ prefs_.set(name, cell->value());
+
+ sprintf(name, "readonly%d.%d", i, j);
+ prefs_.set(name, cell->readonly());
+ }
+}
+
+
+// Solve the puzzle...
+void
+Sudoku::solve_cb(Fl_Widget *widget, void *) {
+ ((Sudoku *)(widget->window()))->solve_game();
+}
+
+
+// Solve the puzzle...
+void
+Sudoku::solve_game() {
+ int i, j;
+
+ for (i = 0; i < 9; i ++)
+ for (j = 0; j < 9; j ++) {
+ SudokuCell *cell = grid_cells_[i][j];
+
+ cell->value(grid_values_[i][j]);
+ cell->readonly();
+ cell->color(FL_GRAY);
+ }
+}
+
+
+// Main entry for game...
+int
+main(int argc, char *argv[]) {
+ Sudoku s;
+
+ s.show(argc, argv);
+ return (Fl::run());
+}
+
+
+//
+// End of "$Id$".
+//
diff --git a/test/sudoku.png b/test/sudoku.png
new file mode 100644
index 000000000..070a41016
--- /dev/null
+++ b/test/sudoku.png
Binary files differ