shithub: puzzles

Download patch

ref: 3b83debfa8a7a5dc82c40d6500d35a9c98135cea
parent: cef5fe0310139ee6d16db580e30cb0bc5657c54b
author: sirjofri <sirjofri@sirjofri.de>
date: Sun May 26 11:42:59 EDT 2024

better option handling (buttons and entry boxes)

--- a/plan9.c
+++ b/plan9.c
@@ -186,11 +186,8 @@
 	exits(nil);
 }
 
-char *showcmd = "c_game show";
-
 static void p9_draw_text(void *handle, int x, int y, int fonttype, int fontsize, int align, int color, const char *text)
 {
-	// todo: align, fontsize, fonttype
 	Font *f;
 	Point p, size;
 	frontend *fe = (frontend*)handle;
@@ -616,52 +613,104 @@
 	}
 }
 
+typedef struct Option Option;
+struct Option {
+	char *name;
+	Control *kctl;
+	Control *vctl;
+};
+
+Option options[32];
+
+Option*
+findoption(char *name)
+{
+	Option *o;
+	for (o = options; o->name; o++)
+		if (strcmp(o->name, name) == 0)
+			return o;
+	return nil;
+}
+
+Option*
+findoptionname(char *ctl)
+{
+	Option *o;
+	for (o = options; o->name; o++)
+		if (strcmp(o->vctl->name, ctl) == 0)
+			return o;
+	return nil;
+}
+
 void
