ref: 7d6a4f26f918097cd7bbaec474ceafa986940eb4
parent: 699e5d2bb6e9c2daea77457f0b0aea19cc4b1498
author: rodri <[email protected]>
date: Mon Aug 26 10:16:57 EDT 2024
solar: show an info box when clicking on a planet.
--- a/solar.c
+++ b/solar.c
@@ -36,7 +36,6 @@
Scambx, Scamby, Scambz,
Sfps,
Sframes,
- Splanet,
Se
};
@@ -54,6 +53,7 @@
typedef struct HReq HReq;
typedef struct Cmdbut Cmdbut;
typedef struct Cmdbox Cmdbox;
+typedef struct Infobox Infobox;
struct Planet
{
@@ -92,6 +92,13 @@
ulong ncmds;
};
+struct Infobox
+{
+ char *title;
+ char **items;
+ Image *image;
+};
+
Rune keys[Ke] = {
[K↑] = Kup,
[K↓] = Kdown,
@@ -135,6 +142,7 @@
char datefmt[] = "YYYY-MM-DD";
Rectangle viewr, cmdr;
Cmdbox cmdbox;
+Infobox *infobox;
Image *screenb;
Mousectl *mctl;
Keyboardctl *kctl;
@@ -195,6 +203,106 @@
}
static void
+refreshinfobox(Infobox *info)
+{
+ static Point pad = {2, 2};
+ static Image *tbg, *tfg, *bg[2], *fg;
+ Rectangle tr, cr, rr; /* title, content and row rects */
+ char **s;
+ int i;
+
+ assert(info != nil && info->image != nil && info->items != nil);
+
+ if(tbg == nil){
+ tbg = eallocimage(display, UR, RGBA32, 1, 0x4444887F);
+ tfg = display->white;
+ bg[0] = eallocimage(display, UR, RGBA32, 1, 0xEEEEEEEE);
+ bg[1] = eallocimage(display, UR, RGBA32, 1, 0xAAAAAAAA);
+ fg = display->black;
+ }
+
+ tr = info->image->r;
+ tr.max.y = tr.min.y + 2*font->height;
+
+ draw(info->image, tr, tbg, nil, ZP);
+ string(info->image, addpt(tr.min, Pt(Dx(tr)/2 - stringwidth(font, info->title)/2,font->height/2)),
+ tfg, ZP, font, info->title);
+
+ cr = info->image->r;
+ cr.min.y = tr.max.y;
+
+ draw(info->image, cr, bg[1], nil, ZP);
+
+ rr.min = addpt(cr.min, pad);
+ rr.max = subpt(cr.max, pad);
+ rr.max.y = rr.min.y + font->height+4;
+
+ for(s = info->items, i = 0; *s != nil; s++, i ^= 1){
+ draw(info->image, rr, bg[i], nil, ZP);
+ string(info->image, rr.min, fg, ZP, font, *s);
+ rr = rectaddpt(rr, Pt(0,Dy(rr)));
+ }
+
+ border(info->image, info->image->r, 1, tbg, ZP);
+}
+
+static Infobox *
+mkplanetinfobox(Planet *p, Rectangle r)
+{
+ enum { ID, POS, RADIUS, NITEMS };
+ Infobox *info;
+ char **items, buf[256];
+ int i;
+
+ if(p == nil || badrect(r))
+ return nil;
+
+ items = emalloc((NITEMS + 1)*sizeof(*items));
+ for(i = 0; i < NITEMS; i++){
+ switch(i){
+ case ID: snprint(buf, sizeof buf, "id: %d", p->id); break;
+ case POS: snprint(buf, sizeof buf, "position (in km): %V", p->body->p); break;
+ case RADIUS: snprint(buf, sizeof buf, "radius (in km): %g", p->scale); break;
+ }
+ items[i] = strdup(buf);
+ if(items[i] == nil)
+ sysfatal("strdup: %r");
+ }
+ items[i] = nil;
+
+ info = emalloc(sizeof *info);
+ memset(info, 0, sizeof *info);
+ info->title = p->name;
+ info->items = items;
+ info->image = eallocimage(display, r, RGBA32, 0, DTransparent);
+ refreshinfobox(info);
+ return info;
+}
+
+static void
+freeinfobox(Infobox *info)
+{
+ char **s;
+
+ if(info == nil)
+ return;
+
+ freeimage(info->image);
+ for(s = info->items; *s != nil; s++)
+ free(*s);
+ free(info);
+}
+
+static void
+drawinfobox(Image *dst, Infobox *info)
+{
+ if(info == nil)
+ return;
+
+ draw(dst, rectaddpt(info->image->r, dst->r.min), info->image, nil, info->image->r.min);
+}
+
+static void
selectplanet(Planet *p)
{
static Planet *oldp;
@@ -211,6 +319,10 @@
esel = scene->getent(scene, "selection");
if(esel != nil)
scene->delent(scene, esel);
+ lockdisplay(display);
+ freeinfobox(infobox);
+ infobox = nil;
+ unlockdisplay(display);
if(p == nil)
return;
@@ -219,6 +331,10 @@
esel = newentity("selection", msel);
esel->RFrame3 = e->RFrame3;
+ lockdisplay(display);
+ infobox = mkplanetinfobox(p, Rpt(subpt(viewr.max, Pt(400,200)), viewr.max));
+ unlockdisplay(display);
+
memset(&aabb, 0, sizeof aabb);
for(i = 0; i < e->mdl->nprims; i++)
for(j = 0; j < e->mdl->prims[i].type+1; j++){
@@ -427,7 +543,6 @@
!camera->stats.min? 0: 1e9/camera->stats.min,
!camera->stats.v? 0: 1e9/camera->stats.v);
snprint(stats[Sframes], sizeof(stats[Sframes]), "frame %llud", camera->stats.nframes);
- snprint(stats[Splanet], sizeof(stats[Splanet]), "%s", selplanet == nil? "": selplanet->name);
for(i = 0; i < Se; i++)
stringbg(screen, addpt(screen->r.min, Pt(10,10 + i*font->height)), display->black, ZP, font, stats[i], display->white, ZP);
}
@@ -440,6 +555,7 @@
lockdisplay(display);
draw(screen, rectaddpt(viewr, screen->r.min), screenb, nil, ZP);
draw(screen, rectaddpt(cmdbox.r, screen->r.min), display->white, nil, ZP);
+ drawinfobox(screen, infobox);
for(i = 0; i < cmdbox.ncmds; i++){
border(screen, rectaddpt(cmdbox.cmds[i].r, screen->r.min), 1, display->black, ZP);
string(screen, addpt(screen->r.min, addpt(cmdbox.cmds[i].r.min, Pt(Cmdpadding,Cmdpadding))), display->black, ZP, font, cmdbox.cmds[i].label);