├── .gitignore ├── LICENCE.txt ├── README.md ├── doc ├── doxyfile └── theme │ ├── DoxygenLayout.xml │ ├── bootstrap_integration.js │ ├── customdoxygen.css │ ├── footer.html │ └── header.html ├── screenshot └── Screenshot1.png └── src ├── Canvas.cpp ├── Canvas.h ├── Color.hpp ├── ColorConverter.h ├── Image.cpp ├── Image.h ├── NanoCanvas.h ├── Paint.hpp ├── Text.cpp └── Text.h /.gitignore: -------------------------------------------------------------------------------- 1 | # doc/html 2 | doc/html 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | 22 | # Compiled Static libraries 23 | *.lai 24 | *.la 25 | *.a 26 | *.lib 27 | 28 | # Executables 29 | *.exe 30 | *.out 31 | *.app 32 | -------------------------------------------------------------------------------- /LICENCE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Geequlim 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | NanoCanvas {#mainpage} 2 | --- 3 | 4 | NanoCanvas is the HTML5 Canvas liked antialiased vector graphics rendering library writing in C++11 based on [Mikko Mononen's NanoVG](https://github.com/memononen/nanovg) . 5 | 6 | ## Feartures 7 | 8 | * Easy to use , with HTML5 Canvas liked API 9 | 10 | ```c++ 11 | 12 | canvas.clearColor(Colors::DarkOliveGreen); //Clear canvas with color 13 | 14 | // Draw a rounded rectangle 15 | canvas.beginPath() 16 | .roundedRect(50,50,100,100,10) 17 | .fillStyle(Colors::Salmon) 18 | .fill(); 19 | 20 | // Draw styled text 21 | TextStyle textStyle; 22 | textStyle.size = 36.0f; 23 | textStyle.color = Colors::White; 24 | textStyle.face = font.face; 25 | canvas.fillStyle(textStyle) 26 | .beginPath() 27 | .fillText("Hello Canvas",30,190); 28 | ``` 29 | 30 | ![](https://raw.githubusercontent.com/Geequlim/NanoCanvas/master/screenshot/Screenshot1.png) 31 | 32 | * Hardware accelerated so it's fast 33 | 34 | Thanks for backend ports of NanoVG , now we can use NanoCanvas with OpenGL, OpenGL ES, [BGFX](https://github.com/bkaradzic/bgfx) and [D3D](https://github.com/cmaughan/nanovg). 35 | 36 | 37 | ## Integrate to your projects 38 | 39 | 1. Add NanoVG code to your projects and add the folder where your nanovg.h file located to your include directory. Be sure `#included "nanovg.h"` works on your projects. 40 | 41 | 2. Add NanoCanvas code files under `src` folder in to your projects. 42 | 43 | 3. Create Canvas with NanoVG context 44 | For example,using OpenGL 3.x as the backend renderer. 45 | ```c++ 46 | NVGcontext * nvgCtx = nvgCreateGL3(NVG_ANTIALIAS | NVG_DEBUG |NVG_STENCIL_STROKES); 47 | Canvas canvas(nvgCtx,wndWidth ,wndHeight); 48 | if(canvas.valid()) { 49 | // Everything is OK 50 | } 51 | ``` 52 | 53 | 4 . Draw awesome graphics 54 | Draw graphics between `begineFrame()` and `endFrame` method. 55 | 56 | ```c++ 57 | // main render loop 58 | while ( appRunning ) 59 | { 60 | canvas.begineFrame(wndWidth,wndHeight); 61 | // Draw awesome graphics here 62 | canvas.endFrame(); 63 | } 64 | ``` 65 | 66 | ### Why not takes NanoVG itself ? 67 | 68 | You can use the backend renderer as your like. You have to do that by yourself. :) 69 | 70 | --- 71 | 72 | ## For more informations 73 | 74 | ### [Documemtations](https://geequlim.github.io/NanoCanvas/doc/html/index.html) is avaliable. 75 | -------------------------------------------------------------------------------- /doc/theme/DoxygenLayout.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | -------------------------------------------------------------------------------- /doc/theme/bootstrap_integration.js: -------------------------------------------------------------------------------- 1 | $( document ).ready(function() 2 | { 3 | $("div.headertitle").addClass("page-header"); 4 | $("div.title").addClass("h1"); 5 | 6 | $(".dynheader").addClass("alert alert-info"); // expand button for class diagrams 7 | $(".dyncontent").addClass("panel panel-default"); 8 | 9 | $(".fragment").addClass("well"); // panel containing blocks of code 10 | 11 | $(".memitem").addClass("panel panel-info"); // panel containing a member function 12 | $(".memitem").find(".deprecated").closest(".memitem").addClass("panel-danger"); // change the style of deprecated functions 13 | $(".deprecated").find(".el") 14 | .addClass("label label-danger") 15 | .css("margin-bottom", "5px"); 16 | $(".memproto").addClass("panel-heading"); // panel containing a member function prototype 17 | $(".memdoc").addClass("panel-body"); // panel containing a member function description 18 | 19 | $("table.params").addClass("table"); 20 | $("table.directory").addClass("table table-striped"); 21 | $("table.fieldtable").addClass("table") // tables where elements like enumerations are shown 22 | 23 | $(".contents").addClass("panel panel-default"); 24 | 25 | $("table.memberdecls").addClass("table"); // table listing all member functions 26 | $(".memberdecls").find(".memSeparator").remove(); 27 | 28 | $("span.mlabel").addClass("label label-info"); // labels containing abstract/virtual info 29 | 30 | // navigation bar 31 | $('li > a[href="index.html"] > span').before(" "); 32 | $('li > a[href="modules.html"] > span').before(" "); 33 | $('li > a[href="namespaces.html"] > span').before(" "); 34 | $('li > a[href="annotated.html"] > span').before(" "); 35 | $('li > a[href="classes.html"] > span').before(" "); 36 | $('li > a[href="inherits.html"] > span').before(" "); 37 | $('li > a[href="functions.html"] > span').before(" "); 38 | $('li > a[href="functions_func.html"] > span').before(" "); 39 | $('li > a[href="functions_vars.html"] > span').before(" "); 40 | $('li > a[href="functions_enum.html"] > span').before(" "); 41 | $('li > a[href="functions_eval.html"] > span').before(" "); 42 | $("div.tabs").addClass("nav nav-tabs"); 43 | $("div.tabs2").addClass("nav nav-tabs"); 44 | $("ul.tablist").addClass("nav nav-pills nav-justified"); 45 | $("ul.tablist").css("margin-top", "0.5em"); 46 | $("ul.tablist").css("margin-bottom", "0.5em"); 47 | $("ul.tablist").css("margin-left", "auto"); 48 | $("ul.tablist").css("margin-right", "auto"); 49 | $("ul.tablist").css("max-width", "600px"); 50 | $("li.current").addClass("active"); 51 | $("#nav-path > ul").addClass("breadcrumb"); 52 | $("#nav-path > ul").css("margin-left", "auto"); 53 | $("#nav-path > ul").css("margin-right", "auto"); 54 | $("#nav-path > ul").css("max-width", "980px"); 55 | $(".navpath").removeClass("navpath"); 56 | $("li.navelem").removeClass("navelem"); 57 | $("ul.tablist").removeClass("tablist"); 58 | $("div.tabs").removeClass("tabs"); 59 | $("div.tabs2").removeClass("tabs2"); 60 | 61 | // search box 62 | $("#MSearchBox").css("position", "relative"); 63 | $(".right").css("position", "relative"); 64 | $(".right").css("right", "0px"); 65 | $(".right").css("left", "141px"); 66 | var results = $("#MSearchResultsWindow"); 67 | $("#MSearchBox").parent().append(results) 68 | results 69 | .css("position", "absolute") 70 | .css("z-index", "500") 71 | .css("top", "initial") 72 | .css("margin-top", "8px"); 73 | 74 | // detail level 75 | $("div.levels").css("margin", "0.5em"); 76 | $("div.levels > span").addClass("btn btn-default btn-xs"); 77 | $("div.levels > span").css("margin-right", "0.25em"); 78 | 79 | }); 80 | -------------------------------------------------------------------------------- /doc/theme/customdoxygen.css: -------------------------------------------------------------------------------- 1 | /* The standard CSS for doxygen 1.8.7 */ 2 | 3 | body, table, div, p, dl { 4 | font: 400 14px/22px "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif; 5 | } 6 | 7 | /* @group Heading Levels */ 8 | 9 | h1.groupheader { 10 | font-size: 200%; 11 | } 12 | 13 | .title { 14 | margin: 10px 2px; 15 | } 16 | 17 | h2.groupheader { 18 | font-size: 200%; 19 | font-weight: normal; 20 | margin-top: 1.75em; 21 | padding-top: 8px; 22 | padding-bottom: 4px; 23 | width: 100%; 24 | } 25 | 26 | h3.groupheader { 27 | font-size: 150%; 28 | } 29 | 30 | h1, h2, h3, h4, h5, h6 { 31 | margin-right: 15px; 32 | } 33 | 34 | h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow { 35 | text-shadow: 0 0 15px cyan; 36 | } 37 | 38 | dt { 39 | font-weight: bold; 40 | } 41 | 42 | div.multicol { 43 | -moz-column-gap: 1em; 44 | -webkit-column-gap: 1em; 45 | -moz-column-count: 3; 46 | -webkit-column-count: 3; 47 | } 48 | 49 | p.startli, p.startdd { 50 | margin-top: 2px; 51 | } 52 | 53 | p.starttd { 54 | margin-top: 0px; 55 | } 56 | 57 | p.endli { 58 | margin-bottom: 0px; 59 | } 60 | 61 | p.enddd { 62 | margin-bottom: 4px; 63 | } 64 | 65 | p.endtd { 66 | margin-bottom: 2px; 67 | } 68 | 69 | /* @end */ 70 | 71 | caption { 72 | font-weight: bold; 73 | } 74 | 75 | span.legend { 76 | font-size: 70%; 77 | text-align: center; 78 | } 79 | 80 | h3.version { 81 | font-size: 90%; 82 | text-align: center; 83 | } 84 | 85 | div.qindex, div.navtab{ 86 | background-color: #EBEFF6; 87 | border: 1px solid #A3B4D7; 88 | text-align: center; 89 | } 90 | 91 | div.qindex, div.navpath { 92 | width: 100%; 93 | line-height: 140%; 94 | } 95 | 96 | div.navtab { 97 | margin-right: 15px; 98 | } 99 | 100 | /* @group Link Styling */ 101 | 102 | a { 103 | color: #3D578C; 104 | font-weight: normal; 105 | text-decoration: none; 106 | } 107 | 108 | .contents a:visited { 109 | color: #4665A2; 110 | } 111 | 112 | a:hover { 113 | text-decoration: underline; 114 | } 115 | 116 | a.qindex { 117 | font-weight: bold; 118 | } 119 | 120 | a.qindexHL { 121 | font-weight: bold; 122 | background-color: #9CAFD4; 123 | color: #ffffff; 124 | border: 1px double #869DCA; 125 | } 126 | 127 | .contents a.qindexHL:visited { 128 | color: #ffffff; 129 | } 130 | 131 | a.el { 132 | font-weight: bold; 133 | } 134 | 135 | a.elRef { 136 | } 137 | 138 | a.code, a.code:visited, a.line, a.line:visited { 139 | color: #4665A2; 140 | } 141 | 142 | a.codeRef, a.codeRef:visited, a.lineRef, a.lineRef:visited { 143 | color: #4665A2; 144 | } 145 | 146 | /* @end */ 147 | 148 | dl.el { 149 | margin-left: -1cm; 150 | } 151 | 152 | pre.fragment { 153 | word-wrap: break-word; 154 | font-size: 9pt; 155 | line-height: 125%; 156 | font-family: Consolas, monospace, fixed; 157 | font-size: 105%; 158 | } 159 | 160 | div.line { 161 | font-family: monospace, fixed; 162 | font-size: 13px; 163 | min-height: 13px; 164 | line-height: 1.0; 165 | text-wrap: unrestricted; 166 | white-space: -moz-pre-wrap; /* Moz */ 167 | white-space: -pre-wrap; /* Opera 4-6 */ 168 | white-space: -o-pre-wrap; /* Opera 7 */ 169 | white-space: pre-wrap; /* CSS3 */ 170 | word-wrap: break-word; /* IE 5.5+ */ 171 | text-indent: -53px; 172 | padding-left: 53px; 173 | padding-bottom: 0px; 174 | margin: 0px; 175 | } 176 | 177 | div.line.glow { 178 | background-color: cyan; 179 | } 180 | 181 | 182 | span.lineno { 183 | padding-right: 4px; 184 | text-align: right; 185 | border-right: 2px solid #0F0; 186 | background-color: #E8E8E8; 187 | white-space: pre; 188 | } 189 | span.lineno a { 190 | background-color: #D8D8D8; 191 | } 192 | 193 | span.lineno a:hover { 194 | background-color: #C8C8C8; 195 | } 196 | 197 | div.ah { 198 | background-color: black; 199 | font-weight: bold; 200 | color: #ffffff; 201 | margin-bottom: 3px; 202 | margin-top: 3px; 203 | padding: 0.2em; 204 | border: solid thin #333; 205 | border-radius: 0.5em; 206 | -webkit-border-radius: .5em; 207 | -moz-border-radius: .5em; 208 | } 209 | 210 | div.groupHeader { 211 | margin-left: 16px; 212 | margin-top: 12px; 213 | font-weight: bold; 214 | } 215 | 216 | div.groupText { 217 | margin-left: 16px; 218 | font-style: italic; 219 | } 220 | 221 | body { 222 | background-color: white; 223 | color: black; 224 | margin: 0; 225 | } 226 | 227 | div.contents { 228 | margin-top: 10px; 229 | margin-left: auto; 230 | margin-right: auto; 231 | max-width: 980px; 232 | padding: 15px; 233 | } 234 | 235 | td.indexkey { 236 | background-color: #EBEFF6; 237 | font-weight: bold; 238 | border: 1px solid #C4CFE5; 239 | margin: 2px 0px 2px 0; 240 | padding: 2px 10px; 241 | white-space: nowrap; 242 | vertical-align: top; 243 | } 244 | 245 | td.indexvalue { 246 | background-color: #EBEFF6; 247 | border: 1px solid #C4CFE5; 248 | padding: 2px 10px; 249 | margin: 2px 0px; 250 | } 251 | 252 | p.formulaDsp { 253 | text-align: center; 254 | } 255 | 256 | img.formulaDsp { 257 | 258 | } 259 | 260 | img.formulaInl { 261 | vertical-align: middle; 262 | } 263 | 264 | div.center { 265 | text-align: center; 266 | margin-top: 0px; 267 | margin-bottom: 0px; 268 | padding: 0px; 269 | } 270 | 271 | div.center img { 272 | border: 0px; 273 | } 274 | 275 | address.footer { 276 | text-align: right; 277 | padding-right: 12px; 278 | } 279 | 280 | img.footer { 281 | border: 0px; 282 | vertical-align: middle; 283 | } 284 | 285 | /* @group Code Colorization */ 286 | 287 | span.keyword { 288 | color: #008000 289 | } 290 | 291 | span.keywordtype { 292 | color: #604020 293 | } 294 | 295 | span.keywordflow { 296 | color: #e08000 297 | } 298 | 299 | span.comment { 300 | color: #800000 301 | } 302 | 303 | span.preprocessor { 304 | color: #806020 305 | } 306 | 307 | span.stringliteral { 308 | color: #002080 309 | } 310 | 311 | span.charliteral { 312 | color: #008080 313 | } 314 | 315 | span.vhdldigit { 316 | color: #ff00ff 317 | } 318 | 319 | span.vhdlchar { 320 | color: #000000 321 | } 322 | 323 | span.vhdlkeyword { 324 | color: #700070 325 | } 326 | 327 | span.vhdllogic { 328 | color: #ff0000 329 | } 330 | 331 | blockquote { 332 | background-color: #F7F8FB; 333 | border-left: 2px solid #9CAFD4; 334 | margin: 0 24px 0 4px; 335 | padding: 0 12px 0 16px; 336 | } 337 | 338 | /* @end */ 339 | 340 | 341 | .search { 342 | color: #003399; 343 | font-weight: bold; 344 | } 345 | 346 | form.search { 347 | margin-bottom: 0px; 348 | margin-top: 0px; 349 | } 350 | 351 | input.search { 352 | font-size: 75%; 353 | color: #000080; 354 | font-weight: normal; 355 | background-color: #e8eef2; 356 | } 357 | 358 | 359 | td.tiny { 360 | font-size: 75%; 361 | } 362 | 363 | .dirtab { 364 | padding: 4px; 365 | border-collapse: collapse; 366 | border: 1px solid #A3B4D7; 367 | } 368 | 369 | th.dirtab { 370 | background: #EBEFF6; 371 | font-weight: bold; 372 | } 373 | 374 | hr { 375 | height: 0px; 376 | border: none; 377 | border-top: 1px solid #4A6AAA; 378 | } 379 | 380 | hr.footer { 381 | height: 1px; 382 | } 383 | 384 | /* @group Member Descriptions */ 385 | 386 | table.memberdecls { 387 | border-spacing: 0px; 388 | padding: 0px; 389 | } 390 | 391 | .mdescLeft, .mdescRight, 392 | .memItemLeft, .memItemRight, 393 | .memTemplItemLeft, .memTemplItemRight, .memTemplParams { 394 | border: none; 395 | margin: 4px; 396 | padding: 1px 0 0 8px; 397 | } 398 | 399 | .mdescLeft, .mdescRight { 400 | padding: 0px 8px 4px 8px; 401 | color: #555; 402 | } 403 | 404 | .memItemLeft, .memTemplItemLeft { 405 | white-space: nowrap; 406 | } 407 | 408 | .memItemRight { 409 | width: 100%; 410 | } 411 | 412 | .memTemplParams { 413 | color: #4665A2; 414 | white-space: nowrap; 415 | font-size: 80%; 416 | } 417 | 418 | /* @end */ 419 | 420 | /* @group Member Details */ 421 | 422 | /* Styles for detailed member documentation */ 423 | 424 | .memtemplate { 425 | font-size: 80%; 426 | color: #4665A2; 427 | font-weight: normal; 428 | margin-left: 9px; 429 | } 430 | 431 | .memnav { 432 | background-color: #EBEFF6; 433 | border: 1px solid #A3B4D7; 434 | text-align: center; 435 | margin: 2px; 436 | margin-right: 15px; 437 | padding: 2px; 438 | } 439 | 440 | .mempage { 441 | width: 100%; 442 | } 443 | 444 | .memitem { 445 | padding: 0; 446 | margin-bottom: 10px; 447 | margin-right: 5px; 448 | display: table !important; 449 | width: 100%; 450 | } 451 | 452 | .memname { 453 | font-weight: bold; 454 | margin-left: 6px; 455 | } 456 | 457 | .memname td { 458 | vertical-align: bottom; 459 | } 460 | 461 | .memproto, dl.reflist dt { 462 | padding: 6px 0px 6px 0px; 463 | font-weight: bold; 464 | } 465 | 466 | .memdoc, dl.reflist dd { 467 | padding: 6px 10px 2px 10px; 468 | } 469 | 470 | dl.reflist dt { 471 | padding: 5px; 472 | } 473 | 474 | dl.reflist dd { 475 | margin: 0px 0px 10px 0px; 476 | padding: 5px; 477 | } 478 | 479 | .paramkey { 480 | text-align: right; 481 | } 482 | 483 | .paramtype { 484 | color: #207ec3; 485 | white-space: nowrap; 486 | } 487 | 488 | .paramname { 489 | color: #20b086; 490 | white-space: nowrap; 491 | } 492 | .paramname em { 493 | font-style: normal; 494 | } 495 | .paramname code { 496 | line-height: 14px; 497 | } 498 | 499 | .params, .retval, .exception, .tparams { 500 | margin-left: 0px; 501 | padding-left: 0px; 502 | } 503 | 504 | .params .paramname, .retval .paramname { 505 | font-weight: bold; 506 | vertical-align: top; 507 | } 508 | 509 | .params .paramtype { 510 | font-style: italic; 511 | vertical-align: top; 512 | } 513 | 514 | .params .paramdir { 515 | font-family: Consolas,courier,monospace; 516 | vertical-align: top; 517 | } 518 | 519 | table.mlabels { 520 | border-spacing: 0px; 521 | } 522 | 523 | td.mlabels-left { 524 | width: 100%; 525 | padding: 0px; 526 | } 527 | 528 | td.mlabels-right { 529 | vertical-align: bottom; 530 | padding: 0px; 531 | white-space: nowrap; 532 | } 533 | 534 | span.mlabels { 535 | margin-left: 8px; 536 | } 537 | 538 | span.mlabel { 539 | margin-right: 4px; 540 | padding: 2px 3px; 541 | border-radius: 3px; 542 | font-size: 7pt; 543 | white-space: nowrap; 544 | vertical-align: middle; 545 | } 546 | 547 | 548 | 549 | /* @end */ 550 | 551 | /* these are for tree view inside a (index) page */ 552 | 553 | div.directory { 554 | margin: 10px 0px; 555 | border-top: 1px solid #9CAFD4; 556 | border-bottom: 1px solid #9CAFD4; 557 | width: 100%; 558 | } 559 | 560 | .directory table { 561 | border-collapse:collapse; 562 | } 563 | 564 | .directory td { 565 | margin: 0px; 566 | padding: 0px; 567 | vertical-align: top; 568 | } 569 | 570 | .directory td.entry { 571 | white-space: nowrap; 572 | padding-right: 6px; 573 | padding-top: 3px; 574 | } 575 | 576 | .directory td.entry a { 577 | outline:none; 578 | } 579 | 580 | .directory td.entry a img { 581 | border: none; 582 | } 583 | 584 | .directory td.desc { 585 | width: 100%; 586 | padding-left: 6px; 587 | padding-right: 6px; 588 | padding-top: 3px; 589 | border-left: 1px solid rgba(0,0,0,0.05); 590 | } 591 | 592 | .directory tr.even { 593 | padding-left: 6px; 594 | background-color: #F7F8FB; 595 | } 596 | 597 | .directory img { 598 | vertical-align: -30%; 599 | } 600 | 601 | .directory .levels { 602 | white-space: nowrap; 603 | width: 100%; 604 | text-align: right; 605 | font-size: 9pt; 606 | } 607 | 608 | .directory .levels span { 609 | cursor: pointer; 610 | padding-left: 2px; 611 | padding-right: 2px; 612 | color: #3D578C; 613 | } 614 | 615 | .arrow { 616 | color: #9CAFD4; 617 | -webkit-user-select: none; 618 | -khtml-user-select: none; 619 | -moz-user-select: none; 620 | -ms-user-select: none; 621 | user-select: none; 622 | cursor: pointer; 623 | font-size: 80%; 624 | display: inline-block; 625 | width: 16px; 626 | height: 22px; 627 | } 628 | 629 | .icon { 630 | font-weight: bold; 631 | font-size: 12px; 632 | height: 14px; 633 | width: 16px; 634 | display: inline-block; 635 | background-color: #728DC1; 636 | color: white; 637 | text-align: center; 638 | border-radius: 4px; 639 | margin-left: 2px; 640 | margin-right: 2px; 641 | } 642 | 643 | .icona { 644 | width: 24px; 645 | height: 22px; 646 | display: inline-block; 647 | } 648 | 649 | .iconfopen { 650 | width: 24px; 651 | height: 18px; 652 | margin-bottom: 4px; 653 | background-image:url('ftv2folderopen.png'); 654 | background-position: 0px -4px; 655 | background-repeat: repeat-y; 656 | vertical-align:top; 657 | display: inline-block; 658 | } 659 | 660 | .iconfclosed { 661 | width: 24px; 662 | height: 18px; 663 | margin-bottom: 4px; 664 | background-image:url('ftv2folderclosed.png'); 665 | background-position: 0px -4px; 666 | background-repeat: repeat-y; 667 | vertical-align:top; 668 | display: inline-block; 669 | } 670 | 671 | .icondoc { 672 | width: 24px; 673 | height: 18px; 674 | margin-bottom: 4px; 675 | background-image:url('ftv2doc.png'); 676 | background-position: 0px -4px; 677 | background-repeat: repeat-y; 678 | vertical-align:top; 679 | display: inline-block; 680 | } 681 | 682 | table.directory { 683 | font: 400 14px Roboto,sans-serif; 684 | } 685 | 686 | /* @end */ 687 | 688 | div.dynheader { 689 | margin-top: 8px; 690 | } 691 | 692 | address { 693 | font-style: normal; 694 | color: #2A3D61; 695 | } 696 | 697 | table.doxtable { 698 | border-collapse:collapse; 699 | margin-top: 4px; 700 | margin-bottom: 4px; 701 | } 702 | 703 | table.doxtable td, table.doxtable th { 704 | border: 1px solid #2D4068; 705 | padding: 3px 7px 2px; 706 | } 707 | 708 | table.doxtable th { 709 | background-color: #374F7F; 710 | color: #FFFFFF; 711 | font-size: 110%; 712 | padding-bottom: 4px; 713 | padding-top: 5px; 714 | } 715 | 716 | .fieldtable td, .fieldtable th { 717 | padding: 3px 7px 2px; 718 | } 719 | 720 | .fieldtable td.fieldtype, .fieldtable td.fieldname { 721 | white-space: nowrap; 722 | } 723 | 724 | .fieldtable td.fieldname { 725 | padding-top: 3px; 726 | } 727 | 728 | .fieldtable td.fielddoc p:first-child { 729 | margin-top: 0px; 730 | } 731 | 732 | .fieldtable td.fielddoc p:last-child { 733 | margin-bottom: 2px; 734 | } 735 | 736 | .fieldtable th { 737 | font-size: 90%; 738 | padding-bottom: 4px; 739 | padding-top: 5px; 740 | text-align:left; 741 | } 742 | 743 | .tabsearch { 744 | top: 0px; 745 | left: 10px; 746 | height: 42px; 747 | background-image: url('tab_b.png'); 748 | z-index: 101; 749 | overflow: hidden; 750 | font-size: 13px; 751 | } 752 | 753 | .navpath ul 754 | { 755 | font-size: 11px; 756 | background-image:url('tab_b.png'); 757 | background-repeat:repeat-x; 758 | background-position: 0 -5px; 759 | height:30px; 760 | line-height:30px; 761 | color:#8AA0CC; 762 | border:solid 1px #C2CDE4; 763 | overflow:hidden; 764 | margin:0px; 765 | padding:0px; 766 | } 767 | 768 | .navpath li 769 | { 770 | list-style-type:none; 771 | float:left; 772 | padding-left:10px; 773 | padding-right:15px; 774 | background-image:url('bc_s.png'); 775 | background-repeat:no-repeat; 776 | background-position:right; 777 | color:#364D7C; 778 | } 779 | 780 | .navpath li.navelem a 781 | { 782 | height:32px; 783 | display:block; 784 | text-decoration: none; 785 | outline: none; 786 | color: #283A5D; 787 | text-decoration: none; 788 | } 789 | 790 | .navpath li.navelem a:hover 791 | { 792 | color:#6884BD; 793 | } 794 | 795 | .navpath li.footer 796 | { 797 | list-style-type:none; 798 | float:right; 799 | padding-left:10px; 800 | padding-right:15px; 801 | background-image:none; 802 | background-repeat:no-repeat; 803 | background-position:right; 804 | color:#364D7C; 805 | font-size: 8pt; 806 | } 807 | 808 | 809 | div.summary 810 | { 811 | visibility: hidden 812 | } 813 | 814 | div.ingroups 815 | { 816 | font-size: 8pt; 817 | width: 50%; 818 | text-align: left; 819 | } 820 | 821 | div.ingroups a 822 | { 823 | white-space: nowrap; 824 | } 825 | 826 | div.header 827 | { 828 | margin: 0px; 829 | max-width: 980px; 830 | margin-left: auto; 831 | margin-right: auto; 832 | } 833 | 834 | div.headertitle 835 | { 836 | padding: 5px 5px 5px 10px; 837 | max-width: 980px; 838 | margin-left: auto; 839 | margin-right: auto; 840 | } 841 | 842 | dl 843 | { 844 | padding: 0 0 0 10px; 845 | } 846 | 847 | /* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug */ 848 | dl.section 849 | { 850 | margin-left: 0px; 851 | padding-left: 0px; 852 | } 853 | 854 | dl.note 855 | { 856 | margin-left:-7px; 857 | padding-left: 3px; 858 | border-left:4px solid; 859 | border-color: #7be554; 860 | } 861 | 862 | dl.warning, dl.attention 863 | { 864 | margin-left:-7px; 865 | padding-left: 3px; 866 | border-left:4px solid; 867 | border-color: #f2596c; 868 | } 869 | 870 | dl.pre, dl.post, dl.invariant 871 | { 872 | margin-left:-7px; 873 | padding-left: 3px; 874 | border-left:4px solid; 875 | border-color: #00D000; 876 | } 877 | 878 | dl.deprecated 879 | { 880 | margin-left:-7px; 881 | padding-left: 3px; 882 | } 883 | 884 | dl.todo 885 | { 886 | margin-left:-7px; 887 | padding-left: 3px; 888 | border-left:4px solid; 889 | border-color: #00C0E0; 890 | } 891 | 892 | dl.test 893 | { 894 | margin-left:-7px; 895 | padding-left: 3px; 896 | border-left:4px solid; 897 | border-color: #3030E0; 898 | } 899 | 900 | dl.bug 901 | { 902 | margin-left:-7px; 903 | padding-left: 3px; 904 | border-left:4px solid; 905 | border-color: #C08050; 906 | } 907 | 908 | dl.section dd { 909 | margin-bottom: 6px; 910 | } 911 | 912 | 913 | #projectlogo 914 | { 915 | text-align: center; 916 | vertical-align: bottom; 917 | border-collapse: separate; 918 | } 919 | 920 | #projectlogo img 921 | { 922 | border: 0px none; 923 | } 924 | 925 | #projectname 926 | { 927 | font: 300% Tahoma, Arial,sans-serif; 928 | margin: 0px; 929 | padding: 2px 0px; 930 | } 931 | 932 | #projectbrief 933 | { 934 | font: 120% Tahoma, Arial,sans-serif; 935 | margin: 0px; 936 | padding: 0px; 937 | } 938 | 939 | #projectnumber 940 | { 941 | font: 50% Tahoma, Arial,sans-serif; 942 | margin: 0px; 943 | padding: 0px; 944 | } 945 | 946 | #titlearea 947 | { 948 | padding: 0px; 949 | margin: 0px; 950 | width: 100%; 951 | border-bottom: 1px solid #5373B4; 952 | } 953 | 954 | .image 955 | { 956 | text-align: center; 957 | } 958 | 959 | .dotgraph 960 | { 961 | text-align: center; 962 | } 963 | 964 | .mscgraph 965 | { 966 | text-align: center; 967 | } 968 | 969 | .diagraph 970 | { 971 | text-align: center; 972 | } 973 | 974 | .caption 975 | { 976 | font-weight: bold; 977 | } 978 | 979 | div.zoom 980 | { 981 | border: 1px solid #90A5CE; 982 | } 983 | 984 | dl.citelist { 985 | margin-bottom:50px; 986 | } 987 | 988 | dl.citelist dt { 989 | color:#334975; 990 | float:left; 991 | font-weight:bold; 992 | margin-right:10px; 993 | padding:5px; 994 | } 995 | 996 | dl.citelist dd { 997 | margin:2px 0; 998 | padding:5px 0; 999 | } 1000 | 1001 | div.toc { 1002 | padding: 14px 25px; 1003 | background-color: #F4F6FA; 1004 | border: 1px solid #D8DFEE; 1005 | border-radius: 7px 7px 7px 7px; 1006 | float: right; 1007 | height: auto; 1008 | margin: 0 20px 10px 10px; 1009 | width: 200px; 1010 | } 1011 | 1012 | div.toc li { 1013 | background: url("bdwn.png") no-repeat scroll 0 5px transparent; 1014 | font: 10px/1.2 Verdana,DejaVu Sans,Geneva,sans-serif; 1015 | margin-top: 5px; 1016 | padding-left: 10px; 1017 | padding-top: 2px; 1018 | } 1019 | 1020 | div.toc h3 { 1021 | font: bold 12px/1.2 Arial,FreeSans,sans-serif; 1022 | color: #4665A2; 1023 | border-bottom: 0 none; 1024 | margin: 0; 1025 | } 1026 | 1027 | div.toc ul { 1028 | list-style: none outside none; 1029 | border: medium none; 1030 | padding: 0px; 1031 | } 1032 | 1033 | div.toc li.level1 { 1034 | margin-left: 0px; 1035 | } 1036 | 1037 | div.toc li.level2 { 1038 | margin-left: 15px; 1039 | } 1040 | 1041 | div.toc li.level3 { 1042 | margin-left: 30px; 1043 | } 1044 | 1045 | div.toc li.level4 { 1046 | margin-left: 45px; 1047 | } 1048 | 1049 | .inherit_header { 1050 | font-weight: bold; 1051 | } 1052 | 1053 | .inherit_header td { 1054 | padding: 6px 0px 2px 5px; 1055 | } 1056 | 1057 | .inherit { 1058 | display: none; 1059 | } 1060 | 1061 | tr.heading h2 { 1062 | margin-top: 12px; 1063 | margin-bottom: 4px; 1064 | } 1065 | 1066 | /* tooltip related style info */ 1067 | 1068 | .ttc { 1069 | position: absolute; 1070 | display: none; 1071 | } 1072 | 1073 | .footerStyle { 1074 | text-align: center; 1075 | padding: 10px; 1076 | padding-top: 20px; 1077 | vertical-align: bottom; 1078 | } 1079 | 1080 | 1081 | #powerTip { 1082 | cursor: default; 1083 | white-space: nowrap; 1084 | background-color: white; 1085 | border: 1px solid gray; 1086 | border-radius: 4px 4px 4px 4px; 1087 | display: none; 1088 | font-size: smaller; 1089 | max-width: 80%; 1090 | opacity: 0.9; 1091 | padding: 1ex 1em 1em; 1092 | position: absolute; 1093 | z-index: 2147483647; 1094 | } 1095 | 1096 | #powerTip div.ttdoc { 1097 | color: grey; 1098 | font-style: italic; 1099 | } 1100 | 1101 | #powerTip div.ttname a { 1102 | font-weight: bold; 1103 | } 1104 | 1105 | #powerTip div.ttname { 1106 | font-weight: bold; 1107 | } 1108 | 1109 | #powerTip div.ttdeci { 1110 | color: #006318; 1111 | } 1112 | 1113 | #powerTip div { 1114 | margin: 0px; 1115 | padding: 0px; 1116 | font: 12px/16px Roboto,sans-serif; 1117 | } 1118 | 1119 | #powerTip:before, #powerTip:after { 1120 | content: ""; 1121 | position: absolute; 1122 | margin: 0px; 1123 | } 1124 | 1125 | #powerTip.n:after, #powerTip.n:before, 1126 | #powerTip.s:after, #powerTip.s:before, 1127 | #powerTip.w:after, #powerTip.w:before, 1128 | #powerTip.e:after, #powerTip.e:before, 1129 | #powerTip.ne:after, #powerTip.ne:before, 1130 | #powerTip.se:after, #powerTip.se:before, 1131 | #powerTip.nw:after, #powerTip.nw:before, 1132 | #powerTip.sw:after, #powerTip.sw:before { 1133 | border: solid transparent; 1134 | content: " "; 1135 | height: 0; 1136 | width: 0; 1137 | position: absolute; 1138 | } 1139 | 1140 | #powerTip.n:after, #powerTip.s:after, 1141 | #powerTip.w:after, #powerTip.e:after, 1142 | #powerTip.nw:after, #powerTip.ne:after, 1143 | #powerTip.sw:after, #powerTip.se:after { 1144 | border-color: rgba(255, 255, 255, 0); 1145 | } 1146 | 1147 | #powerTip.n:before, #powerTip.s:before, 1148 | #powerTip.w:before, #powerTip.e:before, 1149 | #powerTip.nw:before, #powerTip.ne:before, 1150 | #powerTip.sw:before, #powerTip.se:before { 1151 | border-color: rgba(128, 128, 128, 0); 1152 | } 1153 | 1154 | #powerTip.n:after, #powerTip.n:before, 1155 | #powerTip.ne:after, #powerTip.ne:before, 1156 | #powerTip.nw:after, #powerTip.nw:before { 1157 | top: 100%; 1158 | } 1159 | 1160 | #powerTip.n:after, #powerTip.ne:after, #powerTip.nw:after { 1161 | border-top-color: #ffffff; 1162 | border-width: 10px; 1163 | margin: 0px -10px; 1164 | } 1165 | #powerTip.n:before { 1166 | border-top-color: #808080; 1167 | border-width: 11px; 1168 | margin: 0px -11px; 1169 | } 1170 | #powerTip.n:after, #powerTip.n:before { 1171 | left: 50%; 1172 | } 1173 | 1174 | #powerTip.nw:after, #powerTip.nw:before { 1175 | right: 14px; 1176 | } 1177 | 1178 | #powerTip.ne:after, #powerTip.ne:before { 1179 | left: 14px; 1180 | } 1181 | 1182 | #powerTip.s:after, #powerTip.s:before, 1183 | #powerTip.se:after, #powerTip.se:before, 1184 | #powerTip.sw:after, #powerTip.sw:before { 1185 | bottom: 100%; 1186 | } 1187 | 1188 | #powerTip.s:after, #powerTip.se:after, #powerTip.sw:after { 1189 | border-bottom-color: #ffffff; 1190 | border-width: 10px; 1191 | margin: 0px -10px; 1192 | } 1193 | 1194 | #powerTip.s:before, #powerTip.se:before, #powerTip.sw:before { 1195 | border-bottom-color: #808080; 1196 | border-width: 11px; 1197 | margin: 0px -11px; 1198 | } 1199 | 1200 | #powerTip.s:after, #powerTip.s:before { 1201 | left: 50%; 1202 | } 1203 | 1204 | #powerTip.sw:after, #powerTip.sw:before { 1205 | right: 14px; 1206 | } 1207 | 1208 | #powerTip.se:after, #powerTip.se:before { 1209 | left: 14px; 1210 | } 1211 | 1212 | #powerTip.e:after, #powerTip.e:before { 1213 | left: 100%; 1214 | } 1215 | #powerTip.e:after { 1216 | border-left-color: #ffffff; 1217 | border-width: 10px; 1218 | top: 50%; 1219 | margin-top: -10px; 1220 | } 1221 | #powerTip.e:before { 1222 | border-left-color: #808080; 1223 | border-width: 11px; 1224 | top: 50%; 1225 | margin-top: -11px; 1226 | } 1227 | 1228 | #powerTip.w:after, #powerTip.w:before { 1229 | right: 100%; 1230 | } 1231 | #powerTip.w:after { 1232 | border-right-color: #ffffff; 1233 | border-width: 10px; 1234 | top: 50%; 1235 | margin-top: -10px; 1236 | } 1237 | #powerTip.w:before { 1238 | border-right-color: #808080; 1239 | border-width: 11px; 1240 | top: 50%; 1241 | margin-top: -11px; 1242 | } 1243 | 1244 | @media print 1245 | { 1246 | #top { display: none; } 1247 | #side-nav { display: none; } 1248 | #nav-path { display: none; } 1249 | body { overflow:visible; } 1250 | h1, h2, h3, h4, h5, h6 { page-break-after: avoid; } 1251 | .summary { display: none; } 1252 | .memitem { page-break-inside: avoid; } 1253 | #doc-content 1254 | { 1255 | margin-left:0 !important; 1256 | height:auto !important; 1257 | width:auto !important; 1258 | overflow:inherit; 1259 | display:inline; 1260 | } 1261 | } 1262 | -------------------------------------------------------------------------------- /doc/theme/footer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 |
13 |

