├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTORS.md ├── LICENSE ├── Package.swift ├── README.md ├── Sources └── Igis │ ├── Alpha.swift │ ├── Audio.swift │ ├── Canvas.swift │ ├── CanvasIdentifiedObject.swift │ ├── CanvasObject.swift │ ├── ClipPath.swift │ ├── Color.swift │ ├── ColorStop.swift │ ├── Containment.swift │ ├── ContainmentSet.swift │ ├── CursorStyle.swift │ ├── DoublePoint.swift │ ├── Ellipse.swift │ ├── FillMode.swift │ ├── FillStyle.swift │ ├── Gradient.swift │ ├── HTTPHandler.swift │ ├── Igis.swift │ ├── Image.swift │ ├── Layout.swift │ ├── LineWidth.swift │ ├── Lines.swift │ ├── Matrix.swift │ ├── PainterBase.swift │ ├── PainterProtocol.swift │ ├── Path.swift │ ├── Pattern.swift │ ├── Point.swift │ ├── Rect.swift │ ├── Rectangle.swift │ ├── Resources │ ├── index.html │ ├── style.css │ └── websocket.js │ ├── Size.swift │ ├── State.swift │ ├── StrokeStyle.swift │ ├── Text.swift │ ├── TextMetric.swift │ ├── Transform.swift │ ├── Turtle.swift │ └── WebSocketHandler.swift ├── Tests ├── IgisTests │ ├── ColorTests.swift │ ├── PointTests.swift │ └── RectTests.swift └── LinuxMain.swift ├── docs ├── Alpha │ └── index.html ├── Audio │ └── index.html ├── Audio_Mode │ └── index.html ├── Canvas │ └── index.html ├── CanvasIdentifiedObject │ └── index.html ├── CanvasObject │ └── index.html ├── Clip │ └── index.html ├── ClipPath │ └── index.html ├── ClipPath_WindingRule │ └── index.html ├── Clip_WindingRule │ └── index.html ├── Color │ └── index.html ├── ColorStop │ └── index.html ├── Color_Name │ └── index.html ├── Containment │ └── index.html ├── ContainmentSet │ └── index.html ├── CursorStyle │ └── index.html ├── CursorStyle_Style │ └── index.html ├── DoublePoint │ └── index.html ├── Ellipse │ └── index.html ├── FillMode │ └── index.html ├── FillStyle │ └── index.html ├── Gradient │ └── index.html ├── Gradient_Mode │ └── index.html ├── Igis │ └── index.html ├── Image │ └── index.html ├── Image_RenderMode │ └── index.html ├── Layout │ └── index.html ├── Layout_ChildAttribute │ └── index.html ├── Layout_ChildRule │ └── index.html ├── LineWidth │ └── index.html ├── Lines │ └── index.html ├── Matrix │ └── index.html ├── PainterBase │ └── index.html ├── PainterProtocol │ └── index.html ├── Path │ └── index.html ├── Pattern │ └── index.html ├── Pattern_Repetition │ └── index.html ├── Point │ └── index.html ├── Rect │ └── index.html ├── Rectangle │ └── index.html ├── Size │ └── index.html ├── State │ └── index.html ├── State_Mode │ └── index.html ├── StrokeStyle │ └── index.html ├── Text │ └── index.html ├── TextMetric │ └── index.html ├── TextMetric_Metrics │ └── index.html ├── Text_Alignment │ └── index.html ├── Text_Baseline │ └── index.html ├── Transform │ └── index.html ├── Transform_Mode │ └── index.html ├── Turtle │ └── index.html ├── WebSocketHandler │ └── index.html ├── all.css └── index.html ├── make.sh ├── makeDocs.sh └── test.sh /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | /*.xcodeproj 5 | Package.resolved 6 | *~ 7 | \#*\# -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at support@tangogolfdigital.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /CONTRIBUTORS.md: -------------------------------------------------------------------------------- 1 | For the purpose of tracking copyright, this is the list of individuals and 2 | organizations who have contributed source code to IGIS. 3 | 4 | For employees of an organization/company where the copyright of work done 5 | by employees of that company is held by the company itself, only the company 6 | needs to be listed here. 7 | 8 | ## COPYRIGHT HOLDERS 9 | 10 | - Tango Golf Digital, LLC 11 | 12 | ### Contributors 13 | 14 | - David Ben-Yaakov 15 | 16 | NOTE: 17 | IGIS is based upon the work of David Ben-Yaakov on the grounds of Carnegie 18 | Mellon University and the University of Pittsburgh beginning in 1983. 19 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.0 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "Igis", 8 | products: [ 9 | // Products define the executables and libraries produced by a package, and make them visible to other packages. 10 | .library( 11 | name: "Igis", 12 | type: .dynamic, 13 | targets: ["Igis"]), 14 | ], 15 | dependencies: [ 16 | // Dependencies declare other packages that this package depends on. 17 | // .package(url: /* package url */, from: "1.0.0"), 18 | .package(url: "https://github.com/apple/swift-nio.git", from: "2.54.0") 19 | ], 20 | targets: [ 21 | // Targets are the basic building blocks of a package. A target can define a module or a test suite. 22 | // Targets can depend on other targets in this package, and on products in packages which this package depends on. 23 | .target( 24 | name: "Igis", 25 | dependencies: ["NIO", 26 | "NIOHTTP1", 27 | "NIOWebSocket"]), 28 | .testTarget( 29 | name: "IgisTests", 30 | dependencies: ["Igis"]), 31 | ] 32 | ) 33 | -------------------------------------------------------------------------------- /Sources/Igis/Alpha.swift: -------------------------------------------------------------------------------- 1 | /* 2 | IGIS - Remote graphics for Swift on Linux 3 | Copyright (C) 2018, 2019 CoderMerlin.com 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | 16 | import Foundation 17 | 18 | public final class Alpha : CanvasObject { 19 | public let alphaValue : Double 20 | 21 | public init(alphaValue:Double) { 22 | self.alphaValue = alphaValue 23 | } 24 | 25 | internal override func canvasCommand() -> String { 26 | let commands = "globalAlpha|\(alphaValue)" 27 | return commands 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/Igis/Audio.swift: -------------------------------------------------------------------------------- 1 | /* 2 | IGIS - Remote graphics for Swift on Linux 3 | Copyright (C) 2018,2019 CoderMerlin.com 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | 16 | import Foundation 17 | 18 | public class Audio : CanvasIdentifiedObject { 19 | public let sourceURL : URL 20 | public let shouldLoop : Bool 21 | 22 | public enum Mode { 23 | case play 24 | case pause 25 | } 26 | public var mode : Mode 27 | 28 | public init(sourceURL:URL, shouldLoop:Bool = false) { 29 | self.sourceURL = sourceURL 30 | self.shouldLoop = shouldLoop 31 | self.mode = .play 32 | } 33 | 34 | internal override func canvasCommand() -> String { 35 | if !isReady { 36 | print("WARNING: canvasCommand requested on audio not yet ready. ID: \(id.uuidString).") 37 | } 38 | var commands : String = "setAudioMode|\(id.uuidString)|" 39 | switch mode { 40 | case .play: 41 | commands += "play" 42 | case .pause: 43 | commands += "pause" 44 | } 45 | return commands 46 | } 47 | 48 | internal override func setupCommand() -> String { 49 | let commands = "createAudio|\(id.uuidString)|\(sourceURL.absoluteString)|\(shouldLoop)" 50 | return commands 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /Sources/Igis/CanvasIdentifiedObject.swift: -------------------------------------------------------------------------------- 1 | /* 2 | IGIS - Remote graphics for Swift on Linux 3 | Copyright (C) 2018 CoderMerlin.com 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | 16 | import Foundation 17 | 18 | public class CanvasIdentifiedObject : CanvasObject { 19 | 20 | internal let id = UUID() 21 | 22 | // Object state; proceeds from top to bottom 23 | internal enum State : Int { 24 | case pendingTransmission // Not yet transmitted 25 | case transmissionQueued // Transmission queued for client 26 | case processedByClient // Processed by client 27 | case resourceError // Resource is not available on client 28 | case ready // Ready for use on client 29 | } 30 | private var state : State = .pendingTransmission 31 | 32 | internal func setupCommand() -> String { 33 | fatalError("setupCommand() invoked on CanvasIdentifiedObject") 34 | } 35 | 36 | internal func setState(_ newState:State) { 37 | if newState.rawValue <= state.rawValue { 38 | print("ERROR: State of object with id \(id) is regressing from \(state) to \(newState).") 39 | } 40 | state = newState 41 | } 42 | 43 | public var isReady : Bool { 44 | return state == .ready 45 | } 46 | 47 | public var isResourceError : Bool { 48 | return state == .resourceError 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /Sources/Igis/CanvasObject.swift: -------------------------------------------------------------------------------- 1 | /* 2 | IGIS - Remote graphics for Swift on Linux 3 | Copyright (C) 2018 CoderMerlin.com 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | 16 | public class CanvasObject { 17 | internal func canvasCommand() -> String { 18 | fatalError("canvasCommand() invoked on CanvasObject") 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /Sources/Igis/ClipPath.swift: -------------------------------------------------------------------------------- 1 | /* 2 | IGIS - Remote graphics for Swift on Linux 3 | Copyright (C) 2018, 2019 CoderMerlin.com 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | 16 | import Foundation 17 | 18 | public class ClipPath : CanvasObject { 19 | 20 | public enum WindingRule { 21 | case nonZero 22 | case evenOdd 23 | } 24 | 25 | private let path : Path 26 | public let windingRule : WindingRule 27 | 28 | /// Creates a new `Clip` with an embedded path 29 | /// - Parameters: 30 | /// - path: A `Path` (which will be copied) and should be closed 31 | /// - windingRule: The `WindingRule` to be used for calculating the `Clip` 32 | public init(path:Path, windingRule:WindingRule = .nonZero) { 33 | self.path = Path(source:path) 34 | self.windingRule = windingRule 35 | } 36 | 37 | internal override func canvasCommand() -> String { 38 | var commands = path.pathCommands() 39 | commands += "||" 40 | 41 | commands += "clip|" 42 | switch windingRule { 43 | case .nonZero: 44 | commands += "nonzero" 45 | case .evenOdd: 46 | commands += "evenodd" 47 | } 48 | return commands 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Sources/Igis/ColorStop.swift: -------------------------------------------------------------------------------- 1 | public class ColorStop { 2 | let position : Double 3 | let color : Color 4 | 5 | public init(position:Double, color:Color) { 6 | self.position = position 7 | self.color = color 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Sources/Igis/Containment.swift: -------------------------------------------------------------------------------- 1 | /* 2 | IGIS - Remote graphics for Swift on Linux 3 | Copyright (C) 2018 CoderMerlin.com 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | 16 | 17 | // Provides a description of a rectangle relative to a target Point or Rect 18 | public enum Containment { 19 | // Special cases combining horizontal and vertical containment 20 | case containedFully // Included in set when both containedHorizontally AND containedVertically (Points,Rects) 21 | case overlapsFully // Included in set when both overlapsHorizontally AND overlapsVertically (Rects only) 22 | case beyondFully // Included in set when both beyondHorizontally AND beyondVertically (Points,Rects) 23 | case contact // Included in set when target is in contact with rectangle (Points, Rects) 24 | 25 | // Horizontal cases 26 | case beyondLeft // Indicates target's right side is beyond (to left of) object (Points,Rects) 27 | case overlapsLeft // Indicates target's left is beyond left but target's right is (Rects only) 28 | // within or beyond object (toward right) 29 | case beyondHorizontally // Included in set when either beyondLeft OR beyondRight (Points,Rects) 30 | case containedHorizontally // Target is contained within left and right of object (Points,Rects) 31 | case overlapsHorizontally // Included in set when both overlapsLeft AND overlapsRight (Rects only) 32 | case overlapsRight // Indicates target's right is beyond right but target's left is (Rects only) 33 | // within or beyond object (toward left) 34 | case beyondRight // Indicates target's left side is beyond (to right of) object (Points,Rects) 35 | 36 | // Vertical cases 37 | case beyondTop // Indicates target's bottom side is beyond (on top of) object (Points,Rects) 38 | case overlapsTop // Indicates target's top is beyond top but target's bottom is (Rects only) 39 | // within or beyond object (toward bottom) 40 | case beyondVertically // Included in set when either beyondTop OR beyondBottom (Points,Rects) 41 | case containedVertically // Target is contained within top and bottom of object (Points,Rects) 42 | case overlapsVertically // Included in set when both overlapsTop AND overlapsBottom (Points,Rects) 43 | case overlapsBottom // Indicates target's bottom is beyond bottom but target's top is (Rects only) 44 | // within or beyond object (toward top) 45 | case beyondBottom // Indicates target's top side is beyond (below) object (Points,Rects) 46 | } 47 | -------------------------------------------------------------------------------- /Sources/Igis/ContainmentSet.swift: -------------------------------------------------------------------------------- 1 | /* 2 | IGIS - Remote graphics for Swift on Linux 3 | Copyright (C) 2018 CoderMerlin.com 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | 16 | public typealias ContainmentSet = Set 17 | 18 | -------------------------------------------------------------------------------- /Sources/Igis/CursorStyle.swift: -------------------------------------------------------------------------------- 1 | /* 2 | IGIS - Remote graphics for Swift on Linux 3 | Copyright (C) 2018-2020 CoderMerlin.com 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | 16 | public class CursorStyle : CanvasObject { 17 | public enum Style : String { 18 | // Defaults 19 | case initial = "initial" 20 | case auto = "auto" 21 | case defaultCursor = "default" 22 | 23 | // None 24 | case none = "none" 25 | 26 | // Waiting 27 | case progress = "progress" 28 | case wait = "wait" 29 | 30 | // Pointer types 31 | case pointer = "pointer" 32 | case crosshair = "crosshair" 33 | case help = "help" 34 | case contextMenu = "context-menu" 35 | case alias = "alias" 36 | 37 | // Text and cells 38 | case text = "text" 39 | case textVertical = "vertical-text" 40 | case cell = "cell" 41 | 42 | // Movement and dragging 43 | case notAllowed = "not-allowed" 44 | case noDrop = "no-drop" 45 | 46 | case allScroll = "all-scroll" 47 | 48 | case move = "move" 49 | case copy = "copy" 50 | 51 | case resizeNorth = "n-resize" 52 | case resizeNorthEast = "ne-resize" 53 | case resizeEast = "e-resize" 54 | case resizeSouthEast = "se-resize" 55 | case resizeSouth = "s-resize" 56 | case resizeSouthWest = "sw-resize" 57 | case resizeWest = "w-resize" 58 | case resizeNorthWest = "nw-resize" 59 | 60 | case resizeRow = "row-resize" 61 | case resizeColumn = "col-resize" 62 | 63 | // Zooming 64 | case zoomIn = "zoom-in" 65 | case zoomOut = "zoom-out" 66 | } 67 | private let style : Style 68 | 69 | public init(style:Style) { 70 | self.style = style 71 | } 72 | 73 | internal override func canvasCommand() -> String { 74 | let commands = "cursorStyle|\(style.rawValue)" 75 | return commands 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Sources/Igis/DoublePoint.swift: -------------------------------------------------------------------------------- 1 | /* 2 | IGIS - Remote graphics for Swift on Linux 3 | Copyright (C) 2018-2020 CoderMerlin.com 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | 16 | import Foundation 17 | 18 | /// A `DoublePoint` represents a location in a two-dimensional plane. 19 | public struct DoublePoint : Equatable { 20 | /// The coordinate along the x-axis 21 | public var x : Double 22 | /// The coordinate along the y-axis 23 | public var y : Double 24 | 25 | /// The point (x:0.0, y:0.0) 26 | static public let zero = DoublePoint(x: 0.0, y: 0.0) 27 | 28 | /// Creates a new `DoublePoint` located at (x:0, y:0) 29 | public init() { 30 | self.x = 0.0 31 | self.y = 0.0 32 | } 33 | 34 | /// Creates a new `DoublePoint` from the specified coordinates 35 | /// - Parameters: 36 | /// - x: The x coordinate 37 | /// - y: The y coordinate 38 | public init(x:Double, y:Double) { 39 | self.x = x 40 | self.y = y 41 | } 42 | 43 | /// Creates a new `DoublePoint` from the specified coordinates 44 | /// - Parameters: 45 | /// - x: The x coordinate 46 | /// - y: The y coordinate 47 | public init(x:Int, y:Int) { 48 | self.x = Double(x) 49 | self.y = Double(y) 50 | } 51 | 52 | /// Creates a new `DoublePoint` from the specified `Point` 53 | /// - Parameters: 54 | /// - point: The source of the x, y coordinates 55 | public init(_ point:Point) { 56 | self.x = Double(point.x) 57 | self.y = Double(point.y) 58 | } 59 | 60 | /// Calculates the square of the distance between this point and another 61 | /// - Parameters: 62 | /// - target: The target point to which to calculate the distance 63 | /// - Returns: The square of the distance to a target point 64 | public func distanceSquared(target:DoublePoint) -> Double { 65 | let xDistance = target.x - x 66 | let xDistanceSquared = xDistance * xDistance 67 | 68 | let yDistance = target.y - y 69 | let yDistanceSquared = yDistance * yDistance 70 | 71 | return xDistanceSquared + yDistanceSquared 72 | } 73 | 74 | /// Calculates the distance between this point and another 75 | /// - Parameters: 76 | /// - target: The target point to which to calculate the distance 77 | /// - Returns: The distance to a target point 78 | public func distance(target:DoublePoint) -> Double { 79 | return sqrt(distanceSquared(target:target)) 80 | } 81 | 82 | /// Converts an array of `Point`s to an array of `DoublePoint`s 83 | static public func DoublePoints(_ points: [Point]) -> [DoublePoint] { 84 | return points.map {DoublePoint($0)} 85 | } 86 | 87 | /// Equivalence operator for two `DoublePoint`s 88 | static public func == (lhs:DoublePoint, rhs:DoublePoint) -> Bool { 89 | return lhs.x == rhs.x && lhs.y == rhs.y 90 | } 91 | 92 | /// Addition operator for two `DoublePoint`s 93 | static public func + (left: DoublePoint, right: DoublePoint) -> DoublePoint { 94 | return DoublePoint(x: left.x + right.x, y: left.y + right.y) 95 | } 96 | 97 | /// Compound addition operator for two `DoublePoint`s 98 | static public func += (left: inout DoublePoint, right: DoublePoint) { 99 | left = left + right 100 | } 101 | 102 | /// Negation operator for a `DoublePoint` 103 | static public prefix func - (doublePoint: DoublePoint) -> DoublePoint { 104 | return DoublePoint(x: -doublePoint.x, y: -doublePoint.y) 105 | } 106 | 107 | /// Subtraction operator for two `DoublePoint`s 108 | static public func - (left: DoublePoint, right: DoublePoint) -> DoublePoint { 109 | return left + -right 110 | } 111 | 112 | /// Compound subtration operator for two `DoublePoint`s 113 | static public func -= (left: inout DoublePoint, right: DoublePoint) { 114 | left = left - right 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /Sources/Igis/Ellipse.swift: -------------------------------------------------------------------------------- 1 | /* 2 | IGIS - Remote graphics for Swift on Linux 3 | Copyright (C) 2018 CoderMerlin.com 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | 16 | public class Ellipse : CanvasObject { 17 | public var center : Point 18 | public var radiusX : Int 19 | public var radiusY : Int 20 | public var rotation : Double // radians 21 | public var startAngle : Double 22 | public var endAngle : Double 23 | public var antiClockwise : Bool 24 | public var fillMode : FillMode 25 | 26 | public init(center:Point, radiusX:Int, radiusY:Int, rotation:Double=0.0, startAngle:Double=0.0, endAngle:Double=2.0*Double.pi, 27 | antiClockwise:Bool=false, fillMode:FillMode = .stroke) { 28 | self.center = center 29 | self.radiusX = radiusX 30 | self.radiusY = radiusY 31 | self.rotation = rotation 32 | self.startAngle = startAngle 33 | self.endAngle = endAngle 34 | self.antiClockwise = antiClockwise 35 | self.fillMode = fillMode 36 | } 37 | 38 | internal override func canvasCommand() -> String { 39 | var commands = String() 40 | commands += "beginPath||" 41 | commands += "ellipse|\(center.x)|\(center.y)|\(radiusX)|\(radiusY)|\(rotation)|\(startAngle)|\(endAngle)|\(antiClockwise)||" 42 | 43 | switch fillMode { 44 | case .stroke: 45 | commands += "stroke" 46 | case .fill, .clear: 47 | commands += "fill" 48 | case .fillAndStroke: 49 | commands += "fill||stroke" 50 | } 51 | 52 | return commands 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Sources/Igis/FillMode.swift: -------------------------------------------------------------------------------- 1 | /* 2 | IGIS - Remote graphics for Swift on Linux 3 | Copyright (C) 2018 CoderMerlin.com 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | 16 | public enum FillMode { 17 | case stroke 18 | case fill 19 | case fillAndStroke 20 | case clear 21 | } 22 | -------------------------------------------------------------------------------- /Sources/Igis/FillStyle.swift: -------------------------------------------------------------------------------- 1 | /* 2 | IGIS - Remote graphics for Swift on Linux 3 | Copyright (C) 2018 CoderMerlin.com 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | 16 | public class FillStyle : CanvasObject { 17 | private enum Mode { 18 | case solidColor(color:Color) 19 | case gradient(gradientValue:Gradient) 20 | case pattern(patternValue:Pattern) 21 | } 22 | private let mode : Mode 23 | 24 | public init(color:Color) { 25 | mode = .solidColor(color:color) 26 | } 27 | 28 | public init(gradient:Gradient) { 29 | mode = .gradient(gradientValue:gradient) 30 | } 31 | 32 | public init(pattern:Pattern) { 33 | mode = .pattern(patternValue:pattern) 34 | } 35 | 36 | internal override func canvasCommand() -> String { 37 | var commands = String() 38 | switch mode { 39 | case .solidColor(let color): 40 | commands += "fillStyleSolidColor|\(color.style)" 41 | case .gradient(let gradient): 42 | if !gradient.isReady { 43 | print("WARNING: canvasCommand requested on gradient not yet ready. ID: \(gradient.id.uuidString).") 44 | } 45 | commands += "fillStyleGradient|\(gradient.id.uuidString)" 46 | case .pattern(let pattern): 47 | if !pattern.isReady { 48 | print("WARNING: canvasCommand requested on pattern not yet read. ID: \(pattern.id.uuidString).") 49 | } 50 | commands += "fillStylePattern|\(pattern.id.uuidString)" 51 | } 52 | 53 | return commands 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Sources/Igis/Gradient.swift: -------------------------------------------------------------------------------- 1 | /* 2 | IGIS - Remote graphics for Swift on Linux 3 | Copyright (C) 2018 CoderMerlin.com 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | 16 | import Foundation 17 | 18 | 19 | /// A `Gradient` is used to create a `FillStyle` for filling various objects. 20 | /// 21 | /// `Gradient`s have two flavors: 22 | /// 1. Linear 23 | /// 2. Radial 24 | /// 25 | /// ### Usage: 26 | /// There are several steps required to use a gradient: 27 | /// 1. Create the Gradient object 28 | /// 2. Add two or more ColorStops 29 | /// 3. Setup the Gradient object 30 | /// 4. Use the Gradient to initialize a StrokeStyle or FillStyle 31 | /// 5. Because the Gradient is a CanvasIdentifiedObject, be sure it `isReady` 32 | /// prior to rendering 33 | /// 6. Render the associated FillStyle prior to the object(s) to be filled 34 | /// with the gradient 35 | /// 36 | /// ### Example: 37 | /// 38 | /// ~~~ 39 | /// var gradient : Gradient 40 | /// 41 | /// init() { 42 | /// gradient = Gradient(mode:.linear(start:Point(x:0, y:60), end:Point(x:320, y:60))) 43 | /// gradient.addColorStop(ColorStop(position:0.0, color:Color(.red))) 44 | /// gradient.addColorStop(ColorStop(position:0.25, color:Color(.yellow))) 45 | /// gradient.addColorStop(ColorStop(position:0.5, color:Color(.green))) 46 | /// gradient.addColorStop(ColorStop(position:0.5, color:Color(.green))) 47 | /// gradient.addColorStop(ColorStop(position:0.5, color:Color(.green))) 48 | /// } 49 | /// 50 | /// override func setup(canvas:Canvas) { 51 | /// canvas.setup(gradient) 52 | /// } 53 | /// 54 | /// override func render(canvas:Canvas) { 55 | /// if gradient.isReady { 56 | /// let fillStyle = FillStyle(gradient:gradient) 57 | /// canvas.render(fillStyle, rectangle) 58 | /// } 59 | /// } 60 | /// ~~~ 61 | 62 | public class Gradient : CanvasIdentifiedObject { 63 | 64 | /// The `Mode` is used to determine whether this is a `linear` or `radial` `Gradient`. 65 | /// 66 | /// NB: `Gradient` coordinates are global and are not relative to the rendered 67 | /// object's coordinates. 68 | public enum Mode { 69 | /// Creates a gradient along the line connecting the two given coordinates 70 | case linear(start:Point, end:Point) 71 | 72 | /// Creates a radial gradient using the size and coordnates of two circles 73 | case radial(center1:Point, radius1:Double, center2:Point, radius2:Double) 74 | } 75 | 76 | public let mode : Mode 77 | 78 | /// Maintains a list of colorStops for this Gradient. 79 | /// 80 | /// NB: This cannot be changed after setup() has been invoked. 81 | public private(set) var colorStops : [ColorStop] 82 | 83 | /// Creates a new `Gradient` 84 | /// - Parameters: 85 | /// - mode: Specifies the `Gradient` mode (linear or radial) 86 | public init(mode:Mode) { 87 | self.mode = mode 88 | self.colorStops = [ColorStop]() 89 | } 90 | 91 | /// Adds a `ColorStop` to the `Gradient`. 92 | /// - Parameters: 93 | /// - colorStop: The `ColorStop` to be added 94 | public func addColorStop(_ colorStop:ColorStop) { 95 | colorStops.append(colorStop) 96 | } 97 | 98 | internal override func canvasCommand() -> String { 99 | print("ERROR: canvasCommand requested on gradient which may not be directly rendered. ID: \(id.uuidString).") 100 | return "" 101 | } 102 | 103 | internal override func setupCommand() -> String { 104 | var commands = "" 105 | switch mode { 106 | case .linear(let start, let end): 107 | commands += "createLinearGradient|\(id.uuidString)|\(start.x)|\(start.y)|\(end.x)|\(end.y)|\(colorStops.count)|" 108 | case .radial(let center1, let radius1, let center2, let radius2): 109 | commands += "createRadialGradient|\(id.uuidString)|\(center1.x)|\(center1.y)|\(radius1)|\(center2.x)|\(center2.y)|\(radius2)|\(colorStops.count)|" 110 | } 111 | commands += colorStops.map {"\($0.position)|\($0.color.style)"}.joined(separator:"|") 112 | 113 | return commands 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /Sources/Igis/HTTPHandler.swift: -------------------------------------------------------------------------------- 1 | /* 2 | IGIS - Remote graphics for Swift on Linux 3 | Copyright (C) 2018 CoderMerlin.com 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | 16 | // Reference: https://github.com/apple/swift-nio/blob/master/Sources/NIOWebSocketServer/main.swift 17 | import Foundation 18 | import Dispatch 19 | import NIO 20 | import NIOHTTP1 21 | import NIOWebSocket 22 | 23 | final class HTTPHandler: ChannelInboundHandler, RemovableChannelHandler { 24 | typealias InboundIn = HTTPServerRequestPart 25 | typealias OutboundOut = HTTPServerResponsePart 26 | 27 | private var resourceDirectory:URL 28 | 29 | init(resourceDirectory:URL) { 30 | self.resourceDirectory = resourceDirectory 31 | } 32 | 33 | func channelRead(context: ChannelHandlerContext, data: NIOAny) { 34 | let requestPart = self.unwrapInboundIn(data) 35 | guard case .head(let head) = requestPart else { 36 | return 37 | } 38 | 39 | // GETs only. 40 | guard case .GET = head.method else { 41 | self.respondError(context: context, status:.methodNotAllowed) 42 | return 43 | } 44 | 45 | // The URI will (should) point to the desired resource, a file located in the "Resources" directory 46 | guard let url = URL(string:head.uri) else { 47 | print("WARNING: Specified url is not valid: \(head.uri)") 48 | self.respondError(context: context, status:.notFound) 49 | return 50 | } 51 | let fileURL = resourceDirectory.appendingPathComponent(url.path, isDirectory: false).standardizedFileURL 52 | let filePath = fileURL.path 53 | guard FileManager.default.fileExists(atPath:filePath) else { 54 | print("WARNING: Requested missing file at \(filePath)") 55 | self.respondError(context: context, status:.notFound) 56 | return 57 | } 58 | 59 | // Only three file types are currently supported 60 | let suffix = fileURL.pathExtension.lowercased() 61 | var mimeType : String 62 | switch suffix { 63 | case "html": 64 | mimeType = "text/html" 65 | case "css": 66 | mimeType = "text/css" 67 | case "js": 68 | mimeType = "text/javascript" 69 | default: 70 | print("WARNING: Unexpected file suffix in \(filePath)") 71 | self.respondError(context: context, status:.notImplemented) 72 | return 73 | } 74 | 75 | 76 | // Load the requested file 77 | var contents : String 78 | do { 79 | contents = try String(contentsOf:fileURL, encoding:.utf8) 80 | } catch (let error) { 81 | print("WARNING: Failed to load file \(filePath) because \(error)") 82 | self.respondError(context: context, status:.internalServerError) 83 | return 84 | } 85 | 86 | // Create the buffer for the response body 87 | var buffer = context.channel.allocator.buffer(capacity: contents.utf8.count) 88 | buffer.writeString(contents) 89 | 90 | var headers = HTTPHeaders() 91 | headers.add(name: "Content-Type", value: mimeType) 92 | headers.add(name: "Content-Length", value: String(buffer.readableBytes)) 93 | headers.add(name: "Connection", value: "close") 94 | let responseHead = HTTPResponseHead(version: .init(major: 1, minor: 1), status: .ok, headers: headers) 95 | context.write(self.wrapOutboundOut(.head(responseHead)), promise: nil) 96 | context.write(self.wrapOutboundOut(.body(.byteBuffer(buffer))), promise: nil) 97 | context.write(self.wrapOutboundOut(.end(nil))).whenComplete { (_: Result) in 98 | context.close(promise: nil) 99 | } 100 | context.flush() 101 | } 102 | 103 | private func respondError(context: ChannelHandlerContext, status:HTTPResponseStatus) { 104 | var headers = HTTPHeaders() 105 | headers.add(name: "Connection", value: "close") 106 | headers.add(name: "Content-Length", value: "0") 107 | let head = HTTPResponseHead(version: .init(major: 1, minor: 1), status: status, headers: headers) 108 | context.write(self.wrapOutboundOut(.head(head)), promise: nil) 109 | context.write(self.wrapOutboundOut(.end(nil))).whenComplete { (_: Result) in 110 | context.close(promise: nil) 111 | } 112 | context.flush() 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /Sources/Igis/Image.swift: -------------------------------------------------------------------------------- 1 | /* 2 | IGIS - Remote graphics for Swift on Linux 3 | Copyright (C) 2018 CoderMerlin.com 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | 16 | import Foundation 17 | 18 | public class Image : CanvasIdentifiedObject { 19 | public let sourceURL : URL 20 | 21 | public enum RenderMode { 22 | case destinationPoint(_ topLeft:Point) 23 | case destinationRect(_ rect:Rect) 24 | case sourceAndDestination(sourceRect:Rect, destinationRect:Rect) 25 | } 26 | public var renderMode : RenderMode 27 | 28 | public init(sourceURL:URL, topLeft:Point = Point(x:0, y:0)) { 29 | self.sourceURL = sourceURL 30 | self.renderMode = .destinationPoint(topLeft) 31 | } 32 | 33 | internal override func canvasCommand() -> String { 34 | if !isReady { 35 | print("WARNING: canvasCommand requested on image not yet ready. ID: \(id.uuidString).") 36 | } 37 | var commands : String = "drawImage|\(id.uuidString)|" 38 | switch renderMode { 39 | case .destinationPoint(let topLeft): 40 | commands += "\(topLeft.x)|\(topLeft.y)" 41 | case .destinationRect(let rect): 42 | commands += "\(rect.topLeft.x)|\(rect.topLeft.y)|\(rect.size.width)|\(rect.size.height)" 43 | case .sourceAndDestination(let sourceRect, let destinationRect): 44 | commands += "\(sourceRect.topLeft.x)|\(sourceRect.topLeft.y)|\(sourceRect.size.width)|\(sourceRect.size.height)|" + 45 | "\(destinationRect.topLeft.x)|\(destinationRect.topLeft.y)|\(destinationRect.size.width)|\(destinationRect.size.height)" 46 | } 47 | 48 | return commands 49 | } 50 | 51 | internal override func setupCommand() -> String { 52 | let commands = "createImage|\(id.uuidString)|\(sourceURL.absoluteString)" 53 | return commands 54 | } 55 | 56 | 57 | } 58 | -------------------------------------------------------------------------------- /Sources/Igis/LineWidth.swift: -------------------------------------------------------------------------------- 1 | /* 2 | IGIS - Remote graphics for Swift on Linux 3 | Copyright (C) 2018 CoderMerlin.com 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | 16 | public class LineWidth : CanvasObject { 17 | public let width : Int 18 | 19 | public init(width:Int) { 20 | self.width = width 21 | } 22 | 23 | internal override func canvasCommand() -> String { 24 | var commands = String() 25 | commands += "lineWidth|\(width)" 26 | return commands 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Sources/Igis/Lines.swift: -------------------------------------------------------------------------------- 1 | /* 2 | IGIS - Remote graphics for Swift on Linux 3 | Copyright (C) 2018 CoderMerlin.com 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | 16 | public class Lines : CanvasObject { 17 | 18 | private enum PointAction { 19 | case moveTo(point:Point) 20 | case lineTo(point:Point) 21 | } 22 | private var pointActions = [PointAction]() 23 | 24 | public init(from:Point, to:Point) { 25 | pointActions.append(.moveTo(point:from)) 26 | pointActions.append(.lineTo(point:to)) 27 | } 28 | 29 | public func moveTo(_ point:Point) { 30 | pointActions.append(.moveTo(point:point)) 31 | } 32 | 33 | public func lineTo(_ point:Point) { 34 | pointActions.append(.lineTo(point:point)) 35 | } 36 | 37 | internal override func canvasCommand() -> String { 38 | var pointActionStrings = [String]() 39 | 40 | for pointAction in pointActions { 41 | switch pointAction { 42 | case .moveTo(let point): 43 | pointActionStrings.append("moveTo|\(point.x)|\(point.y)") 44 | case .lineTo(let point): 45 | pointActionStrings.append("lineTo|\(point.x)|\(point.y)") 46 | } 47 | } 48 | 49 | var commands = String() 50 | commands += "beginPath||" 51 | commands += pointActionStrings.joined(separator:"||") 52 | commands += "||stroke" 53 | return commands 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /Sources/Igis/Matrix.swift: -------------------------------------------------------------------------------- 1 | /* 2 | IGIS - Remote graphics for Swift on Linux 3 | Copyright (C) 2018-2020 CoderMerlin.com 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | 16 | // This class represents a 3 x 3 matrix of Doubles and provides supporting 17 | // functionality to handle 2D transforms 18 | public class Matrix : CustomStringConvertible { 19 | private static let identityValues = [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]] 20 | 21 | public typealias Vector = [Double] // Must contain exactly 3 elements 22 | public let values : [[Double]] // Must be 3x3 matrix 23 | 24 | // Creates a matrix from a transform (used for the HTML Canvas) 25 | public init(transform:Transform) { 26 | let values = transform.values 27 | precondition(values.count == 6, "transform must have exactly six elements") 28 | let row1 = [values[0], values[1], 0.0] 29 | let row2 = [values[2], values[3], 0.0] 30 | let row3 = [values[4], values[5], 1.0] 31 | self.values = [row1, row2, row3] 32 | } 33 | 34 | // Creates a matrix from a 3x3 array 35 | public init(values:[[Double]]) { 36 | precondition(values.count == 3, "values must be a 3x3 array") 37 | for rowIndex in 0..<3 { 38 | precondition(values[rowIndex].count == 3, "values must be a 3x3 array") 39 | } 40 | self.values = values 41 | } 42 | 43 | // Returns the specified row 44 | public func row(_ rowIndex:Int) -> Vector { 45 | precondition((0..<3).contains(rowIndex), "Expected index in range 0..<3") 46 | 47 | var vector = Vector() 48 | for columnIndex in 0..<3 { 49 | vector.append(values[rowIndex][columnIndex]) 50 | } 51 | 52 | return vector 53 | } 54 | 55 | // Returns the specifed column 56 | public func column(_ columnIndex:Int) -> Vector { 57 | precondition((0..<3).contains(columnIndex), "Expected index in range 0..<3") 58 | 59 | var vector = Vector() 60 | for rowIndex in 0..<3 { 61 | vector.append(values[rowIndex][columnIndex]) 62 | } 63 | 64 | return vector 65 | } 66 | 67 | // Returns the dot product of two vectors 68 | public func dotProduct(left:Vector, right:Vector) -> Double { 69 | precondition(left.count == 3, "Expected left.count to be 3") 70 | precondition(right.count == 3, "Expected right.count to be 3") 71 | 72 | var sum = 0.0 73 | for index in 0..<3 { 74 | sum += left[index] * right[index] 75 | } 76 | return sum 77 | } 78 | 79 | public var description : String { 80 | // Convert to strings and pad all to uniform length 81 | let allValues : [Double] = Array(values.joined()) 82 | let allStrings = allValues.map {"\($0)"} 83 | let longestCount = allStrings.reduce(0) {(result:Int, s:String) in max(s.count, result)} 84 | let paddingCount = longestCount + 2 85 | let paddedStrings = allStrings.map {$0.padding(toLength:paddingCount, withPad:" ", startingAt:0)} 86 | 87 | // Form the string 88 | var s = "" 89 | for row in 0 ..< 3 { 90 | s += "[ " 91 | for column in 0 ..< 3 { 92 | s += paddedStrings[row * 3 + column] 93 | } 94 | s += "]\n" 95 | } 96 | 97 | return s 98 | } 99 | 100 | // Mutliplies this matrix by another and returns the resultant matrix 101 | public func multiply(byMatrix:Matrix) -> Matrix { 102 | var values = Array(repeating:Array(repeating:0.0, count:3), count:3) 103 | for rowIndex in 0..<3 { 104 | for columnIndex in 0..<3 { 105 | let rowVector = byMatrix.row(rowIndex) 106 | let columnVector = self.column(columnIndex) 107 | let result = dotProduct(left:rowVector, right:columnVector) 108 | values[rowIndex][columnIndex] = result 109 | } 110 | } 111 | 112 | return Matrix(values:values) 113 | } 114 | 115 | // Applies the matrix to the provided DoublePoint and returns the result 116 | public func apply(toDoublePoint:DoublePoint) -> DoublePoint { 117 | let source : Vector = [toDoublePoint.x, toDoublePoint.y, 1] 118 | var target : Vector = Array(repeating:0.0, count:3) 119 | for index in 0 ..< 3 { 120 | let columnVector = self.column(index) 121 | target[index] = dotProduct(left:source, right:columnVector) 122 | } 123 | return DoublePoint(x:target[0], y:target[1]) 124 | } 125 | 126 | // Applies the matrix to the provided Point and returns the result 127 | public func apply(toPoint:Point) -> Point { 128 | let applied = apply(toDoublePoint:DoublePoint(toPoint)) 129 | return Point(applied) 130 | } 131 | 132 | // Applies the matrix to the provided array of DoublePoint and returns the result 133 | public func apply(toDoublePoints:[DoublePoint]) -> [DoublePoint] { 134 | return toDoublePoints.map {apply(toDoublePoint:$0)} 135 | } 136 | 137 | // Applies the matrix to the provided array of Point and returns the result 138 | public func apply(toPoints:[Point]) -> [Point] { 139 | return toPoints.map {apply(toPoint:$0)} 140 | } 141 | 142 | // Mutliply a series of matrices and returns the resultant matrix 143 | // If no matrices are provided, the identity matrix will be returned 144 | public static func multiply(matrices:[Matrix]) -> Matrix { 145 | var result = Matrix(values:Self.identityValues) 146 | for matrix in matrices { 147 | result = result.multiply(byMatrix:matrix) 148 | } 149 | return result 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /Sources/Igis/PainterBase.swift: -------------------------------------------------------------------------------- 1 | /* 2 | IGIS - Remote graphics for Swift on Linux 3 | Copyright (C) 2018 CoderMerlin.com 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | 16 | /* 17 | This MAY be used as a base class that fulfills the PainterProtocol, 18 | essentially acting as a stub for which only selected functions may 19 | be overridden. 20 | */ 21 | 22 | open class PainterBase : PainterProtocol { 23 | public required init() { 24 | } 25 | 26 | open func framesPerSecond() -> Int { 27 | return 10 28 | } 29 | 30 | open func setup(canvas:Canvas) { 31 | } 32 | 33 | open func calculate(canvasId:Int, canvasSize:Size?) { 34 | } 35 | 36 | open func render(canvas:Canvas) { 37 | } 38 | 39 | open func onCanvasResize(size:Size) { 40 | } 41 | 42 | open func onWindowResize(size:Size) { 43 | } 44 | 45 | open func onClick(location:Point) { 46 | } 47 | 48 | open func onMouseDown(location:Point) { 49 | } 50 | 51 | open func onMouseUp(location:Point) { 52 | } 53 | 54 | open func onWindowMouseUp(location:Point) { 55 | } 56 | 57 | open func onMouseMove(location:Point) { 58 | } 59 | 60 | open func onKeyDown(key:String, code:String, ctrlKey:Bool, shiftKey:Bool, altKey:Bool, metaKey:Bool) { 61 | } 62 | 63 | open func onKeyUp(key:String, code:String, ctrlKey:Bool, shiftKey:Bool, altKey:Bool, metaKey:Bool) { 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /Sources/Igis/PainterProtocol.swift: -------------------------------------------------------------------------------- 1 | /* 2 | IGIS - Remote graphics for Swift on Linux 3 | Copyright (C) 2018 CoderMerlin.com 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | 16 | public protocol PainterProtocol { 17 | init() 18 | 19 | func framesPerSecond() -> Int 20 | 21 | func setup(canvas:Canvas) 22 | func calculate(canvasId:Int, canvasSize:Size?) 23 | func render(canvas:Canvas) 24 | 25 | func onCanvasResize(size:Size) 26 | func onWindowResize(size:Size) 27 | 28 | func onClick(location:Point) 29 | func onMouseDown(location:Point) 30 | func onMouseUp(location:Point) 31 | func onWindowMouseUp(location:Point) 32 | func onMouseMove(location:Point) 33 | 34 | func onKeyDown(key:String, code:String, ctrlKey:Bool, shiftKey:Bool, altKey:Bool, metaKey:Bool) 35 | func onKeyUp(key:String, code:String, ctrlKey:Bool, shiftKey:Bool, altKey:Bool, metaKey:Bool) 36 | 37 | } 38 | -------------------------------------------------------------------------------- /Sources/Igis/Pattern.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public class Pattern : CanvasIdentifiedObject { 4 | 5 | public enum Repetition { 6 | case repeated 7 | case repeatedX 8 | case repeatedY 9 | case notRepeated 10 | } 11 | 12 | public let image : Image 13 | public let repetition : Repetition 14 | 15 | public init(image:Image, repetition:Repetition = .repeated) { 16 | self.image = image 17 | self.repetition = repetition 18 | } 19 | 20 | internal override func canvasCommand() -> String { 21 | print("ERROR: canvasCommand requested on pattern which may not be directly rendered. ID: \(id.uuidString).") 22 | return "" 23 | } 24 | 25 | internal override func setupCommand() -> String { 26 | let repetitionString : String 27 | switch repetition { 28 | case .repeated: 29 | repetitionString = "repeated" 30 | case .repeatedX: 31 | repetitionString = "repeatedX" 32 | case .repeatedY: 33 | repetitionString = "repeatedY" 34 | case .notRepeated: 35 | repetitionString = "notRepeated" 36 | } 37 | let command = "createPattern|\(id.uuidString)|\(image.id.uuidString)|\(repetitionString)" 38 | return command 39 | } 40 | 41 | 42 | } 43 | -------------------------------------------------------------------------------- /Sources/Igis/Point.swift: -------------------------------------------------------------------------------- 1 | /* 2 | IGIS - Remote graphics for Swift on Linux 3 | Copyright (C) 2018-2020 CoderMerlin.com 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | 16 | import Foundation 17 | 18 | /// A `Point` represents a location in a two-dimensional plane. 19 | public struct Point : Equatable { 20 | /// The coordinate along the x-axis 21 | public var x : Int 22 | /// The coordinate along the y-axis 23 | public var y : Int 24 | 25 | /// The point (x:0, y:0) 26 | static public let zero = Point(x: 0, y: 0) 27 | 28 | /// Creates a new `Point` located at (x:0, y:0) 29 | public init() { 30 | self.x = 0 31 | self.y = 0 32 | } 33 | 34 | /// Creates a new `Point` from the specified coordinates 35 | /// - Parameters: 36 | /// - x: The x coordinate 37 | /// - y: The y coordinate 38 | public init(x:Int, y:Int) { 39 | self.x = x 40 | self.y = y 41 | } 42 | 43 | /// Creates a new `Point` from the specified `DoublePoint` 44 | /// - Parameters: 45 | /// - doublePoint: The source of the new coordinates 46 | public init(_ doublePoint:DoublePoint) { 47 | self.x = Int(doublePoint.x) 48 | self.y = Int(doublePoint.y) 49 | } 50 | 51 | /// Calculates the square of the distance between this point and another 52 | /// - Parameters: 53 | /// - target: The target point to which to calculate the distance 54 | /// - Returns: The square of the distance to a target point 55 | public func distanceSquared(to target:Point) -> Int { 56 | let xDistance = target.x - x 57 | let xDistanceSquared = xDistance * xDistance 58 | 59 | let yDistance = target.y - y 60 | let yDistanceSquared = yDistance * yDistance 61 | 62 | return xDistanceSquared + yDistanceSquared 63 | } 64 | 65 | /// Calculates the distance between this point and another 66 | /// - Parameters: 67 | /// - target: The target point to which to calculate the distance 68 | /// - Returns: The distance to a target point 69 | public func distance(to target: Point) -> Double { 70 | return sqrt(Double(distanceSquared(to:target))) 71 | } 72 | 73 | /// Converts an array of `DoublePoint`s to an array of `Point`s 74 | static public func Points(_ doublePoints: [DoublePoint]) -> [Point] { 75 | return doublePoints.map {Point($0)} 76 | } 77 | 78 | /// Equivalence operator for two `Point`s 79 | static public func == (left: Point, right: Point) -> Bool { 80 | return left.x == right.x && left.y == right.y 81 | } 82 | 83 | /// Addition operator for two `Point`s 84 | static public func + (left: Point, right: Point) -> Point { 85 | return Point(x: left.x + right.x, y: left.y + right.y) 86 | } 87 | 88 | /// Compound addition operator for two `Point`s 89 | static public func += (left: inout Point, right: Point) { 90 | left = left + right 91 | } 92 | 93 | /// Negation operator for a `Point` 94 | static public prefix func - (point:Point) -> Point { 95 | return Point(x: -point.x, y: -point.y) 96 | } 97 | 98 | /// Subtraction operator for two `Point`s 99 | static public func - (left: Point, right: Point) -> Point { 100 | return left + -right 101 | } 102 | 103 | /// Compound subtration operator for two `Point`s 104 | static public func -= (left: inout Point, right: Point) { 105 | left = left - right 106 | } 107 | } 108 | 109 | -------------------------------------------------------------------------------- /Sources/Igis/Rectangle.swift: -------------------------------------------------------------------------------- 1 | /* 2 | IGIS - Remote graphics for Swift on Linux 3 | Copyright (C) 2018 CoderMerlin.com 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | 16 | public class Rectangle : CanvasObject { 17 | public var rect : Rect 18 | public var fillMode : FillMode 19 | 20 | public init(rect:Rect, fillMode:FillMode = .fill) { 21 | self.rect = rect 22 | self.fillMode = fillMode 23 | } 24 | 25 | internal override func canvasCommand() -> String { 26 | var commands = String() 27 | switch fillMode { 28 | case .stroke: 29 | commands += "strokeRect|\(rect.topLeft.x)|\(rect.topLeft.y)|\(rect.size.width)|\(rect.size.height)" 30 | case .fill: 31 | commands += "fillRect|\(rect.topLeft.x)|\(rect.topLeft.y)|\(rect.size.width)|\(rect.size.height)" 32 | case .fillAndStroke: 33 | commands += "fillRect|\(rect.topLeft.x)|\(rect.topLeft.y)|\(rect.size.width)|\(rect.size.height)||" 34 | commands += "strokeRect|\(rect.topLeft.x)|\(rect.topLeft.y)|\(rect.size.width)|\(rect.size.height)" 35 | case .clear: 36 | commands += "clearRect|\(rect.topLeft.x)|\(rect.topLeft.y)|\(rect.size.width)|\(rect.size.height)" 37 | } 38 | return commands 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Sources/Igis/Resources/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Coder Merlin: IGIS 9 | 10 | 11 | 12 |
13 |

Igis is attempting to play audio on your device.

14 | 15 |
16 | 17 |
18 | 19 |
20 | 21 |
22 |
23 |
24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /Sources/Igis/Resources/style.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | height: 100%; 3 | padding: 0; 4 | margin: 0; 5 | font: 0.92rem Arial; 6 | line-height: 1.12rem; 7 | } 8 | 9 | .visible { 10 | visibility: visible !important; 11 | } 12 | 13 | #canvasContainer, #canvasMain { 14 | width: 100%; 15 | height: 100%; 16 | } 17 | 18 | #divStatistics { 19 | visibility: hidden; 20 | position: fixed; 21 | top: 6px; 22 | right: 6px; 23 | padding: 6px 12px; 24 | width: 188px; 25 | background-color: #2A2B2C90; 26 | color: white; 27 | } 28 | 29 | #divStatistics p { 30 | margin: 0; 31 | } 32 | 33 | #enablePlayButtonContainer { 34 | visibility: hidden; 35 | display: flex; 36 | justify-content: center; 37 | align-items: center; 38 | position: fixed; 39 | padding: 6px 0; 40 | width: 100%; 41 | background-color: #2A2B2C90; 42 | color: white; 43 | } 44 | 45 | #enablePlayButtonContainer * { 46 | margin: 0 6px; 47 | } 48 | 49 | #enablePlayButton { 50 | font-weight: 600; 51 | padding: 5px 0; 52 | width: 200px; 53 | border: none; 54 | outline: none; 55 | background-color: cyan; 56 | } 57 | 58 | #enablePlayButtonContainer.visible ~ #divStatistics { 59 | top: 44px; 60 | } 61 | -------------------------------------------------------------------------------- /Sources/Igis/Size.swift: -------------------------------------------------------------------------------- 1 | /* 2 | IGIS - Remote graphics for Swift on Linux 3 | Copyright (C) 2018 Tango Golf Digital, LLC 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | 16 | /// A `Size` represents dimensions in a two-dimensional plane. 17 | public struct Size : Equatable { 18 | /// The x-axis extent 19 | public var width : Int 20 | 21 | /// The y-axis extent 22 | public var height : Int 23 | 24 | /// The size (width:0, height:0) 25 | static public let zero = Size(width: 0, height: 0) 26 | 27 | /// The aspect ratio of this size (width / height). 28 | public var aspectRatio : Double { 29 | return Double(width) / Double(height) 30 | } 31 | 32 | /// Create a new `Size` of (width:0, height:0) 33 | public init() { 34 | self.width = 0 35 | self.height = 0 36 | } 37 | 38 | /// Creates a new `Size` from the specified parameters 39 | /// - Parameters: 40 | /// - width: The x-axis extent 41 | /// - height: The y-axis extent 42 | public init(width:Int, height:Int) { 43 | self.width = width 44 | self.height = height 45 | } 46 | 47 | /// Enlarges both dimenisions by the amount specified 48 | /// (negative numbers reduce the dimensions) 49 | /// - Parameters: 50 | /// - change: The amount by which to increase both dimensions 51 | public mutating func enlarge(by change:Int) { 52 | width += change 53 | height += change 54 | } 55 | 56 | /// The `Point` located at the center between the origin (x:0, y:0) 57 | /// and the point located at size 58 | public var center : Point { 59 | Point(x: width / 2, y: height / 2) 60 | } 61 | 62 | /// Equivalence operator for two `Size`s 63 | static public func == (lhs:Size, rhs:Size) -> Bool { 64 | return lhs.width == rhs.width && lhs.height == rhs.height 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Sources/Igis/State.swift: -------------------------------------------------------------------------------- 1 | /* 2 | IGIS - Remote graphics for Swift on Linux 3 | Copyright (C) 2018, 2019 Tango Golf Digital, LLC 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | 16 | import Foundation 17 | 18 | public class State : CanvasObject { 19 | 20 | public enum Mode { 21 | case save 22 | case restore 23 | } 24 | 25 | public let mode : Mode 26 | 27 | public init(mode:Mode) { 28 | self.mode = mode 29 | } 30 | 31 | internal override func canvasCommand() -> String { 32 | let commands : String 33 | switch mode { 34 | case .save: 35 | commands = "save" 36 | case .restore: 37 | commands = "restore" 38 | } 39 | return commands 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Sources/Igis/StrokeStyle.swift: -------------------------------------------------------------------------------- 1 | /* 2 | IGIS - Remote graphics for Swift on Linux 3 | Copyright (C) 2018 Tango Golf Digital, LLC 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | 16 | public class StrokeStyle : CanvasObject { 17 | private enum Mode { 18 | case solidColor(color:Color) 19 | case gradient(gradientValue:Gradient) 20 | } 21 | private let mode : Mode 22 | 23 | public init(color:Color) { 24 | mode = .solidColor(color:color) 25 | } 26 | 27 | public init(gradient:Gradient) { 28 | mode = .gradient(gradientValue:gradient) 29 | } 30 | 31 | internal override func canvasCommand() -> String { 32 | var commands = String() 33 | switch mode { 34 | case .solidColor(let color): 35 | commands += "strokeStyleSolidColor|\(color.style)" 36 | case .gradient(let gradient): 37 | if !gradient.isReady { 38 | print("WARNING: canvasCommand requested on gradient not yet ready. ID: \(gradient.id.uuidString).") 39 | } 40 | commands += "strokeStyleGradient|\(gradient.id.uuidString)" 41 | } 42 | 43 | return commands 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Sources/Igis/Text.swift: -------------------------------------------------------------------------------- 1 | /* 2 | IGIS - Remote graphics for Swift on Linux 3 | Copyright (C) 2018 Tango Golf Digital, LLC 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | 16 | public class Text : CanvasObject { 17 | public enum Alignment { 18 | case left 19 | case center 20 | case right 21 | 22 | case start 23 | case end 24 | } 25 | public enum Baseline { 26 | case top 27 | case hanging 28 | case middle 29 | case alphabetic 30 | case ideographic 31 | case bottom 32 | } 33 | public var location : Point 34 | public var text : String 35 | public var fillMode : FillMode 36 | 37 | public var font : String? 38 | public var alignment : Alignment? = nil 39 | public var baseline : Baseline? = nil 40 | 41 | public init(location:Point, text:String, fillMode:FillMode = .fill) { 42 | self.location = location 43 | self.text = text 44 | self.fillMode = fillMode 45 | } 46 | 47 | internal override func canvasCommand() -> String { 48 | var commands = String() 49 | 50 | if let font = font { 51 | commands += "font|\(font)||" 52 | } 53 | 54 | if let alignment = alignment { 55 | commands += "textAlign|" 56 | switch alignment { 57 | case .left: 58 | commands += "left" 59 | case .center: 60 | commands += "center" 61 | case .right: 62 | commands += "right" 63 | case .start: 64 | commands += "start" 65 | case .end: 66 | commands += "end" 67 | } 68 | commands += "||" 69 | } 70 | 71 | if let baseline = baseline { 72 | commands += "textBaseline|" 73 | switch baseline { 74 | case .top: 75 | commands += "top" 76 | case .hanging: 77 | commands += "hanging" 78 | case .middle: 79 | commands += "middle" 80 | case .alphabetic: 81 | commands += "alphabetic" 82 | case .ideographic: 83 | commands += "ideographic" 84 | case .bottom: 85 | commands += "bottom" 86 | } 87 | commands += "||" 88 | } 89 | 90 | 91 | if (text.count > 0) { 92 | switch fillMode { 93 | case .stroke: 94 | commands += "strokeText|\(text)|\(location.x)|\(location.y)" 95 | case .fill, .clear: 96 | commands += "fillText|\(text)|\(location.x)|\(location.y)" 97 | case .fillAndStroke: 98 | commands += "fillText|\(text)|\(location.x)|\(location.y)||" 99 | commands += "strokeText|\(text)|\(location.x)|\(location.y)" 100 | } 101 | } 102 | return commands 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /Sources/Igis/Transform.swift: -------------------------------------------------------------------------------- 1 | /* 2 | IGIS - Remote graphics for Swift on Linux 3 | Copyright (C) 2018-2020 Tango Golf Digital, LLC 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | 16 | import Foundation 17 | 18 | public class Transform : CanvasObject, CustomStringConvertible { 19 | 20 | private static let identityValues : Array = [1, 0, 0, 1, 0, 0] 21 | 22 | public enum Mode { 23 | case toIdentity // Transform TO the identity 24 | case fromIdentity // Apply a new transform, starting from the identity 25 | case fromCurrent // Apply a new transform, starting from the current transform 26 | } 27 | 28 | public let mode : Mode 29 | public let values : Array 30 | 31 | // Create an identity transform 32 | public init(mode:Mode = .toIdentity) { 33 | self.mode = mode 34 | values = Self.identityValues 35 | } 36 | 37 | // Creates a scaling transform 38 | public init(scale:DoublePoint, mode:Mode = .fromCurrent) { 39 | self.mode = mode 40 | values = [scale.x, 0, 0, scale.y, 0, 0] 41 | } 42 | 43 | // Creates a rotation transform 44 | public init(rotateRadians:Double, mode:Mode = .fromCurrent) { 45 | self.mode = mode 46 | let c = cos(rotateRadians) 47 | let s = sin(rotateRadians) 48 | values = [c, s, -s, c, 0, 0] 49 | } 50 | 51 | // Creates a translation transform 52 | public init(translate:DoublePoint, mode:Mode = .fromCurrent) { 53 | self.mode = mode 54 | values = [1, 0, 0, 1, translate.x, translate.y] 55 | } 56 | 57 | // Creates a shearing transform 58 | public init(shear:DoublePoint, mode:Mode = .fromCurrent) { 59 | self.mode = mode 60 | values = [1, shear.y, shear.x, 1, 0, 0] 61 | } 62 | 63 | // Creates a transform from a matrix 64 | public init(matrix:Matrix, mode:Mode = .fromCurrent) { 65 | self.mode = mode 66 | let values = matrix.values 67 | self.values = [values[0][0], values[0][1], values[1][0], values[1][1], values[2][0], values[2][1]] 68 | } 69 | 70 | internal override func canvasCommand() -> String { 71 | guard values.count == 6 else { 72 | fatalError("Transforms must contain exactly six elements") 73 | } 74 | 75 | var commands = (mode == .fromCurrent) ? "transform" : "setTransform" 76 | commands += "|" 77 | 78 | let transformAsString = values.map {"\($0)"}.joined(separator:"|") 79 | commands += transformAsString 80 | 81 | return commands 82 | } 83 | 84 | public var description : String { 85 | // Convert to strings and pad all to uniform length 86 | let strings = values.map {"\($0)"} 87 | let longestCount = strings.reduce(0) {(result:Int, s:String) in max(s.count, result)} 88 | let paddingCount = longestCount + 2 89 | let paddedStrings = strings.map {$0.padding(toLength:paddingCount, withPad:" ", startingAt:0)} 90 | 91 | // Form the string 92 | var s = "" 93 | for row in 0 ..< 3 { 94 | s += "[" 95 | for column in 0 ..< 2 { 96 | s += paddedStrings[row * 2 + column] 97 | } 98 | s += "]\n" 99 | } 100 | 101 | return s 102 | } 103 | 104 | // Multiplies a series of transforms and returns the resultant Matrix 105 | // If no transforms are provided, the identiy matrix will be returned 106 | public static func multiply(transforms:[Transform], mode:Mode = .fromCurrent) -> Matrix { 107 | let matrices = transforms.map {Matrix(transform:$0)} 108 | return Matrix.multiply(matrices:matrices) 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /Sources/Igis/WebSocketHandler.swift: -------------------------------------------------------------------------------- 1 | /* 2 | IGIS - Remote graphics for Swift on Linux 3 | Copyright (C) 2018 Tango Golf Digital, LLC 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | 16 | // Reference: https://github.com/apple/swift-nio/blob/master/Sources/NIOWebSocketServer/main.swift 17 | import Dispatch 18 | import NIO 19 | import NIOHTTP1 20 | import NIOWebSocket 21 | 22 | 23 | public final class WebSocketHandler: ChannelInboundHandler { 24 | public typealias InboundIn = WebSocketFrame 25 | public typealias OutboundOut = WebSocketFrame 26 | 27 | private var awaitingClose: Bool = false 28 | private let canvas : Canvas 29 | 30 | init(canvas:Canvas) { 31 | self.canvas = canvas 32 | } 33 | 34 | public func handlerAdded(context: ChannelHandlerContext) { 35 | let interval = canvas.nextRecurringInterval() 36 | context.eventLoop.scheduleTask(in: interval, {self.recurringCallback(context: context)}) 37 | canvas.ready(context:context, webSocketHandler:self) 38 | } 39 | 40 | public func channelRead(context: ChannelHandlerContext, data: NIOAny) { 41 | let frame = self.unwrapInboundIn(data) 42 | 43 | switch frame.opcode { 44 | case .connectionClose: 45 | self.receivedClose(context: context, frame: frame) 46 | case .ping: 47 | self.pong(context: context, frame: frame) 48 | case .text: 49 | var data = frame.unmaskedData 50 | let text = data.readString(length: data.readableBytes) ?? "" 51 | canvas.reception(context: context, webSocketHandler:self, text:text) 52 | default: 53 | // We ignore all other frames. 54 | break 55 | } 56 | } 57 | 58 | public func recurringCallback(context: ChannelHandlerContext) { 59 | let interval = canvas.nextRecurringInterval() 60 | context.eventLoop.scheduleTask(in: interval, {self.recurringCallback(context: context)}) 61 | canvas.recurring(context:context, webSocketHandler:self) 62 | } 63 | 64 | public func channelReadComplete(context: ChannelHandlerContext) { 65 | context.flush() 66 | } 67 | 68 | public func send(context: ChannelHandlerContext, text:String) { 69 | guard context.channel.isActive else { return } 70 | guard !self.awaitingClose else { return } 71 | 72 | var buffer = context.channel.allocator.buffer(capacity: text.utf8.count) 73 | buffer.writeString(text) 74 | 75 | let frame = WebSocketFrame(fin:true, opcode:.text, data:buffer) 76 | context.writeAndFlush(self.wrapOutboundOut(frame)).whenFailure { (_:Error) in 77 | context.close(promise:nil) 78 | } 79 | } 80 | 81 | private func receivedClose(context: ChannelHandlerContext, frame: WebSocketFrame) { 82 | // Handle a received close frame. In websockets, we're just going to send the close 83 | // frame and then close, unless we already sent our own close frame. 84 | if awaitingClose { 85 | // Cool, we started the close and were waiting for the user. We're done. 86 | context.close(promise: nil) 87 | } else { 88 | // This is an unsolicited close. We're going to send a response frame and 89 | // then, when we've sent it, close up shop. We should send back the close code the remote 90 | // peer sent us, unless they didn't send one at all. 91 | var data = frame.unmaskedData 92 | let closeDataCode = data.readSlice(length: 2) ?? context.channel.allocator.buffer(capacity: 0) 93 | let closeFrame = WebSocketFrame(fin: true, opcode: .connectionClose, data: closeDataCode) 94 | _ = context.write(self.wrapOutboundOut(closeFrame)).map { () in 95 | context.close(promise: nil) 96 | } 97 | } 98 | } 99 | 100 | private func pong(context: ChannelHandlerContext, frame: WebSocketFrame) { 101 | var frameData = frame.data 102 | let maskingKey = frame.maskKey 103 | 104 | if let maskingKey = maskingKey { 105 | frameData.webSocketUnmask(maskingKey) 106 | } 107 | 108 | let responseFrame = WebSocketFrame(fin: true, opcode: .pong, data: frameData) 109 | context.write(self.wrapOutboundOut(responseFrame), promise: nil) 110 | } 111 | 112 | private func closeOnError(context: ChannelHandlerContext) { 113 | // We have hit an error, we want to close. We do that by sending a close frame and then 114 | // shutting down the write side of the connection. 115 | var data = context.channel.allocator.buffer(capacity: 2) 116 | data.write(webSocketErrorCode: .protocolError) 117 | let frame = WebSocketFrame(fin: true, opcode: .connectionClose, data: data) 118 | context.write(self.wrapOutboundOut(frame)).whenComplete { (_: Result) in 119 | context.close(mode: .output, promise: nil) 120 | } 121 | awaitingClose = true 122 | } 123 | } 124 | 125 | -------------------------------------------------------------------------------- /Tests/IgisTests/ColorTests.swift: -------------------------------------------------------------------------------- 1 | /* 2 | IGIS - Remote graphics for Swift on Linux 3 | Copyright (C) 2022 Tango Golf Digital, LLC 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | 16 | import XCTest 17 | 18 | @testable import Igis 19 | 20 | final class ColorTests : XCTestCase { 21 | let refrenceInput1 = "#FFFFFF" 22 | let referenceR1: UInt8 = 0xFF 23 | let referenceG1: UInt8 = 0xFF 24 | let referenceB1: UInt8 = 0xFF 25 | 26 | let refrenceInput2 = "#FF00FF" 27 | let referenceR2: UInt8 = 0xFF 28 | let referenceG2: UInt8 = 0x00 29 | let referenceB2: UInt8 = 0xFF 30 | 31 | let refrenceInput3 = "#F0FF00" 32 | let referenceR3: UInt8 = 0xF0 33 | let referenceG3: UInt8 = 0xFF 34 | let referenceB3: UInt8 = 0x00 35 | 36 | func testColorInput1() { 37 | let data = Color(refrenceInput1) 38 | 39 | XCTAssertEqual(data.red, referenceR1) 40 | XCTAssertEqual(data.green, referenceG1) 41 | XCTAssertEqual(data.blue, referenceB1) 42 | } 43 | 44 | 45 | func testColorInput2() { 46 | let data = Color(refrenceInput2) 47 | 48 | XCTAssertEqual(data.red, referenceR2) 49 | XCTAssertEqual(data.green, referenceG2) 50 | XCTAssertEqual(data.blue, referenceB2) 51 | } 52 | 53 | 54 | func testColorInput3() { 55 | let data = Color(refrenceInput3) 56 | 57 | XCTAssertEqual(data.red, referenceR3) 58 | XCTAssertEqual(data.green, referenceG3) 59 | XCTAssertEqual(data.blue, referenceB3) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Tests/IgisTests/PointTests.swift: -------------------------------------------------------------------------------- 1 | /* 2 | IGIS - Remote graphics for Swift on Linux 3 | Copyright (C) 2020 Tango Golf Digital, LLC 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | 16 | import XCTest 17 | 18 | @testable import Igis 19 | 20 | final class PointTests : XCTestCase { 21 | 22 | let referenceX1 = -179843 23 | let referenceY1 = 274970 24 | 25 | let referenceX2 = 239574 26 | let referenceY2 = -893483 27 | 28 | 29 | func testZero() { 30 | let data = Point.zero 31 | let referenceX = 0 32 | let referenceY = 0 33 | XCTAssertEqual(data.x, referenceX) 34 | XCTAssertEqual(data.y, referenceY) 35 | } 36 | 37 | func testInitDefault() { 38 | let data = Point() 39 | let referenceX = 0 40 | let referenceY = 0 41 | XCTAssertEqual(data.x, referenceX) 42 | XCTAssertEqual(data.y, referenceY) 43 | } 44 | 45 | func testInitXY() { 46 | let data = Point(x: referenceX1, y: referenceY1) 47 | XCTAssertEqual(data.x, referenceX1) 48 | XCTAssertEqual(data.y, referenceY1) 49 | } 50 | 51 | func testInitDoublePoint() { 52 | let data = Point(DoublePoint(x:Double(referenceX1), y:Double(referenceY1))) 53 | XCTAssertEqual(data.x, referenceX1) 54 | XCTAssertEqual(data.y, referenceY1) 55 | } 56 | 57 | func testDistanceSquared() { 58 | let point1 = Point(x:referenceX1, y:referenceY1) 59 | let point2 = Point(x:referenceX2, y:referenceY2) 60 | let deltaX = referenceX2 - referenceX1 61 | let deltaY = referenceY2 - referenceY1 62 | let deltaXSquared = deltaX * deltaX 63 | let deltaYSquared = deltaY * deltaY 64 | let reference = deltaXSquared + deltaYSquared 65 | 66 | let data1 = point1.distanceSquared(to:point2) 67 | let data2 = point2.distanceSquared(to:point1) 68 | 69 | XCTAssertEqual(data1, reference) 70 | XCTAssertEqual(data2, reference) 71 | } 72 | 73 | func testDistance() { 74 | let point1 = Point(x:referenceX1, y:referenceY1) 75 | let point2 = Point(x:referenceX2, y:referenceY2) 76 | let deltaX = referenceX2 - referenceX1 77 | let deltaY = referenceY2 - referenceY1 78 | let deltaXSquared = Double(deltaX * deltaX) 79 | let deltaYSquared = Double(deltaY * deltaY) 80 | let reference = (deltaXSquared + deltaYSquared).squareRoot() 81 | 82 | let data1 = point1.distance(to:point2) 83 | let data2 = point2.distance(to:point1) 84 | 85 | XCTAssertEqual(data1, reference) 86 | XCTAssertEqual(data2, reference) 87 | } 88 | 89 | func testDoublePoints() { 90 | let point1 = Point(x:referenceX1, y:referenceY1) 91 | let point2 = Point(x:referenceX2, y:referenceY2) 92 | let reference = [point1, point2] 93 | let doublePoint1 = DoublePoint(x:referenceX1, y:referenceY1) 94 | let doublePoint2 = DoublePoint(x:referenceX2, y:referenceY2) 95 | let data = Point.Points([doublePoint1, doublePoint2]) 96 | 97 | XCTAssertEqual(data, reference) 98 | } 99 | 100 | func testEquivalenceOperator() { 101 | let reference = Point(x:referenceX1, y:referenceY1) 102 | let data1 = Point(x:referenceX1, y:referenceY1) 103 | let data2 = Point(x:referenceX2, y:referenceY2) 104 | 105 | XCTAssertTrue(data1 == reference) 106 | XCTAssertFalse(data2 == reference) 107 | } 108 | 109 | func testAdditionOperator() { 110 | let addend1 = Point(x:referenceX1, y:referenceY1) 111 | let addend2 = Point(x:referenceX2, y:referenceY2) 112 | let reference = Point(x:referenceX1 + referenceX2, y:referenceY1 + referenceY2) 113 | let data = addend1 + addend2 114 | 115 | XCTAssertEqual(data, reference) 116 | } 117 | 118 | func testCompoundAdditionOperator() { 119 | var data = Point(x:referenceX1, y:referenceY1) 120 | let addend = Point(x:referenceX2, y:referenceY2) 121 | data += addend 122 | let reference = Point(x: referenceX1 + referenceX2, y: referenceY1 + referenceY2) 123 | 124 | XCTAssertEqual(data, reference) 125 | } 126 | 127 | func testNegationOperator() { 128 | let data = -Point(x:referenceX1, y:referenceY1) 129 | let reference = Point(x: -referenceX1, y: -referenceY1) 130 | 131 | XCTAssertEqual(data, reference) 132 | } 133 | 134 | func testSubtractionOperator() { 135 | let minuend = Point(x: referenceX1, y: referenceY1) 136 | let subtrahend = Point(x: referenceX2, y: referenceY2) 137 | let data = minuend - subtrahend 138 | let reference = Point(x: referenceX1 - referenceX2, y: referenceY1 - referenceY2) 139 | 140 | XCTAssertEqual(data, reference) 141 | } 142 | 143 | func testCompoundSubtractionOperator() { 144 | var data = Point(x: referenceX1, y: referenceY1) 145 | let subtrahend = Point(x: referenceX2, y: referenceY2) 146 | data -= subtrahend 147 | let reference = Point(x: referenceX1 - referenceX2, y: referenceY1 - referenceY2) 148 | 149 | XCTAssertEqual(data, reference) 150 | } 151 | 152 | } 153 | -------------------------------------------------------------------------------- /Tests/IgisTests/RectTests.swift: -------------------------------------------------------------------------------- 1 | /* 2 | IGIS - Remote graphics for Swift on Linux 3 | Copyright (C) 2020 Tango Golf Digital, LLC 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | 16 | import XCTest 17 | 18 | @testable import Igis 19 | 20 | final class RectTests : XCTestCase { 21 | 22 | let referenceX1 = -174738 23 | let referenceY1 = 383841 24 | let referenceW1 = 31385 25 | let referenceH1 = 78445 26 | 27 | let referenceX2 = 386758 28 | let referenceY2 = -846864 29 | let referenceW2 = 74734 30 | let referenceH2 = 19437 31 | 32 | let deltaWidth = 7463 33 | let deltaHeight = 4752 34 | let delta = 352 35 | 36 | func testZero() { 37 | let data = Rect.zero 38 | let referenceX = 0 39 | let referenceY = 0 40 | let referenceW = 0 41 | let referenceH = 0 42 | XCTAssertEqual(data.topLeft.x, referenceX) 43 | XCTAssertEqual(data.topLeft.y, referenceY) 44 | XCTAssertEqual(data.size.width, referenceW) 45 | XCTAssertEqual(data.size.height, referenceH) 46 | } 47 | 48 | func testInitDefault() { 49 | let data = Rect() 50 | let referenceX = 0 51 | let referenceY = 0 52 | let referenceW = 0 53 | let referenceH = 0 54 | XCTAssertEqual(data.topLeft.x, referenceX) 55 | XCTAssertEqual(data.topLeft.y, referenceY) 56 | XCTAssertEqual(data.size.width, referenceW) 57 | XCTAssertEqual(data.size.height, referenceH) 58 | } 59 | 60 | func testInitSize() { 61 | let data = Rect(size:Size(width:referenceW1, height:referenceH1)) 62 | let referenceX = 0 63 | let referenceY = 0 64 | XCTAssertEqual(data.topLeft, Point(x:referenceX, y:referenceY)) 65 | XCTAssertEqual(data.size, Size(width:referenceW1, height:referenceH1)) 66 | } 67 | 68 | func testInitTopLeftSize() { 69 | let data = Rect(topLeft:Point(x:referenceX1, y:referenceY1), 70 | size:Size(width:referenceW1, height:referenceH1)) 71 | XCTAssertEqual(data.topLeft, Point(x:referenceX1, y:referenceY1)) 72 | XCTAssertEqual(data.size, Size(width:referenceW1, height:referenceH1)) 73 | } 74 | 75 | func testInitBottomLeftSize() { 76 | let data = Rect(bottomLeft:Point(x:referenceX1, y:referenceY1), 77 | size:Size(width:referenceW1, height:referenceH1)) 78 | XCTAssertEqual(data.bottomLeft, Point(x:referenceX1, y:referenceY1)) 79 | XCTAssertEqual(data.size, Size(width:referenceW1, height:referenceH1)) 80 | } 81 | 82 | func testInitTopRightSize() { 83 | let data = Rect(topRight:Point(x:referenceX1, y:referenceY1), 84 | size:Size(width:referenceW1, height:referenceH1)) 85 | XCTAssertEqual(data.topRight, Point(x:referenceX1, y:referenceY1)) 86 | XCTAssertEqual(data.size, Size(width:referenceW1, height:referenceH1)) 87 | } 88 | 89 | func testInitBottomRightSize() { 90 | let data = Rect(bottomRight:Point(x:referenceX1, y:referenceY1), 91 | size:Size(width:referenceW1, height:referenceH1)) 92 | XCTAssertEqual(data.bottomRight, Point(x:referenceX1, y:referenceY1)) 93 | XCTAssertEqual(data.size, Size(width:referenceW1, height:referenceH1)) 94 | } 95 | 96 | func testLocal() { 97 | let source = Rect(topLeft:Point(x:referenceX1, y:referenceY1), 98 | size:Size(width:referenceW1, height:referenceH1)) 99 | let origin = Rect(topLeft:Point(x:referenceX2, y:referenceY2), 100 | size:Size(width:referenceW2, height:referenceH2)) 101 | let data = source.local(to:origin) 102 | XCTAssertEqual(data.topLeft, Point(x:referenceX1-referenceX2, y:referenceY1-referenceY2)) 103 | XCTAssertEqual(data.size, Size(width:referenceW1, height:referenceH1)) 104 | } 105 | 106 | // TODO: Add tests for containment 107 | 108 | func testLeftRightTopBottom() { 109 | var data = Rect() 110 | data.left = referenceX1 111 | data.right = referenceX1 + referenceW1 112 | data.top = referenceY1 113 | data.bottom = referenceY1 + referenceH1 114 | XCTAssertEqual(data.left, referenceX1) 115 | XCTAssertEqual(data.right, referenceX1 + referenceW1) 116 | XCTAssertEqual(data.top, referenceY1) 117 | XCTAssertEqual(data.bottom, referenceY1 + referenceH1) 118 | XCTAssertEqual(data.topLeft, Point(x:referenceX1, y:referenceY1)) 119 | XCTAssertEqual(data.size, Size(width:referenceW1, height:referenceH1)) 120 | } 121 | 122 | func testInflateSize() { 123 | var data = Rect(topLeft:Point(x:referenceX1, y:referenceY1), 124 | size:Size(width:referenceW1, height:referenceH1)) 125 | data.inflate(by: Size(width:deltaWidth, height:deltaHeight)) 126 | XCTAssertEqual(data.left, referenceX1 - deltaWidth) 127 | XCTAssertEqual(data.right, referenceX1 + referenceW1 + deltaWidth) 128 | XCTAssertEqual(data.top, referenceY1 - deltaHeight) 129 | XCTAssertEqual(data.bottom, referenceY1 + referenceH1 + deltaHeight) 130 | } 131 | 132 | func testInflateInt() { 133 | var data = Rect(topLeft:Point(x:referenceX1, y:referenceY1), 134 | size:Size(width:referenceW1, height:referenceH1)) 135 | data.inflate(by: delta) 136 | XCTAssertEqual(data.left, referenceX1 - delta) 137 | XCTAssertEqual(data.right, referenceX1 + referenceW1 + delta) 138 | XCTAssertEqual(data.top, referenceY1 - delta) 139 | XCTAssertEqual(data.bottom, referenceY1 + referenceH1 + delta) 140 | } 141 | 142 | } 143 | -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | /* 2 | IGIS - Remote graphics for Swift on Linux 3 | Copyright (C) 2020 Tango Golf Digital, LLC 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | */ 15 | 16 | import XCTest 17 | 18 | @testable import IgisTests 19 | 20 | fatalError("Run the tests with `swift test --enable-test-discovery`.") 21 | -------------------------------------------------------------------------------- /docs/Alpha/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Igis - Alpha 7 | 8 | 9 | 10 |
11 | 12 | 13 | Igis 14 | 15 | Documentation 16 | 17 | Beta 18 |
19 | 20 | 25 | 26 | 32 | 33 |
34 |
35 |

