*/}}

example_viewer.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. /*
  2. * Part of LaGUI demonstration programs
  3. * Copyright (C) 2022-2023 Wu Yiming
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "la_5.h"
  19. STRUCTURE(ExampleItem){
  20. laListItem Item;
  21. laSafeString* Name;
  22. laSafeString* Path;
  23. laSafeString* Code;
  24. laUiDefineFunc Define;
  25. };
  26. STRUCTURE(ExampleViewer){
  27. real pad;
  28. laListHandle Examples;
  29. ExampleItem* CurrentExample;
  30. int ShowCode;
  31. };
  32. ExampleViewer* EV;
  33. void ExamplesList(laUiList *uil, laPropPack *This, laPropPack *DetachedProps, laColumn *UNUSED, int context){
  34. laColumn* c=laFirstColumn(uil),*cl,*cr; laSplitColumn(uil,c,0.4); cl=laLeftColumn(c,7); cr=laRightColumn(c,0);
  35. laShowItemFull(uil,cl,0,"viewer.examples",0,0,laui_IdentifierOnly,0);
  36. laUiItem* b=laOnConditionThat(uil,cr,laPropExpression(0,"viewer.current"));{
  37. laShowItemFull(uil,cr,0,"viewer.examples",LA_WIDGET_COLLECTION_SINGLE,0,0,0)->Flags|=LA_UI_FLAGS_NO_DECAL;
  38. }laElse(uil,b);{
  39. laShowLabel(uil,cr,"Select an example to begin.",0,0);
  40. }laEndCondition(uil,b);
  41. }
  42. static void AddExample(char* name, char* path, laUiDefineFunc func){
  43. ExampleItem* ei=memAcquire(sizeof(ExampleItem));
  44. strSafeSet(&ei->Name,name); strSafeSet(&ei->Path,path); ei->Define=func; strSafeSet(&ei->Code,"// Unable to locate source code for this example");
  45. lstAppendItem(&EV->Examples,ei);
  46. char filename[512]; sprintf(filename,"example_source_files/%s.c",path);
  47. FILE* f=fopen(filename,"r"); if(!f) return;
  48. int s; fseek(f,0,SEEK_END); s=ftell(f); fseek(f,0,SEEK_SET); if(!s){ fclose(f); return; }
  49. char* buf=calloc(1,s+1); fread(buf,s,1,f); fclose(f);
  50. strSafeSet(&ei->Code,buf);
  51. free(buf);
  52. }
  53. static void ExamplesCleanUp(){
  54. ExampleItem* ei;
  55. while(ei=lstPopItem(&EV->Examples)){ strSafeDestroy(&ei->Name); strSafeDestroy(&ei->Path); strSafeDestroy(&ei->Code); memFree(ei); }
  56. memFree(EV);
  57. }
  58. #define EXAMPLE_COMMON_BEGIN \
  59. ExampleItem* ei=This->EndInstance;\
  60. laColumn* c=laFirstColumn(uil);\
  61. laUiItem* row=laBeginRow(uil,c,0,0);\
  62. laShowItem(uil,c,This,"name")->Expand=1;\
  63. laUiItem* eui=laShowItem(uil,c,0,"viewer.show_code");eui->Flags|=LA_UI_FLAGS_EXPAND;\
  64. laEndRow(uil,row);\
  65. laUiItem* bu=laOnConditionThat(uil,c,laPropExpression(0,"viewer.show_code"));{\
  66. char instructions[256]; sprintf(instructions,"text=Open \"%s.c\" in external editor;file=%s.c",ei->Path->Ptr,ei->Path->Ptr);\
  67. row=laBeginRow(uil,c,0,0); laShowSeparator(uil,c)->Expand=1; \
  68. laShowItemFull(uil,c,0,"EXAMPLE_open_source_code",0,instructions,0,0);\
  69. laEndRow(uil,row);\
  70. laShowSeparator(uil,c);\
  71. laShowItem(uil,c,This,"base.code")->Extra->HeightCoeff=-2;\
  72. }laElse(uil,bu);{\
  73. row=laBeginRow(uil,c,0,0);\
  74. char instructions[256]; sprintf(instructions,"text=Launch \"%s\";program=%s",ei->Name->Ptr,ei->Path->Ptr);\
  75. laShowItemFull(uil,c,0,"EXAMPLE_launch_program",0,instructions,0,0);\
  76. laEndRow(uil,row);\
  77. laShowSeparator(uil,c);
  78. #define EXAMPLE_COMMON_END \
  79. }laEndCondition(uil,bu);
  80. void ui_Fruits(laUiList *uil, laPropPack *This, laPropPack *DetachedProps, laColumn *UNUSED, int context){
  81. EXAMPLE_COMMON_BEGIN
  82. laShowLabel(uil,c,"\
  83. This demo mainly shows three things:\n\
  84. 1) The dynamic-typed list manipulation, operators, and UI adaptation in LaGUI.\n\
  85. 2) The ability to save and load data files based on the data structure description (via PropContainer and Prop).\n\
  86. 3) Automatic undo-redo support based on data structure description.\n\
  87. \n\
  88. Play with this demo:\n\
  89. --------------------\n\
  90. 1) Click 'Stuff' and 'Bowl' can reveal things inside those list handles.\n\
  91. 2) Add or remove fruits or bowls with the UI.\n\
  92. 3) You can select bowl reference in the last select box (COLLECTION_SELECTOR) of each fruit.\n\
  93. 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\
  94. 5) Try closing the window while you have bowls created, a dialog would show to ask you to save changes.\n\
  95. 6) Assign new files with the dropbox to the right, use file name ending with .udf to save changes.\n\
  96. 7) You can later read the files using File->Read.\
  97. ",0,0)->Flags|=LA_TEXT_LINE_WRAP|LA_TEXT_MONO;
  98. EXAMPLE_COMMON_END
  99. }
  100. void ui_Simplest(laUiList *uil, laPropPack *This, laPropPack *DetachedProps, laColumn *UNUSED, int context){
  101. EXAMPLE_COMMON_BEGIN
  102. laColumn* c=laFirstColumn(uil);
  103. laShowLabel(uil,c,"\
  104. Hello! Thanks for trying LaGUI!\n\
  105. ===============================\n\
  106. The first example is the simplest possible LaGUI application, we only create a panel saying \"Hello world!\".\
  107. ",0,0)->Flags|=LA_TEXT_LINE_WRAP|LA_TEXT_MONO;
  108. laUiItem* row=laBeginRow(uil,c,0,0);
  109. laShowItemFull(uil,c,0,"EXAMPLE_launch_program",0,"program=simplest;text=Click to launch the program",0,0);
  110. laEndRow(uil,row);
  111. laShowLabel(uil,c,"\n\
  112. How do I begin?\n\
  113. ---------------\n\
  114. 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 \
  115. 🞆 menu. Since this is the simplest program, you can only find built-in panels in there.\n\
  116. \n\
  117. To manipulate the layout:\n\
  118. -------------------------\n\
  119. 1) You can dock panels by pressing the 🗖 button, then drop the panel to approperiate region.\n\
  120. 2) To tear off a docked the panel, drag the panel title to the center of each region and release.\n\
  121. 3) You could maximize a region by clicking ⯆ on the top left of each region and select approperiate operations.\n\
  122. 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\
  123. ",0,0)->Flags|=LA_TEXT_LINE_WRAP|LA_TEXT_MONO;
  124. EXAMPLE_COMMON_END
  125. }
  126. void ui_Operator(laUiList *uil, laPropPack *This, laPropPack *DetachedProps, laColumn *UNUSED, int context){
  127. EXAMPLE_COMMON_BEGIN
  128. laColumn* c=laFirstColumn(uil);
  129. laShowLabel(uil,c,"\n\
  130. Operator demonstration program\n\
  131. ------------------------------\n\
  132. 1) Press the \"Something!\" Button to invoke a one-time operator, you can see some strings printed on stdout and LaGUI Terminal.\n\
  133. 2) Press the \"Modal!\" Button to invoke a modal operator, the operator would keep printing out pointer coordinates as you move the mouse\
  134. while the user interface is kept from getting input events.\n\
  135. 3) Use right mouse button to exit the modal operator.\n\
  136. Use 🞆->Terminal to show LaGUI Terminal.",0,0)->Flags|=LA_TEXT_LINE_WRAP|LA_TEXT_MONO;
  137. EXAMPLE_COMMON_END
  138. }
  139. void ui_SimpleProperties(laUiList *uil, laPropPack *This, laPropPack *DetachedProps, laColumn *UNUSED, int context){
  140. EXAMPLE_COMMON_BEGIN
  141. laColumn* c=laFirstColumn(uil);
  142. laShowLabel(uil,c,"\n\
  143. Properties demonstration program\n\
  144. --------------------------------\n\
  145. The simplest program to demonstrate how to register properties for them to show on the interface.\n\n\
  146. Play with this demo:\n\
  147. --------------------\n\
  148. 1) You can manipulate the value widgets.\n\
  149. 2) You can right click them for extra opeartions.\n\
  150. 3) Create a new \"Properties\" panel from the 🞆 button, \
  151. verify that adjustiing values in either panels would cause the other panel to refresh in sync.\n\
  152. 4) Test invoking a operator from property.\n\
  153. ",0,0)->Flags|=LA_TEXT_LINE_WRAP|LA_TEXT_MONO;
  154. EXAMPLE_COMMON_END
  155. }
  156. void ui_Widgets(laUiList *uil, laPropPack *This, laPropPack *DetachedProps, laColumn *UNUSED, int context){
  157. EXAMPLE_COMMON_BEGIN
  158. laShowLabel(uil,c,"\
  159. This demo shows commom widgets inside LaGUI.\n\
  160. \n\
  161. What you need to know about widgets in LaGUI:\n\
  162. ---------------------------------------------\n\
  163. 1) Except labels, you need a data source (a defined property in LaGUI) to show any other kind of widget.\n \
  164. 2) To show a button, you need to define an operator, and an operator is basically what you trigger an action with.\n \
  165. 3) A widget can have multiple style/looks controlled by mainly `ui->Flags`. Some ui types accept extra instructions as a string, like you \
  166. could specify \"text=something;\" to a button.\n\
  167. 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\
  168. 5) Canvas widgets are drawn on their own offscreen buffers. They can also be customized to have your own drawing and event handling callbacks, \
  169. they can be set to display a certain property as well.\n\
  170. ",0,0)->Flags|=LA_TEXT_LINE_WRAP|LA_TEXT_MONO;
  171. EXAMPLE_COMMON_END
  172. }
  173. void ui_WidgetFlags(laUiList *uil, laPropPack *This, laPropPack *DetachedProps, laColumn *UNUSED, int context){
  174. EXAMPLE_COMMON_BEGIN
  175. laShowLabel(uil,c,"\
  176. This demo shows most-used UI flags and their effects on widgets.\n\
  177. \n\
  178. When using widget creator like `laShowItem`, set ui->Flags to the combination of UI flags to adjust the look and interaction of the widget. \
  179. 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 \
  180. UI flags and won't generate any errors.\n\
  181. \n\
  182. Launch the program to see the effect of each UI flags.\
  183. ",0,0)->Flags|=LA_TEXT_LINE_WRAP|LA_TEXT_MONO;
  184. EXAMPLE_COMMON_END
  185. }
  186. void ui_Calculator(laUiList *uil, laPropPack *This, laPropPack *DetachedProps, laColumn *UNUSED, int context){
  187. EXAMPLE_COMMON_BEGIN
  188. laColumn* c=laFirstColumn(uil);
  189. laShowLabel(uil,c,"\
  190. Calculator demo\n\
  191. ===============\n\
  192. This program mainly demonstrates how to use LaGUI to create a node-based UI. The program creates a simple node-socket graph structure for \
  193. 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 \
  194. 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\
  195. ",0,0)->Flags|=LA_TEXT_LINE_WRAP|LA_TEXT_MONO;
  196. laShowLabel(uil,c,"\
  197. Play with calculator demo:\n\
  198. --------------------------\n\
  199. 1) Click \"New Calculator\" to create a calculator page.\n\
  200. 2) Click the \"+\" buttons to the left/right of the rack name to add a node rack.\n\
  201. 3) Click \"Add Node\" button to insert a node into the rack.\n\
  202. 4) Insert more nodes and connecct nodes with each other, you can create more racks too.\n\
  203. 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\
  204. 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\
  205. 7) If you try to read calculator files, the calculator page that's referenced by any \"Reference\" node will be automatically loaded too.\n\
  206. 8) The imlementation of a DAG evaluator is left for you as a practice.\n\
  207. 9) There are some node-related configurable options in user preferences, try changing those and see what those options do.\n\
  208. ",0,0)->Flags|=LA_TEXT_LINE_WRAP|LA_TEXT_MONO;
  209. EXAMPLE_COMMON_END
  210. }
  211. void ui_Modelling(laUiList *uil, laPropPack *This, laPropPack *DetachedProps, laColumn *UNUSED, int context){
  212. EXAMPLE_COMMON_BEGIN
  213. laColumn* c=laFirstColumn(uil);
  214. laShowLabel(uil,c,"\
  215. Modelling functionality demo\n\
  216. ============================\n\
  217. LaGUI has a simple geometry layer that allows you to load or model mesh geometries. This example demonstrates the default modeller. \
  218. ",0,0)->Flags|=LA_TEXT_LINE_WRAP|LA_TEXT_MONO;
  219. EXAMPLE_COMMON_END
  220. }
  221. int inv_LaunchDemo(laOperator* a, laEvent* e){
  222. char* program=strGetArgumentString(a->ExtraInstructionsP,"program"); if(!program) return LA_FINISHED;
  223. char command[512]; sprintf(command,"./%s &",program);
  224. system(command);
  225. return LA_FINISHED;
  226. }
  227. int inv_OpenDemoSource(laOperator* a, laEvent* e){
  228. char* file=strGetArgumentString(a->ExtraInstructionsP,"file"); if(!file) return LA_FINISHED;
  229. char command[512]; sprintf(command,"xdg-open example_source_files/%s &",file);
  230. system(command);
  231. return LA_FINISHED;
  232. }
  233. laPropContainer *pcGeneric,*pcFruits,*pcSimplest,*pcOperator,*pcSimpleProperties,*pcModelling,*pcCalculator,*pcWidgets,*pcWidgetFlags;
  234. void* get_ExampleViewer(void* unused){
  235. return EV;
  236. }
  237. laPropContainer* get_ExamplesGetType(ExampleItem* ei){
  238. if(ei->Define==ui_Fruits) return pcFruits;
  239. if(ei->Define==ui_Simplest) return pcSimplest;
  240. if(ei->Define==ui_Operator) return pcOperator;
  241. if(ei->Define==ui_SimpleProperties) return pcSimpleProperties;
  242. if(ei->Define==ui_Modelling) return pcModelling;
  243. if(ei->Define==ui_Calculator) return pcCalculator;
  244. if(ei->Define==ui_Widgets) return pcWidgets;
  245. if(ei->Define==ui_WidgetFlags) return pcWidgetFlags;
  246. return pcGeneric;
  247. }
  248. void set_CurrentExample(ExampleViewer* v, ExampleItem* ei){
  249. memAssignRef(v,&v->CurrentExample, ei); v->ShowCode=0;
  250. }
  251. #define EXAMPLE_ADD_PC(name,_PC,_UI) \
  252. pc=laAddPropertyContainer("example_" name, name "Example", name "example",0,_UI,sizeof(ExampleItem),0,0,1); _PC=pc;\
  253. 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);\
  254. laAddSubGroup(pc,"base","Base","Base example","program_example",0,0,0,0,0,0,0,0,0,0,0,LA_UDF_LOCAL);
  255. static void InitExamples(){
  256. laCreateOperatorType("EXAMPLE_launch_program","Launch Program", "Launch example program",0,0,0,inv_LaunchDemo,0,L'🏃',0);
  257. 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);
  258. laPropContainer* root=laDefineRoot(),*pc; laProp*p;
  259. laAddSubGroup(root,"viewer","Viewer","Example viewer","example_viewer",0,0,0,-1,0,get_ExampleViewer,0,0,0,0,0,0);
  260. pc=laAddPropertyContainer("example_viewer","Example Viewer","Example viewer root data",0,0,sizeof(ExampleViewer),0,0,1);
  261. 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);
  262. 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);
  263. 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);
  264. laAddEnumItemAs(p,"DESC","Description","Show description of the example",0,0);
  265. laAddEnumItemAs(p,"IMPL","Code","Show implementation of the example",1,0);
  266. pc=laAddPropertyContainer("program_example","Program Example","Program example",0,laui_IdentifierOnly,sizeof(ExampleItem),0,0,1); pcGeneric=pc;
  267. 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);
  268. 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);
  269. EXAMPLE_ADD_PC("simplest",pcSimplest,ui_Simplest);
  270. EXAMPLE_ADD_PC("operator",pcOperator,ui_Operator);
  271. EXAMPLE_ADD_PC("simple_properties",pcSimpleProperties,ui_SimpleProperties);
  272. EXAMPLE_ADD_PC("fruits",pcFruits,ui_Fruits);
  273. EXAMPLE_ADD_PC("widgets",pcWidgets,ui_Widgets);
  274. EXAMPLE_ADD_PC("widget_flags",pcWidgetFlags,ui_WidgetFlags);
  275. EXAMPLE_ADD_PC("calculator",pcCalculator,ui_Calculator);
  276. EXAMPLE_ADD_PC("modelling_main",pcModelling,ui_Modelling);
  277. EV=memAcquire(sizeof(ExampleViewer));
  278. AddExample("Simplest","simplest",ui_Simplest);
  279. AddExample("Operator","operator",ui_Operator);
  280. AddExample("Simple Properties","simple_properties",ui_SimpleProperties);
  281. AddExample("Widgets","widgets",ui_Widgets);
  282. AddExample("Widget Flags","widget_flags",ui_WidgetFlags);
  283. AddExample("Fruits","fruits",ui_Fruits);
  284. AddExample("Calculator","calculator",ui_Calculator);
  285. AddExample("Modelling","modelling_main",ui_Modelling);
  286. laSetCleanupCallback(ExamplesCleanUp);
  287. }
  288. int main(int argc, char *argv[]){
  289. laGetReady();
  290. char buf[512];getcwd(buf,512);
  291. printf("%s\n",buf);
  292. InitExamples();
  293. laRegisterUiTemplate("examples_list","Examples List", ExamplesList,0,0,"Demonstration",0,0,0);
  294. laWindow* w = laDesignWindow(-1,-1,800,600);
  295. laLayout* l = laDesignLayout(w,"LaGUI Examples");
  296. laCreatePanel(l->FirstBlock,"examples_list");
  297. laStartWindow(w);
  298. laMainLoop();
  299. }