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.

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