36 | Class 37 | Alpha 38 |

39 | 40 |
41 |
public final class Alpha : CanvasObject 
42 |
43 |
44 | 45 |
46 | 47 | 49 | 51 | 52 | 54 | 55 | %11 56 | 57 | 58 | 59 | Alpha 60 | 61 | 62 | Alpha 63 | 64 | 65 | 66 | 67 | 68 | CanvasObject 69 | 70 | 71 | CanvasObject 72 | 73 | 74 | 75 | 76 | 77 | Alpha->CanvasObject 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 |
87 |

Superclass

88 |
89 |
CanvasObject
90 |
91 |
92 |
93 |
94 |

Initializers

95 | 96 |
97 |

98 | init(alpha​Value:​) 99 |

100 |
101 |
public init(alphaValue:Double) 
102 |
103 |
104 |
105 |
106 |

Properties

107 | 108 |
109 |

110 | alpha​Value 111 |

112 |
113 |
public let alphaValue : Double
114 |
115 |
116 |
117 | 118 | 119 | 120 |
121 |
122 | 123 |
124 |

125 | Generated on using swift-doc 1.0.0-beta.6. 126 |

127 |
128 | 129 | 130 | -------------------------------------------------------------------------------- /docs/Audio_Mode/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Igis - Audio.Mode 7 | 8 | 9 | 10 |
11 | 12 | 13 | Igis 14 | 15 | Documentation 16 | 17 | Beta 18 |
19 | 20 | 25 | 26 | 32 | 33 |
34 |
35 |

