[hitori: 1/3] Add cell cursor




commit 09771631806aaff0172a04efbf54dba181e5b686
Author: Toni Ruža <toni ruza gmail com>
Date:   Sun Oct 31 17:23:03 2021 +0100

    Add cell cursor

 data/hitori.css |  4 +++
 data/hitori.ui  |  4 ++-
 src/interface.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/main.c      |  4 +++
 src/main.h      |  3 ++
 5 files changed, 100 insertions(+), 1 deletion(-)
---
diff --git a/data/hitori.css b/data/hitori.css
index c89221b..06ba301 100644
--- a/data/hitori.css
+++ b/data/hitori.css
@@ -22,3 +22,7 @@
 
 @define-color tag2-unpainted-color #8ae234; /* Tango's lightest "chameleon" */
 @define-color tag2-painted-color alpha(@tag2-unpainted-color, 0.7);
+
+/* Cursor color */
+
+@define-color cursor-color #3584e4;
diff --git a/data/hitori.ui b/data/hitori.ui
index 8f43109..6540b4d 100644
--- a/data/hitori.ui
+++ b/data/hitori.ui
@@ -173,11 +173,13 @@
                                        <object class="GtkDrawingArea" id="hitori_drawing_area">
                                                <property name="expand">True</property>
                                                <property name="valign">fill</property>
+            <property name="can_focus">True</property>
                                                <property name="width-request">360</property>
                                                <property name="height-request">360</property>
-                                               <property name="events">GDK_BUTTON_PRESS_MASK | 
GDK_BUTTON_RELEASE_MASK</property>
+                                               <property name="events">GDK_BUTTON_PRESS_MASK | 
GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK</property>
                                                <signal name="draw" handler="hitori_draw_cb"/>
                                                <signal name="button-release-event" 
handler="hitori_button_release_cb"/>
+            <signal name="key-press-event" handler="hitori_key_press_cb"/>
                                        </object>
                                </child>
                                <child>
diff --git a/src/interface.c b/src/interface.c
index 4a00c85..d5d90aa 100644
--- a/src/interface.c
+++ b/src/interface.c
@@ -34,12 +34,14 @@
 #define HINT_FLASHES 6
 #define HINT_DISABLED 0
 #define HINT_INTERVAL 500
+#define CURSOR_MARGIN 3
 
 static void hitori_cancel_hinting (Hitori *hitori);
 
 /* Declarations for GtkBuilder */
 gboolean hitori_draw_cb (GtkWidget *drawing_area, cairo_t *cr, Hitori *hitori);
 gboolean hitori_button_release_cb (GtkWidget *drawing_area, GdkEventButton *event, Hitori *hitori);
+gboolean hitori_key_press_cb (GtkWidget *drawing_area, GdkEventKey *event, Hitori *hitori);
 void hitori_destroy_cb (GtkWindow *window, Hitori *hitori);
 void hitori_window_state_event_cb (GtkWindow *window, GdkEventWindowState *event, Hitori *hitori);
 static void new_game_cb (GSimpleAction *action, GVariant *parameter, gpointer user_data);
@@ -164,6 +166,9 @@ hitori_create_interface (Hitori *hitori)
        g_simple_action_set_enabled (hitori->undo_action, FALSE);
        g_simple_action_set_enabled (hitori->redo_action, FALSE);
 
+       /* Cursor is initially not active as playing with the mouse is more common */
+       hitori->cursor_active = FALSE;
+
        return hitori->window;
 }
 
@@ -322,6 +327,19 @@ draw_cell (Hitori *hitori, GtkStyleContext *style_context, cairo_t *cr, gdouble
        pango_cairo_show_layout (cr, layout);
 
        g_object_unref (layout);
+
+       if (hitori->cursor_active &&
+           hitori->cursor_position.x == iter.x && hitori->cursor_position.y == iter.y &&
+           gtk_widget_is_focus (hitori->drawing_area)) {
+               /* Draw the cursor */
+               lookup_color (style_context, "cursor-color", &colour);
+               gdk_cairo_set_source_rgba (cr, &colour);
+               cairo_set_line_width (cr, border.left);
+               cairo_rectangle (cr,
+                                x_pos + CURSOR_MARGIN, y_pos + CURSOR_MARGIN,
+                                cell_size - (2 * CURSOR_MARGIN), cell_size - (2 * CURSOR_MARGIN));
+               cairo_stroke (cr);
+       }
 }
 
 gboolean
