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.

863 lines
24KB

  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. #include <assert.h>
  17. ////////////////////////////////////////////////////////////////////////////////
  18. #define UI_IMPLEMENTATION
  19. #ifndef _UI_H_
  20. #define _UI_H_
  21. #define UI_COLD 0x0000
  22. #define UI_HOT 0x0001
  23. #define UI_ACTIVE 0x0002
  24. // containers
  25. #define UI_ROOT 0x0100
  26. #define UI_COLUMN 0x0101
  27. #define UI_ROW 0x0102
  28. // controls
  29. #define UI_BUTTON 0x0203
  30. #define UI_MAX_ITEMS 4096
  31. #define UI_MAX_BUFFERSIZE 1048576
  32. #define UI_MAX_DEPTH 64
  33. typedef struct UIcontext UIcontext;
  34. typedef unsigned long long UIhandle;
  35. typedef struct UIrect {
  36. int x, y, w, h;
  37. } UIrect;
  38. UIcontext *uiCreateContext();
  39. void uiMakeCurrent(UIcontext *ctx);
  40. void uiDestroyContext(UIcontext *ctx);
  41. void uiSetButton(int button, int enabled);
  42. int uiGetButton(int button);
  43. void uiSetCursor(int x, int y);
  44. void uiGetCursor(int *x, int *y);
  45. void uiClear();
  46. int uiItem(int parent, UIhandle handle, int kind,
  47. int w, int h, void *data, int size);
  48. int uiColumn(int parent, int spacing);
  49. int uiRow(int parent, int spacing);
  50. void uiLayout();
  51. int uiFirstChild(int item);
  52. int uiLastChild(int item);
  53. int uiNextSibling(int item);
  54. int uiParent(int item);
  55. void uiSetSpacing(int item, int spacing);
  56. int uiGetSpacing(int item);
  57. int uiGetKind(int item);
  58. UIrect uiGetRect(int item);
  59. UIrect uiGetScreenRect(int item);
  60. void uiSetRect(int item, int x, int y, int w, int h);
  61. void *uiGetData(int item);
  62. int uiGetChildId(int item);
  63. int uiGetChildCount(int item);
  64. int uiGetHandle(int item);
  65. int uiGetState(int item);
  66. #endif // _UI_H_
  67. #ifdef UI_IMPLEMENTATION
  68. #define UI_MAX_KIND 16
  69. typedef struct UIitem {
  70. UIhandle handle;
  71. int parent;
  72. // number of kids
  73. int numkids;
  74. // index of kid relative to parent
  75. int kidid;
  76. UIrect rect;
  77. int absx,absy;
  78. int kind;
  79. int data;
  80. int spacing;
  81. // index of first kid
  82. int firstkid;
  83. // index of last kid
  84. int lastkid;
  85. // index of next sibling with same parent
  86. int nextitem;
  87. } UIitem;
  88. struct UIcontext {
  89. unsigned long long buttons;
  90. int cx, cy;
  91. UIhandle hot;
  92. UIhandle active;
  93. int count;
  94. UIitem items[UI_MAX_ITEMS];
  95. int datasize;
  96. unsigned char data[UI_MAX_BUFFERSIZE];
  97. };
  98. static UIcontext *ui_context = NULL;
  99. UIcontext *uiCreateContext() {
  100. UIcontext *ctx = (UIcontext *)malloc(sizeof(UIcontext));
  101. memset(ctx, 0, sizeof(UIcontext));
  102. return ctx;
  103. }
  104. void uiMakeCurrent(UIcontext *ctx) {
  105. ui_context = ctx;
  106. uiClear();
  107. }
  108. void uiDestroyContext(UIcontext *ctx) {
  109. free(ctx);
  110. }
  111. void uiSetButton(int button, int enabled) {
  112. assert(ui_context);
  113. unsigned long long mask = 1ull<<button;
  114. ui_context->buttons = (enabled)?
  115. (ui_context->buttons | mask):
  116. (ui_context->buttons & ~mask);
  117. }
  118. int uiGetButton(int button) {
  119. assert(ui_context);
  120. return (ui_context->buttons & (1ull<<button))?1:0;
  121. }
  122. void uiSetCursor(int x, int y) {
  123. assert(ui_context);
  124. ui_context->cx = x;
  125. ui_context->cy = y;
  126. }
  127. void uiGetCursor(int *x, int *y) {
  128. assert(ui_context);
  129. *x = ui_context->cx;
  130. *y = ui_context->cy;
  131. }
  132. UIitem *uiItemPtr(int item) {
  133. assert(ui_context && (item >= 0) && (item < ui_context->count));
  134. return ui_context->items + item;
  135. }
  136. void uiClear() {
  137. assert(ui_context);
  138. ui_context->count = 1;
  139. ui_context->datasize = 0;
  140. ui_context->hot = 0;
  141. // init root object
  142. UIitem *item = ui_context->items;
  143. memset(item, 0, sizeof(UIitem));
  144. item->parent = -1;
  145. item->firstkid = -1;
  146. item->lastkid = -1;
  147. item->nextitem = -1;
  148. item->kind = UI_ROOT;
  149. item->data = -1;
  150. }
  151. int uiAllocItem(int parent, UIhandle handle, int kind, void *data, int size) {
  152. assert(ui_context && (ui_context->count < UI_MAX_ITEMS));
  153. assert((size >= 0) && ((ui_context->datasize+size) <= UI_MAX_BUFFERSIZE));
  154. assert(parent >= 0);
  155. int idx = ui_context->count++;
  156. UIitem *item = uiItemPtr(idx);
  157. memset(item, 0, sizeof(UIitem));
  158. item->parent = parent;
  159. item->handle = handle;
  160. item->firstkid = -1;
  161. item->lastkid = -1;
  162. item->nextitem = -1;
  163. item->kidid = ui_context->items[parent].numkids++;
  164. if (ui_context->items[parent].lastkid < 0) {
  165. ui_context->items[parent].firstkid = idx;
  166. ui_context->items[parent].lastkid = idx;
  167. } else {
  168. ui_context->items[ui_context->items[parent].lastkid].nextitem = idx;
  169. ui_context->items[parent].lastkid = idx;
  170. }
  171. item->kind = kind;
  172. item->data = -1;
  173. if (data && size) {
  174. item->data = ui_context->datasize;
  175. ui_context->datasize += size;
  176. memcpy(ui_context->data + item->data, data, size);
  177. }
  178. return idx;
  179. }
  180. int uiItem(
  181. int parent, UIhandle handle, int kind, int w, int h, void *data, int size) {
  182. int idx = uiAllocItem(parent, handle, kind, data, size);
  183. UIitem *item = uiItemPtr(idx);
  184. item->rect.w = w;
  185. item->rect.h = h;
  186. return idx;
  187. }
  188. void uiSetSpacing(int item, int spacing) {
  189. uiItemPtr(item)->spacing = spacing;
  190. }
  191. int uiGetSpacing(int item) {
  192. return uiItemPtr(item)->spacing;
  193. }
  194. int uiColumn(int parent, int spacing) {
  195. int idx = uiItem(parent, 0, UI_COLUMN, 0, 0, NULL, 0);
  196. uiSetSpacing(idx, spacing);
  197. return idx;
  198. }
  199. int uiRow(int parent, int spacing) {
  200. int idx = uiItem(parent, 0, UI_ROW, 0, 0, NULL, 0);
  201. uiSetSpacing(idx, spacing);
  202. return idx;
  203. }
  204. UIrect uiGetRect(int item) {
  205. return uiItemPtr(item)->rect;
  206. }
  207. UIrect uiGetScreenRect(int item) {
  208. UIitem *pitem = uiItemPtr(item);
  209. UIrect rect = pitem->rect;
  210. rect.x = pitem->absx;
  211. rect.y = pitem->absy;
  212. return rect;
  213. }
  214. void uiSetRect(int item, int x, int y, int w, int h) {
  215. UIitem *pitem = uiItemPtr(item);
  216. pitem->rect.w = w;
  217. pitem->rect.h = h;
  218. pitem->rect.x = x;
  219. pitem->rect.y = y;
  220. }
  221. int uiFirstChild(int item) {
  222. return uiItemPtr(item)->firstkid;
  223. }
  224. int uiLastChild(int item) {
  225. return uiItemPtr(item)->lastkid;
  226. }
  227. int uiNextSibling(int item) {
  228. return uiItemPtr(item)->nextitem;
  229. }
  230. int uiParent(int item) {
  231. return uiItemPtr(item)->parent;
  232. }
  233. int uiGetKind(int item) {
  234. return uiItemPtr(item)->kind;
  235. }
  236. void *uiGetData(int item) {
  237. UIitem *pitem = uiItemPtr(item);
  238. if (pitem->data < 0) return NULL;
  239. return ui_context->data + pitem->data;
  240. }
  241. int uiGetHandle(int item) {
  242. return uiItemPtr(item)->handle;
  243. }
  244. int uiGetChildId(int item) {
  245. return uiItemPtr(item)->kidid;
  246. }
  247. int uiGetChildCount(int item) {
  248. return uiItemPtr(item)->numkids;
  249. }
  250. void uiLayoutItem(int item, int x, int y);
  251. void uiLayoutChildren(int item, int x, int y) {
  252. int kid = uiFirstChild(item);
  253. while (kid > 0) {
  254. uiLayoutItem(kid, x, y);
  255. kid = uiNextSibling(kid);
  256. }
  257. }
  258. void uiLayoutItem(int item, int x, int y) {
  259. UIrect rect = uiGetRect(item);
  260. rect.x += x;
  261. rect.y += y;
  262. switch(uiGetKind(item)) {
  263. case UI_COLUMN:
  264. case UI_ROOT: {
  265. int kid = uiFirstChild(item);
  266. while (kid > 0) {
  267. UIitem *pitem = uiItemPtr(kid);
  268. if (!pitem->rect.w || (pitem->rect.w > rect.w)) {
  269. pitem->rect.w = rect.w;
  270. }
  271. kid = uiNextSibling(kid);
  272. }
  273. uiLayoutChildren(item, rect.x, rect.y);
  274. int spacing = uiItemPtr(item)->spacing;
  275. int h = -spacing;
  276. // stack kids vertically
  277. kid = uiFirstChild(item);
  278. while (kid > 0) {
  279. UIitem *pitem = uiItemPtr(kid);
  280. h += spacing;
  281. pitem->rect.y = h;
  282. h += pitem->rect.h;
  283. kid = uiNextSibling(kid);
  284. }
  285. if (h > rect.h) {
  286. uiItemPtr(item)->rect.h = h;
  287. }
  288. } break;
  289. case UI_ROW: {
  290. uiLayoutChildren(item, rect.x, rect.y);
  291. int spacing = uiItemPtr(item)->spacing;
  292. // figure out height of row
  293. // also see how much horizontal space is used
  294. int lastkidid = uiGetChildCount(item)-1;
  295. lastkidid = (lastkidid<0)?0:lastkidid;
  296. int w = spacing*lastkidid;
  297. // how many children have no explicit width?
  298. int numdynkids = 0;
  299. int kid = uiFirstChild(item);
  300. while (kid > 0) {
  301. UIitem *pitem = uiItemPtr(kid);
  302. if (pitem->rect.h > rect.h)
  303. rect.h = pitem->rect.h;
  304. if (!pitem->rect.w)
  305. numdynkids++;
  306. else
  307. w += pitem->rect.w;
  308. kid = uiNextSibling(kid);
  309. }
  310. uiItemPtr(item)->rect.h = rect.h;
  311. int space = rect.w - w;
  312. // distribute remaining width across children
  313. int dw = numdynkids?(space / numdynkids):0;
  314. dw = (dw<0)?0:dw;
  315. // rounding error
  316. space -= numdynkids*dw;
  317. w = -spacing;
  318. // stack kids horizontally
  319. kid = uiFirstChild(item);
  320. while (kid > 0) {
  321. UIitem *pitem = uiItemPtr(kid);
  322. w += spacing;
  323. pitem->rect.x = w;
  324. if (!pitem->rect.w) {
  325. --numdynkids;
  326. // round last kid
  327. if (!numdynkids)
  328. dw += space;
  329. pitem->rect.w = dw;
  330. }
  331. w += pitem->rect.w;
  332. kid = uiNextSibling(kid);
  333. }
  334. } break;
  335. default: break;
  336. }
  337. }
  338. void uiUpdateItemState(int item, int x, int y) {
  339. UIitem *pitem = uiItemPtr(item);
  340. pitem->absx = pitem->rect.x+x;
  341. pitem->absy = pitem->rect.y+y;
  342. if (pitem->handle) {
  343. int cx = ui_context->cx - pitem->absx;
  344. int cy = ui_context->cy - pitem->absy;
  345. if ((cx>=0)
  346. && (cy>=0)
  347. && (cx<pitem->rect.w)
  348. && (cy<pitem->rect.h)) {
  349. ui_context->hot = pitem->handle;
  350. if (!ui_context->active && uiGetButton(0)) {
  351. ui_context->active = pitem->handle;
  352. }
  353. }
  354. }
  355. int kid = uiFirstChild(item);
  356. while (kid > 0) {
  357. uiUpdateItemState(kid, pitem->absx, pitem->absy);
  358. kid = uiNextSibling(kid);
  359. }
  360. }
  361. void uiLayout() {
  362. uiLayoutItem(0, 0, 0);
  363. uiUpdateItemState(0, 0, 0);
  364. if (!uiGetButton(0)) {
  365. ui_context->active = 0;
  366. }
  367. }
  368. int uiIsActive(int item) {
  369. assert(ui_context);
  370. return (ui_context->active == uiItemPtr(item)->handle)?1:0;
  371. }
  372. int uiIsHot(int item) {
  373. assert(ui_context);
  374. return (ui_context->hot == uiItemPtr(item)->handle)?1:0;
  375. }
  376. int uiGetState(int item) {
  377. return (!uiIsHot(item))?UI_COLD:(uiIsActive(item))?UI_ACTIVE:UI_HOT;
  378. }
  379. #endif // UI_IMPLEMENTATION
  380. ////////////////////////////////////////////////////////////////////////////////
  381. typedef struct UIData {
  382. int iconid;
  383. const char *label;
  384. } UIData;
  385. ////////////////////////////////////////////////////////////////////////////////
  386. void init(NVGcontext *vg) {
  387. bndSetFont(nvgCreateFont(vg, "system", "../droidsans.ttf"));
  388. bndSetIconImage(nvgCreateImage(vg, "../blender_icons16.png"));
  389. }
  390. int cornerFlags(int item) {
  391. int parent = uiParent(item);
  392. int spacing = uiGetSpacing(parent);
  393. if (spacing >= 0) return BND_CORNER_NONE;
  394. int numkids = uiGetChildCount(parent);
  395. int numid = uiGetChildId(item);
  396. if (numkids == 0) return BND_CORNER_NONE;
  397. switch(uiGetKind(parent)) {
  398. case UI_COLUMN: {
  399. if (!numid) return BND_CORNER_DOWN;
  400. else if (numid == numkids-1) return BND_CORNER_TOP;
  401. else return BND_CORNER_ALL;
  402. } break;
  403. case UI_ROW: {
  404. if (!numid) return BND_CORNER_RIGHT;
  405. else if (numid == numkids-1) return BND_CORNER_LEFT;
  406. else return BND_CORNER_ALL;
  407. } break;
  408. default: break;
  409. }
  410. return BND_CORNER_NONE;
  411. }
  412. void drawUI(NVGcontext *vg, int item, int x, int y) {
  413. UIData *data = (UIData *)uiGetData(item);
  414. UIrect rect = uiGetRect(item);
  415. rect.x += x;
  416. rect.y += y;
  417. switch(uiGetKind(item)) {
  418. case UI_BUTTON: {
  419. assert(data);
  420. bndToolButton(vg,rect.x,rect.y,rect.w,rect.h,
  421. cornerFlags(item),(BNDwidgetState)uiGetState(item),
  422. data->iconid,data->label);
  423. } break;
  424. default: break;
  425. }
  426. int kid = uiFirstChild(item);
  427. while (kid > 0) {
  428. drawUI(vg, kid, rect.x, rect.y);
  429. kid = uiNextSibling(kid);
  430. }
  431. }
  432. void draw(NVGcontext *vg, float w, float h) {
  433. bndBackground(vg, 0, 0, w, h);
  434. int x = 10;
  435. int y = 10;
  436. bndToolButton(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT,
  437. BND_ICONID(6,3),"Default");
  438. y += 25;
  439. bndToolButton(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER,
  440. BND_ICONID(6,3),"Hovered");
  441. y += 25;
  442. bndToolButton(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE,
  443. BND_ICONID(6,3),"Active");
  444. y += 40;
  445. bndRadioButton(vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT,
  446. -1,"Default");
  447. y += 25;
  448. bndRadioButton(vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER,
  449. -1,"Hovered");
  450. y += 25;
  451. bndRadioButton(vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE,
  452. -1,"Active");
  453. y += 25;
  454. bndLabel(vg,x,y,120,BND_WIDGET_HEIGHT,-1,"Label:");
  455. y += BND_WIDGET_HEIGHT;
  456. bndChoiceButton(vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT,
  457. -1, "Default");
  458. y += 25;
  459. bndChoiceButton(vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER,
  460. -1, "Hovered");
  461. y += 25;
  462. bndChoiceButton(vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE,
  463. -1, "Active");
  464. y += 25;
  465. int ry = y;
  466. int rx = x;
  467. y = 10;
  468. x += 130;
  469. bndOptionButton(vg,x,y,120,BND_WIDGET_HEIGHT,BND_DEFAULT,"Default");
  470. y += 25;
  471. bndOptionButton(vg,x,y,120,BND_WIDGET_HEIGHT,BND_HOVER,"Hovered");
  472. y += 25;
  473. bndOptionButton(vg,x,y,120,BND_WIDGET_HEIGHT,BND_ACTIVE,"Active");
  474. y += 40;
  475. bndNumberField(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_DOWN,BND_DEFAULT,
  476. "Top","100");
  477. y += BND_WIDGET_HEIGHT-2;
  478. bndNumberField(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_ALL,BND_DEFAULT,
  479. "Center","100");
  480. y += BND_WIDGET_HEIGHT-2;
  481. bndNumberField(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_TOP,BND_DEFAULT,
  482. "Bottom","100");
  483. int mx = x-30;
  484. int my = y-12;
  485. int mw = 120;
  486. bndMenuBackground(vg,mx,my,mw,120,BND_CORNER_TOP);
  487. bndMenuLabel(vg,mx,my,mw,BND_WIDGET_HEIGHT,-1,"Menu Title");
  488. my += BND_WIDGET_HEIGHT-2;
  489. bndMenuItem(vg,mx,my,mw,BND_WIDGET_HEIGHT,BND_DEFAULT,
  490. BND_ICONID(17,3),"Default");
  491. my += BND_WIDGET_HEIGHT-2;
  492. bndMenuItem(vg,mx,my,mw,BND_WIDGET_HEIGHT,BND_HOVER,
  493. BND_ICONID(18,3),"Hovered");
  494. my += BND_WIDGET_HEIGHT-2;
  495. bndMenuItem(vg,mx,my,mw,BND_WIDGET_HEIGHT,BND_ACTIVE,
  496. BND_ICONID(19,3),"Active");
  497. y = 10;
  498. x += 130;
  499. int ox = x;
  500. bndNumberField(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT,
  501. "Default","100");
  502. y += 25;
  503. bndNumberField(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER,
  504. "Hovered","100");
  505. y += 25;
  506. bndNumberField(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE,
  507. "Active","100");
  508. y += 40;
  509. bndRadioButton(vg,x,y,60,BND_WIDGET_HEIGHT,BND_CORNER_RIGHT,BND_DEFAULT,
  510. -1,"One");
  511. x += 60-1;
  512. bndRadioButton(vg,x,y,60,BND_WIDGET_HEIGHT,BND_CORNER_ALL,BND_DEFAULT,
  513. -1,"Two");
  514. x += 60-1;
  515. bndRadioButton(vg,x,y,60,BND_WIDGET_HEIGHT,BND_CORNER_ALL,BND_DEFAULT,
  516. -1,"Three");
  517. x += 60-1;
  518. bndRadioButton(vg,x,y,60,BND_WIDGET_HEIGHT,BND_CORNER_LEFT,BND_ACTIVE,
  519. -1,"Butts");
  520. x = ox;
  521. y += 40;
  522. float progress_value = fmodf(glfwGetTime()/10.0,1.0);
  523. char progress_label[32];
  524. sprintf(progress_label, "%d%%", int(progress_value*100+0.5f));
  525. bndSlider(vg,x,y,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT,
  526. progress_value,"Default",progress_label);
  527. y += 25;
  528. bndSlider(vg,x,y,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER,
  529. progress_value,"Hovered",progress_label);
  530. y += 25;
  531. bndSlider(vg,x,y,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE,
  532. progress_value,"Active",progress_label);
  533. int rw = x+240-rx;
  534. float s_offset = sinf(glfwGetTime()/2.0)*0.5+0.5;
  535. float s_size = cosf(glfwGetTime()/3.11)*0.5+0.5;
  536. bndScrollBar(vg,rx,ry,rw,BND_SCROLLBAR_HEIGHT,BND_DEFAULT,s_offset,s_size);
  537. ry += 20;
  538. bndScrollBar(vg,rx,ry,rw,BND_SCROLLBAR_HEIGHT,BND_HOVER,s_offset,s_size);
  539. ry += 20;
  540. bndScrollBar(vg,rx,ry,rw,BND_SCROLLBAR_HEIGHT,BND_ACTIVE,s_offset,s_size);
  541. const char edit_text[] = "The quick brown fox";
  542. int textlen = strlen(edit_text)+1;
  543. int t = int(glfwGetTime()*2);
  544. int idx1 = (t/textlen)%textlen;
  545. int idx2 = idx1 + (t%(textlen-idx1));
  546. ry += 25;
  547. bndTextField(vg,rx,ry,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT,
  548. -1, edit_text, idx1, idx2);
  549. ry += 25;
  550. bndTextField(vg,rx,ry,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER,
  551. -1, edit_text, idx1, idx2);
  552. ry += 25;
  553. bndTextField(vg,rx,ry,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE,
  554. -1, edit_text, idx1, idx2);
  555. rx += rw + 20;
  556. ry = 10;
  557. bndScrollBar(vg,rx,ry,BND_SCROLLBAR_WIDTH,240,BND_DEFAULT,s_offset,s_size);
  558. rx += 20;
  559. bndScrollBar(vg,rx,ry,BND_SCROLLBAR_WIDTH,240,BND_HOVER,s_offset,s_size);
  560. rx += 20;
  561. bndScrollBar(vg,rx,ry,BND_SCROLLBAR_WIDTH,240,BND_ACTIVE,s_offset,s_size);
  562. x = ox;
  563. y += 40;
  564. bndToolButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_RIGHT,
  565. BND_DEFAULT,BND_ICONID(0,10),NULL);
  566. x += BND_TOOL_WIDTH-1;
  567. bndToolButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  568. BND_DEFAULT,BND_ICONID(1,10),NULL);
  569. x += BND_TOOL_WIDTH-1;
  570. bndToolButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  571. BND_DEFAULT,BND_ICONID(2,10),NULL);
  572. x += BND_TOOL_WIDTH-1;
  573. bndToolButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  574. BND_DEFAULT,BND_ICONID(3,10),NULL);
  575. x += BND_TOOL_WIDTH-1;
  576. bndToolButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  577. BND_DEFAULT,BND_ICONID(4,10),NULL);
  578. x += BND_TOOL_WIDTH-1;
  579. bndToolButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_LEFT,
  580. BND_DEFAULT,BND_ICONID(5,10),NULL);
  581. x += BND_TOOL_WIDTH-1;
  582. x += 5;
  583. bndRadioButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_RIGHT,
  584. BND_DEFAULT,BND_ICONID(0,11),NULL);
  585. x += BND_TOOL_WIDTH-1;
  586. bndRadioButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  587. BND_DEFAULT,BND_ICONID(1,11),NULL);
  588. x += BND_TOOL_WIDTH-1;
  589. bndRadioButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  590. BND_DEFAULT,BND_ICONID(2,11),NULL);
  591. x += BND_TOOL_WIDTH-1;
  592. bndRadioButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  593. BND_DEFAULT,BND_ICONID(3,11),NULL);
  594. x += BND_TOOL_WIDTH-1;
  595. bndRadioButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  596. BND_ACTIVE,BND_ICONID(4,11),NULL);
  597. x += BND_TOOL_WIDTH-1;
  598. bndRadioButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_LEFT,
  599. BND_DEFAULT,BND_ICONID(5,11),NULL);
  600. uiClear();
  601. uiSetRect(0,600,10,250,400);
  602. int col = uiColumn(0,1);
  603. UIData data = { BND_ICONID(6,3), "Item 1" };
  604. uiItem(col, 1, UI_BUTTON, 0, BND_WIDGET_HEIGHT, &data, sizeof(data));
  605. data.label = "Item 2";
  606. uiItem(col, 2, UI_BUTTON, 0, BND_WIDGET_HEIGHT, &data, sizeof(data));
  607. { // nested row
  608. int row = uiRow(col,-1);
  609. data.label = "Item 3.0";
  610. uiItem(row, 3, UI_BUTTON, 0, BND_WIDGET_HEIGHT, &data, sizeof(data));
  611. data.label = NULL;
  612. data.iconid = BND_ICONID(0,10);
  613. uiItem(row, 4, UI_BUTTON, BND_TOOL_WIDTH, BND_WIDGET_HEIGHT, &data, sizeof(data));
  614. data.label = NULL;
  615. data.iconid = BND_ICONID(1,10);
  616. uiItem(row, 5, UI_BUTTON, BND_TOOL_WIDTH, BND_WIDGET_HEIGHT, &data, sizeof(data));
  617. data.iconid = BND_ICONID(6,3);
  618. data.label = "Item 3.3";
  619. uiItem(row, 6, UI_BUTTON, 0, BND_WIDGET_HEIGHT, &data, sizeof(data));
  620. }
  621. { // nested column
  622. int col2 = uiColumn(col,-2);
  623. data.label = "Item 4.0";
  624. uiItem(col2, 7, UI_BUTTON, 0, BND_WIDGET_HEIGHT, &data, sizeof(data));
  625. data.label = "Item 4.1";
  626. uiItem(col2, 8, UI_BUTTON, 0, BND_WIDGET_HEIGHT, &data, sizeof(data));
  627. }
  628. data.label = "Item 5";
  629. uiItem(col, 9, UI_BUTTON, 0, BND_WIDGET_HEIGHT, &data, sizeof(data));
  630. uiLayout();
  631. drawUI(vg, 0, 0, 0);
  632. }
  633. ////////////////////////////////////////////////////////////////////////////////
  634. void errorcb(int error, const char* desc)
  635. {
  636. printf("GLFW error %d: %s\n", error, desc);
  637. }
  638. static void mousebutton(GLFWwindow *window, int button, int action, int mods) {
  639. NVG_NOTUSED(window);
  640. NVG_NOTUSED(mods);
  641. uiSetButton(button, (action==GLFW_PRESS)?1:0);
  642. }
  643. static void cursorpos(GLFWwindow *window, double x, double y) {
  644. NVG_NOTUSED(window);
  645. uiSetCursor((int)x,(int)y);
  646. }
  647. static void key(GLFWwindow* window, int key, int scancode, int action, int mods)
  648. {
  649. NVG_NOTUSED(scancode);
  650. NVG_NOTUSED(mods);
  651. if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
  652. glfwSetWindowShouldClose(window, GL_TRUE);
  653. }
  654. int main()
  655. {
  656. GLFWwindow* window;
  657. struct NVGcontext* vg = NULL;
  658. UIcontext *uictx;
  659. uictx = uiCreateContext();
  660. uiMakeCurrent(uictx);
  661. if (!glfwInit()) {
  662. printf("Failed to init GLFW.");
  663. return -1;
  664. }
  665. glfwSetErrorCallback(errorcb);
  666. #ifndef _WIN32 // don't require this on win32, and works with more cards
  667. glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
  668. glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
  669. glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
  670. glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
  671. #endif
  672. glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, 1);
  673. window = glfwCreateWindow(1000, 600, "Blendish Demo", NULL, NULL);
  674. if (!window) {
  675. glfwTerminate();
  676. return -1;
  677. }
  678. glfwSetKeyCallback(window, key);
  679. glfwSetCursorPosCallback(window, cursorpos);
  680. glfwSetMouseButtonCallback(window, mousebutton);
  681. glfwMakeContextCurrent(window);
  682. #ifdef NANOVG_GLEW
  683. glewExperimental = GL_TRUE;
  684. if(glewInit() != GLEW_OK) {
  685. printf("Could not init glew.\n");
  686. return -1;
  687. }
  688. // GLEW generates GL error because it calls glGetString(GL_EXTENSIONS), we'll consume it here.
  689. glGetError();
  690. #endif
  691. vg = nvgCreateGL3(NVG_ANTIALIAS | NVG_STENCIL_STROKES);
  692. if (vg == NULL) {
  693. printf("Could not init nanovg.\n");
  694. return -1;
  695. }
  696. init(vg);
  697. glfwSwapInterval(0);
  698. glfwSetTime(0);
  699. while (!glfwWindowShouldClose(window))
  700. {
  701. double mx, my;
  702. int winWidth, winHeight;
  703. int fbWidth, fbHeight;
  704. float pxRatio;
  705. glfwGetCursorPos(window, &mx, &my);
  706. glfwGetWindowSize(window, &winWidth, &winHeight);
  707. glfwGetFramebufferSize(window, &fbWidth, &fbHeight);
  708. // Calculate pixel ration for hi-dpi devices.
  709. pxRatio = (float)fbWidth / (float)winWidth;
  710. // Update and render
  711. glViewport(0, 0, fbWidth, fbHeight);
  712. glClearColor(0,0,0,1);
  713. glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
  714. nvgBeginFrame(vg, winWidth, winHeight, pxRatio);
  715. draw(vg, winWidth, winHeight);
  716. nvgEndFrame(vg);
  717. glfwSwapBuffers(window);
  718. glfwPollEvents();
  719. }
  720. uiDestroyContext(uictx);
  721. nvgDeleteGL3(vg);
  722. glfwTerminate();
  723. return 0;
  724. }