~ubuntu-branches/ubuntu/trusty/ricochet/trusty-proposed

« back to all changes in this revision

Viewing changes to ricochet-0.1/nichrome-rrboard.5c

  • Committer: Package Import Robot
  • Author(s): Keith Packard
  • Date: 2012-06-11 13:37:57 UTC
  • Revision ID: package-import@ubuntu.com-20120611133757-zn0ukd22vz56ymto
Tags: 0.3
* Improve appearance of board
* Fix user list when removing/adding same user

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright © 2012 Keith Packard <keithp@keithp.com>
3
 
 *
4
 
 * This program is free software; you can redistribute it and/or modify
5
 
 * it under the terms of the GNU General Public License as published by
6
 
 * the Free Software Foundation; version 2 of the License.
7
 
 *
8
 
 * This program is distributed in the hope that it will be useful, but
9
 
 * WITHOUT ANY WARRANTY; without even the implied warranty of
10
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
 
 * General Public License for more details.
12
 
 *
13
 
 * You should have received a copy of the GNU General Public License along
14
 
 * with this program; if not, write to the Free Software Foundation, Inc.,
15
 
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16
 
 */
17
 
 
18
 
autoload Nichrome;
19
 
autoload RR;
20
 
autoload Client;
21
 
autoload Client::Draw;
22
 
autoload Mutex;
23
 
autoload Nichrome::Timer;
24
 
 
25
 
