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.

484 lines
15KB

  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 UI_IMPLEMENTATION
  17. #include "oui.h"
  18. ////////////////////////////////////////////////////////////////////////////////
  19. typedef enum {
  20. // default
  21. ST_DEFAULT = 0,
  22. // radio button
  23. ST_RADIO = 1,
  24. } SubType;
  25. typedef struct {
  26. int size;
  27. int subtype;
  28. int iconid;
  29. const char *label;
  30. } UIData;
  31. ////////////////////////////////////////////////////////////////////////////////
  32. void init(NVGcontext *vg) {
  33. bndSetFont(nvgCreateFont(vg, "system", "../droidsans.ttf"));
  34. bndSetIconImage(nvgCreateImage(vg, "../blender_icons16.png"));
  35. }
  36. int cornerFlags(int item) {
  37. int parent = uiParent(item);
  38. int spacing = uiGetSpacing(parent);
  39. if (spacing >= 0) return BND_CORNER_NONE;
  40. int numkids = uiGetChildCount(parent);
  41. int numid = uiGetChildId(item);
  42. if (numkids == 0) return BND_CORNER_NONE;
  43. switch(uiGetKind(parent)) {
  44. case UI_COLUMN: {
  45. if (!numid) return BND_CORNER_DOWN;
  46. else if (numid == numkids-1) return BND_CORNER_TOP;
  47. else return BND_CORNER_ALL;
  48. } break;
  49. case UI_ROW: {
  50. if (!numid) return BND_CORNER_RIGHT;
  51. else if (numid == numkids-1) return BND_CORNER_LEFT;
  52. else return BND_CORNER_ALL;
  53. } break;
  54. default: break;
  55. }
  56. return BND_CORNER_NONE;
  57. }
  58. void drawUI(NVGcontext *vg, int item, int x, int y) {
  59. const UIData *data = (const UIData *)uiGetData(item);
  60. UIrect rect = uiGetRect(item);
  61. rect.x += x;
  62. rect.y += y;
  63. switch(uiGetKind(item)) {
  64. case UI_LABEL: {
  65. assert(data);
  66. bndLabel(vg,rect.x,rect.y,rect.w,rect.h,
  67. data->iconid,data->label);
  68. } break;
  69. case UI_BUTTON: {
  70. assert(data);
  71. switch(data->subtype) {
  72. default: {
  73. bndToolButton(vg,rect.x,rect.y,rect.w,rect.h,
  74. cornerFlags(item),(BNDwidgetState)uiGetState(item),
  75. data->iconid,data->label);
  76. } break;
  77. case ST_RADIO:{
  78. BNDwidgetState state = (BNDwidgetState)uiGetState(item);
  79. bndRadioButton(vg,rect.x,rect.y,rect.w,rect.h,
  80. cornerFlags(item),state,
  81. data->iconid,data->label);
  82. } break;
  83. }
  84. } break;
  85. default: break;
  86. }
  87. int kid = uiFirstChild(item);
  88. while (kid > 0) {
  89. drawUI(vg, kid, rect.x, rect.y);
  90. kid = uiNextSibling(kid);
  91. }
  92. }
  93. int label(int parent, int iconid, const char *label) {
  94. UIData data = { sizeof(UIData), ST_DEFAULT, iconid, label };
  95. return uiItem(parent, 0, UI_LABEL, 0, BND_WIDGET_HEIGHT, &data);
  96. }
  97. int button(int parent, UIhandle handle, int iconid, const char *label,
  98. UIhandler handler) {
  99. UIData data = { sizeof(UIData), ST_DEFAULT, iconid, label };
  100. int item = uiItem(parent, handle, UI_BUTTON, 0, BND_WIDGET_HEIGHT, &data);
  101. uiSetHandler(item, handler);
  102. return item;
  103. }
  104. static UIhandle radio_handle = 0;
  105. void radiohandler(int item) {
  106. radio_handle = uiGetHandle(item);
  107. uiSetActive(item, 1);
  108. }
  109. int radio(int parent, UIhandle handle, int iconid, const char *label) {
  110. UIData data = { sizeof(UIData), ST_RADIO, iconid, label };
  111. int w = (label)?0:BND_TOOL_WIDTH;
  112. int item = uiItem(parent, handle, UI_BUTTON, w, BND_WIDGET_HEIGHT, &data);
  113. uiSetHandler(item, radiohandler);
  114. uiSetEarlyHandler(item, true);
  115. if (radio_handle == handle)
  116. uiSetActive(item, 1);
  117. return item;
  118. }
  119. void demohandler(int item) {
  120. const UIData *data = (const UIData *)uiGetData(item);
  121. printf("clicked: %lld %s\n", uiGetHandle(item), data->label);
  122. }
  123. void draw(NVGcontext *vg, float w, float h) {
  124. bndBackground(vg, 0, 0, w, h);
  125. int x = 10;
  126. int y = 10;
  127. bndToolButton(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT,
  128. BND_ICONID(6,3),"Default");
  129. y += 25;
  130. bndToolButton(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER,
  131. BND_ICONID(6,3),"Hovered");
  132. y += 25;
  133. bndToolButton(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE,
  134. BND_ICONID(6,3),"Active");
  135. y += 40;
  136. bndRadioButton(vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT,
  137. -1,"Default");
  138. y += 25;
  139. bndRadioButton(vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER,
  140. -1,"Hovered");
  141. y += 25;
  142. bndRadioButton(vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE,
  143. -1,"Active");
  144. y += 25;
  145. bndLabel(vg,x,y,120,BND_WIDGET_HEIGHT,-1,"Label:");
  146. y += BND_WIDGET_HEIGHT;
  147. bndChoiceButton(vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT,
  148. -1, "Default");
  149. y += 25;
  150. bndChoiceButton(vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER,
  151. -1, "Hovered");
  152. y += 25;
  153. bndChoiceButton(vg,x,y,80,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE,
  154. -1, "Active");
  155. y += 25;
  156. int ry = y;
  157. int rx = x;
  158. y = 10;
  159. x += 130;
  160. bndOptionButton(vg,x,y,120,BND_WIDGET_HEIGHT,BND_DEFAULT,"Default");
  161. y += 25;
  162. bndOptionButton(vg,x,y,120,BND_WIDGET_HEIGHT,BND_HOVER,"Hovered");
  163. y += 25;
  164. bndOptionButton(vg,x,y,120,BND_WIDGET_HEIGHT,BND_ACTIVE,"Active");
  165. y += 40;
  166. bndNumberField(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_DOWN,BND_DEFAULT,
  167. "Top","100");
  168. y += BND_WIDGET_HEIGHT-2;
  169. bndNumberField(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_ALL,BND_DEFAULT,
  170. "Center","100");
  171. y += BND_WIDGET_HEIGHT-2;
  172. bndNumberField(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_TOP,BND_DEFAULT,
  173. "Bottom","100");
  174. int mx = x-30;
  175. int my = y-12;
  176. int mw = 120;
  177. bndMenuBackground(vg,mx,my,mw,120,BND_CORNER_TOP);
  178. bndMenuLabel(vg,mx,my,mw,BND_WIDGET_HEIGHT,-1,"Menu Title");
  179. my += BND_WIDGET_HEIGHT-2;
  180. bndMenuItem(vg,mx,my,mw,BND_WIDGET_HEIGHT,BND_DEFAULT,
  181. BND_ICONID(17,3),"Default");
  182. my += BND_WIDGET_HEIGHT-2;
  183. bndMenuItem(vg,mx,my,mw,BND_WIDGET_HEIGHT,BND_HOVER,
  184. BND_ICONID(18,3),"Hovered");
  185. my += BND_WIDGET_HEIGHT-2;
  186. bndMenuItem(vg,mx,my,mw,BND_WIDGET_HEIGHT,BND_ACTIVE,
  187. BND_ICONID(19,3),"Active");
  188. y = 10;
  189. x += 130;
  190. int ox = x;
  191. bndNumberField(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT,
  192. "Default","100");
  193. y += 25;
  194. bndNumberField(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER,
  195. "Hovered","100");
  196. y += 25;
  197. bndNumberField(vg,x,y,120,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE,
  198. "Active","100");
  199. y += 40;
  200. bndRadioButton(vg,x,y,60,BND_WIDGET_HEIGHT,BND_CORNER_RIGHT,BND_DEFAULT,
  201. -1,"One");
  202. x += 60-1;
  203. bndRadioButton(vg,x,y,60,BND_WIDGET_HEIGHT,BND_CORNER_ALL,BND_DEFAULT,
  204. -1,"Two");
  205. x += 60-1;
  206. bndRadioButton(vg,x,y,60,BND_WIDGET_HEIGHT,BND_CORNER_ALL,BND_DEFAULT,
  207. -1,"Three");
  208. x += 60-1;
  209. bndRadioButton(vg,x,y,60,BND_WIDGET_HEIGHT,BND_CORNER_LEFT,BND_ACTIVE,
  210. -1,"Butts");
  211. x = ox;
  212. y += 40;
  213. float progress_value = fmodf(glfwGetTime()/10.0,1.0);
  214. char progress_label[32];
  215. sprintf(progress_label, "%d%%", int(progress_value*100+0.5f));
  216. bndSlider(vg,x,y,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT,
  217. progress_value,"Default",progress_label);
  218. y += 25;
  219. bndSlider(vg,x,y,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER,
  220. progress_value,"Hovered",progress_label);
  221. y += 25;
  222. bndSlider(vg,x,y,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE,
  223. progress_value,"Active",progress_label);
  224. int rw = x+240-rx;
  225. float s_offset = sinf(glfwGetTime()/2.0)*0.5+0.5;
  226. float s_size = cosf(glfwGetTime()/3.11)*0.5+0.5;
  227. bndScrollBar(vg,rx,ry,rw,BND_SCROLLBAR_HEIGHT,BND_DEFAULT,s_offset,s_size);
  228. ry += 20;
  229. bndScrollBar(vg,rx,ry,rw,BND_SCROLLBAR_HEIGHT,BND_HOVER,s_offset,s_size);
  230. ry += 20;
  231. bndScrollBar(vg,rx,ry,rw,BND_SCROLLBAR_HEIGHT,BND_ACTIVE,s_offset,s_size);
  232. const char edit_text[] = "The quick brown fox";
  233. int textlen = strlen(edit_text)+1;
  234. int t = int(glfwGetTime()*2);
  235. int idx1 = (t/textlen)%textlen;
  236. int idx2 = idx1 + (t%(textlen-idx1));
  237. ry += 25;
  238. bndTextField(vg,rx,ry,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_DEFAULT,
  239. -1, edit_text, idx1, idx2);
  240. ry += 25;
  241. bndTextField(vg,rx,ry,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_HOVER,
  242. -1, edit_text, idx1, idx2);
  243. ry += 25;
  244. bndTextField(vg,rx,ry,240,BND_WIDGET_HEIGHT,BND_CORNER_NONE,BND_ACTIVE,
  245. -1, edit_text, idx1, idx2);
  246. rx += rw + 20;
  247. ry = 10;
  248. bndScrollBar(vg,rx,ry,BND_SCROLLBAR_WIDTH,240,BND_DEFAULT,s_offset,s_size);
  249. rx += 20;
  250. bndScrollBar(vg,rx,ry,BND_SCROLLBAR_WIDTH,240,BND_HOVER,s_offset,s_size);
  251. rx += 20;
  252. bndScrollBar(vg,rx,ry,BND_SCROLLBAR_WIDTH,240,BND_ACTIVE,s_offset,s_size);
  253. x = ox;
  254. y += 40;
  255. bndToolButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_RIGHT,
  256. BND_DEFAULT,BND_ICONID(0,10),NULL);
  257. x += BND_TOOL_WIDTH-1;
  258. bndToolButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  259. BND_DEFAULT,BND_ICONID(1,10),NULL);
  260. x += BND_TOOL_WIDTH-1;
  261. bndToolButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  262. BND_DEFAULT,BND_ICONID(2,10),NULL);
  263. x += BND_TOOL_WIDTH-1;
  264. bndToolButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  265. BND_DEFAULT,BND_ICONID(3,10),NULL);
  266. x += BND_TOOL_WIDTH-1;
  267. bndToolButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  268. BND_DEFAULT,BND_ICONID(4,10),NULL);
  269. x += BND_TOOL_WIDTH-1;
  270. bndToolButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_LEFT,
  271. BND_DEFAULT,BND_ICONID(5,10),NULL);
  272. x += BND_TOOL_WIDTH-1;
  273. x += 5;
  274. bndRadioButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_RIGHT,
  275. BND_DEFAULT,BND_ICONID(0,11),NULL);
  276. x += BND_TOOL_WIDTH-1;
  277. bndRadioButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  278. BND_DEFAULT,BND_ICONID(1,11),NULL);
  279. x += BND_TOOL_WIDTH-1;
  280. bndRadioButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  281. BND_DEFAULT,BND_ICONID(2,11),NULL);
  282. x += BND_TOOL_WIDTH-1;
  283. bndRadioButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  284. BND_DEFAULT,BND_ICONID(3,11),NULL);
  285. x += BND_TOOL_WIDTH-1;
  286. bndRadioButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_ALL,
  287. BND_ACTIVE,BND_ICONID(4,11),NULL);
  288. x += BND_TOOL_WIDTH-1;
  289. bndRadioButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_LEFT,
  290. BND_DEFAULT,BND_ICONID(5,11),NULL);
  291. // some OUI stuff
  292. uiClear();
  293. uiSetRect(0,600,10,250,400);
  294. int col = uiColumn(0,1);
  295. button(col, 1, BND_ICONID(6,3), "Item 1", demohandler);
  296. button(col, 2, BND_ICONID(6,3), "Item 2", demohandler);
  297. {
  298. int row = uiRow(col,-1);
  299. radio(row, 3, BND_ICONID(6,3), "Item 3.0");
  300. radio(row, 4, BND_ICONID(0,10), NULL);
  301. radio(row, 5, BND_ICONID(1,10), NULL);
  302. radio(row, 6, BND_ICONID(6,3), "Item 3.3");
  303. }
  304. {
  305. int row = uiRow(col,8);
  306. int coll = uiColumn(row,-2);
  307. label(coll, -1, "Items 4.0:");
  308. coll = uiColumn(coll,-2);
  309. button(coll, 7, BND_ICONID(6,3), "Item 4.0.0", demohandler);
  310. button(coll, 8, BND_ICONID(6,3), "Item 4.0.1", demohandler);
  311. int colr = uiColumn(row,-2);
  312. label(colr, -1, "Items 4.1:");
  313. colr = uiColumn(colr,-2);
  314. button(colr, 9, BND_ICONID(6,3), "Item 4.1.0", demohandler);
  315. button(colr,10, BND_ICONID(6,3), "Item 4.1.1", demohandler);
  316. }
  317. button(col, 11, BND_ICONID(6,3), "Item 5", NULL);
  318. uiProcess();
  319. drawUI(vg, 0, 0, 0);
  320. }
  321. ////////////////////////////////////////////////////////////////////////////////
  322. void errorcb(int error, const char* desc)
  323. {
  324. printf("GLFW error %d: %s\n", error, desc);
  325. }
  326. static void mousebutton(GLFWwindow *window, int button, int action, int mods) {
  327. NVG_NOTUSED(window);
  328. NVG_NOTUSED(mods);
  329. uiSetButton(button, (action==GLFW_PRESS)?1:0);
  330. }
  331. static void cursorpos(GLFWwindow *window, double x, double y) {
  332. NVG_NOTUSED(window);
  333. uiSetCursor((int)x,(int)y);
  334. }
  335. static void key(GLFWwindow* window, int key, int scancode, int action, int mods)
  336. {
  337. NVG_NOTUSED(scancode);
  338. NVG_NOTUSED(mods);
  339. if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
  340. glfwSetWindowShouldClose(window, GL_TRUE);
  341. }
  342. int main()
  343. {
  344. GLFWwindow* window;
  345. struct NVGcontext* vg = NULL;
  346. UIcontext *uictx;
  347. uictx = uiCreateContext();
  348. uiMakeCurrent(uictx);
  349. if (!glfwInit()) {
  350. printf("Failed to init GLFW.");
  351. return -1;
  352. }
  353. glfwSetErrorCallback(errorcb);
  354. #ifndef _WIN32 // don't require this on win32, and works with more cards
  355. glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
  356. glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
  357. glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
  358. glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
  359. #endif
  360. glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, 1);
  361. window = glfwCreateWindow(1000, 600, "Blendish Demo", NULL, NULL);
  362. if (!window) {
  363. glfwTerminate();
  364. return -1;
  365. }
  366. glfwSetKeyCallback(window, key);
  367. glfwSetCursorPosCallback(window, cursorpos);
  368. glfwSetMouseButtonCallback(window, mousebutton);
  369. glfwMakeContextCurrent(window);
  370. #ifdef NANOVG_GLEW
  371. glewExperimental = GL_TRUE;
  372. if(glewInit() != GLEW_OK) {
  373. printf("Could not init glew.\n");
  374. return -1;
  375. }
  376. // GLEW generates GL error because it calls glGetString(GL_EXTENSIONS), we'll consume it here.
  377. glGetError();
  378. #endif
  379. vg = nvgCreateGL3(NVG_ANTIALIAS | NVG_STENCIL_STROKES);
  380. if (vg == NULL) {
  381. printf("Could not init nanovg.\n");
  382. return -1;
  383. }
  384. init(vg);
  385. glfwSwapInterval(0);
  386. glfwSetTime(0);
  387. while (!glfwWindowShouldClose(window))
  388. {
  389. double mx, my;
  390. int winWidth, winHeight;
  391. int fbWidth, fbHeight;
  392. float pxRatio;
  393. glfwGetCursorPos(window, &mx, &my);
  394. glfwGetWindowSize(window, &winWidth, &winHeight);
  395. glfwGetFramebufferSize(window, &fbWidth, &fbHeight);
  396. // Calculate pixel ration for hi-dpi devices.
  397. pxRatio = (float)fbWidth / (float)winWidth;
  398. // Update and render
  399. glViewport(0, 0, fbWidth, fbHeight);
  400. glClearColor(0,0,0,1);
  401. glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
  402. nvgBeginFrame(vg, winWidth, winHeight, pxRatio);
  403. draw(vg, winWidth, winHeight);
  404. nvgEndFrame(vg);
  405. glfwSwapBuffers(window);
  406. glfwPollEvents();
  407. }
  408. uiDestroyContext(uictx);
  409. nvgDeleteGL3(vg);
  410. glfwTerminate();
  411. return 0;
  412. }