shithub: battleship

Download patch

ref: 33de2d046acfc7ee42fb71b1804b091f671b098a
parent: a99916512365d68d130c7dfdb3f7ac5e2e0bbe8a
author: rodri <rgl@antares-labs.eu>
date: Wed Sep 20 09:15:48 EDT 2023

more work on the menulist of matches.

--- a/bts.c
+++ b/bts.c
@@ -80,7 +80,7 @@
 Ship *curship;
 int layoutdone;
 Point2 lastshot;
-Matchlist matchlist;
+Menulist *matches;
 
 struct {
 	int state;
@@ -122,29 +122,6 @@
 	return np;
 }
 
-void
-addmatch(Mlist *m, int id, char *title)
-{
-	m->entries = erealloc(m->entries, ++m->nentries * sizeof *m->entries);
-	m->entries[m->nentries-1] = (Mentry){id, title};
-}
-
-void
-freematchlist(Mlist *m)
-{
-	int i;
-
-	if(m->entries == nil)
-		return;
-
-	for(i = 0; i < m->nentries; i++)
-		free(m->entries[i].title);
-	free(m->entries);
-	m->entries = nil;
-	m->nentries = 0;
-	m->filling = 0;
-}
-
 int
 rectXarmada(Rectangle r)
 {
@@ -290,52 +267,6 @@
 }
 
 void