extend namespace Nichrome {
26
 
 
27
 
        public namespace RRboard {
28
 
 
29
 
                import Client;
30
 
                import RR;
31
 
 
32
 
                public int      board_width = RR::Width * Draw::cell_width;
33
 
                public int      board_height = RR::Height * Draw::cell_height;
34
 
 
35
 
                public typedef widget_t + struct {
36
 
                        RR::Board               board;
37
 
                        RR::RobotOrNone         active_robot;
38
 
                        *Timer::timer_t         timer;
39
 
                        void (RR::Color color,
40
 
                              RR::Direction direction) move_callback;
41
 
                        int                     button_x, button_y;
42
 
                } rrboard_widget_t;
43
 
 
44
 
                real dimension(&rrboard_widget_t widget) = min (widget.geometry.width, widget.geometry.height);
45
 
 
46
 
                Draw::transform_t transform(&rrboard_widget_t widget) {
47
 
                        real    dim = dimension(&widget);
48
 
                        return (Draw::transform_t) {
49
 
                                .xscale = dim / board_width,
50
 
                                .yscale = dim / board_height,
51
 
                                .xoff = (widget.geometry.width - dim) // 2,
52
 
                                .yoff = (widget.geometry.height - dim) // 2
53
 
                                };
54
 
                }
55
 
 
56
 
                void draw (cairo_t cr, &rrboard_widget_t widget) {
57
 
                        Draw::transform_t       t = transform(&widget);
58
 
 
59
 
                        save(cr);
60
 
                        for (int y = 0; y < RR::Height; y++)
61
 
                                for (int x = 0; x < RR::Width; x++) {
62
 
                                        Draw::background(cr, x, y, widget.board[x,y], &t);
63
 
                                        Draw::walls(cr, x, y, widget.board[x,y], &t);
64
 
                                        Draw::contents(cr, x, y, widget.board[x,y], widget.active_robot, &t);
65
 
                                }
66
 
                        for (int y = RR::Height / 2 - 1; y < RR::Height/2 + 1; y++)
67
 
                                for (int x = RR::Width / 2 - 1; x < RR::Width/2 + 1; x++) {
68
 
                                        Draw::background(cr, x, y, widget.board[x,y], &t);
69
 
                                        Draw::walls(cr, x, y, widget.board[x,y], &t);
70
 
                                }
71
 
                        Draw::target(cr, RR::Width / 2 - 1, RR::Height / 2 - 1,
72
 
                                     RR::active_target(&widget.board), &t);
73
 
                        restore(cr);
74
 
                }
75
 
 
76
 
                void outline (cairo_t cr, &rrboard_widget_t widget) {
77
 
                        rectangle(cr, 0, 0, widget.geometry.width, widget.geometry.height);
78
 
                }
79
 
 
80
 
                void natural (cairo_t cr, &rrboard_widget_t widget) {
81
 
                        rectangle(cr, 0, 0, board_width, board_height);
82
 
                }
83
 
 
84
 
                /* Override default widget configure function to also reposition
85
 
                 * the timer widget
86
 
                 */
87
 
                void configure (&rrboard_widget_t widget, rect_t geometry) {
88
 
                        Widget::configure(&widget, geometry);
89
 
 
90
 
                        /* Configure timer to sit over the central
91
 
                         * region of the board
92
 
                         */
93
 
                        real board_dim = dimension(&widget);
94
 
                        real timer_dim = board_dim * 2 / RR::Width;
95
 
                        real timer_pos = board_dim / RR::Width * 7;
96
 
                        widget.timer->configure (widget.timer,
97
 
                                         (rect_t) {
98
 
                                                 .x = geometry.x + timer_pos,
99
 
                                                 .y = geometry.y + timer_pos,
100
 
                                                 .width = timer_dim,
101
 
                                                 .height = timer_dim
102
 
                                                 });
103
 
                }
104
 
 
105
 
                void set_active_robot(&rrboard_widget_t widget, RR::Robot robot) {
106
 
                        widget.active_robot = (RR::RobotOrNone.robot) robot;
107
 
                        Widget::redraw(&widget);
108
 
                }
109
 
                
110
 
                void set_active (&rrboard_widget_t widget, string color) {
111
 
                        try {
112
 
                                set_active_robot(&widget, (RR::Robot) { .color = RR::color(color) });
113
 
                        } catch RR::rr_error(RR::Error error) {
114
 
                        }
115
 
                }
116
 
 
117
 
                void move_active (&rrboard_widget_t widget, string dir) {
118
 
                        try {
119
 
                                RR::Direction direction = RR::direction(dir);
120
 
                                union switch (widget.active_robot) {
121
 
                                case robot r:
122
 
                                        widget.move_callback(r.color, direction);
123
 
                                        break;
124
 
                                default:
125
 
                                }
126
 
                        } catch RR::rr_error(RR::Error error) {
127
 
                        }
128
 
                }
129
 
 
130
 
                protected void key (&rrboard_widget_t widget, &key_event_t event) {
131
 
 
132
 
                        if (event.type != key_type_t.press)
133
 
                                return;
134
 
 
135
 
                        switch (event.key) {
136
 
                        case "r": case "R":
137
 
                        case "g": case "G":
138
 
                        case "b": case "B":
139
 
                        case "y": case "Y":
140
 
                                set_active (&widget, event.key);
141
 
                                break;
142
 
                        case " ":
143
 
                                set_active (&widget, "whirl");
144
 
                                break;
145
 
                        case "Left": case "w": case "W":
146
 
                                move_active(&widget, "west");
147
 
                                break;
148
 
                        case "Right": case "e": case "E":
149
 
                                move_active(&widget, "east");
150
 
                                break;
151
 
                        case "Up": case "n": case "N":
152
 
                                move_active(&widget, "north");
153
 
                                break;
154
 
                        case "Down": case "s": case "S":
155
 
                                move_active(&widget, "south");
156
 
                                break;
157
 
                        }
158
 
                }
159
 
 
160
 
                typedef struct { int x, y; } position_t;
161
 
 
162
 
                /*
163
 
                 * A bit expensive, but it's more reliable than trying to
164
 
                 * keep track of robot positions separately
165
 
                 */
166
 
                position_t find_robot (&rrboard_widget_t widget, RR::Robot robot) {
167
 
                        for (int y = 0; y < RR::Height; y++)
168
 
                                for (int x = 0; x < RR::Width; x++) {
169
 
                                        union switch (widget.board[x,y].robot) {
170
 
                                        case robot r:
171
 
                                                if (r.color == robot.color)
172
 
                                                        return (position_t) { .x = x, .y = y };
173
 
                                                break;
174
 
                                        default:
175
 
                                        }
176
 
                                }
177
 
                        return (position_t) { .x = 0, .y = 0 };
178
 
                }
179
 
 
180
 
                protected void button (&rrboard_widget_t widget, &button_event_t event) {
181
 
 
182
 
                        /* Convert button position to board location */
183
 
                        Draw::transform_t       t = transform(&widget);
184
 
                        int                     x = floor ((event.x - t.xoff) / t.xscale / Draw::cell_width);
185
 
                        int                     y = floor ((event.y - t.yoff) / t.yscale / Draw::cell_height);
186
 
 
187
 
                        enum switch (event.type) {
188
 
                        case press:
189
 
                                RR::Object      object = widget.board[x,y];
190
 
 
191
 
                                /* Clicking on a robot selects that robot
192
 
                                 */
193
 
                                union switch (object.robot) {
194
 
                                case robot r:
195
 
                                        set_active_robot(&widget, r);
196
 
                                        break;
197
 
                                default:
198
 
                                }
199
 
                                break;
200
 
                        case release:
201
 
 
202
 
                                /* Releasing with an active robot moves the robot
203
 
                                 * towards the point of release
204
 
                                 */
205
 
                                union switch (widget.active_robot) {
206
 
                                case robot r:
207
 
                                        position_t      robot_pos = find_robot(&widget, r);
208
 
                                        int     dx = x - robot_pos.x;
209
 
                                        int     dy = y - robot_pos.y;
210
 
 
211
 
                                        if (abs (dx) > abs (dy)) {
212
 
                                                if (dx < 0)
213
 
                                                        move_active(&widget, "west");
214
 
                                                else if (dx > 0)
215
 
                                                        move_active(&widget, "east");
216
 
                                        } else {
217
 
                                                if (dy < 0)
218
 
                                                        move_active(&widget, "north");
219
 
                                                else if (dy > 0)
220
 
                                                        move_active(&widget, "south");
221
 
                                        }
222
 
                                        break;
223
 
                                default:
224
 
                                        break;
225
 
                                }
226
 
                                break;
227
 
                        default:
228
 
                        }
229
 
                }
230
 
 
231
 
                protected void set_timer (&rrboard_widget_t widget, real time) {
232
 
                        Timer::set_timer(widget.timer, time);
233
 
                }
234
 
                
235
 
                protected void stop_timer (&rrboard_widget_t widget) {
236
 
                        Timer::stop_timer(widget.timer);
237
 
                }
238
 
 
239
 
                public *rrboard_widget_t new(&nichrome_t nichrome,
240
 
                                             void(RR::Color color, RR::Direction dir) move_callback){
241
 
                        &rrboard_widget_t       widget = &(rrboard_widget_t) {};
242
 
 
243
 
                        widget.timer = Timer::new(&nichrome);   /* make sure timer is above rrboard */
244
 
                        Widget::init(&nichrome, &widget);
245
 
                        widget.draw = draw;
246
 
                        widget.outline = outline;
247
 
                        widget.natural = natural;
248
 
                        widget.configure = configure;
249
 
                        widget.key = key;
250
 
                        widget.button = button;
251
 
                        widget.active_robot = RobotOrNone.none;
252
 
                        widget.move_callback = move_callback;
253
 
                        widget.board = (RR::Board) { { { .robot = RobotOrNone.none,
254
 
                                                         .target = TargetOrNone.none,
255
 
                                                         .walls = { .left = false, .right = false,
256
 
                                                                  .above = false, .below = false }
257
 
                                        } ... } ... };
258
 
                        return &widget;
259
 
                }
260
 
        }
261
 
}