123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351 |
- /*
- * 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 <http://www.gnu.org/licenses/>.
- */
- #include "la_5.h"
- STRUCTURE(ExampleItem){
- laListItem Item;
- laSafeString* Name;
- laSafeString* Path;
- laSafeString* Code;
- laUiDefineFunc Define;
- };
- STRUCTURE(ExampleViewer){
- real pad;
- laListHandle Examples;
- ExampleItem* CurrentExample;
- int ShowCode;
- };
- ExampleViewer* EV;
- void ExamplesList(laUiList *uil, laPropPack *This, laPropPack *DetachedProps, laColumn *UNUSED, int context){
- laColumn* c=laFirstColumn(uil),*cl,*cr; laSplitColumn(uil,c,0.4); cl=laLeftColumn(c,7); cr=laRightColumn(c,0);
- laShowItemFull(uil,cl,0,"viewer.examples",0,0,laui_IdentifierOnly,0);
- laUiItem* b=laOnConditionThat(uil,cr,laPropExpression(0,"viewer.current"));{
- laShowItemFull(uil,cr,0,"viewer.examples",LA_WIDGET_COLLECTION_SINGLE,0,0,0)->Flags|=LA_UI_FLAGS_NO_DECAL;
- }laElse(uil,b);{
- laShowLabel(uil,cr,"Select an example to begin.",0,0);
- }laEndCondition(uil,b);
- }
- static void AddExample(char* name, char* path, laUiDefineFunc func){
- ExampleItem* ei=memAcquire(sizeof(ExampleItem));
- strSafeSet(&ei->Name,name); strSafeSet(&ei->Path,path); ei->Define=func; strSafeSet(&ei->Code,"// Unable to locate source code for this example");
- lstAppendItem(&EV->Examples,ei);
- char filename[512]; sprintf(filename,"example_source_files/%s.c",path);
- FILE* f=fopen(filename,"r"); if(!f) return;
- int s; fseek(f,0,SEEK_END); s=ftell(f); fseek(f,0,SEEK_SET); if(!s){ fclose(f); return; }
- char* buf=calloc(1,s+1); fread(buf,s,1,f); fclose(f);
- strSafeSet(&ei->Code,buf);
- free(buf);
- }
- static void ExamplesCleanUp(){
- ExampleItem* ei;
- while(ei=lstPopItem(&EV->Examples)){ strSafeDestroy(&ei->Name); strSafeDestroy(&ei->Path); strSafeDestroy(&ei->Code); memFree(ei); }
- memFree(EV);
- }
- #define EXAMPLE_COMMON_BEGIN \
- ExampleItem* ei=This->EndInstance;\
- laColumn* c=laFirstColumn(uil);\
- laUiItem* row=laBeginRow(uil,c,0,0);\
- laShowItem(uil,c,This,"name")->Expand=1;\
- laUiItem* eui=laShowItem(uil,c,0,"viewer.show_code");eui->Flags|=LA_UI_FLAGS_EXPAND;\
- laEndRow(uil,row);\
- laUiItem* bu=laOnConditionThat(uil,c,laPropExpression(0,"viewer.show_code"));{\
- char instructions[256]; sprintf(instructions,"text=Open \"%s.c\" in external editor;file=%s.c",ei->Path->Ptr,ei->Path->Ptr);\
- row=laBeginRow(uil,c,0,0); laShowSeparator(uil,c)->Expand=1; \
- laShowItemFull(uil,c,0,"EXAMPLE_open_source_code",0,instructions,0,0);\
- laEndRow(uil,row);\
- laShowSeparator(uil,c);\
- laShowItem(uil,c,This,"base.code")->Extra->HeightCoeff=-2;\
- }laElse(uil,bu);{\
- row=laBeginRow(uil,c,0,0);\
- char instructions[256]; sprintf(instructions,"text=Launch \"%s\";program=%s",ei->Name->Ptr,ei->Path->Ptr);\
- laShowItemFull(uil,c,0,"EXAMPLE_launch_program",0,instructions,0,0);\
- laEndRow(uil,row);\
- laShowSeparator(uil,c);
- #define EXAMPLE_COMMON_END \
- }laEndCondition(uil,bu);
- void ui_Fruits(laUiList *uil, laPropPack *This, laPropPack *DetachedProps, laColumn *UNUSED, int context){
- EXAMPLE_COMMON_BEGIN
- laShowLabel(uil,c,"\
- This demo mainly shows three things:\n\
- 1) The dynamic-typed list manipulation, operators, and UI adaptation in LaGUI.\n\
- 2) The ability to save and load data files based on the data structure description (via PropContainer and Prop).\n\
- 3) Automatic undo-redo support based on data structure description.\n\
- \n\
- Play with this demo:\n\
- --------------------\n\
- 1) Click 'Stuff' and 'Bowl' can reveal things inside those list handles.\n\
- 2) Add or remove fruits or bowls with the UI.\n\
- 3) You can select bowl reference in the last select box (COLLECTION_SELECTOR) of each fruit.\n\
- 4) Try pressing Ctrl-Z/Ctrl-Shift-Z to undo and redo after you changed anything. In the console you should be able to see undo status.\n\
- 5) Try closing the window while you have bowls created, a dialog would show to ask you to save changes.\n\
- 6) Assign new files with the dropbox to the right, use file name ending with .udf to save changes.\n\
- 7) You can later read the files using File->Read.\
- ",0,0)->Flags|=LA_TEXT_LINE_WRAP|LA_TEXT_MONO;
-
- EXAMPLE_COMMON_END
- }
- void ui_Simplest(laUiList *uil, laPropPack *This, laPropPack *DetachedProps, laColumn *UNUSED, int context){
- EXAMPLE_COMMON_BEGIN
- laColumn* c=laFirstColumn(uil);
- laShowLabel(uil,c,"\
- Hello! Thanks for trying LaGUI!\n\
- ===============================\n\
- The first example is the simplest possible LaGUI application, we only create a panel saying \"Hello world!\".\
- ",0,0)->Flags|=LA_TEXT_LINE_WRAP|LA_TEXT_MONO;
- laUiItem* row=laBeginRow(uil,c,0,0);
- laShowItemFull(uil,c,0,"EXAMPLE_launch_program",0,"program=simplest;text=Click to launch the program",0,0);
- laEndRow(uil,row);
- laShowLabel(uil,c,"\n\
- How do I begin?\n\
- ---------------\n\
- Press the 🞆 button on the top left to explore LaGUI's built-in functionalities. Every panel in a LaGUI program should be accessible from the \
- 🞆 menu. Since this is the simplest program, you can only find built-in panels in there.\n\
- \n\
- To manipulate the layout:\n\
- -------------------------\n\
- 1) You can dock panels by pressing the 🗖 button, then drop the panel to approperiate region.\n\
- 2) To tear off a docked the panel, drag the panel title to the center of each region and release.\n\
- 3) You could maximize a region by clicking ⯆ on the top left of each region and select approperiate operations.\n\
- 4) You can also use 🗗 button on the top to create a new window/layout, then dock some new panels there to customize your workspace.\n\
- ",0,0)->Flags|=LA_TEXT_LINE_WRAP|LA_TEXT_MONO;
- EXAMPLE_COMMON_END
- }
- void ui_Operator(laUiList *uil, laPropPack *This, laPropPack *DetachedProps, laColumn *UNUSED, int context){
- EXAMPLE_COMMON_BEGIN
- laColumn* c=laFirstColumn(uil);
- laShowLabel(uil,c,"\n\
- Operator demonstration program\n\
- ------------------------------\n\
- 1) Press the \"Something!\" Button to invoke a one-time operator, you can see some strings printed on stdout and LaGUI Terminal.\n\
- 2) Press the \"Modal!\" Button to invoke a modal operator, the operator would keep printing out pointer coordinates as you move the mouse\
- while the user interface is kept from getting input events.\n\
- 3) Use right mouse button to exit the modal operator.\n\
- Use 🞆->Terminal to show LaGUI Terminal.",0,0)->Flags|=LA_TEXT_LINE_WRAP|LA_TEXT_MONO;
- EXAMPLE_COMMON_END
- }
- void ui_SimpleProperties(laUiList *uil, laPropPack *This, laPropPack *DetachedProps, laColumn *UNUSED, int context){
- EXAMPLE_COMMON_BEGIN
- laColumn* c=laFirstColumn(uil);
- laShowLabel(uil,c,"\n\
- Properties demonstration program\n\
- --------------------------------\n\
- The simplest program to demonstrate how to register properties for them to show on the interface.\n\n\
- Play with this demo:\n\
- --------------------\n\
- 1) You can manipulate the value widgets.\n\
- 2) You can right click them for extra opeartions.\n\
- 3) Create a new \"Properties\" panel from the 🞆 button, \
- verify that adjustiing values in either panels would cause the other panel to refresh in sync.\n\
- 4) Test invoking a operator from property.\n\
- ",0,0)->Flags|=LA_TEXT_LINE_WRAP|LA_TEXT_MONO;
- EXAMPLE_COMMON_END
- }
- void ui_Widgets(laUiList *uil, laPropPack *This, laPropPack *DetachedProps, laColumn *UNUSED, int context){
- EXAMPLE_COMMON_BEGIN
- laShowLabel(uil,c,"\
- This demo shows commom widgets inside LaGUI.\n\
- \n\
- What you need to know about widgets in LaGUI:\n\
- ---------------------------------------------\n\
- 1) Except labels, you need a data source (a defined property in LaGUI) to show any other kind of widget.\n \
- 2) To show a button, you need to define an operator, and an operator is basically what you trigger an action with.\n \
- 3) A widget can have multiple style/looks controlled by mainly `ui->Flags`. Some ui types accept extra instructions as a string, like you \
- could specify \"text=something;\" to a button.\n\
- 4) You could arrange widgets in a columns or rows, also with groups and tabs. Currently, group/subprop widgets can not be used inside a row.\n\
- 5) Canvas widgets are drawn on their own offscreen buffers. They can also be customized to have your own drawing and event handling callbacks, \
- they can be set to display a certain property as well.\n\
- ",0,0)->Flags|=LA_TEXT_LINE_WRAP|LA_TEXT_MONO;
-
- EXAMPLE_COMMON_END
- }
- void ui_WidgetFlags(laUiList *uil, laPropPack *This, laPropPack *DetachedProps, laColumn *UNUSED, int context){
- EXAMPLE_COMMON_BEGIN
- laShowLabel(uil,c,"\
- This demo shows most-used UI flags and their effects on widgets.\n\
- \n\
- When using widget creator like `laShowItem`, set ui->Flags to the combination of UI flags to adjust the look and interaction of the widget. \
- Not all UI flags are supported by every kind of widgets, but the most common ones can always be used, and widgets will just ignore unsupported \
- UI flags and won't generate any errors.\n\
- \n\
- Launch the program to see the effect of each UI flags.\
- ",0,0)->Flags|=LA_TEXT_LINE_WRAP|LA_TEXT_MONO;
-
- EXAMPLE_COMMON_END
- }
- void ui_Calculator(laUiList *uil, laPropPack *This, laPropPack *DetachedProps, laColumn *UNUSED, int context){
- EXAMPLE_COMMON_BEGIN
- laColumn* c=laFirstColumn(uil);
- laShowLabel(uil,c,"\
- Calculator demo\n\
- ===============\n\
- This program mainly demonstrates how to use LaGUI to create a node-based UI. The program creates a simple node-socket graph structure for \
- the user to edit the data flow and the logic. The demo didn't implement the actual \"evaluation\" part, it's mainly to provide a reference to \
- how should one create such a data structure description in LaGUI's property system, and the special UI flags for enabling the node rack canvas.\n\
- ",0,0)->Flags|=LA_TEXT_LINE_WRAP|LA_TEXT_MONO;
- laShowLabel(uil,c,"\
- Play with calculator demo:\n\
- --------------------------\n\
- 1) Click \"New Calculator\" to create a calculator page.\n\
- 2) Click the \"+\" buttons to the left/right of the rack name to add a node rack.\n\
- 3) Click \"Add Node\" button to insert a node into the rack.\n\
- 4) Insert more nodes and connecct nodes with each other, you can create more racks too.\n\
- 5) Ctrl-Z and Ctrl-Shift-Z to undo and redo, you should be able to see connections change as how you manipulated them.\n\
- 6) Try closing the window while you have an caluclator, a dialog would show to ask you to save changes. You can save them too.\n\
- 7) If you try to read calculator files, the calculator page that's referenced by any \"Reference\" node will be automatically loaded too.\n\
- 8) The imlementation of a DAG evaluator is left for you as a practice.\n\
- 9) There are some node-related configurable options in user preferences, try changing those and see what those options do.\n\
- ",0,0)->Flags|=LA_TEXT_LINE_WRAP|LA_TEXT_MONO;
- EXAMPLE_COMMON_END
- }
- void ui_Modelling(laUiList *uil, laPropPack *This, laPropPack *DetachedProps, laColumn *UNUSED, int context){
- EXAMPLE_COMMON_BEGIN
- laColumn* c=laFirstColumn(uil);
- laShowLabel(uil,c,"\
- Modelling functionality demo\n\
- ============================\n\
- LaGUI has a simple geometry layer that allows you to load or model mesh geometries. This example demonstrates the default modeller. \
- ",0,0)->Flags|=LA_TEXT_LINE_WRAP|LA_TEXT_MONO;
- EXAMPLE_COMMON_END
- }
- int inv_LaunchDemo(laOperator* a, laEvent* e){
- char* program=strGetArgumentString(a->ExtraInstructionsP,"program"); if(!program) return LA_FINISHED;
- char command[512]; sprintf(command,"./%s &",program);
- system(command);
- return LA_FINISHED;
- }
- int inv_OpenDemoSource(laOperator* a, laEvent* e){
- char* file=strGetArgumentString(a->ExtraInstructionsP,"file"); if(!file) return LA_FINISHED;
- char command[512]; sprintf(command,"xdg-open example_source_files/%s &",file);
- system(command);
- return LA_FINISHED;
- }
- laPropContainer *pcGeneric,*pcFruits,*pcSimplest,*pcOperator,*pcSimpleProperties,*pcModelling,*pcCalculator,*pcWidgets,*pcWidgetFlags;
- void* get_ExampleViewer(void* unused){
- return EV;
- }
- laPropContainer* get_ExamplesGetType(ExampleItem* ei){
- if(ei->Define==ui_Fruits) return pcFruits;
- if(ei->Define==ui_Simplest) return pcSimplest;
- if(ei->Define==ui_Operator) return pcOperator;
- if(ei->Define==ui_SimpleProperties) return pcSimpleProperties;
- if(ei->Define==ui_Modelling) return pcModelling;
- if(ei->Define==ui_Calculator) return pcCalculator;
- if(ei->Define==ui_Widgets) return pcWidgets;
- if(ei->Define==ui_WidgetFlags) return pcWidgetFlags;
- return pcGeneric;
- }
- void set_CurrentExample(ExampleViewer* v, ExampleItem* ei){
- memAssignRef(v,&v->CurrentExample, ei); v->ShowCode=0;
- }
- #define EXAMPLE_ADD_PC(name,_PC,_UI) \
- pc=laAddPropertyContainer("example_" name, name "Example", name "example",0,_UI,sizeof(ExampleItem),0,0,1); _PC=pc;\
- laAddStringProperty(pc,"name","Name","Name of the example",LA_WIDGET_STRING_PLAIN,0,0,0,1,offsetof(ExampleItem,Name),0,0,0,0,LA_READ_ONLY|LA_AS_IDENTIFIER);\
- laAddSubGroup(pc,"base","Base","Base example","program_example",0,0,0,0,0,0,0,0,0,0,0,LA_UDF_LOCAL);
- static void InitExamples(){
- laCreateOperatorType("EXAMPLE_launch_program","Launch Program", "Launch example program",0,0,0,inv_LaunchDemo,0,L'🏃',0);
- laCreateOperatorType("EXAMPLE_open_source_code","Open Source Code", "Open source code of the example in a external program",0,0,0,inv_OpenDemoSource,0,L'🡵',0);
- laPropContainer* root=laDefineRoot(),*pc; laProp*p;
- laAddSubGroup(root,"viewer","Viewer","Example viewer","example_viewer",0,0,0,-1,0,get_ExampleViewer,0,0,0,0,0,0);
- pc=laAddPropertyContainer("example_viewer","Example Viewer","Example viewer root data",0,0,sizeof(ExampleViewer),0,0,1);
- laAddSubGroup(pc,"examples","Examples","Example programs","program_example",get_ExamplesGetType,0,0,offsetof(ExampleViewer,CurrentExample),0,0,0,set_CurrentExample,0,0,offsetof(ExampleViewer,Examples),0);
- laAddSubGroup(pc,"current","Current Example","Current example","program_example",get_ExamplesGetType,0,0,offsetof(ExampleViewer,CurrentExample),0,0,0,0,0,0,0,LA_UDF_REFER);
- p=laAddEnumProperty(pc,"show_code","Show Code","Show code instead of descriptions",0,0,0,0,0,offsetof(ExampleViewer,ShowCode),0,0,0,0,0,0,0,0,0,0);
- laAddEnumItemAs(p,"DESC","Description","Show description of the example",0,0);
- laAddEnumItemAs(p,"IMPL","Code","Show implementation of the example",1,0);
- pc=laAddPropertyContainer("program_example","Program Example","Program example",0,laui_IdentifierOnly,sizeof(ExampleItem),0,0,1); pcGeneric=pc;
- laAddStringProperty(pc,"name","Name","Name of the example",LA_WIDGET_STRING_PLAIN,0,0,0,1,offsetof(ExampleItem,Name),0,0,0,0,LA_READ_ONLY|LA_AS_IDENTIFIER);
- laAddStringProperty(pc,"code","Code","Code of the example",LA_WIDGET_STRING_MULTI,0,0,0,1,offsetof(ExampleItem,Code),0,0,0,0,LA_READ_ONLY);
-
- EXAMPLE_ADD_PC("simplest",pcSimplest,ui_Simplest);
- EXAMPLE_ADD_PC("operator",pcOperator,ui_Operator);
- EXAMPLE_ADD_PC("simple_properties",pcSimpleProperties,ui_SimpleProperties);
- EXAMPLE_ADD_PC("fruits",pcFruits,ui_Fruits);
- EXAMPLE_ADD_PC("widgets",pcWidgets,ui_Widgets);
- EXAMPLE_ADD_PC("widget_flags",pcWidgetFlags,ui_WidgetFlags);
- EXAMPLE_ADD_PC("calculator",pcCalculator,ui_Calculator);
- EXAMPLE_ADD_PC("modelling_main",pcModelling,ui_Modelling);
- EV=memAcquire(sizeof(ExampleViewer));
- AddExample("Simplest","simplest",ui_Simplest);
- AddExample("Operator","operator",ui_Operator);
- AddExample("Simple Properties","simple_properties",ui_SimpleProperties);
- AddExample("Widgets","widgets",ui_Widgets);
- AddExample("Widget Flags","widget_flags",ui_WidgetFlags);
- AddExample("Fruits","fruits",ui_Fruits);
- AddExample("Calculator","calculator",ui_Calculator);
- AddExample("Modelling","modelling_main",ui_Modelling);
- laSetCleanupCallback(ExamplesCleanUp);
- }
- int main(int argc, char *argv[]){
- laGetReady();
- char buf[512];getcwd(buf,512);
- printf("%s\n",buf);
- InitExamples();
- laRegisterUiTemplate("examples_list","Examples List", ExamplesList,0,0,"Demonstration",0,0,0);
- laWindow* w = laDesignWindow(-1,-1,800,600);
- laLayout* l = laDesignLayout(w,"LaGUI Examples");
- laCreatePanel(l->FirstBlock,"examples_list");
- laStartWindow(w);
- laMainLoop();
- }
|