36 | Enumeration 37 | Audio.​Mode 38 |

39 | 40 |
41 |
public enum Mode 
42 |
43 |
44 | 45 | 46 |

Member Of

47 |
48 |
Audio
49 |
50 |
51 |
52 |
53 |

Enumeration Cases

54 | 55 |
56 |

57 | play 58 |

59 |
60 |
case play
61 |
62 |
63 |
64 |

65 | pause 66 |

67 |
68 |
case pause
69 |
70 |
71 |
72 | 73 | 74 | 75 |
76 |
77 | 78 |
79 |

80 | Generated on using swift-doc 1.0.0-beta.6. 81 |

82 |
83 | 84 | 85 | -------------------------------------------------------------------------------- /docs/Canvas/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Igis - Canvas 7 | 8 | 9 | 10 |
11 | 12 | 13 | Igis 14 | 15 | Documentation 16 | 17 | Beta 18 |
19 | 20 | 25 | 26 | 32 | 33 |
34 |
35 |

36 | Class 37 | Canvas 38 |

39 | 40 |
41 |
public class Canvas 
42 |
43 | 44 |
45 |

Properties

46 | 47 |
48 |

49 | canvas​Id 50 |

51 |
52 |
public let canvasId : Int
53 |
54 |
55 |
56 |

