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.

879 lines
27KB

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