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