You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

749 lines
23KB

  1. //
  2. // based on NanoVG's example code by Mikko Mononen
  3. #include <stdio.h>
  4. #ifdef NANOVG_GLEW
  5. # include <GL/glew.h>
  6. #endif
  7. #ifdef __APPLE__
  8. # define GLFW_INCLUDE_GLCOREARB
  9. #endif
  10. #include <GLFW/glfw3.h>
  11. #include "nanovg.h"
  12. #define NANOVG_GL3_IMPLEMENTATION
  13. #include "nanovg_gl.h"
  14. #define BLENDISH_IMPLEMENTATION
  15. #include "blendish.h"
  16. #define OUI_IMPLEMENTATION
  17. #include "oui.h"
  18. ////////////////////////////////////////////////////////////////////////////////
  19. typedef enum {
  20. // label
  21. ST_LABEL = 0,
  22. // button
  23. ST_BUTTON = 1,
  24. // radio button
  25. ST_RADIO = 2,
  26. // progress slider
  27. ST_SLIDER = 3,
  28. // column
  29. ST_COLUMN = 4,
  30. // row
  31. ST_ROW = 5,
  32. // check button
  33. ST_CHECK = 6,
  34. } SubType;
  35. typedef struct {
  36. int subtype;
  37. } UIData;
  38. typedef struct {
  39. UIData head;
  40. int iconid;
  41. const char *label;
  42. } UIButtonData;
  43. typedef struct {
  44. UIData head;
  45. const char *label;
  46. int *option;
  47. } UICheckData;
  48. typedef struct {
  49. UIData head;
  50. int iconid;
  51. const char *label;
  52. int *value;
  53. } UIRadioData;
  54. typedef struct {
  55. UIData head;
  56. const char *label;
  57. float *progress;
  58. } UISliderData;
  59. ////////////////////////////////////////////////////////////////////////////////
  60. void init(NVGcontext *vg) {
  61. bndSetFont(nvgCreateFont(vg, "system", "../DejaVuSans.ttf"));
  62. bndSetIconImage(nvgCreateImage(vg, "../blender_icons16.png"));
  63. }
  64. // calculate which corners are sharp for an item, depending on whether
  65. // the container the item is in has negative spacing, and the item
  66. // is first or last element in a sequence of 2 or more elements.
  67. int cornerFlags(int item) {
  68. int parent = uiParent(item);
  69. int numkids = uiGetChildCount(parent);
  70. if (numkids < 2) return BND_CORNER_NONE;
  71. const UIData *head = (const UIData *)uiGetData(parent);
  72. if (head) {
  73. int numid = uiGetChildId(item);
  74. switch(head->subtype) {
  75. case ST_COLUMN: {
  76. if (!numid) return BND_CORNER_DOWN;
  77. else if (numid == numkids-1) return BND_CORNER_TOP;
  78. else return BND_CORNER_ALL;
  79. } break;
  80. case ST_ROW: {
  81. if (!numid) return BND_CORNER_RIGHT;
  82. else if (numid == numkids-1) return BND_CORNER_LEFT;
  83. else return BND_CORNER_ALL;
  84. } break;
  85. default: break;
  86. }
  87. }
  88. return BND_CORNER_NONE;
  89. }
  90. void testrect(NVGcontext *vg, UIrect rect) {
  91. #if 0
  92. nvgBeginPath(vg);
  93. nvgRect(vg,rect.x+0.5,rect.y+0.5,rect.w-1,rect.h-1);
  94. nvgStrokeColor(vg,nvgRGBf(1,0,0));
  95. nvgStrokeWidth(vg,1);
  96. nvgStroke(vg);
  97. #endif
  98. }
  99. void drawUI(NVGcontext *vg, int item, int x, int y) {
  100. const UIData *head = (const UIData *)uiGetData(item);
  101. UIrect rect = uiGetRect(item);
  102. rect.x += x;
  103. rect.y += y;
  104. if (uiGetState(item) == UI_FROZEN) {
  105. nvgGlobalAlpha(vg, 0.5);
  106. }
  107. if (head) {
  108. switch(head->subtype) {
  109. default: {
  110. testrect(vg,rect);
  111. } break;
  112. case ST_LABEL: {
  113. assert(head);
  114. const UIButtonData *data = (UIButtonData*)head;
  115. bndLabel(vg,rect.x,rect.y,rect.w,rect.h,
  116. data->iconid,data->label);
  117. } break;
  118. case ST_BUTTON: {
  119. const UIButtonData *data = (UIButtonData*)head;
  120. bndToolButton(vg,rect.x,rect.y,rect.w,rect.h,
  121. cornerFlags(item),(BNDwidgetState)uiGetState(item),
  122. data->iconid,data->label);
  123. } break;
  124. case ST_CHECK: {
  125. const UICheckData *data = (UICheckData*)head;
  126. BNDwidgetState state = (BNDwidgetState)uiGetState(item);
  127. if (*data->option)
  128. state = BND_ACTIVE;
  129. bndOptionButton(vg,rect.x,rect.y,rect.w,rect.h, state,
  130. data->label);
  131. } break;
  132. case ST_RADIO:{
  133. const UIRadioData *data = (UIRadioData*)head;
  134. BNDwidgetState state = (BNDwidgetState)uiGetState(item);
  135. if (*data->value == uiGetChildId(item))
  136. state = BND_ACTIVE;
  137. bndRadioButton(vg,rect.x,rect.y,rect.w,rect.h,
  138. cornerFlags(item),state,
  139. data->iconid,data->label);
  140. } break;
  141. case ST_SLIDER:{
  142. const UISliderData *data = (UISliderData*)head;
  143. BNDwidgetState state = (BNDwidgetState)uiGetState(item);
  144. static char value[32];
  145. sprintf(value,"%.0f%%",(*data->progress)*100.0f);
  146. bndSlider(vg,rect.x,rect.y,rect.w,rect.h,
  147. cornerFlags(item),state,
  148. *data->progress,data->label,value);
  149. } break;
  150. }
  151. } else {
  152. testrect(vg,rect);
  153. }
  154. int kid = uiFirstChild(item);
  155. while (kid > 0) {
  156. drawUI(vg, kid, rect.x, rect.y);
  157. kid = uiNextSibling(kid);
  158. }
  159. if (uiGetState(item) == UI_FROZEN) {
  160. nvgGlobalAlpha(vg, 1.0);
  161. }
  162. }
  163. int label(int parent, int iconid, const char *label) {
  164. int item = uiItem();
  165. uiSetSize(item, 0, BND_WIDGET_HEIGHT);
  166. UIButtonData *data = (UIButtonData *)uiAllocData(item, sizeof(UIButtonData));
  167. data->head.subtype = ST_LABEL;
  168. data->iconid = iconid;
  169. data->label = label;
  170. uiAppend(parent, item);
  171. return item;
  172. }
  173. void demohandler(int item, UIevent event) {
  174. const UIButtonData *data = (const UIButtonData *)uiGetData(item);
  175. printf("clicked: %lld %s\n", uiGetHandle(item), data->label);
  176. }
  177. int button(int parent, UIhandle handle, int iconid, const char *label,
  178. UIhandler handler) {
  179. // create new ui item
  180. int item = uiItem();
  181. // set persistent handle for item that is used
  182. // to track activity over time
  183. uiSetHandle(item, handle);
  184. // set size of wiget; horizontal size is dynamic, vertical is fixed
  185. uiSetSize(item, 0, BND_WIDGET_HEIGHT);
  186. // attach event handler e.g. demohandler above
  187. uiSetHandler(item, handler, UI_BUTTON0_HOT_UP);
  188. // store some custom data with the button that we use for styling
  189. UIButtonData *data = (UIButtonData *)uiAllocData(item, sizeof(UIButtonData));
  190. data->head.subtype = ST_BUTTON;
  191. data->iconid = iconid;
  192. data->label = label;
  193. uiAppend(parent, item);
  194. return item;
  195. }
  196. void checkhandler(int item, UIevent event) {
  197. const UICheckData *data = (const UICheckData *)uiGetData(item);
  198. *data->option = !(*data->option);
  199. }
  200. int check(int parent, UIhandle handle, const char *label, int *option) {
  201. // create new ui item
  202. int item = uiItem();
  203. // set persistent handle for item that is used
  204. // to track activity over time
  205. uiSetHandle(item, handle);
  206. // set size of wiget; horizontal size is dynamic, vertical is fixed
  207. uiSetSize(item, 0, BND_WIDGET_HEIGHT);
  208. // attach event handler e.g. demohandler above
  209. uiSetHandler(item, checkhandler, UI_BUTTON0_DOWN);
  210. // store some custom data with the button that we use for styling
  211. UICheckData *data = (UICheckData *)uiAllocData(item, sizeof(UICheckData));
  212. data->head.subtype = ST_CHECK;
  213. data->label = label;
  214. data->option = option;
  215. uiAppend(parent, item);
  216. return item;
  217. }
  218. // simple logic for a slider
  219. // starting offset of the currently active slider
  220. static float sliderstart = 0.0;
  221. // event handler for slider (same handler for all sliders)
  222. void sliderhandler(int item, UIevent event) {
  223. // retrieve the custom data we saved with the slider
  224. UISliderData *data = (UISliderData *)uiGetData(item);
  225. switch(event) {
  226. default: break;
  227. case UI_BUTTON0_DOWN: {
  228. // button was pressed for the first time; capture initial
  229. // slider value.
  230. sliderstart = *data->progress;
  231. } break;
  232. case UI_BUTTON0_CAPTURE: {
  233. // called for every frame that the button is pressed.
  234. // get the delta between the click point and the current
  235. // mouse position
  236. UIvec2 pos = uiGetCursorStartDelta();
  237. // get the items layouted rectangle
  238. UIrect rc = uiGetRect(item);
  239. // calculate our new offset and clamp
  240. float value = sliderstart + ((float)pos.x / (float)rc.w);
  241. value = (value<0)?0:(value>1)?1:value;
  242. // assign the new value
  243. *data->progress = value;
  244. } break;
  245. }
  246. }
  247. int slider(int parent, UIhandle handle, const char *label, float *progress) {
  248. // create new ui item
  249. int item = uiItem();
  250. // set persistent handle for item that is used
  251. // to track activity over time
  252. uiSetHandle(item, handle);
  253. // set size of wiget; horizontal size is dynamic, vertical is fixed
  254. uiSetSize(item, 0, BND_WIDGET_HEIGHT);
  255. // attach our slider event handler and capture two classes of events
  256. uiSetHandler(item, sliderhandler,
  257. UI_BUTTON0_DOWN | UI_BUTTON0_CAPTURE);
  258. // store some custom data with the button that we use for styling
  259. // and logic, e.g. the pointer to the data we want to alter.
  260. UISliderData *data = (UISliderData *)uiAllocData(item, sizeof(UISliderData));
  261. data->head.subtype = ST_SLIDER;
  262. data->label = label;
  263. data->progress = progress;
  264. uiAppend(parent, item);
  265. return item;
  266. }
  267. // simple logic for a radio button
  268. void radiohandler(int item, UIevent event) {
  269. UIRadioData *data = (UIRadioData *)uiGetData(item);
  270. *data->value = uiGetChildId(item);
  271. }
  272. int radio(int parent, UIhandle handle, int iconid, const char *label, int *value) {
  273. int item = uiItem();
  274. uiSetHandle(item, handle);
  275. uiSetSize(item, label?0:BND_TOOL_WIDTH, BND_WIDGET_HEIGHT);
  276. UIRadioData *data = (UIRadioData *)uiAllocData(item, sizeof(UIRadioData));
  277. data->head.subtype = ST_RADIO;
  278. data->iconid = iconid;
  279. data->label = label;
  280. data->value = value;
  281. uiSetHandler(item, radiohandler, UI_BUTTON0_DOWN);
  282. uiAppend(parent, item);
  283. return item;
  284. }
  285. void columnhandler(int parent, UIevent event) {
  286. int item = uiLastChild(parent);
  287. int last = uiPrevSibling(item);
  288. // mark the new item as positioned under the previous item
  289. uiSetRelToTop(item, last);
  290. // fill parent horizontally, anchor to previous item vertically
  291. uiSetLayout(item, UI_HFILL|UI_TOP);
  292. // if not the first item, add a margin of 1
  293. uiSetMargins(item, 0, (last < 0)?0:1, 0, 0);
  294. }
  295. int column(int parent) {
  296. int item = uiItem();
  297. uiSetHandler(item, columnhandler, UI_APPEND);
  298. uiAppend(parent, item);
  299. return item;
  300. }
  301. void vgrouphandler(int parent, UIevent event) {
  302. int item = uiLastChild(parent);
  303. int last = uiPrevSibling(item);
  304. // mark the new item as positioned under the previous item
  305. uiSetRelToTop(item, last);
  306. // fill parent horizontally, anchor to previous item vertically
  307. uiSetLayout(item, UI_HFILL|UI_TOP);
  308. // if not the first item, add a margin
  309. uiSetMargins(item, 0, (last < 0)?0:-2, 0, 0);
  310. }
  311. int vgroup(int parent) {
  312. int item = uiItem();
  313. UIData *data = (UIData *)uiAllocData(item, sizeof(UIData));
  314. data->subtype = ST_COLUMN;
  315. uiSetHandler(item, vgrouphandler, UI_APPEND);
  316. uiAppend(parent, item);
  317. return item;
  318. }
  319. void hgrouphandler(int parent, UIevent event) {
  320. int item = uiLastChild(parent);
  321. int last = uiPrevSibling(item);
  322. uiSetRelToLeft(item, last);
  323. if (last > 0)
  324. uiSetRelToRight(last, item);
  325. uiSetLayout(item, UI_LEFT|UI_RIGHT);
  326. uiSetMargins(item, (last < 0)?0:-1, 0, 0, 0);
  327. }
  328. int hgroup(int parent) {
  329. int item = uiItem();
  330. UIData *data = (UIData *)uiAllocData(item, sizeof(UIData));
  331. data->subtype = ST_ROW;
  332. uiSetHandler(item, hgrouphandler, UI_APPEND);
  333. uiAppend(parent, item);
  334. return item;
  335. }
  336. void rowhandler(int parent, UIevent event) {
  337. int item = uiLastChild(parent);
  338. int last = uiPrevSibling(item);
  339. uiSetRelToLeft(item, last);
  340. if (last > 0)
  341. uiSetRelToRight(last, item);
  342. uiSetLayout(item, UI_LEFT|UI_RIGHT);
  343. uiSetMargins(item, (last < 0)?0:8, 0, 0, 0);
  344. }
  345. int row(int parent) {
  346. int item = uiItem();
  347. uiSetHandler(item, rowhandler, UI_APPEND);
  348. uiAppend(parent, item);
  349. return item;
  350. }
  351. void draw(NVGcontext *vg, float w, float h) {
  352. bndBackground(vg, 0, 0, w, h);
  353. int x = 10;
  354. int y = 10;
  355. bndToolButton(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT,
  356. BND_ICONID(6,3),"Default");
  357. y += 25;
  358. bndToolButton(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER,
  359. BND_ICONID(6,3),"Hovered");
  360. y += 25;
  361. bndToolButton(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE,
  362. BND_ICONID(6,3),"Active");
  363. y += 40;
  364. bndRadioButton(vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT,
  365. -1,"Default");
  366. y += 25;
  367. bndRadioButton(vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER,
  368. -1,"Hovered");
  369. y += 25;
  370. bndRadioButton(vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE,
  371. -1,"Active");
  372. y += 25;
  373. bndLabel(vg,x,y,120,BND_WIDGET_HEIGHT,-1,"Label:");
  374. y += BND_WIDGET_HEIGHT;
  375. bndChoiceButton(vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT,
  376. -1, "Default");
  377. y += 25;
  378. bndChoiceButton(vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER,
  379. -1, "Hovered");
  380. y += 25;
  381. bndChoiceButton(vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE,
  382. -1, "Active");
  383. y += 25;
  384. int ry = y;
  385. int rx = x;
  386. y = 10;
  387. x += 130;
  388. bndOptionButton(vg,x,y,120,BND_WIDGET_HEIGHT,BND_DEFAULT,"Default");
  389. y += 25;
  390. bndOptionButton(vg,x,y,120,BND_WIDGET_HEIGHT,BND_HOVER,"Hovered");
  391. y += 25;
  392. bndOptionButton(vg,x,y,120,BND_WIDGET_HEIGHT,BND_ACTIVE,"Active");
  393. y += 40;
  394. bndNumberField(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_DOWN,BND_DEFAULT,
  395. "Top","100");
  396. y += BND_WIDGET_HEIGHT-2;
  397. bndNumberField(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_ALL,BND_DEFAULT,
  398. "Center","100");
  399. y += BND_WIDGET_HEIGHT-2;
  400. bndNumberField(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_TOP,BND_DEFAULT,
  401. "Bottom","100");
  402. int mx = x-30;
  403. int my = y-12;
  404. int mw = 120;
  405. bndMenuBackground(vg,mx,my,mw,120,BND_CORNER_TOP);
  406. bndMenuLabel(vg,mx,my,mw,BND_WIDGET_HEIGHT,-1,"Menu Title");
  407. my += BND_WIDGET_HEIGHT-2;
  408. bndMenuItem(vg,mx,my,mw,BND_WIDGET_HEIGHT,BND_DEFAULT,
  409. BND_ICONID(17,3),"Default");
  410. my += BND_WIDGET_HEIGHT-2;
  411. bndMenuItem(vg,mx,my,mw,BND_WIDGET_HEIGHT,BND_HOVER,
  412. BND_ICONID(18,3),"Hovered");
  413. my += BND_WIDGET_HEIGHT-2;
  414. bndMenuItem(vg,mx,my,mw,BND_WIDGET_HEIGHT,BND_ACTIVE,
  415. BND_ICONID(19,3),"Active");
  416. y = 10;
  417. x += 130;
  418. int ox = x;
  419. bndNumberField(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT,
  420. "Default","100");
  421. y += 25;
  422. bndNumberField(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER,
  423. "Hovered","100");
  424. y += 25;
  425. bndNumberField(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE,
  426. "Active","100");
  427. y += 40;
  428. bndRadioButton(vg,x,y,60,BND_WIDGET_HEIGHT,BND_CORNER_RIGHT,BND_DEFAULT,
  429. -1,"One");
  430. x += 60-1;
  431. bndRadioButton(vg,x,y,60,BND_WIDGET_HEIGHT,BND_CORNER_ALL,BND_DEFAULT,
  432. -1,"Two");
  433. x += 60-1;
  434. bndRadioButton(vg,x,y,60,BND_WIDGET_HEIGHT,BND_CORNER_ALL,BND_DEFAULT,
  435. -1,"Three");
  436. x += 60-1;
  437. bndRadioButton(vg,x,y,60,BND_WIDGET_HEIGHT,BND_CORNER_LEFT,BND_ACTIVE,
  438. -1,"Butts");
  439. x = ox;
  440. y += 40;
  441. float progress_value = fmodf(glfwGetTime()/10.0,1.0);
  442. char progress_label[32];
  443. sprintf(progress_label, "%d%%", int(progress_value*100+0.5f));
  444. bndSlider(vg,x,y,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT,
  445. progress_value,"Default",progress_label);
  446. y += 25;
  447. bndSlider(vg,x,y,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER,
  448. progress_value,"Hovered",progress_label);
  449. y += 25;
  450. bndSlider(vg,x,y,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE,
  451. progress_value,"Active",progress_label);
  452. int rw = x+240-rx;
  453. float s_offset = sinf(glfwGetTime()/2.0)*0.5+0.5;
  454. float s_size = cosf(glfwGetTime()/3.11)*0.5+0.5;
  455. bndScrollBar(vg,rx,ry,rw,BND_SCROLLBAR_HEIGHT,BND_DEFAULT,s_offset,s_size);
  456. ry += 20;
  457. bndScrollBar(vg,rx,ry,rw,BND_SCROLLBAR_HEIGHT,BND_HOVER,s_offset,s_size);
  458. ry += 20;
  459. bndScrollBar(vg,rx,ry,rw,BND_SCROLLBAR_HEIGHT,BND_ACTIVE,s_offset,s_size);
  460. const char edit_text[] = "The quick brown fox";
  461. int textlen = strlen(edit_text)+1;
  462. int t = int(glfwGetTime()*2);
  463. int idx1 = (t/textlen)%textlen;
  464. int idx2 = idx1 + (t%(textlen-idx1));
  465. ry += 25;
  466. bndTextField(vg,rx,ry,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT,
  467. -1, edit_text, idx1, idx2);
  468. ry += 25;
  469. bndTextField(vg,rx,ry,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER,
  470. -1, edit_text, idx1, idx2);
  471. ry += 25;
  472. bndTextField(vg,rx,ry,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE,
  473. -1, edit_text, idx1, idx2);
  474. rx += rw + 20;
  475. ry = 10;
  476. bndScrollBar(vg,rx,ry,BND_SCROLLBAR_WIDTH,240,BND_DEFAULT,s_offset,s_size);
  477. rx += 20;
  478. bndScrollBar(vg,rx,ry,BND_SCROLLBAR_WIDTH,240,BND_HOVER,s_offset,s_size);
  479. rx += 20;
  480. bndScrollBar(vg,rx,ry,BND_SCROLLBAR_WIDTH,240,BND_ACTIVE,s_offset,s_size);
  481. x = ox;
  482. y += 40;
  483. bndToolButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_RIGHT,
  484. BND_DEFAULT,BND_ICONID(0,10),NULL);
  485. x += BND_TOOL_WIDTH-1;
  486. bndToolButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  487. BND_DEFAULT,BND_ICONID(1,10),NULL);
  488. x += BND_TOOL_WIDTH-1;
  489. bndToolButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  490. BND_DEFAULT,BND_ICONID(2,10),NULL);
  491. x += BND_TOOL_WIDTH-1;
  492. bndToolButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  493. BND_DEFAULT,BND_ICONID(3,10),NULL);
  494. x += BND_TOOL_WIDTH-1;
  495. bndToolButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  496. BND_DEFAULT,BND_ICONID(4,10),NULL);
  497. x += BND_TOOL_WIDTH-1;
  498. bndToolButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_LEFT,
  499. BND_DEFAULT,BND_ICONID(5,10),NULL);
  500. x += BND_TOOL_WIDTH-1;
  501. x += 5;
  502. bndRadioButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_RIGHT,
  503. BND_DEFAULT,BND_ICONID(0,11),NULL);
  504. x += BND_TOOL_WIDTH-1;
  505. bndRadioButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  506. BND_DEFAULT,BND_ICONID(1,11),NULL);
  507. x += BND_TOOL_WIDTH-1;
  508. bndRadioButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  509. BND_DEFAULT,BND_ICONID(2,11),NULL);
  510. x += BND_TOOL_WIDTH-1;
  511. bndRadioButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  512. BND_DEFAULT,BND_ICONID(3,11),NULL);
  513. x += BND_TOOL_WIDTH-1;
  514. bndRadioButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  515. BND_ACTIVE,BND_ICONID(4,11),NULL);
  516. x += BND_TOOL_WIDTH-1;
  517. bndRadioButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_LEFT,
  518. BND_DEFAULT,BND_ICONID(5,11),NULL);
  519. // some OUI stuff
  520. // some persistent variables for demonstration
  521. static int enum1 = 0;
  522. static float progress1 = 0.25f;
  523. static float progress2 = 0.75f;
  524. static int option1 = 1;
  525. static int option2 = 0;
  526. static int option3 = 0;
  527. uiClear();
  528. int root = uiItem();
  529. // position root element
  530. uiSetLayout(0,UI_LEFT|UI_TOP);
  531. uiSetMargins(0,600,10,0,0);
  532. uiSetSize(0,250,400);
  533. int col = column(0);
  534. uiSetLayout(col, UI_TOP|UI_HFILL);
  535. button(col, 1, BND_ICONID(6,3), "Item 1", demohandler);
  536. button(col, 2, BND_ICONID(6,3), "Item 2", demohandler);
  537. {
  538. int h = hgroup(col);
  539. radio(h, 3, BND_ICONID(6,3), "Item 3.0", &enum1);
  540. radio(h, 4, BND_ICONID(0,10), NULL, &enum1);
  541. radio(h, 5, BND_ICONID(1,10), NULL, &enum1);
  542. radio(h, 6, BND_ICONID(6,3), "Item 3.3", &enum1);
  543. }
  544. {
  545. int rows = row(col);
  546. int coll = vgroup(rows);
  547. label(coll, -1, "Items 4.0:");
  548. coll = vgroup(coll);
  549. button(coll, 7, BND_ICONID(6,3), "Item 4.0.0", demohandler);
  550. button(coll, 8, BND_ICONID(6,3), "Item 4.0.1", demohandler);
  551. int colr = vgroup(rows);
  552. uiSetFrozen(colr, option1);
  553. label(colr, -1, "Items 4.1:");
  554. colr = vgroup(colr);
  555. slider(colr, 9, "Item 4.1.0", &progress1);
  556. slider(colr,10, "Item 4.1.1", &progress2);
  557. }
  558. button(col, 11, BND_ICONID(6,3), "Item 5", NULL);
  559. check(col, 12, "Frozen", &option1);
  560. check(col, 13, "Item 7", &option2);
  561. check(col, 14, "Item 8", &option3);
  562. uiProcess();
  563. drawUI(vg, 0, 0, 0);
  564. }
  565. ////////////////////////////////////////////////////////////////////////////////
  566. void errorcb(int error, const char* desc)
  567. {
  568. printf("GLFW error %d: %s\n", error, desc);
  569. }
  570. static void mousebutton(GLFWwindow *window, int button, int action, int mods) {
  571. NVG_NOTUSED(window);
  572. NVG_NOTUSED(mods);
  573. uiSetButton(button, (action==GLFW_PRESS)?1:0);
  574. }
  575. static void cursorpos(GLFWwindow *window, double x, double y) {
  576. NVG_NOTUSED(window);
  577. uiSetCursor((int)x,(int)y);
  578. }
  579. static void key(GLFWwindow* window, int key, int scancode, int action, int mods)
  580. {
  581. NVG_NOTUSED(scancode);
  582. NVG_NOTUSED(mods);
  583. if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
  584. glfwSetWindowShouldClose(window, GL_TRUE);
  585. }
  586. int main()
  587. {
  588. GLFWwindow* window;
  589. struct NVGcontext* vg = NULL;
  590. UIcontext *uictx;
  591. uictx = uiCreateContext();
  592. uiMakeCurrent(uictx);
  593. if (!glfwInit()) {
  594. printf("Failed to init GLFW.");
  595. return -1;
  596. }
  597. glfwSetErrorCallback(errorcb);
  598. #ifndef _WIN32 // don't require this on win32, and works with more cards
  599. glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
  600. glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
  601. glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
  602. glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
  603. #endif
  604. glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, 1);
  605. window = glfwCreateWindow(1000, 600, "OUI Blendish Demo", NULL, NULL);
  606. if (!window) {
  607. glfwTerminate();
  608. return -1;
  609. }
  610. glfwSetKeyCallback(window, key);
  611. glfwSetCursorPosCallback(window, cursorpos);
  612. glfwSetMouseButtonCallback(window, mousebutton);
  613. glfwMakeContextCurrent(window);
  614. #ifdef NANOVG_GLEW
  615. glewExperimental = GL_TRUE;
  616. if(glewInit() != GLEW_OK) {
  617. printf("Could not init glew.\n");
  618. return -1;
  619. }
  620. // GLEW generates GL error because it calls glGetString(GL_EXTENSIONS), we'll consume it here.
  621. glGetError();
  622. #endif
  623. vg = nvgCreateGL3(NVG_ANTIALIAS | NVG_STENCIL_STROKES);
  624. if (vg == NULL) {
  625. printf("Could not init nanovg.\n");
  626. return -1;
  627. }
  628. init(vg);
  629. glfwSwapInterval(0);
  630. glfwSetTime(0);
  631. while (!glfwWindowShouldClose(window))
  632. {
  633. double mx, my;
  634. int winWidth, winHeight;
  635. int fbWidth, fbHeight;
  636. float pxRatio;
  637. glfwGetCursorPos(window, &mx, &my);
  638. glfwGetWindowSize(window, &winWidth, &winHeight);
  639. glfwGetFramebufferSize(window, &fbWidth, &fbHeight);
  640. // Calculate pixel ration for hi-dpi devices.
  641. pxRatio = (float)fbWidth / (float)winWidth;
  642. // Update and render
  643. glViewport(0, 0, fbWidth, fbHeight);
  644. glClearColor(0,0,0,1);
  645. glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
  646. nvgBeginFrame(vg, winWidth, winHeight, pxRatio);
  647. draw(vg, winWidth, winHeight);
  648. nvgEndFrame(vg);
  649. glfwSwapBuffers(window);
  650. glfwPollEvents();
  651. }
  652. uiDestroyContext(uictx);
  653. nvgDeleteGL3(vg);
  654. glfwTerminate();
  655. return 0;
  656. }