example.c 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301
  1. //
  2. // based on NanoVG's example code by Mikko Mononen
  3. #include <stdio.h>
  4. #ifdef NANOVG_GLEW
  5. #define GLEW_STATIC
  6. # include <GL/glew.h>
  7. #endif
  8. #ifdef __APPLE__
  9. # define GLFW_INCLUDE_GLCOREARB
  10. #endif
  11. #include <GLFW/glfw3.h>
  12. #include "nanovg.h"
  13. #define NANOVG_GL3_IMPLEMENTATION
  14. #include "nanovg_gl.h"
  15. #define BLENDISH_IMPLEMENTATION
  16. #include "blendish.h"
  17. #define OUI_IMPLEMENTATION
  18. #include "oui.h"
  19. ////////////////////////////////////////////////////////////////////////////////
  20. typedef enum {
  21. // label
  22. ST_LABEL = 0,
  23. // button
  24. ST_BUTTON = 1,
  25. // radio button
  26. ST_RADIO = 2,
  27. // progress slider
  28. ST_SLIDER = 3,
  29. // column
  30. ST_COLUMN = 4,
  31. // row
  32. ST_ROW = 5,
  33. // check button
  34. ST_CHECK = 6,
  35. // panel
  36. ST_PANEL = 7,
  37. // text
  38. ST_TEXT = 8,
  39. //
  40. ST_IGNORE = 9,
  41. ST_DEMOSTUFF = 10,
  42. // colored rectangle
  43. ST_RECT = 11,
  44. ST_HBOX = 12,
  45. ST_VBOX = 13,
  46. } SubType;
  47. typedef struct {
  48. int subtype;
  49. UIhandler handler;
  50. } UIData;
  51. typedef struct {
  52. UIData head;
  53. const char *label;
  54. NVGcolor color;
  55. } UIRectData;
  56. typedef struct {
  57. UIData head;
  58. int iconid;
  59. const char *label;
  60. } UIButtonData;
  61. typedef struct {
  62. UIData head;
  63. const char *label;
  64. int *option;
  65. } UICheckData;
  66. typedef struct {
  67. UIData head;
  68. int iconid;
  69. const char *label;
  70. int *value;
  71. } UIRadioData;
  72. typedef struct {
  73. UIData head;
  74. const char *label;
  75. float *progress;
  76. } UISliderData;
  77. typedef struct {
  78. UIData head;
  79. char *text;
  80. int maxsize;
  81. } UITextData;
  82. ////////////////////////////////////////////////////////////////////////////////
  83. void draw_demostuff(NVGcontext *vg, int x, int y, float w, float h);
  84. static struct NVGcontext* _vg = NULL;
  85. void ui_handler(int item, UIevent event) {
  86. UIData *data = (UIData *)uiGetHandle(item);
  87. if (data && data->handler) {
  88. data->handler(item, event);
  89. }
  90. }
  91. void init(NVGcontext *vg) {
  92. bndSetFont(nvgCreateFont(vg, "system", "../DejaVuSans.ttf"));
  93. bndSetIconImage(nvgCreateImage(vg, "../blender_icons16.png", 0));
  94. }
  95. void testrect(NVGcontext *vg, UIrect rect) {
  96. #if 0
  97. nvgBeginPath(vg);
  98. nvgRect(vg,rect.x+0.5,rect.y+0.5,rect.w-1,rect.h-1);
  99. nvgStrokeColor(vg,nvgRGBf(1,0,0));
  100. nvgStrokeWidth(vg,1);
  101. nvgStroke(vg);
  102. #endif
  103. }
  104. void drawUI(NVGcontext *vg, int item, int corners);
  105. void drawUIItems(NVGcontext *vg, int item, int corners) {
  106. int kid = uiFirstChild(item);
  107. while (kid > 0) {
  108. drawUI(vg, kid, corners);
  109. kid = uiNextSibling(kid);
  110. }
  111. }
  112. void drawUIItemsHbox(NVGcontext *vg, int item) {
  113. int kid = uiFirstChild(item);
  114. if (kid < 0) return;
  115. int nextkid = uiNextSibling(kid);
  116. if (nextkid < 0) {
  117. drawUI(vg, kid, BND_CORNER_NONE);
  118. } else {
  119. drawUI(vg, kid, BND_CORNER_RIGHT);
  120. kid = nextkid;
  121. while (uiNextSibling(kid) > 0) {
  122. drawUI(vg, kid, BND_CORNER_ALL);
  123. kid = uiNextSibling(kid);
  124. }
  125. drawUI(vg, kid, BND_CORNER_LEFT);
  126. }
  127. }
  128. void drawUIItemsVbox(NVGcontext *vg, int item) {
  129. int kid = uiFirstChild(item);
  130. if (kid < 0) return;
  131. int nextkid = uiNextSibling(kid);
  132. if (nextkid < 0) {
  133. drawUI(vg, kid, BND_CORNER_NONE);
  134. } else {
  135. drawUI(vg, kid, BND_CORNER_DOWN);
  136. kid = nextkid;
  137. while (uiNextSibling(kid) > 0) {
  138. drawUI(vg, kid, BND_CORNER_ALL);
  139. kid = uiNextSibling(kid);
  140. }
  141. drawUI(vg, kid, BND_CORNER_TOP);
  142. }
  143. }
  144. void drawUI(NVGcontext *vg, int item, int corners) {
  145. const UIData *head = (const UIData *)uiGetHandle(item);
  146. UIrect rect = uiGetRect(item);
  147. if (uiGetState(item) == UI_FROZEN) {
  148. nvgGlobalAlpha(vg, BND_DISABLED_ALPHA);
  149. }
  150. if (head) {
  151. switch(head->subtype) {
  152. default: {
  153. testrect(vg,rect);
  154. drawUIItems(vg,item,corners);
  155. } break;
  156. case ST_HBOX: {
  157. drawUIItemsHbox(vg, item);
  158. } break;
  159. case ST_VBOX: {
  160. drawUIItemsVbox(vg, item);
  161. } break;
  162. case ST_PANEL: {
  163. bndBevel(vg,rect.x,rect.y,rect.w,rect.h);
  164. drawUIItems(vg,item,corners);
  165. } break;
  166. case ST_LABEL: {
  167. assert(head);
  168. const UIButtonData *data = (UIButtonData*)head;
  169. bndLabel(vg,rect.x,rect.y,rect.w,rect.h,
  170. data->iconid,data->label);
  171. } break;
  172. case ST_BUTTON: {
  173. const UIButtonData *data = (UIButtonData*)head;
  174. bndToolButton(vg,rect.x,rect.y,rect.w,rect.h,
  175. corners,(BNDwidgetState)uiGetState(item),
  176. data->iconid,data->label);
  177. } break;
  178. case ST_CHECK: {
  179. const UICheckData *data = (UICheckData*)head;
  180. BNDwidgetState state = (BNDwidgetState)uiGetState(item);
  181. if (*data->option)
  182. state = BND_ACTIVE;
  183. bndOptionButton(vg,rect.x,rect.y,rect.w,rect.h, state,
  184. data->label);
  185. } break;
  186. case ST_RADIO:{
  187. const UIRadioData *data = (UIRadioData*)head;
  188. BNDwidgetState state = (BNDwidgetState)uiGetState(item);
  189. if (*data->value == item)
  190. state = BND_ACTIVE;
  191. bndRadioButton(vg,rect.x,rect.y,rect.w,rect.h,
  192. corners,state,
  193. data->iconid,data->label);
  194. } break;
  195. case ST_SLIDER:{
  196. const UISliderData *data = (UISliderData*)head;
  197. BNDwidgetState state = (BNDwidgetState)uiGetState(item);
  198. static char value[32];
  199. sprintf(value,"%.0f%%",(*data->progress)*100.0f);
  200. bndSlider(vg,rect.x,rect.y,rect.w,rect.h,
  201. corners,state,
  202. *data->progress,data->label,value);
  203. } break;
  204. case ST_TEXT: {
  205. const UITextData *data = (UITextData*)head;
  206. BNDwidgetState state = (BNDwidgetState)uiGetState(item);
  207. int idx = strlen(data->text);
  208. bndTextField(vg,rect.x,rect.y,rect.w,rect.h,
  209. corners,state, -1, data->text, idx, idx);
  210. } break;
  211. case ST_DEMOSTUFF: {
  212. draw_demostuff(vg, rect.x, rect.y, rect.w, rect.h);
  213. } break;
  214. case ST_RECT: {
  215. const UIRectData *data = (UIRectData*)head;
  216. if (rect.w && rect.h) {
  217. BNDwidgetState state = (BNDwidgetState)uiGetState(item);
  218. nvgSave(vg);
  219. nvgStrokeColor(vg, nvgRGBAf(data->color.r,data->color.g,data->color.b,0.9f));
  220. if (state != BND_DEFAULT) {
  221. nvgFillColor(vg, nvgRGBAf(data->color.r,data->color.g,data->color.b,0.5f));
  222. } else {
  223. nvgFillColor(vg, nvgRGBAf(data->color.r,data->color.g,data->color.b,0.1f));
  224. }
  225. nvgStrokeWidth(vg,2);
  226. nvgBeginPath(vg);
  227. #if 0
  228. nvgRect(vg,rect.x,rect.y,rect.w,rect.h);
  229. #else
  230. nvgRoundedRect(vg,rect.x,rect.y,rect.w,rect.h,3);
  231. #endif
  232. nvgFill(vg);
  233. nvgStroke(vg);
  234. if (state != BND_DEFAULT) {
  235. nvgFillColor(vg, nvgRGBAf(0.0f,0.0f,0.0f,1.0f));
  236. nvgFontSize(vg, 15.0f);
  237. nvgBeginPath(vg);
  238. nvgTextAlign(vg, NVG_ALIGN_TOP|NVG_ALIGN_CENTER);
  239. nvgTextBox(vg, rect.x, rect.y+rect.h*0.3f, rect.w, data->label, NULL);
  240. }
  241. nvgRestore(vg);
  242. }
  243. nvgSave(vg);
  244. nvgIntersectScissor(vg, rect.x, rect.y, rect.w, rect.h);
  245. drawUIItems(vg,item,corners);
  246. nvgRestore(vg);
  247. } break;
  248. }
  249. } else {
  250. testrect(vg,rect);
  251. drawUIItems(vg,item,corners);
  252. }
  253. if (uiGetState(item) == UI_FROZEN) {
  254. nvgGlobalAlpha(vg, 1.0);
  255. }
  256. }
  257. int colorrect(const char *label, NVGcolor color) {
  258. int item = uiItem();
  259. UIRectData *data = (UIRectData *)uiAllocHandle(item, sizeof(UIRectData));
  260. data->head.subtype = ST_RECT;
  261. data->head.handler = NULL;
  262. data->label = label;
  263. data->color = color;
  264. uiSetEvents(item, UI_BUTTON0_DOWN);
  265. return item;
  266. }
  267. int label(int iconid, const char *label) {
  268. int item = uiItem();
  269. uiSetSize(item, 0, BND_WIDGET_HEIGHT);
  270. UIButtonData *data = (UIButtonData *)uiAllocHandle(item, sizeof(UIButtonData));
  271. data->head.subtype = ST_LABEL;
  272. data->head.handler = NULL;
  273. data->iconid = iconid;
  274. data->label = label;
  275. return item;
  276. }
  277. void demohandler(int item, UIevent event) {
  278. const UIButtonData *data = (const UIButtonData *)uiGetHandle(item);
  279. printf("clicked: %p %s\n", uiGetHandle(item), data->label);
  280. }
  281. int button(int iconid, const char *label, UIhandler handler) {
  282. // create new ui item
  283. int item = uiItem();
  284. // set size of wiget; horizontal size is dynamic, vertical is fixed
  285. uiSetSize(item, 0, BND_WIDGET_HEIGHT);
  286. uiSetEvents(item, UI_BUTTON0_HOT_UP);
  287. // store some custom data with the button that we use for styling
  288. UIButtonData *data = (UIButtonData *)uiAllocHandle(item, sizeof(UIButtonData));
  289. data->head.subtype = ST_BUTTON;
  290. data->head.handler = handler;
  291. data->iconid = iconid;
  292. data->label = label;
  293. return item;
  294. }
  295. void checkhandler(int item, UIevent event) {
  296. const UICheckData *data = (const UICheckData *)uiGetHandle(item);
  297. *data->option = !(*data->option);
  298. }
  299. int check(const char *label, int *option) {
  300. // create new ui item
  301. int item = uiItem();
  302. // set size of wiget; horizontal size is dynamic, vertical is fixed
  303. uiSetSize(item, 0, BND_WIDGET_HEIGHT);
  304. // attach event handler e.g. demohandler above
  305. uiSetEvents(item, UI_BUTTON0_DOWN);
  306. // store some custom data with the button that we use for styling
  307. UICheckData *data = (UICheckData *)uiAllocHandle(item, sizeof(UICheckData));
  308. data->head.subtype = ST_CHECK;
  309. data->head.handler = checkhandler;
  310. data->label = label;
  311. data->option = option;
  312. return item;
  313. }
  314. // simple logic for a slider
  315. // starting offset of the currently active slider
  316. static float sliderstart = 0.0;
  317. // event handler for slider (same handler for all sliders)
  318. void sliderhandler(int item, UIevent event) {
  319. // retrieve the custom data we saved with the slider
  320. UISliderData *data = (UISliderData *)uiGetHandle(item);
  321. switch(event) {
  322. default: break;
  323. case UI_BUTTON0_DOWN: {
  324. // button was pressed for the first time; capture initial
  325. // slider value.
  326. sliderstart = *data->progress;
  327. } break;
  328. case UI_BUTTON0_CAPTURE: {
  329. // called for every frame that the button is pressed.
  330. // get the delta between the click point and the current
  331. // mouse position
  332. UIvec2 pos = uiGetCursorStartDelta();
  333. // get the items layouted rectangle
  334. UIrect rc = uiGetRect(item);
  335. // calculate our new offset and clamp
  336. float value = sliderstart + ((float)pos.x / (float)rc.w);
  337. value = (value<0)?0:(value>1)?1:value;
  338. // assign the new value
  339. *data->progress = value;
  340. } break;
  341. }
  342. }
  343. int slider(const char *label, float *progress) {
  344. // create new ui item
  345. int item = uiItem();
  346. // set size of wiget; horizontal size is dynamic, vertical is fixed
  347. uiSetSize(item, 0, BND_WIDGET_HEIGHT);
  348. // attach our slider event handler and capture two classes of events
  349. uiSetEvents(item, UI_BUTTON0_DOWN | UI_BUTTON0_CAPTURE);
  350. // store some custom data with the button that we use for styling
  351. // and logic, e.g. the pointer to the data we want to alter.
  352. UISliderData *data = (UISliderData *)uiAllocHandle(item, sizeof(UISliderData));
  353. data->head.subtype = ST_SLIDER;
  354. data->head.handler = sliderhandler;
  355. data->label = label;
  356. data->progress = progress;
  357. return item;
  358. }
  359. void textboxhandler(int item, UIevent event) {
  360. UITextData *data = (UITextData *)uiGetHandle(item);
  361. switch(event) {
  362. default: break;
  363. case UI_BUTTON0_DOWN: {
  364. uiFocus(item);
  365. } break;
  366. case UI_KEY_DOWN: {
  367. unsigned int key = uiGetKey();
  368. switch(key) {
  369. default: break;
  370. case GLFW_KEY_BACKSPACE: {
  371. int size = strlen(data->text);
  372. if (!size) return;
  373. data->text[size-1] = 0;
  374. } break;
  375. case GLFW_KEY_ENTER: {
  376. uiFocus(-1);
  377. } break;
  378. }
  379. } break;
  380. case UI_CHAR: {
  381. unsigned int key = uiGetKey();
  382. if ((key > 255)||(key < 32)) return;
  383. int size = strlen(data->text);
  384. if (size >= (data->maxsize-1)) return;
  385. data->text[size] = (char)key;
  386. } break;
  387. }
  388. }
  389. int textbox(char *text, int maxsize) {
  390. int item = uiItem();
  391. uiSetSize(item, 0, BND_WIDGET_HEIGHT);
  392. uiSetEvents(item, UI_BUTTON0_DOWN | UI_KEY_DOWN | UI_CHAR);
  393. // store some custom data with the button that we use for styling
  394. // and logic, e.g. the pointer to the data we want to alter.
  395. UITextData *data = (UITextData *)uiAllocHandle(item, sizeof(UITextData));
  396. data->head.subtype = ST_TEXT;
  397. data->head.handler = textboxhandler;
  398. data->text = text;
  399. data->maxsize = maxsize;
  400. return item;
  401. }
  402. // simple logic for a radio button
  403. void radiohandler(int item, UIevent event) {
  404. UIRadioData *data = (UIRadioData *)uiGetHandle(item);
  405. *data->value = item;
  406. }
  407. int radio(int iconid, const char *label, int *value) {
  408. int item = uiItem();
  409. uiSetSize(item, label?0:BND_TOOL_WIDTH, BND_WIDGET_HEIGHT);
  410. UIRadioData *data = (UIRadioData *)uiAllocHandle(item, sizeof(UIRadioData));
  411. data->head.subtype = ST_RADIO;
  412. data->head.handler = radiohandler;
  413. data->iconid = iconid;
  414. data->label = label;
  415. data->value = value;
  416. uiSetEvents(item, UI_BUTTON0_DOWN);
  417. return item;
  418. }
  419. int panel() {
  420. int item = uiItem();
  421. UIData *data = (UIData *)uiAllocHandle(item, sizeof(UIData));
  422. data->subtype = ST_PANEL;
  423. data->handler = NULL;
  424. return item;
  425. }
  426. int hbox() {
  427. int item = uiItem();
  428. UIData *data = (UIData *)uiAllocHandle(item, sizeof(UIData));
  429. data->subtype = ST_HBOX;
  430. data->handler = NULL;
  431. uiSetBox(item, UI_ROW);
  432. return item;
  433. }
  434. int vbox() {
  435. int item = uiItem();
  436. UIData *data = (UIData *)uiAllocHandle(item, sizeof(UIData));
  437. data->subtype = ST_VBOX;
  438. data->handler = NULL;
  439. uiSetBox(item, UI_COLUMN);
  440. return item;
  441. }
  442. int column_append(int parent, int item) {
  443. uiInsert(parent, item);
  444. // fill parent horizontally, anchor to previous item vertically
  445. uiSetLayout(item, UI_HFILL);
  446. uiSetMargins(item, 0, 1, 0, 0);
  447. return item;
  448. }
  449. int column() {
  450. int item = uiItem();
  451. uiSetBox(item, UI_COLUMN);
  452. return item;
  453. }
  454. int vgroup_append(int parent, int item) {
  455. uiInsert(parent, item);
  456. // fill parent horizontally, anchor to previous item vertically
  457. uiSetLayout(item, UI_HFILL);
  458. return item;
  459. }
  460. int vgroup() {
  461. int item = uiItem();
  462. uiSetBox(item, UI_COLUMN);
  463. return item;
  464. }
  465. int hgroup_append(int parent, int item) {
  466. uiInsert(parent, item);
  467. uiSetLayout(item, UI_HFILL);
  468. return item;
  469. }
  470. int hgroup_append_fixed(int parent, int item) {
  471. uiInsert(parent, item);
  472. return item;
  473. }
  474. int hgroup() {
  475. int item = uiItem();
  476. uiSetBox(item, UI_ROW);
  477. return item;
  478. }
  479. int row_append(int parent, int item) {
  480. uiInsert(parent, item);
  481. uiSetLayout(item, UI_HFILL);
  482. return item;
  483. }
  484. int row() {
  485. int item = uiItem();
  486. uiSetBox(item, UI_ROW);
  487. return item;
  488. }
  489. void draw_noodles(NVGcontext *vg, int x, int y) {
  490. int w = 200;
  491. int s = 70;
  492. bndNodeBackground(vg, x+w, y-50, 100, 200, BND_DEFAULT, BND_ICONID(6,3),
  493. "Default", nvgRGBf(0.392f,0.392f,0.392f));
  494. bndNodeBackground(vg, x+w+120, y-50, 100, 200, BND_HOVER, BND_ICONID(6,3),
  495. "Hover", nvgRGBf(0.392f,0.392f,0.392f));
  496. bndNodeBackground(vg, x+w+240, y-50, 100, 200, BND_ACTIVE, BND_ICONID(6,3),
  497. "Active", nvgRGBf(0.392f,0.392f,0.392f));
  498. for (int i = 0; i < 9; ++i) {
  499. int a = i%3;
  500. int b = i/3;
  501. bndNodeWire(vg, x, y+s*a, x+w, y+s*b, (BNDwidgetState)a, (BNDwidgetState)b);
  502. }
  503. bndNodePort(vg, x, y, BND_DEFAULT, nvgRGBf(0.5f, 0.5f, 0.5f));
  504. bndNodePort(vg, x+w, y, BND_DEFAULT, nvgRGBf(0.5f, 0.5f, 0.5f));
  505. bndNodePort(vg, x, y+s, BND_HOVER, nvgRGBf(0.5f, 0.5f, 0.5f));
  506. bndNodePort(vg, x+w, y+s, BND_HOVER, nvgRGBf(0.5f, 0.5f, 0.5f));
  507. bndNodePort(vg, x, y+2*s, BND_ACTIVE, nvgRGBf(0.5f, 0.5f, 0.5f));
  508. bndNodePort(vg, x+w, y+2*s, BND_ACTIVE, nvgRGBf(0.5f, 0.5f, 0.5f));
  509. }
  510. static void roothandler(int parent, UIevent event) {
  511. switch(event) {
  512. default: break;
  513. case UI_SCROLL: {
  514. UIvec2 pos = uiGetScroll();
  515. printf("scroll! %d %d\n", pos.x, pos.y);
  516. } break;
  517. case UI_BUTTON0_DOWN: {
  518. printf("%d clicks\n", uiGetClicks());
  519. } break;
  520. }
  521. }
  522. void draw_demostuff(NVGcontext *vg, int x, int y, float w, float h) {
  523. nvgSave(vg);
  524. nvgTranslate(vg, x, y);
  525. bndSplitterWidgets(vg, 0, 0, w, h);
  526. x = 10;
  527. y = 10;
  528. bndToolButton(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT,
  529. BND_ICONID(6,3),"Default");
  530. y += 25;
  531. bndToolButton(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER,
  532. BND_ICONID(6,3),"Hovered");
  533. y += 25;
  534. bndToolButton(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE,
  535. BND_ICONID(6,3),"Active");
  536. y += 40;
  537. bndRadioButton(vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT,
  538. -1,"Default");
  539. y += 25;
  540. bndRadioButton(vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER,
  541. -1,"Hovered");
  542. y += 25;
  543. bndRadioButton(vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE,
  544. -1,"Active");
  545. y += 25;
  546. bndLabel(vg,x,y,120,BND_WIDGET_HEIGHT,-1,"Label:");
  547. y += BND_WIDGET_HEIGHT;
  548. bndChoiceButton(vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT,
  549. -1, "Default");
  550. y += 25;
  551. bndChoiceButton(vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER,
  552. -1, "Hovered");
  553. y += 25;
  554. bndChoiceButton(vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE,
  555. -1, "Active");
  556. y += 25;
  557. int ry = y;
  558. int rx = x;
  559. y = 10;
  560. x += 130;
  561. bndOptionButton(vg,x,y,120,BND_WIDGET_HEIGHT,BND_DEFAULT,"Default");
  562. y += 25;
  563. bndOptionButton(vg,x,y,120,BND_WIDGET_HEIGHT,BND_HOVER,"Hovered");
  564. y += 25;
  565. bndOptionButton(vg,x,y,120,BND_WIDGET_HEIGHT,BND_ACTIVE,"Active");
  566. y += 40;
  567. bndNumberField(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_DOWN,BND_DEFAULT,
  568. "Top","100");
  569. y += BND_WIDGET_HEIGHT-2;
  570. bndNumberField(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_ALL,BND_DEFAULT,
  571. "Center","100");
  572. y += BND_WIDGET_HEIGHT-2;
  573. bndNumberField(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_TOP,BND_DEFAULT,
  574. "Bottom","100");
  575. int mx = x-30;
  576. int my = y-12;
  577. int mw = 120;
  578. bndMenuBackground(vg,mx,my,mw,120,BND_CORNER_TOP);
  579. bndMenuLabel(vg,mx,my,mw,BND_WIDGET_HEIGHT,-1,"Menu Title");
  580. my += BND_WIDGET_HEIGHT-2;
  581. bndMenuItem(vg,mx,my,mw,BND_WIDGET_HEIGHT,BND_DEFAULT,
  582. BND_ICONID(17,3),"Default");
  583. my += BND_WIDGET_HEIGHT-2;
  584. bndMenuItem(vg,mx,my,mw,BND_WIDGET_HEIGHT,BND_HOVER,
  585. BND_ICONID(18,3),"Hovered");
  586. my += BND_WIDGET_HEIGHT-2;
  587. bndMenuItem(vg,mx,my,mw,BND_WIDGET_HEIGHT,BND_ACTIVE,
  588. BND_ICONID(19,3),"Active");
  589. y = 10;
  590. x += 130;
  591. int ox = x;
  592. bndNumberField(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT,
  593. "Default","100");
  594. y += 25;
  595. bndNumberField(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER,
  596. "Hovered","100");
  597. y += 25;
  598. bndNumberField(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE,
  599. "Active","100");
  600. y += 40;
  601. bndRadioButton(vg,x,y,60,BND_WIDGET_HEIGHT,BND_CORNER_RIGHT,BND_DEFAULT,
  602. -1,"One");
  603. x += 60-1;
  604. bndRadioButton(vg,x,y,60,BND_WIDGET_HEIGHT,BND_CORNER_ALL,BND_DEFAULT,
  605. -1,"Two");
  606. x += 60-1;
  607. bndRadioButton(vg,x,y,60,BND_WIDGET_HEIGHT,BND_CORNER_ALL,BND_DEFAULT,
  608. -1,"Three");
  609. x += 60-1;
  610. bndRadioButton(vg,x,y,60,BND_WIDGET_HEIGHT,BND_CORNER_LEFT,BND_ACTIVE,
  611. -1,"Butts");
  612. x = ox;
  613. y += 40;
  614. float progress_value = fmodf(glfwGetTime()/10.0,1.0);
  615. char progress_label[32];
  616. sprintf(progress_label, "%d%%", (int)(progress_value*100+0.5f));
  617. bndSlider(vg,x,y,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT,
  618. progress_value,"Default",progress_label);
  619. y += 25;
  620. bndSlider(vg,x,y,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER,
  621. progress_value,"Hovered",progress_label);
  622. y += 25;
  623. bndSlider(vg,x,y,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE,
  624. progress_value,"Active",progress_label);
  625. int rw = x+240-rx;
  626. float s_offset = sinf(glfwGetTime()/2.0)*0.5+0.5;
  627. float s_size = cosf(glfwGetTime()/3.11)*0.5+0.5;
  628. bndScrollBar(vg,rx,ry,rw,BND_SCROLLBAR_HEIGHT,BND_DEFAULT,s_offset,s_size);
  629. ry += 20;
  630. bndScrollBar(vg,rx,ry,rw,BND_SCROLLBAR_HEIGHT,BND_HOVER,s_offset,s_size);
  631. ry += 20;
  632. bndScrollBar(vg,rx,ry,rw,BND_SCROLLBAR_HEIGHT,BND_ACTIVE,s_offset,s_size);
  633. const char edit_text[] = "The quick brown fox";
  634. int textlen = strlen(edit_text)+1;
  635. int t = (int)(glfwGetTime()*2);
  636. int idx1 = (t/textlen)%textlen;
  637. int idx2 = idx1 + (t%(textlen-idx1));
  638. ry += 25;
  639. bndTextField(vg,rx,ry,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT,
  640. -1, edit_text, idx1, idx2);
  641. ry += 25;
  642. bndTextField(vg,rx,ry,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER,
  643. -1, edit_text, idx1, idx2);
  644. ry += 25;
  645. bndTextField(vg,rx,ry,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE,
  646. -1, edit_text, idx1, idx2);
  647. draw_noodles(vg, 20, ry+50);
  648. rx += rw + 20;
  649. ry = 10;
  650. bndScrollBar(vg,rx,ry,BND_SCROLLBAR_WIDTH,240,BND_DEFAULT,s_offset,s_size);
  651. rx += 20;
  652. bndScrollBar(vg,rx,ry,BND_SCROLLBAR_WIDTH,240,BND_HOVER,s_offset,s_size);
  653. rx += 20;
  654. bndScrollBar(vg,rx,ry,BND_SCROLLBAR_WIDTH,240,BND_ACTIVE,s_offset,s_size);
  655. x = ox;
  656. y += 40;
  657. bndToolButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_RIGHT,
  658. BND_DEFAULT,BND_ICONID(0,10),NULL);
  659. x += BND_TOOL_WIDTH-1;
  660. bndToolButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  661. BND_DEFAULT,BND_ICONID(1,10),NULL);
  662. x += BND_TOOL_WIDTH-1;
  663. bndToolButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  664. BND_DEFAULT,BND_ICONID(2,10),NULL);
  665. x += BND_TOOL_WIDTH-1;
  666. bndToolButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  667. BND_DEFAULT,BND_ICONID(3,10),NULL);
  668. x += BND_TOOL_WIDTH-1;
  669. bndToolButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  670. BND_DEFAULT,BND_ICONID(4,10),NULL);
  671. x += BND_TOOL_WIDTH-1;
  672. bndToolButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_LEFT,
  673. BND_DEFAULT,BND_ICONID(5,10),NULL);
  674. x += BND_TOOL_WIDTH-1;
  675. x += 5;
  676. bndRadioButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_RIGHT,
  677. BND_DEFAULT,BND_ICONID(0,11),NULL);
  678. x += BND_TOOL_WIDTH-1;
  679. bndRadioButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  680. BND_DEFAULT,BND_ICONID(1,11),NULL);
  681. x += BND_TOOL_WIDTH-1;
  682. bndRadioButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  683. BND_DEFAULT,BND_ICONID(2,11),NULL);
  684. x += BND_TOOL_WIDTH-1;
  685. bndRadioButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  686. BND_DEFAULT,BND_ICONID(3,11),NULL);
  687. x += BND_TOOL_WIDTH-1;
  688. bndRadioButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  689. BND_ACTIVE,BND_ICONID(4,11),NULL);
  690. x += BND_TOOL_WIDTH-1;
  691. bndRadioButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_LEFT,
  692. BND_DEFAULT,BND_ICONID(5,11),NULL);
  693. nvgRestore(vg);
  694. }
  695. static int enum1 = -1;
  696. void build_democontent(int parent) {
  697. // some persistent variables for demonstration
  698. static float progress1 = 0.25f;
  699. static float progress2 = 0.75f;
  700. static int option1 = 1;
  701. static int option2 = 0;
  702. static int option3 = 0;
  703. int col = column();
  704. uiInsert(parent, col);
  705. uiSetMargins(col, 10, 10, 10, 10);
  706. uiSetLayout(col, UI_TOP|UI_HFILL);
  707. column_append(col, button(BND_ICON_GHOST, "Item 1", demohandler));
  708. if (option3)
  709. column_append(col, button(BND_ICON_GHOST, "Item 2", demohandler));
  710. {
  711. int h = column_append(col, hbox());
  712. hgroup_append(h, radio(BND_ICON_GHOST, "Item 3.0", &enum1));
  713. if (option2)
  714. uiSetMargins(hgroup_append_fixed(h, radio(BND_ICON_REC, NULL, &enum1)), -1,0,0,0);
  715. uiSetMargins(hgroup_append_fixed(h, radio(BND_ICON_PLAY, NULL, &enum1)), -1,0,0,0);
  716. uiSetMargins(hgroup_append(h, radio(BND_ICON_GHOST, "Item 3.3", &enum1)), -1,0,0,0);
  717. }
  718. {
  719. int rows = column_append(col, row());
  720. int coll = row_append(rows, vgroup());
  721. vgroup_append(coll, label(-1, "Items 4.0:"));
  722. coll = vgroup_append(coll, vbox());
  723. vgroup_append(coll, button(BND_ICON_GHOST, "Item 4.0.0", demohandler));
  724. uiSetMargins(vgroup_append(coll, button(BND_ICON_GHOST, "Item 4.0.1", demohandler)),0,-2,0,0);
  725. int colr = row_append(rows, vgroup());
  726. uiSetMargins(colr, 8, 0, 0, 0);
  727. uiSetFrozen(colr, option1);
  728. vgroup_append(colr, label(-1, "Items 4.1:"));
  729. colr = vgroup_append(colr, vbox());
  730. vgroup_append(colr, slider("Item 4.1.0", &progress1));
  731. uiSetMargins(vgroup_append(colr, slider("Item 4.1.1", &progress2)),0,-2,0,0);
  732. }
  733. column_append(col, button(BND_ICON_GHOST, "Item 5", NULL));
  734. static char textbuffer[1024] = "The quick brown fox.";
  735. column_append(col, textbox(textbuffer, 1024));
  736. column_append(col, check("Frozen", &option1));
  737. column_append(col, check("Item 7", &option2));
  738. column_append(col, check("Item 8", &option3));
  739. }
  740. int demorect(int parent, const char *label, float hue, int box, int layout, int w, int h, int m1, int m2, int m3, int m4) {
  741. int item = colorrect(label, nvgHSL(hue, 1.0f, 0.8f));
  742. uiSetLayout(item, layout);
  743. uiSetBox(item, box);
  744. uiSetMargins(item, m1, m2, m3, m4);
  745. uiSetSize(item, w, h);
  746. uiInsert(parent, item);
  747. return item;
  748. }
  749. void build_layoutdemo(int parent) {
  750. const int M = 10;
  751. const int S = 150;
  752. int box = demorect(parent, "Box( UI_LAYOUT )\nLayout( UI_FILL )", 0.6f, UI_LAYOUT, UI_FILL, 0, 0, M, M, M, M);
  753. demorect(box, "Layout( UI_HFILL | UI_TOP )", 0.7f, 0, UI_HFILL|UI_TOP, S, S+M, M, M, M, 0);
  754. demorect(box, "Layout( UI_HFILL )", 0.7f, 0, UI_HFILL, S, S+2*M, M, 0, M, 0);
  755. demorect(box, "Layout( UI_HFILL | UI_DOWN )", 0.7f, 0, UI_HFILL|UI_DOWN, S, S+M, M, 0, M, M);
  756. demorect(box, "Layout( UI_LEFT | UI_VFILL )", 0.7f, 0, UI_LEFT|UI_VFILL, S+M, S, M, M, 0, M);
  757. demorect(box, "Layout( UI_VFILL )", 0.7f, 0, UI_VFILL, S+2*M, S, 0, M, 0, M);
  758. demorect(box, "Layout( UI_RIGHT | UI_VFILL )", 0.7f, 0, UI_RIGHT|UI_VFILL, S+M, S, 0, M, M, M);
  759. demorect(box, "Layout( UI_LEFT | UI_TOP )", 0.55f, 0, UI_LEFT|UI_TOP, S, S, M, M, 0, 0);
  760. demorect(box, "Layout( UI_TOP )", 0.57f, 0, UI_TOP, S, S, 0, M, 0, 0);
  761. demorect(box, "Layout( UI_RIGHT | UI_TOP )", 0.55f, 0, UI_RIGHT|UI_TOP, S, S, 0, M, M, 0);
  762. demorect(box, "Layout( UI_LEFT )", 0.57f, 0, UI_LEFT, S, S, M, 0, 0, 0);
  763. demorect(box, "Layout( UI_CENTER )", 0.59f, 0, UI_CENTER, S, S, 0, 0, 0, 0);
  764. demorect(box, "Layout( UI_RIGHT )", 0.57f, 0, UI_RIGHT, S, S, 0, 0, M, 0);
  765. demorect(box, "Layout( UI_LEFT | UI_DOWN )", 0.55f, 0, UI_LEFT|UI_DOWN, S, S, M, 0, 0, M);
  766. demorect(box, "Layout( UI_DOWN)", 0.57f, 0, UI_DOWN, S, S, 0, 0, 0, M);
  767. demorect(box, "Layout( UI_RIGHT | UI_DOWN )", 0.55f, 0, UI_RIGHT|UI_DOWN, S, S, 0, 0, M, M);
  768. }
  769. void build_rowdemo(int parent) {
  770. uiSetBox(parent, UI_COLUMN);
  771. const int M = 10;
  772. const int S = 200;
  773. const int T = 100;
  774. {
  775. int box = demorect(parent, "Box( UI_ROW )\nLayout( UI_LEFT | UI_VFILL )", 0.6f, UI_ROW, UI_LEFT|UI_VFILL, 0, S, M, M, M, M);
  776. demorect(box, "Layout( UI_TOP )", 0.05f, 0, UI_TOP, T, T, M, M, M, 0);
  777. demorect(box, "Layout( UI_VCENTER )", 0.1f, 0, UI_VCENTER, T, T, 0, 0, M, 0);
  778. demorect(box, "Layout( UI_VFILL )", 0.15f, 0, UI_VFILL, T, T, 0, M, M, M);
  779. demorect(box, "Layout( UI_DOWN )", 0.25f, 0, UI_DOWN, T, T, 0, 0, M, M);
  780. }
  781. {
  782. int box = demorect(parent, "Box( UI_ROW | UI_JUSTIFY )\nLayout( UI_FILL )", 0.6f, UI_ROW|UI_JUSTIFY, UI_FILL, 0, S, M, 0, M, M);
  783. demorect(box, "Layout( UI_TOP )", 0.05f, 0, UI_TOP, T, T, M, M, M, 0);
  784. demorect(box, "Layout( UI_VCENTER )", 0.1f, 0, UI_VCENTER, T, T, 0, 0, M, 0);
  785. demorect(box, "Layout( UI_VFILL )", 0.15f, 0, UI_VFILL, T, T, 0, M, M, M);
  786. demorect(box, "Layout( UI_DOWN )", 0.25f, 0, UI_DOWN, T, T, 0, 0, M, M);
  787. }
  788. {
  789. int box = demorect(parent, "Box( UI_ROW )\nLayout( UI_FILL )", 0.6f, UI_ROW, UI_FILL, 0, S, M, 0, M, M);
  790. demorect(box, "Layout( UI_TOP )", 0.05f, 0, UI_TOP, T, T, M, M, M, 0);
  791. demorect(box, "Layout( UI_VCENTER )", 0.1f, 0, UI_VCENTER, T, T, 0, 0, M, 0);
  792. demorect(box, "Layout( UI_VFILL )", 0.15f, 0, UI_VFILL, T, T, 0, M, M, M);
  793. demorect(box, "Layout( UI_HFILL )", 0.2f, 0, UI_HFILL, T, T, 0, 0, M, 0);
  794. demorect(box, "Layout( UI_HFILL )", 0.2f, 0, UI_HFILL, T, T, 0, 0, M, 0);
  795. demorect(box, "Layout( UI_HFILL )", 0.2f, 0, UI_HFILL, T, T, 0, 0, M, 0);
  796. demorect(box, "Layout( UI_DOWN )", 0.25f, 0, UI_DOWN, T, T, 0, 0, M, M);
  797. }
  798. }
  799. void build_columndemo(int parent) {
  800. uiSetBox(parent, UI_ROW);
  801. const int M = 10;
  802. const int S = 200;
  803. const int T = 100;
  804. {
  805. int box = demorect(parent, "Box( UI_COLUMN )\nLayout( UI_TOP | UI_HFILL )", 0.6f, UI_COLUMN, UI_TOP|UI_HFILL, S, 0, M, M, M, M);
  806. demorect(box, "Layout( UI_LEFT )", 0.05f, 0, UI_LEFT, T, T, M, M, 0, M);
  807. demorect(box, "Layout( UI_HCENTER )", 0.1f, 0, UI_HCENTER, T, T, 0, 0, 0, M);
  808. demorect(box, "Layout( UI_HFILL )", 0.15f, 0, UI_HFILL, T, T, M, 0, M, M);
  809. demorect(box, "Layout( UI_RIGHT )", 0.25f, 0, UI_RIGHT, T, T, 0, 0, M, M);
  810. }
  811. {
  812. int box = demorect(parent, "Box( UI_COLUMN )\nLayout( UI_FILL )", 0.6f, UI_COLUMN, UI_FILL, S, 0, 0, M, M, M);
  813. demorect(box, "Layout( UI_LEFT )", 0.05f, 0, UI_LEFT, T, T, M, M, 0, M);
  814. demorect(box, "Layout( UI_HCENTER )", 0.1f, 0, UI_HCENTER, T, T, 0, 0, 0, M);
  815. demorect(box, "Layout( UI_HFILL )", 0.15f, 0, UI_HFILL, T, T, M, 0, M, M);
  816. demorect(box, "Layout( UI_RIGHT )", 0.25f, 0, UI_RIGHT, T, T, 0, 0, M, M);
  817. }
  818. {
  819. int box = demorect(parent, "Box( UI_COLUMN )\nLayout( UI_FILL )", 0.6f, UI_COLUMN, UI_FILL, S, 0, 0, M, M, M);
  820. demorect(box, "Layout( UI_LEFT )", 0.05f, 0, UI_LEFT, T, T, M, M, 0, M);
  821. demorect(box, "Layout( UI_HCENTER )", 0.1f, 0, UI_HCENTER, T, T, 0, 0, 0, M);
  822. demorect(box, "Layout( UI_HFILL )", 0.15f, 0, UI_HFILL, T, T, M, 0, M, M);
  823. demorect(box, "Layout( UI_VFILL )", 0.2f, 0, UI_VFILL, T, T, 0, 0, 0, M);
  824. demorect(box, "Layout( UI_VFILL )", 0.2f, 0, UI_VFILL, T, T, 0, 0, 0, M);
  825. demorect(box, "Layout( UI_VFILL )", 0.2f, 0, UI_VFILL, T, T, 0, 0, 0, M);
  826. demorect(box, "Layout( UI_RIGHT )", 0.25f, 0, UI_RIGHT, T, T, 0, 0, M, M);
  827. }
  828. }
  829. void fill_wrap_row_box(int box) {
  830. const int M = 5;
  831. const int S = 100;
  832. const int T = 50;
  833. srand(303);
  834. for (int i = 0; i < 20; ++i) {
  835. float hue = (float)(rand()%360)/360.0f;
  836. int width = 10 + (rand()%5)*10;
  837. int u;
  838. switch(rand()%4) {
  839. default: break;
  840. case 0: {
  841. u = demorect(box, "Layout( UI_TOP )",
  842. hue, 0, UI_TOP, width, T, M, M, M, M);
  843. } break;
  844. case 1: {
  845. u = demorect(box, "Layout( UI_VCENTER )",
  846. hue, 0, UI_VCENTER, width, T/2, M, M, M, M);
  847. } break;
  848. case 2: {
  849. u = demorect(box, "Layout( UI_VFILL )",
  850. hue, 0, UI_VFILL, width, T, M, M, M, M);
  851. } break;
  852. case 3: {
  853. u = demorect(box, "Layout( UI_DOWN )",
  854. hue, 0, UI_DOWN, width, T/2, M, M, M, M);
  855. } break;
  856. }
  857. if (rand()%10 == 0)
  858. uiSetLayout(u, uiGetLayout(u)|UI_BREAK);
  859. }
  860. }
  861. void fill_wrap_column_box(int box) {
  862. const int M = 5;
  863. const int S = 100;
  864. const int T = 50;
  865. srand(303);
  866. for (int i = 0; i < 20; ++i) {
  867. float hue = (float)(rand()%360)/360.0f;
  868. int height = 10 + (rand()%5)*10;
  869. int u;
  870. switch(rand()%4) {
  871. default: break;
  872. case 0: {
  873. u = demorect(box, "Layout( UI_LEFT )",
  874. hue, 0, UI_LEFT, T, height, M, M, M, M);
  875. } break;
  876. case 1: {
  877. u = demorect(box, "Layout( UI_HCENTER )",
  878. hue, 0, UI_HCENTER, T/2, height, M, M, M, M);
  879. } break;
  880. case 2: {
  881. u = demorect(box, "Layout( UI_HFILL )",
  882. hue, 0, UI_HFILL, T, height, M, M, M, M);
  883. } break;
  884. case 3: {
  885. u = demorect(box, "Layout( UI_RIGHT )",
  886. hue, 0, UI_RIGHT, T/2, height, M, M, M, M);
  887. } break;
  888. }
  889. if (rand()%10 == 0)
  890. uiSetLayout(u, uiGetLayout(u)|UI_BREAK);
  891. }
  892. }
  893. void build_wrapdemo(int parent) {
  894. int col = uiItem();
  895. uiInsert(parent, col);
  896. uiSetBox(col, UI_COLUMN);
  897. uiSetLayout(col, UI_FILL);
  898. const int M = 5;
  899. const int S = 100;
  900. const int T = 50;
  901. int box;
  902. box = demorect(col, "Box( UI_ROW | UI_WRAP | UI_START )\nLayout( UI_HFILL | UI_TOP )",
  903. 0.6f, UI_ROW | UI_WRAP | UI_START, UI_TOP, 0, 0, M, M, M, M);
  904. fill_wrap_row_box(box);
  905. box = demorect(col, "Box( UI_ROW | UI_WRAP | UI_MIDDLE )\nLayout( UI_HFILL | UI_TOP )",
  906. 0.6f, UI_ROW | UI_WRAP, UI_HFILL | UI_TOP, 0, 0, M, M, M, M);
  907. fill_wrap_row_box(box);
  908. box = demorect(col, "Box( UI_ROW | UI_WRAP | UI_END )\nLayout( UI_HFILL | UI_TOP )",
  909. 0.6f, UI_ROW | UI_WRAP | UI_END, UI_HFILL | UI_TOP, 0, 0, M, M, M, M);
  910. fill_wrap_row_box(box);
  911. box = demorect(col, "Box( UI_ROW | UI_WRAP | UI_JUSTIFY )\nLayout( UI_HFILL | UI_TOP )",
  912. 0.6f, UI_ROW | UI_WRAP | UI_JUSTIFY, UI_HFILL | UI_TOP, 0, 0, M, M, M, M);
  913. fill_wrap_row_box(box);
  914. box = demorect(col, "Box( UI_COLUMN | UI_WRAP | UI_START )\nLayout( UI_LEFT | UI_VFILL )",
  915. 0.6f, UI_COLUMN | UI_WRAP | UI_START, UI_LEFT | UI_VFILL, 0, 0, M, M, M, M);
  916. fill_wrap_column_box(box);
  917. }
  918. int add_menu_option(int parent, const char *name, int *choice) {
  919. int opt = radio(-1, name, choice);
  920. uiInsert(parent, opt);
  921. uiSetLayout(opt, UI_HFILL|UI_TOP);
  922. uiSetMargins(opt, 1, 1, 1, 1);
  923. return opt;
  924. }
  925. void draw(NVGcontext *vg, float w, float h) {
  926. bndBackground(vg, 0, 0, w, h);
  927. // some OUI stuff
  928. uiBeginLayout();
  929. int root = panel();
  930. // position root element
  931. uiSetSize(0,w,h);
  932. ((UIData*)uiGetHandle(root))->handler = roothandler;
  933. uiSetEvents(root, UI_SCROLL|UI_BUTTON0_DOWN);
  934. uiSetBox(root, UI_COLUMN);
  935. static int choice = -1;
  936. int menu = uiItem();
  937. uiSetLayout(menu, UI_HFILL|UI_TOP);
  938. uiSetBox(menu, UI_ROW);
  939. uiInsert(root, menu);
  940. int opt_blendish_demo = add_menu_option(menu, "Blendish Demo", &choice);
  941. int opt_oui_demo = add_menu_option(menu, "OUI Demo", &choice);
  942. int opt_layouts = add_menu_option(menu, "UI_LAYOUT", &choice);
  943. int opt_row = add_menu_option(menu, "UI_ROW", &choice);
  944. int opt_column = add_menu_option(menu, "UI_COLUMN", &choice);
  945. int opt_wrap = add_menu_option(menu, "UI_WRAP", &choice);
  946. if (choice < 0)
  947. choice = opt_blendish_demo;
  948. int content = uiItem();
  949. uiSetLayout(content, UI_FILL);
  950. uiInsert(root, content);
  951. if (choice == opt_blendish_demo) {
  952. int democontent = uiItem();
  953. uiSetLayout(democontent, UI_FILL);
  954. uiInsert(content, democontent);
  955. UIData *data = (UIData *)uiAllocHandle(democontent, sizeof(UIData));
  956. data->handler = 0;
  957. data->subtype = ST_DEMOSTUFF;
  958. } else if (choice == opt_oui_demo) {
  959. int democontent = uiItem();
  960. uiSetLayout(democontent, UI_TOP);
  961. uiSetSize(democontent, 250, 0);
  962. uiInsert(content, democontent);
  963. build_democontent(democontent);
  964. } else if (choice == opt_layouts) {
  965. build_layoutdemo(content);
  966. } else if (choice == opt_row) {
  967. build_rowdemo(content);
  968. } else if (choice == opt_column) {
  969. build_columndemo(content);
  970. } else if (choice == opt_wrap) {
  971. build_wrapdemo(content);
  972. }
  973. uiEndLayout();
  974. drawUI(vg, 0, BND_CORNER_NONE);
  975. #if 0
  976. for (int i = 0; i < uiGetLastItemCount(); ++i) {
  977. if (uiRecoverItem(i) == -1) {
  978. UIitem *pitem = uiLastItemPtr(i);
  979. nvgBeginPath(vg);
  980. nvgRect(vg,pitem->margins[0],pitem->margins[1],pitem->size[0],pitem->size[1]);
  981. nvgStrokeWidth(vg, 2);
  982. nvgStrokeColor(vg, nvgRGBAf(1.0f,0.0f,0.0f,0.5f));
  983. nvgStroke(vg);
  984. }
  985. }
  986. #endif
  987. if (choice == opt_blendish_demo) {
  988. UIvec2 cursor = uiGetCursor();
  989. cursor.x -= w/2;
  990. cursor.y -= h/2;
  991. if (abs(cursor.x) > (w/3)) {
  992. bndJoinAreaOverlay(vg, 0, 0, w, h, 0, (cursor.x > 0));
  993. } else if (abs(cursor.y) > (h/3)) {
  994. bndJoinAreaOverlay(vg, 0, 0, w, h, 1, (cursor.y > 0));
  995. }
  996. }
  997. uiProcess((int)(glfwGetTime()*1000.0));
  998. }
  999. ////////////////////////////////////////////////////////////////////////////////
  1000. void errorcb(int error, const char* desc)
  1001. {
  1002. printf("GLFW error %d: %s\n", error, desc);
  1003. }
  1004. static void mousebutton(GLFWwindow *window, int button, int action, int mods) {
  1005. NVG_NOTUSED(window);
  1006. switch(button) {
  1007. case 1: button = 2; break;
  1008. case 2: button = 1; break;
  1009. }
  1010. uiSetButton(button, mods, (action==GLFW_PRESS)?1:0);
  1011. }
  1012. static void cursorpos(GLFWwindow *window, double x, double y) {
  1013. NVG_NOTUSED(window);
  1014. uiSetCursor((int)x,(int)y);
  1015. }
  1016. static void scrollevent(GLFWwindow *window, double x, double y) {
  1017. NVG_NOTUSED(window);
  1018. uiSetScroll((int)x, (int)y);
  1019. }
  1020. static void charevent(GLFWwindow *window, unsigned int value) {
  1021. NVG_NOTUSED(window);
  1022. uiSetChar(value);
  1023. }
  1024. static void key(GLFWwindow* window, int key, int scancode, int action, int mods)
  1025. {
  1026. NVG_NOTUSED(scancode);
  1027. if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
  1028. glfwSetWindowShouldClose(window, GL_TRUE);
  1029. uiSetKey(key, mods, action);
  1030. }
  1031. int main()
  1032. {
  1033. GLFWwindow* window;
  1034. UIcontext *uictx;
  1035. uictx = uiCreateContext(4096, 1<<20);
  1036. uiMakeCurrent(uictx);
  1037. uiSetHandler(ui_handler);
  1038. if (!glfwInit()) {
  1039. printf("Failed to init GLFW.");
  1040. return -1;
  1041. }
  1042. glfwSetErrorCallback(errorcb);
  1043. #ifndef _WIN32 // don't require this on win32, and works with more cards
  1044. glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
  1045. glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
  1046. glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
  1047. glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
  1048. #endif
  1049. glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, 1);
  1050. window = glfwCreateWindow(650, 650, "OUI Blendish Demo", NULL, NULL);
  1051. if (!window) {
  1052. glfwTerminate();
  1053. return -1;
  1054. }
  1055. glfwSetKeyCallback(window, key);
  1056. glfwSetCharCallback(window, charevent);
  1057. glfwSetCursorPosCallback(window, cursorpos);
  1058. glfwSetMouseButtonCallback(window, mousebutton);
  1059. glfwSetScrollCallback(window, scrollevent);
  1060. glfwMakeContextCurrent(window);
  1061. #ifdef NANOVG_GLEW
  1062. glewExperimental = GL_TRUE;
  1063. if(glewInit() != GLEW_OK) {
  1064. printf("Could not init glew.\n");
  1065. return -1;
  1066. }
  1067. // GLEW generates GL error because it calls glGetString(GL_EXTENSIONS), we'll consume it here.
  1068. glGetError();
  1069. #endif
  1070. //_vg = nvgCreateGL3(NVG_ANTIALIAS | NVG_STENCIL_STROKES);
  1071. _vg = nvgCreateGL3(NVG_ANTIALIAS);
  1072. if (_vg == NULL) {
  1073. printf("Could not init nanovg.\n");
  1074. return -1;
  1075. }
  1076. init(_vg);
  1077. printf("sizeof(UIitem)=%lu\n", sizeof(UIitem));
  1078. glfwSwapInterval(0);
  1079. glfwSetTime(0);
  1080. double c = 0.0;
  1081. int total = 0;
  1082. int peak_items = 0;
  1083. unsigned int peak_alloc = 0;
  1084. while (!glfwWindowShouldClose(window))
  1085. {
  1086. double mx, my;
  1087. int winWidth, winHeight;
  1088. int fbWidth, fbHeight;
  1089. float pxRatio;
  1090. glfwGetCursorPos(window, &mx, &my);
  1091. glfwGetWindowSize(window, &winWidth, &winHeight);
  1092. glfwGetFramebufferSize(window, &fbWidth, &fbHeight);
  1093. // Calculate pixel ration for hi-dpi devices.
  1094. pxRatio = (float)fbWidth / (float)winWidth;
  1095. // Update and render
  1096. glViewport(0, 0, fbWidth, fbHeight);
  1097. glClearColor(0,0,0,1);
  1098. glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
  1099. double t = glfwGetTime();
  1100. nvgBeginFrame(_vg, winWidth, winHeight, pxRatio);
  1101. draw(_vg, winWidth, winHeight);
  1102. peak_items = (peak_items > uiGetItemCount())?peak_items:uiGetItemCount();
  1103. peak_alloc = (peak_alloc > uiGetAllocSize())?peak_alloc:uiGetAllocSize();
  1104. nvgEndFrame(_vg);
  1105. double t2 = glfwGetTime();
  1106. c += (t2 - t);
  1107. total++;
  1108. if (total > (1*60)) {
  1109. printf("%fms\n", (c / (double)total)*1000.0);
  1110. total = 0;
  1111. c = 0.0;
  1112. }
  1113. glfwSwapBuffers(window);
  1114. glfwPollEvents();
  1115. }
  1116. printf("Peak item count: %i (%lu bytes)\nPeak allocated handles: %u bytes\n",
  1117. peak_items, peak_items * sizeof(UIitem), peak_alloc);
  1118. uiDestroyContext(uictx);
  1119. nvgDeleteGL3(_vg);
  1120. glfwTerminate();
  1121. return 0;
  1122. }