#include /******************************************************************** * Parameters */ any *list = [null,MCOMMAND]; persist(list); /******************************************************************** * The tnt menu */ typedef struct TNTmenu TNTmenu; struct TNTmenu { void setlabel(displayitem); void appenditem(any *); void setvisualstate(int,name); void stealallcolors(object); void settarget(any); void setnotifier(name nm); void setchoicemode(name nm); void setdefault(int d); void setitemlist(any *); void setpinnable(boolean); void qvalidate(); void open_pinned(canvastype); void close_pinned(); float width(); float height(); char *itemstring(int i); }; extern struct { TNTmenu new(name,canvastype); } ClassHNMenu; TNTmenu tntmn = null; object menutarget = null; #postscript /ClassHNCommandMenu ClassCommandMenu [] classbegin /ExecuteNotifier { % value notifier -- self /notify /target self send send } def /itemstring { % i -- str|null /item self send { dup isarray? {0 get} {exit} ifelse } loop dup type /stringtype ne {pop null} if } def /width {/size self send pop} def /height {/size self send exch pop} def classend def /ClassHNSettingsMenu ClassSettingsMenu [] classbegin /ExecuteNotifier { % value notifier -- dup null ne { self /notify /target self send send } { /ExecuteNotifier super send } ifelse } def /itemstring { % i -- str|null /item self send { dup isarray? {0 get} {exit} ifelse } loop dup type /stringtype ne {pop null} if } def /width {/size self send pop} def /height {/size self send exch pop} def classend def /ClassHNMenu ClassMenu [] classbegin /ClassCommandMenu ClassHNCommandMenu def /ClassSettingsMenu ClassHNSettingsMenu def /qvalidate {/?validate super send} def /width {/size self send pop} def /height {/size self send exch pop} def /open_pinned { % canvas -- dup /setinvoker self send PinnedCopy null ne { /map PinnedCopy send /totop PinnedCopy send } if 0 1 /itemcount self send 1 sub { /item self send dup isarray? { dup length 2 eq { 1 get dup type /canvastype eq { 2 copy /open_pinned exch send } if } if } if pop } for pop } def /close_pinned { PinnedCopy null ne { /unmap PinnedCopy send } if 0 1 /itemcount self send 1 sub { /item self send dup isarray? { dup length 2 eq { 1 get dup type /canvastype eq { /close_pinned 1 index send } if } if } if pop } for } def /setallcolors { % c1 c2 c3 c4 c5 c6 c7 -- 7 copy /setallcolors super send 0 1 /itemcount self send 1 sub { /item self send dup isarray? { dup length 2 eq { 1 get dup type /canvastype eq { 8 copy /setallcolors exch send } if } if } if pop } for pop pop pop pop pop pop pop } def /stealallcolors { % object {2DFG 2DBG FG BG0 BG BG2 BG3} exch send /setallcolors self send } def classend def currentdict /ClassHNCommandMenu undef currentdict /ClassHNSettingsMenu undef #end /******************************************************************** * Create TNTmenu */ int nritems(any *l) { return (length(l) - MHLEN) / MFLEN; } any *getheader(any *l) { return getinterval(l,0,MHLEN); } any *getitem(any *l,int i) { return getinterval(l,MHLEN + (i * MFLEN),MFLEN); } TNTmenu createtntmenu(any *l) { int df; any *d; TNTmenu m; int n; gsave(); setcanvas(framebuffer); d = getheader(l); m = ClassHNMenu.new(/Grid,framebuffer); if ((int)d[MHSTATE] & MEXCLUSIVE) m.setchoicemode(/Exclusive); else if ((int)d[MHSTATE] & MNONEXCLUSIVE) m.setchoicemode(/NonExclusive); if ((int)d[MHSTATE] & MPIN) m.setpinnable(true); m.setlabel(d[MHLABEL]); m.settarget(soften(self)); m.setnotifier(/MenuAction); df = -1; for (n = 0 ; n < nritems(l) ; n++) { d = getitem(l,n); switch (truedicttype(d[MFACTION])) { case /packedarraytype: case /arraytype: m.appenditem([d[MFLABEL], createtntmenu((any *)d[MFACTION])]); break; case /nametype: m.appenditem([d[MFLABEL],d[MFACTION]]); break; case /nulltype: m.appenditem([d[MFLABEL]]); break; } if ((int)d[MFSTATE] & MINACTIVE) m.setvisualstate(n,/InActive); if ((int)d[MFSTATE] & MDEFAULT) df = n; } if (df >= 0) m.setdefault(df); m.qvalidate(); grestore(); return m; } any validate() { if (tntmn) return tntmn; else return tntmn = createtntmenu(list); } /******************************************************************** * manipulating the menu list */ void setmenu(any *l) { list = l; unpromote(/tntmn); } #postscript /DIString /DIString load def #end char *itemstring(int i) { return DIString(list[(i * MFLEN) + MHLEN]); } int defaultindex(any *l) { int n, i; if ((n = tntmn.default()) == null) return -1; else return (n); } boolean defaultactive() { int n = defaultindex(list); return (n >= 0) && (!((int)list[(n * MFLEN) + MHLEN + MFSTATE] & MINACTIVE)); } displayitem defaultitem() { int n = defaultindex(list); if (n < 0) return null; else return (displayitem)list[(n * MFLEN) + MHLEN + MFLABEL]; } /******************************************************************** * Notification */ eventtype track_evt = null; void notify(any i, name message, TNTmenu m) { int *a; switch (type(i)) { case /arraytype: case /packedarraytype: a = (int *)i; PdBSend([a[1],i,m.itemstring(a[0])],message,menutarget); case /integertype: PdBSend([true,i,m.itemstring((int)i)],message,menutarget); break; } } void execdefault0(any *l, object t) { int i = defaultindex(l); any *d; if (i >= 0) { d = getitem(l,i); switch (truedicttype(d[MFACTION])) { case /packedarraytype: case /arraytype: execdefault0((any *)d[MFACTION],t); break; case /nametype: PdBSend([true,i,DIString(d[MFLABEL])],(name)d[MFACTION],t); break; default: PdBSend([true,i,DIString(d[MFLABEL])],/MenuAction,t); break; } } } void execdefault(object t) { execdefault0(list,t); } /******************************************************************** * show menu */ void show_menu_pos(object t,name pos) { menutarget = (object)soften(t); track_evt = (eventtype)currentprocess[/track_evt]; tntmn.stealallcolors(t); currentprocess[/menumenu] = tntmn; currentprocess[/menuposname] = pos; breakpoint(); undef((dicttype)currentprocess,/menumenu); undef((dicttype)currentprocess,/menuposname); undef((dicttype)currentprocess,/menuok); undef((dicttype)currentprocess,/track_evt); } void showmenu(object t) { if (known((dicttype)currentprocess,/menuok)) { validate(); show_menu_pos(t,/Default); } } void showmenuS(object t, float X, float Y) { if (known((dicttype)currentprocess,/menuok)) { validate(); mouseevent.XLocation = X - (tntmn.width()/2); mouseevent.YLocation = Y; show_menu_pos(t,/NorthWest); } } void showmenuE(object t, float X, float Y) { if (known((dicttype)currentprocess,/menuok)) { validate(); mouseevent.XLocation = X; mouseevent.YLocation = Y; setcursorlocation(X,Y); show_menu_pos(t,/NorthWest); } } void showmenuSE(object t, float X, float Y) { if (known((dicttype)currentprocess,/menuok)) { validate(); mouseevent.XLocation = X; mouseevent.YLocation = Y; show_menu_pos(t,/NorthWest); } } /******************************************************************** * owner */ void owner_close() { if (promoted(/tntmn)) tntmn.close_pinned(); } void owner_open() { if (promoted(/tntmn)) tntmn.open_pinned(cv); }