The documentation was generated by Doxygen

14 |

Copyright © 2015 Geequlim. All rights reserved.

15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /doc/theme/header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | $projectname: $title 9 | $title 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | $treeview 19 | $search 20 | $mathjax 21 | 22 | $extrastylesheet 23 | 24 | 25 |
26 | 27 |
28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 41 | 42 | 43 | 44 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 |
36 |
$projectname 37 |  $projectnumber 38 |
39 |
$projectbrief
40 |
45 |
$projectbrief
46 |
$searchbox
57 |
58 | 59 | 60 | -------------------------------------------------------------------------------- /screenshot/Screenshot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Geequlim/NanoCanvas/69425bfa119fd5b352609c4da7a736cbd8ff6337/screenshot/Screenshot1.png -------------------------------------------------------------------------------- /src/Canvas.cpp: -------------------------------------------------------------------------------- 1 | #include "NanoCanvas.h" 2 | #include "nanovg.h" 3 | 4 | namespace NanoCanvas 5 | { 6 | 7 | NVGcolor nvgColor(const Color& color) 8 | { 9 | return nvgRGBA(color.r,color.g,color.b,color.a); 10 | } 11 | 12 | NVGpaint nvgPaint(Canvas& canvas,const Paint& paint) 13 | { 14 | NVGpaint nvgPaint; 15 | switch(paint.type) 16 | { 17 | case Paint::Type::Linear: 18 | { 19 | float x0 = paint.xx; 20 | float y0 = paint.yy; 21 | float x1 = paint.aa; 22 | float y1 = paint.bb; 23 | canvas.local2Global(x0,y0); 24 | canvas.local2Global(x1,y1); 25 | nvgPaint = nvgLinearGradient(canvas.nvgContext(),x0,y0,x1,y1, 26 | nvgColor(paint.sColor), 27 | nvgColor(paint.eColor)); 28 | } 29 | break; 30 | case Paint::Type::Box: 31 | { 32 | float x = paint.xx; 33 | float y = paint.yy; 34 | canvas.local2Global(x,y); 35 | nvgPaint = nvgBoxGradient(canvas.nvgContext(),x,y, 36 | paint.aa,paint.bb,paint.cc, 37 | paint.dd,nvgColor(paint.sColor), 38 | nvgColor(paint.eColor)); 39 | } 40 | break; 41 | case Paint::Type::Radial: 42 | { 43 | float cx = paint.xx; 44 | float cy = paint.yy; 45 | canvas.local2Global(cx,cy); 46 | nvgPaint = nvgRadialGradient(canvas.nvgContext(),cx,cy, 47 | paint.aa,paint.bb, 48 | nvgColor(paint.sColor), 49 | nvgColor(paint.eColor)); 50 | } 51 | break; 52 | case Paint::Type::ImagePattern: 53 | { 54 | float ox = paint.xx; 55 | float oy = paint.yy; 56 | canvas.local2Global(ox,oy); 57 | nvgPaint = nvgImagePattern(canvas.nvgContext(),ox,oy, 58 | paint.aa,paint.bb, 59 | paint.cc, 60 | paint.imageID, 61 | paint.dd); 62 | } 63 | break; 64 | case Paint::Type::None: 65 | default: 66 | break; 67 | } 68 | return nvgPaint; 69 | } 70 | 71 | /*----------------- Propoties ---------------------*/ 72 | Canvas::Canvas(NVGcontext* ctx,float width , float height , float scaleRatio) 73 | { 74 | m_nvgCtx = ctx; 75 | m_width = width; 76 | m_height = height; 77 | m_scaleRatio = scaleRatio; 78 | m_xPos = m_yPos = 0; 79 | } 80 | 81 | 82 | /*-------------------- Style Control -------------------*/ 83 | 84 | Canvas& Canvas::globalAlpha(float alpha) 85 | { 86 | nvgGlobalAlpha(m_nvgCtx,alpha); 87 | return *this; 88 | } 89 | 90 | Canvas& Canvas::lineCap(LineCap cap) 91 | { 92 | int nvgCap = NVG_BUTT; 93 | if ( cap == LineCap::SQUARE ) 94 | nvgCap = NVG_SQUARE; 95 | else if ( cap == LineCap::ROUND) 96 | nvgCap = NVG_ROUND; 97 | nvgLineCap(m_nvgCtx,nvgCap); 98 | return *this; 99 | } 100 | 101 | Canvas& Canvas::lineJoin(LineJoin join) 102 | { 103 | int nvgJoin = NVG_BEVEL; 104 | if ( join == LineJoin::ROUND ) 105 | nvgJoin = NVG_ROUND; 106 | else if ( join == LineJoin::MITER) 107 | nvgJoin = NVG_MITER; 108 | nvgLineJoin(m_nvgCtx,nvgJoin); 109 | return *this; 110 | } 111 | 112 | Canvas& Canvas::lineWidth(float width) 113 | { 114 | nvgStrokeWidth(m_nvgCtx,width); 115 | return *this; 116 | } 117 | 118 | Canvas& Canvas::miterLimit(float limit) 119 | { 120 | nvgMiterLimit(m_nvgCtx,limit); 121 | return *this; 122 | } 123 | 124 | 125 | Canvas& Canvas::fillStyle(const Color& color) 126 | { 127 | nvgFillColor(m_nvgCtx,nvgRGBA(color.r,color.g,color.b,color.a)); 128 | return *this; 129 | } 130 | 131 | Canvas& Canvas::fillStyle(const Paint& paint) 132 | { 133 | if (paint.type != Paint::Type::None ) 134 | { 135 | NVGpaint npaint = nvgPaint(*this,paint); 136 | nvgFillPaint(m_nvgCtx,npaint); 137 | } 138 | return *this; 139 | } 140 | 141 | Canvas& Canvas::strokeStyle(const Paint& paint) 142 | { 143 | if (paint.type != Paint::Type::None ) 144 | { 145 | NVGpaint npaint = nvgPaint(*this,paint); 146 | nvgStrokePaint(m_nvgCtx,npaint); 147 | } 148 | return *this; 149 | } 150 | 151 | Canvas& Canvas::strokeStyle(const Color& color) 152 | { 153 | nvgStrokeColor(m_nvgCtx,nvgRGBA(color.r,color.g,color.b,color.a)); 154 | return *this; 155 | } 156 | 157 | Paint Canvas::createLinearGradient(float x0,float y0,float x1,float y1, 158 | const Color& scolor , const Color& ecolor) 159 | { 160 | Paint gdt; 161 | gdt.type = Paint::Type::Linear; 162 | gdt.xx = x0; 163 | gdt.yy = y0; 164 | gdt.aa = x1; 165 | gdt.bb = y1; 166 | gdt.sColor = scolor; 167 | gdt.eColor = ecolor; 168 | return gdt; 169 | } 170 | 171 | Paint Canvas::createRadialGradient(float cx,float cy,float r1,float r2, 172 | const Color& icolor , const Color& ocolor) 173 | { 174 | Paint gdt; 175 | gdt.type = Paint::Type::Radial; 176 | gdt.xx = cx; 177 | gdt.yy = cy; 178 | gdt.aa = r1; 179 | gdt.bb = r2; 180 | gdt.sColor = icolor; 181 | gdt.eColor = ocolor; 182 | return gdt; 183 | } 184 | 185 | Paint Canvas::createBoxGradient(float x, float y, float w, float h, 186 | float r, float f, Color icol, Color ocol) 187 | { 188 | Paint gdt; 189 | gdt.type = Paint::Type::Box; 190 | gdt.xx = x; 191 | gdt.yy = y; 192 | gdt.aa = w; 193 | gdt.bb = h; 194 | gdt.cc = r; 195 | gdt.dd = f; 196 | gdt.sColor = icol; 197 | gdt.eColor = ocol; 198 | return gdt; 199 | } 200 | 201 | Paint Canvas::createPattern(const Image& image,float ox, float oy, 202 | float w, float h,float angle, float alpha) 203 | { 204 | Paint gdt; 205 | gdt.type = Paint::Type::ImagePattern; 206 | gdt.imageID = image.imageID; 207 | gdt.xx = ox; 208 | gdt.yy = oy; 209 | gdt.aa = w; 210 | gdt.bb = h; 211 | gdt.cc = angle; 212 | gdt.dd = alpha; 213 | return gdt; 214 | } 215 | 216 | Canvas& Canvas::font(const Font& font) 217 | { 218 | if(font.valid()) 219 | nvgFontFaceId(m_nvgCtx,font.face); 220 | return *this; 221 | } 222 | 223 | Canvas& Canvas::font(float size) 224 | { 225 | nvgFontSize(m_nvgCtx,size); 226 | return *this; 227 | } 228 | 229 | Canvas& Canvas::textAlign( HorizontalAlign hAlign,VerticalAlign vAlign) 230 | { 231 | nvgTextAlign(m_nvgCtx,hAlign|vAlign); 232 | return *this; 233 | } 234 | 235 | void applyTextStyle(Canvas& canvas,const TextStyle& textStyle ) 236 | { 237 | if( textStyle.face>=0 ) 238 | nvgFontFaceId(canvas.nvgContext(),textStyle.face); 239 | if( !std::isnan(textStyle.lineHeight) ) 240 | nvgTextLineHeight(canvas.nvgContext(),textStyle.lineHeight); 241 | if( !std::isnan(textStyle.blur) ) 242 | nvgFontBlur(canvas.nvgContext(),textStyle.blur); 243 | if( !std::isnan(textStyle.letterSpace)) 244 | nvgTextLetterSpacing(canvas.nvgContext(),textStyle.letterSpace); 245 | nvgTextAlign(canvas.nvgContext(),textStyle.hAlign|textStyle.vAlign); 246 | nvgFontSize(canvas.nvgContext(),textStyle.size); 247 | } 248 | 249 | Canvas& Canvas::fillStyle(const TextStyle& textStyle) 250 | { 251 | applyTextStyle(*this,textStyle); 252 | nvgFillColor(m_nvgCtx,nvgColor(textStyle.color)); 253 | return *this; 254 | } 255 | 256 | float Canvas::measureText(const string& text,float rowWidth) 257 | { 258 | float width = 0; 259 | if( std::isnan(rowWidth)) 260 | width = nvgTextBounds(m_nvgCtx,0,0,text.c_str(),nullptr,nullptr); 261 | else 262 | { 263 | float bouds[4]{0}; 264 | width = measureText(text,0,0,bouds,rowWidth); 265 | } 266 | return width; 267 | } 268 | 269 | float Canvas::measureText(const string& text,float x,float y, 270 | float* bounds,float rowWidth) 271 | { 272 | local2Global(x,y); 273 | if( std::isnan(rowWidth)) 274 | nvgTextBounds(m_nvgCtx,x,y,text.c_str(),nullptr,bounds); 275 | else 276 | nvgTextBoxBounds(m_nvgCtx,x,y,rowWidth,text.c_str(),nullptr,bounds); 277 | float width = 0; 278 | if( bounds ) 279 | width = bounds[2] - bounds[0]; 280 | return width; 281 | } 282 | 283 | /* ------------------- Basic Path ----------------------*/ 284 | 285 | Canvas& Canvas::moveTo(float x,float y) 286 | { 287 | local2Global(x,y); 288 | nvgMoveTo(m_nvgCtx,x,y); 289 | return *this; 290 | } 291 | 292 | Canvas& Canvas::lineTo(float x,float y) 293 | { 294 | local2Global(x,y); 295 | nvgLineTo(m_nvgCtx,x,y); 296 | return *this; 297 | } 298 | 299 | Canvas& Canvas::arcTo(float x1,float y1,float x2,float y2,float r) 300 | { 301 | local2Global(x1,y1); 302 | local2Global(x2,y2); 303 | nvgArcTo(m_nvgCtx,x1,y1,x2,y2,r); 304 | return *this; 305 | } 306 | 307 | Canvas& Canvas::quadraticCurveTo(float cpx,float cpy,float x, float y) 308 | { 309 | local2Global(cpx,cpy); 310 | local2Global(x,y); 311 | nvgQuadTo(m_nvgCtx,cpx,cpy,x,y); 312 | return *this; 313 | } 314 | 315 | Canvas& Canvas::bezierCurveTo(float cp1x,float cp1y, 316 | float cp2x,float cp2y, 317 | float x, float y) 318 | { 319 | local2Global(cp1x,cp1y); 320 | local2Global(cp2x,cp2y); 321 | local2Global(x,y); 322 | nvgBezierTo(m_nvgCtx,cp1x,cp1y,cp2x,cp2y,x,y); 323 | return *this; 324 | } 325 | 326 | Canvas& Canvas::arc(float x,float y,float r, 327 | float sAngle,float eAngle,bool counterclockwise) 328 | { 329 | local2Global(x,y); 330 | int dir = counterclockwise? NVG_CCW : NVG_CW; 331 | nvgArc(m_nvgCtx,x,y,r,sAngle,eAngle,dir); 332 | return *this; 333 | } 334 | 335 | 336 | Canvas& Canvas::closePath() 337 | { 338 | nvgClosePath(m_nvgCtx); 339 | return *this; 340 | } 341 | 342 | 343 | /* ------------------- Advance Path --------------------*/ 344 | 345 | 346 | Canvas& Canvas::rect(float x,float y,float w,float h) 347 | { 348 | local2Global(x,y); 349 | nvgRect(m_nvgCtx,x,y,w,h); 350 | return *this; 351 | } 352 | 353 | Canvas& Canvas::roundedRect(float x,float y,float w,float h,float r) 354 | { 355 | local2Global(x,y); 356 | nvgRoundedRect(m_nvgCtx,x,y,w,h,r); 357 | return *this; 358 | } 359 | 360 | Canvas& Canvas::circle(float cx ,float cy , float r) 361 | { 362 | local2Global(cx,cy); 363 | nvgCircle(m_nvgCtx,cx,cy,r); 364 | return *this; 365 | } 366 | 367 | Canvas& Canvas::ellipse(float cx, float cy, float rx, float ry) 368 | { 369 | local2Global(cx,cy); 370 | nvgEllipse(m_nvgCtx,cx,cy,rx,ry); 371 | return *this; 372 | } 373 | 374 | /* ------------------- Draw Action ---------------------*/ 375 | 376 | Canvas& Canvas::fill() 377 | { 378 | nvgFill(m_nvgCtx); 379 | return *this; 380 | } 381 | 382 | Canvas& Canvas::stroke() 383 | { 384 | nvgStroke(m_nvgCtx); 385 | return *this; 386 | } 387 | 388 | Canvas& Canvas::fillRect(float x,float y,float w,float h) 389 | { 390 | local2Global(x,y); 391 | nvgBeginPath(m_nvgCtx); 392 | nvgRect(m_nvgCtx,x,y,w,h); 393 | nvgFill(m_nvgCtx); 394 | return *this; 395 | } 396 | 397 | Canvas& Canvas::strokeRect(float x,float y,float w,float h) 398 | { 399 | local2Global(x,y); 400 | nvgBeginPath(m_nvgCtx); 401 | nvgRect(m_nvgCtx,x,y,w,h); 402 | nvgStroke(m_nvgCtx); 403 | return *this; 404 | } 405 | 406 | Canvas& Canvas::clearColor(const Color& color) 407 | { 408 | nvgCancelFrame(m_nvgCtx); 409 | nvgFillColor(m_nvgCtx,nvgRGBA(color.r,color.g,color.b,color.a)); 410 | nvgBeginPath(m_nvgCtx); 411 | nvgRect(m_nvgCtx,m_xPos,m_yPos,m_width,m_height); 412 | nvgFill(m_nvgCtx); 413 | 414 | return *this; 415 | } 416 | 417 | Canvas& Canvas::fillText(const string& text,float x,float y,float rowWidth) 418 | { 419 | if(text.length()) 420 | { 421 | local2Global(x,y); 422 | if( std::isnan(rowWidth) ) 423 | nvgText(m_nvgCtx,x,y,text.c_str(),nullptr); 424 | else 425 | nvgTextBox(m_nvgCtx,x,y,rowWidth,text.c_str(),nullptr); 426 | } 427 | return *this; 428 | } 429 | 430 | Canvas& Canvas::drawImage(Image& image,float x,float y, 431 | float width,float height, 432 | float sx,float sy,float swidth,float sheight) 433 | { 434 | if(image.valid()) 435 | { 436 | save(); 437 | 438 | local2Global(x,y); 439 | int w,h; 440 | image.size(w,h); 441 | 442 | if( std::isnan(swidth) ) 443 | swidth = w - sx; 444 | if( std::isnan(sheight) ) 445 | sheight = h - sy; 446 | if( std::isnan(width) ) 447 | width = swidth; 448 | if( std::isnan(height) ) 449 | height = sheight; 450 | 451 | resetClip(); 452 | clip(x,y,width,height); 453 | 454 | float sw = width / swidth; 455 | float sh = height / sheight; 456 | float rx,ry,rw,rh; 457 | rw = w * sw; 458 | rh = h * sh; 459 | rx = x - sx*sw; 460 | ry = y - sy*sh; 461 | 462 | Paint pattern = createPattern(image,rx,ry,rw,rh,0,1.0f); 463 | fillStyle(pattern); 464 | rect(rx,ry,rw,rh).fill(); 465 | restore(); 466 | } 467 | return *this; 468 | } 469 | 470 | /*------------------- State Handling -----------------*/ 471 | 472 | Canvas& Canvas::save() 473 | { 474 | nvgSave(m_nvgCtx); 475 | return *this; 476 | } 477 | 478 | Canvas& Canvas::restore() 479 | { 480 | nvgRestore(m_nvgCtx); 481 | return *this; 482 | } 483 | 484 | Canvas& Canvas::reset() 485 | { 486 | nvgReset(m_nvgCtx); 487 | return *this; 488 | } 489 | 490 | /*--------------------- Transformations ----------------*/ 491 | 492 | Canvas& Canvas::scale(float scalewidth , float scaleheight) 493 | { 494 | nvgScale(m_nvgCtx,scalewidth,scaleheight); 495 | return *this; 496 | } 497 | 498 | Canvas& Canvas::rotate(float angle) 499 | { 500 | nvgRotate(m_nvgCtx,angle); 501 | return *this; 502 | } 503 | 504 | Canvas& Canvas::translate(float x,float y) 505 | { 506 | nvgTranslate(m_nvgCtx,x,y); 507 | return *this; 508 | } 509 | 510 | Canvas& Canvas::transform(float a, float b, float c, 511 | float d, float e, float f) 512 | { 513 | nvgTransform(m_nvgCtx,a,b,c,d,e,f); 514 | return *this; 515 | } 516 | 517 | Canvas& Canvas::setTransform(float a, float b, float c, 518 | float d, float e, float f) 519 | { 520 | nvgResetTransform(m_nvgCtx); 521 | nvgTransform(m_nvgCtx,a,b,c,d,e,f); 522 | return *this; 523 | } 524 | 525 | Canvas& Canvas::restTransform() 526 | { 527 | nvgResetTransform(m_nvgCtx); 528 | return *this; 529 | } 530 | 531 | /*---------------- Canvas Control -----------------*/ 532 | Canvas& Canvas::begineFrame(int windowWidth, int windowHeight) 533 | { 534 | nvgBeginFrame(m_nvgCtx,windowWidth,windowHeight,m_scaleRatio); 535 | // Clip out side area 536 | nvgScissor(m_nvgCtx,m_xPos,m_yPos,m_width,m_height); 537 | 538 | return *this; 539 | } 540 | 541 | Canvas& Canvas::cancelFrame() 542 | { 543 | nvgCancelFrame(m_nvgCtx); 544 | return *this; 545 | } 546 | 547 | void Canvas::endFrame() 548 | { 549 | nvgEndFrame(m_nvgCtx); 550 | } 551 | 552 | Canvas& Canvas::beginPath() 553 | { 554 | nvgBeginPath(m_nvgCtx); 555 | return *this; 556 | } 557 | 558 | Canvas& Canvas::pathWinding( Winding dir) 559 | { 560 | int windingDir = NVG_CW; 561 | if ( dir == Winding::CCW) 562 | windingDir = NVG_CCW; 563 | nvgPathWinding(m_nvgCtx, windingDir); 564 | return *this; 565 | } 566 | 567 | Canvas& Canvas::clip(float x,float y,float w,float h) 568 | { 569 | local2Global(x,y); 570 | nvgIntersectScissor(m_nvgCtx,x,y,w,h); 571 | return *this; 572 | } 573 | 574 | Canvas& Canvas::resetClip() 575 | { 576 | nvgResetScissor(m_nvgCtx); 577 | return *this; 578 | } 579 | } 580 | -------------------------------------------------------------------------------- /src/Canvas.h: -------------------------------------------------------------------------------- 1 | #ifndef CANVAS_H 2 | #define CANVAS_H 3 | 4 | #include 5 | class NVGcontext; 6 | 7 | namespace NanoCanvas 8 | { 9 | using namespace TextAlign; 10 | 11 | /** 12 | * @class Canvas 13 | * @author Geequlim 14 | * @file Canvas.h 15 | * @brief The HTML5's Canvas liked render API writing in C++11 based on NanoVG 16 | */ 17 | class Canvas 18 | { 19 | public: 20 | enum class Winding 21 | { 22 | /// Counter clock wise 23 | CCW = 1, 24 | /// Clock wise 25 | CW = 2, 26 | }; 27 | 28 | /// Line cap style 29 | enum class LineCap 30 | { 31 | /// A flat edge is added to each end of the line 32 | BUTT, 33 | /// A rounded end cap is added to each end of the line 34 | ROUND, 35 | /// A square end cap is added to each end of the line 36 | SQUARE 37 | 38 | }; 39 | 40 | /// Line join style 41 | enum class LineJoin 42 | { 43 | /// Creates a beveled corner 44 | BEVEL, 45 | /// Creates a rounded corner 46 | ROUND, 47 | /// Creates a sharp corner 48 | MITER 49 | }; 50 | 51 | /** 52 | * @brief Construct a canvas with NanoVG Context 53 | * @param ctx The NanoVG Context used for this canvas 54 | * @param width The width of the canvas, in pixels 55 | * @param height The height of the canvas, in pixels 56 | * @param scaleRatio The device pixel ration 57 | */ 58 | Canvas(NVGcontext* ctx,float width , float height , float scaleRatio =1.0f); 59 | 60 | /* ------------------- Basic Path ----------------------*/ 61 | 62 | /** 63 | * @brief Moves the path to the specified point in the canvas, without creating a line 64 | * 65 | * The moveTo() method moves the path to the specified point in the canvas, without creating a line. 66 | * 67 | * @param x The x-coordinate of where to move the path to 68 | * @param y The y-coordinate of where to move the path to 69 | * @return The Canvas to operate with 70 | */ 71 | Canvas& moveTo(float x,float y); 72 | 73 | /** 74 | * @brief Adds a new point and creates a line from that point to the last specified point in the canvas 75 | * 76 | * The lineTo() method adds a new point and creates a line from that point to the last specified point in the canvas (this method does not draw the line). 77 | * 78 | * @param x The x-coordinate of where to create the line to 79 | * @param y The y-coordinate of where to create the line to 80 | * @return The Canvas to operate with 81 | */ 82 | Canvas& lineTo(float x,float y); 83 | 84 | /** 85 | * @brief Creates an arc/curve between two tangents on the canvas. 86 | * @param x1 The x-coordinate of the first tangent 87 | * @param y1 The y-coordinate of the first tangent 88 | * @param x2 The x-coordinate of the second tangent 89 | * @param y2 The y-coordinate of the second tangent 90 | * @param r The radius of the arc 91 | * @return The Canvas to operate with 92 | */ 93 | Canvas& arcTo(float x1,float y1,float x2,float y2,float r); 94 | 95 | /** 96 | * @brief Creates a quadratic Bézier curve 97 | * 98 | * The quadraticCurveTo() method adds a point to the current path by using the specified control points that represent a quadratic Bézier curve.@n 99 | * A quadratic Bézier curve requires two points. 100 | * The first point is a control point that is used in the quadratic Bézier calculation and the second point is the ending point for the curve. 101 | * The starting point for the curve is the last point in the current path. If a path does not exist, use the beginPath() and moveTo() methods to define a starting point. 102 | * 103 | * @param cpx The x-coordinate of the Bézier control point 104 | * @param cpy The y-coordinate of the Bézier control point 105 | * @param x The x-coordinate of the ending point 106 | * @param y The y-coordinate of the ending point 107 | * @return The Canvas to operate with 108 | */ 109 | Canvas& quadraticCurveTo(float cpx,float cpy,float x, float y); 110 | 111 | /** 112 | * @brief Creates a cubic Bézier curve 113 | * 114 | * The bezierCurveTo() method adds a point to the current path by using the specified control points that represent a cubic Bézier curve. 115 | * @n 116 | * A cubic bezier curve requires three points. 117 | * The first two points are control points that are used in the cubic Bézier calculation and the last point is the ending point for the curve. 118 | * The starting point for the curve is the last point in the current path. If a path does not exist, use the beginPath() and moveTo() methods to define a starting point. 119 | * 120 | * @param cp1x The x-coordinate of the first Bézier control point 121 | * @param cp1y The y-coordinate of the first Bézier control point 122 | * @param cp2x The x-coordinate of the second Bézier control point 123 | * @param cp2y The y-coordinate of the second Bézier control point 124 | * @param x The x-coordinate of the ending point 125 | * @param y The y-coordinate of the ending point 126 | * @return The Canvas to operate with 127 | */ 128 | Canvas& bezierCurveTo(float cp1x,float cp1y, 129 | float cp2x,float cp2y, 130 | float x, float y); 131 | 132 | /** 133 | * @brief Creates an arc/curve (used to create circles, or parts of circles) 134 | * The arc() method creates an arc/curve (used to create circles, or parts of circles). 135 | * @note Tip: To create a circle with arc(): Set start angle to 0 and end angle to 2*π. 136 | * @param x The x-coordinate of the center of the circle 137 | * @param y The y-coordinate of the center of the circle 138 | * @param r The radius of the circle 139 | * @param sAngle The starting angle, in radians (0 is at the 3 o'clock position of the arc's circle) 140 | * @param eAngle The ending angle, in radians 141 | * @param counterclockwise Optional. Specifies whether the drawing should be counterclockwise or clockwise. False is default, and indicates clockwise, while true indicates counter-clockwise. 142 | * @return 143 | */ 144 | Canvas& arc(float x,float y,float r, 145 | float sAngle,float eAngle,bool counterclockwise = false); 146 | 147 | /** 148 | * @brief Close current path with a line segment 149 | * @return The canvas to operate with 150 | */ 151 | Canvas& closePath(); 152 | 153 | 154 | /* ------------------- Advance Path --------------------*/ 155 | 156 | /** 157 | * @brief Creates a rectangle 158 | * 159 | * The rect() method creates a rectangle. 160 | * 161 | * @param x The x-coordinate of the upper-left corner of the rectangle 162 | * @param y The y-coordinate of the upper-left corner of the rectangle 163 | * @param w The width of the rectangle, in pixels 164 | * @param h The height of the rectangle, in pixels 165 | * @return The canvas which the path be added to 166 | */ 167 | Canvas& rect(float x,float y,float w,float h); 168 | 169 | /** 170 | * @brief Creates a rounded rectangle 171 | * @param x The x-coordinate of the upper-left corner of the rectangle 172 | * @param y The y-coordinate of the upper-left corner of the rectangle 173 | * @param w The width of the rectangle, in pixels 174 | * @param h The height of the rectangle, in pixels 175 | * @param r The radius of the circle formed by 4 corners of the rounded rectangle 176 | * @return The canvas to create path 177 | */ 178 | Canvas& roundedRect(float x,float y,float w,float h,float r); 179 | 180 | /** 181 | * @brief Creates a circle 182 | * @param cx The x-coordinate of center point for the circle 183 | * @param cy The y-coordinate of center point for the circle 184 | * @param r The radius of the circle 185 | * @return The canvas to create path 186 | */ 187 | Canvas& circle(float cx ,float cy , float r); 188 | 189 | /** 190 | * @brief Creates an ellipse 191 | * @param cx The x-coordinate of center point for the ellipse 192 | * @param cy The x-coordinate of center point for the ellipse 193 | * @param rx The radius of the ellipse in horizentoal 194 | * @param ry The radius of the ellipse in vertical 195 | * @return The canvas to create path 196 | */ 197 | Canvas& ellipse(float cx, float cy, float rx, float ry); 198 | 199 | /* ------------------- Draw Action ---------------------*/ 200 | 201 | /** 202 | * @brief Fills the current drawing (path) 203 | * 204 | * The fill() method fills the current drawing (path). The default color is black. 205 | * 206 | * @note If the path is not closed, the fill() method will add a line from the last point to the startpoint of the path to close the path (like closePath()), and then fill the path. 207 | * @return The canvas to fill 208 | */ 209 | Canvas& fill(); 210 | 211 | /** 212 | * @brief Actually draws the path you have defined 213 | * 214 | * The stroke() method actually draws the path you have defined with all those moveTo() and lineTo() methods. The default color is black. 215 | * 216 | * @return The canvas to stroke 217 | */ 218 | Canvas& stroke(); 219 | 220 | /** 221 | * @brief Draws a "filled" rectangle 222 | * 223 | * The fillRect() method draws a "filled" rectangle. The default color of the fill is black. 224 | * 225 | * @param x The x-coordinate of the upper-left corner of the rectangle 226 | * @param y The y-coordinate of the upper-left corner of the rectangle 227 | * @param w The width of the rectangle, in pixels 228 | * @param h The height of the rectangle, in pixels 229 | * @return The canvas to draw 230 | */ 231 | Canvas& fillRect(float x,float y,float w,float h); 232 | 233 | /** 234 | * @brief Draws a rectangle (no fill) 235 | * 236 | * The strokeRect() method draws a rectangle (no fill). The default color of the stroke is black. 237 | * 238 | * @param x The x-coordinate of the upper-left corner of the rectangle 239 | * @param y The y-coordinate of the upper-left corner of the rectangle 240 | * @param w The width of the rectangle, in pixels 241 | * @param h The height of the rectangle, in pixels 242 | * @return The canvas to draw 243 | */ 244 | Canvas& strokeRect(float x,float y,float w,float h); 245 | 246 | /** 247 | * @brief Clear the canvas with color 248 | * @param color The color to fill the hole canvas 249 | * @return The canvas to operate with 250 | */ 251 | Canvas& clearColor(const Color& color); 252 | 253 | 254 | /** 255 | * @brief Draws "filled" text on the canvas 256 | * @param text Specifies the text that will be written on the canvas 257 | * @param x The x coordinate where to start painting the text (relative to the canvas) 258 | * @param y The y coordinate where to start painting the text (relative to the canvas) 259 | * @param rowWidth The max row width of the text box,NAN is not limited 260 | * @return The canvas to operate with 261 | */ 262 | Canvas& fillText(const string& text,float x,float y,float rowWidth = NAN); 263 | 264 | /** 265 | * @brief Draws an image onto the canvas 266 | * 267 | * The drawImage() method can also draw parts of an image, and/or increase/reduce the image size. 268 | * 269 | * @param image Specifies the image to use 270 | * @param x The x coordinate where to place the image on the canvas 271 | * @param y The y coordinate where to place the image on the canvas 272 | * @param width The width of the image to use (stretch or reduce the image),NAN as the default be the same as wdith of the clipped area 273 | * @param height The height of the image to use (stretch or reduce the image),NAN as the default be the same as wdith of the clipped area 274 | * @param sx The x coordinate where to start clipping,0 as the default 275 | * @param sy The y coordinate where to start clipping,0 as the default 276 | * @param swidth The wdith of the clipped image,NAN as defualt to clip to right side of the image 277 | * @param sheight The height of the clipped image,NAN as defualt to clip to bottom side of the image 278 | * @return The canvas to draw this image 279 | */ 280 | Canvas& drawImage(Image& image,float x,float y, 281 | float width = NAN,float height = NAN, 282 | float sx = 0,float sy = 0, 283 | float swidth = NAN,float sheight = NAN); 284 | 285 | /*-------------------- Style Control -------------------*/ 286 | 287 | /** 288 | * @brief Set the style of the end caps for a line 289 | * 290 | * @param cap The line cap style 291 | * @return The canvas to operate with 292 | */ 293 | Canvas& lineCap(LineCap cap); 294 | 295 | /** 296 | * @brief Set the type of corner created, when two lines meet 297 | * @param join The line join style 298 | * @return The canvas to operate with 299 | */ 300 | Canvas& lineJoin(LineJoin join); 301 | 302 | /** 303 | * @brief Set the current line width 304 | * @param width The current line width, in pixels 305 | * @return The canvas to operate with 306 | */ 307 | Canvas& lineWidth(float width); 308 | 309 | /** 310 | * @brief Sets the maximum miter length 311 | * 312 | * The miter length is the distance between the inner corner and the outer corner where two lines meet. 313 | * @n 314 | * The miter length grows bigger as the angle of the corner gets smaller. 315 | * 316 | * @note The miterLimit property works only if the lineJoin attribute is "miter". 317 | * @param limit A positive number that specifies the maximum miter length. If the current miter length exceeds the miterLimit, the corner will display as lineJoin "bevel" 318 | * @return The canvas to operate with 319 | */ 320 | Canvas& miterLimit(float limit); 321 | 322 | /** 323 | * @brief Sets the current alpha or transparency value of the drawing. 324 | * @param alpha new alpha vlaue of canvas 325 | * @return The canvas to operate with 326 | */ 327 | Canvas& globalAlpha(float alpha); 328 | 329 | 330 | /** 331 | * @brief Sets the color to fill the drawing 332 | * @param color The color to fill with 333 | * @return The canvas to operate with 334 | */ 335 | Canvas& fillStyle(const Color& color); 336 | 337 | /** 338 | * @brief Set the gradient or pattern paint used to fill the drawing 339 | * @param paint The paint used to fill the drawing 340 | * @return The canvas to operate with 341 | */ 342 | Canvas& fillStyle(const Paint& paint); 343 | 344 | /** 345 | * @brief Set the color used for strokes. 346 | * @param color Stroke color 347 | * @return The canvas to operate with 348 | */ 349 | Canvas& strokeStyle(const Color& color); 350 | 351 | /** 352 | * @brief Set the gradient or pattern paint used for strokes 353 | * @param paint The paint used to fill the drawing 354 | * @return The canvas to operate with 355 | */ 356 | Canvas& strokeStyle(const Paint& paint); 357 | 358 | 359 | /** 360 | * @brief Set current font for text rendering 361 | * @note If the face of the font is invalid ,it doesn't work 362 | * @see NanoCanvas::Font 363 | * @param font The font to use 364 | * @return The canvas to operate with 365 | */ 366 | Canvas& font(const Font& font); 367 | 368 | /** 369 | * @brief Set font size for current text style. 370 | * @param size The font size 371 | * @return The canvas to operate with 372 | */ 373 | Canvas& font(float size); 374 | 375 | /** 376 | * @brief Sets the text alignment of current text style 377 | * @param hAlign The horizontak alignment 378 | * @param vAlign The verical alignment 379 | * @see TextAlign::HorizontalAlign 380 | * @see TextAlign::VerticalAlign 381 | * @return The canvas to operate with 382 | */ 383 | Canvas& textAlign( HorizontalAlign hAlign,VerticalAlign vAlign); 384 | 385 | /** 386 | * @brief Set styles for text rendering 387 | * @param textStyle The text style to use 388 | * @see NanoCanvas::TextStyle 389 | * @return The canvas to operate with 390 | */ 391 | Canvas& fillStyle(const TextStyle& textStyle); 392 | 393 | /** 394 | * @brief Creates a linear gradient (to use on canvas content) 395 | * @param x0 The x-coordinate of the start point of the gradient 396 | * @param y0 The y-coordinate of the start point of the gradient 397 | * @param x1 The x-coordinate of the end point of the gradient 398 | * @param y1 The y-coordinate of the end point of the gradient 399 | * @param scolor The start color 400 | * @param outter The end color 401 | * @return The created gradient style object. 402 | */ 403 | static Paint createLinearGradient(float x0,float y0,float x1,float y1, 404 | const Color& scolor , const Color& ecolor); 405 | 406 | /** 407 | * @brief Creates a radial/circular gradient (to use on canvas content) 408 | * @param cx The x-coordinate of the circle of the gradient 409 | * @param cy The y-coordinate of the circle of the gradient 410 | * @param r1 The radius of the inner circle 411 | * @param r2 The radius of the outter circle 412 | * @param icolor The color on inner circle 413 | * @param ocolor The color on outer circle 414 | * @return The created gradient style object. 415 | */ 416 | static Paint createRadialGradient(float cx,float cy,float r1,float r2, 417 | const Color& icolor , const Color& ocolor); 418 | 419 | /** 420 | * @brief Creates and returns a box gradient. 421 | * @par Box gradient is a feathered rounded rectangle, it is useful for rendering drop shadows or highlights for boxes. 422 | * @param x The x-coordinate of the upper-left corner of the rectangle 423 | * @param y The y-coordinate of the upper-left corner of the rectangle 424 | * @param w The width of the rectangle, in pixels 425 | * @param h The height of the rectangle, in pixels 426 | * @param r The radius of the circle formed by 4 corners of the rounded rectangle 427 | * @param f How blurry the border of the rectangle is 428 | * @param icol The inner color of the gradient 429 | * @param ocol The outer color of the gradient 430 | * @return The created gradient style object. 431 | */ 432 | static Paint createBoxGradient(float x, float y, float w, float h, 433 | float r, float f, Color icol, Color ocol); 434 | 435 | /** 436 | * @brief Creates and returns an image pattern paint. 437 | * @param image Specifies the image of the pattern to use 438 | * @param ox The x-coordinate of the upper-left corner of the image would be draw 439 | * @param oy The y-coordinate of the upper-left corner of the image would be draw 440 | * @param w The width of the pattern 441 | * @param h The height of the pattern 442 | * @param angle The rotation around the top-left corner in radians 443 | * @param alpha The transparent of the image pattern 444 | * @return The patter paint created 445 | */ 446 | static Paint createPattern(const Image& image,float ox, float oy, 447 | float w, float h,float angle = 0.0f, float alpha = 1.0f); 448 | 449 | /** 450 | * @brief Check the width of the text, before writing it on the canvas 451 | * @param text The text to be measured 452 | * @param rowWidth The max row width of the text box,NAN is not limited 453 | * @return The width of the specified text 454 | */ 455 | float measureText(const string& text,float rowWidth = NAN); 456 | 457 | /** 458 | * @brief Check the boundary of the text, before writing it on the canvas 459 | * @param text The text to be measured 460 | * @param x The x-coordinate of the text 461 | * @param y The y-coordinate of the text 462 | * @param bounds [in] The float array to store boundary values should be a pointer to float[4] 463 | * @param rowWidth The max row width of the text box,NAN is not limited 464 | * @return The width of the specified text 465 | */ 466 | float measureText(const string& text,float x,float y,float* bounds,float rowWidth = NAN); 467 | 468 | 469 | /*--------------------- Transformations ----------------*/ 470 | 471 | /** 472 | * @brief Scales the current drawing, bigger or smaller. 473 | * @note If you scale a drawing, all future drawings will also be scaled. The positioning will also be scaled. 474 | * If you scale(2,2); drawings will be positioned twice as far from the left and top of the canvas as you specify. 475 | * @param scalewidth Scales the width of the current drawing (1=100%, 0.5=50%, 2=200%, etc.) 476 | * @param scaleheight Scales the height of the current drawing (1=100%, 0.5=50%, 2=200%, etc.) 477 | * @return The canvas to scale with 478 | */ 479 | Canvas& scale(float scalewidth , float scaleheight); 480 | 481 | /** 482 | * @brief Rotates the current drawing 483 | * @note: The rotation will only affect drawings made AFTER the rotation is done. 484 | * @par To calculate from degrees to radians: degrees*Math.PI/180. 485 | * @n Example: to rotate 5 degrees, specify the following: 5*Math.PI/180 486 | * @param angle The rotation angle, in radians. 487 | * @return The canvas to rotate with 488 | */ 489 | Canvas& rotate(float angle); 490 | 491 | /** 492 | * @brief Remaps the (0,0) position on the canvas 493 | * @note When you call a method such as fillRect() after translate(), the value is added to the x- and y-coordinate values. 494 | * @param x The value to add to horizontal (x) coordinates 495 | * @param y The value to add to vertical (y) coordinates 496 | * @return The canvas to translate with 497 | */ 498 | Canvas& translate(float x,float y); 499 | 500 | /** 501 | * @brief Replaces the current transformation matrix for the drawing 502 | * @par Each object on the canvas has a current transformation matrix. @n 503 | * The transform() method replaces the current transformation matrix. It multiplies the current transformation matrix with the matrix described by: @n 504 | * 505 | * @li a c e 506 | * @li b d f 507 | * @li 0 0 1 508 | * 509 | * @par In other words, the transform() method lets you scale, rotate, move, and skew the current context. 510 | * @note The transformation will only affect drawings made after the transform() method is called. 511 | * @note The transform() method behaves relatively to other transformations made by rotate(), scale(), translate(), or transform(). Example: If you already have set your drawing to scale by two, and the transform() method scales your drawings by two, your drawings will now scale by four. 512 | * @par Tip: Check out the setTransform() method, which does not behave relatively to other transformations. 513 | * 514 | * @param a Scales the drawing horizontally 515 | * @param b Skew the the drawing horizontally 516 | * @param c Skew the the drawing vertically 517 | * @param d Scales the drawing vertically 518 | * @param e Moves the the drawing horizontally 519 | * @param f Moves the the drawing vertically 520 | * @return The canvas to transform with 521 | */ 522 | Canvas& transform(float a, float b, float c, float d, float e, float f); 523 | 524 | /** 525 | * @brief Resets the current transform to the identity matrix. Then runs transform() 526 | * @param a Scales the drawing horizontally 527 | * @param b Skew the the drawing horizontally 528 | * @param c Skew the the drawing vertically 529 | * @param d Scales the drawing vertically 530 | * @param e Moves the the drawing horizontally 531 | * @param f Moves the the drawing vertically 532 | * @see Canvas::transform() 533 | * @see Canvas::restTransform() 534 | * @return The canvas to set transform with 535 | */ 536 | Canvas& setTransform(float a, float b, float c, float d, float e, float f); 537 | 538 | /** 539 | * @brief Resets the current transform to the identity matrix. 540 | * @return The canvas to set transform with 541 | */ 542 | Canvas& restTransform(); 543 | 544 | /*--------------------- Canvas Control -----------------*/ 545 | /** 546 | * @brief Begin drawing a new frame 547 | * 548 | * Calls to Canvas drawing API should be wrapped in begineFrame() & endFrame() 549 | * begineFrame() defines the size of the window to render to in relation currently 550 | * set viewport (i.e. glViewport on GL backends). 551 | * 552 | * @param windowWidth Width of your window 553 | * @param windowHeight Height of your window 554 | * @return The canvas to begine frame with 555 | */ 556 | Canvas& begineFrame(int windowWidth, int windowHeight); 557 | 558 | /** 559 | * @brief Cancels drawing the current frame. 560 | * @return The canvas to cancle draw 561 | */ 562 | Canvas& cancelFrame(); 563 | 564 | /** @brief Ends drawing flushing remaining render state. */ 565 | void endFrame(); 566 | 567 | /** 568 | * @brief Begins a path, or resets the current path 569 | * @return The canvas to create path 570 | */ 571 | Canvas& beginPath(); 572 | 573 | /** 574 | * @brief Sets the current path winding 575 | * @param dir CVS_CW or CVS_CW 576 | * @return The canvas to operate with 577 | */ 578 | Canvas& pathWinding( Winding dir); 579 | 580 | 581 | /** 582 | * @brief Clip of a rectangular region 583 | * @param x The x-coordinate of the upper-left corner of the clip region 584 | * @param y The y-coordinate of the upper-left corner of the clip region 585 | * @param w The width of the clip region, in pixels 586 | * @param h The width of the clip region, in pixels 587 | * @return The canvas to clip with 588 | */ 589 | Canvas& clip(float x,float y,float w,float h); 590 | 591 | /** 592 | * @brief Reset clip state ,remove all clip region 593 | * @return The canvas to reset 594 | */ 595 | Canvas& resetClip(); 596 | 597 | 598 | 599 | /* --------------------- State NanoVG Handling ------------------- 600 | * 601 | * 602 | * NanoVG contains state which represents how paths will be rendered. 603 | * The state contains transform, fill and stroke styles, text and font styles,and scissor clipping. 604 | * 605 | *-----------------------------------------------------------------*/ 606 | 607 | /** 608 | * @brief Pushe and save the current render state into a state stack. 609 | * @note A matching restore() must be used to restore the state. 610 | * @return The canvas to save state 611 | */ 612 | Canvas& save(); 613 | 614 | /** 615 | * @brief Pop and restore current render state. 616 | * @return The canvas to restore state 617 | */ 618 | Canvas& restore(); 619 | 620 | /** 621 | * @brief Resets current render state to default values. Does not affect the render state stack. 622 | * @return The canvas to reset state 623 | */ 624 | Canvas& reset(); 625 | 626 | 627 | /*------------------ Canvas propoties ---------------------*/ 628 | 629 | /** 630 | * @brief Check is the context avaliable 631 | * @return Is the context avaliable 632 | */ 633 | inline bool valid()const { return m_nvgCtx; } 634 | 635 | /** 636 | * @brief Set canvas size 637 | * @param width The width of the canvas, in pixels 638 | * @param height The height of the canvas, in pixels 639 | * @return The canvas to resize 640 | */ 641 | inline Canvas& setSize(float width,float height) 642 | { 643 | m_width = width; 644 | m_height = height; 645 | return *this; 646 | } 647 | 648 | /** 649 | * @brief Set position of the canvas 650 | * @param x The x-coordinate of the upper-left corner of the rectangle 651 | * @param y The y-coordinate of the upper-left corner of the rectangle 652 | * @return The canvas to change position 653 | */ 654 | inline Canvas& setPosition(float x , float y) 655 | { 656 | m_xPos = x; 657 | m_yPos = y; 658 | return *this; 659 | } 660 | 661 | /** 662 | * @brief Set scale ration of the canvas 663 | * 664 | * Device pixel ration allows to control the rendering on Hi-DPI devices. 665 | * For example, GLFW returns two dimension for an opened window: window size and 666 | * frame buffer size. In that case you would set windowWidth/Height to the window size 667 | * devicePixelRatio to: frameBufferWidth / windowWidth. 668 | * 669 | * @param ratio The device pixel ration 670 | * @return The canvas to set scale ration with 671 | */ 672 | inline Canvas& setScaleRatio(float ratio) 673 | { 674 | m_scaleRatio = ratio; 675 | return *this; 676 | } 677 | 678 | /** 679 | * @brief Convert coordinates in canvas to coordinates in windows 680 | * @param x [inout] The x-coordinate to convert 681 | * @param y [inout] The x-coordinate to convert 682 | */ 683 | inline void local2Global(float& x,float& y) 684 | { 685 | x = m_xPos + x; 686 | y = m_yPos + y; 687 | } 688 | 689 | /** 690 | * @brief Convert coordinates in windows to coordinates in canvas 691 | * @param x [inout] The x-coordinate to convert 692 | * @param y [inout] The x-coordinate to convert 693 | */ 694 | inline void global2Local(float& x,float& y) 695 | { 696 | x = x - m_xPos; 697 | y = y - m_yPos; 698 | } 699 | 700 | 701 | /** 702 | * @brief Get the NanoVG context for advanced contol 703 | * @return The NanoVG context of this canvas 704 | */ 705 | NVGcontext* nvgContext(){ return m_nvgCtx; } 706 | 707 | protected: 708 | /// The NanoVG context 709 | NVGcontext * m_nvgCtx; 710 | /// The width of the canvas 711 | float m_width; 712 | /// The height of the canvas 713 | float m_height; 714 | /// Buffer / window size ratio 715 | float m_scaleRatio; 716 | /// The x-coordinate of the canvas in window 717 | float m_xPos; 718 | /// The y-coordinate of the canvas in window 719 | float m_yPos; 720 | }; 721 | } 722 | 723 | #endif // CANVAS_H 724 | -------------------------------------------------------------------------------- /src/Color.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __NanoCanvas_Color_H__ 2 | #define __NanoCanvas_Color_H__ 3 | 4 | namespace NanoCanvas 5 | { 6 | #include "ColorConverter.h" 7 | 8 | using Byte = unsigned char; 9 | 10 | struct Color 11 | { 12 | union 13 | { 14 | struct 15 | { 16 | /// Red value 17 | Byte r; 18 | /// Green value 19 | Byte g; 20 | /// Blue value 21 | Byte b; 22 | /// Alpha value 23 | Byte a; 24 | }; 25 | Byte mem[4]; 26 | }; 27 | 28 | 29 | Color(){ r = g = b = a = 0; } 30 | 31 | /** 32 | * @brief Construct a color with an unsigned integer value 33 | * @param color The color code value 34 | */ 35 | Color(const unsigned int color) 36 | { 37 | set(color); 38 | } 39 | 40 | /** 41 | * @brief Construct color with it's components value in the range [0,255] 42 | * @param _r The red component value 43 | * @param _g The green component value 44 | * @param _b The blue component value 45 | * @param _a The alpha component value 46 | */ 47 | Color(Byte _r, Byte _g, Byte _b, Byte _a = 255) 48 | { 49 | set(_r,_g,_b,_a); 50 | } 51 | 52 | /** 53 | * @brief Construct color with it's components value in the range [0,255] 54 | * @param _r The red component value 55 | * @param _g The green component value 56 | * @param _b The blue component value 57 | * @param _a The alpha component value 58 | */ 59 | Color(int _r, int _g, int _b, int _a = 255) 60 | { 61 | set(_r,_g,_b,_a); 62 | } 63 | 64 | /** 65 | * @brief Construct color with it's components value in the range [0,255] 66 | * @param _r The red component value 67 | * @param _g The green component value 68 | * @param _b The blue component value 69 | * @param _a The alpha component value 70 | */ 71 | Color(unsigned _r, unsigned _g, unsigned _b, unsigned _a = 255) 72 | { 73 | set(_r,_g,_b,_a); 74 | } 75 | 76 | /** 77 | * @brief Construct color with it's components value in the range [0,1] 78 | * @param _r The red component value 79 | * @param _g The green component value 80 | * @param _b The blue component value 81 | * @param _a The alpha component value 82 | */ 83 | Color(float _r, float _g, float _b, float _a = 1.0f) 84 | { 85 | set(_r,_g,_b,_a); 86 | } 87 | 88 | /// Convert the color to unsigned int as the color code 89 | inline operator unsigned int() const { return code(); } 90 | 91 | inline Byte& operator[](int index){ return mem[index]; } 92 | inline const Byte operator[](int index) const { return mem[index]; } 93 | 94 | inline bool operator==(const Color& color){ return code() == color.code(); } 95 | inline bool operator<(const Color& color){ return code() < color.code(); } 96 | 97 | inline Color& operator = (const unsigned int color){ return set(color); } 98 | 99 | Color& operator += (const Color& color) 100 | { 101 | r = clamp( r + color.r, 0, UCHAR_MAX); 102 | g = clamp( g + color.g, 0, UCHAR_MAX); 103 | b = clamp( b + color.b, 0, UCHAR_MAX); 104 | a = clamp( a + color.a, 0, UCHAR_MAX); 105 | return *this; 106 | } 107 | 108 | Color& operator -= (const Color& color) 109 | { 110 | using std::max; 111 | r = clamp( r - color.r, 0, UCHAR_MAX); 112 | g = clamp( g - color.g, 0, UCHAR_MAX); 113 | b = clamp( b - color.b, 0, UCHAR_MAX); 114 | a = clamp( a - color.a, 0, UCHAR_MAX); 115 | return *this; 116 | } 117 | 118 | Color& operator *= (const Color& color) 119 | { 120 | r = clamp( r + (color.r * color.a/UCHAR_MAX), 0, UCHAR_MAX); 121 | g = clamp( g + (color.g * color.a/UCHAR_MAX), 0, UCHAR_MAX); 122 | b = clamp( b + (color.b * color.a/UCHAR_MAX), 0, UCHAR_MAX); 123 | return *this; 124 | } 125 | 126 | Color operator + (const Color& color) 127 | { 128 | Color ret(*this); 129 | ret += color; 130 | return ret; 131 | } 132 | 133 | Color operator - (const Color& color) 134 | { 135 | Color ret(*this); 136 | ret -= color; 137 | return ret; 138 | } 139 | 140 | Color operator * (const Color& color) 141 | { 142 | Color ret(*this); 143 | ret *= color; 144 | return ret; 145 | } 146 | 147 | inline Color& set(unsigned int color) 148 | { 149 | r = (Byte)( color >> 24U ); 150 | g = (Byte)((color >> 16U) & 0x00ffU); 151 | b = (Byte)((color >> 8U) & 0x0000ffU); 152 | a = (Byte)( color % 0x100U ); 153 | return *this; 154 | } 155 | 156 | inline Color& set(float _r, float _g , float _b,float _a) 157 | { 158 | r = clamp( (Byte)(_r * UCHAR_MAX), 0, UCHAR_MAX); 159 | g = clamp( (Byte)(_g * UCHAR_MAX), 0, UCHAR_MAX); 160 | b = clamp( (Byte)(_b * UCHAR_MAX), 0, UCHAR_MAX); 161 | a = clamp( (Byte)(_a * UCHAR_MAX), 0, UCHAR_MAX); 162 | return *this; 163 | } 164 | 165 | inline Color& set(Byte _r, Byte _g, Byte _b, Byte _a) 166 | { 167 | r = _r; g = _g; b = _b; a = _a; 168 | return *this; 169 | } 170 | 171 | inline Color& set(unsigned _r, unsigned _g, unsigned _b, unsigned _a) 172 | { 173 | r = (Byte)_r; g = (Byte)_g; b = (Byte)_b; a = (Byte)_a; 174 | return *this; 175 | } 176 | 177 | inline Color& set(int _r, int _g, int _b, int _a) 178 | { 179 | r = (Byte)_r; g = (Byte)_g; b = (Byte)_b; a = (Byte)_a; 180 | return *this; 181 | } 182 | 183 | inline unsigned int code()const 184 | { 185 | unsigned int color = 0U; 186 | color |= ( r << 24U ); 187 | color |= ( g << 16U ); 188 | color |= ( b << 8U ); 189 | color |= a; 190 | return color; 191 | } 192 | 193 | inline float redf()const{ return r/255.0f; } 194 | inline float greenf()const{ return g/255.0f; } 195 | inline float bluef()const{ return b/255.0f; } 196 | inline float alphaf()const{ return a/255.0f; } 197 | 198 | static Color createWidthHSL(float _h , float _s,float _l,float _a = 1.0f) 199 | { 200 | Color color(0.0f,0.0f,0.0f,_a); 201 | ColorConverter::hslToRgb(_h,_s,_l,color.mem); 202 | return color; 203 | } 204 | }; 205 | 206 | namespace Colors 207 | { 208 | static Color ZeroColor = 0U; 209 | static Color AliceBlue = 0xF0F8FFFF; 210 | static Color AntiqueWhile = 0xFAEBD7FF; 211 | static Color Aqua = 0x00FFFFFF; 212 | static Color Aquamarine = 0x7FFFd4FF; 213 | static Color Azure = 0xF0FFFFFF; 214 | static Color Beiqe = 0xF5F5DCFF; 215 | static Color Bisque = 0xFFE4C4FF; 216 | static Color Black = 0x000000FF; 217 | static Color BlanchedAlmond = 0xFFEBCDFF; 218 | static Color Blue = 0x0000FFFF; 219 | static Color BlueViolet = 0x8A2BE2FF; 220 | static Color Brown = 0xA52A2AFF; 221 | static Color BurlyWood = 0xDEB887FF; 222 | static Color CadetBlue = 0x5F9EA0FF; 223 | static Color Chartreuse = 0x7FFF00FF; 224 | static Color Chocolate = 0xD2691EFF; 225 | static Color Coral = 0xFF7F50FF; 226 | static Color CornflowerBlue= 0x6495EDFF; 227 | static Color Cornsilk = 0xFFF8DCFF; 228 | static Color Crimson = 0xDC143CFF; 229 | static Color Cyan = 0x00FFFFFF; 230 | static Color DarkBlue = 0x00008BFF; 231 | static Color DarkCyan = 0x008B8BFF; 232 | static Color DarkGoldenRod = 0xB8860BFF; 233 | static Color DarkGray = 0xA9A9A9FF; 234 | static Color DarkGreen = 0x006400FF; 235 | static Color DarkKhaki = 0xBDB76BFF; 236 | static Color DarkMagenta = 0x8B008BFF; 237 | static Color DarkOliveGreen = 0x556B2FFF; 238 | static Color Darkorange = 0xFF8C00FF; 239 | static Color DarkOrchid = 0x9932CCFF; 240 | static Color DarkRed = 0x8B0000FF; 241 | static Color DarkSalmon = 0xE9967AFF; 242 | static Color DarkSeaGreen = 0x8FBC8FFF; 243 | static Color DarkSlateBlue = 0x483D8BFF; 244 | static Color DarkSlateGray = 0x2F4F4FFF; 245 | static Color DarkTurquoise = 0x00CED1FF; 246 | static Color DarkViolet = 0x9400D3FF; 247 | static Color DeepPink = 0xFF1493FF; 248 | static Color DeepSkyBlue = 0x00BFFFFF; 249 | static Color DimGray = 0x696969FF; 250 | static Color DodgerBlue = 0x1E90FFFF; 251 | static Color Feldspar = 0xD19275FF; 252 | static Color FireBrick = 0xB22222FF; 253 | static Color FloralWhite = 0xFFFAF0FF; 254 | static Color ForestGreen = 0x228B22FF; 255 | static Color Fuchsia = 0xFF00FFFF; 256 | static Color Gainsboro = 0xDCDCDCFF; 257 | static Color GhostWhite = 0xF8F8FFFF; 258 | static Color Gold = 0xFFD700FF; 259 | static Color GoldenRod = 0xDAA520FF; 260 | static Color Gray = 0x808080FF; 261 | static Color Green = 0x008000FF; 262 | static Color GreenYellow = 0xADFF2FFF; 263 | static Color HoneyDew = 0xF0FFF0FF; 264 | static Color HotPink = 0xFF69B4FF; 265 | static Color IndianRed = 0xCD5C5CFF; 266 | static Color Indigo = 0x4B0082FF; 267 | static Color Ivory = 0xFFFFF0FF; 268 | static Color Khaki = 0xF0E68CFF; 269 | static Color Lavender = 0xE6E6FAFF; 270 | static Color LavenderBlush = 0xFFF0F5FF; 271 | static Color LawnGreen = 0x7CFC00FF; 272 | static Color LemonChiffon = 0xFFFACDFF; 273 | static Color LightBlue = 0xADD8E6FF; 274 | static Color LightCoral = 0xF08080FF; 275 | static Color LightCyan = 0xE0FFFFFF; 276 | static Color LightGoldenRodYellow = 0xFAFAD2FF; 277 | static Color LightGrey = 0xD3D3D3FF; 278 | static Color LightGreen = 0x90EE90FF; 279 | static Color LightPink = 0xFFB6C1FF; 280 | static Color LightSalmon = 0xFFA07AFF; 281 | static Color LightSeaGreen = 0x20B2AAFF; 282 | static Color LightSkyBlue = 0x87CEFAFF; 283 | static Color LightSlateBlue = 0x8470FFFF; 284 | static Color LightSlateGray = 0x778899FF; 285 | static Color LightSteelBlue = 0xB0C4DEFF; 286 | static Color LightYellow = 0xFFFFE0FF; 287 | static Color Lime = 0x00FF00FF; 288 | static Color LimeGreen = 0x32CD32FF; 289 | static Color Linen = 0xFAF0E6FF; 290 | static Color Magenta = 0xFF00FFFF; 291 | static Color Maroon = 0x800000FF; 292 | static Color MediumAquaMarine = 0x66CDAAFF; 293 | static Color MediumBlue = 0x0000CDFF; 294 | static Color MediumOrchid = 0xBA55D3FF; 295 | static Color MediumPurple = 0x9370D8FF; 296 | static Color MediumSeaGreen = 0x3CB371FF; 297 | static Color MediumSlateBlue = 0x7B68EEFF; 298 | static Color MediumSpringGreen = 0x00FA9AFF; 299 | static Color MediumTurquoise = 0x48D1CCFF; 300 | static Color MediumVioletRed = 0xC71585FF; 301 | static Color MidnightBlue = 0x191970FF; 302 | static Color MintCream = 0xF5FFFAFF; 303 | static Color MistyRose = 0xFFE4E1FF; 304 | static Color Moccasin = 0xFFE4B5FF; 305 | static Color NavajoWhite = 0xFFDEADFF; 306 | static Color Navy = 0x000080FF; 307 | static Color OldLace = 0xFDF5E6FF; 308 | static Color Olive = 0x808000FF; 309 | static Color OliveDrab = 0x6B8E23FF; 310 | static Color Orange = 0xFFA500FF; 311 | static Color OrangeRed = 0xFFA500FF; 312 | static Color Orchid = 0xDA70D6FF; 313 | static Color PaleGoldenRod = 0xEEE8AAFF; 314 | static Color PaleGreen = 0x98FB98FF; 315 | static Color PaleTurquoise = 0xAFEEEEFF; 316 | static Color PaleVioletRed = 0xD87093FF; 317 | static Color PapayaWhip = 0xFFEFD5FF; 318 | static Color PeachPuff = 0xFFDAB9FF; 319 | static Color Peru = 0xCD853FFF; 320 | static Color Pink = 0xFFC0CBFF; 321 | static Color Plum = 0xDDA0DDFF; 322 | static Color PowderBlue = 0xB0E0E6FF; 323 | static Color Purple = 0x800080FF; 324 | static Color Red = 0xFF0000FF; 325 | static Color RosyBrown = 0xBC8F8FFF; 326 | static Color RoyalBlue = 0x4169E1FF; 327 | static Color SaddleBrown = 0x8B4513FF; 328 | static Color Salmon = 0xFA8072FF; 329 | static Color SandyBrown = 0xF4A460FF; 330 | static Color SeaGreen = 0x2E8B57FF; 331 | static Color SeaShell = 0xFFF5EEFF; 332 | static Color Sienna = 0xA0522DFF; 333 | static Color Silver = 0xC0C0C0FF; 334 | static Color SkyBlue = 0x87CEEBFF; 335 | static Color SlateBlue = 0x6A5ACDFF; 336 | static Color SlateGray = 0x708090FF; 337 | static Color Snow = 0xFFFAFAFF; 338 | static Color SpringGreen = 0x00FF7FFF; 339 | static Color SteelBlue = 0x4682B4FF; 340 | static Color Tan = 0xD2B48CFF; 341 | static Color Teal = 0x008080FF; 342 | static Color Thistle = 0xD8BFD8FF; 343 | static Color Tomato = 0xFF6347FF; 344 | static Color Turquoise = 0x40E0D0FF; 345 | static Color Violet = 0xEE82EEFF; 346 | static Color VioletRed = 0xD02090FF; 347 | static Color Wheat = 0xF5DEB3FF; 348 | static Color White = 0xFFFFFFFF; 349 | static Color WhiteSmoke = 0xF5F5F5FF; 350 | static Color Yellow = 0xFFFF00FF; 351 | static Color YellowGreen = 0x9ACD32FF; 352 | } 353 | 354 | /** @brief Get hex code string from color */ 355 | string to_string(const Color& color); 356 | } 357 | 358 | #endif //__NanoCanvas_Color_H__ 359 | -------------------------------------------------------------------------------- /src/ColorConverter.h: -------------------------------------------------------------------------------- 1 | #ifndef ColorConverter_H_ 2 | #define ColorConverter_H_ 3 | 4 | #include 5 | namespace ColorConverter 6 | { 7 | using byte = unsigned char; 8 | 9 | static double clamp(double x, double a, double b) 10 | { 11 | return x < a ? a : (x > b ? b : x); 12 | } 13 | 14 | static double threeway_max(double a, double b, double c) 15 | { 16 | return std::max(a, std::max(b, c)); 17 | } 18 | 19 | static double threeway_min(double a, double b, double c) 20 | { 21 | return std::min(a, std::min(b, c)); 22 | } 23 | 24 | static double hue2rgb(double h, double m1, double m2) 25 | { 26 | if (h < 0.0) h += 1.0; 27 | if (h > 1.0) h -= 1.0; 28 | if (h < 1.0/6.0) 29 | return m1 + (m2 - m1) * h * 6.0; 30 | else if (h < 3.0/6.0) 31 | return m2; 32 | else if (h < 4.0/6.0) 33 | return m1 + (m2 - m1) * (2.0f/3.0f - h) * 6.0f; 34 | 35 | return m1; 36 | } 37 | 38 | /** 39 | * Converts an HSL color value to RGB. Conversion formula 40 | * adapted from http://en.wikipedia.org/wiki/HSL_color_space. 41 | * Assumes h, s, and l are contained in the set [0, 1] and 42 | * returns r, g, and b in the set [0, 255]. 43 | * 44 | * @param double h The hue 45 | * @param double s The saturation 46 | * @param double l The lightness 47 | * @return byte rgb[] The RGB representation 48 | */ 49 | static void hslToRgb(double h, double s, double l, byte rgb[]) 50 | { 51 | double m1, m2; 52 | double useless; 53 | h = std::modf(h,&useless); 54 | if (h < 0.0) h += 1.0; 55 | s = clamp(s,0.0,1.0); 56 | l = clamp(l,0.0,1.0); 57 | m2 = l <= 0.5f ? (l * (1 + s)) : (l + s - l * s); 58 | m1 = 2 * l - m2; 59 | 60 | double r = clamp(hue2rgb(h + 1.0/3.0, m1, m2), 0.0, 1.0); 61 | double g = clamp(hue2rgb(h, m1, m2), 0.0, 1.0); 62 | double b = clamp(hue2rgb(h - 1.0/3.0, m1, m2), 0.0, 1.0); 63 | 64 | rgb[0] = byte(r*255); 65 | rgb[1] = byte(g*255); 66 | rgb[2] = byte(b*255); 67 | } 68 | 69 | /** 70 | * Converts an RGB color value to HSL. Conversion formula 71 | * adapted from http://en.wikipedia.org/wiki/HSL_color_space. 72 | * Assumes r, g, and b are contained in the set [0, 255] and 73 | * returns h, s, and l in the set [0, 1]. 74 | * 75 | * @param byte r The red color value 76 | * @param byte g The green color value 77 | * @param byte b The blue color value 78 | * @param double hsl[] The HSL representation 79 | */ 80 | static void rgbToHsl(byte r, byte g, byte b, double hsl[]) 81 | { 82 | // TODO: 83 | } 84 | 85 | 86 | /** 87 | * Converts an RGB color value to HSV. Conversion formula 88 | * adapted from http://en.wikipedia.org/wiki/HSV_color_space. 89 | * Assumes r, g, and b are contained in the set [0, 255] and 90 | * returns h, s, and v in the set [0, 1]. 91 | * 92 | * @param byte r The red color value 93 | * @param byte g The green color value 94 | * @param byte b The blue color value 95 | * @return double hsv[] The HSV representation 96 | */ 97 | static void rgbToHsv(byte r, byte g, byte b, double hsv[]) 98 | { 99 | // TODO: 100 | } 101 | 102 | /** 103 | * Converts an HSV color value to RGB. Conversion formula 104 | * adapted from http://en.wikipedia.org/wiki/HSV_color_space. 105 | * Assumes h, s, and v are contained in the set [0, 1] and 106 | * returns r, g, and b in the set [0, 255]. 107 | * 108 | * @param double h The hue 109 | * @param double s The saturation 110 | * @param double v The value 111 | * @return byte rgb[] The RGB representation 112 | */ 113 | static void hsvToRgb(double h, double s, double v, byte rgb[]) 114 | { 115 | // TODO: 116 | } 117 | }; 118 | 119 | #endif //ColorConverter_H_ 120 | -------------------------------------------------------------------------------- /src/Image.cpp: -------------------------------------------------------------------------------- 1 | #include "NanoCanvas.h" 2 | #include "nanovg.h" 3 | 4 | namespace NanoCanvas 5 | { 6 | Image::Image(Canvas& canvas,const string& filePath, int imageFlags) 7 | { 8 | m_canvas = &canvas; 9 | auto vg = canvas.nvgContext(); 10 | if(vg && filePath.length() ) 11 | imageID = nvgCreateImage(vg,filePath.c_str(),imageFlags); 12 | } 13 | Image::Image(Canvas& canvas,const Memery& memory, int imageFlags) 14 | { 15 | m_canvas = &canvas; 16 | auto vg = canvas.nvgContext(); 17 | if(vg && memory.valid() ) 18 | { 19 | imageID = nvgCreateImageMem(vg,imageFlags, 20 | (unsigned char*)(memory.data), 21 | memory.size); 22 | } 23 | } 24 | 25 | Image::Image(Canvas& canvas,int w,int h,const Memery& memory,int imageFlags) 26 | { 27 | m_canvas = &canvas; 28 | auto vg = canvas.nvgContext(); 29 | if(vg && memory.valid() ) 30 | { 31 | imageID = nvgCreateImageRGBA(vg,w,h,imageFlags, 32 | (unsigned char*)(memory.data)); 33 | } 34 | } 35 | 36 | Image::~Image() 37 | { 38 | if(m_canvas) 39 | { 40 | auto vg = m_canvas->nvgContext(); 41 | if(vg) 42 | nvgDeleteImage(vg,imageID); 43 | } 44 | } 45 | 46 | void Image::update(const Memery& memory) 47 | { 48 | if(m_canvas) 49 | { 50 | auto vg = m_canvas->nvgContext(); 51 | if(vg) 52 | nvgUpdateImage(vg,imageID,(const unsigned char*)(memory.data)); 53 | } 54 | } 55 | 56 | void Image::size(int& width,int& height) 57 | { 58 | if(m_canvas) 59 | { 60 | auto vg = m_canvas->nvgContext(); 61 | if(vg) 62 | nvgImageSize(vg,imageID,&width,&height); 63 | } 64 | } 65 | } 66 | 67 | 68 | -------------------------------------------------------------------------------- /src/Image.h: -------------------------------------------------------------------------------- 1 | #ifndef IMAGE_H 2 | #define IMAGE_H 3 | 4 | namespace NanoCanvas 5 | { 6 | class Canvas; 7 | 8 | /** 9 | * @class Image 10 | * @brief The Image class of Nano canas 11 | * NanoVG allows you to load jpg, png, psd, tga, pic and gif files to be used for rendering. 12 | */ 13 | class Image 14 | { 15 | public: 16 | 17 | /** @brief Flags for image creation 18 | * Can be used with bit operation 19 | */ 20 | enum ImageFlag 21 | { 22 | /// Generate mipmaps during creation of the image. 23 | GenerateMipmaps = 1<<0, 24 | /// Repeat image in X direction. 25 | RepeatX = 1<<1, 26 | /// Repeat image in Y direction. 27 | RepeatY = 1<<2, 28 | /// Flips (inverses) image in Y direction when rendered. 29 | FlipY = 1<<3, 30 | /// Image data has premultiplied alpha. 31 | PreMultiplied = 1<<4, 32 | }; 33 | 34 | /// Delete default constructor 35 | Image() = delete; 36 | 37 | /** 38 | * @brief Creates image by loading it from the disk from specified file name. 39 | * @param canvas The canvas who owns the image 40 | * @param filePath The image file path to load 41 | * @param imageFlags Creation flags 42 | * @see Image::ImageFlag 43 | */ 44 | Image(Canvas& canvas,const string& filePath, int imageFlags = 0); 45 | 46 | /** 47 | * @brief Creates image by loading it from the specified chunk of memory. 48 | * @param canvas The canvas who owns the image 49 | * @param memory The memery block to load from 50 | * @param imageFlags Creation flags 51 | * @see Image::ImageFlag 52 | */ 53 | Image(Canvas& canvas,const Memery& memory, int imageFlags = 0); 54 | 55 | /** 56 | * @brief Creates image with RGBA formate from specified image data. 57 | * @param canvas The canvas who owns the image 58 | * @param w The width of the image 59 | * @param w The height of the image 60 | * @param memory The memery block to load from 61 | * @param imageFlags Creation flags 62 | */ 63 | Image(Canvas& canvas,int w,int h,const Memery& memory,int imageFlags=0); 64 | 65 | ~Image(); 66 | 67 | /// Delete copy constructor 68 | Image(const Image&) = delete; 69 | /// Disable assignment 70 | Image& operator=(const Image&) = delete; 71 | 72 | /// Check is the image id is bigger than 0 73 | inline bool valid()const{ return imageID;} 74 | 75 | /// Update the image with memory data 76 | void update(const Memery& memory); 77 | 78 | /** 79 | * @brief Get image size 80 | * @param width [out] The width of the image , must be left-value 81 | * @param height [out] The height of the image , must be left-value 82 | */ 83 | void size(int& width,int& height); 84 | 85 | /// The image id of nanovg 86 | int imageID = 0; 87 | private: 88 | /// The owner canvas 89 | Canvas * m_canvas = nullptr; 90 | }; 91 | } 92 | 93 | #endif // IMAGE_H 94 | -------------------------------------------------------------------------------- /src/NanoCanvas.h: -------------------------------------------------------------------------------- 1 | #ifndef __NANOCANVAS_H__ 2 | #define __NANOCANVAS_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | namespace NanoCanvas 11 | { 12 | using std::string; 13 | static string nullstr; 14 | 15 | /// The data structure for memery blocks 16 | struct Memery 17 | { 18 | /// The data of the memery block 19 | void * data = nullptr; 20 | 21 | /// Size of the memery block in bytes 22 | unsigned long size = 0UL; 23 | 24 | /// Check is the data is not NULL and size is not 0 25 | bool valid()const{ return ( data && size ); } 26 | 27 | /** 28 | * @brief Invalidate the memery object 29 | * @attention This method does NOT free the memery,you have to do it yourself! 30 | */ 31 | void invalidate(){ data = nullptr ;size = 0UL; } 32 | }; 33 | 34 | /// The π definition 35 | static constexpr long double PI = 3.14159265358979323846264338327L; 36 | 37 | /** 38 | * @brief Get a number in range @b [a,b] 39 | * @return The value between @e a and @e b 40 | * @li if @e a <= @e x <= @e b returns @e x 41 | * @li if @e x < @e a returns @e a 42 | * @li if @e x > @e b returns @e b 43 | */ 44 | template 45 | inline T clamp(T x, T a, T b) 46 | { 47 | return x < a ? a : (x > b ? b : x); 48 | } 49 | 50 | 51 | //Convert degree to radians 52 | template 53 | T degree2Radians(const T _degree) 54 | { 55 | return _degree * ( PI / (T)180); 56 | } 57 | 58 | //Conver radians to degree 59 | template 60 | T radians2Degree(const T _radians) 61 | { 62 | return _radians * ( ( (T)180 )/ PI) ; 63 | } 64 | } 65 | 66 | #include "Color.hpp" 67 | #include "Text.h" 68 | #include "Image.h" 69 | #include "Paint.hpp" 70 | #include "Canvas.h" 71 | 72 | #endif //__NANOCANVAS_H__ 73 | -------------------------------------------------------------------------------- /src/Paint.hpp: -------------------------------------------------------------------------------- 1 | #ifndef PAINT_HPP 2 | #define PAINT_HPP 3 | 4 | namespace NanoCanvas 5 | { 6 | /// The Paint can be used as gradiants and image patterns with Canvas::fillStyle 7 | /// @see Canvas::fillStyle 8 | struct Paint 9 | { 10 | /// Paint type 11 | enum class Type 12 | { 13 | /// Liner gradiant 14 | Linear, 15 | /// Radial gradiant 16 | Radial, 17 | /// Box gradiant 18 | Box, 19 | /// Image pattern 20 | ImagePattern, 21 | /// Invalidate paint 22 | None 23 | } type = Type::None; /// The type of this paint 24 | float xx =0.0f, yy =0.0f , aa =0.0f, bb =0.0f, cc =0.0f,dd =0.0f; 25 | /// The nanovg image id of the image pattern 26 | int imageID = 0; 27 | /// The start color of the gradiant 28 | Color sColor = Colors::ZeroColor; 29 | /// The end color of the gradiant 30 | Color eColor = Colors::ZeroColor; 31 | }; 32 | } 33 | 34 | #endif // PAINT_HPP 35 | -------------------------------------------------------------------------------- /src/Text.cpp: -------------------------------------------------------------------------------- 1 | #include "NanoCanvas.h" 2 | #include "nanovg.h" 3 | 4 | namespace NanoCanvas 5 | { 6 | Font::Font(Canvas& canvas, const string& fname , const string& ttfPath) 7 | { 8 | if( canvas.valid() && fname.length() && ttfPath.length() ) 9 | { 10 | face = nvgCreateFont(canvas.nvgContext(),fname.c_str(),ttfPath.c_str()); 11 | } 12 | name = fname; 13 | } 14 | 15 | Font::Font(Canvas& canvas, const string& fname , 16 | const Memery& memory,bool invalidateMem) 17 | { 18 | if( canvas.valid() && memory.valid() && fname.length() ) 19 | { 20 | face = nvgCreateFontMem(canvas.nvgContext(),fname.c_str(), 21 | (unsigned char*)memory.data, 22 | memory.size,invalidateMem); 23 | } 24 | name = fname; 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /src/Text.h: -------------------------------------------------------------------------------- 1 | #ifndef TEXT_H 2 | #define TEXT_H 3 | 4 | namespace NanoCanvas 5 | { 6 | class Canvas; 7 | 8 | /** 9 | * @class Font 10 | * @brief Text font class 11 | */ 12 | struct Font 13 | { 14 | /// The face id of the font 15 | int face = -1; 16 | 17 | /// The font name 18 | string name = nullstr; 19 | 20 | Font() = default; 21 | 22 | /** 23 | * @brief Creates font by loading it from the disk from specified file path. 24 | * @param canvas The canvas who owns this font 25 | * @param fname The name of the font 26 | * @param ttfPath The ttf file path to load 27 | */ 28 | Font(Canvas& canvas, const string& fname , const string& ttfPath); 29 | 30 | /** 31 | * @brief Creates image by loading it from the specified memory chunk. 32 | * @param canvas The canvas who owns this font 33 | * @param fname The name of the font 34 | * @param mem The memory to load from 35 | * @param invalidateMem Should invalidate the memery after loading 36 | * @note Invalidate memery is not release the memery you should do that yourself! 37 | * @see Memery::invalidate 38 | */ 39 | Font(Canvas& canvas,const string& fname,const Memery& mem,bool invalidateMem); 40 | 41 | /** 42 | * @brief Check is the font face is valid 43 | * @return Is the font face is valid 44 | */ 45 | inline bool valid()const{ return face >= 0; } 46 | ~Font(){}; 47 | }; 48 | 49 | /// The text alignment is formed by horizontal alignment and vertical alignemt 50 | namespace TextAlign 51 | { 52 | /// Horizontal Alignment 53 | enum HorizontalAlign 54 | { 55 | /// Align text horizontally to left. 56 | Left = 1<<0, 57 | /// Align text horizontally to center. 58 | Center = 1<<1, 59 | /// Align text horizontally to right. 60 | Right = 1<<2, 61 | }; 62 | 63 | /// Vertical Alignment 64 | enum VerticalAlign 65 | { 66 | /// Align text vertically to top. 67 | Top = 1<<3, 68 | /// Align text vertically to middle. 69 | Middle = 1<<4, 70 | /// Align text vertically to bottom. 71 | Bottom = 1<<5, 72 | /// Align text vertically to baseline. 73 | Baseline = 1<<6 74 | }; 75 | } 76 | 77 | /// Text style description structure 78 | /// @note The text alignment of text is formed by horizontal alignment and vertical alignemt 79 | struct TextStyle 80 | { 81 | /// The font face of current text style 82 | int face = -1; 83 | /// The font size of current text style in pixel 84 | float size = 12.0f; 85 | /// The proportional line height of current text style. 86 | /// The line height is specified as multiple of font size. 87 | float lineHeight = NAN; 88 | /// The blur of current text style 89 | float blur = NAN; 90 | /// The letter spacing of current text style in pixel 91 | float letterSpace = NAN; 92 | /// The color of current text style 93 | Color color = Colors::ZeroColor; 94 | /// The horizontal alignment of current text style 95 | /// @see TextAlign::HorizontalAlign 96 | TextAlign::HorizontalAlign hAlign = TextAlign::Left; 97 | /// The vertical alignment of current text style 98 | /// @see TextAlign::VerticalAlign 99 | TextAlign::VerticalAlign vAlign = TextAlign::Baseline; 100 | }; 101 | } 102 | 103 | #endif // TEXT_H 104 | --------------------------------------------------------------------------------