/* * Part of LaGUI demonstration programs * Copyright (C) 2022-2023 Wu Yiming * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "la_5.h" extern LA MAIN; STRUCTURE(Bowl){ laListItem Item; laSafeString* Name; laListHandle Fruits; }; STRUCTURE(Basket){ int pad; int example; laSafeString* name; laListHandle Stuff; laListHandle Bowls; }; #define FRUIT_TYPE_APPLE 1 #define FRUIT_TYPE_PEAR 2 STRUCTURE(Fruit){ laListItem Item; int Type; Fruit* WhyNot; laListHandle* Parent; Bowl* Container; laListHandle Bundled; }; STRUCTURE(Apple){ Fruit Base; real HowSweet; }; STRUCTURE(Pear){ Fruit Base; int Really; }; Basket B={0}; laPropContainer* pcApple,*pcPear; laProp* pBasket, *pFruit, *pBowl; int INV_AddBowl(laOperator* a, laEvent* e){ Bowl* b=memAcquireHyper(sizeof(Bowl)); lstAppendItem(&B.Bowls,b); laRecordAndPushProp(0, "basket");laNotifyUsers("basket"); laPrintDBInstInfo(); return LA_FINISHED; } int INV_RemoveBowl(laOperator* a, laEvent* e){ Bowl* b=a->This?a->This->EndInstance:B.Bowls.pLast; if(!b) return LA_FINISHED; lstRemoveItem(&B.Bowls, b); memLeave(b); laRecordAndPushProp(0, "basket");laNotifyUsers("basket"); laPrintDBInstInfo(); return LA_FINISHED; } int INV_AddFruit(laOperator* a, laEvent* e){ laListHandle* into=(a->This&&a->This->LastPs->p==pBowl)?&((Bowl*)a->This->EndInstance)->Fruits:0; if(!into) into=a->This?&((Fruit*)a->This->EndInstance)->Bundled:0; char* stype; int size=sizeof(Apple); int type=FRUIT_TYPE_APPLE; if(stype=strGetArgumentString(a->ExtraInstructionsP,"type")){ if(!strcmp(stype,"pear")) {size=sizeof(Pear);type=FRUIT_TYPE_PEAR;} } Fruit* f=memAcquire(size); f->Type=type; if(into){ lstAppendItem(into, f); f->Parent=into; laNotifyUsers("basket"); /*laNotifyUsersPPPath(a->This,"base.bundled");*/ } else{ lstAppendItem(&B.Stuff, f); laNotifyUsers("basket");} laRecordAndPushProp(0, "basket"); laPrintDBInstInfo(); return LA_FINISHED; } void DestroyFruit(Fruit* f){ Fruit* NextF; for(Fruit*fi=f->Bundled.pFirst;fi;fi=NextF){ NextF=fi->Item.pNext; DestroyFruit(fi); } memLeave(f); } int INV_RemoveFruit(laOperator* a, laEvent* e){ Fruit* f=a->This?a->This->EndInstance:0; laListHandle* l; if(f->Parent){ l=f->Parent;lstRemoveItem(l,f); laNotifyUsers("basket"); } else{ l=&B.Stuff; lstRemoveItem(l,f);laNotifyUsers("basket"); } DestroyFruit(f); laRecordAndPushProp(0, "basket"); return LA_FINISHED; } int INV_MoveFruit(laOperator* a, laEvent* e){ Fruit* f=a->This?a->This->EndInstance:0; laListHandle* l; int direction=0; char* dir; if(dir=strGetArgumentString(a->ExtraInstructionsP,"direction")){ if(!strcmp(dir,"up")) {direction=1;} } if(f->Parent){ l=f->Parent; laNotifyUsers("basket"); /*laNotifyUsersPPPath(a->This,"base.parent.bundled");*/ } else{ l=&B.Stuff; laNotifyUsers("basket"); } if(direction) lstMoveUp(l,f); else lstMoveDown(l,f); laRecordAndPushProp(0, "basket"); return LA_FINISHED; } int INV_PushBasketState(laOperator* a, laEvent* e){ laRecordAndPushProp(0, "basket"); logPrint("Pushed state: \"basket\"\n"); return LA_FINISHED; } laPropContainer* FruitGetType(Fruit* f){ if(f->Type==FRUIT_TYPE_APPLE) return pcApple; if(f->Type==FRUIT_TYPE_PEAR) return pcPear; return pcApple; } void* FruitGetBasket(void* none){ return &B; } void* BowlGetFirst(void* none, void *UNUSED){ return B.Bowls.pFirst; } void* FruitGetFirst(void* none, void *UNUSED){ return B.Stuff.pFirst; } void FruitsPanel(laUiList *uil, laPropPack *This, laPropPack *DetachedProps, laColumn *UNUSED, int context){ laColumn* c=laFirstColumn(uil); laColumn* cl; laSplitColumn(uil,c,0.5); cl=laLeftColumn(c,0); laShowItem(uil,c,0,"basket"); laUiItem* r=laBeginRow(uil,c,0,0); strSafeSet(&laShowItem(uil,c,0,"FRUIT_add")->ExtraInstructions,"type=apple;icon=๐Ÿ;text=Add Apple;"); strSafeSet(&laShowItem(uil,c,0,"FRUIT_add")->ExtraInstructions,"type=pear;icon=๐Ÿ;text=Add Pear;"); laShowItem(uil,c,0,"BOWL_add"); laEndRow(uil,r); laShowSeparator(uil,c); r=laBeginRow(uil,c,0,0); laShowItem(uil,c,0,"LA_undo"); laShowItem(uil,c,0,"LA_redo"); laShowItem(uil,c,0,"STATE_push"); laEndRow(uil,r); } void UIBowl(laUiList *uil, laPropPack *This, laPropPack *DetachedProps, laColumn *UNUSED, int context){ laColumn* c=laFirstColumn(uil); laColumn* cl,*cr; laSplitColumn(uil,c,0.4); cl=laLeftColumn(c, 1); cr=laRightColumn(c,0); laUiItem*u; laUiItem* r=laBeginRow(uil,cr,1,0); laShowItem(uil,cr,This,"name")->Expand=1; laShowItem(uil,cr,This,"remove")->Flags|=LA_UI_FLAGS_ICON; laEndRow(uil,r); r=laOnConditionToggle(uil,cl,0,0,0,0,0);{ laShowItem(uil,cr,This,"fruits"); laUiItem* r1=laBeginRow(uil,cr,0,0); strSafeSet(&laShowItem(uil,cr,This,"add_fruit")->ExtraInstructions,"type=apple;icon=๐Ÿ;text=Add Apple;"); strSafeSet(&laShowItem(uil,cr,This,"add_fruit")->ExtraInstructions,"type=pear;icon=๐Ÿ;text=Add Pear;"); laEndRow(uil,r1); }laEndCondition(uil,r); } void UIApple(laUiList *uil, laPropPack *This, laPropPack *DetachedProps, laColumn *UNUSED, int context){ laColumn* c=laFirstColumn(uil); laColumn* cl,*cr; laSplitColumn(uil,c,0.4); cl=laLeftColumn(c, 1); cr=laRightColumn(c,0); laUiItem*u; laUiItem* r=laBeginRow(uil,cr,1,0); laShowLabel(uil,cr,"Apple",0,0)->Expand=1; laShowItem(uil,cr,This,"how_sweet")->Expand=1; laShowItem(uil,cr,This,"base.why_not")->Expand=1; laShowItem(uil,cr,This,"base.container")->Expand=1; laShowItem(uil,cr,This,"base.remove")->Flags|=LA_UI_FLAGS_ICON; u=laShowItem(uil,cr,This,"base.move"); strSafeSet(&u->ExtraInstructions,"direction=up;icon=๐Ÿกน;");u->Flags|=LA_UI_FLAGS_ICON; u=laShowItem(uil,cr,This,"base.move"); strSafeSet(&u->ExtraInstructions,"direction=down;icon=๐Ÿกป;");u->Flags|=LA_UI_FLAGS_ICON; laEndRow(uil,r); r=laOnConditionToggle(uil,cl,0,0,0,0,0);{ laShowItem(uil,cr,This,"base.bundled"); laUiItem* r1=laBeginRow(uil,cr,0,0); strSafeSet(&laShowItem(uil,cr,This,"base.add")->ExtraInstructions,"type=apple;icon=๐Ÿ;text=Add Apple;"); strSafeSet(&laShowItem(uil,cr,This,"base.add")->ExtraInstructions,"type=pear;icon=๐Ÿ;text=Add Pear;"); laEndRow(uil,r1); }laEndCondition(uil,r); } void UIPear(laUiList *uil, laPropPack *This, laPropPack *DetachedProps, laColumn *UNUSED, int context){ laColumn* c=laFirstColumn(uil); laColumn* cl,*cr; laSplitColumn(uil,c,0.4); cl=laLeftColumn(c, 1); cr=laRightColumn(c,0); laUiItem*u; laUiItem* r=laBeginRow(uil,cr,1,0); laShowLabel(uil,cr,"Pear",0,0)->Expand=1; laShowItem(uil,cr,This,"really")->Expand=1; laShowItem(uil,cr,This,"base.why_not")->Expand=1; laShowItem(uil,cr,This,"base.container")->Expand=1; laShowItem(uil,cr,This,"base.remove")->Flags|=LA_UI_FLAGS_ICON; u=laShowItem(uil,cr,This,"base.move"); strSafeSet(&u->ExtraInstructions,"direction=up;icon=๐Ÿกน;");u->Flags|=LA_UI_FLAGS_ICON; u=laShowItem(uil,cr,This,"base.move"); strSafeSet(&u->ExtraInstructions,"direction=down;icon=๐Ÿกป;");u->Flags|=LA_UI_FLAGS_ICON; laEndRow(uil,r); r=laOnConditionToggle(uil,cl,0,0,0,0,0);{ laShowItem(uil,cr,This,"base.bundled"); laUiItem* r1=laBeginRow(uil,cr,0,0); strSafeSet(&laShowItem(uil,cr,This,"base.add")->ExtraInstructions,"type=apple;icon=๐Ÿ;text=Add Apple;"); strSafeSet(&laShowItem(uil,cr,This,"base.add")->ExtraInstructions,"type=pear;icon=๐Ÿ;text=Add Pear;"); laEndRow(uil,r1); }laEndCondition(uil,r); } void UIBowlSimple(laUiList *uil, laPropPack *This, laPropPack *DetachedProps, laColumn *UNUSED, int context){ laColumn* c=laFirstColumn(uil); laShowItemFull(uil,c,This,"name",LA_WIDGET_STRING_PLAIN, 0 ,0,0); } void UIFruitSimple(laUiList *uil, laPropPack *This, laPropPack *DetachedProps, laColumn *UNUSED, int context){ laColumn* c=laFirstColumn(uil); laShowItem(uil,c,This,"type"); } int RegisterEverything(){ laRegisterUiTemplate("panel_fruit", "Fruits", FruitsPanel, 0, 0,0, 0,0,0); laCreateOperatorType("BOWL_add", "Add Bowl", "Add a bowl", 0,0,0,INV_AddBowl,0,'+',0); laCreateOperatorType("BOWL_remove", "Remove Bowl", "Remove a bowl", 0,0,0,INV_RemoveBowl,0,'-',0); laCreateOperatorType("FRUIT_add", "Add Fruit", "Add a fruit into the basket or bundle", 0,0,0,INV_AddFruit,0,'+',0); laCreateOperatorType("FRUIT_remove", "Remove Fruit", "Remove a fruit", 0,0,0,INV_RemoveFruit,0,'-',0); laCreateOperatorType("FRUIT_move", "Move Fruit", "Move a fruit", 0,0,0,INV_MoveFruit,0,'~',0); laCreateOperatorType("STATE_push", "Push State", "Push basket state", 0,0,0,INV_PushBasketState,0,0,0); laPropContainer* pc=laDefineRoot(); laAddSubGroup(pc, "basket", "Basket", "The basket", "basket",0,0,0,-1,FruitGetBasket,0,0,0,0,0,0,LA_UDF_SINGLE|LA_UDF_LOCAL); laProp*p; pc=laAddPropertyContainer("bowl", "Bowl", "Some sort of a bowl", 0, UIBowl, sizeof(Bowl), 0, 0, 2); laAddStringProperty(pc,"name","Name","Name of the bowl",0,0,0,0,1,offsetof(Bowl,Name),0,0,0,0,LA_AS_IDENTIFIER); laAddSubGroup(pc, "fruits", "Fruits","Fruits","fruit",FruitGetType,0,0,-1,0,0,0,0,0,0,offsetof(Bowl,Fruits),0); laAddOperatorProperty(pc,"remove","Remove","Remove a bowl", "BOWL_remove", '-', 0); laAddOperatorProperty(pc,"add_fruit","Add","Add a fruit into the bowl", "FRUIT_add", '+', 0); pc=laAddPropertyContainer("basket", "Basket", "A basket of fruits", 0, 0, sizeof(Basket), 0, 0, 1|LA_UDF_LOCAL|LA_PROP_OTHER_ALLOC|LA_UDF_SINGLE); laAddIntProperty(pc,"example","Example","Example int",0,0,0,0,0,1,0,0,offsetof(Basket,example),0,0,0,0,0,0,0,0,0,0,0); laAddStringProperty(pc,"name","Name","Name of the basket",0,0,0,0,1,offsetof(Basket,name),0,0,0,0,LA_UDF_REFER); laAddSubGroup(pc, "stuff", "Stuff","Stuffs","fruit",FruitGetType,0,0,-1,0,0,0,0,0,0,offsetof(Basket,Stuff),0); pBowl = laAddSubGroup(pc, "bowls", "Bowls","Bowls","bowl",0,0,0,-1,0,0,0,0,0,0,offsetof(Basket,Bowls),0); pc=laAddPropertyContainer("fruit", "Fruit", "A fruit", 0, 0, sizeof(Fruit), 0, 0, 1); p=laAddEnumProperty(pc,"type","Type","Type",0,0,0,0,0,offsetof(Fruit,Type),0,0,0,0,0,0,0,0,0,LA_AS_IDENTIFIER|LA_READ_ONLY); laAddEnumItemAs(p,"APPLE","Apple","Apple", FRUIT_TYPE_APPLE, L'๐Ÿ'); laAddEnumItemAs(p,"PEAR","Pear","Pear", FRUIT_TYPE_PEAR, L'๐Ÿ'); pFruit = laAddSubGroup(pc, "bundled", "Bundled","Bundled","fruit",FruitGetType,0,0,-1,0,0,0,0,0,0,offsetof(Fruit,Bundled),0); laAddSubGroup(pc, "why_not", "Why Not","Why not try","fruit",0,LA_WIDGET_COLLECTION_SELECTOR,UIFruitSimple,offsetof(Fruit,WhyNot),FruitGetFirst,0,laget_ListNext,0,0,0,0,LA_UDF_REFER); laAddSubGroup(pc, "parent", "Parent","Parent","any_pointer",0,0,0,offsetof(Fruit,Parent),0,0,0,0,0,0,0,LA_UDF_REFER); laAddSubGroup(pc, "container", "Container","Container of this fruit","bowl",0,LA_WIDGET_COLLECTION_SELECTOR,UIBowlSimple,offsetof(Fruit, Container),BowlGetFirst,0,laget_ListNext,0,0,0,0,LA_UDF_REFER); laAddOperatorProperty(pc,"add","Add","Add a fruit into bundled", "FRUIT_add", '+', 0); laAddOperatorProperty(pc,"remove","Remove","Remove a fruit", "FRUIT_remove", '-', 0); laAddOperatorProperty(pc,"move","Move","Move a fruit", "FRUIT_move", '~', 0); pcApple=pc=laAddPropertyContainer("apple", "Apple", "An apple", 0, UIApple, sizeof(Apple), 0, 0, 1); laAddSubGroup(pc,"base", "Base","Base fruit","fruit",0,0,0,0,0,0,0,0,0,0,0,LA_UDF_SINGLE|LA_UDF_LOCAL); laAddFloatProperty(pc,"how_sweet","How Sweet","How sweet",0,0,0,100,0,0.1,0,0,offsetof(Apple,HowSweet),0,0,0,0,0,0,0,0,0,0,LA_AS_IDENTIFIER); pcPear=pc=laAddPropertyContainer("pear", "Pear", "A pear", 0, UIPear, sizeof(Pear), 0, 0, 1); laAddSubGroup(pc, "base","Base","Base fruit","fruit",0,0,0,0,0,0,0,0,0,0,0,LA_UDF_SINGLE|LA_UDF_LOCAL); p=laAddEnumProperty(pc,"really","Really","Really a pear?",LA_WIDGET_ENUM_CYCLE,0,0,0,0,offsetof(Pear,Really),0,0,0,0,0,0,0,0,0,LA_AS_IDENTIFIER); laAddEnumItemAs(p,"NAH","Nah","Nah I don't think so", 0, L'๐Ÿค”'); laAddEnumItemAs(p,"YEAH","Yeah","It's really a pear", 1, L'๐Ÿ˜„'); laSaveProp("basket"); tnsObject* s=tnsCreateRootObject("My Root", 0); tnsObject* o=tnsCreateLight(s,"Sun",100,100,100,1,1); tnsVector3d target={0,0,0}, up={0,0,1}; tnsLookAt(o,target,up); } int main(int argc, char *argv[]){ laGetReady(); RegisterEverything(); laRefreshUDFRegistries(); // Use this to save and load preference when exit and during start up // laEnsureUserPreferences(); laAddRootDBInst("basket"); laWindow* w = laDesignWindow(-1,-1,600,600); laLayout* l = laDesignLayout(w, "Fruit Layout"); laBlock* b = l->FirstBlock; laPanel* p=laCreatePanel(b, "panel_fruit"); laStartWindow(w); laMainLoop(); }