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.

454 lines
14KB

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