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.

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