plan9fox/libpanel/button.c
xfnw 856abd2f7d Squashed 'sys/src/cmd/gopher/' content from commit 3680728b6
git-subtree-dir: sys/src/cmd/gopher
git-subtree-split: 3680728b631ed65201b397f4ae3e5d1b03be42f9
2022-07-01 15:46:23 -04:00

189 lines
4.6 KiB
C

#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <panel.h>
#include "pldefs.h"
typedef struct Button Button;
struct Button{
int btype; /* button type */
Icon *icon; /* what to write on the button */
int check; /* for check/radio buttons */
void (*hit)(Panel *, int, int); /* call back user code on check/radio hit */
void (*menuhit)(int, int); /* call back user code on menu item hit */
void (*pl_buttonhit)(Panel *, int); /* call back user code on button hit */
int index; /* arg to menuhit */
int buttons;
};
/*
* Button types
*/
#define BUTTON 1
#define CHECK 2
#define RADIO 3
void pl_drawbutton(Panel *p){
Rectangle r;
Button *bp;
bp=p->data;
r=pl_boxf(p->b, p->r, p->flags, p->state);
switch(bp->btype){
case CHECK:
r=pl_check(p->b, r, bp->check);
break;
case RADIO:
r=pl_radio(p->b, r, bp->check);
break;
}
pl_drawicon(p->b, r, PLACECEN, p->flags, bp->icon);
}
int pl_hitbutton(Panel *p, Mouse *m){
int oldstate, hitme;
Panel *sib;
Button *bp;
bp=p->data;
oldstate=p->state;
if(m->buttons&OUT){
hitme=0;
p->state=UP;
}
else if(m->buttons&7){
hitme=0;
p->state=DOWN;
bp->buttons=m->buttons;
}
else{ /* mouse inside, but no buttons down */
hitme=p->state==DOWN;
p->state=UP;
}
if(hitme) switch(bp->btype){
case CHECK:
if(hitme) bp->check=!bp->check;
break;
case RADIO:
if(bp->check) bp->check=0;
else{
if(p->parent){
for(sib=p->parent->child;sib;sib=sib->next){
if(sib->hit==pl_hitbutton
&& ((Button *)sib->data)->btype==RADIO
&& ((Button *)sib->data)->check){
((Button *)sib->data)->check=0;
pldraw(sib, p->b);
}
}
}
bp->check=1;
}
break;
}
if(hitme || oldstate!=p->state) pldraw(p, p->b);
if(hitme && bp->hit){
bp->hit(p, bp->buttons, bp->check);
p->state=UP;
}
return 0;
}
void pl_typebutton(Panel *g, Rune c){
USED(g, c);
}
Point pl_getsizebutton(Panel *p, Point children){
Point s;
int ckw;
Button *bp;
USED(children); /* shouldn't have any children */
bp=p->data;
s=pl_iconsize(p->flags, bp->icon);
if(bp->btype!=BUTTON){
ckw=pl_ckwid();
if(s.y<ckw){
s.x+=ckw;
s.y=ckw;
}
else s.x+=s.y;
}
return pl_boxsize(s, p->state);
}
void pl_childspacebutton(Panel *g, Point *ul, Point *size){
USED(g, ul, size);
}
void pl_initbtype(Panel *v, int flags, Icon *icon, void (*hit)(Panel *, int, int), int btype){
Button *bp;
bp=v->data;
v->flags=flags|LEAF;
v->state=UP;
v->draw=pl_drawbutton;
v->hit=pl_hitbutton;
v->type=pl_typebutton;
v->getsize=pl_getsizebutton;
v->childspace=pl_childspacebutton;
bp->btype=btype;
bp->check=0;
bp->hit=hit;
bp->icon=icon;
switch(btype){
case BUTTON: v->kind="button"; break;
case CHECK: v->kind="checkbutton"; break;
case RADIO: v->kind="radiobutton"; break;
}
}
void pl_buttonhit(Panel *p, int buttons, int check){
USED(check);
if(((Button *)p->data)->pl_buttonhit) ((Button *)p->data)->pl_buttonhit(p, buttons);
}
void plinitbutton(Panel *p, int flags, Icon *icon, void (*hit)(Panel *, int)){
((Button *)p->data)->pl_buttonhit=hit;
pl_initbtype(p, flags, icon, pl_buttonhit, BUTTON);
}
void plinitcheckbutton(Panel *p, int flags, Icon *icon, void (*hit)(Panel *, int, int)){
pl_initbtype(p, flags, icon, hit, CHECK);
}
void plinitradiobutton(Panel *p, int flags, Icon *icon, void (*hit)(Panel *, int, int)){
pl_initbtype(p, flags, icon, hit, RADIO);
}
Panel *plbutton(Panel *parent, int flags, Icon *icon, void (*hit)(Panel *, int)){
Panel *p;
p=pl_newpanel(parent, sizeof(Button));
plinitbutton(p, flags, icon, hit);
return p;
}
Panel *plcheckbutton(Panel *parent, int flags, Icon *icon, void (*hit)(Panel *, int, int)){
Panel *p;
p=pl_newpanel(parent, sizeof(Button));
plinitcheckbutton(p, flags, icon, hit);
return p;
}
Panel *plradiobutton(Panel *parent, int flags, Icon *icon, void (*hit)(Panel *, int, int)){
Panel *p;
p=pl_newpanel(parent, sizeof(Button));
plinitradiobutton(p, flags, icon, hit);
return p;
}
void pl_hitmenu(Panel *p, int buttons){
void (*hit)(int, int);
hit=((Button *)p->data)->menuhit;
if(hit) hit(buttons, ((Button *)p->data)->index);
}
void plinitmenu(Panel *v, int flags, Icon **item, int cflags, void (*hit)(int, int)){
Panel *b;
int i;
v->flags=flags;
v->kind="menu";
if(v->child){
plfree(v->child);
v->child=0;
}
for(i=0;item[i];i++){
b=plbutton(v, cflags, item[i], pl_hitmenu);
((Button *)b->data)->menuhit=hit;
((Button *)b->data)->index=i;
}
}
Panel *plmenu(Panel *parent, int flags, Icon **item, int cflags, void (*hit)(int, int)){
Panel *v;
v=plgroup(parent, flags);
plinitmenu(v, flags, item, cflags, hit);
return v;
}
void plsetbutton(Panel *p, int val){
((Button *)p->data)->check=val;
}