M event.c => event.c +36 -4
@@ 71,6 71,9 @@ sendevent(GuiElement *g, Event event)
case Xmousescroll:
s->event = smprint("mousescroll %s\n", e->direction == Up ? "up" : "down");
break;
+ case Xmenuhit:
+ s->event = smprint("menuhit %c %d %s\n", e->hit.button, e->hit.which, e->hit.text);
+ break;
case Xkeyboard:
s->event = smprint("key %C\n", e->r);
break;
@@ 93,19 96,49 @@ mouseevent(Mouse m)
static GuiElement *lastM = nil;
static GuiElement *lastR = nil;
+ int down = 0;
+
int b = lastbuttons ^ m.buttons;
lastbuttons = m.buttons;
- if(b&4 && m.buttons&4)
+ if(b&4 && m.buttons&4){
lastR = g;
- if(b&2 && m.buttons&2)
+ down = 3;
+ }
+ if(b&2 && m.buttons&2){
lastM = g;
- if(b&1 && m.buttons&1)
+ down = 2;
+ }
+ if(b&1 && m.buttons&1){
lastL = g;
+ down = 1;
+ }
if(!g)
return 0;
wlock(&g->lock);
+ Event e;
+ MenuSpec *ms = getprop(g, Pmenus, 0).menus;
+ if(down >= 1 && down <= 3 && ms->menus[down-1] != nil){
+ int which = menuhit(down, mousectl, ms->menus[down-1], nil);
+ e.type = Xmenuhit;
+ e.hit.button = (down == 1) ? 'L' : (down == 2) ? 'M' : 'R';
+ e.hit.which = which;
+ e.hit.text = ms->menus[down-1]->item[which];
+ if(g->listening && which != -1)
+ sendevent(g, e);
+ wunlock(&g->lock);
+
+ switch(down){
+ case 1: lastL = nil; break;
+ case 2: lastM = nil; break;
+ case 3: lastR = nil; break;
+ }
+ lastbuttons = lastbuttons ^ (1<<(down-1));
+
+ return 1;
+ }
+
if(!g->listening){
wunlock(&g->lock);
return 0;
@@ 114,7 147,6 @@ mouseevent(Mouse m)
b = g->buttons ^ m.buttons;
g->buttons = m.buttons;
- Event e;
if(b&16 && m.buttons&16){
e.type = Xmousescroll;
e.direction = Down;
M graphics.c => graphics.c +9 -9
@@ 8,8 8,8 @@
#include "guifs.h"
Point mousexy;
-Mousectl *mouse;
-Keyboardctl *keyboard;
+Mousectl *mousectl;
+Keyboardctl *keyboardctl;
Channel *updatechan;
Channel *mkcolourchan;
Channel *newcolourchan;
@@ 122,9 122,9 @@ guiproc(void *)
if(initdraw(nil, nil, "guifs") < 0)
sysfatal("initdraw failed");
- if((mouse = initmouse(nil, screen)) == nil)
+ if((mousectl = initmouse(nil, screen)) == nil)
sysfatal("initmouse failed");
- if((keyboard = initkeyboard(nil)) == nil)
+ if((keyboardctl = initkeyboard(nil)) == nil)
sysfatal("initkeyboard failed");
enum {
@@ 139,13 139,13 @@ guiproc(void *)
[Aupdategui] =
{updatechan, &i, CHANRCV},
[Aresize] =
- {mouse->resizec, nil, CHANRCV},
+ {mousectl->resizec, nil, CHANRCV},
[Amkcolour] =
{mkcolourchan, &c, CHANRCV},
[Amouse] =
- {mouse->c, &mouse->Mouse, CHANRCV},
+ {mousectl->c, &mousectl->Mouse, CHANRCV},
[Akeyboard] =
- {keyboard->c, &r, CHANRCV},
+ {keyboardctl->c, &r, CHANRCV},
[Aaltend] =
{nil, nil, CHANEND},
};
@@ 169,10 169,10 @@ guiproc(void *)
}
break;
case Amouse:
- mousexy = mouse->Mouse.xy;
+ mousexy = mousectl->Mouse.xy;
if(!root)
break;
- if(mouseevent(mouse->Mouse))
+ if(mouseevent(mousectl->Mouse))
resized(0);
break;
case Akeyboard:
M guifs.h => guifs.h +18 -1
@@ 7,11 7,12 @@ enum {
Pbordercolour,
Ptext,
Ptextcolour,
+ Pmenus,
Pmax,
};
enum {
- nbaseprops = 5
+ nbaseprops = 6
};
enum {
@@ 32,12 33,14 @@ enum {
Xmouseup,
Xmouseclick,
Xmousescroll,
+ Xmenuhit,
Xkeyboard,
Xmax,
};
typedef struct Colour Colour;
typedef struct Spacing Spacing;
+typedef struct MenuSpec MenuSpec;
typedef union PropVal PropVal;
typedef struct PropSpec PropSpec;
typedef struct Prop Prop;
@@ 57,9 60,15 @@ struct Spacing {
int left;
};
+struct MenuSpec {
+ char seps[3];
+ Menu *menus[3];
+};
+
union PropVal {
Colour *colour;
Spacing *spacing;
+ MenuSpec *menus;
int orientation;
Rune *text;
};
@@ 80,9 89,15 @@ struct Prop {
struct Event {
int type;
union {
+ int i;
Mouse m;
Rune r;
int direction;
+ struct {
+ char button;
+ int which;
+ char *text;
+ } hit;
};
};
@@ 130,8 145,10 @@ extern GuiElement *root;
extern PropSpec propspecs[Pmax];
extern GuiSpec guispecs[Gmax];
extern int baseprops[nbaseprops];
+extern Mousectl *mousectl;
void *emalloc(ulong);
+void *erealloc(void *, ulong);
int allspace(char *);
Colour *mkcolour(ulong);
M main.c => main.c +2 -2
@@ 160,6 160,8 @@ newgui(GuiElement *parent)
g->events = chancreate(sizeof(char *), 0);
+ settype(g, Gcontainer);
+
if(parent){
g->id = parent->nchildren;
wlock(&parent->lock);
@@ 169,8 171,6 @@ newgui(GuiElement *parent)
wunlock(&parent->lock);
}
- settype(g, Gcontainer);
-
return g;
}
M props.c => props.c +112 -2
@@ 109,6 109,17 @@ deftext(int gtag, int ptag)
return v;
}
+PropVal
+defmenus(int gtag, int ptag)
+{
+ USED(gtag);
+ USED(ptag);
+
+ PropVal v;
+ v.menus = emalloc(sizeof(MenuSpec));
+ return v;
+}
+
char *
printcolour(PropVal p)
{
@@ 155,6 166,36 @@ printtext(PropVal p)
}
char *
+printmenus(PropVal p)
+{
+ MenuSpec *spec = p.menus;
+
+ char which[3] = "LMR";
+ char *str = smprint("");
+ for(int i = 0; i < 3; i++){
+ if(spec->menus[i] == nil)
+ continue;
+
+ char sep = spec->seps[i];
+ char *tmp = str;
+ str = smprint("%s%c", tmp, which[i]);
+ free(tmp);
+
+ char **items = spec->menus[i]->item;
+ for(int j = 0; items[j] != nil; j++){
+ tmp = str;
+ str = smprint("%s%c%s", tmp, sep, items[j]);
+ free(tmp);
+ }
+
+ tmp = str;
+ str = smprint("%s\n", tmp);
+ free(tmp);
+ }
+ return str;
+}
+
+char *
parsecolour(char *str, PropVal *p)
{
char *r;
@@ 226,6 267,74 @@ parsetext(char *str, PropVal *p)
return nil;
}
+char *
+parsemenus(char *str, PropVal *p)
+{
+ char *err = nil;
+ int n = 0;
+ for(int i = 0; str[i] != 0; i++)
+ if(str[i] == '\n')
+ n++;
+
+ char **lines = emalloc(sizeof(char *) * (n+1));
+ n = getfields(str, lines, n, 1, "\n");
+
+ p->menus = emalloc(sizeof(MenuSpec));
+ MenuSpec *spec = p->menus;
+ for(int i = 0; i < n; i++){
+ char *line = lines[i];
+ if(strlen(line) == 0)
+ continue;
+
+ if(strlen(line) <= 2)
+ return Eparse;
+
+ int which;
+ switch(line[0]){
+ case 'L': which = 0; break;
+ case 'M': which = 1; break;
+ case 'R': which = 2; break;
+ default:
+ err = Eparse;
+ goto Lend;
+ }
+
+ if(spec->menus[which] == nil)
+ spec->menus[which] = emalloc(sizeof(Menu));
+
+ int count = 0;
+ char sep = line[1];
+ spec->seps[which] = sep;
+ spec->menus[which]->item = emalloc(sizeof(char *));
+
+ char *start = line+2;
+ char *end;
+ while(*start != 0){
+ count++;
+ spec->menus[which]->item = erealloc(spec->menus[which]->item, sizeof(char *) * count);
+ for(end = start; *end != 0 && *end != sep && *end != '\n'; end++);
+ int len = end-start;
+ char *buf = emalloc(len+1);
+ memcpy(buf, start, len);
+ buf[len] = 0;
+
+ spec->menus[which]->item[count-1] = buf;
+ start = end;
+ if(*start != 0){
+ do{
+ start++;
+ }while(*start == '\n');
+ }
+ }
+ spec->menus[which]->item[count] = nil;
+ print("count: %d\n", count);
+ }
+
+Lend:
+ free(lines);
+ return err;
+}
+
PropVal
getprop(GuiElement *g, int tag, int lock)
{
@@ 239,7 348,7 @@ getprop(GuiElement *g, int tag, int lock)
runlock(&g->lock);
if(v == nil)
- sysfatal("invalid prop for this gui element");
+ sysfatal("invalid prop %d for this gui element", tag);
else
return *v;
}
@@ 268,6 377,7 @@ PropSpec propspecs[Pmax] = {
[Pbordercolour] = {"bordercolour", defcolour, printcolour, parsecolour},
[Ptext] = {"text", deftext, printtext, parsetext},
[Ptextcolour] = {"textcolour", defcolour, printcolour, parsecolour},
+ [Pmenus] = {"menus", defmenus, printmenus, parsemenus},
};
-int baseprops[nbaseprops] = {Pbackground, Pborder, Pmargin, Ppadding, Pbordercolour};>
\ No newline at end of file
+int baseprops[nbaseprops] = {Pbackground, Pborder, Pmargin, Ppadding, Pbordercolour, Pmenus};<
\ No newline at end of file
M test.rc => test.rc +5 -0
@@ 68,4 68,9 @@ for(f in `{walk /mnt/gui | grep $dir'/[0-9]+/event'}){
printevents $f <$f >[2]/dev/null &
}
+# Create a right-click menu on the text field
+echo 'R/this is a/right click/menu' >> /mnt/gui/0/props/menus
+# Also attach an event printer to the text field
+printevents 'text field' </mnt/gui/0/event >[2]/dev/null &
+
wait