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.

851 lines
26KB

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