/* * Copyright (c) 2014-2015, Claudio Lapilli and the newRPL Team * All rights reserved. * This file is released under the 3-clause BSD license. * See the file LICENSE.txt that shipped with this distribution. */ #include #include #include // SOFT MENU API // RETURN THE NUMBER OF ITEMS IN A MENU BINT uiCountMenuItems(WORD MenuCode,WORDPTR menu) { if(MENUSPECIAL(MenuCode)==1) { // MENU IS VARS return rplGetVisibleVarCount(); } if(!menu) return 0; if(ISLIST(*menu)) return rplListLength(menu); return 1; } WORDPTR uiGetLibObject(BINT libnum,WORD Code,WORD Opcode) { LIBHANDLER han=rplGetLibHandler(libnum); if(!han) return 0; WORD SavedOpcode=CurOpcode; BINT SavedException=Exceptions; BINT SavedErrorCode=ErrorCode; Exceptions=0; // ERASE ANY PREVIOUS ERROR TO ALLOW THE LIBRARY TO RUN CurOpcode=MKOPCODE(libnum,Opcode); ArgNum3=Code; RetNum=-1; (*han)(); Exceptions=SavedException; ErrorCode=SavedErrorCode; CurOpcode=SavedOpcode; if(RetNum!=OK_CONTINUE) return 0; return ObjectPTR; } // GET A MENU OBJECT FROM A MENU CODE WORDPTR uiGetLibMenu(WORD MenuCode) { if(MENUSPECIAL(MenuCode)==1) { // MENU IS VARS, NO NEED FOR MENU OBJECT return 0; } return uiGetLibObject(MENULIBRARY(MenuCode),MenuCode,OPCODE_LIBMENU); } WORDPTR uiGetLibCmdHelp(WORD Command) { return uiGetLibObject(LIBNUM(Command),Command,OPCODE_LIBHELP); } WORDPTR uiGetLibMsg(WORD MsgCode) { return uiGetLibObject(LIBFROMMSG(MsgCode),MsgCode,OPCODE_LIBMSG); } // RETURN A POINTER TO A MENU ITEM OBJECT // FIRST ITEM = NUMBER 0 WORDPTR uiGetMenuItem(WORD MenuCode,WORDPTR menu,BINT item) { if(MENUSPECIAL(MenuCode)==1) { // MENU IS VARS // RETURN A POINTER TO THE VARIABLE NAME WORDPTR *var=rplFindVisibleGlobalByIndex(item); if(!var) return 0; return var[0]; } if(!menu) return 0; if(!ISLIST(*menu)) { if(item!=0) return 0; return menu; } WORDPTR ptr=menu+1,end=rplSkipOb(menu); while(ptr=rplSkipOb(item)-1) return; if(*ptr==CMD_ENDLIST) ptr=item; else { // IF IT'S A PROGRAM, RUN IT AND TAKE THE RESULT FROM THE STACK if(ISPROGRAM(*ptr)) { rplPushData(item); rplPushData(ptr); BINT nresults=uiCmdRunTransparent(CMD_OVR_XEQ,1,1); if(nresults==1) ptr=rplPopData(); else ptr=(WORDPTR)empty_string; // IF THE PROGRAM FAILED TO RETURN AN OBJECT, JUST USE THE EMPTY STRING item=rplPopData(); // RESTORE THE item POINTER IN CASE OF GC // CONTINUE HERE WITH THE NEW ptr } // IF IT'S A LIST, THEN TAKE THE FLAGS FROM THE SECOND ELEMENT IN THE LIST, AND USE THE FIRST AS THE DISPLAY OBJECT if(ISLIST(*ptr)) { ptr=ptr+1; if(ptr>=rplSkipOb(item)-1) return; if(*ptr==CMD_ENDLIST) ptr=item; else { WORDPTR next=rplSkipOb(ptr); if(ISBINT(*next)) flags=rplReadBINT(next); } } } } else ptr=item; // HERE ptr HAS AN OBJECT TO DISPLAY // AND flags HAS THE FLAGS if(ISIDENT(*ptr)) { // SPECIAL CASE: FOR IDENTS LOOK FOR VARIABLES AND DRAW DIFFERENTLY IF IT'S A DIRECTORY WORDPTR *var=rplFindGlobal(ptr,1); BINT w=StringWidthN((char *)(ptr+1),(char *)(ptr+1)+rplGetIdentLength(ptr),halScreen.MenuFont),pos; if(w>=scr->clipx2-scr->clipx) pos=scr->clipx+1; else pos=(scr->clipx2+1+scr->clipx-w)>>1; if((flags&1) || (var && ISDIR(*var[1]))) { //ggl_clipvline(scr,scr->clipx2,scr->clipy,scr->clipy2,ggl_mkcolor(color)); ggl_cliphline(scr,scr->clipy2,scr->clipx,scr->clipx2,ggl_mkcolor(8)); } DrawTextN(pos,scr->clipy,(char *)(ptr+1),(char *)(ptr+1)+rplGetIdentLength(ptr),halScreen.MenuFont,color,scr); // DARKEN/LIGHTEN EFFECT ON LAST FEW PIXELS if(w>=scr->clipx2-scr->clipx) { scr->x=scr->clipx2; scr->y=scr->clipy; ggl_filter(scr,1,scr->clipy2-scr->clipy+1,0xA,(color)? &ggl_fltlighten:&ggl_fltdarken); scr->x--; ggl_filter(scr,1,scr->clipy2-scr->clipy+1,0x6,(color)? &ggl_fltlighten:&ggl_fltdarken); scr->x--; ggl_filter(scr,1,scr->clipy2-scr->clipy+1,0x4,(color)? &ggl_fltlighten:&ggl_fltdarken); } if(flags&2) { // SECOND BIT IN FLAGS MEANS INVERTED scr->x=scr->clipx; scr->y=scr->clipy; ggl_filter(scr,scr->clipx2-scr->clipx+1,scr->clipy2-scr->clipy+1,0,&ggl_fltinvert); } return; } // ALL OTHER OBJECTS NEED TO BE DECOMPILED, EXCEPT THE STRING AND GROBS BINT totaln; BYTEPTR string,endstring; // TODO: ADD GROBS HERE if(!ISSTRING(*ptr)) { WORD ptrprolog=*ptr; BINT SavedException=Exceptions; BINT SavedErrorCode=ErrorCode; Exceptions=0; // ERASE ANY PREVIOUS ERROR TO ALLOW THE DECOMPILER TO RUN // DO NOT SAVE IPtr BECAUSE IT CAN MOVE WORDPTR opname=rplDecompile(ptr,0); Exceptions=SavedException; ErrorCode=SavedErrorCode; if(!opname) return; // HERE WE HAVE A STRING, DO SOME MORE POST-PROCESSING DEPENDING ON OBJECT string=(BYTEPTR) (opname+1); totaln=rplStrLen(opname); endstring=(BYTEPTR)utf8nskip((char *)string,(char *)rplSkipOb(opname),totaln); if(ISUNIT(ptrprolog)) { // TODO: SKIP THE NUMERIC PORTION, LEAVE JUST THE UNIT if((totaln>2)&&(string[0]=='1')&&(string[1]=='_')) { totaln-=2; string+=2; } } // TODO: ADD MORE SPECIALIZED HANDLING HERE } else { string=(BYTEPTR) (ptr+1); totaln=rplStrLen(ptr); endstring=(BYTEPTR)utf8nskip((char *)string,(char *)rplSkipOb(ptr),totaln); } // JUST DISPLAY THE STRING BINT w=StringWidthN((char *)string,(char *)endstring,halScreen.MenuFont),pos; if(w>=scr->clipx2-scr->clipx) pos=scr->clipx+1; else pos=(scr->clipx2+1+scr->clipx-w)>>1; if(flags&1) { // FOR NOW, flags & 1 INDICATES THE MENU IS TO BE DISPLAYED AS A DIRECTORY //ggl_clipvline(scr,scr->clipx2,scr->clipy,scr->clipy2,ggl_mkcolor(color)); ggl_cliphline(scr,scr->clipy2,scr->clipx,scr->clipx2,ggl_mkcolor(8)); } DrawTextN(pos,scr->clipy,(char *)string,(char *)endstring,halScreen.MenuFont,color,scr); // DARKEN/LIGHTEN EFFECT ON LAST FEW PIXELS if(w>=scr->clipx2-scr->clipx) { scr->x=scr->clipx2; scr->y=scr->clipy; ggl_filter(scr,1,scr->clipy2-scr->clipy+1,0xA,(color)? &ggl_fltlighten:&ggl_fltdarken); scr->x--; ggl_filter(scr,1,scr->clipy2-scr->clipy+1,0x6,(color)? &ggl_fltlighten:&ggl_fltdarken); scr->x--; ggl_filter(scr,1,scr->clipy2-scr->clipy+1,0x4,(color)? &ggl_fltlighten:&ggl_fltdarken); } if(flags&2) { // SECOND BIT IN FLAGS MEANS INVERTED scr->x=scr->clipx; scr->y=scr->clipy; ggl_filter(scr,scr->clipx2-scr->clipx+1,scr->clipy2-scr->clipy+1,0,&ggl_fltinvert); } return; }