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.

893 lines
28KB

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