57 | canvas​Size 58 |

59 |
60 |
public private(set) var canvasSize : Size? = nil
61 |
62 |
63 |
64 |

65 | window​Size 66 |

67 |
68 |
public private(set) var windowSize : Size? = nil
69 |
70 |
71 |
72 |
73 |

Methods

74 | 75 |
76 |

77 | render(_:​) 78 |

79 |
80 |
public func render(_ canvasObjects:[CanvasObject]) 
81 |
82 |
83 |
84 |

85 | render(_:​) 86 |

87 |
88 |
public func render(_ canvasObjects:CanvasObject...) 
89 |
90 |
91 |
92 |

93 | setup(_:​) 94 |

95 |
96 |
public func setup(_ canvasIdentifiedObjects:[CanvasIdentifiedObject]) 
97 |
98 |
99 |
100 |

101 | setup(_:​) 102 |

103 |
104 |
public func setup(_ canvasIdentifiedObjects:CanvasIdentifiedObject...) 
105 |
106 |
107 |
108 |

109 | canvas​Set​Size(size:​) 110 |

111 |
112 |
public func canvasSetSize(size:Size) 
113 |
114 |
115 |
116 |

117 | display​Statistics(_:​) 118 |

119 |
120 |
public func displayStatistics(_ displayStatistics:Bool = true) 
121 |
122 |
123 |
124 | 125 | 126 | 127 |
128 |
129 | 130 |
131 |

