Adds piemenus to libdraw, which can be easily used instead of normal menuhits. Notes: Sat Mar 12 10:05:50 EST 2005 rsc I built a rio with these just to try it. Maybe I just haven't used them long enough but they just feel weird to me. I'm hesitant to put them in the distribution until there's a compelling use for them. But I want to save the code, so I created /n/sources/patch/saved, for such things, and it will be the first patch saved there. Russ Reference: /n/sources/patch/sorry/piemenus-rio Date: Thu Mar 10 16:19:38 CET 2005 Reviewed-by: rsc --- /sys/src/libdraw/piemenuhit.c Thu Jan 1 00:00:00 1970 +++ /sys/src/libdraw/piemenuhit.c Thu Mar 10 16:16:03 2005 @@ -0,0 +1,226 @@ +#include +#include +#include +#include +#include + +static Image *back, *bord, *high; + +double +rad(double i) +{ + + return (i * PI) / 180; +} + +double +dist(Point p0, Point p1) +{ + + return sqrt((p0.x - p1.x) * (p0.x - p1.x) + (p0.y - p1.y) * (p0.y - p1.y)); +} + +Point +cente(Point p0, Point p1, Point p2) +{ + double l, d; + Point r0, r1; + + l = dist(p2, p0); + r0.x = p2.x + (((p0.x - p2.x) / l) * l / 2); + r0.y = p2.y + (((p0.y - p2.y) / l) * l / 2); + + l = dist(p1, p0); + r1.x = p1.x + (((p0.x - p1.x) / l) * l / 2); + r1.y = p1.y + (((p0.y - p1.y) / l) * l / 2); + + l = p2.y - r1.y - p1.y + r0.y; + d = (double)(r0.y - r1.y) / l; + + r1.x = r0.x + d * (p1.x - r0.x); + r1.y = r0.y + d * (p1.y - r0.y); + + return r1; +} + +void +draw_pie(Point p, int r, Image *b, Image *w, Image *h, Menu *m, int a, int n) +{ + Point p0, p1; + double d, e, sr; + char *item; + + e = 360 / n; + d = 0; + sr = -1; + + ellipse(screen, p, r, r, 1, h, ZP); + fillellipse(screen, p, r - 1, r - 1, w, ZP); + if(a > 0) + fillarc(screen, p, r, r, b, ZP, (a - 1) * e, e); + + p0 = p; + p1 = p; + + p0.x += cos(rad(d)) * r; + p0.y += sin(rad(d)) * r; + p1.x += cos(rad(d + e)) * r; + p1.y += sin(rad(d + e)) * r; + + sr = dist(cente(p, p0, p1), p); + + d = e / 2; + + while(--n >= 0) + { + p0 = p; + item = strdup(m->item[n]); + if(strlen(item) > 8) + { + item[8] = '\0'; + item[7] = '.'; + item[6] = '.'; + item[5] = '.'; + } + + p0.x += cos(rad(d)) * sr; + p0.y += sin(rad(d)) * sr; + + p0.x -= stringwidth(font, item) / 2; + p0.y -= font->height / 2; + + string(screen, p0, (n == (a - 1)) ? display->white : display->black, ZP, font, item); + free(item); + d += e; + } + + return; +} + +int +piemenuhit(int but, Mousectl *mc, Menu *menu, Screen *scr) +{ + Rectangle menur; + Image *b, *backup, *back, *high, *bord; + int maxwid, nitem, i, t; + double cdeli, cpart, radius; + Point /*mov,*/ p; + char *item, set; + + back = allocimagemix(display, DPalegreen, DWhite); + high = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DDarkgreen); + bord = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DMedgreen); + set = 'y'; + + if(back == nil || high == nil || bord == nil) + { + set = 'n'; + freeimage(back); + freeimage(high); + freeimage(bord); + back = display->white; + high = display->black; + bord = display->black; + } + + replclipr(screen, 0, screen->r); + maxwid = 0; + nitem = 0; + while(item = menu->item ? menu->item[nitem] : (*menu->gen)(nitem)) + { + item = strdup(item); + if(strlen(item) > 8) + item[8] = '\0'; + + i = stringwidth(font, item); + if(i > maxwid) + maxwid = i; + free(item); + nitem++; + } + if(menu->lasthit < 0 || menu->lasthit >= nitem) + menu->lasthit = -1; + + p = mc->xy; + radius = ((font->height / 2) + maxwid); + radius += radius * nitem / 8; + menur.min = Pt(p.x - radius - 1, p.y - radius - 1); + menur.max = Pt(p.x + radius + 2, p.y + radius + 2); + + cpart = 360 / nitem; + cdeli = cpart / 2; + + if(scr){ + b = allocwindow(scr, menur, Refbackup, DNofill); + if(b == nil) + b = screen; + backup = nil; + }else{ + b = screen; + backup = allocimage(display, Rect(0, 0, Dx(menur), Dy(menur)), screen->chan, 0, DNofill); + if(backup) + draw(backup, backup->r, screen, nil, menur.min); + } + + /*if(menu->lasthit != -1) + { + mov = p; + mov.x += cos(rad(cdeli + cpart * menu->lasthit)) * (radius * 0.5); + mov.y += sin(rad(cdeli + cpart * menu->lasthit)) * (radius * 0.5); + moveto(mc, mov); + }*/ + + draw_pie(p, radius, high, back, bord, menu, menu->lasthit, nitem); + + while(mc->buttons & (1<<(but-1))){ + if(dist(p, mc->xy) < radius && dist(p, mc->xy) != 0) + { + cdeli = acos((p.x - mc->xy.x) / dist(p, mc->xy)); + if(mc->xy.y >= p.y) + cdeli += rad(180); + if(mc->xy.y < p.y) + cdeli = rad(180) - cdeli; + + i = -1; + t = -1; + while(++t <= nitem) + { + if(cdeli < rad(t * cpart) && cdeli <= rad((t + 1) * cpart)) + { + i = t; + break; + } + } + + if(i != menu->lasthit || (menu->lasthit == -1 && i != -1)) + { + menu->lasthit = i; + draw_pie(p, radius, high, back, bord, menu, menu->lasthit, nitem); + } + } else { + if(menu->lasthit != -1) + { + menu->lasthit = -1; + draw_pie(p, radius, high, back, bord, menu, menu->lasthit, nitem); + } + } + readmouse(mc); + } + if(b != screen) + freeimage(b); + if(backup){ + draw(screen, menur, backup, nil, ZP); + freeimage(backup); + } + replclipr(screen, 0, screen->clipr); + flushimage(display, 1); + + if(set == 'y') + { + freeimage(back); + freeimage(bord); + freeimage(high); + } + + return menu->lasthit - 1; +} --- /sys/src/libdraw/epiemenuhit.c Thu Jan 1 00:00:00 1970 +++ /sys/src/libdraw/epiemenuhit.c Thu Mar 10 16:16:15 2005 @@ -0,0 +1,217 @@ +#include +#include +#include +#include + +static Image *back, *bord, *high; + +double +erad(double i) +{ + + return (i * PI) / 180; +} + +double +edist(Point p0, Point p1) +{ + + return sqrt((p0.x - p1.x) * (p0.x - p1.x) + (p0.y - p1.y) * (p0.y - p1.y)); +} + +Point +ecente(Point p0, Point p1, Point p2) +{ + double l, d; + Point r0, r1; + + l = edist(p2, p0); + r0.x = p2.x + (((p0.x - p2.x) / l) * l / 2); + r0.y = p2.y + (((p0.y - p2.y) / l) * l / 2); + + l = edist(p1, p0); + r1.x = p1.x + (((p0.x - p1.x) / l) * l / 2); + r1.y = p1.y + (((p0.y - p1.x) / l) * l / 2); + + l = p2.x - r1.x - p1.x + r0.x; + d = (double)(r0.x - r1.x) / l; + + r1.x = r0.x + d * (p1.x - r0.x); + r1.y = r0.y + d * (p1.y - r0.y); + + return r1; +} + +void +edraw_pie(Point p, int r, Image *b, Image *w, Image *h, Menu *m, int a, int n) +{ + Point p0, p1; + double d, e, sr; + char *item; + + e = 360 / n; + d = 0; + sr = -1; + + ellipse(screen, p, r, r, 1, h, ZP); + fillellipse(screen, p, r - 1, r - 1, w, ZP); + if(a > 0) + fillarc(screen, p, r, r, b, ZP, (a - 1) * e, e); + + p0 = p; + p1 = p; + + p0.x += cos(erad(d)) * r; + p0.y += sin(erad(d)) * r; + p1.x += cos(erad(d + e)) * r; + p1.y += sin(erad(d + e)) * r; + + sr = edist(ecente(p, p0, p1), p); + + d = e / 2; + + while(--n >= 0) + { + p0 = p; + item = strdup(m->item[n]); + if(strlen(item) > 8) + { + item[8] = '\0'; + item[7] = '.'; + item[6] = '.'; + item[5] = '.'; + } + + p0.x += cos(erad(d)) * sr; + p0.y += sin(erad(d)) * sr; + + p0.x -= stringwidth(font, item) / 2; + p0.y -= font->height / 2; + + string(screen, p0, (n == (a - 1)) ? display->white : display->black, ZP, font, item); + free(item); + d += e; + } + + return; +} + +int +epiemenuhit(int but, Mouse *m, Menu *menu) +{ + Rectangle menur; + Image *b, *back, *high, *bord; + int maxwid, nitem, i, t; + double cdeli, cpart, radius; + Point /*mov,*/ p; + char *item, set; + + back = allocimagemix(display, DPalegreen, DWhite); + high = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DDarkgreen); + bord = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DMedgreen); + set = 'y'; + + if(back == nil || high == nil || bord == nil) + { + set = 'n'; + freeimage(back); + freeimage(high); + freeimage(bord); + back = display->white; + high = display->black; + bord = display->black; + } + + replclipr(screen, 0, screen->r); + maxwid = 0; + nitem = 0; + while(item = menu->item ? menu->item[nitem] : (*menu->gen)(nitem)) + { + item = strdup(item); + if(strlen(item) > 8) + item[8] = '\0'; + + i = stringwidth(font, item); + if(i > maxwid) + maxwid = i; + free(item); + nitem++; + } + if(menu->lasthit < 0 || menu->lasthit >= nitem) + menu->lasthit = -1; + + p = m->xy; + radius = ((font->height / 2) + maxwid); + radius += radius * nitem / 8; + menur.min = Pt(p.x - radius - 1, p.y - radius - 1); + menur.max = Pt(p.x + radius + 2, p.y + radius + 2); + + cpart = 360 / nitem; + cdeli = cpart / 2; + + b = allocimage(display, Rect(0, 0, Dx(menur), Dy(menur)), screen->chan, 0, DNofill); + if(b == 0) + b = screen; + draw(b, b->r, screen, nil, menur.min); + + /*if(menu->lasthit != -1) + { + mov = p; + mov.x += cos(erad(cdeli + cpart * menu->lasthit)) * (radius * 0.5); + mov.y += sin(erad(cdeli + cpart * menu->lasthit)) * (radius * 0.5); + emoveto(mov); + }*/ + + edraw_pie(p, radius, high, back, bord, menu, menu->lasthit, nitem); + + while(m->buttons & (1<<(but-1))){ + if(edist(p, m->xy) < radius && edist(p, m->xy) != 0) + { + cdeli = acos((p.x - m->xy.x) / edist(p, m->xy)); + if(m->xy.y >= p.y) + cdeli += erad(180); + if(m->xy.y < p.y) + cdeli = erad(180) - cdeli; + + i = -1; + t = -1; + while(++t <= nitem) + { + if(cdeli < erad(t * cpart) && cdeli <= erad((t + 1) * cpart)) + { + i = t; + break; + } + } + + if(i != menu->lasthit || (menu->lasthit == -1 && i != -1)) + { + menu->lasthit = i; + edraw_pie(p, radius, high, back, bord, menu, menu->lasthit, nitem); + } + } else { + if(menu->lasthit != -1) + { + menu->lasthit = -1; + edraw_pie(p, radius, high, back, bord, menu, menu->lasthit, nitem); + } + } + flushimage(display, 1); + *m = emouse(); + } + + draw(screen, menur, b, nil, ZP); + if(b != screen) + freeimage(b); + + replclipr(screen, 0, screen->clipr); + + if(set == 'y') + { + freeimage(back); + freeimage(bord); + freeimage(high); + } + + return menu->lasthit - 1; +} --- /sys/src/libdraw/mkfile Thu Mar 10 16:16:32 2005 +++ /sys/src/libdraw/mkfile Thu Mar 10 16:16:29 2005 @@ -21,6 +21,7 @@ egetrect.$O\ ellipse.$O\ emenuhit.$O\ + epiemenuhit.$O\ event.$O\ fmt.$O\ font.$O\ @@ -38,6 +39,7 @@ mouse.$O\ newwindow.$O\ openfont.$O\ + piemenuhit.$O\ poly.$O\ loadimage.$O\ readcolmap.$O\ --- /sys/include/event.h Thu Mar 10 16:16:54 2005 +++ /sys/include/event.h Thu Mar 10 16:16:50 2005 @@ -64,3 +64,5 @@ extern void edrawgetrect(Rectangle, int); extern int ereadmouse(Mouse*); extern int eatomouse(Mouse*, char*, int); +extern int epiemenuhit(int, Mouse*, Menu*); + --- /sys/include/mouse.h Thu Mar 10 16:17:19 2005 +++ /sys/include/mouse.h Thu Mar 10 16:17:15 2005 @@ -44,3 +44,4 @@ extern void drawgetrect(Rectangle, int); extern Rectangle getrect(int, Mousectl*); extern int menuhit(int, Mousectl*, Menu*, Screen*); +extern int piemenuhit(int, Mousectl*, Menu*, Screen*); --- /sys/man/2/event Thu Mar 10 16:17:48 2005 +++ /sys/man/2/event Thu Mar 10 16:17:44 2005 @@ -1,6 +1,6 @@ .TH EVENT 2 .SH NAME -event, einit, estart, estartfn, etimer, eread, emouse, ekbd, ecanread, ecanmouse, ecankbd, ereadmouse, eatomouse, eresized, egetrect, edrawgetrect, emenuhit, emoveto, esetcursor, Event, Mouse, Menu \- graphics events +event, einit, estart, estartfn, etimer, eread, emouse, ekbd, ecanread, ecanmouse, ecankbd, ereadmouse, eatomouse, eresized, egetrect, edrawgetrect, emenuhit, epiemenuhit, emoveto, esetcursor, Event, Mouse, Menu \- graphics events .SH SYNOPSIS .nf .PP @@ -69,6 +69,8 @@ .B int emenuhit(int but, Mouse *m, Menu *menu) .PP +.B +int epiemenuhit(int but, Mouse *m, Menu *menu) .PP .B int emoveto(Point p) @@ -359,6 +361,12 @@ The .I m argument is filled in with the final mouse event. +.PP +.I Epiemenuhit +is the same like +.I emenuhit +, but draws instead a piemenu, where menuitems longer then eight characters +are shortened. .PP .I Emoveto moves the mouse cursor to the position --- /sys/man/2/mouse Thu Mar 10 16:18:20 2005 +++ /sys/man/2/mouse Thu Mar 10 16:18:17 2005 @@ -1,6 +1,6 @@ .TH MOUSE 2 .SH NAME -initmouse, readmouse, closemouse, moveto, cursorswitch, getrect, drawgetrect, menuhit, setcursor \- mouse control +initmouse, readmouse, closemouse, moveto, cursorswitch, getrect, drawgetrect, menuhit, setcursor, piemenuhit \- mouse control .SH SYNOPSIS .nf .B @@ -42,6 +42,9 @@ .PP .B int menuhit(int but, Mousectl *mc, Menu *menu, Screen *scr) +.PP +.B +int piemenuhit(int but, Mousectl *mc, Menu *menu, Screen *scr) .fi .SH DESCRIPTION These functions access and control a mouse in a multi-threaded environment. @@ -238,6 +241,16 @@ .IR emenuhit , creating backing store for the menu, writing the menu directly on the display, and restoring the display when the menu is removed. +.PP +.IR Piemenuhit +is a replacement function of +.I menuhit +, has the brother function +.I epiemenuhit +, that is a replacement for +.I emenuhit +and draws instead of a rectangle menu piemenus. If the +name of a menuitem is longer then eight characters, it is shortened. .PP .SH SOURCE .B /sys/src/libdraw --- /sys/man/2/INDEX Thu Mar 10 16:19:02 2005 +++ /sys/man/2/INDEX Thu Mar 10 16:18:54 2005 @@ -417,6 +417,7 @@ einit event ekbd event emenuhit event +epiemenuhit event emouse event emoveto event eread event @@ -868,6 +869,7 @@ getrect mouse initmouse mouse menuhit mouse +piemenuhit mouse mouse mouse moveto mouse readmouse mouse