|
| 1 | +#! /usr/bin/env -S vala workbench.vala --pkg libadwaita-1 |
| 2 | + |
| 3 | +private Chessboard chessboard; |
| 4 | +private Gtk.Box box; |
| 5 | +private Gtk.Label label; |
| 6 | + |
| 7 | +public class Chessboard : Gtk.Widget { |
| 8 | + const int SQUARE_SIZE = 70; |
| 9 | + const int BOARD_SIZE = 8 * SQUARE_SIZE; |
| 10 | + const float PIECE_SIZE = 1.5f * SQUARE_SIZE; |
| 11 | + |
| 12 | + private Gdk.RGBA black_squares_color; |
| 13 | + private Gdk.RGBA white_squares_color; |
| 14 | + private Gdk.RGBA knight_color; |
| 15 | + |
| 16 | + private float x; |
| 17 | + private float y; |
| 18 | + private float initial_x; |
| 19 | + private float initial_y; |
| 20 | + private Gsk.Path knight_path; |
| 21 | + private Gsk.Stroke knight_stroke; |
| 22 | + private Graphene.Rect knight_bounds; |
| 23 | + private Gtk.GestureDrag gesture; |
| 24 | + private bool gesture_started = false; |
| 25 | + |
| 26 | + public Chessboard() { |
| 27 | + // Initialize colors |
| 28 | + black_squares_color = Gdk.RGBA(); |
| 29 | + black_squares_color.parse("Gray"); |
| 30 | + white_squares_color = Gdk.RGBA(); |
| 31 | + white_squares_color.parse("LightGray"); |
| 32 | + knight_color = Gdk.RGBA(); |
| 33 | + knight_color.parse("SaddleBrown"); |
| 34 | + |
| 35 | + // Initialize knight position and contour |
| 36 | + x = y = (float) 4 * SQUARE_SIZE - PIECE_SIZE / 2; |
| 37 | + initial_x = x; |
| 38 | + initial_y = y; |
| 39 | + // Made by SVG Repo: https://www.svgrepo.com/svg/380957/chess-piece-knight-strategy |
| 40 | + knight_path = Gsk.Path.parse( |
| 41 | + "M47.26,22.08c-.74-3.36-5.69-5.27-7.74-5.92l.34-4.5a1,1,0,0,0-1.74-.74L33.9,15.66c-6.45,2.23-11,6-13.39,11.19-2.9,6.19-2.2,12.94-1.29,17.06H13.71l-1.27,9.5H50.08l-1.27-9.5h-8c.85-4.13-3-10.63-5.59-14.53A5.93,5.93,0,0,0,39,28.1c2.85,1.17,9.48,2.29,10.77,2,1-.19,1.3-1.33,1.5-2.09,0-.12,0-.22,0-.23C52.4,25.82,49.64,23.63,47.26,22.08Zm-.2,23.83.74,5.5H14.72l.74-5.5h31.6Zm2.27-18.35a4.87,4.87,0,0,1-.19.63c-1.6,0-7.92-1.13-9.8-2.13a1,1,0,0,0-1.11.11,4.25,4.25,0,0,1-3.06,1.2A3.65,3.65,0,0,1,33,26.23a1,1,0,0,0-1.39-.16,1,1,0,0,0-.17,1.4C34,30.74,40.19,40,38.78,43.91H21.28c-.87-3.79-1.7-10.37,1-16.21,2.22-4.76,6.42-8.2,12.47-10.23a1,1,0,0,0,.43-.29l2.43-2.72-.18,2.36a1,1,0,0,0,.74,1c1.78.47,6.92,2.39,7.13,4.9a1,1,0,0,0,.46.76,15.42,15.42,0,0,1,3.25,2.54,2.06,2.06,0,0,1,.51.8A3,3,0,0,0,49.33,27.56Z" |
| 42 | + ); |
| 43 | + knight_stroke = new Gsk.Stroke(2.0f); |
| 44 | + knight_path.get_stroke_bounds(knight_stroke, out knight_bounds); |
| 45 | + |
| 46 | + // Add drag gesture and connect it to signals |
| 47 | + gesture = new Gtk.GestureDrag(); |
| 48 | + add_controller(gesture); |
| 49 | + |
| 50 | + gesture.drag_begin.connect(() => { |
| 51 | + var knight_hitbox = Graphene.Rect(); |
| 52 | + knight_hitbox.init(initial_x, initial_y, PIECE_SIZE, PIECE_SIZE); |
| 53 | + var cursor_pos = Graphene.Point(); |
| 54 | + cursor_pos.init((float) x, (float) y); |
| 55 | + gesture_started = knight_hitbox.contains_point(cursor_pos); |
| 56 | + }); |
| 57 | + |
| 58 | + gesture.drag_end.connect((offset_x, offset_y) => { |
| 59 | + if (!gesture_started)return; |
| 60 | + initial_x += (float) offset_x; |
| 61 | + initial_y += (float) offset_y; |
| 62 | + queue_draw(); |
| 63 | + gesture_started = false; |
| 64 | + }); |
| 65 | + gesture.drag_update.connect((offset_x, offset_y) => { |
| 66 | + if (!gesture_started)return; |
| 67 | + x = initial_x + (float) offset_x; |
| 68 | + y = initial_y + (float) offset_y; |
| 69 | + queue_draw(); |
| 70 | + }); |
| 71 | + } |
| 72 | + |
| 73 | + public override void snapshot(Gtk.Snapshot snapshot) { |
| 74 | + // Draw chessboard by repeating a 2x2 block of squares |
| 75 | + var bounds = Graphene.Rect(); |
| 76 | + bounds.init(0, 0, BOARD_SIZE, BOARD_SIZE); |
| 77 | + var child_bounds = Graphene.Rect(); |
| 78 | + child_bounds.init(0, 0, 2 * SQUARE_SIZE, 2 * SQUARE_SIZE); |
| 79 | + snapshot.push_repeat(bounds, child_bounds); // start of repeated part |
| 80 | + |
| 81 | + var r11 = Graphene.Rect(); |
| 82 | + r11.init(0, 0, SQUARE_SIZE, SQUARE_SIZE); |
| 83 | + snapshot.append_color(white_squares_color, r11); |
| 84 | + |
| 85 | + var r12 = Graphene.Rect(); |
| 86 | + r12.init(0, SQUARE_SIZE, SQUARE_SIZE, SQUARE_SIZE); |
| 87 | + snapshot.append_color(black_squares_color, r12); |
| 88 | + |
| 89 | + var r21 = Graphene.Rect(); |
| 90 | + r21.init(SQUARE_SIZE, 0, SQUARE_SIZE, SQUARE_SIZE); |
| 91 | + snapshot.append_color(black_squares_color, r21); |
| 92 | + |
| 93 | + var r22 = Graphene.Rect(); |
| 94 | + r22.init(SQUARE_SIZE, SQUARE_SIZE, SQUARE_SIZE, SQUARE_SIZE); |
| 95 | + snapshot.append_color(white_squares_color, r22); |
| 96 | + |
| 97 | + snapshot.pop(); // end of repeated part |
| 98 | + |
| 99 | + // Draw knight anchored on position (x, y) |
| 100 | + var anchor = Graphene.Point(); |
| 101 | + anchor.init(x, y); |
| 102 | + float factor = (float) PIECE_SIZE / knight_bounds.get_width(); |
| 103 | + var transformation = new Gsk.Transform().translate(anchor).scale(factor, factor); |
| 104 | + snapshot.transform(transformation); |
| 105 | + snapshot.append_stroke(knight_path, knight_stroke, knight_color); |
| 106 | + } |
| 107 | + |
| 108 | + public override void measure(Gtk.Orientation orientation, int for_size, out int minimum, out int natural, out int minimum_baseline, out int natural_baseline) { |
| 109 | + minimum = BOARD_SIZE; |
| 110 | + natural = BOARD_SIZE; |
| 111 | + minimum_baseline = -1; |
| 112 | + natural_baseline = -1; |
| 113 | + } |
| 114 | +} |
| 115 | + |
| 116 | + |
| 117 | +public void main() { |
| 118 | + box = (Gtk.Box) workbench.builder.get_object("box"); |
| 119 | + label = (Gtk.Label) workbench.builder.get_object("label"); |
| 120 | + chessboard = new Chessboard(){ |
| 121 | + hexpand = true, vexpand = true |
| 122 | + }; |
| 123 | + box.insert_child_after(chessboard, label); |
| 124 | +} |
0 commit comments