132 | Generated on using swift-doc 1.0.0-beta.6. 133 |

134 |
135 | 136 | 137 | -------------------------------------------------------------------------------- /docs/ClipPath/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Igis - ClipPath 7 | 8 | 9 | 10 |
11 | 12 | 13 | Igis 14 | 15 | Documentation 16 | 17 | Beta 18 |
19 | 20 | 25 | 26 | 32 | 33 |
34 |
35 |

36 | Class 37 | Clip​Path 38 |

39 | 40 |
41 |
public class ClipPath : CanvasObject 
42 |
43 |
44 | 45 |
46 | 47 | 49 | 51 | 52 | 54 | 55 | %109 56 | 57 | 58 | 59 | ClipPath 60 | 61 | 62 | ClipPath 63 | 64 | 65 | 66 | 67 | 68 | CanvasObject 69 | 70 | 71 | CanvasObject 72 | 73 | 74 | 75 | 76 | 77 | ClipPath->CanvasObject 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 |
87 |

Nested Types

88 |
89 |
ClipPath.WindingRule
90 |
91 |
92 |

Superclass

93 |
94 |
CanvasObject
95 |
96 |
97 |
98 |
99 |

Initializers

100 | 101 |
102 |

103 | init(path:​winding​Rule:​) 104 |

