1 /*-
2 # X-BASED RUBIK'S CUBE(tm)
3 #
4 # Rubik2d.c
5 #
6 ###
7 #
8 # Copyright (c) 1994 - 99 David Albert Bagley, bagleyd@tux.org
9 #
10 # All Rights Reserved
11 #
12 # Permission to use, copy, modify, and distribute this software and
13 # its documentation for any purpose and without fee is hereby granted,
14 # provided that the above copyright notice appear in all copies and
15 # that both that copyright notice and this permission notice appear in
16 # supporting documentation, and that the name of the author not be
17 # used in advertising or publicity pertaining to distribution of the
18 # software without specific, written prior permission.
19 #
20 # This program is distributed in the hope that it will be "playable",
21 # but WITHOUT ANY WARRANTY; without even the implied warranty of
22 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
23 #
24 */
25
26 /* Methods file for Rubik2d */
27
28 #include <stdio.h>
29 #include <X11/IntrinsicP.h>
30 #include <X11/Intrinsic.h>
31 #include <X11/StringDefs.h>
32 #include <X11/CoreP.h>
33 #include "RubikP.h"
34 #include "Rubik2dP.h"
35
36 static void InitializeRubik2D(Widget request, Widget renew);
37 static void ResizeRubik2D(Rubik2DWidget w);
38 static void ExposeRubik2D(Widget renew, XEvent * event, Region region);
39 static Boolean SetValuesRubik2D(Widget current, Widget request, Widget renew);
40 static void MoveRubik2DTop(Rubik2DWidget w,
41 XEvent * event, char **args, int nArgs);
42 static void MoveRubik2DLeft(Rubik2DWidget w,
43 XEvent * event, char **args, int nArgs);
44 static void MoveRubik2DRight(Rubik2DWidget w,
45 XEvent * event, char **args, int nArgs);
46 static void MoveRubik2DBottom(Rubik2DWidget w,
47 XEvent * event, char **args, int nArgs);
48 static void ResizePolyhedrons(Rubik2DWidget w);
49 static void DrawFrame(Rubik2DWidget w, GC gc);
50 static void DrawOrientLine(Rubik2DWidget w, int orient, int dx, int dy, GC borderGC, int offset);
51
52 static char defaultTranslationsRubik2D[] =
53 "<KeyPress>q: Quit()\n\
54 Ctrl<KeyPress>C: Quit()\n\
55 <KeyPress>KP_Divide: MoveCcw()\n\
56 <KeyPress>Up: MoveTop()\n\
57 <KeyPress>KP_8: MoveTop()\n\
58 <KeyPress>R8: MoveTop()\n\
59 <KeyPress>Left: MoveLeft()\n\
60 <KeyPress>KP_4: MoveLeft()\n\
61 <KeyPress>R10: MoveLeft()\n\
62 <KeyPress>Begin: MoveCw()\n\
63 <KeyPress>KP_5: MoveCw()\n\
64 <KeyPress>R11: MoveCw()\n\
65 <KeyPress>Right: MoveRight()\n\
66 <KeyPress>KP_6: MoveRight()\n\
67 <KeyPress>R12: MoveRight()\n\
68 <KeyPress>Down: MoveBottom()\n\
69 <KeyPress>KP_2: MoveBottom()\n\
70 <KeyPress>R14: MoveBottom()\n\
71 <Btn1Down>: Select()\n\
72 <Btn1Up>: Release()\n\
73 <KeyPress>p: Practice()\n\
74 <Btn2Down>(2+): Practice()\n\
75 <Btn2Down>: PracticeMaybe()\n\
76 <KeyPress>r: Randomize()\n\
77 <Btn3Down>(2+): Randomize()\n\
78 <Btn3Down>: RandomizeMaybe()\n\
79 <KeyPress>g: Get()\n\
80 <KeyPress>w: Write()\n\
81 <KeyPress>u: Undo()\n\
82 <KeyPress>s: Solve()\n\
83 <KeyPress>d: Decrement()\n\
84 <KeyPress>i: Increment()\n\
85 <KeyPress>x: IncrementX()\n\
86 <KeyPress>y: IncrementY()\n\
87 <KeyPress>z: IncrementZ()\n\
88 <KeyPress>o: Orientize()";
89
90 static XtActionsRec actionsListRubik2D[] =
91 {
92 {"Quit", (XtActionProc) QuitRubik},
93 {"MoveCcw", (XtActionProc) MoveRubikCcw},
94 {"MoveTop", (XtActionProc) MoveRubik2DTop},
95 {"MoveLeft", (XtActionProc) MoveRubik2DLeft},
96 {"MoveCw", (XtActionProc) MoveRubikCw},
97 {"MoveRight", (XtActionProc) MoveRubik2DRight},
98 {"MoveBottom", (XtActionProc) MoveRubik2DBottom},
99 {"Select", (XtActionProc) SelectRubik},
100 {"Release", (XtActionProc) ReleaseRubik},
101 {"Practice", (XtActionProc) PracticeRubik},
102 {"PracticeMaybe", (XtActionProc) PracticeRubikMaybe},
103 {"Randomize", (XtActionProc) RandomizeRubik},
104 {"RandomizeMaybe", (XtActionProc) RandomizeRubikMaybe},
105 {"Get", (XtActionProc) GetRubik},
106 {"Write", (XtActionProc) WriteRubik},
107 {"Undo", (XtActionProc) UndoRubik},
108 {"Solve", (XtActionProc) SolveRubik},
109 {"Decrement", (XtActionProc) DecrementRubik},
110 {"Increment", (XtActionProc) IncrementRubik},
111 {"IncrementX", (XtActionProc) IncrementXRubik},
112 {"IncrementY", (XtActionProc) IncrementYRubik},
113 {"IncrementZ", (XtActionProc) IncrementZRubik},
114 {"Orientize", (XtActionProc) OrientizeRubik}
115 };
116
117 static XtResource resourcesRubik2D[] =
118 {
119 {XtNuserName, XtCUserName, XtRString, sizeof (String),
120 XtOffset(RubikWidget, rubik.username), XtRString, "nobody"},
121 {XtNfaceColor0, XtCLabel, XtRString, sizeof (String),
122 XtOffset(RubikWidget, rubik.faceName[0]), XtRString, "Red"},
123 {XtNfaceColor1, XtCLabel, XtRString, sizeof (String),
124 XtOffset(RubikWidget, rubik.faceName[1]), XtRString, "Yellow"},
125 {XtNfaceColor2, XtCLabel, XtRString, sizeof (String),
126 XtOffset(RubikWidget, rubik.faceName[2]), XtRString, "White"},
127 {XtNfaceColor3, XtCLabel, XtRString, sizeof (String),
128 XtOffset(RubikWidget, rubik.faceName[3]), XtRString, "Green"},
129 {XtNfaceColor4, XtCLabel, XtRString, sizeof (String),
130 XtOffset(RubikWidget, rubik.faceName[4]), XtRString, "Orange"},
131 {XtNfaceColor5, XtCLabel, XtRString, sizeof (String),
132 XtOffset(RubikWidget, rubik.faceName[5]), XtRString, "Blue"},
133 {XtNforeground, XtCForeground, XtRPixel, sizeof (Pixel),
134 XtOffset(RubikWidget, rubik.foreground), XtRString, XtDefaultForeground},
135 {XtNpieceBorder, XtCColor, XtRPixel, sizeof (Pixel),
136 XtOffset(RubikWidget, rubik.borderColor), XtRString, XtDefaultForeground},
137 {XtNwidth, XtCWidth, XtRDimension, sizeof (Dimension),
138 XtOffset(RubikWidget, core.width), XtRString, "300"},
139 {XtNheight, XtCHeight, XtRDimension, sizeof (Dimension),
140 XtOffset(RubikWidget, core.height), XtRString, "400"},
141 {XtNsizex, XtCSizeX, XtRInt, sizeof (int),
142 XtOffset(RubikWidget, rubik.sizex), XtRString, "3"}, /* DEFAULTCUBES */
143 {XtNsizey, XtCSizeY, XtRInt, sizeof (int),
144 XtOffset(RubikWidget, rubik.sizey), XtRString, "3"}, /* DEFAULTCUBES */
145 {XtNsizez, XtCSizeZ, XtRInt, sizeof (int),
146 XtOffset(RubikWidget, rubik.sizez), XtRString, "3"}, /* DEFAULTCUBES */
147 {XtNorient, XtCOrient, XtRBoolean, sizeof (Boolean),
148 XtOffset(RubikWidget, rubik.orient), XtRString, "FALSE"}, /* DEFAULTORIENT */
149 {XtNmono, XtCMono, XtRBoolean, sizeof (Boolean),
150 XtOffset(RubikWidget, rubik.mono), XtRString, "FALSE"},
151 {XtNreverse, XtCReverse, XtRBoolean, sizeof (Boolean),
152 XtOffset(RubikWidget, rubik.reverse), XtRString, "FALSE"},
153 {XtNface, XtCFace, XtRInt, sizeof (int),
154 XtOffset(RubikWidget, rubik.currentFace), XtRString, "-1"},
155 {XtNpos, XtCPos, XtRInt, sizeof (int),
156 XtOffset(RubikWidget, rubik.currentPosition), XtRString, "-1"},
157 {XtNdirection, XtCDirection, XtRInt, sizeof (int),
158 XtOffset(RubikWidget, rubik.currentDirection), XtRString, "-1"},
159 {XtNpractice, XtCBoolean, XtRBoolean, sizeof (Boolean),
160 XtOffset(RubikWidget, rubik.practice), XtRString, "FALSE"},
161 {XtNstart, XtCBoolean, XtRBoolean, sizeof (Boolean),
162 XtOffset(RubikWidget, rubik.started), XtRString, "FALSE"},
163 {XtNselectCallback, XtCCallback, XtRCallback, sizeof (caddr_t),
164 XtOffset(RubikWidget, rubik.select), XtRCallback, NULL}
165 };
166
167 Rubik2DClassRec rubik2dClassRec =
168 {
169 {
170 (WidgetClass) & rubikClassRec, /* superclass */
171 "Rubik2D", /* class name */
172 sizeof (Rubik2DRec), /* widget size */
173 NULL, /* class initialize */
174 NULL, /* class part initialize */
175 FALSE, /* class inited */
176 (XtInitProc) InitializeRubik2D, /* initialize */
177 NULL, /* initialize hook */
178 XtInheritRealize, /* realize */
179 actionsListRubik2D, /* actions */
180 XtNumber(actionsListRubik2D), /* num actions */
181 resourcesRubik2D, /* resources */
182 XtNumber(resourcesRubik2D), /* num resources */
183 NULLQUARK, /* xrm class */
184 TRUE, /* compress motion */
185 TRUE, /* compress exposure */
186 TRUE, /* compress enterleave */
187 TRUE, /* visible interest */
188 NULL, /* destroy */
189 (XtWidgetProc) ResizeRubik2D, /* resize */
190 (XtExposeProc) ExposeRubik2D, /* expose */
191 (XtSetValuesFunc) SetValuesRubik2D, /* set values */
192 NULL, /* set values hook */
193 XtInheritSetValuesAlmost, /* set values almost */
194 NULL, /* get values hook */
195 XtInheritAcceptFocus, /* accept focus */
196 XtVersion, /* version */
197 NULL, /* callback private */
198 defaultTranslationsRubik2D, /* tm table */
199 NULL, /* query geometry */
200 NULL, /* display accelerator */
201 NULL /* extension */
202 },
203 {
204 0 /* ignore */
205 },
206 {
207 0 /* ignore */
208 }
209 };
210
211 WidgetClass rubik2dWidgetClass = (WidgetClass) & rubik2dClassRec;
212
213 static RowNext rotateToRow[MAXFACES] = /*CW to min face */
214 {
215 {1, LEFT, TOP},
216 {0, BOTTOM, RIGHT},
217 {0, RIGHT, BOTTOM},
218 {0, TOP, LEFT},
219 {1, RIGHT, BOTTOM},
220 {0, LEFT, TOP}
221 };
222 static int planeToCube[MAXRECT] =
223 {6, 0, 6, 1, 2, 3, 6, 4, 6, 6, 5, 6};
224 static int cubeToPlane[MAXFACES] =
225 {1, 3, 4, 5, 7, 10};
226
227 static void
InitializeRubik2D(Widget request,Widget renew)228 InitializeRubik2D(Widget request, Widget renew)
229 {
230 Rubik2DWidget w = (Rubik2DWidget) renew;
231
232 w->rubik.dim = 2;
233 ResizeRubik2D(w);
234 }
235
236 static void
ResizeCubie(Rubik2DWidget w)237 ResizeCubie(Rubik2DWidget w)
238 {
239 XPoint flatlength, flatlengthh;
240 int tempLength;
241
242 w->rubik.delta = 3;
243 flatlength.x = w->rubik.sizex + 2 * w->rubik.sizez;
244 flatlength.y = 2 * w->rubik.sizey + 2 * w->rubik.sizez;
245 flatlengthh.x = 2 * w->rubik.sizex + 2 * w->rubik.sizez;
246 flatlengthh.y = w->rubik.sizey + 2 * w->rubik.sizez;
247 w->rubik.vertical = /* w->core.height >= w->core.width */
248 (w->core.height / flatlength.y + w->core.width / flatlength.x <=
249 w->core.height / flatlengthh.y + w->core.width / flatlengthh.x);
250 if (!w->rubik.vertical)
251 flatlength = flatlengthh;
252 tempLength = MIN((w->core.height - 2 * w->rubik.delta - 2) / flatlength.y,
253 (w->core.width - 2 * w->rubik.delta - 2) / flatlength.x);
254 w->rubik2d.cubeLength = MAX(tempLength - w->rubik.delta + 1, 0);
255 w->rubik2d.faceLengthx = w->rubik.sizex * (w->rubik2d.cubeLength +
256 w->rubik.delta - 1);
257 w->rubik2d.faceLengthy = w->rubik.sizey * (w->rubik2d.cubeLength +
258 w->rubik.delta - 1);
259 w->rubik2d.faceLengthz = w->rubik.sizez * (w->rubik2d.cubeLength +
260 w->rubik.delta - 1);
261 w->rubik2d.viewLengthx = w->rubik2d.faceLengthx + w->rubik.delta - 1;
262 w->rubik2d.viewLengthy = w->rubik2d.faceLengthy + w->rubik.delta - 1;
263 w->rubik2d.viewLengthz = w->rubik2d.faceLengthz + w->rubik.delta - 1;
264 }
265
266 static void
ResizeRubik2D(Rubik2DWidget w)267 ResizeRubik2D(Rubik2DWidget w)
268 {
269 ResizeCubie(w);
270 if (w->rubik.vertical) {
271 w->rubik.puzzleSize.x = (w->rubik2d.viewLengthx - 1) +
272 2 * (w->rubik2d.viewLengthz - 1) + w->rubik.delta;
273 w->rubik.puzzleSize.y = 2 * (w->rubik2d.viewLengthy - 1) +
274 2 * (w->rubik2d.viewLengthz - 1) + w->rubik.delta;
275 } else {
276 w->rubik.puzzleSize.x = 2 * (w->rubik2d.viewLengthx - 1) +
277 2 * (w->rubik2d.viewLengthz - 1) + w->rubik.delta;
278 w->rubik.puzzleSize.y = (w->rubik2d.viewLengthy - 1) +
279 2 * (w->rubik2d.viewLengthz - 1) + w->rubik.delta;
280 }
281 w->rubik.puzzleOffset.x = ((int) w->core.width - w->rubik.puzzleSize.x)
282 / 2;
283 w->rubik.puzzleOffset.y = ((int) w->core.height - w->rubik.puzzleSize.y)
284 / 2;
285 ResizePolyhedrons(w);
286 }
287
288 static void
ExposeRubik2D(Widget renew,XEvent * event,Region region)289 ExposeRubik2D(Widget renew, XEvent * event, Region region)
290 {
291 Rubik2DWidget w = (Rubik2DWidget) renew;
292
293 if (w->core.visible) {
294 if (w->rubik.reverse)
295 XFillRectangle(XtDisplay(w), XtWindow(w),
296 w->rubik.inverseGC, 0, 0, w->core.width, w->core.height);
297 DrawFrame(w, w->rubik.puzzleGC);
298 DrawAllPolyhedrons((RubikWidget) w);
299 }
300 }
301
302 static Boolean
SetValuesRubik2D(Widget current,Widget request,Widget renew)303 SetValuesRubik2D(Widget current, Widget request, Widget renew)
304 {
305 Rubik2DWidget c = (Rubik2DWidget) current, w = (Rubik2DWidget) renew;
306 Boolean redraw = False;
307
308 if (w->rubik.sizex != c->rubik.sizex ||
309 w->rubik.sizey != c->rubik.sizey ||
310 w->rubik.sizez != c->rubik.sizez) {
311 ResetPolyhedrons((RubikWidget) w);
312 ResizeRubik2D(w);
313 redraw = True;
314 }
315 if (w->rubik2d.cubeLength != c->rubik2d.cubeLength) {
316 ResizeRubik2D(w);
317 redraw = True;
318 }
319 return (redraw);
320 }
321
322 static void
MoveRubik2DTop(Rubik2DWidget w,XEvent * event,char ** args,int nArgs)323 MoveRubik2DTop(Rubik2DWidget w, XEvent * event, char **args, int nArgs)
324 {
325 MoveRubikInput((RubikWidget) w, event->xbutton.x, event->xbutton.y, TOP,
326 (int) (event->xkey.state & ControlMask));
327 }
328
329 static void
MoveRubik2DLeft(Rubik2DWidget w,XEvent * event,char ** args,int nArgs)330 MoveRubik2DLeft(Rubik2DWidget w, XEvent * event, char **args, int nArgs)
331 {
332 MoveRubikInput((RubikWidget) w, event->xbutton.x, event->xbutton.y, LEFT,
333 (int) (event->xkey.state & ControlMask));
334 }
335
336 static void
MoveRubik2DRight(Rubik2DWidget w,XEvent * event,char ** args,int nArgs)337 MoveRubik2DRight(Rubik2DWidget w, XEvent * event, char **args, int nArgs)
338 {
339 MoveRubikInput((RubikWidget) w, event->xbutton.x, event->xbutton.y, RIGHT,
340 (int) (event->xkey.state & ControlMask));
341 }
342
343 static void
MoveRubik2DBottom(Rubik2DWidget w,XEvent * event,char ** args,int nArgs)344 MoveRubik2DBottom(Rubik2DWidget w, XEvent * event, char **args, int nArgs)
345 {
346 MoveRubikInput((RubikWidget) w, event->xbutton.x, event->xbutton.y, BOTTOM,
347 (int) (event->xkey.state & ControlMask));
348 }
349
350 static void
ResizePolyhedrons(Rubik2DWidget w)351 ResizePolyhedrons(Rubik2DWidget w)
352 {
353 ResizeCubie(w);
354 w->rubik.orientLineLength = w->rubik2d.cubeLength / 4;
355 w->rubik.letterOffset.x = -2;
356 w->rubik.letterOffset.y = 4;
357 }
358
359 static void
FacePosition(Rubik2DWidget w,int faceX,int faceY,int * viewLengthx,int * viewLengthy)360 FacePosition(Rubik2DWidget w, int faceX, int faceY,
361 int *viewLengthx, int *viewLengthy)
362 {
363 int i;
364
365 *viewLengthx = w->rubik.puzzleOffset.x;
366 *viewLengthy = w->rubik.puzzleOffset.y;
367 for (i = 0; i < faceX; i++) {
368 if (i & 1) {
369 *viewLengthx += w->rubik2d.viewLengthx;
370 } else {
371 *viewLengthx += w->rubik2d.viewLengthz;
372 }
373 }
374 for (i = 0; i < faceY; i++) {
375 if (i & 1) {
376 *viewLengthy += w->rubik2d.viewLengthy;
377 } else {
378 *viewLengthy += w->rubik2d.viewLengthz;
379 }
380 }
381 }
382
383 Boolean
SelectPolyhedrons2D(Rubik2DWidget w,int x,int y,int * face,int * position)384 SelectPolyhedrons2D(Rubik2DWidget w, int x, int y, int *face, int *position)
385 {
386 int faceX, faceY, i, j, sizeOfRow, sizeOfColumn, tempLength;
387
388 x -= w->rubik.puzzleOffset.x;
389 y -= w->rubik.puzzleOffset.y;
390 /* faceX = x / w->rubik2d.viewLength; */
391 for (faceX = 0; faceX <= MAXY; faceX++) {
392 if (faceX & 1)
393 tempLength = w->rubik2d.viewLengthx;
394 else
395 tempLength = w->rubik2d.viewLengthz;
396 if (x <= tempLength)
397 break;
398 else
399 x -= tempLength;
400 }
401 /* faceY = y / w->rubik2d.viewLength; */
402 for (faceY = 0; faceY <= MAXY; faceY++) {
403 if (faceY & 1)
404 tempLength = w->rubik2d.viewLengthy;
405 else
406 tempLength = w->rubik2d.viewLengthz;
407 if (y <= tempLength)
408 break;
409 else
410 y -= tempLength;
411 }
412 i = MAX((x - w->rubik.delta) /
413 (w->rubik2d.cubeLength + w->rubik.delta - 1), 0);
414 j = MAX((y - w->rubik.delta) /
415 (w->rubik2d.cubeLength + w->rubik.delta - 1), 0);
416 if ((faceX != 1 && faceY != 1) ||
417 (faceX >= 3 && w->rubik.vertical) ||
418 (faceY >= 3 && !w->rubik.vertical))
419 return False;
420 if (faceX == 3)
421 *face = MAXFACES - 1;
422 else
423 *face = planeToCube[faceX + faceY * MAXX];
424 faceSizes((RubikWidget) w, *face, &sizeOfRow, &sizeOfColumn);
425 if (i >= sizeOfRow)
426 i = sizeOfRow - 1;
427 if (j >= sizeOfColumn)
428 j = sizeOfColumn - 1;
429 if (faceX == 3) {
430 i = sizeOfRow - 1 - i;
431 j = sizeOfColumn - 1 - j;
432 }
433 *position = j * sizeOfRow + i;
434 return True;
435 }
436
437 Boolean
NarrowSelection2D(Rubik2DWidget w,int * face,int * position,int * direction)438 NarrowSelection2D(Rubik2DWidget w, int *face, int *position, int *direction)
439 {
440 if (*face == MAXFACES - 1 && *direction < MAXORIENT && !w->rubik.vertical)
441 *direction = (*direction + HALF) % MAXORIENT;
442 /* Remap to row movement */
443 if (*direction == CW || *direction == CCW) {
444 int i, j, sizeOfRow, sizeOfColumn, newFace;
445
446 newFace = rotateToRow[*face].face;
447 faceSizes((RubikWidget) w, newFace, &sizeOfRow, &sizeOfColumn);
448 *direction = (*direction == CCW) ?
449 (rotateToRow[*face].direction + 2) % MAXORIENT :
450 rotateToRow[*face].direction;
451 if (rotateToRow[*face].sideFace == LEFT ||
452 rotateToRow[*face].sideFace == BOTTOM) {
453 i = sizeOfRow - 1;
454 j = sizeOfColumn - 1;
455 } else {
456 i = j = 0;
457 }
458 *face = newFace;
459 *position = j * sizeOfRow + i;
460 }
461 return True;
462 }
463
464 static void
DrawFrame(Rubik2DWidget w,GC gc)465 DrawFrame(Rubik2DWidget w, GC gc)
466 {
467 int i;
468 XPoint tempLength;
469 XPoint pos[MAXXY + 1], letters;
470
471 tempLength.x = w->rubik.puzzleOffset.x;
472 tempLength.y = w->rubik.puzzleOffset.y;
473 for (i = 0; i <= MAXY; i++) {
474 pos[i] = tempLength;
475 if (i & 1) {
476 tempLength.x += w->rubik2d.viewLengthx;
477 tempLength.y += w->rubik2d.viewLengthy;
478 } else {
479 tempLength.x += w->rubik2d.viewLengthz;
480 tempLength.y += w->rubik2d.viewLengthz;
481 }
482 }
483 XDrawLine(XtDisplay(w), XtWindow(w), gc,
484 pos[1].x, pos[0].y, pos[2].x, pos[0].y);
485 XDrawLine(XtDisplay(w), XtWindow(w), gc,
486 pos[3].x, pos[1].y, pos[3].x, pos[2].y);
487 XDrawLine(XtDisplay(w), XtWindow(w), gc,
488 pos[1].x, pos[3].y, pos[2].x, pos[3].y);
489 XDrawLine(XtDisplay(w), XtWindow(w), gc,
490 pos[0].x, pos[1].y, pos[0].x, pos[2].y);
491 letters.x = (pos[0].x + pos[1].x) / 2 - w->rubik.delta;
492 letters.y = (pos[0].y + pos[1].y) / 2;
493 XDrawString(XtDisplay(w), XtWindow(w), gc,
494 (int) (letters.x + 5 * w->rubik.letterOffset.x),
495 (int) (letters.y + w->rubik.letterOffset.y), "Front", 5);
496 letters.x = (pos[2].x + pos[3].x) / 2 - w->rubik.delta;
497 letters.y = (pos[2].y + pos[3].y) / 2;
498 XDrawString(XtDisplay(w), XtWindow(w), gc,
499 (int) (letters.x + 4 * w->rubik.letterOffset.x),
500 (int) (letters.y + w->rubik.letterOffset.y), "Back", 4);
501 if (w->rubik.vertical) {
502 XDrawLine(XtDisplay(w), XtWindow(w), gc,
503 pos[1].x, pos[0].y, pos[1].x, pos[4].y);
504 XDrawLine(XtDisplay(w), XtWindow(w), gc,
505 pos[2].x, pos[0].y, pos[2].x, pos[4].y);
506 XDrawLine(XtDisplay(w), XtWindow(w), gc,
507 pos[0].x, pos[1].y, pos[3].x, pos[1].y);
508 XDrawLine(XtDisplay(w), XtWindow(w), gc,
509 pos[0].x, pos[2].y, pos[3].x, pos[2].y);
510 XDrawLine(XtDisplay(w), XtWindow(w), gc,
511 pos[1].x, pos[4].y, pos[2].x, pos[4].y);
512 } else {
513 XDrawLine(XtDisplay(w), XtWindow(w), gc,
514 pos[0].x, pos[1].y, pos[4].x, pos[1].y);
515 XDrawLine(XtDisplay(w), XtWindow(w), gc,
516 pos[0].x, pos[2].y, pos[4].x, pos[2].y);
517 XDrawLine(XtDisplay(w), XtWindow(w), gc,
518 pos[1].x, pos[0].y, pos[1].x, pos[3].y);
519 XDrawLine(XtDisplay(w), XtWindow(w), gc,
520 pos[2].x, pos[0].y, pos[2].x, pos[3].y);
521 XDrawLine(XtDisplay(w), XtWindow(w), gc,
522 pos[4].x, pos[1].y, pos[4].x, pos[2].y);
523 }
524 }
525
526 void
DrawSquare2D(Rubik2DWidget w,int face,int position,int offset)527 DrawSquare2D(Rubik2DWidget w, int face, int position, int offset)
528 {
529 GC faceGC, borderGC;
530 int dx, dy, orient, i, j, sizeOfRow, sizeOfColumn;
531
532 faceSizes((RubikWidget) w, face, &sizeOfRow, &sizeOfColumn);
533 i = position % sizeOfRow;
534 j = position / sizeOfRow;
535 orient = w->rubik.cubeLoc[face][position].rotation;
536 if (w->rubik.vertical || face != MAXFACES - 1) {
537 FacePosition(w,
538 cubeToPlane[face] % MAXX, cubeToPlane[face] / MAXX,
539 &dx, &dy);
540 dx += i * (w->rubik2d.cubeLength + w->rubik.delta - 1);
541 dy += j * (w->rubik2d.cubeLength + w->rubik.delta - 1);
542 } else {
543 FacePosition(w,
544 cubeToPlane[face] / MAXX, cubeToPlane[face] % MAXX,
545 &dx, &dy);
546 dx += (sizeOfRow - 1 - i) *
547 (w->rubik2d.cubeLength + w->rubik.delta - 1);
548 dy += (sizeOfColumn - 1 - j) *
549 (w->rubik2d.cubeLength + w->rubik.delta - 1);
550 orient = (orient + HALF) % STRT;
551 }
552 dx += w->rubik.delta - 1;
553 dy += w->rubik.delta - 1;
554 if (offset) {
555 borderGC = w->rubik.faceGC[(int) w->rubik.cubeLoc[face][position].face];
556 if (w->rubik.depth < 2 || w->rubik.mono) {
557 faceGC = w->rubik.inverseGC;
558 } else {
559 faceGC = w->rubik.borderGC;
560 }
561 } else {
562 faceGC = w->rubik.faceGC[(int) w->rubik.cubeLoc[face][position].face];
563 borderGC = w->rubik.borderGC;
564 }
565 XFillRectangle(XtDisplay(w), XtWindow(w),
566 faceGC, dx, dy, w->rubik2d.cubeLength, w->rubik2d.cubeLength);
567 XDrawRectangle(XtDisplay(w), XtWindow(w),
568 borderGC, dx, dy, w->rubik2d.cubeLength, w->rubik2d.cubeLength);
569 if (w->rubik.depth < 2 || w->rubik.mono) {
570 int letterX, letterY;
571 char buf[2];
572
573 (void) sprintf(buf, "%c",
574 w->rubik.faceName[(int) w->rubik.cubeLoc[face][position].face][0]);
575 letterX = dx + w->rubik2d.cubeLength / 2 + w->rubik.letterOffset.x;
576 letterY = dy + w->rubik2d.cubeLength / 2 + w->rubik.letterOffset.y;
577 if (offset) {
578 borderGC = w->rubik.borderGC;
579 } else {
580 borderGC = w->rubik.inverseGC;
581 }
582 XDrawString(XtDisplay(w), XtWindow(w), borderGC,
583 letterX, letterY, buf, 1);
584 }
585 if (w->rubik.orient)
586 DrawOrientLine(w, orient, dx, dy, borderGC, offset);
587 }
588
589 static void
DrawOrientLine(Rubik2DWidget w,int orient,int dx,int dy,GC borderGC,int offset)590 DrawOrientLine(Rubik2DWidget w, int orient, int dx, int dy, GC borderGC, int offset)
591 {
592 switch (orient) {
593 case TOP:
594 XDrawLine(XtDisplay(w), XtWindow(w), borderGC,
595 dx + w->rubik2d.cubeLength / 2,
596 dy,
597 dx + w->rubik2d.cubeLength / 2,
598 dy + w->rubik.orientLineLength);
599 return;
600 case RIGHT:
601 XDrawLine(XtDisplay(w), XtWindow(w), borderGC,
602 dx + w->rubik2d.cubeLength,
603 dy + w->rubik2d.cubeLength / 2,
604 dx + w->rubik2d.cubeLength - w->rubik.orientLineLength -
605 1,
606 dy + w->rubik2d.cubeLength / 2);
607 return;
608 case BOTTOM:
609 XDrawLine(XtDisplay(w), XtWindow(w), borderGC,
610 dx + w->rubik2d.cubeLength / 2,
611 dy + w->rubik2d.cubeLength,
612 dx + w->rubik2d.cubeLength / 2,
613 dy + w->rubik2d.cubeLength - w->rubik.orientLineLength -
614 1);
615 return;
616 case LEFT:
617 XDrawLine(XtDisplay(w), XtWindow(w), borderGC,
618 dx,
619 dy + w->rubik2d.cubeLength / 2,
620 dx + w->rubik.orientLineLength,
621 dy + w->rubik2d.cubeLength / 2);
622 return;
623 default:
624 (void) printf("DrawOrientLine: orient %d\n", orient);
625 }
626 }
627