/* * X11 GUI for slide puzzle game * Copyright © 2022 Nick Bowler * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include "motif.h" /* TODO user-selectable colours */ static const char * const colours[][3] = { /*primary bottom top */ "#8d2e28", "#6a1b17", "#a14842", /* red */ "#b46e28", "#924a16", "#c7904f", /* orange */ "#d8b740", "#c59f39", "#e2c65d", /* yellow */ "#286428", "#194719", "#4e874e", /* green */ "#003471", "#001f4f", "#00528b", /* blue */ "#dcdcdc", "#c0c0c0", "#eaeaea", /* white */ }; static void init_colours(struct app_state *state, Screen *screen) { Display *display = DisplayOfScreen(screen); Colormap cmap = DefaultColormapOfScreen(screen); XColor colour, junk; unsigned i, j; for (j = 0; j < COLOUR_MAX; j++) { for (i = 0; i < TILE_MAX-1; i++) { XAllocNamedColor(display, cmap, colours[i][j], &colour, &junk); state->tile_colour[i][j] = colour.pixel; } } } void x11_initialize(struct app_state *state, Screen *screen) { Display *display = DisplayOfScreen(screen); Window root = RootWindowOfScreen(screen); Colormap cmap = DefaultColormapOfScreen(screen); XGCValues gcv; init_colours(state, screen); gcv.line_width = 1; state->tile_gc = XCreateGC(display, root, GCLineWidth, &gcv); } static void draw_tile(struct app_state *state, Display *display, Drawable d, int tile, int gx, int gy, Dimension tw, Dimension th) { int tx = gx * tw, ty = gy * th; XSegment topshadow[] = { { tx, ty, tx, ty+th }, { tx+1, ty, tx+tw, ty }, { tx+1, ty+1, tx+1, ty+th-1 }, { tx+2, ty+1, tx+tw-1, ty+1 } }; XSegment bottomshadow[] = { { tx+1, ty+th-1, tx+tw, ty+th-1 }, { tx+tw-1, ty+th-1, tx+tw-1, ty+1 }, { tx+2, ty+th-2, tx+tw-1, ty+th-2 }, { tx+tw-2, ty+th-2, tx+tw-2, ty+2 } }; XSetForeground(display, state->tile_gc, state->tile_colour[tile-1][COLOUR_LIGHT]); XDrawSegments(display, d, state->tile_gc, topshadow, XtNumber(topshadow)); XSetForeground(display, state->tile_gc, state->tile_colour[tile-1][COLOUR_DARK]); XDrawSegments(display, d, state->tile_gc, bottomshadow, XtNumber(bottomshadow)); XSetForeground(display, state->tile_gc, state->tile_colour[tile-1][COLOUR_PRIMARY]); XFillRectangle(display, d, state->tile_gc, tx+2, ty+2, tw-4, th-4); } static void redraw_tile(struct app_state *state, Display *display, Drawable d, uint_fast32_t bit0, uint_fast32_t bit1, uint_fast32_t bit2, int x, int y, Dimension w, Dimension h) { uint_fast32_t pos = board_position(x, y); unsigned char tile = 0; if (bit0 & pos) tile |= 1; if (bit1 & pos) tile |= 2; if (bit2 & pos) tile |= 4; assert(tile < TILE_MAX); if (tile == TILE_EMPTY) { XClearArea(display, d, x*w, y*h, w, h, 0); } else { draw_tile(state, display, d, tile, x, y, w, h); } } void x11_redraw_goal(struct app_state *state) { Display *display = XtDisplay(state->goal); Window goal = XtWindow(state->goal); Dimension w, h; int i; XtVaGetValues(state->goal, XmNwidth, &w, XmNheight, &h, (char *)NULL); w /= 3; h /= 3; for (i = 0; i < 9; i++) { uint_least16_t *gp = state->board.goal; redraw_tile(state, display, goal, gp[0], gp[1], gp[2], i%3, i/3, w, h); } } void x11_redraw_game(struct app_state *state) { Display *display = XtDisplay(state->goal); Window game = XtWindow(state->game); Dimension w, h; int i; XtVaGetValues(state->game, XmNwidth, &w, XmNheight, &h, (char *)NULL); w /= 5; h /= 5; for (i = 0; i < 25; i++) { uint_least32_t *gp = state->board.game; redraw_tile(state, display, game, gp[0], gp[1], gp[2], i%5, i/5, w, h); } }