105 |
106 |
public init(path:Path, windingRule:WindingRule = .nonZero) 
107 |
108 |
109 |

Creates a new Clip with an embedded path

110 | 111 |
112 |

Parameters

113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 128 | 129 | 130 | 131 | 132 | 134 | 135 | 136 |
pathPath

A Path (which will be copied) and should be closed

127 |
winding​RuleWinding​Rule

The WindingRule to be used for calculating the Clip

133 |
137 |
138 |
139 |
140 |

Properties

141 | 142 |
143 |

144 | winding​Rule 145 |

146 |
147 |
public let windingRule : WindingRule
148 |
149 |
150 |
151 | 152 | 153 | 154 |
155 |
156 | 157 |
158 |

159 | Generated on using swift-doc 1.0.0-beta.6. 160 |

161 |
162 | 163 | 164 | -------------------------------------------------------------------------------- /docs/ClipPath_WindingRule/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Igis - ClipPath.WindingRule 7 | 8 | 9 | 10 |
11 | 12 | 13 | Igis 14 | 15 | Documentation 16 | 17 | Beta 18 |
19 | 20 | 25 | 26 | 32 | 33 |
34 |
35 |

36 | Enumeration 37 | Clip​Path.​Winding​Rule 38 |

39 | 40 |
41 |
public enum WindingRule 
42 |
43 |
44 | 45 | 46 |

Member Of

47 |
48 |
ClipPath
49 |
50 |
51 |
52 |
53 |

Enumeration Cases

54 | 55 |
56 |

57 | non​Zero 58 |

59 |
60 |
case nonZero
61 |
62 |
63 |
64 |

65 | even​Odd 66 |

67 |
68 |
case evenOdd
69 |
70 |
71 |
72 | 73 | 74 | 75 |
76 |
77 | 78 |
79 |

80 | Generated on using swift-doc 1.0.0-beta.6. 81 |

82 |
83 | 84 | 85 | -------------------------------------------------------------------------------- /docs/Color/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Igis - Color 7 | 8 | 9 | 10 |
11 | 12 | 13 | Igis 14 | 15 | Documentation 16 | 17 | Beta 18 |
19 | 20 | 25 | 26 | 32 | 33 |
34 |
35 |

36 | Class 37 | Color 38 |

39 | 40 |
41 |
public final class Color 
42 |
43 |
44 | 45 | 46 |

Nested Types

47 |
48 |
Color.Name
49 |
50 |
51 |
52 |
53 |

Initializers

54 | 55 |
56 |

57 | init(red:​green:​blue:​) 58 |

59 |
60 |
public required init (red:UInt8, green:UInt8, blue:UInt8) 
61 |
62 |
63 |
64 |