+clearoptions(void)
+{
+	for (Option *o = options; o->name; o++) {
+		if (o->name == nil)
+			return;
+		free(o->name);
+		chanprint(fe->cs->ctl, "c_settings remove %q", o->kctl->name);
+		chanprint(fe->cs->ctl, "c_settings remove %q", o->vctl->name);
+		deactivate(o->vctl);
+		closecontrol(o->kctl);
+		closecontrol(o->vctl);
+		o->kctl = o->vctl = nil;
+		o->name = nil;
+	}
+}
+
+void
 addoption(config_item *cfg)
 {
-	char buf[128];
-	int isnew;
+	char buf[8];
 	Control *label, *entry;
+	int last;
+	Option *o;
 	
-	snprint(buf, 128, "l_%s", cfg->name);
-	label = controlcalled(buf);
-	isnew = 0;
-	if (!label) {
-		label = createlabel(fe->cs, buf);
-		isnew = 1;
+	for (o = options; o->name; o++) {
+		last++;
 	}
+	
+	o->name = strdup(cfg->name);
+	
+	snprint(buf, sizeof(buf), "l_%d", last);
+	label = createlabel(fe->cs, buf);
+	o->kctl = label;
 	chanprint(fe->cs->ctl, "%q value %q", buf, cfg->name);
 	chanprint(fe->cs->ctl, "%q align center", buf);
 	chanprint(fe->cs->ctl, "%q size 100 %d 500 %d", buf, font->height*2, font->height*2);
-	if (isnew)
-		chanprint(fe->cs->ctl, "c_settings add %q", buf);
-	snprint(buf, 128, "e_%s", cfg->name);
+	chanprint(fe->cs->ctl, "c_settings add %q", buf);
 	
-	isnew = 0;
-	entry = controlcalled(buf);
-	if (!entry)
-		isnew = 1;
+	snprint(buf, sizeof(buf), "e_%d", last);
+	
+	entry = nil;
 	switch (cfg->type) {
 	case C_STRING:
-		if (!entry)
-			entry = createentry(fe->cs, buf);
+		entry = createentry(fe->cs, buf);
 		chanprint(fe->cs->ctl, "%q border 1", buf);
 		chanprint(fe->cs->ctl, "%q size 100 %d 500 %d", buf, font->height, font->height);
 		chanprint(fe->cs->ctl, "%q value %q", buf, cfg->u.string.sval);
+		chanprint(fe->cs->ctl, "%q align center", buf);
+		controlwire(entry, "data", fe->settingschan);
 		break;
 	case C_BOOLEAN:
 		if (!entry)
-			entry = createbutton(fe->cs, buf);
+			entry = createtextbutton(fe->cs, buf);
 		chanprint(fe->cs->ctl, "%q border 1", buf);
+		chanprint(fe->cs->ctl, "%q textcolor black\n%q pressedtextcolor black", buf, buf);
 		chanprint(fe->cs->ctl, "%q size 100 %d 500 %d", buf, font->height, font->height);
 		chanprint(fe->cs->ctl, "%q value %d", buf, cfg->u.boolean.bval);
+		chanprint(fe->cs->ctl, "%q text %s", buf, cfg->u.boolean.bval ? "yes" : "no");
+		chanprint(fe->cs->ctl, "%q align center", buf);
+		chanprint(fe->cs->ctl, "%q mask transparent", buf);
+		controlwire(entry, "event", fe->settingschan);
 		break;
 	case C_CHOICES:
 		// todo
 		break;
 	}
-	if (entry && isnew) {
-		controlwire(entry, "event", fe->settingschan);
+	o->vctl = entry;
+	if (entry) {
 		activate(entry);
 		chanprint(fe->cs->ctl, "c_settings add %q", buf);
 	}
@@ -677,6 +726,17 @@
 	config_item *cfg;
 	Control *c, *info;
 	
+	/* assumptions: if b_savecfg exists, then l_cfginfo also exists */
+	
+	c = controlcalled("b_savecfg");
+	/* if already set up, remove from widget to add back later */
+	if (c) {
+		chanprint(fe->cs->ctl, "c_settings remove l_cfginfo");
+		chanprint(fe->cs->ctl, "c_settings remove b_savecfg");
+	}
+	
+	clearoptions();
+	
 	for (int i = 0; i < nelem(configcats); i++) {
 		cfg = midend_get_config(fe->me, configcats[i], &t);
 		if (configs[i]) {
@@ -685,21 +745,20 @@
 		}
 		configs[i] = cfg;
 		
-		while (cfg && cfg->type != C_END) {
+		for (; cfg && cfg->type != C_END; cfg++) {
 			addoption(cfg);
-			cfg++;
 		}
 	}
 	
-	c = controlcalled("b_savecfg");
 	/* if already set up, early return */
-	if (c)
+	if (c) {
+		goto Addbuttons;
 		return;
+	}
 	
 	info = createlabel(fe->cs, "l_cfginfo");
 	chanprint(fe->cs->ctl, "l_cfginfo align centerleft");
 	chanprint(fe->cs->ctl, "l_cfginfo size 50 %d 500 %d", font->height, font->height);
-	chanprint(fe->cs->ctl, "c_settings add l_cfginfo");
 	
 	c = createtextbutton(fe->cs, "b_savecfg");
 	chanprint(fe->cs->ctl, "b_savecfg text Save");
@@ -706,16 +765,45 @@
 	chanprint(fe->cs->ctl, "b_savecfg border 1");
 	chanprint(fe->cs->ctl, "b_savecfg align center");
 	chanprint(fe->cs->ctl, "b_savecfg size 50 %d 100 %d", font->height, font->height);
-	chanprint(fe->cs->ctl, "c_settings add b_savecfg");
 	controlwire(c, "event", fe->c);
 	activate(c);
+
+Addbuttons:
+	chanprint(fe->cs->ctl, "c_settings add l_cfginfo");
+	chanprint(fe->cs->ctl, "c_settings add b_savecfg");
 }
 
+void setoption(char *name, char *value, config_item *conf);
+
+void
+readoptions(void)
+{
+	char buf[128];
+	char *val;
+	config_item *cfg;
+	Control *c;
+	Option *o;
+	
+	for (int i = 0; i < nelem(configcats); i++) {
+		for (cfg = configs[i]; cfg && cfg->type != C_END; cfg++) {
+			if (cfg->type != C_STRING)
+				continue;
+			o = findoption(cfg->name);
+			if (!o || !o->vctl)
+				continue;
+			chanprint(fe->cs->ctl, "%q data", o->vctl->name);
+			val = recvp(fe->settingschan);
+			setoption(cfg->name, val, cfg);
+		}
+	}
+}
+
 int
 saveoptions(void)
 {
 	char *s;
 	int r = 1;
+	readoptions();
 	for (int i = 0; i < nelem(configcats); i++) {
 		s = midend_set_config(fe->me, configcats[i], configs[i]);
 		if (s) {
@@ -722,6 +810,8 @@
 			chanprint(fe->cs->ctl, "l_cfginfo value %q", s);
 			r = 0;
 		}
+		free_cfg(configs[i]);
+		configs[i] = nil;
 	}
 	loadoptions();
 	LOG("saved options");
@@ -729,27 +819,36 @@
 }
 
 void
-setoption(char *name, char *value)
+setoption(char *name, char *value, config_item *conf)
 {
 	int n;
 	config_item *cfg;
+	Option *o;
+	
+	if (conf) {
+		cfg = conf;
+		goto Found;
+	}
 	for (int i = 0; i < nelem(configs); i++) {
-		cfg = configs[i];
-		while (cfg && cfg->type != C_END) {
+		for (cfg = configs[i]; cfg && cfg->type != C_END; cfg++) {
 			if (strcmp(cfg->name, name) == 0)
 				goto Found;
-			cfg++;
 		}
 	}
 	return;
+
 Found:
+	Log("Set %q to %q\n", cfg->name, value);
 	switch (cfg->type) {
 	case C_STRING:
 		cfg->u.string.sval = value;
 		break;
 	case C_BOOLEAN:
-		n = atoi(value);
-		cfg->u.boolean.bval = n ? 1 : 0;
+		n = atoi(value) ? 1 : 0;
+		cfg->u.boolean.bval = n;
+		o = findoption(name);
+		chanprint(fe->cs->ctl, "%q value %d", o->vctl->name, n);
+		chanprint(fe->cs->ctl, "%q text %q", o->vctl->name, n ? "yes" : "no");
 		break;
 	case C_CHOICES:
 		// todo
@@ -983,7 +1082,8 @@
 	
 	for (;;) {
 		switch (alt(a)) {
-		case 0: /* libcontrol event channel */	
+		case 0: /* libcontrol event channel */
+			Log("Control: %s\n", s);
 			tokenize(s, args, nelem(args));
 			
 			if (strcmp(args[0], "b_game:") == 0) {
@@ -1015,10 +1115,10 @@
 				goto Out;
 			break;
 		case 4: /* settings */
+			Log("Setting: %s\n", s);
 			tokenize(s, args, nelem(args));
-			s = args[0] + 2; /* get rid of "e_" */
-			s[strlen(s)-1] = 0; /* get rid of sender ":" */
-			setoption(s, args[2]);
+			args[0][strlen(args[0])-1] = 0; /* get rid of sender ":" */
+			setoption(findoptionname(args[0])->name, args[2], nil);
 			break;
 		}
 	}