4
** Copyright (c) 1993-2001 by Hans-Ulrich Kiel & Joerg Czeranski
5
** All rights reserved.
7
** Redistribution and use in source and binary forms, with or without
8
** modification, are permitted provided that the following conditions are
11
** 1. Redistributions of source code must retain the above copyright
12
** notice, this list of conditions and the following disclaimer.
13
** 2. Redistributions in binary form must reproduce the above copyright
14
** notice, this list of conditions and the following disclaimer in the
15
** documentation and/or other materials provided with the distribution.
16
** 3. The name of the authors may not be used to endorse or promote
17
** products derived from this software without specific prior written
19
** 4. The name ``iMaze'' may not be used for products derived from this
20
** software unless a prefix or a suffix is added to the name.
22
** THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
23
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25
** DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT,
26
** INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
30
** STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
31
** IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
** POSSIBILITY OF SUCH DAMAGE.
37
#include <X11/StringDefs.h>
38
#include <X11/IntrinsicP.h>
40
#include "lab_edit_wp.h"
43
static char sccsid[] = "@(#)lab_edit_w.c 3.3 12/04/01";
50
#define DEFAULT_WALL 5
53
#define DOOR_CORNER_WIDTH (2 * WALL_WIDTH)
55
#define DOOR_COLOR1 (N_WALL_COLORS + 1)
57
#define IS_DOOR_COLOR(x) ((x) >= DOOR_COLOR1)
64
static void LabEditInit(Widget request_w, Widget new_w, ArgList arg_list,
66
static void LabEditDestroy(Widget arg_w);
67
static Boolean LabEditSetValues(Widget current_w, Widget request_w,
68
Widget new_w, ArgList arg_list, Cardinal *n_args);
69
static void LabEditExpose(Widget arg_w, XEvent *event, Region arg_r);
76
static XtResource resources[] =
83
XtOffsetOf(LabEditRec, labEdit.foreground_pixel),
92
XtOffsetOf(LabEditRec, labEdit.wall_colors[0]),
101
XtOffsetOf(LabEditRec, labEdit.wall_colors[1]),
110
XtOffsetOf(LabEditRec, labEdit.wall_colors[2]),
119
XtOffsetOf(LabEditRec, labEdit.wall_colors[3]),
128
XtOffsetOf(LabEditRec, labEdit.wall_colors[4]),
137
XtOffsetOf(LabEditRec, labEdit.wall_colors[5]),
146
XtOffsetOf(LabEditRec, labEdit.wall_colors[6]),
155
XtOffsetOf(LabEditRec, labEdit.door_colors[0]),
164
XtOffsetOf(LabEditRec, labEdit.door_colors[1]),
173
XtOffsetOf(LabEditRec, labEdit.door_colors[2]),
182
XtOffsetOf(LabEditRec, labEdit.door_colors[3]),
191
XtOffsetOf(LabEditRec, labEdit.door_colors[4]),
200
XtOffsetOf(LabEditRec, labEdit.door_colors[5]),
209
XtOffsetOf(LabEditRec, labEdit.door_colors[6]),
218
XtOffsetOf(LabEditRec, labEdit.door_colors[7]),
227
XtOffsetOf(LabEditRec, labEdit.h_cells),
236
XtOffsetOf(LabEditRec, labEdit.v_cells),
242
static XtActionsRec actions[] =
244
{ "start_add_wall", LabEditStartAddWall },
245
{ "start_remove_wall", LabEditStartRemoveWall },
246
{ "extend_wall", LabEditExtendWall },
247
{ "finish_wall", LabEditFinishWall },
248
{ "abort_wall", LabEditAbortWall },
249
{ "toggle_door", LabEditToggleDoor }
252
static char translations[] =
253
"Button1<BtnDown>: abort_wall() \n\
254
Button2<BtnDown>: abort_wall() \n\
255
Button3<BtnDown>: abort_wall() \n\
256
<Btn1Down>: start_add_wall() \n\
257
<Btn2Down>: toggle_door() \n\
258
<Btn3Down>: start_remove_wall() \n\
259
<Btn1Motion>: extend_wall() \n\
260
<Btn3Motion>: extend_wall() \n\
261
<Btn1Up>: finish_wall() \n\
262
<Btn3Up>: finish_wall()";
264
LabEditClassRec labEditClassRec =
268
/* superclass */ (WidgetClass)&coreClassRec,
269
/* class_name */ "LabEdit",
270
/* widget_size */ sizeof(LabEditRec),
271
/* class_initialize */ NULL,
272
/* class_part_initialize */ NULL,
273
/* class_inited */ FALSE,
274
/* initialize */ LabEditInit,
275
/* initialize_hook */ NULL,
276
/* realize */ XtInheritRealize,
277
/* actions */ actions,
278
/* num_actions */ XtNumber(actions),
279
/* resources */ resources,
280
/* num_resources */ XtNumber(resources),
281
/* xrm_class */ NULLQUARK,
282
/* compress_motion */ TRUE,
283
/* compress_exposure */ XtExposeCompressMultiple,
284
/* compress_enterleave */ TRUE,
285
/* visible_interest */ FALSE,
286
/* destroy */ LabEditDestroy,
287
/* resize */ NULL, /***/
288
/* expose */ LabEditExpose,
289
/* set_values */ LabEditSetValues,
290
/* set_values_hook */ NULL,
291
/* set_values_almost */ XtInheritSetValuesAlmost,
292
/* get_values_hook */ NULL,
293
/* accept_focus */ NULL, /***/
294
/* version */ XtVersion,
295
/* callback_private */ NULL,
296
/* tm_table */ translations,
297
/* query_geometry */ XtInheritQueryGeometry,
298
/* display_accelerator */ XtInheritDisplayAccelerator,
308
WidgetClass labEditWidgetClass = (WidgetClass)&labEditClassRec;
316
static int random_door_color(void)
318
return zufall() % N_DOOR_COLORS + DOOR_COLOR1;
322
static void LabEditInit(Widget request_w, Widget new_w, ArgList arg_list,
329
w = (LabEditWidget)new_w;
331
w->labEdit.modified = 0;
333
gc_set.foreground = w->labEdit.foreground_pixel;
334
w->labEdit.foreground_gc = XtGetGC(new_w, GCForeground, &gc_set);
336
for (i = 0; i < N_WALL_COLORS; i++)
338
gc_set.foreground = w->labEdit.wall_colors[i];
339
w->labEdit.wall_gcs[i] = XtGetGC(new_w, GCForeground, &gc_set);
342
for (i = 0; i < N_DOOR_COLORS; i++)
344
gc_set.foreground = w->labEdit.door_colors[i];
345
w->labEdit.door_gcs[i] = XtGetGC(new_w, GCForeground, &gc_set);
348
h = w->labEdit.h_cells;
349
v = w->labEdit.v_cells;
351
w->labEdit.walls = (void *)XtMalloc(h * sizeof *w->labEdit.walls);
352
for (x = 0; x < h; x++)
353
w->labEdit.walls[x] =
354
(void *)XtMalloc(v * sizeof **w->labEdit.walls);
360
static void LabEditDestroy(Widget arg_w)
365
w = (LabEditWidget)arg_w;
367
XtReleaseGC(arg_w, w->labEdit.foreground_gc);
369
for (i = 0; i < N_WALL_COLORS; i++)
370
XtReleaseGC(arg_w, w->labEdit.wall_gcs[i]);
372
for (i = 0; i < N_DOOR_COLORS; i++)
373
XtReleaseGC(arg_w, w->labEdit.door_gcs[i]);
375
h = w->labEdit.h_cells;
377
for (x = 0; x < h; x++)
378
XtFree((char *)w->labEdit.walls[x]);
379
XtFree((char *)w->labEdit.walls);
383
static Boolean LabEditSetValues(Widget current_w, Widget request_w,
384
Widget new_w, ArgList arg_list, Cardinal *n_args)
386
LabEditWidget w, old_w;
389
old_w = (LabEditWidget)current_w;
390
w = (LabEditWidget)new_w;
392
if (w->labEdit.h_cells == old_w->labEdit.h_cells &&
393
w->labEdit.v_cells == old_w->labEdit.v_cells)
397
/* destroy old lab data */
399
h = old_w->labEdit.h_cells;
401
for (x = 0; x < h; x++)
402
XtFree((char *)w->labEdit.walls[x]);
403
XtFree((char *)w->labEdit.walls);
406
/* create again with new size */
408
h = w->labEdit.h_cells;
409
v = w->labEdit.v_cells;
411
w->labEdit.walls = (void *)XtMalloc(h * sizeof *w->labEdit.walls);
412
for (x = 0; x < h; x++)
413
w->labEdit.walls[x] =
414
(void *)XtMalloc(v * sizeof **w->labEdit.walls);
423
static void draw_wall(LabEditWidget w, GC gc, int x1, int y1, int x2, int y2,
426
static int dx[4] = { -1, 0, 1, 0 };
427
static int dy[4] = { 0, 1, 0, -1 };
428
XSegment s[WALL_WIDTH];
431
for (i = 0; i < WALL_WIDTH; i++)
433
s[i].x1 = x1 + i * (dy[dir] + dx[dir]) + (i ? 0 : dx[dir]);
434
s[i].y1 = y1 + i * (-dx[dir] + dy[dir]) + (i ? 0 : dy[dir]);
435
s[i].x2 = x2 + i * (dy[dir] - dx[dir]) - dx[dir];
436
s[i].y2 = y2 + i * (-dx[dir] - dy[dir]) - dy[dir];
439
XDrawSegments(XtDisplay(w), XtWindow(w), gc, s, WALL_WIDTH);
443
static void draw_door(LabEditWidget w, GC gc, int x1, int y1, int x2, int y2,
446
static int dx[4] = { -1, 0, 1, 0 };
447
static int dy[4] = { 0, 1, 0, -1 };
448
XSegment s[2 * WALL_WIDTH];
451
for (i = 0; i < WALL_WIDTH; i++)
453
s[i].x1 = x1 + i * dy[dir] + DOOR_CORNER_WIDTH * dx[dir];
454
s[i].y1 = y1 - i * dx[dir] + DOOR_CORNER_WIDTH * dy[dir];
455
s[i].x2 = x2 + i * dy[dir] - DOOR_CORNER_WIDTH * dx[dir];
456
s[i].y2 = y2 - i * dx[dir] - DOOR_CORNER_WIDTH * dy[dir];
459
XDrawSegments(XtDisplay(w), XtWindow(w), gc, s, WALL_WIDTH);
461
for (i = 0; i < WALL_WIDTH; i++)
463
s[i].x1 = x1 + i * (dy[dir] + dx[dir]) + (i ? 0 : dx[dir]);
464
s[i].y1 = y1 + i * (-dx[dir] + dy[dir]) + (i ? 0 : dy[dir]);
465
s[i].x2 = x1 + i * dy[dir] + (DOOR_CORNER_WIDTH - 1) * dx[dir];
466
s[i].y2 = y1 - i * dx[dir] + (DOOR_CORNER_WIDTH - 1) * dy[dir];
468
s[i + WALL_WIDTH].x1 = x2 + i * dy[dir] -
469
(DOOR_CORNER_WIDTH - 1) * dx[dir];
470
s[i + WALL_WIDTH].y1 = y2 - i * dx[dir] -
471
(DOOR_CORNER_WIDTH - 1) * dy[dir];
472
s[i + WALL_WIDTH].x2 = x2 + i * (dy[dir] - dx[dir]) - dx[dir];
473
s[i + WALL_WIDTH].y2 = y2 + i * (-dx[dir] - dy[dir]) - dy[dir];
476
XDrawSegments(XtDisplay(w), XtWindow(w),
477
w->labEdit.foreground_gc, s, 2 * WALL_WIDTH);
481
static void draw_wall_or_door(LabEditWidget w, int x1, int y1, int x2, int y2,
485
draw_door(w, w->labEdit.door_gcs[color - 8],
486
x1, y1, x2, y2, dir);
488
draw_wall(w, w->labEdit.wall_gcs[color - 1],
489
x1, y1, x2, y2, dir);
493
static int calculate_wall_color(LabEditWidget w, int x, int y, int dir)
497
if (!w->labEdit.wall_pending ||
498
!w->labEdit.wall_is_vert && dir != NORTH && dir != SOUTH ||
499
w->labEdit.wall_is_vert && dir != WEST && dir != EAST ||
500
dir == NORTH && y != w->labEdit.wall_y0 ||
501
dir == SOUTH && y + 1 != w->labEdit.wall_y0 ||
502
dir == WEST && x != w->labEdit.wall_x0 ||
503
dir == EAST && x + 1 != w->labEdit.wall_x0)
504
return w->labEdit.walls[x][y][dir];
506
l = w->labEdit.wall_length;
507
if (w->labEdit.wall_is_vert)
508
r = y - w->labEdit.wall_y0;
510
r = x - w->labEdit.wall_x0;
512
if (l < 0 && (r < l || r > 0) ||
513
l >= 0 && (r > l || r < 0))
514
return w->labEdit.walls[x][y][dir];
516
return w->labEdit.wall_color;
520
static void LabEditExpose(Widget arg_w, XEvent *event, Region arg_r)
523
int x, y, h, v, width, height;
526
w = (LabEditWidget)arg_w;
527
if (!XtIsRealized(arg_w))
530
h = w->labEdit.h_cells;
531
v = w->labEdit.v_cells;
533
width = w->core.width;
534
height = w->core.height;
536
for (x = 0; x < h; x++)
539
x2 = width * (x + 1) / h - 1;
541
if (x1 >= event->xexpose.x + event->xexpose.width ||
542
x2 < event->xexpose.x)
545
for (y = 0; y < v; y++)
550
y2 = height * (y + 1) / v - 1;
552
if (y1 >= event->xexpose.y + event->xexpose.height ||
553
y2 < event->xexpose.y)
565
XDrawPoints(XtDisplay(w), XtWindow(w),
566
w->labEdit.foreground_gc,
567
p, 4, CoordModeOrigin);
569
draw_wall_or_door(w, x2, y1, x1, y1, NORTH,
570
calculate_wall_color(w, x, y, NORTH));
572
draw_wall_or_door(w, x1, y1, x1, y2, WEST,
573
calculate_wall_color(w, x, y, WEST));
575
draw_wall_or_door(w, x1, y2, x2, y2, SOUTH,
576
calculate_wall_color(w, x, y, SOUTH));
578
draw_wall_or_door(w, x2, y2, x2, y1, EAST,
579
calculate_wall_color(w, x, y, EAST));
585
static void schedule_blocks(LabEditWidget w, int x, int y, int n_h, int n_v)
587
int h, v, width, height;
590
h = w->labEdit.h_cells;
591
v = w->labEdit.v_cells;
593
width = w->core.width;
594
height = w->core.height;
597
x2 = width * (x + n_h) / h;
599
y2 = height * (y + n_v) / v;
601
XClearArea(XtDisplay(w), XtWindow(w), x1, y1, x2 - x1, y2 - y1, True);
605
static void refresh_pending_wall(LabEditWidget w)
610
if (!w->labEdit.wall_pending)
613
x = w->labEdit.wall_x0;
614
y = w->labEdit.wall_y0;
616
if (w->labEdit.wall_is_vert)
627
l = w->labEdit.wall_length;
630
x += dx * w->labEdit.wall_length;
631
y += dy * w->labEdit.wall_length;
636
if (w->labEdit.wall_is_vert)
637
schedule_blocks(w, x - 1, y, 2, l + 1);
639
schedule_blocks(w, x, y - 1, l + 1, 2);
643
static int find_wall(LabEditWidget w, XEvent *event, int *x_p, int *y_p,
646
int h, v, width, height;
649
if (!XtIsRealized((Widget)w))
652
h = w->labEdit.h_cells;
653
v = w->labEdit.v_cells;
655
width = w->core.width;
656
height = w->core.height;
658
if (event->xbutton.x < 0 || event->xbutton.x >= width ||
659
event->xbutton.y < 0 || event->xbutton.y >= height)
662
a = (event->xbutton.x * h * height +
663
(height - 1 - event->xbutton.y) * v * width) / width / height;
664
b = (event->xbutton.x * h * height +
665
event->xbutton.y * v * width) / width / height;
667
if (*is_vert_p = (a + b) % 2)
671
*x_p = (a + b + 1 - v) / 2;
672
*y_p = (b - a + v - 1) / 2;
674
if (*x_p > 0 && *x_p < h && *y_p >= 0 && *y_p < v)
681
*x_p = (a + b - v) / 2;
682
*y_p = (b - a + v) / 2;
684
if (*x_p >= 0 && *x_p < h && *y_p > 0 && *y_p < v)
692
static void change_wall(LabEditWidget w, XEvent *event)
694
w->labEdit.wall_length = 0;
695
w->labEdit.wall_pending = find_wall(w, event, &w->labEdit.wall_x0,
696
&w->labEdit.wall_y0, &w->labEdit.wall_is_vert);
705
void LabEditSetWall(Widget arg_w, int x, int y, int dir, int value)
709
w = (LabEditWidget)arg_w;
711
if (x < 0 || x >= w->labEdit.h_cells ||
712
y < 0 || y >= w->labEdit.v_cells ||
716
w->labEdit.walls[x][y][dir] = value;
718
if (XtIsRealized(arg_w))
719
schedule_blocks(w, x, y, 1, 1);
723
int LabEditGetWall(Widget arg_w, int x, int y, int dir)
727
w = (LabEditWidget)arg_w;
729
if (x < 0 || x >= w->labEdit.h_cells ||
730
y < 0 || y >= w->labEdit.v_cells ||
732
return 0; /* shouldn't happen */
734
return w->labEdit.walls[x][y][dir];
738
void LabEditStartAddWall(Widget arg_w, XEvent *event, String *params,
743
w = (LabEditWidget)arg_w;
745
LabEditAbortWall(arg_w, event, params, n_params);
747
w->labEdit.wall_color = DEFAULT_WALL;
748
change_wall(w, event);
749
refresh_pending_wall(w);
753
void LabEditStartRemoveWall(Widget arg_w, XEvent *event, String *params,
758
w = (LabEditWidget)arg_w;
760
LabEditAbortWall(arg_w, event, params, n_params);
762
w->labEdit.wall_color = 0;
763
change_wall(w, event);
764
refresh_pending_wall(w);
768
void LabEditExtendWall(Widget arg_w, XEvent *event, String *params,
772
int h, v, width, height, old_l, new_l;
775
w = (LabEditWidget)arg_w;
777
if (!XtIsRealized(arg_w))
780
if (!w->labEdit.wall_pending)
783
h = w->labEdit.h_cells;
784
v = w->labEdit.v_cells;
786
width = w->core.width;
787
height = w->core.height;
789
old_l = w->labEdit.wall_length;
791
if (event->xbutton.x < 0 || event->xbutton.x >= width ||
792
event->xbutton.y < 0 || event->xbutton.y >= height)
795
bx = event->xbutton.x * h / width;
796
by = event->xbutton.y * v / height;
798
if (w->labEdit.wall_is_vert)
799
new_l = by - w->labEdit.wall_y0;
801
new_l = bx - w->labEdit.wall_x0;
806
if (old_l > 0 && new_l < old_l || old_l < 0 && new_l > old_l)
807
refresh_pending_wall(w);
809
w->labEdit.wall_length = new_l;
810
refresh_pending_wall(w);
814
void LabEditFinishWall(Widget arg_w, XEvent *event, String *params,
821
w = (LabEditWidget)arg_w;
823
if (!XtIsRealized(arg_w))
826
if (!w->labEdit.wall_pending)
829
x = w->labEdit.wall_x0;
830
y = w->labEdit.wall_y0;
831
l = w->labEdit.wall_length;
832
color = w->labEdit.wall_color;
834
if (is_vert = w->labEdit.wall_is_vert)
852
for (l++; l--; x += dx, y += dy)
855
w->labEdit.walls[x][y][WEST] = color;
856
w->labEdit.walls[x - 1][y][EAST] = color;
860
w->labEdit.walls[x][y][NORTH] = color;
861
w->labEdit.walls[x][y - 1][SOUTH] = color;
864
refresh_pending_wall(w);
865
w->labEdit.wall_pending = 0;
866
w->labEdit.modified = 1;
870
void LabEditAbortWall(Widget arg_w, XEvent *event, String *params,
875
w = (LabEditWidget)arg_w;
877
refresh_pending_wall(w);
878
w->labEdit.wall_pending = 0;
882
void LabEditToggleDoor(Widget arg_w, XEvent *event, String *params,
889
w = (LabEditWidget)arg_w;
891
if (!XtIsRealized(arg_w))
894
LabEditAbortWall(arg_w, event, params, n_params);
896
if (!find_wall(w, event, &x, &y, &is_vert))
901
wall1 = &w->labEdit.walls[x - 1][y][EAST];
902
wall2 = &w->labEdit.walls[x][y][WEST];
906
wall1 = &w->labEdit.walls[x][y - 1][SOUTH];
907
wall2 = &w->labEdit.walls[x][y][NORTH];
910
if (IS_DOOR_COLOR(*wall1))
911
if (IS_DOOR_COLOR(*wall2))
913
*wall2 = DEFAULT_WALL;
914
schedule_blocks(w, x, y, 1, 1);
919
*wall2 = random_door_color();
920
*wall1 = DEFAULT_WALL;
922
else if (IS_DOOR_COLOR(*wall2))
923
*wall1 = random_door_color();
926
*wall1 = random_door_color();
927
*wall2 = random_door_color();
931
schedule_blocks(w, x - 1, y, 2, 1);
933
schedule_blocks(w, x, y - 1, 1, 2);
935
w->labEdit.modified = 1;
939
void LabEditClear(Widget arg_w)
944
w = (LabEditWidget)arg_w;
946
w->labEdit.modified = 0;
948
h = w->labEdit.h_cells;
949
v = w->labEdit.v_cells;
951
for (x = 0; x < h; x++)
954
for (y = 0; y < v; y++)
955
for (i = 0; i < 4; i++)
956
w->labEdit.walls[x][y][i] = 0;
958
w->labEdit.walls[x][0][NORTH] = DEFAULT_WALL;
959
w->labEdit.walls[x][v - 1][SOUTH] = DEFAULT_WALL;
962
for (y = 0; y < v; y++)
964
w->labEdit.walls[0][y][WEST] = DEFAULT_WALL;
965
w->labEdit.walls[h - 1][y][EAST] = DEFAULT_WALL;
968
w->labEdit.wall_pending = 0;
970
if (!XtIsRealized(arg_w))
973
schedule_blocks(w, 0, 0, h, v);
977
void LabEditSetUnmodified(Widget arg_w)
981
w = (LabEditWidget)arg_w;
983
w->labEdit.modified = 0;
987
int LabEditIsModified(Widget arg_w)
991
w = (LabEditWidget)arg_w;
993
return w->labEdit.modified;