ref: cec6a8217fa2ae90a72226959e215b663c88bc41
dir: /plan9.c/
#include <npe.h> #include <draw.h> #include <event.h> #undef PI #include "puzzles.h" #ifdef COMBINED #error Plan 9 should not be COMBINED #endif struct frontend { Image *image; midend *me; Image *background; Image **colors; int ncolors; Point ZP; int topbarh; }; frontend *fe; void frontend_default_colour(frontend *fe, float *output) { output[0] = .9; output[1] = .9; output[2] = .9; } void get_random_seed(void **randseed, int *randseedsize) { long *t = malloc(sizeof(long)); assert(t); time(t); *randseed = (void*)t; *randseedsize = sizeof(long); } void deactivate_timer(frontend *fe) { } void activate_timer(frontend *fe) { } void fatal(const char *fmt, ...) { va_list ap; fprint(2, "fatal error: "); va_start(ap, fmt); vfprint(2, fmt, ap); va_end(ap); fprint(2, "\n"); sysfatal("error"); } #ifdef DEBUGGING void debug_printf(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprint(1, fmt, ap); va_end(ap); } #endif void usage(void) { fprint(2, "usage: %s [-ho] [--options]\n", argv0); exits(nil); } static void p9_draw_text(void *handle, int x, int y, int fonttype, int fontsize, int align, int color, const char *text) { frontend *fe = (frontend*)handle; string(fe->image, addpt(fe->ZP, Pt(x, y)), fe->colors[color], ZP, font, text); } static void p9_draw_rect(void *handle, int x, int y, int w, int h, int color) { frontend *fe = (frontend*)handle; draw(fe->image, rectaddpt(Rect(x, y, x+w, y+h), fe->ZP), fe->colors[color], nil, ZP); } static void p9_draw_line(void *handle, int x1, int y1, int x2, int y2, int color) { frontend *fe = (frontend*)handle; line(fe->image, addpt(fe->ZP, Pt(x1, y1)), addpt(fe->ZP, Pt(x2, y2)), Endsquare, Endsquare, 1, fe->colors[color], ZP); } static void p9_draw_thick_line(void *handle, float thickness, float x1, float y1, float x2, float y2, int color) { frontend *fe = (frontend*)handle; line(fe->image, addpt(fe->ZP, Pt(x1, y1)), addpt(fe->ZP, Pt(x2, y2)), Endsquare, Endsquare, thickness, fe->colors[color], ZP); } static void p9_draw_poly(void *handle, const int *coords, int npoints, int fillcolor, int outlinecolor) { Point *points; frontend *fe = (frontend*)handle; points = malloc(npoints * sizeof(Point)); for (int i = 0; i < npoints; i++) { points[i].x = coords[i*2+0] + fe->ZP.x; points[i].y = coords[i*2+1] + fe->ZP.y; } if (fillcolor > 0) fillpoly(fe->image, points, npoints, 0, fe->colors[fillcolor], fe->ZP); if (outlinecolor > 0) poly(fe->image, points, npoints, Endsquare, Endsquare, 1, fe->colors[outlinecolor], fe->ZP); free(points); } static void p9_draw_circle(void *handle, int cx, int cy, int radius, int fillcolor, int outlinecolor) { frontend *fe = (frontend*)handle; Point c = addpt(fe->ZP, Pt(cx, cy)); fillellipse(fe->image, c, radius, radius, fe->colors[fillcolor], ZP); ellipse(fe->image, c, radius, radius, 0, fe->colors[outlinecolor], ZP); } static void p9_draw_update(void *handle, int x, int y, int w, int h) { } static void p9_clip(void *handle, int x, int y, int w, int h) { } static void p9_unclip(void *handle) { } static void p9_start_draw(void *handle) { } static void p9_end_draw(void *handle) { } static void p9_status_bar(void *handle, const char *text) { frontend *fe = (frontend*)handle; draw(fe->image, Rect(fe->ZP.x+10, fe->image->r.max.y-20, fe->image->r.max.x, fe->image->r.max.y), fe->background, nil, ZP); string(fe->image, Pt(fe->ZP.x+10, fe->image->r.max.y-20), display->black, ZP, font, text); } static blitter* p9_blitter_new(void *handle, int w, int h) { return nil; } static void p9_blitter_free(void *handle, blitter *bl) { } static void p9_blitter_save(void *handle, blitter *bl, int x, int y) { } static void p9_blitter_load(void *handle, blitter *bl, int x, int y) { } static const drawing_api p9_drawing = { p9_draw_text, p9_draw_rect, p9_draw_line, p9_draw_poly, p9_draw_circle, p9_draw_update, p9_clip, p9_unclip, p9_start_draw, p9_end_draw, p9_status_bar, p9_blitter_new, p9_blitter_free, p9_blitter_save, p9_blitter_load, nil, nil, nil, nil, nil, nil, nil, nil, /* {begin,end}_{doc,page,puzzle}, line_width, line_dotted */ nil, /* text_fallback */ #ifdef NO_THICK_LINE nil, #else p9_draw_thick_line, #endif }; static int rgb2col(int r, int g, int b) { return (r<<24) | (g<<16) | (b<<8) | 0xFF; } static frontend* new_window(void) { frontend *fe; fe = mallocz(sizeof(frontend), 1); if (!fe) sysfatal("error: out of memory!"); fe->me = midend_new(fe, &thegame, &p9_drawing, fe); return fe; } void initfe(frontend *fe) { float *colors; int ncolors; int r, g, b; int col; float bgcol[3]; fe->topbarh = 20; fe->image = screen; fe->ZP = screen->r.min; fe->ZP.y += fe->topbarh; frontend_default_colour(fe, bgcol); fe->background = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, rgb2col(bgcol[0]*255., bgcol[1]*255., bgcol[2]*255.)); colors = midend_colours(fe->me, &ncolors); fe->colors = mallocz(ncolors * sizeof(Image*), 1); for (int i = 0; i < ncolors; i++) { r = colors[i*3+0] * 255.; g = colors[i*3+1] * 255.; b = colors[i*3+2] * 255.; fe->colors[i] = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, rgb2col(r, g, b)); } free(colors); } void resize(void) { int x, y; x = screen->r.max.x - screen->r.min.x; y = screen->r.max.y - screen->r.min.y; midend_size(fe->me, &x, &y, 1, 1.); } void redrawui(void) { Point to = fe->ZP; to.x = fe->image->r.max.x; line(fe->image, fe->ZP, to, Endsquare, Endsquare, 0, display->black, ZP); } void eresized(int new) { if (new && getwindow(display, Refnone) < 0) { sysfatal("can't reattach to window: %r"); } fe->image = screen; fe->ZP = screen->r.min; fe->ZP.y += fe->topbarh; draw(screen, screen->r, fe->background, nil, ZP); resize(); midend_redraw(fe->me); redrawui(); } void keyboardev(int c, Event *ev) { switch (c) { case 'q': case 127: /* DEL */ exits(nil); break; default: if (c >= 0 && midend_process_key(fe->me, 0, 0, c) == PKR_QUIT) { exits(nil); } } } void printoptions(config_item *c) { char *t; char *s = nil, *cnames[16], *ckws[16]; int n = 0, m; config_item *cfg = midend_get_config(fe->me, CFG_PREFS, &t); print("Options:\n"); while (cfg->type != C_END) { switch (cfg->type) { case C_STRING: s = cfg->u.string.sval; break; case C_BOOLEAN: s = cfg->u.boolean.bval ? "1" : "0"; break; case C_CHOICES: print(" Choices:\n"); n = getfields(cfg->u.choices.choicenames, cnames, 16, 1, ":"); m = getfields(cfg->u.choices.choicekws, ckws, 16, 1, ":"); assert(n == m && cfg->u.choices.selected < n); s = ckws[cfg->u.choices.selected]; break; } print("--%s=%s\n %s\n", cfg->kw, s, cfg->name); if (cfg->type == C_CHOICES) { print(" Choices:\n"); for (int i = 0; i < n; i++) { print(" %s: %s\n", ckws[i], cnames[i]); } } cfg++; } } void parseoption(config_item *cfg, char *keyval) { char *arg[2]; int n; n = getfields(keyval, arg, 2, 1, "="); if (n != 2) usage(); // exits while (cfg && cfg->type != C_END) if (strcmp(cfg->kw, arg[0]) != 0) cfg++; if (!cfg || cfg->type == C_END) { fprint(2, "no valid option\n"); return; } print("%s : %s\n", cfg->kw, cfg->name); return; switch (cfg->type) { case C_STRING: cfg->u.string.sval = arg[1]; print("is string"); break; case C_BOOLEAN: n = atoi(arg[1]); print("is boolean"); cfg->u.boolean.bval = n ? 1 : 0; break; case C_CHOICES: // TODO print("is choices"); fprint(2, "not implemented yet!\n"); break; case C_END: default: print("not found"); break; } } void hittopbar(int x, int buttons) { if (buttons&1) { print("left mouse\n"); } else if (buttons&2) { print("middle mouse\n"); } else if (buttons&4) { print("right mouse\n"); } else /* no button at all */ return; print("pos: %d\n", x); } void main(int argc, char **argv) { Event ev; int e; int x, y; char *s; int doprintoptions = 0; char *wintitle; config_item *cfg; int changedprefs = 0; fe = new_window(); wintitle = nil; cfg = midend_get_config(fe->me, CFG_SETTINGS, &wintitle); ARGBEGIN{ case 'h': usage(); break; case 'o': doprintoptions++; break; case '-': parseoption(cfg, ARGF()); changedprefs++; break; }ARGEND; if (changedprefs) { s = midend_set_config(fe->me, CFG_SETTINGS, cfg); if (s) { fprint(2, "error: %s\n", s); exits("error"); } } if (doprintoptions) { printoptions(cfg); exits(nil); } if (initdraw(nil, nil, wintitle) < 0) { sysfatal("initdraw failed: %r"); } initfe(fe); midend_new_game(fe->me); einit(Emouse|Ekeyboard); eresized(0); for (;;) { switch (event(&ev)) { case Emouse: x = ev.mouse.xy.x - fe->ZP.x; y = ev.mouse.xy.y - fe->ZP.y; if (y < fe->topbarh) { hittopbar(x, ev.mouse.buttons); } if (ev.mouse.buttons&1) { midend_process_key(fe->me, x, y, LEFT_BUTTON); } else if (ev.mouse.buttons&2) { midend_process_key(fe->me, x, y, MIDDLE_BUTTON); } else if (ev.mouse.buttons&4) { midend_process_key(fe->me, x, y, RIGHT_BUTTON); } case Ekeyboard: keyboardev(ev.kbdc, &ev); } } }