-drawmatchlist(Image *dst)
-{
-	Rectangle r, scrollr;
-	static char title[] = "ongoing matches";
-	static char nomatches[] = "no matches";
-	int i;
-
-	USED(scrollr);
-
-	if(debug){
-		fprint(2, "matchlist entries %p nentries %d filling %d\n", matchlist.entries, matchlist.nentries, matchlist.filling);
-		for(i = 0; i < matchlist.nentries; i++)
-			fprint(2, "match id %d title %s\n", matchlist.entries[i].id, matchlist.entries[i].title);
-	}
-
-	if(matchlist.filling)
-		return;
-
-	enum {
-		Vspace = 2,
-		Scrollwidth = 10,
-		Maxvisitems = 5,
-	};
-	r.min = Pt(SCRW/2 - stringwidth(font, title)/2, 14*font->height);
-	r.max = addpt(r.min, Pt(stringwidth(font, title), font->height+Vspace));
-	for(i = 0; i < matchlist.nentries; i++)
-		if(stringwidth(font, matchlist.entries[i].title) > Dx(r))
-			r.max.x = r.min.x + stringwidth(font, matchlist.entries[i].title);
-
-	draw(dst, r, display->white, nil, ZP);
-	string(dst, r.min, display->black, ZP, font, title);
-	for(i = 0; i < matchlist.nentries; i++){
-		r.min.y += font->height+Vspace;
-		r.max.y = r.min.y + font->height+Vspace;
-		draw(dst, r, display->white, nil, ZP);
-		string(dst, r.min, display->black, ZP, font, matchlist.entries[i].title);
-	}
-	if(i == 0){
-		r.min.y += font->height+Vspace;
-		r.max.y = r.min.y + font->height+Vspace;
-		draw(dst, r, display->white, nil, ZP);
-		string(dst, r.min, display->black, ZP, font, nomatches);
-	}
-}
-
-void
 drawinfo(Image *dst)
 {
 	static Image *c;
@@ -405,7 +336,7 @@
 	case Waiting0:
 		drawtitle(screenb);
 		drawgameoptions(screenb);
-		drawmatchlist(screenb);
+		matches->draw(matches, screenb);
 		break;
 	default:
 		drawboard(screenb, &alienboard);
@@ -803,16 +734,13 @@
 			chanprint(egress, "id %s\n", uid);
 		else if(nf == 1 && strcmp(f[0], "queued") == 0)
 			game.state = Ready;
-		else if(!matchlist.filling && nf == 1 && strcmp(f[0], "matches") == 0){
-			if(matchlist.nentries > 0)
-				freematchlist(&matchlist);
-			matchlist.filling++;
-		}else if(matchlist.filling && nf == 3)
-			addmatch(&matchlist, strtoul(f[0], nil, 10), smprint("%s vs %s", f[1], f[2]));
-		else if(matchlist.filling && nf == 1 && strcmp(f[0], "end") == 0)
-			matchlist.filling--;
-		else if(nf == 2 && strcmp(f[0], "no") == 0 && strcmp(f[1], "matches") == 0)
-			freematchlist(&matchlist);
+		else if(!matches->filling && nf == 1 && strcmp(f[0], "matches") == 0){
+			matches->clear(matches);
+			matches->filling = 1;
+		}else if(matches->filling && nf == 3)
+			matches->add(matches, strtoul(f[0], nil, 10), smprint("%s vs %s", f[1], f[2]));
+		else if(matches->filling && nf == 1 && strcmp(f[0], "end") == 0)
+			matches->filling = 0;
 		break;
 	case Ready:
 		if(nf == 1 && strcmp(f[0], "layout") == 0){
@@ -976,6 +904,7 @@
 	inittiles();
 	initboards();
 	initarmada();
+	matches = newmenulist(14*font->height, "ongoing matches");
 	game.state = Waiting0;
 	csetcursor(mctl, &patrolcursor);
 
--- a/btsd.c
+++ b/btsd.c
@@ -234,14 +234,10 @@
 						sendp(playerq, my);
 					else if(nf == 1 && strcmp(f[0], "watch") == 0){
 						rlock(&theaterlk);
-						if(theater.next == &theater)
-							chanprint(my->io.out, "no matches\n");
-						else{
-							chanprint(my->io.out, "matches\n");
-							for(m = theater.next; m != &theater; m = m->next)
-								chanprint(my->io.out, "%d %s %s\n", m->id, m->pl[0]->name, m->pl[1]->name);
-							chanprint(my->io.out, "end\n");
-						}
+						chanprint(my->io.out, "matches\n");
+						for(m = theater.next; m != &theater; m = m->next)
+							chanprint(my->io.out, "%d %s %s\n", m->id, m->pl[0]->name, m->pl[1]->name);
+						chanprint(my->io.out, "end\n");
 						runlock(&theaterlk);
 					}else if(nf == 2 && strcmp(f[0], "watch") == 0){
 						mid = strtoul(f[1], nil, 10);
--- a/dat.h
+++ b/dat.h
@@ -108,7 +108,7 @@
 
 typedef struct Mentry Mentry;
 typedef struct Mlist Mlist;
-typedef struct Matchlist Matchlist;
+typedef struct Menulist Menulist;
 
 struct Mentry
 {
@@ -123,8 +123,15 @@
 	int filling;
 };
 
-struct Matchlist
+struct Menulist
 {
 	Mlist;
-	int selected;	/* [-1,nitems) where -1 is none */
+	char *title;
+	Rectangle r, sr;	/* content and scroll rects */
+	int high;		/* [-1,nitems) where -1 is none */
+
+	void (*add)(Menulist*, int, char*);
+	void (*clear)(Menulist*);
+	void (*update)(Menulist*, Mousectl*);
+	void (*draw)(Menulist*, Image*);
 };
--- a/fns.h
+++ b/fns.h
@@ -21,3 +21,10 @@
 int shiplen(int);
 char *shipname(int);
 char *statename(int);
+int max(int, int);
+
+/*
+ * menulist
+ */
+Menulist *newmenulist(int, char*);
+void delmenulist(Menulist*);
--- /dev/null
+++ b/menulist.c
@@ -1,0 +1,131 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <draw.h>
+#include <mouse.h>
+#include <cursor.h>
+#include <keyboard.h>
+#include <geometry.h>
+#include "dat.h"
+#include "fns.h"
+
+enum {
+	Menuborder = 2,
+	Vspace = 2,
+	Scrollwidth = 10,
+	Maxvisitems = 5,
+};
+static char none[] = "none";
+
+
+static void
+menulist_add(Menulist *ml, int id, char *title)
+{
+	Mentry e = {id, title};
+	int ew;
+
+	ml->entries = erealloc(ml->entries, ++ml->nentries * sizeof *ml->entries);
+	ml->entries[ml->nentries-1] = e;
+
+	if((ew = stringwidth(font, e.title)) > Dx(ml->r)){
+		ml->r.min.x = SCRW/2 - ew/2;
+		ml->r.max.x = ml->r.min.x + ew;
+	}
+	if(ml->nentries > 1)
+		ml->r.max.y += font->height+Vspace;
+}
+
+static void
+menulist_clear(Menulist *ml)
+{
+	int i, w;
+
+	if(ml->entries == nil)
+		return;
+
+	for(i = 0; i < ml->nentries; i++)
+		free(ml->entries[i].title);
+	free(ml->entries);
+	ml->entries = nil;
+	ml->nentries = 0;
+	ml->filling = 0;
+
+	w = max(stringwidth(font, ml->title), stringwidth(font, none));
+	ml->r.min.x = SCRW/2 - w/2;
+	ml->r.max = addpt(ml->r.min, Pt(w, font->height+Vspace));
+	ml->sr = ZR;
+	ml->high = -1;
+}
+
+static void
+menulist_update(Menulist *ml, Mousectl *mc)
+{
+	if(ptinrect(mc->xy, ml->r)){
+		/* item highlighting and selection */
+	}else if(ptinrect(mc->xy, ml->sr)){
+		/* scrolling */
+	}
+}
+
+static void
+menulist_draw(Menulist *ml, Image *dst)
+{
+	static Image *bc;
+	Rectangle tr, er; /* title and per-entry */
+	int i;
+
+	if(ml->filling)
+		return;
+
+	if(bc == nil)
+		bc = eallocimage(display, Rect(0,0,1,1), screen->chan, 1, DPurpleblue);
+
+	/* draw title */
+	tr.min = subpt(ml->r.min, Pt(0,Menuborder + font->height+Vspace));
+	tr.max = Pt(ml->r.max.x, ml->r.min.y - Menuborder);
+	draw(dst, tr, display->black, nil, ZP);
+	string(dst, tr.min, display->white, ZP, font, ml->title);
+
+	/* draw content */
+	border(dst, ml->r, -Menuborder, bc, ZP);
+	er.min = ml->r.min;
+	er.max = Pt(ml->r.max.x, er.min.y + font->height+Vspace);
+	for(i = 0; i < ml->nentries; i++){
+		draw(dst, er, display->white, nil, ZP);
+		string(dst, er.min, display->black, ZP, font, ml->entries[i].title);
+		er.min.y += font->height+Vspace;
+		er.max.y = er.min.y + font->height+Vspace;
+	}
+	if(i == 0){
+		draw(dst, er, display->white, nil, ZP);
+		string(dst, er.min, display->black, ZP, font, none);
+	}
+}
+
+Menulist *
+newmenulist(int topmargin, char *title)
+{
+	Menulist *ml;
+	int w;
+
+	ml = emalloc(sizeof *ml);
+	memset(ml, 0, sizeof *ml);
+	ml->title = estrdup(title);
+	w = max(stringwidth(font, title), stringwidth(font, none));
+	ml->r.min = Pt(SCRW/2 - w/2, topmargin);
+	ml->r.max = addpt(ml->r.min, Pt(w, font->height+Vspace));
+	ml->high = -1;
+	ml->add = menulist_add;
+	ml->clear = menulist_clear;
+	ml->update = menulist_update;
+	ml->draw = menulist_draw;
+	return ml;
+}
+
+void
+delmenulist(Menulist *ml)
+{
+	ml->clear(ml);
+	free(ml->title);
+	free(ml);
+}
--- a/mkfile
+++ b/mkfile
@@ -9,6 +9,7 @@
 OFILES=\
 	alloc.$O\
 	util.$O\
+	menulist.$O\
 
 HFILES=\
 	dat.h\
--- a/util.c
+++ b/util.c
@@ -141,3 +141,9 @@
 		return nil;
 	return statenametab[state];
 }
+
+int
+max(int a, int b)
+{
+	return a > b? a: b;
+}