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.

874 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. }
  304. }
  305. int textbox(char *text, int maxsize) {
  306. int item = uiItem();
  307. uiSetSize(item, 0, BND_WIDGET_HEIGHT);
  308. uiSetHandler(item, textboxhandler,
  309. UI_BUTTON0_DOWN | UI_KEY_DOWN | UI_CHAR);
  310. // store some custom data with the button that we use for styling
  311. // and logic, e.g. the pointer to the data we want to alter.
  312. UITextData *data = (UITextData *)uiAllocHandle(item, sizeof(UITextData));
  313. data->head.subtype = ST_TEXT;
  314. data->text = text;
  315. data->maxsize = maxsize;
  316. return item;
  317. }
  318. // simple logic for a radio button
  319. void radiohandler(int item, UIevent event) {
  320. UIRadioData *data = (UIRadioData *)uiGetHandle(item);
  321. *data->value = uiGetChildId(item);
  322. }
  323. int radio(int iconid, const char *label, int *value) {
  324. int item = uiItem();
  325. uiSetSize(item, label?0:BND_TOOL_WIDTH, BND_WIDGET_HEIGHT);
  326. UIRadioData *data = (UIRadioData *)uiAllocHandle(item, sizeof(UIRadioData));
  327. data->head.subtype = ST_RADIO;
  328. data->iconid = iconid;
  329. data->label = label;
  330. data->value = value;
  331. uiSetHandler(item, radiohandler, UI_BUTTON0_DOWN);
  332. return item;
  333. }
  334. int panel() {
  335. int item = uiItem();
  336. UIData *data = (UIData *)uiAllocHandle(item, sizeof(UIData));
  337. data->subtype = ST_PANEL;
  338. return item;
  339. }
  340. int column_append(int parent, int item) {
  341. int last = uiLastChild(parent);
  342. uiAppend(parent, item);
  343. // mark the new item as positioned under the previous item
  344. uiSetBelow(item, last);
  345. // fill parent horizontally, anchor to previous item vertically
  346. uiSetLayout(item, UI_HFILL|UI_TOP);
  347. // if not the first item, add a margin of 1
  348. uiSetMargins(item, 0, 1, 0, 0);
  349. return item;
  350. }
  351. int column() {
  352. int item = uiItem();
  353. return item;
  354. }
  355. int vgroup_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. return item;
  363. }
  364. int vgroup() {
  365. int item = uiItem();
  366. return item;
  367. }
  368. int hgroup_append(int parent, int item) {
  369. int last = uiLastChild(parent);
  370. uiAppend(parent, item);
  371. uiSetRightTo(item, last);
  372. if (last > 0)
  373. uiSetLeftTo(last, item);
  374. uiSetLayout(item, UI_LEFT|UI_RIGHT);
  375. return item;
  376. }
  377. int hgroup() {
  378. int item = uiItem();
  379. return item;
  380. }
  381. int row_append(int parent, int item) {
  382. int last = uiLastChild(parent);
  383. uiAppend(parent, item);
  384. uiSetRightTo(item, last);
  385. if (last > 0)
  386. uiSetLeftTo(last, item);
  387. uiSetLayout(item, UI_LEFT|UI_RIGHT);
  388. uiSetMargins(item, (last < 0)?0:8, 0, 0, 0);
  389. return item;
  390. }
  391. int row() {
  392. int item = uiItem();
  393. return item;
  394. }
  395. void draw_noodles(NVGcontext *vg, int x, int y) {
  396. int w = 200;
  397. int s = 70;
  398. bndNodeBackground(vg, x+w, y-50, 100, 200, BND_DEFAULT, BND_ICONID(6,3),
  399. "Default", nvgRGBf(0.392f,0.392f,0.392f));
  400. bndNodeBackground(vg, x+w+120, y-50, 100, 200, BND_HOVER, BND_ICONID(6,3),
  401. "Hover", nvgRGBf(0.392f,0.392f,0.392f));
  402. bndNodeBackground(vg, x+w+240, y-50, 100, 200, BND_ACTIVE, BND_ICONID(6,3),
  403. "Active", nvgRGBf(0.392f,0.392f,0.392f));
  404. for (int i = 0; i < 9; ++i) {
  405. int a = i%3;
  406. int b = i/3;
  407. bndNodeWire(vg, x, y+s*a, x+w, y+s*b, (BNDwidgetState)a, (BNDwidgetState)b);
  408. }
  409. bndNodePort(vg, x, y, BND_DEFAULT, nvgRGBf(0.5f, 0.5f, 0.5f));
  410. bndNodePort(vg, x+w, y, BND_DEFAULT, nvgRGBf(0.5f, 0.5f, 0.5f));
  411. bndNodePort(vg, x, y+s, BND_HOVER, nvgRGBf(0.5f, 0.5f, 0.5f));
  412. bndNodePort(vg, x+w, y+s, BND_HOVER, nvgRGBf(0.5f, 0.5f, 0.5f));
  413. bndNodePort(vg, x, y+2*s, BND_ACTIVE, nvgRGBf(0.5f, 0.5f, 0.5f));
  414. bndNodePort(vg, x+w, y+2*s, BND_ACTIVE, nvgRGBf(0.5f, 0.5f, 0.5f));
  415. }
  416. static void roothandler(int parent, UIevent event) {
  417. switch(event) {
  418. default: break;
  419. case UI_SCROLL: {
  420. UIvec2 pos = uiGetScroll();
  421. printf("scroll! %d %d\n", pos.x, pos.y);
  422. } break;
  423. case UI_BUTTON0_DOWN: {
  424. printf("%d clicks\n", uiGetClicks());
  425. } break;
  426. }
  427. }
  428. void draw(NVGcontext *vg, float w, float h) {
  429. bndBackground(vg, 0, 0, w, h);
  430. bndSplitterWidgets(vg, 0, 0, w, h);
  431. int x = 10;
  432. int y = 10;
  433. bndToolButton(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT,
  434. BND_ICONID(6,3),"Default");
  435. y += 25;
  436. bndToolButton(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER,
  437. BND_ICONID(6,3),"Hovered");
  438. y += 25;
  439. bndToolButton(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE,
  440. BND_ICONID(6,3),"Active");
  441. y += 40;
  442. bndRadioButton(vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT,
  443. -1,"Default");
  444. y += 25;
  445. bndRadioButton(vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER,
  446. -1,"Hovered");
  447. y += 25;
  448. bndRadioButton(vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE,
  449. -1,"Active");
  450. y += 25;
  451. bndLabel(vg,x,y,120,BND_WIDGET_HEIGHT,-1,"Label:");
  452. y += BND_WIDGET_HEIGHT;
  453. bndChoiceButton(vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT,
  454. -1, "Default");
  455. y += 25;
  456. bndChoiceButton(vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER,
  457. -1, "Hovered");
  458. y += 25;
  459. bndChoiceButton(vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE,
  460. -1, "Active");
  461. y += 25;
  462. int ry = y;
  463. int rx = x;
  464. y = 10;
  465. x += 130;
  466. bndOptionButton(vg,x,y,120,BND_WIDGET_HEIGHT,BND_DEFAULT,"Default");
  467. y += 25;
  468. bndOptionButton(vg,x,y,120,BND_WIDGET_HEIGHT,BND_HOVER,"Hovered");
  469. y += 25;
  470. bndOptionButton(vg,x,y,120,BND_WIDGET_HEIGHT,BND_ACTIVE,"Active");
  471. y += 40;
  472. bndNumberField(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_DOWN,BND_DEFAULT,
  473. "Top","100");
  474. y += BND_WIDGET_HEIGHT-2;
  475. bndNumberField(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_ALL,BND_DEFAULT,
  476. "Center","100");
  477. y += BND_WIDGET_HEIGHT-2;
  478. bndNumberField(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_TOP,BND_DEFAULT,
  479. "Bottom","100");
  480. int mx = x-30;
  481. int my = y-12;
  482. int mw = 120;
  483. bndMenuBackground(vg,mx,my,mw,120,BND_CORNER_TOP);
  484. bndMenuLabel(vg,mx,my,mw,BND_WIDGET_HEIGHT,-1,"Menu Title");
  485. my += BND_WIDGET_HEIGHT-2;
  486. bndMenuItem(vg,mx,my,mw,BND_WIDGET_HEIGHT,BND_DEFAULT,
  487. BND_ICONID(17,3),"Default");
  488. my += BND_WIDGET_HEIGHT-2;
  489. bndMenuItem(vg,mx,my,mw,BND_WIDGET_HEIGHT,BND_HOVER,
  490. BND_ICONID(18,3),"Hovered");
  491. my += BND_WIDGET_HEIGHT-2;
  492. bndMenuItem(vg,mx,my,mw,BND_WIDGET_HEIGHT,BND_ACTIVE,
  493. BND_ICONID(19,3),"Active");
  494. y = 10;
  495. x += 130;
  496. int ox = x;
  497. bndNumberField(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT,
  498. "Default","100");
  499. y += 25;
  500. bndNumberField(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER,
  501. "Hovered","100");
  502. y += 25;
  503. bndNumberField(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE,
  504. "Active","100");
  505. y += 40;
  506. bndRadioButton(vg,x,y,60,BND_WIDGET_HEIGHT,BND_CORNER_RIGHT,BND_DEFAULT,
  507. -1,"One");
  508. x += 60-1;
  509. bndRadioButton(vg,x,y,60,BND_WIDGET_HEIGHT,BND_CORNER_ALL,BND_DEFAULT,
  510. -1,"Two");
  511. x += 60-1;
  512. bndRadioButton(vg,x,y,60,BND_WIDGET_HEIGHT,BND_CORNER_ALL,BND_DEFAULT,
  513. -1,"Three");
  514. x += 60-1;
  515. bndRadioButton(vg,x,y,60,BND_WIDGET_HEIGHT,BND_CORNER_LEFT,BND_ACTIVE,
  516. -1,"Butts");
  517. x = ox;
  518. y += 40;
  519. float progress_value = fmodf(glfwGetTime()/10.0,1.0);
  520. char progress_label[32];
  521. sprintf(progress_label, "%d%%", int(progress_value*100+0.5f));
  522. bndSlider(vg,x,y,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT,
  523. progress_value,"Default",progress_label);
  524. y += 25;
  525. bndSlider(vg,x,y,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER,
  526. progress_value,"Hovered",progress_label);
  527. y += 25;
  528. bndSlider(vg,x,y,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE,
  529. progress_value,"Active",progress_label);
  530. int rw = x+240-rx;
  531. float s_offset = sinf(glfwGetTime()/2.0)*0.5+0.5;
  532. float s_size = cosf(glfwGetTime()/3.11)*0.5+0.5;
  533. bndScrollBar(vg,rx,ry,rw,BND_SCROLLBAR_HEIGHT,BND_DEFAULT,s_offset,s_size);
  534. ry += 20;
  535. bndScrollBar(vg,rx,ry,rw,BND_SCROLLBAR_HEIGHT,BND_HOVER,s_offset,s_size);
  536. ry += 20;
  537. bndScrollBar(vg,rx,ry,rw,BND_SCROLLBAR_HEIGHT,BND_ACTIVE,s_offset,s_size);
  538. const char edit_text[] = "The quick brown fox";
  539. int textlen = strlen(edit_text)+1;
  540. int t = int(glfwGetTime()*2);
  541. int idx1 = (t/textlen)%textlen;
  542. int idx2 = idx1 + (t%(textlen-idx1));
  543. ry += 25;
  544. bndTextField(vg,rx,ry,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT,
  545. -1, edit_text, idx1, idx2);
  546. ry += 25;
  547. bndTextField(vg,rx,ry,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER,
  548. -1, edit_text, idx1, idx2);
  549. ry += 25;
  550. bndTextField(vg,rx,ry,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE,
  551. -1, edit_text, idx1, idx2);
  552. draw_noodles(vg, 20, ry+50);
  553. rx += rw + 20;
  554. ry = 10;
  555. bndScrollBar(vg,rx,ry,BND_SCROLLBAR_WIDTH,240,BND_DEFAULT,s_offset,s_size);
  556. rx += 20;
  557. bndScrollBar(vg,rx,ry,BND_SCROLLBAR_WIDTH,240,BND_HOVER,s_offset,s_size);
  558. rx += 20;
  559. bndScrollBar(vg,rx,ry,BND_SCROLLBAR_WIDTH,240,BND_ACTIVE,s_offset,s_size);
  560. x = ox;
  561. y += 40;
  562. bndToolButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_RIGHT,
  563. BND_DEFAULT,BND_ICONID(0,10),NULL);
  564. x += BND_TOOL_WIDTH-1;
  565. bndToolButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  566. BND_DEFAULT,BND_ICONID(1,10),NULL);
  567. x += BND_TOOL_WIDTH-1;
  568. bndToolButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  569. BND_DEFAULT,BND_ICONID(2,10),NULL);
  570. x += BND_TOOL_WIDTH-1;
  571. bndToolButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  572. BND_DEFAULT,BND_ICONID(3,10),NULL);
  573. x += BND_TOOL_WIDTH-1;
  574. bndToolButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  575. BND_DEFAULT,BND_ICONID(4,10),NULL);
  576. x += BND_TOOL_WIDTH-1;
  577. bndToolButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_LEFT,
  578. BND_DEFAULT,BND_ICONID(5,10),NULL);
  579. x += BND_TOOL_WIDTH-1;
  580. x += 5;
  581. bndRadioButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_RIGHT,
  582. BND_DEFAULT,BND_ICONID(0,11),NULL);
  583. x += BND_TOOL_WIDTH-1;
  584. bndRadioButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  585. BND_DEFAULT,BND_ICONID(1,11),NULL);
  586. x += BND_TOOL_WIDTH-1;
  587. bndRadioButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  588. BND_DEFAULT,BND_ICONID(2,11),NULL);
  589. x += BND_TOOL_WIDTH-1;
  590. bndRadioButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  591. BND_DEFAULT,BND_ICONID(3,11),NULL);
  592. x += BND_TOOL_WIDTH-1;
  593. bndRadioButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  594. BND_ACTIVE,BND_ICONID(4,11),NULL);
  595. x += BND_TOOL_WIDTH-1;
  596. bndRadioButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_LEFT,
  597. BND_DEFAULT,BND_ICONID(5,11),NULL);
  598. // some OUI stuff
  599. // some persistent variables for demonstration
  600. static int enum1 = 0;
  601. static float progress1 = 0.25f;
  602. static float progress2 = 0.75f;
  603. static int option1 = 1;
  604. static int option2 = 0;
  605. static int option3 = 0;
  606. uiClear();
  607. int root = panel();
  608. // position root element
  609. uiSetLayout(0,UI_LEFT|UI_TOP);
  610. uiSetMargins(0,600,10,0,0);
  611. uiSetSize(0,250,400);
  612. uiSetHandler(root, roothandler, UI_SCROLL|UI_BUTTON0_DOWN);
  613. int col = column();
  614. uiAppend(root, col);
  615. uiSetMargins(col, 10, 10, 10, 10);
  616. uiSetLayout(col, UI_TOP|UI_HFILL);
  617. column_append(col, button(BND_ICONID(6,3), "Item 1", demohandler));
  618. column_append(col, button(BND_ICONID(6,3), "Item 2", demohandler));
  619. {
  620. int h = column_append(col, hgroup());
  621. hgroup_append(h, radio(BND_ICONID(6,3), "Item 3.0", &enum1));
  622. hgroup_append(h, radio(BND_ICONID(0,10), NULL, &enum1));
  623. hgroup_append(h, radio(BND_ICONID(1,10), NULL, &enum1));
  624. hgroup_append(h, radio(BND_ICONID(6,3), "Item 3.3", &enum1));
  625. }
  626. {
  627. int rows = column_append(col, row());
  628. int coll = row_append(rows, vgroup());
  629. vgroup_append(coll, label(-1, "Items 4.0:"));
  630. coll = vgroup_append(coll, vgroup());
  631. vgroup_append(coll, button(BND_ICONID(6,3), "Item 4.0.0", demohandler));
  632. vgroup_append(coll, button(BND_ICONID(6,3), "Item 4.0.1", demohandler));
  633. int colr = row_append(rows, vgroup());
  634. uiSetFrozen(colr, option1);
  635. vgroup_append(colr, label(-1, "Items 4.1:"));
  636. colr = vgroup_append(colr, vgroup());
  637. vgroup_append(colr, slider("Item 4.1.0", &progress1));
  638. vgroup_append(colr, slider("Item 4.1.1", &progress2));
  639. }
  640. column_append(col, button(BND_ICONID(6,3), "Item 5", NULL));
  641. static char textbuffer[1024] = "The quick brown fox.";
  642. column_append(col, textbox(textbuffer, 1024));
  643. column_append(col, check("Frozen", &option1));
  644. column_append(col, check("Item 7", &option2));
  645. column_append(col, check("Item 8", &option3));
  646. uiLayout();
  647. drawUI(vg, 0, 0, 0);
  648. UIvec2 cursor = uiGetCursor();
  649. cursor.x -= w/2;
  650. cursor.y -= h/2;
  651. if (abs(cursor.x) > (w/4)) {
  652. bndJoinAreaOverlay(vg, 0, 0, w, h, 0, (cursor.x > 0));
  653. } else if (abs(cursor.y) > (h/4)) {
  654. bndJoinAreaOverlay(vg, 0, 0, w, h, 1, (cursor.y > 0));
  655. }
  656. uiProcess((int)(glfwGetTime()*1000.0));
  657. }
  658. ////////////////////////////////////////////////////////////////////////////////
  659. void errorcb(int error, const char* desc)
  660. {
  661. printf("GLFW error %d: %s\n", error, desc);
  662. }
  663. static void mousebutton(GLFWwindow *window, int button, int action, int mods) {
  664. NVG_NOTUSED(window);
  665. NVG_NOTUSED(mods);
  666. switch(button) {
  667. case 1: button = 2; break;
  668. case 2: button = 1; break;
  669. }
  670. uiSetButton(button, (action==GLFW_PRESS)?1:0);
  671. }
  672. static void cursorpos(GLFWwindow *window, double x, double y) {
  673. NVG_NOTUSED(window);
  674. uiSetCursor((int)x,(int)y);
  675. }
  676. static void scrollevent(GLFWwindow *window, double x, double y) {
  677. NVG_NOTUSED(window);
  678. uiSetScroll((int)x, (int)y);
  679. }
  680. static void charevent(GLFWwindow *window, unsigned int value) {
  681. NVG_NOTUSED(window);
  682. uiSetChar(value);
  683. }
  684. static void key(GLFWwindow* window, int key, int scancode, int action, int mods)
  685. {
  686. NVG_NOTUSED(scancode);
  687. NVG_NOTUSED(mods);
  688. if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
  689. glfwSetWindowShouldClose(window, GL_TRUE);
  690. uiSetKey(key, mods, action);
  691. }
  692. int main()
  693. {
  694. GLFWwindow* window;
  695. UIcontext *uictx;
  696. uictx = uiCreateContext();
  697. uiMakeCurrent(uictx);
  698. if (!glfwInit()) {
  699. printf("Failed to init GLFW.");
  700. return -1;
  701. }
  702. glfwSetErrorCallback(errorcb);
  703. #ifndef _WIN32 // don't require this on win32, and works with more cards
  704. glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
  705. glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
  706. glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
  707. glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
  708. #endif
  709. glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, 1);
  710. window = glfwCreateWindow(1000, 600, "OUI Blendish Demo", NULL, NULL);
  711. if (!window) {
  712. glfwTerminate();
  713. return -1;
  714. }
  715. glfwSetKeyCallback(window, key);
  716. glfwSetCharCallback(window, charevent);
  717. glfwSetCursorPosCallback(window, cursorpos);
  718. glfwSetMouseButtonCallback(window, mousebutton);
  719. glfwSetScrollCallback(window, scrollevent);
  720. glfwMakeContextCurrent(window);
  721. #ifdef NANOVG_GLEW
  722. glewExperimental = GL_TRUE;
  723. if(glewInit() != GLEW_OK) {
  724. printf("Could not init glew.\n");
  725. return -1;
  726. }
  727. // GLEW generates GL error because it calls glGetString(GL_EXTENSIONS), we'll consume it here.
  728. glGetError();
  729. #endif
  730. _vg = nvgCreateGL3(NVG_ANTIALIAS | NVG_STENCIL_STROKES);
  731. if (_vg == NULL) {
  732. printf("Could not init nanovg.\n");
  733. return -1;
  734. }
  735. init(_vg);
  736. printf("%lu %lu\n", sizeof(UIitem), sizeof(UIitem2));
  737. glfwSwapInterval(0);
  738. glfwSetTime(0);
  739. while (!glfwWindowShouldClose(window))
  740. {
  741. double mx, my;
  742. int winWidth, winHeight;
  743. int fbWidth, fbHeight;
  744. float pxRatio;
  745. glfwGetCursorPos(window, &mx, &my);
  746. glfwGetWindowSize(window, &winWidth, &winHeight);
  747. glfwGetFramebufferSize(window, &fbWidth, &fbHeight);
  748. // Calculate pixel ration for hi-dpi devices.
  749. pxRatio = (float)fbWidth / (float)winWidth;
  750. // Update and render
  751. glViewport(0, 0, fbWidth, fbHeight);
  752. glClearColor(0,0,0,1);
  753. glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
  754. nvgBeginFrame(_vg, winWidth, winHeight, pxRatio);
  755. draw(_vg, winWidth, winHeight);
  756. nvgEndFrame(_vg);
  757. glfwSwapBuffers(window);
  758. glfwPollEvents();
  759. }
  760. uiDestroyContext(uictx);
  761. nvgDeleteGL3(_vg);
  762. glfwTerminate();
  763. return 0;
  764. }