*/}}

example_viewer.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. #include "la_5.h"
  2. STRUCTURE(ExampleItem){
  3. laListItem Item;
  4. laSafeString* Name;
  5. laSafeString* Path;
  6. laSafeString* Code;
  7. laUiDefineFunc Define;
  8. };
  9. STRUCTURE(ExampleViewer){
  10. real pad;
  11. laListHandle Examples;
  12. ExampleItem* CurrentExample;
  13. int ShowCode;
  14. };
  15. ExampleViewer* EV;
  16. void ExamplesList(laUiList *uil, laPropPack *This, laPropPack *DetachedProps, laColumn *UNUSED, int context){
  17. laColumn* c=laFirstColumn(uil),*cl,*cr; laSplitColumn(uil,c,0.4); cl=laLeftColumn(c,7); cr=laRightColumn(c,0);
  18. laShowItemFull(uil,cl,0,"viewer.examples",0,0,laui_IdentifierOnly,0);
  19. laUiItem* b=laOnConditionThat(uil,cr,laPropExpression(0,"viewer.current"));{
  20. laShowItemFull(uil,cr,0,"viewer.examples",LA_WIDGET_COLLECTION_SINGLE,0,0,0)->Flags|=LA_UI_FLAGS_NO_DECAL;
  21. }laElse(uil,b);{
  22. laShowLabel(uil,cr,"Select an example to begin.",0,0);
  23. }laEndCondition(uil,b);
  24. }
  25. static void AddExample(char* name, char* path, laUiDefineFunc func){
  26. ExampleItem* ei=memAcquire(sizeof(ExampleItem));
  27. strSafeSet(&ei->Name,name); strSafeSet(&ei->Path,path); ei->Define=func; strSafeSet(&ei->Code,"// Unable to locate source code for this example");
  28. lstAppendItem(&EV->Examples,ei);
  29. char filename[512]; sprintf(filename,"example_source_files/%s.c",path);
  30. FILE* f=fopen(filename,"r"); if(!f) return;
  31. int s; fseek(f,0,SEEK_END); s=ftell(f); fseek(f,0,SEEK_SET); if(!s){ fclose(f); return; }
  32. char* buf=calloc(1,s); fread(buf,s,1,f); fclose(f);
  33. strSafeSet(&ei->Code,buf);
  34. free(buf);
  35. }
  36. static void ExamplesCleanUp(){
  37. ExampleItem* ei;
  38. while(ei=lstPopItem(&EV->Examples)){ strSafeDestroy(&ei->Name); strSafeDestroy(&ei->Path); strSafeDestroy(&ei->Code); memFree(ei); }
  39. memFree(EV);
  40. }
  41. #define EXAMPLE_COMMON_BEGIN\
  42. ExampleItem* ei=This->EndInstance;\
  43. laColumn* c=laFirstColumn(uil);\
  44. laUiItem* row=laBeginRow(uil,c,0,0);\
  45. laShowItem(uil,c,This,"name")->Expand=1;\
  46. laUiItem* eui=laShowItem(uil,c,0,"viewer.show_code");eui->Flags|=LA_UI_FLAGS_EXPAND;\
  47. laEndRow(uil,row);\
  48. laUiItem* bu=laOnConditionThat(uil,c,laPropExpression(0,"viewer.show_code"));{\
  49. char instructions[256]; sprintf(instructions,"text=Open \"%s.c\" in external editor;file=%s.c",ei->Path->Ptr,ei->Path->Ptr);\
  50. row=laBeginRow(uil,c,0,0); laShowSeparator(uil,c)->Expand=1; \
  51. laShowItemFull(uil,c,0,"EXAMPLE_open_source_code",0,instructions,0,0);\
  52. laEndRow(uil,row);\
  53. laShowSeparator(uil,c);\
  54. laShowItem(uil,c,This,"code")->Extra->HeightCoeff=-2;\
  55. }laElse(uil,bu);{\
  56. row=laBeginRow(uil,c,0,0);\
  57. char instructions[256]; sprintf(instructions,"text=Launch \"%s\";program=%s",ei->Name->Ptr,ei->Path->Ptr);\
  58. laShowItemFull(uil,c,0,"EXAMPLE_launch_program",0,instructions,0,0);\
  59. laEndRow(uil,row);\
  60. laShowSeparator(uil,c);
  61. #define EXAMPLE_COMMON_END\
  62. }laEndCondition(uil,bu);
  63. void ui_Fruits(laUiList *uil, laPropPack *This, laPropPack *DetachedProps, laColumn *UNUSED, int context){
  64. EXAMPLE_COMMON_BEGIN
  65. laShowLabel(uil,c,"\
  66. This demo mainly shows three things:\n\
  67. 1) The dynamic-typed list manipulation, operators, and UI adaptation in LaGUI.\n\
  68. 2) The ability to save and load data files based on the data structure description (via PropContainer and Prop).\n\
  69. 3) Automatic undo-redo support based on data structure description.\n\
  70. \n\
  71. Play with this demo:\n\
  72. --------------------\n\
  73. 1) Click 'Stuff' and 'Bowl' can reveal things inside those list handles.\n\
  74. 2) Add or remove fruits or bowls with the UI.\n\
  75. 3) You can select bowl reference in the last select box (COLLECTION_SELECTOR) of each fruit.\n\
  76. 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\
  77. 5) Try closing the window while you have bowls created, a dialog would show to ask you to save changes.\n\
  78. 6) Assign new files with the dropbox to the right, use file name ending with .udf to save changes.\n\
  79. 7) You can later read the files using File->Read.\
  80. ",0,0)->Flags|=LA_TEXT_LINE_WRAP|LA_TEXT_MONO;
  81. EXAMPLE_COMMON_END
  82. }
  83. void ui_Simplest(laUiList *uil, laPropPack *This, laPropPack *DetachedProps, laColumn *UNUSED, int context){
  84. EXAMPLE_COMMON_BEGIN
  85. laColumn* c=laFirstColumn(uil);
  86. laShowLabel(uil,c,"\
  87. Hello! Thanks for trying LaGUI!\n\
  88. ===============================\n\
  89. The first example is the simplest possible LaGUI application, we only create a panel saying \"Hello world!\".\
  90. ",0,0)->Flags|=LA_TEXT_LINE_WRAP|LA_TEXT_MONO;
  91. laUiItem* row=laBeginRow(uil,c,0,0);
  92. laShowItemFull(uil,c,0,"EXAMPLE_launch_program",0,"program=simplest;text=Click to launch the program",0,0);
  93. laEndRow(uil,row);
  94. laShowLabel(uil,c,"\n\
  95. How do I begin?\n\
  96. ---------------\n\
  97. 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 \
  98. 🞆 menu. Since this is the simplest program, you can only find built-in panels in there.\n\
  99. \n\
  100. To manipulate the layout:\n\
  101. -------------------------\n\
  102. 1) You can dock panels by pressing the 🗖 button, then drop the panel to approperiate region.\n\
  103. 2) To tear down the panel, drag the panel title to the center of each region and release.\n\
  104. 3) You could maximize a region by clicking ⯆ on the top left of each region and select approperiate operations.\n\
  105. 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\
  106. ",0,0)->Flags|=LA_TEXT_LINE_WRAP|LA_TEXT_MONO;
  107. EXAMPLE_COMMON_END
  108. }
  109. void ui_Calculator(laUiList *uil, laPropPack *This, laPropPack *DetachedProps, laColumn *UNUSED, int context){
  110. EXAMPLE_COMMON_BEGIN
  111. laColumn* c=laFirstColumn(uil);
  112. laShowLabel(uil,c,"\
  113. Calculator demo\n\
  114. ===============\n\
  115. This program mainly demonstrates how to use LaGUI to create a node-based UI. The program creates a simple node-socket graph structure for \
  116. 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 \
  117. 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\
  118. ",0,0)->Flags|=LA_TEXT_LINE_WRAP|LA_TEXT_MONO;
  119. laShowLabel(uil,c,"\
  120. Play with calculator demo:\n\
  121. --------------------------\n\
  122. 1) Click \"New Calculator\" to create a calculator page.\n\
  123. 2) Click the \"+\" buttons to the left/right of the rack name to add a node rack.\n\
  124. 3) Click \"Add Node\" button to insert a node into the rack.\n\
  125. 4) Insert more nodes and connecct nodes with each other, you can create more racks too.\n\
  126. 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\
  127. 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\
  128. 7) If you try to read calculator files, the calculator page that's referenced by any \"Reference\" node will be automatically loaded too.\n\
  129. 8) The imlementation of a DAG evaluator is left for you as a practice.\n\
  130. 9) There are some node-related configurable options in user preferences, try changing those and see what those options do.\n\
  131. ",0,0)->Flags|=LA_TEXT_LINE_WRAP|LA_TEXT_MONO;
  132. EXAMPLE_COMMON_END
  133. }
  134. void ui_Modelling(laUiList *uil, laPropPack *This, laPropPack *DetachedProps, laColumn *UNUSED, int context){
  135. EXAMPLE_COMMON_BEGIN
  136. laColumn* c=laFirstColumn(uil);
  137. laShowLabel(uil,c,"\
  138. Modelling functionality demo\n\
  139. ============================\n\
  140. LaGUI has a simple geometry layer that allows you to load or model mesh geometries. This example demonstrates the default modeller. \
  141. ",0,0)->Flags|=LA_TEXT_LINE_WRAP|LA_TEXT_MONO;
  142. EXAMPLE_COMMON_END
  143. }
  144. int inv_LaunchDemo(laOperator* a, laEvent* e){
  145. char* program=strGetArgumentString(a->ExtraInstructionsP,"program"); if(!program) return LA_FINISHED;
  146. char command[512]; sprintf(command,"./%s &",program);
  147. system(command);
  148. return LA_FINISHED;
  149. }
  150. int inv_OpenDemoSource(laOperator* a, laEvent* e){
  151. char* file=strGetArgumentString(a->ExtraInstructionsP,"file"); if(!file) return LA_FINISHED;
  152. char command[512]; sprintf(command,"xdg-open example_source_files/%s &",file);
  153. system(command);
  154. return LA_FINISHED;
  155. }
  156. laPropContainer *pcGeneric,*pcFruits,*pcSimplest,*pcModelling,*pcCalculator;
  157. void* get_ExampleViewer(void* unused){
  158. return EV;
  159. }
  160. laPropContainer* get_ExamplesGetType(void* unused, ExampleItem* ei){
  161. if(ei->Define==ui_Fruits) return pcFruits;
  162. if(ei->Define==ui_Simplest) return pcSimplest;
  163. if(ei->Define==ui_Modelling) return pcModelling;
  164. if(ei->Define==ui_Calculator) return pcCalculator;
  165. return pcGeneric;
  166. }
  167. void set_CurrentExample(ExampleViewer* v, ExampleItem* ei){
  168. memAssignRef(v,&v->CurrentExample, ei); v->ShowCode=0;
  169. }
  170. #define EXAMPLE_ADD_PC(name,_PC,_UI)\
  171. pc=laAddPropertyContainer("example_" name, name "Example", name "example",0,_UI,sizeof(ExampleItem),0,0,1); _PC=pc;\
  172. 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);\
  173. laAddSubGroup(pc,"base","Base","Base example","program_example",0,0,0,0,0,0,0,0,0,0,0,LA_UDF_LOCAL);
  174. static void InitExamples(){
  175. laCreateOperatorType("EXAMPLE_launch_program","Launch Program", "Launch example program",0,0,0,inv_LaunchDemo,0,L'🏃',0);
  176. 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);
  177. laPropContainer* root=laDefineRoot(),*pc; laProp*p;
  178. laAddSubGroup(root,"viewer","Viewer","Example viewer","example_viewer",0,0,0,-1,0,get_ExampleViewer,0,0,0,0,0,0);
  179. pc=laAddPropertyContainer("example_viewer","Example Viewer","Example viewer root data",0,0,sizeof(ExampleViewer),0,0,1);
  180. 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);
  181. 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);
  182. 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);
  183. laAddEnumItemAs(p,"DESC","Description","Show description of the example",0,0);
  184. laAddEnumItemAs(p,"IMPL","Code","Show implementation of the example",1,0);
  185. pc=laAddPropertyContainer("program_example","Program Example","Program example",0,laui_IdentifierOnly,sizeof(ExampleItem),0,0,1); pcGeneric=pc;
  186. 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);
  187. 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);
  188. EXAMPLE_ADD_PC("simplest",pcSimplest,ui_Simplest);
  189. EXAMPLE_ADD_PC("fruits",pcFruits,ui_Fruits);
  190. EXAMPLE_ADD_PC("calculator",pcCalculator,ui_Calculator);
  191. EXAMPLE_ADD_PC("modelling_main",pcModelling,ui_Modelling);
  192. EV=memAcquire(sizeof(ExampleViewer));
  193. AddExample("Simplest","simplest",ui_Simplest);
  194. AddExample("Fruits","fruits",ui_Fruits);
  195. AddExample("Calculator","calculator",ui_Calculator);
  196. AddExample("Modelling","modelling_main",ui_Modelling);
  197. laSetCleanupCallback(ExamplesCleanUp);
  198. }
  199. int main(int argc, char *argv[]){
  200. laGetReady();
  201. char buf[512];getcwd(buf,512);
  202. printf("%s\n",buf);
  203. InitExamples();
  204. laRegisterUiTemplate("examples_list","Examples List", ExamplesList,0,0,"Demonstration");
  205. laWindow* w = laDesignWindow(-1,-1,800,600);
  206. laLayout* l = laDesignLayout(w,"LaGUI Examples");
  207. laCreatePanel(l->FirstBlock,"examples_list");
  208. laStartWindow(w);
  209. laMainLoop();
  210. }