65 | init(_:​) 66 |

67 |
68 |
public init(_ name:Name) 
69 |
70 |
71 |
72 |
73 |

Properties

74 | 75 |
76 |

77 | style 78 |

79 |
80 |
public let style : String
81 |
82 |
83 |
84 |

85 | red 86 |

87 |
88 |
public var red : UInt8 
89 |
90 |
91 |

The red RGB value of the color

92 | 93 |
94 |
95 |
96 |

97 | green 98 |

99 |
100 |
public var green : UInt8 
101 |
102 |
103 |

The green RGB value of the color

104 | 105 |
106 |
107 |
108 |

109 | blue 110 |

111 |
112 |
public var blue : UInt8 
113 |
114 |
115 |

The blue RGB value of the color

116 | 117 |
118 |
119 |
120 |
121 |

Methods

122 | 123 |
124 |

125 | lerp(to:​percent:​) 126 |

127 |
128 |
public func lerp(to target:Color, percent:Double) -> Self 
129 |
130 |
131 |
    132 |
  • Parameters: 133 |
      134 |
    • target: The target Color to which to calculate the new Color between
    • 135 |
    • percent: Value between 0 and 1 representing percentage
    • 136 |
    137 |
  • 138 |
  • Returns: A new Color of percent between this Color and a target Color
  • 139 |
140 | 141 |
142 |
143 |
144 | 145 | 146 | 147 |
148 |
149 | 150 |
151 |

152 | Generated on using swift-doc 1.0.0-beta.6. 153 |

154 |
155 | 156 | 157 | -------------------------------------------------------------------------------- /docs/ColorStop/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Igis - ColorStop 7 | 8 | 9 | 10 |
11 | 12 | 13 | Igis 14 | 15 | Documentation 16 | 17 | Beta 18 |
19 | 20 | 25 | 26 | 32 | 33 |
34 |
35 |

36 | Class 37 | Color​Stop 38 |

39 | 40 |
41 |
public class ColorStop 
42 |
43 | 44 |
45 |

Initializers

46 | 47 |
48 |

49 | init(position:​color:​) 50 |

51 |
52 |
public init(position:Double, color:Color) 
53 |
54 |
55 |
56 | 57 | 58 | 59 |
60 |
61 | 62 |
63 |

64 | Generated on using swift-doc 1.0.0-beta.6. 65 |

66 |
67 | 68 | 69 | -------------------------------------------------------------------------------- /docs/ContainmentSet/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Igis - ContainmentSet 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | Igis 15 | 16 | Documentation 17 | 18 | Beta 19 |
20 | 21 | 26 | 27 | 33 | 34 |
35 |
36 |

37 | Typealias 38 | Containment​Set 39 |

40 | 41 |
public typealias ContainmentSet = Set<Containment>
42 |
43 |
44 | 45 |
46 |

47 | Generated on using swift-doc 1.0.0-beta.2. 48 |

49 |
50 | 51 | 52 | -------------------------------------------------------------------------------- /docs/CursorStyle/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Igis - CursorStyle 7 | 8 | 9 | 10 |
11 | 12 | 13 | Igis 14 | 15 | Documentation 16 | 17 | Beta 18 |
19 | 20 | 25 | 26 | 32 | 33 |
34 |
35 |

36 | Class 37 | Cursor​Style 38 |

39 | 40 |
41 |
public class CursorStyle : CanvasObject 
42 |
43 |
44 | 45 |
46 | 47 | 49 | 51 | 52 | 54 | 55 | %37 56 | 57 | 58 | 59 | CursorStyle 60 | 61 | 62 | CursorStyle 63 | 64 | 65 | 66 | 67 | 68 | CanvasObject 69 | 70 | 71 | CanvasObject 72 | 73 | 74 | 75 | 76 | 77 | CursorStyle->CanvasObject 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 |
87 |

Nested Types

88 |
89 |
CursorStyle.Style
90 |
91 |
92 |

Superclass

93 |
94 |
CanvasObject
95 |
96 |
97 |
98 |
99 |

Initializers

100 | 101 |
102 |

103 | init(style:​) 104 |

105 |
106 |
public init(style:Style) 
107 |
108 |
109 |
110 | 111 | 112 | 113 |
114 |
115 | 116 |
117 |

118 | Generated on using swift-doc 1.0.0-beta.6. 119 |

120 |
121 | 122 | 123 | -------------------------------------------------------------------------------- /docs/FillMode/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Igis - FillMode 7 | 8 | 9 | 10 |
11 | 12 | 13 | Igis 14 | 15 | Documentation 16 | 17 | Beta 18 |
19 | 20 | 25 | 26 | 32 | 33 |
34 |
35 |

36 | Enumeration 37 | Fill​Mode 38 |

39 | 40 |
41 |
public enum FillMode 
42 |
43 | 44 |
45 |

Enumeration Cases

46 | 47 |
48 |

49 | stroke 50 |

51 |
52 |
case stroke
53 |
54 |
55 |
56 |

57 | fill 58 |

59 |
60 |
case fill
61 |
62 |
63 |
64 |

65 | fill​And​Stroke 66 |

67 |
68 |
case fillAndStroke
69 |
70 |
71 |
72 |

73 | clear 74 |

75 |
76 |
case clear
77 |
78 |
79 |
80 | 81 | 82 | 83 |
84 |
85 | 86 |
87 |

88 | Generated on using swift-doc 1.0.0-beta.6. 89 |

90 |
91 | 92 | 93 | -------------------------------------------------------------------------------- /docs/FillStyle/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Igis - FillStyle 7 | 8 | 9 | 10 |
11 | 12 | 13 | Igis 14 | 15 | Documentation 16 | 17 | Beta 18 |
19 | 20 | 25 | 26 | 32 | 33 |
34 |
35 |

36 | Class 37 | Fill​Style 38 |

39 | 40 |
41 |
public class FillStyle : CanvasObject 
42 |
43 |
44 | 45 |
46 | 47 | 49 | 51 | 52 | 54 | 55 | %125 56 | 57 | 58 | 59 | FillStyle 60 | 61 | 62 | FillStyle 63 | 64 | 65 | 66 | 67 | 68 | CanvasObject 69 | 70 | 71 | CanvasObject 72 | 73 | 74 | 75 | 76 | 77 | FillStyle->CanvasObject 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 |
87 |

Superclass

88 |
89 |
CanvasObject
90 |
91 |
92 |
93 |
94 |

Initializers

95 | 96 |
97 |

98 | init(color:​) 99 |

100 |
101 |
public init(color:Color) 
102 |
103 |
104 |
105 |

106 | init(gradient:​) 107 |

108 |
109 |
public init(gradient:Gradient) 
110 |
111 |
112 |
113 |

114 | init(pattern:​) 115 |

116 |
117 |
public init(pattern:Pattern) 
118 |
119 |
120 |
121 | 122 | 123 | 124 |
125 |
126 | 127 |
128 |

129 | Generated on using swift-doc 1.0.0-beta.6. 130 |

131 |
132 | 133 | 134 | -------------------------------------------------------------------------------- /docs/Gradient_Mode/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Igis - Gradient.Mode 7 | 8 | 9 | 10 |
11 | 12 | 13 | Igis 14 | 15 | Documentation 16 | 17 | Beta 18 |
19 | 20 | 25 | 26 | 32 | 33 |
34 |
35 |

36 | Enumeration 37 | Gradient.​Mode 38 |

39 | 40 |
41 |
public enum Mode 
42 |
43 |
44 |

The Mode is used to determine whether this is a linear or radial Gradient.

45 | 46 |
47 |
48 |

NB: Gradient coordinates are global and are not relative to the rendered 49 | object's coordinates.

50 | 51 |
52 |
53 | 54 | 55 |

Member Of

56 |
57 |
Gradient
58 |

A Gradient is used to create a FillStyle for filling various objects.

59 |
60 |
61 |
62 |
63 |

Enumeration Cases

64 | 65 |
66 |

67 | linear 68 |

69 |
70 |
case linear(start:Point, end:Point)
71 |
72 |
73 |

Creates a gradient along the line connecting the two given coordinates

74 | 75 |
76 |
77 |
78 |

79 | radial 80 |

81 |
82 |
case radial(center1:Point, radius1:Double, center2:Point, radius2:Double)
83 |
84 |
85 |

Creates a radial gradient using the size and coordnates of two circles

86 | 87 |
88 |
89 |
90 | 91 | 92 | 93 |
94 |
95 | 96 |
97 |

98 | Generated on using swift-doc 1.0.0-beta.6. 99 |

100 |
101 | 102 | 103 | -------------------------------------------------------------------------------- /docs/Igis/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Igis - Igis 7 | 8 | 9 | 10 |
11 | 12 | 13 | Igis 14 | 15 | Documentation 16 | 17 | Beta 18 |
19 | 20 | 25 | 26 | 32 | 33 |
34 |
35 |

36 | Class 37 | Igis 38 |

39 | 40 |
41 |
public class Igis 
42 |
43 | 44 |
45 |

Initializers

46 | 47 |
48 |

49 | init(resource​Path:​local​Host:​local​Port:​) 50 |

51 |
52 |
public init(resourcePath:String?=nil, localHost:String?=nil, localPort:Int?=nil) 
53 |
54 |
55 |
56 |
57 |

Methods

58 | 59 |
60 |

61 | run(painter​Type:​) 62 |

63 |
64 |
public func run(painterType:PainterProtocol.Type) throws 
65 |
66 |
67 |
68 | 69 | 70 | 71 |
72 |
73 | 74 |
75 |

76 | Generated on using swift-doc 1.0.0-beta.6. 77 |

78 |
79 | 80 | 81 | -------------------------------------------------------------------------------- /docs/Image/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Igis - Image 7 | 8 | 9 | 10 |
11 | 12 | 13 | Igis 14 | 15 | Documentation 16 | 17 | Beta 18 |
19 | 20 | 25 | 26 | 32 | 33 |
34 |
35 |

36 | Class 37 | Image 38 |

39 | 40 |
41 |
public class Image : CanvasIdentifiedObject 
42 |
43 |
44 | 45 |
46 | 47 | 49 | 51 | 52 | 54 | 55 | %105 56 | 57 | 58 | 59 | Image 60 | 61 | 62 | Image 63 | 64 | 65 | 66 | 67 | 68 | CanvasIdentifiedObject 69 | 70 | 71 | CanvasIdentifiedObject 72 | 73 | 74 | 75 | 76 | 77 | Image->CanvasIdentifiedObject 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 |
87 |

Nested Types

88 |
89 |
Image.RenderMode
90 |
91 |
92 |

Superclass

93 |
94 |
CanvasIdentifiedObject
95 |
96 |
97 |
98 |
99 |

Initializers

100 | 101 |
102 |

103 | init(source​URL:​top​Left:​) 104 |

105 |
106 |
public init(sourceURL:URL, topLeft:Point = Point(x:0, y:0)) 
107 |
108 |
109 |
110 |
111 |

Properties

112 | 113 |
114 |

115 | source​URL 116 |

117 |
118 |
public let sourceURL : URL
119 |
120 |
121 |
122 |

123 | render​Mode 124 |

125 |
126 |
public var renderMode : RenderMode
127 |
128 |
129 |
130 | 131 | 132 | 133 |
134 |
135 | 136 |
137 |

138 | Generated on using swift-doc 1.0.0-beta.6. 139 |

140 |
141 | 142 | 143 | -------------------------------------------------------------------------------- /docs/Image_RenderMode/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Igis - Image.RenderMode 7 | 8 | 9 | 10 |
11 | 12 | 13 | Igis 14 | 15 | Documentation 16 | 17 | Beta 18 |
19 | 20 | 25 | 26 | 32 | 33 |
34 |
35 |

36 | Enumeration 37 | Image.​Render​Mode 38 |

39 | 40 |
41 |
public enum RenderMode 
42 |
43 |
44 | 45 | 46 |

Member Of

47 |
48 |
Image
49 |
50 |
51 |
52 |
53 |

Enumeration Cases

54 | 55 |
56 |

57 | destination​Point 58 |

59 |
60 |
case destinationPoint(_ topLeft:Point)
61 |
62 |
63 |
64 |

65 | destination​Rect 66 |

67 |
68 |
case destinationRect(_ rect:Rect)
69 |
70 |
71 |
72 |

73 | source​And​Destination 74 |

75 |
76 |
case sourceAndDestination(sourceRect:Rect, destinationRect:Rect)
77 |
78 |
79 |
80 | 81 | 82 | 83 |
84 |
85 | 86 |
87 |

88 | Generated on using swift-doc 1.0.0-beta.6. 89 |

90 |
91 | 92 | 93 | -------------------------------------------------------------------------------- /docs/Layout/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Igis - Layout 7 | 8 | 9 | 10 |
11 | 12 | 13 | Igis 14 | 15 | Documentation 16 | 17 | Beta 18 |
19 | 20 | 25 | 26 | 32 | 33 |
34 |
35 |

36 | Class 37 | Layout 38 |

39 | 40 |
41 |
public class Layout  
42 |
43 |
44 |

Layout provides the ability to layout a series of Rects using 45 | specified rules. The order of each Rect is always preserved.

46 | 47 |
48 |
49 | 50 | 51 |

Nested Types

52 |
53 |
Layout.ChildAttribute
54 |
55 |
Layout.ChildRule
56 |
57 |
58 |
59 |
60 |

Methods

61 | 62 |
63 |

64 | property(attribute:​child​Rects:​) 65 |

66 |
67 |
public static func property(attribute:ChildAttribute, childRects:[Rect]) -> Int 
68 |
69 |
70 |

Analyzes the childRects and calculates the specified property of the collection

71 | 72 |
73 |
74 |
75 |

76 | apply(rule:​child​Rects:​) 77 |

78 |
79 |
public static func apply(rule:ChildRule, childRects:[Rect]) -> [Rect] 
80 |
81 |
82 |

Applies the specified rule to the collection of Rects and returns 83 | a new collection, maintaining the original order

84 | 85 |
86 |
87 |
88 | 89 | 90 | 91 |
92 |
93 | 94 |
95 |

96 | Generated on using swift-doc 1.0.0-beta.6. 97 |

98 |
99 | 100 | 101 | -------------------------------------------------------------------------------- /docs/LineWidth/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Igis - LineWidth 7 | 8 | 9 | 10 |
11 | 12 | 13 | Igis 14 | 15 | Documentation 16 | 17 | Beta 18 |
19 | 20 | 25 | 26 | 32 | 33 |
34 |
35 |

36 | Class 37 | Line​Width 38 |

39 | 40 |
41 |
public class LineWidth : CanvasObject 
42 |
43 |
44 | 45 |
46 | 47 | 49 | 51 | 52 | 54 | 55 | %85 56 | 57 | 58 | 59 | LineWidth 60 | 61 | 62 | LineWidth 63 | 64 | 65 | 66 | 67 | 68 | CanvasObject 69 | 70 | 71 | CanvasObject 72 | 73 | 74 | 75 | 76 | 77 | LineWidth->CanvasObject 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 |
87 |

