[
  {
    "path": ".gitignore",
    "content": "# RUST STUFF\n\n# Compiled files\n*.o\n*.so\n*.rlib\n*.dll\n\n# Executables\n*.exe\n\n# Generated by Cargo\n/target/\nCargo.lock\n\n\n\n# MAC STUFF\n\n.DS_Store\n.AppleDouble\n.LSOverride\n\n# Icon must end with two \\r\nIcon\n\n# Thumbnails\n._*\n\n# Files that might appear on external disk\n.Spotlight-V100\n.Trashes\n\n"
  },
  {
    "path": ".travis.yml",
    "content": "sudo: false\nlanguage: rust\nos:\n- linux\nenv:\n  global:\n  - secure: W/pxVmgtzNXIQNPOm9lsIjSr2nEHGVD8uOGV0be4kdz0bUXCjFDe1j45VVDnXPoJZDrnv7TO0etn3yT7hpuiZGAT40Ovn7LVq7gqtTAoP2U7vbURN55g0MU9dSIAOUdfclAMZez9HgOHWC0P3Tg6bNkNrW5B5wwpmaFVyYwiQkE=\n  - secure: qlflwsinhvNorlh6l4Hl3tQDytF/LTzlUmw3hA4yj7pwEFUP4BORTvNIlJa+DCft4P4aEU0pgCsC8eb+MQ+q1WOQr2e+EfE+KT/FS9pT6RvqyYUs4QaEznbJkHxMjzkU2N5jf6RGssIEx3ieXD1y+LETxk+KIBFY8DN+wmMYjas=\naddons:\n  apt:\n    packages:\n      - libxxf86vm-dev\n      - libosmesa6-dev\nscript:\n- cargo build --verbose\n- cargo test --verbose\n- cargo doc --verbose\nafter_success: |\n  [ $TRAVIS_BRANCH = master ] &&\n  [ $TRAVIS_PULL_REQUEST = false ] &&\n  cargo doc &&\n  echo \"<meta http-equiv=refresh content=0;url=`echo $TRAVIS_REPO_SLUG | cut -d '/' -f 2`/index.html>\" > target/doc/index.html &&\n  sudo pip install ghp-import &&\n  ghp-import -n target/doc &&\n  git push -fq https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages\n"
  },
  {
    "path": "Cargo.toml",
    "content": "[package]\nname = \"elmesque\"\nversion = \"0.12.0\"\nauthors = [\"mitchmindtree <mitchell.nordine@gmail.com>\"]\ndescription = \"An attempt at porting Elm's incredibly useful, purely functional std graphics modules.\"\nreadme = \"README.md\"\nkeywords = [\"elm\", \"graphics\", \"2d\", \"ui\", \"shape\"]\nlicense = \"MIT\"\nrepository = \"https://github.com/mitchmindtree/elmesque.git\"\nhomepage = \"https://github.com/mitchmindtree/elmesque\"\n\n\n[dependencies]\nnum = \"0.1.27\"\npiston2d-graphics = \"0.13.0\"\nrand = \"0.3.12\"\nrustc-serialize = \"0.3.16\"\nvecmath = \"0.2.0\"\n\n[dev-dependencies]\nfind_folder = \"0.3.0\"\npiston = \"0.16.0\"\npiston_window = \"0.33.0\"\n"
  },
  {
    "path": "ELM_LICENSE.md",
    "content": "Copyright (c) 2013-2015, Evan Czaplicki\n\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n    * Redistributions of source code must retain the above copyright\n      notice, this list of conditions and the following disclaimer.\n\n    * Redistributions in binary form must reproduce the above\n      copyright notice, this list of conditions and the following\n      disclaimer in the documentation and/or other materials provided\n      with the distribution.\n\n    * Neither the name of Evan Czaplicki nor the names of other\n      contributors may be used to endorse or promote products derived\n      from this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "README.md",
    "content": "# elmesque [![Build Status](https://travis-ci.org/mitchmindtree/elmesque.svg?branch=master)](https://travis-ci.org/mitchmindtree/elmesque)\n\nThis crate is an attempt at porting Elm's incredibly useful, purely functional std graphics modules. Its useful for all kinds of 2D freeform graphics and UI design.\n\nSee [the docs](http://mitchmindtree.github.io/elmesque) or checkout [the example](https://github.com/mitchmindtree/elmesque/blob/master/examples/graphics.rs).\n\nVisit [elm-lang.org](http://elm-lang.org/) to learn more about Elm.\n\n\nAll credit and thanks goes to Evan Czaplicki for all algorithms included within.\n\nPorted to Rust by Mitchell Nordine.\n\n\n\nUsage\n-----\n\nAdd elmesque to your cargo dependencies like so.\n\n```toml\n[dependencies]\nelmesque = \"*\"\n```\n\n"
  },
  {
    "path": "assets/NotoSans/LICENSE-2.0.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "examples/graphics.rs",
    "content": "extern crate elmesque;\nextern crate find_folder;\nextern crate graphics;\nextern crate num;\nextern crate piston;\nextern crate piston_window;\n\nuse elmesque::{Form, Renderer};\nuse piston::input::UpdateEvent;\nuse piston::window::WindowSettings;\nuse piston_window::{PistonWindow, Glyphs};\n\nfn main() {\n\n    // Construct the window.\n    let window: PistonWindow =\n        WindowSettings::new(\"Elmesque\", [1180, 580])\n            .exit_on_esc(true)\n            .samples(4)\n            .vsync(true)\n            .build()\n            .unwrap();\n\n    // Construct the GlyphCache.\n    let mut glyph_cache = {\n        let assets = find_folder::Search::ParentsThenKids(3, 3).for_folder(\"assets\").unwrap();\n        let font_path = assets.join(\"NotoSans/NotoSans-Regular.ttf\");\n        Glyphs::new(&font_path, window.factory.borrow().clone()).unwrap()\n    };\n\n    // We'll use this to animate our graphics.\n    let mut secs = 0.0;\n\n    // Poll events from the window.\n    for event in window {\n        event.draw_2d(|context, g| {\n            let view_dim = context.get_view_size();\n            let (w, h) = (view_dim[0], view_dim[1]);\n\n            // Construct the elmesque Renderer with our graphics backend and glyph cache.\n            let mut renderer = Renderer::new(context, g).character_cache(&mut glyph_cache);\n\n            // Construct some freeform graphics aka a `Form`.\n            let form = elmesque_demo_form(secs);\n\n            // Convert the form to an `Element` for rendering.\n            let a = elmesque::form::collage(w as i32, h as i32, vec![form])\n                //.crop((secs / 2.0).sin() * (w / 2.0), (secs / 3.0).sin() * (h / 2.0), 400.0, 400.0)\n                .clear(elmesque::color::black());\n\n            a.draw(&mut renderer);\n        });\n        event.update(|args| secs += args.dt);\n    }\n\n}\n\n\n/// Demo of grouping multiple forms into a new single form, transformable at any stage.\npub fn elmesque_demo_form(secs: f64) -> Form {\n    use elmesque::color::{blue, dark_blue, light_blue, dark_purple, white};\n    use elmesque::form::{circle, group, ngon, oval, point_path, rect, solid, text, traced};\n    use elmesque::text::Text;\n    use elmesque::utils::{degrees};\n    use num::Float;\n\n    // Time to get creative!\n    group(vec![\n\n        rect(60.0, 40.0).filled(blue())\n            .shift(secs.sin() * 50.0, secs.cos() * 50.0)\n            .alpha(((secs * 200.0).cos() * 0.5 + 0.5) as f32)\n            .rotate(-secs),\n\n        rect(100.0, 10.0).filled(dark_blue())\n            .shift((secs * 5.0).sin() * 200.0, (secs * 5.0).cos() * 200.0)\n            .alpha(((secs * 2.0).cos() * 0.5 + 0.5) as f32)\n            .rotate(-(secs * 5.0)),\n\n        rect(10.0, 300.0).filled(blue())\n            .alpha(((secs * 3.0).sin() * 0.25 + 0.75) as f32)\n            .rotate(-(secs * 1.5)),\n\n        rect(5.0, (secs * 0.1).sin() * 600.0 + 300.0).filled(light_blue())\n            .alpha(((secs).cos() * 0.25 + 0.75) as f32)\n            .rotate(secs * 0.75),\n\n        rect(3.0, 2000.0).filled(dark_blue())\n            .alpha(((secs * 100.0).cos() * 0.5 + 0.25) as f32)\n            .rotate(-(secs * 0.5)),\n\n        oval(3.0, 2000.0 * (secs * 60.0).sin()).filled(light_blue())\n            .alpha(((secs * 100.0).cos() * 0.5 + 0.25) as f32)\n            .rotate(-(secs * 0.6)),\n\n        rect(10.0, 750.0).filled(blue())\n            .alpha(((secs * 2.0).cos() * 0.5 + 0.25) as f32)\n            .rotate(-(secs * 1.85)),\n\n        circle((secs * 0.5).sin() * 1500.0).outlined(solid(dark_purple()))\n            .alpha(((secs * 0.2).sin() * 0.25 + 0.35) as f32)\n            .rotate(-(secs * 0.5)),\n\n        ngon(12, (secs * 0.1).cos() * 100.0 + 300.0).filled(blue())\n            .alpha((0.25 * secs.cos()) as f32)\n            .rotate(secs * 0.5),\n\n        ngon(9, (secs * 0.1).cos() * 200.0 + 250.0).outlined(solid(dark_blue()))\n            .alpha(((0.33 * secs).sin() + 0.15) as f32)\n            .rotate(secs * 0.2),\n\n        rect(300.0, 20.0).filled(light_blue())\n            .shift((secs * 1.5).cos() * 250.0, (secs * 1.5).sin() * 250.0)\n            .alpha(((secs * 4.5).cos() * 0.25 + 0.35) as f32)\n            .rotate(secs * 1.5 + degrees(90.0)),\n\n        traced(\n            solid(light_blue()),\n            point_path(vec![(-500.0, 100.0), (0.0, 250.0 * secs.sin()), (500.0, 100.0)])\n        ).alpha(((secs * 0.2).sin() * 0.25 + 0.35) as f32),\n            \n        traced(\n            solid(blue()),\n            point_path(vec![(-500.0, 0.0), (0.0, 0.0), (500.0, 0.0)])\n        ).alpha(((secs * 4.5).cos() * 0.25 + 0.35) as f32),\n\n        traced(\n            solid(dark_blue()),\n            point_path(vec![(-500.0, -100.0), (0.0, -250.0 * secs.sin()), (500.0, -100.0)])\n        ).alpha(((secs * 0.15).cos() * 0.25 + 0.35) as f32),\n\n        text(Text::from_string(\"elmesque\".to_string()).color(white())),\n\n    ]).rotate(degrees(secs.sin() * 360.0))\n      .scale((secs * 0.05).cos() * 0.2 + 0.9)\n\n}\n\n"
  },
  {
    "path": "src/color.rs",
    "content": "//! \n//! A library providing simple `Color` and `Gradient` types along with useful transformations and\n//! presets.\n//!\n//!\n//! Inspiration taken from [elm-lang's color module]\n//! (https://github.com/elm-lang/core/blob/62b22218c42fb8ccc996c86bea450a14991ab815/src/Color.elm)\n//!\n//!\n//! Module for working with colors. Includes [RGB](https://en.wikipedia.org/wiki/RGB_color_model)\n//! and [HSL](http://en.wikipedia.org/wiki/HSL_and_HSV) creation, gradients and built-in names.\n//!\n\nuse rustc_serialize::hex::ToHex;\nuse std::ascii::AsciiExt;\nuse std::f32::consts::PI;\nuse utils::{clampf32, degrees, fmod, min, max, turns};\n\n\n/// Color supporting RGB and HSL variants.\n#[derive(PartialEq, Copy, Clone, Debug, RustcEncodable, RustcDecodable)]\npub enum Color {\n    /// Red, Green, Blue, Alpha - All values' scales represented between 0.0 and 1.0.\n    Rgba(f32, f32, f32, f32),\n    /// Hue, Saturation, Lightness, Alpha - all valuess scales represented between 0.0 and 1.0.\n    Hsla(f32, f32, f32, f32),\n}\n\n/// Regional spelling alias.\npub type Colour = Color;\n\n\n/// Create RGB colors with an alpha component for transparency.\n/// The alpha component is specified with numbers between 0 and 1.\n#[inline]\npub fn rgba(r: f32, g: f32, b: f32, a: f32) -> Color {\n    Color::Rgba(r, g, b, a)\n}\n\n\n/// Create RGB colors from numbers between 0.0 and 1.0.\n#[inline]\npub fn rgb(r: f32, g: f32, b: f32) -> Color {\n    Color::Rgba(r, g, b, 1.0)\n}\n\n\n/// Create RGB colors from numbers between 0 and 255 inclusive.\n/// The alpha component is specified with numbers between 0 and 1.\n#[inline]\npub fn rgba_bytes(r: u8, g: u8, b: u8, a: f32) -> Color {\n    Color::Rgba(r as f32 / 255.0, g as f32 / 255.0, b as f32 / 255.0, a)\n}\n\n\n/// Create RGB colors from numbers between 0 and 255 inclusive.\n#[inline]\npub fn rgb_bytes(r: u8, g: u8, b: u8) -> Color {\n    rgba_bytes(r, g, b, 1.0)\n}\n\n\n/// Create [HSL colors](http://en.wikipedia.org/wiki/HSL_and_HSV) with an alpha component for\n/// transparency.\n#[inline]\npub fn hsla(hue: f32, saturation: f32, lightness: f32, alpha: f32) -> Color {\n    Color::Hsla(hue - turns((hue / (2.0 * PI)).floor()), saturation, lightness, alpha)\n}\n\n\n/// Create [HSL colors](http://en.wikipedia.org/wiki/HSL_and_HSV). This gives you access to colors\n/// more like a color wheel, where all hues are arranged in a circle that you specify with radians.\n/// \n///   red        = hsl(degrees(0.0)   , 1.0 , 0.5)\n///   green      = hsl(degrees(120.0) , 1.0 , 0.5)\n///   blue       = hsl(degrees(240.0) , 1.0 , 0.5)\n///   pastel_red = hsl(degrees(0.0)   , 0.7 , 0.7)\n///\n/// To cycle through all colors, just cycle through degrees. The saturation level is how vibrant\n/// the color is, like a dial between grey and bright colors. The lightness level is a dial between\n/// white and black.\n#[inline]\npub fn hsl(hue: f32, saturation: f32, lightness: f32) -> Color {\n    hsla(hue, saturation, lightness, 1.0)\n}\n\n\n/// Produce a gray based on the input. 0.0 is white, 1.0 is black.\npub fn grayscale(p: f32) -> Color {\n    Color::Hsla(0.0, 0.0, 1.0-p, 1.0)\n}\n/// Produce a gray based on the input. 0.0 is white, 1.0 is black.\npub fn greyscale(p: f32) -> Color {\n    Color::Hsla(0.0, 0.0, 1.0-p, 1.0)\n}\n\n\n/// Construct a random color.\npub fn random() -> Color {\n    rgb(::rand::random(), ::rand::random(), ::rand::random())\n}\n\n\nimpl Color {\n\n    /// Produce a complementary color. The two colors will accent each other. This is the same as\n    /// rotating the hue by 180 degrees.\n    pub fn complement(self) -> Color {\n        match self {\n            Color::Hsla(h, s, l, a) => hsla(h + degrees(180.0), s, l, a),\n            Color::Rgba(r, g, b, a) => {\n                let (h, s, l) = rgb_to_hsl(r, g, b);\n                hsla(h + degrees(180.0), s, l, a)\n            },\n        }\n    }\n\n    /// Calculate and return the luminance of the Color.\n    pub fn luminance(&self) -> f32 {\n        match *self {\n            Color::Rgba(r, g, b, _) => (r + g + b) / 3.0,\n            Color::Hsla(_, _, l, _) => l,\n        }\n    }\n\n    /// Return either black or white, depending which contrasts the Color the most. This will be\n    /// useful for determining a readable color for text on any given background Color.\n    pub fn plain_contrast(self) -> Color {\n        if self.luminance() > 0.5 { black() } else { white() }\n    }\n\n    /// Extract the components of a color in the HSL format.\n    pub fn to_hsl(self) -> Hsla {\n        match self {\n            Color::Hsla(h, s, l, a) => Hsla(h, s, l, a),\n            Color::Rgba(r, g, b, a) => {\n                let (h, s, l) = rgb_to_hsl(r, g, b);\n                Hsla(h, s, l, a)\n            },\n        }\n    }\n\n    /// Extract the components of a color in the RGB format.\n    pub fn to_rgb(self) -> Rgba {\n        match self {\n            Color::Rgba(r, g, b, a) => Rgba(r, g, b, a),\n            Color::Hsla(h, s, l, a) => {\n                let (r, g, b) = hsl_to_rgb(h, s, l);\n                Rgba(r, g, b, a)\n            },\n        }\n    }\n\n    /// Extract the components of a color in the RGB format within a fixed-size array.\n    pub fn to_fsa(self) -> [f32; 4] {\n        let Rgba(r, g, b, a) = self.to_rgb();\n        [r, g, b, a]\n    }\n\n    /// Same as `to_fsa`, except r, g, b and a are represented in byte form.\n    pub fn to_byte_fsa(self) -> [u8; 4] {\n        let Rgba(r, g, b, a) = self.to_rgb();\n        [f32_to_byte(r), f32_to_byte(g), f32_to_byte(b), f32_to_byte(a)]\n    }\n\n    /// Return the hex representation of this color in the format #RRGGBBAA\n    /// e.g. `Color(1.0, 0.0, 5.0, 1.0) == \"#FF0080FF\"`\n    pub fn to_hex(self) -> String {\n        let vals = self.to_byte_fsa();\n        let hex = vals.to_hex().to_ascii_uppercase();\n        format!(\"#{}\", &hex)\n    }\n\n    /// Return the same color but with the given luminance.\n    pub fn with_luminance(self, l: f32) -> Color {\n        let Hsla(h, s, _, a) = self.to_hsl();\n        Color::Hsla(h, s, l, a)\n    }\n\n    /// Return the same color but with the alpha multiplied by the given alpha.\n    pub fn alpha(self, alpha: f32) -> Color {\n        match self {\n            Color::Rgba(r, g, b, a) => Color::Rgba(r, g, b, a * alpha),\n            Color::Hsla(h, s, l, a) => Color::Hsla(h, s, l, a * alpha),\n        }\n    }\n\n    /// Return the same color but with the given alpha.\n    pub fn with_alpha(self, a: f32) -> Color {\n        match self {\n            Color::Rgba(r, g, b, _) => Color::Rgba(r, g, b, a),\n            Color::Hsla(h, s, l, _) => Color::Hsla(h, s, l, a),\n        }\n    }\n\n    /// Return a highlighted version of the current Color.\n    pub fn highlighted(self) -> Color {\n        let luminance = self.luminance();\n        let Rgba(r, g, b, a) = self.to_rgb();\n        let (r, g, b) = {\n            if      luminance > 0.8 { (r - 0.2, g - 0.2, b - 0.2) }\n            else if luminance < 0.2 { (r + 0.2, g + 0.2, b + 0.2) }\n            else {\n                (clampf32((1.0 - r) * 0.5 * r + r),\n                 clampf32((1.0 - g) * 0.1 * g + g),\n                 clampf32((1.0 - b) * 0.1 * b + b))\n            }\n        };\n        let a = clampf32((1.0 - a) * 0.5 + a);\n        rgba(r, g, b, a)\n    }\n\n    /// Return a clicked version of the current Color.\n    pub fn clicked(&self) -> Color {\n        let luminance = self.luminance();\n        let Rgba(r, g, b, a) = self.to_rgb();\n        let (r, g, b) = {\n            if      luminance > 0.8 { (r      , g - 0.2, b - 0.2) }\n            else if luminance < 0.2 { (r + 0.4, g + 0.2, b + 0.2) }\n            else {\n                (clampf32((1.0 - r) * 0.75 + r),\n                 clampf32((1.0 - g) * 0.25 + g),\n                 clampf32((1.0 - b) * 0.25 + b))\n            }\n        };\n        let a = clampf32((1.0 - a) * 0.75 + a);\n        rgba(r, g, b, a)\n    }\n\n    /// Return the Color's invert.\n    pub fn invert(self) -> Color {\n        let Rgba(r, g, b, a) = self.to_rgb();\n        rgba((r - 1.0).abs(), (g - 1.0).abs(), (b - 1.0).abs(), a)\n    }\n\n    /// Return the red value.\n    pub fn red(&self) -> f32 {\n        let Rgba(r, _, _, _) = self.to_rgb();\n        r\n    }\n\n    /// Return the green value.\n    pub fn green(&self) -> f32 {\n        let Rgba(_, g, _, _) = self.to_rgb();\n        g\n    }\n\n    /// Return the blue value.\n    pub fn blue(&self) -> f32 {\n        let Rgba(_, _, b, _) = self.to_rgb();\n        b\n    }\n\n    /// Set the red value.\n    pub fn set_red(&mut self, r: f32) {\n        let Rgba(_, g, b, a) = self.to_rgb();\n        *self = rgba(r, g, b, a);\n    }\n\n    /// Set the green value.\n    pub fn set_green(&mut self, g: f32) {\n        let Rgba(r, _, b, a) = self.to_rgb();\n        *self = rgba(r, g, b, a);\n    }\n\n    /// Set the blue value.\n    pub fn set_blue(&mut self, b: f32) {\n        let Rgba(r, g, _, a) = self.to_rgb();\n        *self = rgba(r, g, b, a);\n    }\n\n}\n\n\n/// The parts of HSL along with an alpha for transparency.\n#[derive(Copy, Clone, Debug)]\npub struct Hsla(pub f32, pub f32, pub f32, pub f32);\n\n\n/// The parts of RGB along with an alpha for transparency.\n#[derive(Copy, Clone, Debug)]\npub struct Rgba(pub f32, pub f32, pub f32, pub f32);\n\n\n/// Convert an f32 color to a byte.\n#[inline]\npub fn f32_to_byte(c: f32) -> u8 { (c * 255.0) as u8 }\n\n\n/// Pure function for converting rgb to hsl.\npub fn rgb_to_hsl(r: f32, g: f32, b: f32) -> (f32, f32, f32) {\n    let c_max = max(max(r, g), b);\n    let c_min = min(min(r, g), b);\n    let c = c_max - c_min;\n\n    let hue = if c == 0.0 {\n        // If there's no difference in the channels we have grayscale, so the hue is undefined.\n        0.0\n    } else {\n        degrees(60.0) * if      c_max == r { fmod(((g - b) / c), 6) }\n                        else if c_max == g { ((b - r) / c) + 2.0 }\n                        else               { ((r - g) / c) + 4.0 }\n    };\n\n    let lightness = (c_max + c_min) / 2.0;\n    let saturation = if lightness == 0.0 { 0.0 }\n                     else { c / (1.0 - (2.0 * lightness - 1.0).abs()) };\n    (hue, saturation, lightness)\n}\n\n\n/// Pure function for converting hsl to rgb.\npub fn hsl_to_rgb(hue: f32, saturation: f32, lightness: f32) -> (f32, f32, f32) {\n    let chroma = (1.0 - (2.0 * lightness - 1.0).abs()) * saturation;\n    let hue = hue / degrees(60.0);\n    let x = chroma * (1.0 - (fmod(hue, 2) - 1.0).abs());\n    let (r, g, b) = match hue {\n        hue if hue < 0.0 => (0.0, 0.0, 0.0),\n        hue if hue < 1.0 => (chroma, x, 0.0),\n        hue if hue < 2.0 => (x, chroma, 0.0),\n        hue if hue < 3.0 => (0.0, chroma, x),\n        hue if hue < 4.0 => (0.0, x, chroma),\n        hue if hue < 5.0 => (x, 0.0, chroma),\n        hue if hue < 6.0 => (chroma, 0.0, x),\n        _ => (0.0, 0.0, 0.0),\n    };\n    let m = lightness - chroma / 2.0;\n    (r + m, g + m, b + m)\n}\n\n\n/// Linear or Radial Gradient.\n#[derive(Clone, Debug)]\npub enum Gradient {\n    /// Takes a start and end point and then a series of color stops that indicate how to\n    /// interpolate between the start and end points.\n    Linear((f64, f64), (f64, f64), Vec<(f64, Color)>),\n    /// First takes a start point and inner radius. Then takes an end point and outer radius.\n    /// It then takes a series of color stops that indicate how to interpolate between the\n    /// inner and outer circles.\n    Radial((f64, f64), f64, (f64, f64), f64, Vec<(f64, Color)>),\n}\n\n\n/// Create a linear gradient.\npub fn linear(start: (f64, f64), end: (f64, f64), colors: Vec<(f64, Color)>) -> Gradient {\n    Gradient::Linear(start, end, colors)\n}\n\n\n/// Create a radial gradient. \npub fn radial(start: (f64, f64), start_r: f64,\n              end: (f64, f64), end_r: f64,\n              colors: Vec<(f64, Color)>) -> Gradient {\n    Gradient::Radial(start, start_r, end, end_r, colors)\n}\n\n\n/// Built-in colors.\n///\n/// These colors come from the\n/// [Tango palette](http://tango.freedesktop.org/Tango_Icon_Theme_Guidelines) which provides\n/// aesthetically reasonable defaults for colors. Each color also comes with a light and dark\n/// version.\n\n/// Scarlet Red - Light - #EF2929\npub fn light_red()      -> Color { rgb_bytes(239 , 41  , 41 ) }\n/// Scarlet Red - Regular - #CC0000\npub fn red()            -> Color { rgb_bytes(204 , 0   , 0  ) }\n/// Scarlet Red - Dark - #A30000\npub fn dark_red()       -> Color { rgb_bytes(164 , 0   , 0  ) }\n\n/// Orange - Light - #FCAF3E\npub fn light_orange()   -> Color { rgb_bytes(252 , 175 , 62 ) }\n/// Orange - Regular - #F57900\npub fn orange()         -> Color { rgb_bytes(245 , 121 , 0  ) }\n/// Orange - Dark - #CE5C00\npub fn dark_orange()    -> Color { rgb_bytes(206 , 92  , 0  ) }\n\n/// Butter - Light - #FCE94F\npub fn light_yellow()   -> Color { rgb_bytes(255 , 233 , 79 ) }\n/// Butter - Regular - #EDD400\npub fn yellow()         -> Color { rgb_bytes(237 , 212 , 0  ) }\n/// Butter - Dark - #C4A000\npub fn dark_yellow()    -> Color { rgb_bytes(196 , 160 , 0  ) }\n\n/// Chameleon - Light - #8AE234\npub fn light_green()    -> Color { rgb_bytes(138 , 226 , 52 ) }\n/// Chameleon - Regular - #73D216\npub fn green()          -> Color { rgb_bytes(115 , 210 , 22 ) }\n/// Chameleon - Dark - #4E9A06\npub fn dark_green()     -> Color { rgb_bytes(78  , 154 , 6  ) }\n\n/// Sky Blue - Light - #729FCF\npub fn light_blue()     -> Color { rgb_bytes(114 , 159 , 207) }\n/// Sky Blue - Regular - #3465A4\npub fn blue()           -> Color { rgb_bytes(52  , 101 , 164) }\n/// Sky Blue - Dark - #204A87\npub fn dark_blue()      -> Color { rgb_bytes(32  , 74  , 135) }\n\n/// Plum - Light - #AD7FA8\npub fn light_purple()   -> Color { rgb_bytes(173 , 127 , 168) }\n/// Plum - Regular - #75507B\npub fn purple()         -> Color { rgb_bytes(117 , 80  , 123) }\n/// Plum - Dark - #5C3566\npub fn dark_purple()    -> Color { rgb_bytes(92  , 53  , 102) }\n\n/// Chocolate - Light - #E9B96E\npub fn light_brown()    -> Color { rgb_bytes(233 , 185 , 110) }\n/// Chocolate - Regular - #C17D11\npub fn brown()          -> Color { rgb_bytes(193 , 125 , 17 ) }\n/// Chocolate - Dark - #8F5902\npub fn dark_brown()     -> Color { rgb_bytes(143 , 89  , 2  ) }\n\n/// Straight Black.\npub fn black()          -> Color { rgb_bytes(0   , 0   , 0  ) }\n/// Straight White.\npub fn white()          -> Color { rgb_bytes(255 , 255 , 255) }\n\n/// Alluminium - Light\npub fn light_gray()     -> Color { rgb_bytes(238 , 238 , 236) }\n/// Alluminium - Regular\npub fn gray()           -> Color { rgb_bytes(211 , 215 , 207) }\n/// Alluminium - Dark\npub fn dark_gray()      -> Color { rgb_bytes(186 , 189 , 182) }\n\n/// Aluminium - Light - #EEEEEC\npub fn light_grey()     -> Color { rgb_bytes(238 , 238 , 236) }\n/// Aluminium - Regular - #D3D7CF\npub fn grey()           -> Color { rgb_bytes(211 , 215 , 207) }\n/// Aluminium - Dark - #BABDB6\npub fn dark_grey()      -> Color { rgb_bytes(186 , 189 , 182) }\n\n/// Charcoal - Light - #888A85\npub fn light_charcoal() -> Color { rgb_bytes(136 , 138 , 133) }\n/// Charcoal - Regular - #555753\npub fn charcoal()       -> Color { rgb_bytes(85  , 87  , 83 ) }\n/// Charcoal - Dark - #2E3436\npub fn dark_charcoal()  -> Color { rgb_bytes(46  , 52  , 54 ) }\n\n\n\n/// Types that can be colored.\npub trait Colorable: Sized {\n\n    /// Set the color of the widget.\n    fn color(self, color: Color) -> Self;\n\n    /// Set the color of the widget from rgba values.\n    fn rgba(self, r: f32, g: f32, b: f32, a: f32) -> Self {\n        self.color(rgba(r, g, b, a))\n    }\n\n    /// Set the color of the widget from rgb values.\n    fn rgb(self, r: f32, g: f32, b: f32) -> Self {\n        self.color(rgb(r, g, b))\n    }\n\n    /// Set the color of the widget from hsla values.\n    fn hsla(self, h: f32, s: f32, l: f32, a: f32) -> Self {\n        self.color(hsla(h, s, l, a))\n    }\n\n    /// Set the color of the widget from hsl values.\n    fn hsl(self, h: f32, s: f32, l: f32) -> Self {\n        self.color(hsl(h, s, l))\n    }\n\n}\n\n"
  },
  {
    "path": "src/element.rs",
    "content": "//! \n//! Ported from [elm-lang's `Graphics.Element` module]\n//! (https://github.com/elm-lang/core/blob/1.1.1/src/Graphics/Element.elm)\n//!\n//!\n//! Graphical elements that snap together to build complex widgets and layouts.\n//!\n//! Each element is a rectangle with a known width and height, making them easy to combine and\n//! position.\n//!\n//!\n//! # Images\n//!\n//!   image, fitted_image, cropped_image, tiled_image\n//!\n//!\n//! # Styling\n//!\n//!   width, height, size, color, opacity\n//!\n//!\n//! # Inspection\n//!\n//!   width_of, height_of, size_of\n//!\n//!\n//! # Layout\n//!\n//!   flow, up, down, left, right, inward, outward\n//!\n//! ## Layout Aliases\n//!\n//! There are some convenience functions for working with `flow` in specific cases:\n//!\n//!   layers, above, below, beside\n//!\n//!\n//! # Positioning\n//!   empty, spacer, container\n//!\n//! ## Specific Positions\n//!\n//! To create a `Position` you can use any of the built-in positions which cover nine common\n//! positions:\n//!\n//!   middle, mid_top, mid_bottom, mid_left, mid_right, top_left, top_right, bottom_left,\n//!   bottom_right\n//!\n//! If you need more precision, you can create custom positions:\n//!\n//!   absolute, relative, middle_at, mid_top_at, mid_bottom_at, mid_left_at, mid_right_at,\n//!   top_left_at, top_right_at, bottom_left_at, bottom_right_at\n//!\n\nuse color::Color;\nuse form::{self, Form};\nuse graphics::character::CharacterCache;\nuse graphics::{Context, Graphics, Transformed};\nuse self::Three::{P, Z, N};\nuse std::path::PathBuf;\nuse transform_2d;\n\n\n/// An Element's Properties.\n#[derive(Clone, Debug)]\npub struct Properties {\n    pub width: i32,\n    pub height: i32,\n    pub opacity: f32,\n    pub crop: Option<(f64, f64, f64, f64)>,\n    pub color: Option<Color>,\n}\n\n\n/// Graphical elements that snap together to build complex widgets and layouts.\n///\n/// Each element is a rectangle with a known width and height, making them easy to combine and\n/// position.\n#[derive(Clone, Debug)]\npub struct Element {\n    pub props: Properties,\n    pub element: Prim,\n}\n\n\nimpl Element {\n\n    /// Create an `Element` with a given width.\n    #[inline]\n    pub fn width(self, new_width: i32) -> Element {\n        let Element { props, element } = self;\n        let new_props = match element {\n            Prim::Image(_, w, h, _) | Prim::Collage(w, h, _) => {\n                Properties {\n                    height: (h as f32 / w as f32 * new_width as f32).round() as i32,\n                    ..props\n                }\n            },\n            _ => props,\n        };\n        Element { props: new_props, element: element }\n    }\n\n    /// Create an `Element` with a given height.\n    #[inline]\n    pub fn height(self, new_height: i32) -> Element {\n        let Element { props, element } = self;\n        let new_props = match element {\n            Prim::Image(_, w, h, _) | Prim::Collage(w, h, _) => {\n                Properties {\n                    width: (w as f32 / h as f32 * new_height as f32).round() as i32,\n                    ..props\n                }\n            },\n            _ => props,\n        };\n        Element { props: new_props, element: element }\n    }\n\n    /// Create an `Element` with a given size.\n    #[inline]\n    pub fn size(self, new_w: i32, new_h: i32) -> Element {\n        self.height(new_h).width(new_w)\n    }\n\n    /// Create an `Element` with a given opacity.\n    #[inline]\n    pub fn opacity(mut self, opacity: f32) -> Element {\n        self.props.opacity = opacity;\n        self\n    }\n\n    /// Create an `Element with a given background color.\n    #[inline]\n    pub fn color(mut self, color: Color) -> Element {\n        self.props.color = Some(color);\n        self\n    }\n\n    /// Crops an `Element` with the given rectangle.\n    #[inline]\n    pub fn crop(self, x: f64, y: f64, w: f64, h: f64) -> Element {\n        let Element { props, element } = self;\n        let new_props = Properties { crop: Some((x, y, w, h)), ..props };\n        Element { props: new_props, element: element }\n    }\n\n    /// Put an element in a container. This lets you position the element really easily, and there are\n    /// tons of ways to set the `Position`.\n    #[inline]\n    pub fn container(self, w: i32, h: i32, pos: Position) -> Element {\n        new_element(w, h, Prim::Container(pos, Box::new(self)))\n    }\n\n    /// Put an element in a cleared wrapper. The color provided will be the color that clears the\n    /// screen before rendering the contained element.\n    #[inline]\n    pub fn clear(self, color: Color) -> Element {\n        new_element(self.get_width(), self.get_height(),\n            Prim::Cleared(color, Box::new(self)))\n    }\n\n    /// Stack elements vertically. To put `a` above `b` you would say: `a.above(b)`\n    #[inline]\n    pub fn above(self, other: Element) -> Element {\n        new_element(::std::cmp::max(self.get_width(), other.get_width()),\n                    self.get_height() + other.get_height(),\n                    Prim::Flow(down(), vec![self, other]))\n    }\n\n    /// Stack elements vertically. To put `a` below `b` you would say: `a.below(b)`\n    #[inline]\n    pub fn below(self, other: Element) -> Element {\n        other.above(self)\n    }\n\n    /// Put elements beside each other horizontally. To put `b` to the right of `a` you would say:\n    ///   `a.beside(b)`\n    #[inline]\n    pub fn beside(self, other: Element) -> Element {\n        new_element(self.get_width() + other.get_width(),\n                    ::std::cmp::max(self.get_height(), other.get_height()),\n                    Prim::Flow(right(), vec![self, other]))\n    }\n\n    /// Return the width of the Element.\n    pub fn get_width(&self) -> i32 { self.props.width }\n\n    /// Return the height of the Element.\n    pub fn get_height(&self) -> i32 { self.props.height }\n\n    /// Return the size of the Element's bounding rectangle.\n    pub fn get_size(&self) -> (i32, i32) { (self.props.width, self.props.height) }\n\n    /// Draw the form with some given graphics backend.\n    #[inline]\n    pub fn draw<'a, C, G>(&self, renderer: &mut Renderer<'a, C, G>)\n        where\n            C: CharacterCache,\n            G: Graphics<Texture=C::Texture>,\n    {\n        let Renderer {\n            context,\n            ref mut backend,\n            ref mut maybe_character_cache,\n        } = *renderer;\n        let view_size = context.get_view_size();\n        let context = context.trans(view_size[0] / 2.0, view_size[1] / 2.0).scale(1.0, -1.0);\n        draw_element(self, 1.0, *backend, maybe_character_cache, context);\n    }\n\n    /// Return whether or not a point is over the element.\n    pub fn is_over(&self, x: i32, y: i32) -> bool {\n        unimplemented!();\n    }\n\n}\n\n/// Return the size of the Element.\npub fn size_of(e: &Element) -> (i32, i32) {\n    (e.props.width, e.props.height)\n}\n\n\n/// Construct a new Element from width, height and some Prim.\n/// Iterates the global GUID counter by one and returns that as the Element id.\n#[inline]\npub fn new_element(w: i32, h: i32, element: Prim) -> Element {\n    Element {\n        props: Properties {\n            width: w,\n            height: h,\n            opacity: 1.0,\n            color: None,\n            crop: None,\n        },\n        element: element,\n    }\n}\n\n\n/// Create an empty box. this is useful for getting your spacing right and making borders.\npub fn spacer(w: i32, h: i32) -> Element {\n    new_element(w, h, Prim::Spacer)\n}\n\n\n/// An Element that takes up no space. Good for things that appear conditionally.\npub fn empty() -> Element {\n    spacer(0, 0)\n}\n\n\n/// The various kinds of Elements.\n#[derive(Clone, Debug)]\npub enum Prim {\n    Image(ImageStyle, i32, i32, PathBuf),\n    Container(Position, Box<Element>),\n    Flow(Direction, Vec<Element>),\n    Collage(i32, i32, Vec<Form>),\n    Cleared(Color, Box<Element>),\n    Spacer,\n}\n\n\n/// Styling for the Image Element.\n#[derive(Copy, Clone, Debug)]\npub enum ImageStyle {\n    Plain,\n    Fitted,\n    Cropped(i32, i32),\n    Tiled,\n}\n\n\n/// Create an image given a width, height and texture.\npub fn image(w: i32, h: i32, path: PathBuf) -> Element {\n    new_element(w, h, Prim::Image(ImageStyle::Plain, w, h, path))\n}\n\n/// Create a fitted image given a width, height and texture. This will crop the picture to best\n/// fill the given dimensions.\npub fn fitted_image(w: i32, h: i32, path: PathBuf) -> Element {\n    new_element(w, h, Prim::Image(ImageStyle::Fitted, w, h, path))\n}\n\n/// Create a cropped image. Take a rectangle out of the picture starting at the given top left\n/// coordinate.\npub fn cropped_image(x: i32, y: i32, w: i32, h: i32, path: PathBuf) -> Element {\n    new_element(w, h, Prim::Image(ImageStyle::Cropped(x, y), w, h, path))\n}\n\n/// Create a tiled image given a width, height and texture.\npub fn tiled_image(w: i32, h: i32, path: PathBuf) -> Element {\n    new_element(w, h, Prim::Image(ImageStyle::Tiled, w, h, path))\n}\n\n\n#[derive(Copy, Clone, Debug)]\npub enum Three { P, Z, N }\n#[derive(Copy, Clone, Debug)]\npub enum Pos { Absolute(i32), Relative(f32) }\n\n/// An element's Position.\n#[derive(Copy, Clone, Debug)]\npub struct Position {\n    horizontal: Three,\n    vertical: Three,\n    x: Pos,\n    y: Pos,\n}\n\n/// The direction for a flow of `Element`s.\n#[derive(Copy, Clone, Debug)]\npub enum Direction { Up, Down, Left, Right, In, Out }\n\n\n/// Have a list of elements flow in a particular direction. The `Direction` starts from the first\n/// element in the list. The result is an `Element`.\npub fn flow(dir: Direction, elements: Vec<Element>) -> Element {\n    if elements.is_empty() { return empty() }\n    let max_w = elements.iter().map(|e| e.get_width()).max().unwrap();\n    let max_h = elements.iter().map(|e| e.get_height()).max().unwrap();\n    let sum_w = elements.iter().fold(0, |total, e| total + e.get_width());\n    let sum_h = elements.iter().fold(0, |total, e| total + e.get_height());\n    let new_flow = |w: i32, h: i32| new_element(w, h, Prim::Flow(dir, elements));\n    match dir {\n        Direction::Up | Direction::Down    => new_flow(max_w, sum_h),\n        Direction::Left | Direction::Right => new_flow(sum_w, max_h),\n        Direction::In | Direction::Out     => new_flow(max_w, max_h),\n    }\n}\n\n/// Layer elements on top of each other, starting from the bottom.\npub fn layers(elements: Vec<Element>) -> Element {\n    let max_w = elements.iter().map(|e| e.get_width()).max().unwrap_or(0);\n    let max_h = elements.iter().map(|e| e.get_height()).max().unwrap_or(0);\n    new_element(max_w, max_h, Prim::Flow(outward(), elements))\n}\n\n\n/// Repetitive things.\npub fn absolute(i: i32) -> Pos { Pos::Absolute(i) }\npub fn relative(f: f32) -> Pos { Pos::Relative(f) }\n\n#[inline]\nfn p(h: Three, v: Three, x: Pos, y: Pos) -> Position {\n    Position { horizontal: h, vertical: v, x: x, y: y }\n}\n\npub fn middle()       -> Position { p(Z, Z, relative(0.5), relative(0.5)) }\npub fn top_left()     -> Position { p(N, P, absolute(0), absolute(0)) }\npub fn top_right()    -> Position { p(P, P, absolute(0), absolute(0)) }\npub fn bottom_left()  -> Position { p(N, N, absolute(0), absolute(0)) }\npub fn bottom_right() -> Position { p(P, N, absolute(0), absolute(0)) }\npub fn mid_left()     -> Position { p(N, Z, absolute(0), relative(0.5)) }\npub fn mid_right()    -> Position { p(P, Z, absolute(0), relative(0.5)) }\npub fn mid_top()      -> Position { p(Z, P, relative(0.5), absolute(0)) }\npub fn mid_bottom()   -> Position { p(Z, N, relative(0.5), absolute(0)) }\n\npub fn middle_at(x: Pos, y: Pos)       -> Position { p(Z, Z, x, y) }\npub fn top_left_at(x: Pos, y: Pos)     -> Position { p(N, P, x, y) }\npub fn top_right_at(x: Pos, y: Pos)    -> Position { p(P, P, x, y) }\npub fn bottom_left_at(x: Pos, y: Pos)  -> Position { p(N, N, x, y) }\npub fn bottom_right_at(x: Pos, y: Pos) -> Position { p(P, N, x, y) }\npub fn mid_left_at(x: Pos, y: Pos)     -> Position { p(N, Z, x, y) }\npub fn mid_right_at(x: Pos, y: Pos)    -> Position { p(P, Z, x, y) }\npub fn mid_top_at(x: Pos, y: Pos)      -> Position { p(Z, P, x, y) }\npub fn mid_bottom_at(x: Pos, y: Pos)   -> Position { p(Z, N, x, y) }\n\npub fn up() -> Direction { Direction::Up }\npub fn down() -> Direction { Direction::Down }\npub fn left() -> Direction { Direction::Left }\npub fn right() -> Direction { Direction::Right }\npub fn inward() -> Direction { Direction::In }\npub fn outward() -> Direction { Direction::Out }\n\n\n\n\n\n\n\n\n/// \n/// CUSTOM NON-ELM FUNCTIONS\n///\n\n\n\n/// Used for rendering elmesque `Element`s.\npub struct Renderer<'a, C: 'a, G: 'a> {\n    context: Context,\n    backend: &'a mut G,\n    maybe_character_cache: Option<&'a mut C>,\n}\n\nimpl<'a, C, G> Renderer<'a, C, G> {\n\n    /// Construct a renderer, used for rendering elmesque `Element`s.\n    pub fn new(context: Context, backend: &'a mut G) -> Renderer<'a, C, G> {\n        Renderer {\n            context: context,\n            backend: backend,\n            maybe_character_cache: None,\n        }\n    }\n\n    /// Builder method for constructing a Renderer with a GlyphCache for drawing text.\n    pub fn character_cache(self, character_cache: &'a mut C) -> Renderer<'a, C, G> {\n        Renderer { maybe_character_cache: Some(character_cache), ..self }\n    }\n\n}\n\n\n\n/// Draw an Element.\npub fn draw_element<'a, C: CharacterCache, G: Graphics<Texture=C::Texture>>(\n    element: &Element,\n    opacity: f32,\n    backend: &mut G,\n    maybe_character_cache: &mut Option<&mut C>,\n    context: Context,\n) {\n    let Element { ref props, ref element } = *element;\n\n    // Crop the Element if some crop was given.\n    // We'll use the `DrawState::scissor` method for this.\n    //\n    // Because `DrawState`'s `scissor` `Rect` uses bottom-left origin coords, we'll have to convert\n    // from our centered-origin coordinate system.\n    //\n    // We'll also need to stretch our coords to match the correct viewport.draw_size.\n    let context = match props.crop {\n        Some((x, y, w, h)) => {\n            use utils::{clamp, map_range};\n            let Context { draw_state, .. } = context;\n\n            // Our view_dim is our virtual window size which is consistent no matter the display.\n            let view_dim = context.get_view_size();\n\n            // Our draw_dim is the actual window size in pixels. Our target crop area must be\n            // represented in this size.\n            let draw_dim = match context.viewport {\n                Some(viewport) => [viewport.draw_size[0] as f64, viewport.draw_size[1] as f64],\n                None => view_dim,\n            };\n\n            // Calculate the distance to the edges of the window from the center.\n            let left = -view_dim[0] / 2.0;\n            let right = view_dim[0] / 2.0;\n            let bottom = -view_dim[1] / 2.0;\n            let top = view_dim[1] / 2.0;\n\n            // We start with the x and y in the center of our crop area, however we need it to be\n            // at the top left of the crop area.\n            let left_x = x - w as f64 / 2.0;\n            let top_y = y - h as f64 / 2.0;\n\n            // Map the position at the top left of the crop area in view_dim to our draw_dim.\n            let x = map_range(left_x, left, right, 0, draw_dim[0] as i32);\n            let y = map_range(top_y, bottom, top, 0, draw_dim[1] as i32);\n \n            // Convert the w and h from our view_dim to the draw_dim.\n            let w_scale = draw_dim[0] / view_dim[0];\n            let h_scale = draw_dim[1] / view_dim[1];\n            let w = w * w_scale;\n            let h = h * h_scale;\n\n            // If we ended up with negative coords for the crop area, we'll use 0 instead as we\n            // can't represent the negative coords with `u16` (the target DrawState dimension type).\n            // We'll hold onto the lost negative values (x_neg and y_neg) so that we can compensate\n            // with the width and height.\n            let x_neg = if x < 0 { x } else { 0 };\n            let y_neg = if y < 0 { y } else { 0 };\n            let mut x = ::std::cmp::max(0, x) as u16;\n            let mut y = ::std::cmp::max(0, y) as u16;\n            let mut w = ::std::cmp::max(0, (w as i32 + x_neg)) as u16;\n            let mut h = ::std::cmp::max(0, (h as i32 + y_neg)) as u16;\n            \n            // If there was already some scissor set, we must check for the intersection.\n            if let Some(rect) = draw_state.scissor {\n                if x + w < rect.x || rect.x + rect.w < x || y + h < rect.y || rect.y + rect.h < y {\n                    // If there is no intersection, we have no scissor.\n                    w = 0;\n                    h = 0;\n                } else {\n                    // If there is some intersection, calculate the overlapping rect.\n                    let (a_l, a_r, a_b, a_t) = (x, x+w, y, y+h);\n                    let (b_l, b_r, b_b, b_t) = (rect.x, rect.x+rect.w, rect.y, rect.y+rect.h);\n                    let l = if a_l > b_l { a_l } else { b_l };\n                    let r = if a_r < b_r { a_r } else { b_r };\n                    let b = if a_b > b_b { a_b } else { b_b };\n                    let t = if a_t < b_t { a_t } else { b_t };\n                    x = l;\n                    y = b;\n                    w = r - l;\n                    h = t - b;\n                }\n            }\n\n            Context { draw_state: draw_state.scissor(x, y, w, h), ..context }\n        },\n        None => context,\n    };\n\n    match *element {\n\n        Prim::Image(style, w, h, ref path) => {\n            let Properties { width, height, opacity, color, .. } = *props;\n            match style {\n                ImageStyle::Plain => {\n                    // let image = graphics::Image {\n                    //     color: None,\n                    //     rectangle: None,\n                    //     source_rectangle: Some([src_x, src_y, w, h]),\n                    // };\n                    // let image = Image::new();\n                    // let texture: &Texture = ::std::ops::Deref::deref(&texture);\n                    // image.draw(texture, draw_state, matrix, backend);\n                    unimplemented!();\n                },\n                ImageStyle::Fitted => {\n                    unimplemented!();\n                },\n                ImageStyle::Cropped(x, y) => {\n                    unimplemented!();\n                },\n                ImageStyle::Tiled => {\n                    unimplemented!();\n                },\n            }\n        },\n\n        Prim::Container(position, ref element) => {\n            let Position { horizontal, vertical, x, y } = position;\n            let context = match (x, y) {\n                (Pos::Relative(x), Pos::Relative(y)) => context.trans(x as f64, y as f64),\n                (Pos::Absolute(x), Pos::Relative(y)) => Context {\n                    transform: transform_2d::matrix(1.0, 0.0, 0.0, 1.0, x as f64, 0.0).0,\n                    ..context\n                }.trans(0.0, y as f64),\n                (Pos::Relative(x), Pos::Absolute(y)) => Context {\n                    transform: transform_2d::matrix(1.0, 0.0, 0.0, 1.0, 0.0, y as f64).0,\n                    ..context\n                }.trans(x as f64, 0.0),\n                (Pos::Absolute(x), Pos::Absolute(y)) => Context {\n                    transform: transform_2d::matrix(1.0, 0.0, 0.0, 1.0, x as f64, y as f64).0,\n                    ..context\n                },\n            };\n            let new_opacity = opacity * props.opacity;\n            draw_element(element, new_opacity, backend, maybe_character_cache, context);\n        }\n\n        Prim::Flow(direction, ref elements) => {\n            let mut context = context;\n            match direction {\n                Direction::Up | Direction::Down => {\n                    let multi = if let Direction::Up = direction { 1.0 } else { -1.0 };\n                    let mut half_prev_height = 0.0;\n                    for element in elements.iter() {\n                        let half_height = element.get_height() as f64 / 2.0;\n                        let new_opacity = opacity * props.opacity;\n                        draw_element(element, new_opacity, backend, maybe_character_cache, context);\n                        let y_trans = half_height + half_prev_height;\n                        context = context.trans(0.0, y_trans * multi);\n                        half_prev_height = half_height;\n                    }\n                },\n                Direction::Left | Direction::Right => {\n                    let multi = if let Direction::Right = direction { 1.0 } else { -1.0 };\n                    let mut half_prev_width = 0.0;\n                    for element in elements.iter() {\n                        let half_width = element.get_width() as f64 / 2.0;\n                        let new_opacity = opacity * props.opacity;\n                        draw_element(element, new_opacity, backend, maybe_character_cache, context);\n                        let x_trans = half_width + half_prev_width;\n                        context = context.trans(x_trans * multi, 0.0);\n                        half_prev_width = half_width;\n                    }\n                },\n                Direction::Out => {\n                    for element in elements.iter() {\n                        let new_opacity = opacity * props.opacity;\n                        draw_element(element, new_opacity, backend, maybe_character_cache, context);\n                    }\n                }\n                Direction::In => {\n                    for element in elements.iter().rev() {\n                        let new_opacity = opacity * props.opacity;\n                        draw_element(element, new_opacity, backend, maybe_character_cache, context);\n                    }\n                }\n            }\n        },\n\n        Prim::Collage(w, h, ref forms) => {\n            for form in forms.iter() {\n                let new_opacity = opacity * props.opacity;\n                form::draw_form(form, new_opacity, backend, maybe_character_cache, context);\n            }\n        },\n\n        Prim::Cleared(color, ref element) => {\n            backend.clear_color(color.to_fsa());\n            draw_element(element, opacity, backend, maybe_character_cache, context);\n        },\n\n        Prim::Spacer => {},\n\n    }\n}\n\n"
  },
  {
    "path": "src/form.rs",
    "content": "//!\n//! Ported from [elm-lang's `Graphics.Collage` module]\n//! (https://github.com/elm-lang/core/blob/62b22218c42fb8ccc996c86bea450a14991ab815/src/Graphics/Collage.elm).\n//!\n//!\n//! This module is for freeform graphics. You can shift, rotate, scale etc. All sorts of forms\n//! including lines, shapes, images and elements.\n//!\n//! Collages use the same coordinate system you might see in an algebra or physics problem. The\n//! origin (0, 0) is at the center of the collage, not the top left corner as in some other\n//! graphics libraries. Furthermore, the y-axis points up, so shifting a form 10 units in the\n//! y-axis will move it up screen.\n//!\n//! # Creating Forms\n//! to_form, filled, textured, gradient, outlined, traced, text, outlined_text\n//!\n//! # Transforming Forms\n//! shift, shift_x, shift_y, scale, rotate, alpha\n//!\n//! # Grouping Forms\n//! Grouping forms makes it easier to write modular graphics code. You can create a form that is a\n//! composite of many subforms. From there it is easy to transform it as a single unit.\n//! group, group_transform\n//!\n//! # Shapes\n//! rect, oval, square, circle, ngon, polygon\n//!\n//! # Paths\n//! segment, path\n//!\n//! # Line Styles\n//! solid, dashed, dotted, LineStyle, LineCap, LineJoin\n//!\n\n\nuse color::{Color, Gradient};\nuse element::{self, Element, new_element};\nuse graphics::{self, Context, Graphics, Transformed};\nuse graphics::character::CharacterCache;\nuse std::f64::consts::PI;\nuse std::path::PathBuf;\nuse text::Text;\nuse transform_2d::{self, Transform2D};\n\n\n/// A general, freeform 2D graphics structure.\n#[derive(Clone, Debug)]\npub struct Form {\n    pub theta: f64,\n    pub scale: f64,\n    pub x: f64,\n    pub y: f64,\n    pub alpha: f32,\n    pub form: BasicForm,\n}\n\n\n#[derive(Clone, Debug)]\npub enum FillStyle {\n    Solid(Color),\n    Texture(PathBuf),\n    Grad(Gradient),\n}\n\n\n#[derive(Copy, Clone, Debug)]\npub enum LineCap {\n    Flat,\n    Round,\n    Padded,\n}\n\n\n#[derive(Copy, Clone, Debug)]\npub enum LineJoin {\n    Smooth,\n    Sharp(f64),\n    Clipped,\n}\n\n\n#[derive(Clone, Debug)]\npub struct LineStyle {\n    pub color: Color,\n    pub width: f64,\n    pub cap: LineCap,\n    pub join: LineJoin,\n    pub dashing: Vec<i64>,\n    pub dash_offset: i64,\n}\n\n\nimpl LineStyle {\n\n    /// The default LineStyle.\n    pub fn default() -> LineStyle {\n        LineStyle {\n            color: ::color::black(),\n            width: 1.0,\n            cap: LineCap::Flat,\n            join: LineJoin::Sharp(10.0),\n            dashing: Vec::new(),\n            dash_offset: 0,\n        }\n    }\n\n    /// The LineStyle with some given width.\n    #[inline]\n    pub fn width(self, w: f64) -> LineStyle {\n        LineStyle { width: w, ..self }\n    }\n\n}\n\n\n/// Create a solid line style with a given color.\npub fn solid(color: Color) -> LineStyle {\n    LineStyle { color: color, ..LineStyle::default() }\n}\n\n/// Create a dashed line style with a given color. Dashing equals `[8, 4]`.\npub fn dashed(color: Color) -> LineStyle {\n    LineStyle { color: color, dashing: vec![8, 4], ..LineStyle::default() }\n}\n\n/// Create a dotted line style with a given color. Dashing equals `[3, 3]`.\npub fn dotted(color: Color) -> LineStyle {\n    LineStyle { color: color, dashing: vec![3, 3], ..LineStyle::default() }\n}\n\n\n/// The basic variants a Form can consist of.\n#[derive(Clone, Debug)]\npub enum BasicForm {\n    PointPath(LineStyle, PointPath),\n    Shape(ShapeStyle, Shape),\n    OutlinedText(LineStyle, Text),\n    Text(Text),\n    Image(i32, i32, (i32, i32), PathBuf),\n    Element(Element),\n    Group(Transform2D, Vec<Form>),\n}\n\n\n/// Whether a shape is outlined or filled.\n#[derive(Clone, Debug)]\npub enum ShapeStyle {\n    Line(LineStyle),\n    Fill(FillStyle),\n}\n\n\nimpl Form {\n\n    fn new(basic_form: BasicForm) -> Form {\n        Form {\n            theta: 0.0,\n            scale: 1.0,\n            x: 0.0,\n            y: 0.0,\n            alpha: 1.0,\n            form: basic_form,\n        }\n    }\n\n\n    /// Move a form by the given amount. this is a relative translation so `shift(10.0, 10.0, form)\n    /// would move `form` ten pixels up and ten pixels to the right.\n    #[inline]\n    pub fn shift(self, x: f64, y: f64) -> Form {\n        Form { x: self.x + x, y: self.y + y, ..self }\n    }\n\n\n    /// Move a shape in the x direction. This is relative so `shift_x(10.0, form)` moves `form` 10\n    /// pixels to the right.\n    #[inline]\n    pub fn shift_x(self, x: f64) -> Form {\n        self.shift(x, 0.0)\n    }\n\n\n    /// Move a shape in the y direction. This is relative so `shift_y(10.0, form)` moves `form\n    /// upwards by 10 pixels.\n    #[inline]\n    pub fn shift_y(self, y: f64) -> Form {\n        self.shift(0.0, y)\n    }\n\n\n    /// Scale a form by a given factor. Scaling by 2 doubles both dimensions and quadruples the\n    /// area.\n    #[inline]\n    pub fn scale(self, scale: f64) -> Form {\n        Form { scale: self.scale * scale, ..self }\n    }\n\n\n    /// Rotate a form by a given angle. Rotate takes radians and turns things counterclockwise.\n    /// So to turn `form` 30 degrees to the left you would say `rotate(degrees(30), form)`.\n    #[inline]\n    pub fn rotate(self, theta: f64) -> Form {\n        Form { theta: self.theta + theta, ..self }\n    }\n\n\n    /// Set the alpha of a Form. The default is 1 and 0 is totally transparent.\n    #[inline]\n    pub fn alpha(self, alpha: f32) -> Form {\n        Form { alpha: alpha, ..self }\n    }\n\n}\n\n\n/// Turn any `Element` into a `Form`. This lets you use text, gifs, and video in your collage. This\n/// means you can move, rotate, and scale an `Element` however you want.\npub fn to_form(element: Element) -> Form {\n    Form::new(BasicForm::Element(element))\n}\n\n\n/// Flatten many forms into a single `Form`. This lets you move and rotate them as a single unit,\n/// making it possible to build small, modular components.\npub fn group(forms: Vec<Form>) -> Form {\n    Form::new(BasicForm::Group(transform_2d::identity(), forms))\n}\n\n\n/// Flatten many forms into a single `Form` and then apply a matrix transformation.\npub fn group_transform(matrix: Transform2D, forms: Vec<Form>) -> Form {\n    Form::new(BasicForm::Group(matrix, forms))\n}\n\n\n/// Trace a path with a given line style.\npub fn traced(style: LineStyle, path: PointPath) -> Form {\n    Form::new(BasicForm::PointPath(style, path))\n}\n\n\n/// Create a line with a given line style.\npub fn line(style: LineStyle, x1: f64, y1: f64, x2: f64, y2: f64) -> Form {\n    traced(style, segment((x1, y1), (x2, y2)))\n}\n\n\n/// Create a sprite from a sprite sheet. It cuts out a rectangle at a given position.\npub fn sprite(w: i32, h: i32, pos: (i32, i32), path: PathBuf) -> Form {\n    Form::new(BasicForm::Image(w, h, pos, path))\n}\n\n\n/// A collage is a collection of 2D forms. There are no strict positioning relationships between\n/// forms, so you are free to do all kinds of 2D graphics.\npub fn collage(w: i32, h: i32, forms: Vec<Form>) -> Element {\n    new_element(w, h, element::Prim::Collage(w, h, forms))\n}\n\n\n/// A path described by a sequence of points.\n#[derive(Clone, Debug)]\npub struct PointPath(pub Vec<(f64, f64)>);\n\n\n/// Create a PointPath that follows a sequence of points.\npub fn point_path(points: Vec<(f64, f64)>) -> PointPath {\n    PointPath(points)\n}\n\n\n/// Create a PointPath along a given line segment. \npub fn segment(a: (f64, f64), b: (f64, f64)) -> PointPath {\n    PointPath(vec![a, b])\n}\n\n\n/// A shape described by its edges.\n#[derive(Clone, Debug)]\npub struct Shape(pub Vec<(f64, f64)>);\n\n\nimpl Shape {\n\n    #[inline]\n    fn fill(self, style: FillStyle) -> Form {\n        Form::new(BasicForm::Shape(ShapeStyle::Fill(style), self))\n    }\n\n\n    /// Create a filled-in shape.\n    #[inline]\n    pub fn filled(self, color: Color) -> Form {\n        self.fill(FillStyle::Solid(color))\n    }\n\n\n    /// Create a textured shape.\n    /// The texture is described by some path and is tiled to fill the entire shape.\n    #[inline]\n    pub fn textured(self, path: PathBuf) -> Form {\n        self.fill(FillStyle::Texture(path))\n    }\n\n\n    /// Fill a shape with a gradient.\n    #[inline]\n    pub fn gradient(self, grad: Gradient) -> Form {\n        self.fill(FillStyle::Grad(grad))\n    }\n\n\n    /// Outline a shape with a given line style.\n    #[inline]\n    pub fn outlined(self, style: LineStyle) -> Form {\n        Form::new(BasicForm::Shape(ShapeStyle::Line(style), self))\n    }\n\n}\n\n\n/// Create an arbitrary polygon by specifying its corners in order. `polygon` will automatically\n/// close all shapes, so the given list of points does not need to start and end with the same\n/// position.\npub fn polygon(points: Vec<(f64, f64)>) -> Shape {\n    Shape(points)\n}\n\n\n/// A rectangle with a given width and height.\npub fn rect(w: f64, h: f64) -> Shape {\n    let hw = w / 2.0;\n    let hh = h / 2.0;\n    Shape(vec![ (0.0-hw, 0.0-hh), (0.0-hw, hh), (hw, hh), (hw, 0.0-hh) ])\n}\n\n\n/// A square with a given edge length.\npub fn square(n: f64) -> Shape {\n    rect(n, n)\n}\n\n\n/// An oval with a given width and height.\npub fn oval(w: f64, h: f64) -> Shape {\n    let n: usize = 50;\n    let t = 2.0 * PI / n as f64;\n    let hw = w / 2.0;\n    let hh = h / 2.0;\n    let f = |i: f64| (hw * (t*i).cos(), hh * (t*i).sin());\n    let points = (0..n-1).map(|i| f(i as f64)).collect();\n    Shape(points)\n}\n\n\n/// A circle with a given radius.\npub fn circle(r: f64) -> Shape {\n    let d = 2.0 * r;\n    oval(d, d)\n}\n\n\n/// A regular polygon with N sides. The first argument specifies the number of sides and the second\n/// is the radius. So to create a pentagon with radius 30, you would say `ngon(5, 30.0)`\npub fn ngon(n: usize, r: f64) -> Shape {\n    let t = 2.0 * PI / n as f64;\n    let f = |i: f64| (r * (t*i).cos(), r * (t*i).sin());\n    let points = (0..n).map(|i| f(i as f64)).collect();\n    Shape(points)\n}\n\n\n/// Create some text. Details like size and color are part of the `Text` value itself, so you can\n/// mix colors and sizes and fonts easily.\npub fn text(t: Text) -> Form {\n    Form::new(BasicForm::Text(t))\n}\n\n\n\n\n\n\n\n\n\n/// \n/// CUSTOM NON-ELM FUNCTIONS.\n/// \n/// Normally Elm renders to html and javascript, however the aim of elmesque is to render to GL.\n///\n\n\n/// This function draws a form with some given transform using the generic [Piston graphics]\n/// (https://github.com/PistonDevelopers/graphics) backend.\npub fn draw_form<'a, C: CharacterCache, G: Graphics<Texture=C::Texture>>(\n    form: &Form,\n    alpha: f32,\n    backend: &mut G,\n    maybe_character_cache: &mut Option<&mut C>,\n    context: Context,\n) {\n    let Form { theta, scale, x, y, alpha, ref form } = *form;\n    let context = context.trans(x, y).scale(scale, scale).rot_rad(theta);\n    match *form {\n\n        BasicForm::PointPath(ref line_style, PointPath(ref points)) => {\n            // NOTE: join, dashing and dash_offset are not yet handled properly.\n            let LineStyle { color, width, cap, join, ref dashing, dash_offset } = *line_style;\n            let color = convert_color(color, alpha);\n            let mut draw_line = |(x1, y1), (x2, y2)| {\n                if dashing.is_empty() {\n                    let line = match cap {\n                        LineCap::Flat => graphics::Line::new(color, width / 2.0),\n                        LineCap::Round => graphics::Line::new_round(color, width / 2.0),\n                        LineCap::Padded => unimplemented!(),\n                    };\n                    line.draw([x1, y1, x2, y2], &context.draw_state, context.transform, backend);\n                } else {\n                    unimplemented!();\n                }\n            };\n            for window in points.windows(2) {\n                let (a, b) = (window[0], window[1]);\n                draw_line(a, b);\n            }\n        },\n\n        BasicForm::Shape(ref shape_style, Shape(ref points)) => {\n            match *shape_style {\n                ShapeStyle::Line(ref line_style) => {\n                    // NOTE: join, dashing and dash_offset are not yet handled properly.\n                    let LineStyle { color, width, cap, join, ref dashing, dash_offset } = *line_style;\n                    let color = convert_color(color, alpha);\n                    let mut draw_line = |(x1, y1), (x2, y2)| {\n                        let line = match cap {\n                            LineCap::Flat => graphics::Line::new(color, width / 2.0),\n                            LineCap::Round => graphics::Line::new_round(color, width / 2.0),\n                            LineCap::Padded => unimplemented!(),\n                        };\n                        line.draw([x1, y1, x2, y2], &context.draw_state, context.transform, backend);\n                    };\n                    for window in points.windows(2) {\n                        let (a, b) = (window[0], window[1]);\n                        draw_line(a, b);\n                    }\n                    if points.len() > 2 {\n                        draw_line(points[points.len()-1], points[0])\n                    }\n                },\n                ShapeStyle::Fill(ref fill_style) => match *fill_style {\n                    FillStyle::Solid(color) => {\n                        let color = convert_color(color, alpha);\n                        let polygon = graphics::Polygon::new(color);\n                        let points: Vec<_> = points.iter().map(|&(x, y)| [x, y]).collect();\n                        polygon.draw(&points[..], &context.draw_state, context.transform, backend);\n                    },\n                    FillStyle::Texture(ref path) => {\n                        unimplemented!();\n                    },\n                    FillStyle::Grad(ref gradient) => {\n                        unimplemented!();\n                    },\n                },\n            }\n        },\n\n        BasicForm::OutlinedText(ref line_style, ref text) => {\n            unimplemented!();\n        },\n\n        BasicForm::Text(ref text) => {\n            let context = context.scale(1.0, -1.0);\n            if let Some(ref mut character_cache) = *maybe_character_cache {\n                use text::Style as TextStyle;\n                use text::Position as TextPosition;\n                use text::TextUnit;\n                let (total_width, max_height) = text.sequence.iter().fold((0.0, 0.0), |(w, h), unit| {\n                    let TextUnit { ref string, ref style } = *unit;\n                    let TextStyle { ref typeface, height, color, bold, italic, line, monospace } = *style;\n                    let height = height.unwrap_or(16.0);\n                    let new_total_width = w + character_cache.width(height as u32, &string);\n                    let new_max_height = if height > h { height } else { h };\n                    (new_total_width, new_max_height)\n                });\n                let x_offset = match text.position {\n                        TextPosition::Center  => -(total_width / 2.0).floor(),\n                        TextPosition::ToLeft  => -total_width.floor(),\n                        TextPosition::ToRight => 0.0\n                    };\n                let y_offset = (max_height / 3.0).floor(); // TODO: FIX THIS (3.0)\n                let context = context.trans(x_offset, y_offset);\n                for unit in text.sequence.iter() {\n                    let TextUnit { ref string, ref style } = *unit;\n                    let TextStyle { ref typeface, height, color, bold, italic, line, monospace } = *style;\n                    let height = height.unwrap_or(16.0).floor();\n                    let color = convert_color(color, alpha);\n                    graphics::text::Text::new_color(color, height as u32)\n                        .round()\n                        .draw(&string[..], *character_cache, &context.draw_state, context.transform, backend);\n                }\n            }\n        },\n\n        BasicForm::Image(src_x, src_y, (w, h), ref path) => {\n            // let image = graphics::Image {\n            //     color: None,\n            //     rectangle: None,\n            //     source_rectangle: Some([src_x, src_y, w, h]),\n            // };\n            // let texture: &Texture = ::std::ops::Deref::deref(&texture);\n            // image.draw(texture, draw_state, matrix, backend);\n            unimplemented!();\n        },\n\n        BasicForm::Group(ref group_transform, ref forms) => {\n            let Transform2D(matrix) = Transform2D(context.transform.clone())\n                .multiply(group_transform.clone());\n            let context = Context { transform: matrix, ..context };\n            for form in forms.iter() {\n                draw_form(form, alpha, backend, maybe_character_cache, context);\n            }\n        },\n\n        BasicForm::Element(ref element) =>\n            element::draw_element(element, alpha, backend, maybe_character_cache, context),\n    }\n}\n\n/// Convert an elmesque color to a piston-graphics color.\nfn convert_color(color: Color, alpha: f32) -> [f32; 4] {\n    use color::hsl_to_rgb;\n    let ((r, g, b), a) = match color {\n        Color::Hsla(h, s, l, a) => (hsl_to_rgb(h, s, l), a),\n        Color::Rgba(r, g, b, a) => ((r, g, b), a),\n    };\n    [r, g, b, a * alpha]\n}\n\n"
  },
  {
    "path": "src/lib.rs",
    "content": "//!\n//! This crate is an attempt at porting Elm's incredibly useful std graphics modules.\n//!\n//! Visit [elm-lang.org](http://elm-lang.org/).\n//!\n//!\n//! All credit goes to Evan Czaplicki for all algorithms included within.\n//!\n//! Ported to Rust by Mitchell Nordine.\n//!\n\nextern crate graphics;\nextern crate num;\nextern crate rand;\nextern crate rustc_serialize;\nextern crate vecmath;\n\npub use color as colour;\npub use element::{Element, Renderer};\npub use form::{Form};\n\npub mod color;\npub mod element;\npub mod form;\npub mod text;\npub mod transform_2d;\npub mod utils;\n"
  },
  {
    "path": "src/text.rs",
    "content": "\nuse color::{black, Color};\nuse std::path::PathBuf;\n\n\n/// Drawable Text.\n#[derive(Clone, Debug)]\npub struct Text {\n    pub sequence: Vec<TextUnit>,\n    pub position: Position,\n}\n\n\n#[derive(Clone, Debug)]\npub struct TextUnit {\n    pub string: String,\n    pub style: Style,\n}\n\n/// Styles for lines on text. This allows you to add an underline, an overline, or strike out text.\n#[derive(Copy, Clone, Debug)]\npub enum Line {\n    Under,\n    Over,\n    Through,\n}\n\n/// Text position relative to center point\n#[derive(Copy, Clone, Debug)]\npub enum Position {\n    Center,\n    ToLeft,\n    ToRight\n}\n\n\n/// Represents all the ways you can style `Text`. If the `type_face` list is empty or the `height`\n/// is `None`, the users will fall back on their default settings. The following `Style` is black,\n/// 16 pixel tall, underlined, and Times New Roman (assuming that typeface is available on the\n/// user's computer):\n///\n///   Style {\n///       type_face: Some(\"Times New Roman\"),\n///       height: Some(16),\n///       color: black(),\n///       bold: false,\n///       italic: false,\n///       line: Some(Line::Under),\n///   }\n///\n#[derive(Clone, Debug)]\npub struct Style {\n    pub typeface: Option<PathBuf>,\n    pub height: Option<f64>,\n    pub color: Color,\n    pub bold: bool,\n    pub italic: bool,\n    pub line: Option<Line>,\n    pub monospace: bool,\n}\n\nimpl Style {\n    pub fn default() -> Style {\n        Style {\n            typeface: None,\n            height: None,\n            color: black(),\n            bold: false,\n            italic: false,\n            line: None,\n            monospace: false,\n        }\n    }\n}\n\n\nimpl Text {\n\n    /// Convert a string into text which can be styled and displayed.\n    pub fn from_string(string: String) -> Text {\n        Text {\n            sequence: vec![TextUnit { string: string, style: Style::default(), }],\n            position: Position::Center\n        }\n    }\n\n    /// Text with nothing in it.\n    pub fn empty() -> Text {\n        Text::from_string(\"\".to_string())\n    }\n\n    /// Put two chunks of text together.\n    #[inline]\n    pub fn append(mut self, other: Text) -> Text {\n        self.sequence.extend(other.sequence.into_iter());\n        self\n    }\n\n    /// Put many chunks of text together.\n    pub fn concat(texts: Vec<Text>) -> Text {\n        let position = texts.get(0).map(|t| t.position).unwrap_or(Position::Center);\n        Text {\n            sequence: texts.into_iter()\n                .flat_map(|Text { sequence, position }| sequence.into_iter())\n                .collect(),\n            position: position\n        }\n    }\n\n    /// Put many chunks of text together with a separator.\n    pub fn join(separator: Text, texts: Vec<Text>) -> Text {\n        texts.into_iter().fold(Text::empty(), |texts, text| {\n            texts.append(text).append(separator.clone())\n        })\n    }\n\n    /// Set the style of some text. For example, if you design a `Style` called `foorter_style` that is\n    /// specifically for the bottom of your page, you could apply it to text like this:\n    ///\n    ///   style(footer_style, from_string(\"the old prince / 2007\"))\n    ///\n    #[inline]\n    pub fn style(self, style: Style) -> Text {\n        let string = String::from_utf8(self.sequence.into_iter().flat_map(|unit| {\n            unit.string.into_bytes().into_iter()\n        }).collect()).unwrap();\n        Text {\n            sequence: vec![TextUnit { string: string, style: style }],\n            ..self\n        }\n    }\n\n    /// Provide a path of a typeface to be used for some text.\n    #[inline]\n    pub fn typeface(mut self, path: PathBuf) -> Text {\n        for unit in self.sequence.iter_mut() {\n            unit.style.typeface = Some(path.clone());\n        }\n        self\n    }\n\n    /// Switch to a monospace typeface. Good for code snippets.\n    ///\n    ///   monospace(from_string(\"(0..3).fold(0, |a, b| a + b)\"))\n    ///\n    #[inline]\n    pub fn monospace(mut self) -> Text {\n        for unit in self.sequence.iter_mut() {\n            unit.style.monospace = true;\n        }\n        self\n    }\n\n    /// Set the height of some text in pixels.\n    #[inline]\n    pub fn height(mut self, h: f64) -> Text {\n        for unit in self.sequence.iter_mut() {\n            unit.style.height = Some(h);\n        }\n        self\n    }\n\n    /// Set the color of some text.\n    #[inline]\n    pub fn color(mut self, color: Color) -> Text {\n        for unit in self.sequence.iter_mut() {\n            unit.style.color = color;\n        }\n        self\n    }\n\n    /// Make the text bold.\n    #[inline]\n    pub fn bold(mut self) -> Text {\n        for unit in self.sequence.iter_mut() {\n            unit.style.bold = true;\n        }\n        self\n    }\n\n    /// Make the text italic.\n    #[inline]\n    pub fn italic(mut self) -> Text {\n        for unit in self.sequence.iter_mut() {\n            unit.style.italic = true;\n        }\n        self\n    }\n\n    /// Put lines on text.\n    #[inline]\n    pub fn line(mut self, line: Line) -> Text {\n        for unit in self.sequence.iter_mut() {\n            unit.style.line = Some(line);\n        }\n        self\n    }\n\n    /// Change the text position relative to it's center point\n    #[inline]\n    pub fn position(mut self, position: Position) -> Text {\n        self.position = position;\n        self\n    }\n}\n\n"
  },
  {
    "path": "src/transform_2d.rs",
    "content": "//!\n//! Ported from [elm-lang's Transform2D module]\n//! (https://github.com/elm-lang/core/blob/62b22218c42fb8ccc996c86bea450a14991ab815/src/Transform2D.elm)\n//!\n//!\n//! A library for performing 2D matrix transformations. It is used primarily with the\n//! `group_transform` function from the `form` module and allows you to do things like rotation,\n//! scaling, translation, shearing and reflection.\n//!\n//! Note that all the matrices in this library are 3*3 matrices of homogeneous coordinates, used\n//! for affine transformations. Since the bottom row is always `0 0 1` in these matrices, it is\n//! omitted in the diagrams below.\n//!\n\n\nuse vecmath::{mat2x3_id, Matrix2x3, row_mat2x3_mul};\n\npub type Matrix2d = Matrix2x3<f64>;\n\n/// Represents a 2D transform.\n#[derive(Clone, Debug)]\npub struct Transform2D(pub Matrix2d);\n\nimpl Transform2D {\n\n    /// Multiply two transforms together.\n    ///\n    ///   ma mb mx     na nb nx\n    ///   mc md my  .  nc nd ny\n    ///    0  0  1      0  0  1\n    ///\n    #[inline]\n    pub fn multiply(self, other: Transform2D) -> Transform2D {\n        let (Transform2D(m), Transform2D(n)) = (self, other);\n        Transform2D(row_mat2x3_mul(m, n))\n    }\n\n}\n\n/// Create an identity transform. Transforming by the identity does not change anything, but it can\n/// come in handy as a default or base case.\n///\n///   1 0 0\n///   0 1 0\n///\n#[inline]\npub fn identity() -> Transform2D {\n    Transform2D(mat2x3_id())\n}\n\n/// Creates a transformation matrix. This lets you create transforms such as scales, shears,\n/// reflections and translations.\n///\n///   a b x\n///   c d y\n///\n#[inline]\npub fn matrix(a: f64, b: f64, c: f64, d: f64, x: f64, y: f64) -> Transform2D {\n    Transform2D([ [a, b, x], [c, d, y] ])\n}\n\n/// Create a [rotation matrix](http://en.wikipedia.org/wiki/Rotation_matrix). Given an angle t, it\n/// creates a counterclockwise rotation matrix.\n///\n///   cos t  -sin t  0\n///   sin t   cos t  0\n///\n#[inline]\npub fn rotation(t: f64) -> Transform2D {\n    Transform2D([ [t.cos(), -t.sin(), 0.0], [t.sin(), t.cos(), 0.0] ])\n}\n\n/// Creates a transformation matrix for translation.\n///\n///   1 0 x\n///   0 1 y\n///\n#[inline]\npub fn translation(x: f64, y: f64) -> Transform2D {\n    matrix(1.0, 0.0, 0.0, 1.0, x, y)\n}\n\n/// Creates a transformation matrix for scaling by all directions.\n///\n///   s 0 0\n///   0 s 0\n///\n#[inline]\npub fn scale(s: f64) -> Transform2D {\n    matrix(s, 0.0, 0.0, s, 0.0, 0.0)\n}\n\n/// Creates a transformation for horizontal scaling.\n#[inline]\npub fn scale_x(s: f64) -> Transform2D {\n    matrix(s, 0.0, 0.0, 1.0, 0.0, 0.0)\n}\n\n/// Creates a transformation for vertical scaling.\n#[inline]\npub fn scale_y(s: f64) -> Transform2D {\n    matrix(1.0, 0.0, 0.0, s, 0.0, 0.0)\n}\n\n"
  },
  {
    "path": "src/utils.rs",
    "content": "\nuse num::{Float, NumCast};\nuse num::PrimInt as Int;\nuse num::traits::cast;\nuse std::f32::consts::PI;\n\n/// Clamp a f32 between 0f32 and 1f32.\npub fn clampf32(f: f32) -> f32 {\n    if f < 0f32 { 0f32 } else if f > 1f32 { 1f32 } else { f }\n}\n\n/// Convert degrees to radians.\npub fn degrees<F: Float + NumCast>(d: F) -> F {\n    d * cast(PI / 180.0).unwrap()\n}\n\n/// Convert turns to radians.\npub fn turns<F: Float + NumCast>(t: F) -> F {\n    let f: F = cast(2.0 * PI).unwrap();\n    f * t\n}\n\n/// The modulo function.\n#[inline]\npub fn modulo<I: Int>(a: I, b: I) -> I {\n    match a % b {\n        r if (r > I::zero() && b < I::zero())\n          || (r < I::zero() && b > I::zero()) => r + b,\n        r                                     => r,\n    }\n}\n\n/// Modulo float.\npub fn fmod(f: f32, n: i32) -> f32 {\n    let i = f.floor() as i32;\n    modulo(i, n) as f32 + f - i as f32\n}\n\n/// Return the min between to floats.\npub fn min(a: f32, b: f32) -> f32 {\n    if a <= b { a } else { b }\n}\n\n/// Return the max between to floats.\npub fn max(a: f32, b: f32) -> f32 {\n    if a >= b { a } else { b }\n}\n\n/// Clamp a value to a range.\n#[inline]\npub fn clamp<T: PartialOrd>(val: T, min: T, max: T) -> T {\n    if val < min { min } else { if val > max { max } else { val } }\n}\n\n/// Map a value from a given range to a new given range.\npub fn map_range<X: NumCast, Y: NumCast>\n(val: X, in_min: X, in_max: X, out_min: Y, out_max: Y) -> Y {\n    let val_f: f64 = NumCast::from(val).unwrap();\n    let in_min_f: f64 = NumCast::from(in_min).unwrap();\n    let in_max_f: f64 = NumCast::from(in_max).unwrap();\n    let out_min_f: f64 = NumCast::from(out_min).unwrap();\n    let out_max_f: f64 = NumCast::from(out_max).unwrap();\n    NumCast::from(\n        (val_f - in_min_f) / (in_max_f - in_min_f) * (out_max_f - out_min_f) + out_min_f\n    ).unwrap()\n}\n\n\n"
  }
]