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.

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