Superclass

88 |
89 |
CanvasObject
90 |
91 |
92 |
93 |
94 |

Initializers

95 | 96 |
97 |

98 | init(width:​) 99 |

100 |
101 |
public init(width:Int) 
102 |
103 |
104 |
105 |
106 |

Properties

107 | 108 |
109 |

110 | width 111 |

112 |
113 |
public let width : Int
114 |
115 |
116 |
117 | 118 | 119 | 120 |
121 |
122 | 123 |
124 |

125 | Generated on using swift-doc 1.0.0-beta.6. 126 |

127 |
128 | 129 | 130 | -------------------------------------------------------------------------------- /docs/Lines/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Igis - Lines 7 | 8 | 9 | 10 |
11 | 12 | 13 | Igis 14 | 15 | Documentation 16 | 17 | Beta 18 |
19 | 20 | 25 | 26 | 32 | 33 |
34 |
35 |

36 | Class 37 | Lines 38 |

39 | 40 |
41 |
public class Lines : CanvasObject 
42 |
43 |
44 | 45 |
46 | 47 | 49 | 51 | 52 | 54 | 55 | %149 56 | 57 | 58 | 59 | Lines 60 | 61 | 62 | Lines 63 | 64 | 65 | 66 | 67 | 68 | CanvasObject 69 | 70 | 71 | CanvasObject 72 | 73 | 74 | 75 | 76 | 77 | Lines->CanvasObject 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 |
87 |

Superclass

88 |
89 |
CanvasObject
90 |
91 |
92 |
93 |
94 |

Initializers

95 | 96 |
97 |

98 | init(from:​to:​) 99 |

100 |
101 |
public init(from:Point, to:Point) 
102 |
103 |
104 |
105 |
106 |

Methods

107 | 108 |
109 |

110 | move​To(_:​) 111 |

112 |
113 |
public func moveTo(_ point:Point) 
114 |
115 |
116 |
117 |

118 | line​To(_:​) 119 |

120 |
121 |
public func lineTo(_ point:Point) 
122 |
123 |
124 |
125 | 126 | 127 | 128 |
129 |
130 | 131 |
132 |

133 | Generated on using swift-doc 1.0.0-beta.6. 134 |

135 |
136 | 137 | 138 | -------------------------------------------------------------------------------- /docs/Pattern/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Igis - Pattern 7 | 8 | 9 | 10 |
11 | 12 | 13 | Igis 14 | 15 | Documentation 16 | 17 | Beta 18 |
19 | 20 | 25 | 26 | 32 | 33 |
34 |
35 |

36 | Class 37 | Pattern 38 |

39 | 40 |
41 |
public class Pattern : CanvasIdentifiedObject 
42 |
43 |
44 | 45 |
46 | 47 | 49 | 51 | 52 | 54 | 55 | %133 56 | 57 | 58 | 59 | Pattern 60 | 61 | 62 | Pattern 63 | 64 | 65 | 66 | 67 | 68 | CanvasIdentifiedObject 69 | 70 | 71 | CanvasIdentifiedObject 72 | 73 | 74 | 75 | 76 | 77 | Pattern->CanvasIdentifiedObject 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 |
87 |

Nested Types

88 |
89 |
Pattern.Repetition
90 |
91 |
92 |

Superclass

93 |
94 |
CanvasIdentifiedObject
95 |
96 |
97 |
98 |
99 |

Initializers

100 | 101 |
102 |

103 | init(image:​repetition:​) 104 |

105 |
106 |
public init(image:Image, repetition:Repetition = .repeated) 
107 |
108 |
109 |
110 |
111 |

Properties

112 | 113 |
114 |

115 | image 116 |

117 |
118 |
public let image : Image
119 |
120 |
121 |
122 |

123 | repetition 124 |

125 |
126 |
public let repetition : Repetition
127 |
128 |
129 |
130 | 131 | 132 | 133 |
134 |
135 | 136 |
137 |

138 | Generated on using swift-doc 1.0.0-beta.6. 139 |

140 |
141 | 142 | 143 | -------------------------------------------------------------------------------- /docs/Pattern_Repetition/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Igis - Pattern.Repetition 7 | 8 | 9 | 10 |
11 | 12 | 13 | Igis 14 | 15 | Documentation 16 | 17 | Beta 18 |
19 | 20 | 25 | 26 | 32 | 33 |
34 |
35 |

36 | Enumeration 37 | Pattern.​Repetition 38 |

39 | 40 |
41 |
public enum Repetition 
42 |
43 |
44 | 45 | 46 |

Member Of

47 |
48 |
Pattern
49 |
50 |
51 |
52 |
53 |

Enumeration Cases

54 | 55 |
56 |

57 | repeated 58 |

59 |
60 |
case repeated
61 |
62 |
63 |
64 |

65 | repeated​X 66 |

67 |
68 |
case repeatedX
69 |
70 |
71 |
72 |

73 | repeated​Y 74 |

75 |
76 |
case repeatedY
77 |
78 |
79 |
80 |

81 | not​Repeated 82 |

83 |
84 |
case notRepeated
85 |
86 |
87 |
88 | 89 | 90 | 91 |
92 |
93 | 94 |
95 |

96 | Generated on using swift-doc 1.0.0-beta.6. 97 |

98 |
99 | 100 | 101 | -------------------------------------------------------------------------------- /docs/Rectangle/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Igis - Rectangle 7 | 8 | 9 | 10 |
11 | 12 | 13 | Igis 14 | 15 | Documentation 16 | 17 | Beta 18 |
19 | 20 | 25 | 26 | 32 | 33 |
34 |
35 |

36 | Class 37 | Rectangle 38 |

39 | 40 |
41 |
public class Rectangle : CanvasObject 
42 |
43 |
44 | 45 |
46 | 47 | 49 | 51 | 52 | 54 | 55 | %7 56 | 57 | 58 | 59 | Rectangle 60 | 61 | 62 | Rectangle 63 | 64 | 65 | 66 | 67 | 68 | CanvasObject 69 | 70 | 71 | CanvasObject 72 | 73 | 74 | 75 | 76 | 77 | Rectangle->CanvasObject 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 |
87 |

Superclass

88 |
89 |
CanvasObject
90 |
91 |
92 |
93 |
94 |

Initializers

95 | 96 |
97 |

98 | init(rect:​fill​Mode:​) 99 |

100 |
101 |
public init(rect:Rect, fillMode:FillMode = .fill) 
102 |
103 |
104 |
105 |
106 |

Properties

107 | 108 |
109 |

110 | rect 111 |

112 |
113 |
public var rect : Rect
114 |
115 |
116 |
117 |

118 | fill​Mode 119 |

120 |
121 |
public var fillMode : FillMode
122 |
123 |
124 |
125 | 126 | 127 | 128 |
129 |
130 | 131 |
132 |

133 | Generated on using swift-doc 1.0.0-beta.6. 134 |

135 |
136 | 137 | 138 | -------------------------------------------------------------------------------- /docs/State/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Igis - State 7 | 8 | 9 | 10 |
11 | 12 | 13 | Igis 14 | 15 | Documentation 16 | 17 | Beta 18 |
19 | 20 | 25 | 26 | 32 | 33 |
34 |
35 |

36 | Class 37 | State 38 |

39 | 40 |
41 |
public class State : CanvasObject 
42 |
43 |
44 | 45 |
46 | 47 | 49 | 51 | 52 | 54 | 55 | %15 56 | 57 | 58 | 59 | State 60 | 61 | 62 | State 63 | 64 | 65 | 66 | 67 | 68 | CanvasObject 69 | 70 | 71 | CanvasObject 72 | 73 | 74 | 75 | 76 | 77 | State->CanvasObject 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 |
87 |

Nested Types

88 |
89 |
State.Mode
90 |
91 |
92 |

Superclass

93 |
94 |
CanvasObject
95 |
96 |
97 |
98 |
99 |

Initializers

100 | 101 |
102 |

103 | init(mode:​) 104 |

105 |
106 |
public init(mode:Mode) 
107 |
108 |
109 |
110 |
111 |

Properties

112 | 113 |
114 |

115 | mode 116 |

117 |
118 |
public let mode : Mode
119 |
120 |
121 |
122 | 123 | 124 | 125 |
126 |
127 | 128 |
129 |

130 | Generated on using swift-doc 1.0.0-beta.6. 131 |

132 |
133 | 134 | 135 | -------------------------------------------------------------------------------- /docs/State_Mode/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Igis - State.Mode 7 | 8 | 9 | 10 |
11 | 12 | 13 | Igis 14 | 15 | Documentation 16 | 17 | Beta 18 |
19 | 20 | 25 | 26 | 32 | 33 |
34 |
35 |

36 | Enumeration 37 | State.​Mode 38 |

39 | 40 |
41 |
public enum Mode 
42 |
43 |
44 | 45 | 46 |

Member Of

47 |
48 |
State
49 |
50 |
51 |
52 |
53 |

Enumeration Cases

54 | 55 |
56 |

57 | save 58 |

59 |
60 |
case save
61 |
62 |
63 |
64 |

65 | restore 66 |

67 |
68 |
case restore
69 |
70 |
71 |
72 | 73 | 74 | 75 |
76 |
77 | 78 |
79 |

80 | Generated on using swift-doc 1.0.0-beta.6. 81 |

82 |
83 | 84 | 85 | -------------------------------------------------------------------------------- /docs/StrokeStyle/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Igis - StrokeStyle 7 | 8 | 9 | 10 |
11 | 12 | 13 | Igis 14 | 15 | Documentation 16 | 17 | Beta 18 |
19 | 20 | 25 | 26 | 32 | 33 |
34 |
35 |

36 | Class 37 | Stroke​Style 38 |

39 | 40 |
41 |
public class StrokeStyle : CanvasObject 
42 |
43 |
44 | 45 |
46 | 47 | 49 | 51 | 52 | 54 | 55 | %89 56 | 57 | 58 | 59 | StrokeStyle 60 | 61 | 62 | StrokeStyle 63 | 64 | 65 | 66 | 67 | 68 | CanvasObject 69 | 70 | 71 | CanvasObject 72 | 73 | 74 | 75 | 76 | 77 | StrokeStyle->CanvasObject 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 |
87 |

Superclass

88 |
89 |
CanvasObject
90 |
91 |
92 |
93 |
94 |

Initializers

95 | 96 |
97 |

98 | init(color:​) 99 |

100 |
101 |
public init(color:Color) 
102 |
103 |
104 |
105 |

106 | init(gradient:​) 107 |

108 |
109 |
public init(gradient:Gradient) 
110 |
111 |
112 |
113 | 114 | 115 | 116 |
117 |
118 | 119 |
120 |

121 | Generated on using swift-doc 1.0.0-beta.6. 122 |

123 |
124 | 125 | 126 | -------------------------------------------------------------------------------- /docs/Text_Alignment/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Igis - Text.Alignment 7 | 8 | 9 | 10 |
11 | 12 | 13 | Igis 14 | 15 | Documentation 16 | 17 | Beta 18 |
19 | 20 | 25 | 26 | 32 | 33 |
34 |
35 |

36 | Enumeration 37 | Text.​Alignment 38 |

39 | 40 |
41 |
public enum Alignment 
42 |
43 |
44 | 45 | 46 |

Member Of

47 |
48 |
Text
49 |
50 |
51 |
52 |
53 |

Enumeration Cases

54 | 55 |
56 |

57 | left 58 |

59 |
60 |
case left
61 |
62 |
63 |
64 |

65 | center 66 |

67 |
68 |
case center
69 |
70 |
71 |
72 |

73 | right 74 |

75 |
76 |
case right
77 |
78 |
79 |
80 |

81 | start 82 |

83 |
84 |
case start
85 |
86 |
87 |
88 |

89 | end 90 |

91 |
92 |
case end
93 |
94 |
95 |
96 | 97 | 98 | 99 |
100 |
101 | 102 |
103 |

104 | Generated on using swift-doc 1.0.0-beta.6. 105 |

106 |
107 | 108 | 109 | -------------------------------------------------------------------------------- /docs/Text_Baseline/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Igis - Text.Baseline 7 | 8 | 9 | 10 |
11 | 12 | 13 | Igis 14 | 15 | Documentation 16 | 17 | Beta 18 |
19 | 20 | 25 | 26 | 32 | 33 |
34 |
35 |

36 | Enumeration 37 | Text.​Baseline 38 |

39 | 40 |
41 |
public enum Baseline 
42 |
43 |
44 | 45 | 46 |

Member Of

47 |
48 |
Text
49 |
50 |
51 |
52 |
53 |

Enumeration Cases

54 | 55 |
56 |

57 | top 58 |

59 |
60 |
case top
61 |
62 |
63 |
64 |

65 | hanging 66 |

67 |
68 |
case hanging
69 |
70 |
71 |
72 |

73 | middle 74 |

75 |
76 |
case middle
77 |
78 |
79 |
80 |

81 | alphabetic 82 |

83 |
84 |
case alphabetic
85 |
86 |
87 |
88 |

89 | ideographic 90 |

91 |
92 |
case ideographic
93 |
94 |
95 |
96 |

97 | bottom 98 |

99 |
100 |
case bottom
101 |
102 |
103 |
104 | 105 | 106 | 107 |
108 |
109 | 110 |
111 |

112 | Generated on using swift-doc 1.0.0-beta.6. 113 |

114 |
115 | 116 | 117 | -------------------------------------------------------------------------------- /docs/Transform_Mode/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Igis - Transform.Mode 7 | 8 | 9 | 10 |
11 | 12 | 13 | Igis 14 | 15 | Documentation 16 | 17 | Beta 18 |
19 | 20 | 25 | 26 | 32 | 33 |
34 |
35 |

36 | Enumeration 37 | Transform.​Mode 38 |

39 | 40 |
41 |
public enum Mode 
42 |
43 |
44 | 45 | 46 |

Member Of

47 |
48 |
Transform
49 |
50 |
51 |
52 |
53 |

Enumeration Cases

54 | 55 |
56 |

57 | to​Identity 58 |

59 |
60 |
case toIdentity
61 |
62 |
63 |
64 |

65 | from​Identity 66 |

67 |
68 |
case fromIdentity
69 |
70 |
71 |
72 |

73 | from​Current 74 |

75 |
76 |
case fromCurrent
77 |
78 |
79 |
80 | 81 | 82 | 83 |
84 |
85 | 86 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /make.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | makeSwift "$@" 3 | -------------------------------------------------------------------------------- /makeDocs.sh: -------------------------------------------------------------------------------- 1 | swift-doc generate . --module-name Igis --format html --output docs --base-url /Igis/ 2 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | swift test --enable-test-discovery | tee >(grep --color=always error) 3 | --------------------------------------------------------------------------------