@@ -424,6 +442,12 @@ hitori_button_release_cb (GtkWidget *drawing_area, GdkEventButton *event, Hitori
        if (pos.x >= hitori->board_size || pos.y >= hitori->board_size)
                return FALSE;
 
+       /* Move the cursor to the clicked cell and deactivate it
+        * (assuming player will use the mouse for the next move) */
+       hitori->cursor_position.x = pos.x;
+       hitori->cursor_position.y = pos.y;
+       hitori->cursor_active = FALSE;
+
        /* Update the undo stack */
        undo = g_new (HitoriUndo, 1);
        undo->cell = pos;
@@ -480,6 +504,68 @@ hitori_button_release_cb (GtkWidget *drawing_area, GdkEventButton *event, Hitori
        return FALSE;
 }
 
+gboolean
+hitori_key_press_cb (GtkWidget *drawing_area, GdkEventKey *event, Hitori *hitori)
+{
+       gboolean did_something = TRUE;
+
+       if (hitori->cursor_active) {
+               switch (event->keyval) {
+                       case GDK_KEY_Left:
+                       case GDK_KEY_h:
+                               if (hitori->cursor_position.x > 0) {
+                                       hitori->cursor_position.x -= 1;
+                               }
+                               break;
+                       case GDK_KEY_Right:
+                       case GDK_KEY_l:
+                               if (hitori->cursor_position.x < hitori->board_size - 1) {
+                                       hitori->cursor_position.x += 1;
+                               }
+                               break;
+                       case GDK_KEY_Up:
+                       case GDK_KEY_k:
+                               if (hitori->cursor_position.y > 0) {
+                                       hitori->cursor_position.y -= 1;
+                               }
+                               break;
+                       case GDK_KEY_Down:
+                       case GDK_KEY_j:
+                               if (hitori->cursor_position.y < hitori->board_size - 1) {
+                                       hitori->cursor_position.y += 1;
+                               }
+                               break;
+                       default:
+                               did_something = FALSE;
+               }
+       } else {
+               /* Activate the cell cursor if any of the keys related to playing with keyboard are pressed */
+               switch (event->keyval) {
+                       case GDK_KEY_Left:
+                       case GDK_KEY_h:
+                       case GDK_KEY_Right:
+                       case GDK_KEY_l:
+                       case GDK_KEY_Up:
+                       case GDK_KEY_k:
+                       case GDK_KEY_Down:
+                       case GDK_KEY_j:
+                       case GDK_KEY_space:
+                       case GDK_KEY_Return:
+                               hitori->cursor_active = TRUE;
+                               break;
+                       default:
+                               break;
+               }
+       }
+
+       if (did_something) {
+               /* Redraw */
+               gtk_widget_queue_draw (hitori->drawing_area);
+       }
+
+       return did_something;
+}
+
 void
 hitori_destroy_cb (GtkWindow *window, Hitori *hitori)
 {
diff --git a/src/main.c b/src/main.c
index 12b6c27..a72b92e 100644
--- a/src/main.c
+++ b/src/main.c
@@ -308,6 +308,10 @@ hitori_new_game (Hitori *hitori, guint board_size)
 
        hitori_reset_timer (hitori);
        hitori_start_timer (hitori);
+
+       /* Reset the cursor position */
+       hitori->cursor_position.x = 0;
+       hitori->cursor_position.y = 0;
 }
 
 void
diff --git a/src/main.h b/src/main.h
index 3d713ef..7fc52cd 100644
--- a/src/main.h
+++ b/src/main.h
@@ -100,6 +100,9 @@ struct _HitoriApplication {
        GtkLabel *timer_label;
        guint timeout_id;
 
+       gboolean cursor_active;
+       HitoriVector cursor_position;
+       
        GSettings *settings;
 };
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]