├── .github ├── ISSUE_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── ci.yml ├── .gitignore ├── .travis.yml ├── COPYING ├── First Presentation.spice ├── Licenses.txt ├── README.md ├── Screenshot.png ├── Screenshot1.png ├── Screenshot2.png ├── Screenshot3.png ├── Spice-up Concept.png ├── com.github.philip_scott.spice-up.yml ├── data ├── SaveFooter-min.html ├── SaveFormat.html ├── SaveHeader-min.html ├── assets.gresource.xml ├── assets │ ├── patterns │ │ ├── 3px-tile.png │ │ ├── 45-degree-fabric-dark.png │ │ ├── 45-degree-fabric-light.png │ │ ├── LISENCE.txt │ │ ├── batthern.png │ │ ├── beige-paper.png │ │ ├── black-linen.png │ │ ├── bright-squares.png │ │ ├── dark-geometric.png │ │ ├── diamond-upholstery.png │ │ ├── flowers.png │ │ ├── gplay.png │ │ ├── hexellence.png │ │ ├── inspiration-geometry.png │ │ ├── light-wool.png │ │ ├── ps-neutral.png │ │ ├── shattered.png │ │ ├── silver-scales.png │ │ ├── subtle-freckles.png │ │ ├── subtle-grey.png │ │ └── xv.png │ └── templates │ │ ├── Black.spice │ │ ├── Colorful.spice │ │ ├── Green.spice │ │ ├── Landscape.spice │ │ ├── Paper.spice │ │ ├── Spice-Up.spice │ │ └── White.spice ├── com.github.philip_scott.spice-up.appdata.xml ├── com.github.philip_scott.spice-up.desktop ├── com.github.philip_scott.spice-up.mime.xml ├── icons │ ├── 16 │ │ └── com.github.philip_scott.spice-up.svg │ ├── 24 │ │ └── com.github.philip_scott.spice-up.svg │ ├── 32 │ │ └── com.github.philip_scott.spice-up.svg │ ├── 48 │ │ └── com.github.philip_scott.spice-up.svg │ ├── 64 │ │ └── com.github.philip_scott.spice-up.svg │ ├── 128 │ │ └── com.github.philip_scott.spice-up.svg │ ├── align-bottom-symbolic.svg │ ├── align-middle-symbolic.svg │ ├── align-top-symbolic.svg │ ├── color-palette-symbolic.svg │ ├── custom-color-symbolic.svg │ ├── drag.svg │ ├── gradient-palette-symbolic.svg │ └── gradient-symbolic.svg ├── meson.build └── stylesheet.css ├── debian ├── changelog ├── compat ├── control ├── copyright ├── rules └── source │ └── format ├── meson.build ├── meson └── post_install.py ├── po ├── LINGUAS ├── POTFILES ├── ca.po ├── com.github.philip-scott.spice-up.pot ├── de.po ├── es.po ├── fr.po ├── ja.po ├── meson.build ├── nl_NL.po ├── pt_BR.po ├── pt_PT.po ├── sr.po └── sr@latin.po ├── pull_request_template.md ├── schemas ├── CMakeLists.txt ├── com.github.philip_scott.spice-up.gschema.xml └── meson.build ├── src ├── Application.vala ├── Services │ ├── Clipboard.vala │ ├── FileManager.vala │ ├── GamepadSlideController.vala │ ├── HistoryManager.vala │ ├── ImageHandler.vala │ ├── Settings.vala │ ├── Slide.vala │ ├── SlideManager.vala │ ├── Utils.vala │ └── libgamepad │ │ ├── drivers │ │ └── linux │ │ │ ├── guid-helpers.vala │ │ │ ├── raw-gamepad-monitor.vala │ │ │ └── raw-gamepad.vala │ │ ├── gamepad-monitor.vala │ │ ├── gamepad.vala │ │ ├── helpers.vala │ │ ├── input-type.vala │ │ ├── libgamepad.vala │ │ ├── raw-gamepad-interface.vala │ │ ├── raw-gamepad-monitor-interface.vala │ │ ├── standard-gamepad-axis.vala │ │ └── standard-gamepad-button.vala ├── Tests │ ├── Canvas │ │ ├── CanvasTest.vala │ │ ├── MockedCanvasItem.vala │ │ ├── TestCommon.vala │ │ └── meson.build │ ├── ColorButton │ │ ├── ColorButtonTest.vala │ │ ├── TestCommon.vala │ │ └── meson.build │ ├── ColorItem │ │ ├── ColorItemTest.vala │ │ ├── MockedCanvasItem.vala │ │ ├── TestCommon.vala │ │ └── meson.build │ ├── ImageItem │ │ ├── ImageItemTest.vala │ │ ├── MockedCanvasItem.vala │ │ ├── TestCommon.vala │ │ └── meson.build │ ├── TextItem │ │ ├── MockedCanvasItem.vala │ │ ├── TestCommon.vala │ │ ├── TextItemTest.vala │ │ └── meson.build │ └── meson.build ├── Widgets │ ├── Canvas.vala │ ├── CanvasItems │ │ ├── CanvasItem.vala │ │ ├── ColorItem.vala │ │ ├── Grabber.vala │ │ ├── ImageItem.vala │ │ └── TextItem.vala │ ├── ColorPicker │ │ ├── ColorButton.vala │ │ ├── ColorChooser.vala │ │ ├── Gradient.vala │ │ ├── GradientEditor.vala │ │ └── PickerWindow.vala │ ├── DynamicToolbar.vala │ ├── EntryCombo.vala │ ├── Headerbar.vala │ ├── Library │ │ ├── Library.vala │ │ └── LibraryItem.vala │ ├── PresenterNotes.vala │ ├── PresenterView.vala │ ├── SlideList.vala │ ├── SlideWidget.vala │ ├── Toolbars │ │ ├── CanvasBar.vala │ │ ├── CommonBar.vala │ │ ├── ImageBar.vala │ │ ├── ShapeBar.vala │ │ ├── TextBar.vala │ │ └── Toolbar.vala │ └── Welcome.vala ├── Window.vala ├── config.vala.in └── meson.build └── vapi └── libevdev.vapi /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ## Expected Behavior 5 | 6 | 7 | 8 | ## Current Behavior 9 | 10 | 11 | 12 | ## Possible Solution 13 | 14 | 15 | 16 | ## Steps to Reproduce (for bugs) 17 | 18 | 1. 19 | 2. 20 | 3. 21 | 4. 22 | 23 | ## Context 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | ## Screenshots of the Problem 33 | 34 | 35 | 36 | ## Your Environment (for bugs) 37 | 38 | 39 | 40 | 41 | 42 | ``` 43 | 46 | - OS Info: 47 | 48 | ``` 49 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | ## Summary / How this PR fixes the problem? 9 | 10 | 11 | ## Steps to Test 12 | 13 | 14 | ## Screenshots 15 | 16 | 17 | 18 | ## Known Issues / Things To Do 19 | 20 | 21 | 22 | 23 | ## This PR fixes/implements the following **bugs/features**: 24 | 25 | 26 | - Fixes # 27 | - Fixes # 28 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | pull_request: 5 | types: 6 | - opened 7 | - reopened 8 | - synchronize 9 | 10 | jobs: 11 | flatpak: 12 | name: Flatpak 13 | runs-on: ubuntu-latest 14 | 15 | strategy: 16 | matrix: 17 | arch: [x86_64, aarch64] 18 | # Don't fail the whole workflow if one architecture fails 19 | fail-fast: false 20 | 21 | container: 22 | image: ghcr.io/elementary/flatpak-platform/runtime:6.1-${{ matrix.arch }} 23 | options: --privileged 24 | 25 | steps: 26 | - name: Checkout 27 | uses: actions/checkout@v2 28 | 29 | - name: Set up QEMU for aarch64 emulation 30 | if: ${{ matrix.arch != 'x86_64' }} 31 | uses: docker/setup-qemu-action@v1 32 | with: 33 | platforms: arm64 34 | 35 | - name: Build 36 | uses: bilelmoussaoui/flatpak-github-actions/flatpak-builder@v4 37 | with: 38 | bundle: spice-up.flatpak 39 | manifest-path: com.github.philip_scott.spice-up.yml 40 | run-tests: false 41 | repository-name: appcenter 42 | repository-url: https://flatpak.elementary.io/repo.flatpakrepo 43 | cache-key: "flatpak-builder-${{ github.sha }}" 44 | arch: ${{ matrix.arch }} 45 | 46 | lint: 47 | name: Lint 48 | runs-on: ubuntu-latest 49 | 50 | container: 51 | image: valalang/lint 52 | 53 | steps: 54 | - name: Checkout 55 | uses: actions/checkout@v2 56 | 57 | - name: Lint 58 | run: io.elementary.vala-lint -d . 59 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | src/config.vala 2 | build/ 3 | *~ 4 | 5 | .flatpak-builder -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | language: node_js 4 | 5 | node_js: 6 | - 10/* 7 | 8 | sudo: required 9 | 10 | services: 11 | - docker 12 | 13 | addons: 14 | apt: 15 | sources: 16 | - ubuntu-toolchain-r-test 17 | packages: 18 | - libstdc++-5-dev 19 | 20 | install: 21 | - npm i -g @elementaryos/houston 22 | 23 | script: 24 | - houston ci 25 | --name-domain com.github.philip-scott.spice-up 26 | -------------------------------------------------------------------------------- /Licenses.txt: -------------------------------------------------------------------------------- 1 | Photos on templates by: 2 | 3 | Nourdine Diouane on Unsplash 4 | Jeremy Gallman on Unsplash 5 | Photo by Khara Woods on Unsplash 6 | 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |

Spice-up

3 |

Create Simple and Beautiful presentations

4 |
5 | 6 |
7 | 8 |

9 | 10 | Get it on AppCenter 11 | 12 |

13 | 14 | 15 |
16 | 17 |

18 | Screenshot 19 |

20 | 21 |

22 | 23 |

24 | 25 | bountysource 26 | 27 | build status 28 |

29 | 30 | Create presentations that stand out! Spice-Up has everything you need to create simple and beautiful presentations. Get your ideas across with beautiful designed templates, or start from scratch with a blank canvas. Either way, you will add some spice to your presentations with a wide variety of background patterns and a beautiful color palette. 31 | 32 | ### Spice Presentations Look Amazing! 33 | Images, Shapes, Text, as well as beautiful background patterns and easy to make custom gradients! 34 | 35 |

36 | Screenshot 37 |

38 | 39 | Easy-to-design slides and powerful features: 40 | 41 | 42 | - **Exporting to PDF:** Share your presentation with anyone, no matter the platform they're at. 43 | - **Presentation Browser:** Scroll though the presentations you have made and jump right into them with one click!. 44 | - **Controller Support:** If you have a USB or Bluetooth controller, plug it in and control your slides! 45 | - **Web Viewer:** Presentations can now be viewed from a web browser if Spice-Up is not installed, even if you're not using Linux. No extra software needed! 46 | - **Edit images** in your favorite editor, and it will automatically update when saved 47 | - **Templates:** a touch of creativity is all you need to make presentations in a blink of an eye. 48 | - **Presenter Notes:** Present like a pro with slide-by-slide notes only viewable by you! 49 | - And much more! 50 | 51 |

52 | Screenshot 53 |

54 | 55 | ## Installation 56 | 57 | [![Get it on AppCenter](https://appcenter.elementary.io/badge.svg)](https://appcenter.elementary.io/com.github.philip-scott.spice-up) 58 | 59 | On elementary OS? Hit the button to get Spice-Up! 60 | 61 | #### Not on elementary? 62 | You can install Spice-Up from a PPA. But be aware that your results may vary 63 | 64 | sudo add-apt-repository ppa:philip.scott/spice-up-daily 65 | sudo apt-get update 66 | sudo apt-get install com.github.philip-scott.spice-up 67 | 68 | ## Dependencies 69 | These dependencies must be present before building 70 | - `gtk+-3.0>=3.9.10` 71 | - `granite>=0.4.1` 72 | - `json-glib-1.0` 73 | - `gee-0.8` 74 | - `gudev-1.0` 75 | - `libevdev` 76 | - `libsoup-2.4` 77 | 78 | ## Building 79 | ``` 80 | mkdir build/ && cd build 81 | cmake .. 82 | make && sudo make all test install 83 | ``` 84 | 85 | 86 |

87 | Spice-Up's Icon 88 |

89 | -------------------------------------------------------------------------------- /Screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Philip-Scott/Spice-up/56647140c7725d0ec6c450eda1756eeea6fc766b/Screenshot.png -------------------------------------------------------------------------------- /Screenshot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Philip-Scott/Spice-up/56647140c7725d0ec6c450eda1756eeea6fc766b/Screenshot1.png -------------------------------------------------------------------------------- /Screenshot2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Philip-Scott/Spice-up/56647140c7725d0ec6c450eda1756eeea6fc766b/Screenshot2.png -------------------------------------------------------------------------------- /Screenshot3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Philip-Scott/Spice-up/56647140c7725d0ec6c450eda1756eeea6fc766b/Screenshot3.png -------------------------------------------------------------------------------- /Spice-up Concept.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Philip-Scott/Spice-up/56647140c7725d0ec6c450eda1756eeea6fc766b/Spice-up Concept.png -------------------------------------------------------------------------------- /com.github.philip_scott.spice-up.yml: -------------------------------------------------------------------------------- 1 | app-id: com.github.philip_scott.spice-up 2 | 3 | runtime: io.elementary.Platform 4 | runtime-version: '6.1' 5 | sdk: io.elementary.Sdk 6 | 7 | command: com.github.philip_scott.spice-up 8 | 9 | finish-args: 10 | - '--share=ipc' 11 | - '--socket=fallback-x11' 12 | - '--socket=wayland' 13 | 14 | - '--device=all' # Required for Controllers 15 | - '--filesystem=xdg-documents' # Required for library 16 | - '--filesystem=/tmp' # Required to share images for editing with external apps 17 | 18 | modules: 19 | - name: gudev 20 | config-opts: 21 | - '--disable-umockdev' 22 | - '--disable-gtk-doc' 23 | sources: 24 | - type: git 25 | url: https://gitlab.gnome.org/GNOME/libgudev.git 26 | tag: '234' 27 | 28 | - name: libevdev 29 | buildsystem: meson 30 | config-opts: 31 | - -Dtests=disabled 32 | - -Ddocumentation=disabled 33 | cleanup: 34 | - /bin 35 | - /include 36 | - /lib/pkgconfig 37 | - /share 38 | sources: 39 | - type: archive 40 | url: https://www.freedesktop.org/software/libevdev/libevdev-1.12.0.tar.xz 41 | sha256: 2f729e3480695791f9482e8388bd723402b89f0eaf118057bbdea3cecee9b237 42 | x-checker-data: 43 | type: anitya 44 | project-id: 20540 45 | stable-only: true 46 | url-template: https://www.freedesktop.org/software/libevdev/libevdev-$version.tar.xz 47 | 48 | - name: libsoup 49 | builddir: true 50 | buildsystem: meson 51 | config-opts: 52 | - "-Dtests=false" 53 | - "-Dvapi=disabled" 54 | - "-Dintrospection=disabled" 55 | sources: 56 | - type: archive 57 | url: https://gitlab.gnome.org/GNOME/libsoup/-/archive/2.68.2/libsoup-2.68.2.tar.gz 58 | sha256: a2a44f8b8eb5e145c5dff473f6d8c5b8f1addcf4e6f12223b4705c7fcc6c29b6 59 | 60 | - name: spice-up 61 | buildsystem: meson 62 | sources: 63 | - type: dir 64 | path: . 65 | -------------------------------------------------------------------------------- /data/SaveFooter-min.html: -------------------------------------------------------------------------------- 1 | 19 | -------------------------------------------------------------------------------- /data/SaveHeader-min.html: -------------------------------------------------------------------------------- 1 | Spice-Up - WebViewer

Loading presentation...

2 | -------------------------------------------------------------------------------- /data/assets.gresource.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | icons/drag.svg 5 | icons/gradient-symbolic.svg 6 | icons/color-palette-symbolic.svg 7 | icons/gradient-palette-symbolic.svg 8 | icons/custom-color-symbolic.svg 9 | icons/align-top-symbolic.svg 10 | icons/align-middle-symbolic.svg 11 | icons/align-bottom-symbolic.svg 12 | stylesheet.css 13 | SaveHeader-min.html 14 | SaveFooter-min.html 15 | 16 | 17 | assets/templates/Black.spice 18 | assets/templates/Colorful.spice 19 | assets/templates/Green.spice 20 | assets/templates/Landscape.spice 21 | assets/templates/Paper.spice 22 | assets/templates/Spice-Up.spice 23 | assets/templates/White.spice 24 | 25 | 26 | assets/patterns/3px-tile.png 27 | assets/patterns/45-degree-fabric-dark.png 28 | assets/patterns/45-degree-fabric-light.png 29 | assets/patterns/batthern.png 30 | assets/patterns/beige-paper.png 31 | assets/patterns/black-linen.png 32 | assets/patterns/bright-squares.png 33 | assets/patterns/diamond-upholstery.png 34 | assets/patterns/flowers.png 35 | assets/patterns/hexellence.png 36 | assets/patterns/gplay.png 37 | assets/patterns/inspiration-geometry.png 38 | assets/patterns/dark-geometric.png 39 | assets/patterns/light-wool.png 40 | assets/patterns/ps-neutral.png 41 | assets/patterns/silver-scales.png 42 | assets/patterns/subtle-freckles.png 43 | assets/patterns/subtle-grey.png 44 | assets/patterns/xv.png 45 | 46 | 47 | -------------------------------------------------------------------------------- /data/assets/patterns/3px-tile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Philip-Scott/Spice-up/56647140c7725d0ec6c450eda1756eeea6fc766b/data/assets/patterns/3px-tile.png -------------------------------------------------------------------------------- /data/assets/patterns/45-degree-fabric-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Philip-Scott/Spice-up/56647140c7725d0ec6c450eda1756eeea6fc766b/data/assets/patterns/45-degree-fabric-dark.png -------------------------------------------------------------------------------- /data/assets/patterns/45-degree-fabric-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Philip-Scott/Spice-up/56647140c7725d0ec6c450eda1756eeea6fc766b/data/assets/patterns/45-degree-fabric-light.png -------------------------------------------------------------------------------- /data/assets/patterns/LISENCE.txt: -------------------------------------------------------------------------------- 1 | Background patterns from subtlepatterns.com 2 | 3 | The authors of the patterns (in no particular order) are: 4 | 5 | Gre3g: http://gre3g.livejournal.com/ 6 | Atoe Mo: http://www.atlemo.com/ 7 | Alexx Tapein: http://www.tapein.com/ 8 | Konstantin Ivanov: http://twitter.com/phenix_h_k 9 | Waseem Dahman: http://twitter.com/dwaseem 10 | Alex Parker: http://twitter.com/misterparker 11 | Haris Sumic 12 | Lasma: http://www.oddfur.com/ 13 | 14 | This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA. 15 | -------------------------------------------------------------------------------- /data/assets/patterns/batthern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Philip-Scott/Spice-up/56647140c7725d0ec6c450eda1756eeea6fc766b/data/assets/patterns/batthern.png -------------------------------------------------------------------------------- /data/assets/patterns/beige-paper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Philip-Scott/Spice-up/56647140c7725d0ec6c450eda1756eeea6fc766b/data/assets/patterns/beige-paper.png -------------------------------------------------------------------------------- /data/assets/patterns/black-linen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Philip-Scott/Spice-up/56647140c7725d0ec6c450eda1756eeea6fc766b/data/assets/patterns/black-linen.png -------------------------------------------------------------------------------- /data/assets/patterns/bright-squares.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Philip-Scott/Spice-up/56647140c7725d0ec6c450eda1756eeea6fc766b/data/assets/patterns/bright-squares.png -------------------------------------------------------------------------------- /data/assets/patterns/dark-geometric.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Philip-Scott/Spice-up/56647140c7725d0ec6c450eda1756eeea6fc766b/data/assets/patterns/dark-geometric.png -------------------------------------------------------------------------------- /data/assets/patterns/diamond-upholstery.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Philip-Scott/Spice-up/56647140c7725d0ec6c450eda1756eeea6fc766b/data/assets/patterns/diamond-upholstery.png -------------------------------------------------------------------------------- /data/assets/patterns/flowers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Philip-Scott/Spice-up/56647140c7725d0ec6c450eda1756eeea6fc766b/data/assets/patterns/flowers.png -------------------------------------------------------------------------------- /data/assets/patterns/gplay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Philip-Scott/Spice-up/56647140c7725d0ec6c450eda1756eeea6fc766b/data/assets/patterns/gplay.png -------------------------------------------------------------------------------- /data/assets/patterns/hexellence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Philip-Scott/Spice-up/56647140c7725d0ec6c450eda1756eeea6fc766b/data/assets/patterns/hexellence.png -------------------------------------------------------------------------------- /data/assets/patterns/inspiration-geometry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Philip-Scott/Spice-up/56647140c7725d0ec6c450eda1756eeea6fc766b/data/assets/patterns/inspiration-geometry.png -------------------------------------------------------------------------------- /data/assets/patterns/light-wool.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Philip-Scott/Spice-up/56647140c7725d0ec6c450eda1756eeea6fc766b/data/assets/patterns/light-wool.png -------------------------------------------------------------------------------- /data/assets/patterns/ps-neutral.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Philip-Scott/Spice-up/56647140c7725d0ec6c450eda1756eeea6fc766b/data/assets/patterns/ps-neutral.png -------------------------------------------------------------------------------- /data/assets/patterns/shattered.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Philip-Scott/Spice-up/56647140c7725d0ec6c450eda1756eeea6fc766b/data/assets/patterns/shattered.png -------------------------------------------------------------------------------- /data/assets/patterns/silver-scales.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Philip-Scott/Spice-up/56647140c7725d0ec6c450eda1756eeea6fc766b/data/assets/patterns/silver-scales.png -------------------------------------------------------------------------------- /data/assets/patterns/subtle-freckles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Philip-Scott/Spice-up/56647140c7725d0ec6c450eda1756eeea6fc766b/data/assets/patterns/subtle-freckles.png -------------------------------------------------------------------------------- /data/assets/patterns/subtle-grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Philip-Scott/Spice-up/56647140c7725d0ec6c450eda1756eeea6fc766b/data/assets/patterns/subtle-grey.png -------------------------------------------------------------------------------- /data/assets/patterns/xv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Philip-Scott/Spice-up/56647140c7725d0ec6c450eda1756eeea6fc766b/data/assets/patterns/xv.png -------------------------------------------------------------------------------- /data/com.github.philip_scott.spice-up.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=Spice-Up 3 | Comment=Spice up your slides 4 | Comment[ca]=Assaoneu les vostres presentacions 5 | Comment[es]=Dele vida a sus presentaciones 6 | Comment[fr]=Épicer vos présentations 7 | Comment[pt_BR]=Tempere os seus slides 8 | Exec=com.github.philip_scott.spice-up %u 9 | Icon=com.github.philip_scott.spice-up 10 | Terminal=false 11 | Type=Application 12 | StartupNotify=true 13 | Categories=Office;Presentation; 14 | MimeType=application/x-spiceup; 15 | -------------------------------------------------------------------------------- /data/com.github.philip_scott.spice-up.mime.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Spice-Up Presentation 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /data/icons/align-bottom-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 16 | 36 | 38 | 39 | 41 | image/svg+xml 42 | 44 | 45 | 46 | 47 | 48 | 50 | 54 | 58 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /data/icons/align-middle-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 16 | 36 | 38 | 39 | 41 | image/svg+xml 42 | 44 | 45 | 46 | 47 | 48 | 50 | 54 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /data/icons/align-top-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 16 | 36 | 38 | 39 | 41 | image/svg+xml 42 | 44 | 45 | 46 | 47 | 48 | 50 | 54 | 58 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /data/icons/color-palette-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 16 | 36 | 39 | 40 | 42 | 43 | 45 | image/svg+xml 46 | 48 | elementary Symbolic Icon Theme 49 | 50 | 51 | 52 | elementary Symbolic Icon Theme 54 | 56 | 59 | 63 | 64 | 67 | 71 | 72 | 73 | 77 | 81 | 85 | 88 | 92 | 96 | 100 | 107 | 114 | 121 | 128 | 135 | 142 | 149 | 156 | 163 | 164 | -------------------------------------------------------------------------------- /data/icons/custom-color-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 16 | 36 | 39 | 40 | 42 | 43 | 45 | image/svg+xml 46 | 48 | elementary Symbolic Icon Theme 49 | 50 | 51 | 52 | elementary Symbolic Icon Theme 54 | 56 | 59 | 63 | 64 | 67 | 71 | 72 | 75 | 79 | 80 | 83 | 87 | 88 | 89 | 93 | 97 | 101 | 104 | 108 | 112 | 116 | 120 | 124 | 128 | 131 | 135 | 139 | 143 | 150 | 157 | 165 | 173 | 181 | 188 | 189 | -------------------------------------------------------------------------------- /data/icons/drag.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 41 | 43 | 44 | 46 | image/svg+xml 47 | 49 | 50 | 51 | 52 | 53 | 55 | 57 | 61 | 62 | 64 | 68 | 72 | 73 | 75 | 79 | 83 | 87 | 91 | 92 | 94 | 98 | 102 | 106 | 110 | 111 | 113 | 117 | 121 | 125 | 129 | 130 | 139 | 149 | 158 | 168 | 169 | 174 | 179 | 184 | 185 | -------------------------------------------------------------------------------- /data/icons/gradient-palette-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 37 | 40 | 41 | 43 | 44 | 46 | image/svg+xml 47 | 49 | elementary Symbolic Icon Theme 50 | 51 | 52 | 53 | elementary Symbolic Icon Theme 55 | 57 | 60 | 64 | 68 | 69 | 72 | 76 | 77 | 80 | 84 | 85 | 95 | 105 | 106 | 110 | 114 | 118 | 121 | 126 | 130 | 134 | 138 | 145 | 152 | 153 | -------------------------------------------------------------------------------- /data/icons/gradient-symbolic.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 37 | 40 | 41 | 43 | 44 | 46 | image/svg+xml 47 | 49 | elementary Symbolic Icon Theme 50 | 51 | 52 | 53 | elementary Symbolic Icon Theme 55 | 57 | 60 | 64 | 68 | 69 | 72 | 76 | 77 | 80 | 84 | 85 | 95 | 96 | 100 | 104 | 108 | 111 | 116 | 120 | 124 | 128 | 135 | 136 | -------------------------------------------------------------------------------- /data/meson.build: -------------------------------------------------------------------------------- 1 | icon_sizes = ['16', '24', '32', '48', '64', '128'] 2 | 3 | foreach i : icon_sizes 4 | install_data( 5 | 'icons' / i / meson.project_name() + '.svg', 6 | install_dir: get_option('datadir') / 'icons' / 'hicolor' / i + 'x' + i / 'apps' 7 | ) 8 | install_data( 9 | 'icons' / i / meson.project_name() + '.svg', 10 | install_dir: get_option('datadir') / 'icons' / 'hicolor' / i + 'x' + i + '@2' / 'apps' 11 | ) 12 | endforeach 13 | 14 | install_data( 15 | meson.project_name() + '.desktop', 16 | install_dir: get_option('datadir') / 'applications' 17 | ) 18 | 19 | install_data( 20 | meson.project_name() + '.appdata.xml', 21 | install_dir: get_option('datadir') / 'metainfo', 22 | ) 23 | 24 | install_data( 25 | meson.project_name() + '.mime.xml', 26 | install_dir: get_option('datadir') / 'mime' / 'packages', 27 | ) 28 | -------------------------------------------------------------------------------- /data/stylesheet.css: -------------------------------------------------------------------------------- 1 | @define-color colorPrimary #2c2d2e; 2 | @define-color colorAccent @SLATE_100; 3 | 4 | .padding-none { 5 | padding: 0; 6 | } 7 | 8 | .icon-shadow { 9 | -gtk-icon-shadow: 0px 0px 3px black; 10 | } 11 | 12 | .slide-list { 13 | background-color: shade(@bg_color, 0.75); 14 | border-right: solid 1px rgba(0,0,0,0.75); 15 | } 16 | 17 | .slide-list .list-row:selected:focus, .slide-list row:selected:focus { 18 | background-color: @colorAccent; 19 | } 20 | 21 | .slide-list .list-row:selected, .slide-list row:selected { 22 | background-color: shade(@colorAccent, 0.7); 23 | } 24 | 25 | .canvas { 26 | box-shadow: 27 | inset 0 -1px 0 0 alpha(@highlight_color, 0.2), 28 | inset 0 1px 0 0 alpha(@highlight_color, 0.3), 29 | inset 1px 0 0 0 alpha(@highlight_color, 0.07), 30 | inset -1px 0 0 0 alpha(@highlight_color, 0.07); 31 | border-radius: 6px; 32 | } 33 | 34 | .gradient.circular .checkered, .gradient.circular .colored { 35 | border-radius: 50% 36 | } 37 | 38 | .gradient.circular .colored { 39 | border: 2px solid rgba(0,0,0,0.5); 40 | } 41 | 42 | .gradient.circular { 43 | background: rgba(255, 255, 255, 0.5); 44 | box-shadow: none; 45 | border: 1.4px solid rgba(0,0,0,0.6); 46 | padding: 3px; 47 | } 48 | 49 | .gradient.circular.selected { 50 | background: rgba(255, 255, 255, 0.9); 51 | border: 1.4px solid rgba(0,0,0,0.9); 52 | } 53 | 54 | .canvas, frame { 55 | border-radius: 6px; 56 | } 57 | 58 | .view.canvas { 59 | border-width: 1px; 60 | border-style: solid; 61 | border-color: rgba(0,0,0,0.75); 62 | } 63 | 64 | .view.canvas.preview { 65 | border-color: black; 66 | border-radius: 4px; 67 | } 68 | 69 | GtkTextView, textview { 70 | background-color: transparent; 71 | } 72 | 73 | GtkTextView:selected, textview:selected { 74 | background-color: rgba(0,0,0,0.75); 75 | color: white; 76 | } 77 | 78 | .spice-dynamic-toolbar { 79 | background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.4), rgba(0, 0, 0, 0.3)); 80 | } 81 | 82 | GtkToggleButton.raised, 83 | .raised, 84 | .spice-dynamic-toolbar .raised { 85 | padding: 2px 8px; 86 | } 87 | 88 | .spice-dynamic-toolbar .raised .entry { 89 | padding: 0 3px; 90 | } 91 | 92 | .spice-scale { 93 | color: @text_color; 94 | } 95 | 96 | .app-back { 97 | background-color: @bg_color; 98 | } 99 | 100 | .fullscreen .app-back { 101 | background-color: black; 102 | } 103 | 104 | .remove-padding { 105 | padding: 0; 106 | } 107 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | com.github.philip-scott.spice-up (0.2) UNSTABLE; urgency=low 2 | 3 | * Updated release 4 | 5 | -- Felipe Escoto Tue, 12 Dec 2017 04:52:12 -0600 6 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 9 2 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: com.github.philip-scott.spice-up 2 | Section: editors 3 | Priority: optional 4 | Maintainer: Felipe Escoto 5 | Build-Depends: cmake, 6 | debhelper (>= 9), 7 | libgtk-3-dev, 8 | valac (>= 0.26), 9 | libgranite-dev, 10 | libjson-glib-dev, 11 | libgudev-1.0-dev, 12 | libevdev-dev, 13 | libsoup2.4-dev 14 | 15 | Standards-Version: 3.9.6 16 | Package: com.github.philip-scott.spice-up 17 | Architecture: any 18 | Depends: ${misc:Depends}, ${shlibs:Depends} 19 | Pre-Depends: dpkg (>= 1.15.6) 20 | Description: Spice-Up 21 | Create simple and beautiful presentations 22 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Upstream Author(s): 2 | 3 | Felipe Escoto 4 | 5 | 6 | Copyright: 7 | 8 | Copyright (C) 2016 Felipe Escoto 9 | 10 | License: 11 | 12 | This program is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU General Public License as published by 14 | the Free Software Foundation, either version 3 of the License, or 15 | (at your option) any later version. 16 | 17 | This package is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU General Public License for more details. 21 | 22 | You should have received a copy of the GNU General Public License 23 | along with this program. If not, see . 24 | 25 | On Debian systems, the complete text of the GNU General 26 | Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". 27 | 28 | The Debian packaging is: 29 | 30 | Copyright (C) 2014 Cody Garver 31 | 32 | and is licensed under the GPL version 3, see above. 33 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # -*- makefile -*- 3 | # Sample debian/rules that uses debhelper. 4 | # This file was originally written by Joey Hess and Craig Small. 5 | # As a special exception, when this file is copied by dh-make into a 6 | # dh-make output file, you may use that output file without restriction. 7 | # This special exception was added by Craig Small in version 0.37 of dh-make. 8 | 9 | # Uncomment this to turn on verbose mode. 10 | #export DH_VERBOSE=1 11 | 12 | # Enable additional explot mitigation 13 | # (PIE and *full* RELRO at the time of this writing) 14 | #export DEB_BUILD_MAINT_OPTIONS=hardening=+all 15 | 16 | %: 17 | dh $@ 18 | 19 | override_dh_builddeb: 20 | dh_builddeb -- -Zxz 21 | 22 | 23 | override_dh_install: 24 | dh_install --fail-missing 25 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (native) 2 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project( 2 | 'com.github.philip_scott.spice-up', 3 | 'vala', 'c', 4 | version: '0.7' 5 | ) 6 | 7 | gnome = import('gnome') 8 | i18n = import('i18n') 9 | 10 | add_project_arguments('-DGETTEXT_PACKAGE="@0@"'.format (meson.project_name()), language:'c') 11 | add_project_arguments( 12 | [ 13 | '--define=PLATFORM_LINUX', 14 | '--pkg=linux', 15 | '--vapidir', meson.current_source_dir() / 'vapi' 16 | ], 17 | language: 'vala' 18 | ) 19 | 20 | gresource = gnome.compile_resources( 21 | 'gresource', 22 | 'data' / 'assets.gresource.xml', 23 | source_dir: 'data' 24 | ) 25 | 26 | evdev_dep = dependency('libevdev') 27 | gee_dep = dependency('gee-0.8') 28 | glib_dep = dependency('glib-2.0') 29 | gobject_dep = dependency('gobject-2.0') 30 | granite_dep = dependency('granite', version: '>=0.5') 31 | gtk_dep = dependency('gtk+-3.0') 32 | gudev_dep = dependency('gudev-1.0') 33 | json_glib_dep = dependency('json-glib-1.0') 34 | soup_dep = dependency('libsoup-2.4') 35 | 36 | subdir('data') 37 | subdir('po') 38 | subdir('schemas') 39 | subdir('src') 40 | 41 | meson.add_install_script('meson/post_install.py') 42 | -------------------------------------------------------------------------------- /meson/post_install.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import subprocess 5 | 6 | schemadir = os.path.join(os.environ['MESON_INSTALL_PREFIX'], 'share', 'glib-2.0', 'schemas') 7 | 8 | if not os.environ.get('DESTDIR'): 9 | print('Compiling gsettings schemas...') 10 | subprocess.call(['glib-compile-schemas', schemadir]) 11 | -------------------------------------------------------------------------------- /po/LINGUAS: -------------------------------------------------------------------------------- 1 | ca 2 | de 3 | es 4 | fr 5 | ja 6 | nl_NL 7 | pt_BR 8 | pt_PT 9 | sr 10 | sr@latin 11 | -------------------------------------------------------------------------------- /po/POTFILES: -------------------------------------------------------------------------------- 1 | src/Application.vala 2 | src/Window.vala 3 | 4 | src/Services/Clipboard.vala 5 | src/Services/Settings.vala 6 | src/Services/Slide.vala 7 | src/Services/SlideManager.vala 8 | src/Services/FileManager.vala 9 | src/Services/HistoryManager.vala 10 | src/Services/ImageHandler.vala 11 | src/Services/Utils.vala 12 | src/Services/GamepadSlideController.vala 13 | 14 | src/Widgets/Canvas.vala 15 | src/Widgets/EntryCombo.vala 16 | src/Widgets/Headerbar.vala 17 | src/Widgets/SlideList.vala 18 | src/Widgets/DynamicToolbar.vala 19 | src/Widgets/Welcome.vala 20 | src/Widgets/SlideWidget.vala 21 | src/Widgets/PresenterView.vala 22 | src/Widgets/PresenterNotes.vala 23 | 24 | src/Widgets/ColorPicker/ColorButton.vala 25 | src/Widgets/ColorPicker/ColorChooser.vala 26 | src/Widgets/ColorPicker/Gradient.vala 27 | src/Widgets/ColorPicker/GradientEditor.vala 28 | src/Widgets/ColorPicker/PickerWindow.vala 29 | 30 | src/Widgets/CanvasItems/CanvasItem.vala 31 | src/Widgets/CanvasItems/TextItem.vala 32 | src/Widgets/CanvasItems/ColorItem.vala 33 | src/Widgets/CanvasItems/ImageItem.vala 34 | src/Widgets/CanvasItems/Grabber.vala 35 | 36 | src/Widgets/Toolbars/CanvasBar.vala 37 | src/Widgets/Toolbars/CommonBar.vala 38 | src/Widgets/Toolbars/ImageBar.vala 39 | src/Widgets/Toolbars/ShapeBar.vala 40 | src/Widgets/Toolbars/TextBar.vala 41 | src/Widgets/Toolbars/Toolbar.vala 42 | 43 | src/Widgets/Library/LibraryItem.vala 44 | src/Widgets/Library/Library.vala 45 | 46 | src/Services/libgamepad/libgamepad.vala 47 | src/Services/libgamepad/gamepad-monitor.vala 48 | src/Services/libgamepad/gamepad.vala 49 | src/Services/libgamepad/helpers.vala 50 | src/Services/libgamepad/input-type.vala 51 | src/Services/libgamepad/raw-gamepad-interface.vala 52 | src/Services/libgamepad/raw-gamepad-monitor-interface.vala 53 | src/Services/libgamepad/standard-gamepad-axis.vala 54 | src/Services/libgamepad/standard-gamepad-button.vala 55 | 56 | src/Services/libgamepad/drivers/linux/guid-helpers.vala 57 | src/Services/libgamepad/drivers/linux/raw-gamepad.vala 58 | src/Services/libgamepad/drivers/linux/raw-gamepad-monitor.vala 59 | -------------------------------------------------------------------------------- /po/meson.build: -------------------------------------------------------------------------------- 1 | i18n.gettext(meson.project_name(), 2 | args: '--directory=' + meson.source_root(), 3 | preset: 'glib' 4 | ) 5 | -------------------------------------------------------------------------------- /pull_request_template.md: -------------------------------------------------------------------------------- 1 | Fixes # 2 | 3 | Changes made in this pull request: 4 | - . 5 | - . 6 | - . 7 | 8 | 9 | Thank you for making a pull request! I will try to review it as soon as possible. 10 | -------------------------------------------------------------------------------- /schemas/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include (GSettings) 2 | add_schema ("com.github.philip_scott.spice-up.gschema.xml") 3 | -------------------------------------------------------------------------------- /schemas/com.github.philip_scott.spice-up.gschema.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 920 5 | The saved width of the window. 6 | The saved width of the window. Must be greater than 700, or it will not take effect. 7 | 8 | 9 | 10 | 920 11 | The saved width of the window. 12 | The saved width of the window. Must be greater than 700, or it will not take effect. 13 | 14 | 15 | 16 | 1100 17 | The saved width of the window. 18 | The saved width of the window. Must be greater than 700, or it will not take effect. 19 | 20 | 21 | 22 | 640 23 | The saved height of the window. 24 | The saved height of the window. Must be greater than 400, or it will not take effect. 25 | 26 | 27 | 28 | "" 29 | The last opened file 30 | The last file you opened is here 31 | 32 | 33 | 34 | [] 35 | The last opened files 36 | The last 10 files you openeded are here 37 | 38 | 39 | 40 | "" 41 | Controler configuration for presentation mode 42 | In JSON format 43 | 44 | 45 | 46 | "0" 47 | Last time it fetched templates from server 48 | Stored to fetch templates only once every day 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /schemas/meson.build: -------------------------------------------------------------------------------- 1 | install_data( 2 | meson.project_name() + '.gschema.xml', 3 | install_dir: get_option('datadir') / 'glib-2.0' / 'schemas' 4 | ) 5 | -------------------------------------------------------------------------------- /src/Application.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Felipe Escoto (https://github.com/Philip-Scott/Spice-up) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 | * Boston, MA 02111-1307, USA. 18 | * 19 | * Authored by: Felipe Escoto 20 | */ 21 | 22 | public static bool DEBUG = false; 23 | 24 | namespace Spice { 25 | public Spice.Services.Settings settings; 26 | public string DATA_DIR; 27 | } 28 | 29 | public class Spice.Application : Gtk.Application { 30 | public const string PROGRAM_NAME = N_("Spice-Up"); 31 | public const string ABOUT_STOCK = N_("About Spice-Up"); 32 | public const string APP_ID = "com.github.philip_scott.spice-up"; 33 | public const string RESOURCE_PATH = "/com/github/philip-scott/spice-up/"; 34 | 35 | private const string APP_NAME = "Spice-Up"; 36 | 37 | public bool running = false; 38 | 39 | public static Spice.Application _instance = null; 40 | public static unowned Spice.Application instance { 41 | get { 42 | if (_instance == null) { 43 | _instance = new Spice.Application (); 44 | } 45 | return _instance; 46 | } 47 | } 48 | 49 | private Gee.HashMap opened_files; 50 | 51 | construct { 52 | flags |= ApplicationFlags.HANDLES_OPEN; 53 | 54 | application_id = APP_ID; 55 | 56 | opened_files = new Gee.HashMap(); 57 | settings = Spice.Services.Settings.get_instance (); 58 | } 59 | 60 | public override void open (File[] files, string hint) { 61 | init (); 62 | foreach (var file in files) { 63 | if (is_file_opened (file)) { 64 | // Preset active window with file 65 | var window = get_window_from_file (file); 66 | window.show_app (); 67 | } else { 68 | // Open New window 69 | var window = new Spice.Window (this); 70 | this.add_window (window); 71 | 72 | window.open_file (file); 73 | window.show_app (); 74 | } 75 | } 76 | } 77 | 78 | private void init () { 79 | if (!running) { 80 | Gtk.Settings.get_default ().gtk_application_prefer_dark_theme = true; 81 | weak Gtk.IconTheme default_theme = Gtk.IconTheme.get_default (); 82 | default_theme.add_resource_path (RESOURCE_PATH); 83 | running = true; 84 | } 85 | } 86 | 87 | public override void activate () { 88 | init (); 89 | 90 | var window = new Spice.Window (this); 91 | this.add_window (window); 92 | window.show_welcome (); 93 | 94 | get_active_spice_window ().show_app (); 95 | } 96 | 97 | public static unowned Spice.Window get_active_spice_window () { 98 | return (Spice.Window) instance.get_active_window (); 99 | } 100 | 101 | public bool is_file_opened (File file) { 102 | return opened_files.has_key (file.get_uri ()); 103 | } 104 | 105 | public void unregister_file_from_window (File file) { 106 | if (is_file_opened (file)) { 107 | opened_files.unset (file.get_uri ()); 108 | } 109 | } 110 | 111 | public void register_file_to_window (File file, Spice.Window window) { 112 | if (!is_file_opened (file)) { 113 | opened_files.set (file.get_uri (), window); 114 | } else { 115 | warning ("File was opened in two separate windows"); 116 | } 117 | } 118 | 119 | public Spice.Window get_window_from_file (File file) { 120 | return opened_files.get (file.get_uri ()); 121 | } 122 | 123 | public static int main (string[] args) { 124 | DEBUG = "-d" in args; 125 | 126 | /* Initiliaze gettext support */ 127 | Intl.setlocale (LocaleCategory.ALL, Intl.get_language_names ()[0]); 128 | //Intl.setlocale (LocaleCategory.NUMERIC, "en_US"); 129 | //Intl.textdomain (TERMINAL_NAME); 130 | 131 | Environment.set_application_name (APP_NAME); 132 | Environment.set_prgname (APP_NAME); 133 | 134 | var application = Spice.Application.instance; 135 | 136 | return application.run (args); 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/Services/HistoryManager.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Felipe Escoto (https://github.com/Philip-Scott/Spice-up) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 | * Boston, MA 02111-1307, USA. 18 | * 19 | * Authored by: Felipe Escoto 20 | */ 21 | 22 | public enum Spice.HistoryActionType { 23 | ITEM_MOVED, 24 | SLIDE_CHANGED, 25 | ITEM_CHANGED, 26 | CANVAS_CHANGED, 27 | ITEM_DEPTH 28 | } 29 | 30 | public class Spice.Services.HistoryManager : Object { 31 | public const uint MAX_SIZE = 50; 32 | 33 | public signal void action_called (Spice.CanvasItem? item); 34 | 35 | public signal void undo_changed (bool is_empty); 36 | public signal void redo_changed (bool is_empty); 37 | 38 | public class HistoryAction : Object { 39 | private Value value; 40 | 41 | public HistoryActionType history_type { get; construct set; } 42 | public unowned I item { get; construct set; } 43 | public unowned Canvas parent { private get; construct set; } 44 | 45 | public string property { get; construct set; } 46 | 47 | public HistoryAction.depth_changed (I item, Canvas canvas, bool moved_up) { 48 | Object (item: item, history_type: HistoryActionType.ITEM_DEPTH, property: "depth", parent: canvas); 49 | value = moved_up; 50 | } 51 | 52 | public HistoryAction.item_moved (I item) { 53 | Object (item: item, history_type: HistoryActionType.ITEM_MOVED, property: "rectangle"); 54 | get_item_property (); 55 | } 56 | 57 | public HistoryAction.item_changed (I item, string property) { 58 | Object (item: item, history_type: HistoryActionType.ITEM_CHANGED, property: property); 59 | get_item_property (); 60 | } 61 | 62 | public HistoryAction.slide_changed (I item, string property) { 63 | Object (item: item, history_type: HistoryActionType.SLIDE_CHANGED, property: property); 64 | get_item_property (); 65 | } 66 | 67 | public HistoryAction.canvas_changed (I item, string property) { 68 | Object (item: item, history_type: HistoryActionType.CANVAS_CHANGED, property: property); 69 | get_item_property (); 70 | } 71 | 72 | private void get_item_property () { 73 | value = Value (typeof (T)); 74 | ((Object) item).get_property (property, ref value); 75 | } 76 | 77 | public void action () { 78 | if (history_type != HistoryActionType.ITEM_DEPTH) { 79 | var temp = Value (typeof (T)); 80 | ((Object) item).get_property (property, ref temp); 81 | ((Object) item).set_property (property, value); 82 | 83 | if (history_type == HistoryActionType.ITEM_CHANGED) { 84 | ((CanvasItem) item).style (); 85 | } else if (history_type == HistoryActionType.CANVAS_CHANGED) { 86 | ((Canvas) item).style (); 87 | } 88 | 89 | this.value = temp; 90 | } else { 91 | if (value.get_boolean ()) { 92 | parent.move_down ((CanvasItem) item, false); 93 | } else { 94 | parent.move_up ((CanvasItem) item, false); 95 | } 96 | 97 | value.set_boolean (!value.get_boolean ()); 98 | } 99 | } 100 | } 101 | 102 | private Queue undo_history; 103 | private Queue redo_history; 104 | 105 | public HistoryManager () { 106 | undo_history = new Queue(); 107 | redo_history = new Queue(); 108 | } 109 | 110 | public void add_undoable_action (HistoryAction action, bool force_add = false) { 111 | redo_history.clear (); 112 | 113 | var last_action = undo_history.peek_head (); 114 | 115 | if (force_add || last_action == null 116 | || last_action.property != action.property 117 | || ((HistoryAction) last_action).item != ((HistoryAction) action).item) { 118 | undo_history.push_head (action); 119 | } 120 | 121 | if (undo_history.get_length () > MAX_SIZE) { 122 | undo_history.pop_tail (); 123 | } 124 | 125 | send_signals (); 126 | } 127 | 128 | public HistoryAction? undo () { 129 | if (undo_history.is_empty()) { 130 | return null; 131 | } 132 | 133 | var item = undo_history.pop_head (); 134 | item.action (); 135 | 136 | if (item.history_type != HistoryActionType.CANVAS_CHANGED) { 137 | action_called (((HistoryAction) item).item); 138 | } else { 139 | action_called (null); 140 | } 141 | 142 | redo_history.push_head (item); 143 | send_signals (); 144 | 145 | return item; 146 | } 147 | 148 | public HistoryAction? redo () { 149 | if (redo_history.is_empty()) { 150 | return null; 151 | } 152 | 153 | var item = redo_history.pop_head (); 154 | item.action (); 155 | 156 | if (item.history_type != HistoryActionType.CANVAS_CHANGED) { 157 | action_called (((HistoryAction) item).item); 158 | } else { 159 | action_called (null); 160 | } 161 | 162 | undo_history.push_head (item); 163 | send_signals (); 164 | 165 | return item; 166 | } 167 | 168 | private void send_signals () { 169 | undo_changed (undo_history.is_empty()); 170 | redo_changed (redo_history.is_empty()); 171 | } 172 | 173 | public void clear_history () { 174 | undo_history.clear (); 175 | redo_history.clear (); 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /src/Services/ImageHandler.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Felipe Escoto (https://github.com/Philip-Scott/Spice-up) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 | * Boston, MA 02111-1307, USA. 18 | * 19 | * Authored by: Felipe Escoto 20 | */ 21 | 22 | public class Spice.ImageHandler : Object { 23 | public static uint FILE_ID = 0; 24 | 25 | public signal void file_changed (); 26 | 27 | private uint file_id; 28 | 29 | const string FILENAME = "/spice-up-%s-img-%u.%s"; 30 | 31 | private FileMonitor? monitor = null; 32 | private bool file_changing = false; 33 | 34 | public bool valid = false; 35 | private string? base64_image = null; 36 | 37 | public string image_extension { get; private set; } 38 | 39 | private string url_ = ""; 40 | public string url { 41 | get { 42 | return url_; 43 | } set { 44 | url_ = value; 45 | var file = File.new_for_path (value); 46 | monitor_file (file); 47 | valid = (file.query_exists () && Utils.is_valid_image (file)); 48 | file_changed (); 49 | } 50 | } 51 | 52 | public ImageHandler.from_data (string _extension, string _base64_data) { 53 | file_id = FILE_ID++; 54 | image_extension = _extension != "" ? _extension : "png"; 55 | base64_image = _base64_data; 56 | url = data_to_file (_base64_data); 57 | } 58 | 59 | public ImageHandler.from_file (File file) { 60 | file_id = FILE_ID++; 61 | replace (file); 62 | } 63 | 64 | public void replace (File file) { 65 | if (monitor != null) { 66 | monitor.cancel (); 67 | } 68 | 69 | image_extension = get_extension (file.get_basename ()); 70 | data_from_file (file); 71 | url = data_to_file (base64_image); 72 | } 73 | 74 | public string serialize () { 75 | return """"image":"%s", "image-data":"%s" """.printf (image_extension, base64_image); 76 | } 77 | 78 | private void monitor_file (File file) { 79 | try { 80 | monitor = file.monitor (FileMonitorFlags.NONE, null); 81 | 82 | monitor.changed.connect ((src, dest, event) => { 83 | if (event == FileMonitorEvent.CHANGED) { 84 | file_changing = true; 85 | } else if (event == FileMonitorEvent.CHANGES_DONE_HINT && file_changing) { 86 | data_from_file (file); 87 | file_changed (); 88 | file_changing = false; 89 | } 90 | }); 91 | } catch (Error e) { 92 | warning ("Could not monitor file: %s", e.message); 93 | } 94 | } 95 | 96 | private string get_extension (string filename) { 97 | var parts = filename.split ("."); 98 | if (parts.length > 1) { 99 | return parts[parts.length - 1]; 100 | } else { 101 | return "png"; 102 | } 103 | } 104 | 105 | private void data_from_file (File file) { 106 | base64_image = Spice.Services.FileManager.file_to_base64 (file); 107 | } 108 | 109 | private string data_to_file (string data) { 110 | var filename = Environment.get_tmp_dir () + FILENAME.printf (Environment.get_user_name (), file_id, image_extension); 111 | Spice.Services.FileManager.base64_to_file (filename, data); 112 | 113 | return filename; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/Services/Settings.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2016 Felipe Escoto (https://github.com/Philip-Scott/Notes-up) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 | * Boston, MA 02111-1307, USA. 18 | * 19 | * Authored by: Felipe Escoto 20 | */ 21 | 22 | public class Spice.Services.Settings : Granite.Services.Settings { 23 | private static Settings? instance = null; 24 | 25 | public int pos_x { get; set; } 26 | public int pos_y { get; set; } 27 | public int window_width { get; set; } 28 | public int window_height { get; set; } 29 | public string last_fetch { get; set; } 30 | public string[] last_files { get; set; } 31 | public string controler_config { get; set; } 32 | 33 | public static Settings get_instance () { 34 | if (instance == null) { 35 | instance = new Settings (); 36 | } 37 | 38 | return instance; 39 | } 40 | 41 | private Settings () { 42 | base ("com.github.philip_scott.spice-up"); 43 | } 44 | 45 | public void add_file (string file) { 46 | if (!Granite.Services.System.history_is_enabled ()) return; 47 | 48 | var current_files = last_files; 49 | 50 | Gee.List existing_files = new Gee.ArrayList (); 51 | existing_files.add_all_array (current_files); 52 | 53 | if (file in current_files) { 54 | existing_files.remove (file); 55 | } 56 | 57 | existing_files.insert (0, file); 58 | if (existing_files.size > 50) { 59 | existing_files = existing_files.slice (0, 10); 60 | } 61 | 62 | last_files = existing_files.to_array (); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Services/Slide.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Felipe Escoto (https://github.com/Philip-Scott/Spice-up) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 | * Boston, MA 02111-1307, USA. 18 | * 19 | * Authored by: Felipe Escoto 20 | */ 21 | 22 | public class Spice.Slide : Object { 23 | public signal void visible_changed (bool val); 24 | 25 | protected Json.Object? save_data = null; 26 | 27 | public Canvas canvas; 28 | public Gtk.Image preview; 29 | 30 | public string preview_data { get; private set; default = ""; } 31 | public string notes { get; set; default = ""; } 32 | public Gtk.StackTransitionType transition { get; set; default = Gtk.StackTransitionType.NONE; } 33 | 34 | private bool visible_ = true; 35 | public bool visible { 36 | get { 37 | return visible_; 38 | } set { 39 | this.visible_ = value; 40 | canvas.visible = value; 41 | visible_changed (value); 42 | } 43 | } 44 | 45 | public Slide (Spice.Window window, Json.Object? save_data = null) { 46 | this.save_data = save_data; 47 | canvas = new Spice.Canvas (window, save_data); 48 | 49 | canvas.request_draw_preview.connect (reload_preview_data); 50 | load_data (); 51 | } 52 | 53 | public Slide.empty (Spice.Window window) { 54 | this.save_data = Utils.get_json_object (EMPTY_SLIDE); 55 | canvas = new Spice.Canvas (window, save_data); 56 | 57 | load_data (); 58 | visible = false; 59 | } 60 | 61 | public Slide.without_canvas (Json.Object? save_data = null) { 62 | this.save_data = save_data; 63 | canvas = null; 64 | 65 | load_data (); 66 | } 67 | 68 | construct { 69 | preview = new Gtk.Image (); 70 | } 71 | 72 | public void load_slide () { 73 | if (save_data == null) return; 74 | canvas.clear_all (); 75 | 76 | var items = save_data.get_array_member ("items"); 77 | 78 | foreach (var raw in items.get_elements ()) { 79 | var item = Utils.canvas_item_from_data (raw.get_object (), canvas); 80 | add_item (item); 81 | } 82 | 83 | this.save_data = null; 84 | } 85 | 86 | private void load_data () { 87 | if (save_data == null) return; 88 | 89 | preview_data = save_data.get_string_member ("preview"); 90 | if (preview_data != null && preview_data != "") { 91 | var pixbuf = Utils.base64_to_pixbuf (preview_data); 92 | 93 | preview.set_from_pixbuf (pixbuf.scale_simple (SlideList.WIDTH, SlideList.HEIGHT, Gdk.InterpType.BILINEAR)); 94 | } 95 | 96 | if (save_data.has_member ("transition")) { 97 | transition = (Gtk.StackTransitionType) save_data.get_int_member ("transition"); 98 | } else { 99 | transition = Gtk.StackTransitionType.NONE; 100 | } 101 | 102 | var raw_notes = save_data.get_string_member ("notes"); 103 | if (raw_notes != null && raw_notes != "") { 104 | notes = (string) GLib.Base64.decode (raw_notes); 105 | } 106 | } 107 | 108 | public void add_item (CanvasItem item, bool select_item = false, bool save_history = false) { 109 | canvas.add_item (item, save_history); 110 | 111 | if (select_item) { 112 | canvas.item_clicked (item); 113 | item.clicked (); 114 | } 115 | } 116 | 117 | public void reload_preview_data () { 118 | Timeout.add (110, () => { 119 | if (canvas.surface != null) { 120 | var pixbuf = canvas.surface.load_to_pixbuf ().scale_simple (SlideList.WIDTH, SlideList.HEIGHT, Gdk.InterpType.BILINEAR); 121 | preview.set_from_pixbuf (pixbuf); 122 | preview_data = Utils.pixbuf_to_base64 (pixbuf); 123 | } 124 | 125 | return false; 126 | }); 127 | } 128 | 129 | public string serialise () { 130 | if (this.save_data != null) { 131 | var root = new Json.Node (Json.NodeType.OBJECT); 132 | root.set_object (save_data); 133 | 134 | var gen = new Json.Generator (); 135 | gen.set_root (root); 136 | 137 | return gen.to_data (null); 138 | } 139 | 140 | string data = ""; 141 | 142 | foreach (var widget in canvas.get_children ()) { 143 | if (widget is CanvasItem && widget.visible) { 144 | CanvasItem item = (CanvasItem) widget; 145 | 146 | data = data + (data != "" ? "," + item.serialise () : item.serialise ()); 147 | } 148 | } 149 | 150 | var raw_notes = (string) GLib.Base64.encode (notes.data); 151 | return "{%s, \"transition\": %d, \"items\": [%s], \"notes\": \"%s\", \"preview\": \"%s\"}\n".printf (canvas.serialise (), (int) transition, data, raw_notes, preview_data); 152 | } 153 | 154 | public void delete () { 155 | var action = new Spice.Services.HistoryManager.HistoryAction.slide_changed (this, "visible"); 156 | canvas.window.history_manager.add_undoable_action (action, true); 157 | 158 | this.visible = false; 159 | } 160 | 161 | public void destroy () { 162 | canvas.destroy (); 163 | } 164 | 165 | private const string EMPTY_SLIDE = """{"background-color":"#000000", "background-pattern":"" , "items": [{"x": 0,"y": 0,"w": 720,"h": 510, "type": "color", "background_color": "#000000", "border-radius": 0 }], "notes":"", "preview": "iVBORw0KGgoAAAANSUhEUgAAAQsAAACWCAYAAADJ2q17AAAABmJLR0QA/wD/AP+gvaeTAAACM0lEQVR4nO3UMWpbURQAUd3Hlwpt1qndxztOVOjDcx8ITCcZzlnBVDNrrY/jOL5m5n4B+Mfe+3Ge5+fcbrc/z+fzvvd+dRPwhmbmcr1e/66ZMQrgv/bel5m5r1eHAD+DWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQCJWQDJ2ns/ZubVHcCbmpnL3vsxa61fx3H8npn7q6OA97P3fpzn+fkNRKooH6vPau0AAAAASUVORK5CYII="}"""; 166 | } 167 | -------------------------------------------------------------------------------- /src/Services/libgamepad/drivers/linux/guid-helpers.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Megh Parikh 3 | * 4 | * This file is part of LibGamepad. 5 | * 6 | * LibGamepad is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * LibGamepad is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with Foobar. If not, see . 18 | */ 19 | 20 | private class LibGamepad.LinuxGuidHelpers : Object { 21 | public static string from_dev (Libevdev.Evdev dev) { 22 | uint16 guid[8]; 23 | guid[0] = (uint16) dev.id_bustype.to_little_endian (); 24 | guid[1] = 0; 25 | guid[2] = (uint16) dev.id_vendor.to_little_endian (); 26 | guid[3] = 0; 27 | guid[4] = (uint16) dev.id_product.to_little_endian (); 28 | guid[5] = 0; 29 | guid[6] = (uint16) dev.id_version.to_little_endian (); 30 | guid[7] = 0; 31 | return uint16s_to_hex_string (guid); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Services/libgamepad/drivers/linux/raw-gamepad-monitor.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Megh Parikh 3 | * 4 | * This file is part of LibGamepad. 5 | * 6 | * LibGamepad is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * LibGamepad is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with Foobar. If not, see . 18 | */ 19 | 20 | private class LibGamepad.LinuxRawGamepadMonitor : Object, RawGamepadMonitor { 21 | public delegate void RawGamepadCallback (RawGamepad raw_gamepad); 22 | 23 | private GUdev.Client client; 24 | 25 | public LinuxRawGamepadMonitor () { 26 | client = new GUdev.Client ({"input"}); 27 | client.uevent.connect (handle_udev_client_callback); 28 | } 29 | 30 | public void foreach_gamepad (RawGamepadCallback callback) { 31 | client.query_by_subsystem ("input").foreach ((dev) => { 32 | if (dev.get_device_file () == null) 33 | return; 34 | var identifier = dev.get_device_file (); 35 | if ((dev.has_property ("ID_INPUT_JOYSTICK") && dev.get_property ("ID_INPUT_JOYSTICK") == "1") || 36 | (dev.has_property (".INPUT_CLASS") && dev.get_property (".INPUT_CLASS") == "joystick")) { 37 | RawGamepad raw_gamepad; 38 | try { 39 | raw_gamepad = new LinuxRawGamepad (identifier); 40 | } catch (FileError err) { 41 | return; 42 | } 43 | callback (raw_gamepad); 44 | } 45 | }); 46 | } 47 | 48 | private void handle_udev_client_callback (string action, GUdev.Device dev) { 49 | if (dev.get_device_file () == null) 50 | return; 51 | 52 | var identifier = dev.get_device_file (); 53 | if ((dev.has_property ("ID_INPUT_JOYSTICK") && dev.get_property ("ID_INPUT_JOYSTICK") == "1") || 54 | (dev.has_property (".INPUT_CLASS") && dev.get_property (".INPUT_CLASS") == "joystick")) { 55 | switch (action) { 56 | case "add": 57 | RawGamepad raw_gamepad; 58 | try { 59 | raw_gamepad = new LinuxRawGamepad (identifier); 60 | } catch (FileError err) { 61 | return; 62 | } 63 | gamepad_plugged (raw_gamepad); 64 | break; 65 | case "remove": 66 | gamepad_unplugged (identifier); 67 | break; 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/Services/libgamepad/drivers/linux/raw-gamepad.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Megh Parikh 3 | * 4 | * This file is part of LibGamepad. 5 | * 6 | * LibGamepad is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * LibGamepad is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with Foobar. If not, see . 18 | */ 19 | 20 | private class LibGamepad.LinuxRawGamepad : Object, RawGamepad { 21 | private int fd; 22 | private GUdev.Client gudev_client; 23 | private uint? event_source_id; 24 | private Libevdev.Evdev dev; 25 | 26 | private uint8 key_map[Linux.Input.KEY_MAX]; 27 | private uint8 abs_map[Linux.Input.ABS_MAX]; 28 | private Linux.Input.AbsInfo abs_info[Linux.Input.ABS_MAX]; 29 | 30 | private string _identifier; 31 | public string identifier { get { return _identifier; } } 32 | 33 | private string _name; 34 | public string name { get { return _name; } } 35 | 36 | private string _guid; 37 | public string guid { get { return _guid; } } 38 | 39 | private uint8 _axes_number = 0; 40 | public uint8 axes_number { get { return _axes_number; } } 41 | 42 | private uint8 _buttons_number = 0; 43 | public uint8 buttons_number { get { return _buttons_number; } } 44 | 45 | private int _dpads_number = -1; 46 | public uint8 dpads_number { 47 | get { 48 | if (_dpads_number != -1) 49 | return (uint8) _dpads_number; 50 | 51 | _dpads_number = 0; 52 | for (var i = Linux.Input.ABS_HAT0X; i <= Linux.Input.ABS_HAT3Y; i += 2) { 53 | if (dev.has_event_code (Linux.Input.EV_ABS, i) || 54 | dev.has_event_code (Linux.Input.EV_ABS, i + 1)) { 55 | var absinfo = dev.get_abs_info (i); 56 | if (absinfo == null) 57 | continue; 58 | 59 | _dpads_number++; 60 | } 61 | } 62 | 63 | return (uint8) _dpads_number; 64 | } 65 | } 66 | 67 | public LinuxRawGamepad (string file_name) throws FileError { 68 | _identifier = file_name; 69 | fd = Posix.open (file_name, Posix.O_RDONLY | Posix.O_NONBLOCK); 70 | 71 | if (fd < 0) 72 | throw new FileError.FAILED (@"Unable to open file $file_name: $(Posix.strerror (Posix.errno))"); 73 | 74 | dev = new Libevdev.Evdev (); 75 | if (dev.set_fd (fd) < 0) 76 | throw new FileError.FAILED (@"Evdev is unable to open $file_name: $(Posix.strerror (Posix.errno))"); 77 | 78 | // Monitor the file for deletion 79 | gudev_client = new GUdev.Client ({"input"}); 80 | gudev_client.uevent.connect (handle_gudev_event); 81 | 82 | _name = dev.name; 83 | _guid = LinuxGuidHelpers.from_dev (dev); 84 | 85 | // Poll the events in the default main loop 86 | var channel = new IOChannel.unix_new (fd); 87 | event_source_id = channel.add_watch (IOCondition.IN, poll_events); 88 | 89 | // Initialize dpads, buttons and axes 90 | for (var i = Linux.Input.BTN_JOYSTICK; i < Linux.Input.KEY_MAX; i++) { 91 | if (dev.has_event_code (Linux.Input.EV_KEY, i)) { 92 | key_map[i - Linux.Input.BTN_MISC] = _buttons_number; 93 | _buttons_number++; 94 | } 95 | } 96 | for (var i = Linux.Input.BTN_MISC; i < Linux.Input.BTN_JOYSTICK; i++) { 97 | if (dev.has_event_code (Linux.Input.EV_KEY, i)) { 98 | key_map[i - Linux.Input.BTN_MISC] = _buttons_number; 99 | _buttons_number++; 100 | } 101 | } 102 | 103 | 104 | // Get info about axes 105 | for (var i = 0; i < Linux.Input.ABS_MAX; i++) { 106 | /* Skip dpads */ 107 | if (i == Linux.Input.ABS_HAT0X) { 108 | i = Linux.Input.ABS_HAT3Y; 109 | continue; 110 | } 111 | if (dev.has_event_code (Linux.Input.EV_ABS, i)) { 112 | var absinfo = dev.get_abs_info (i); 113 | abs_map[i] = _axes_number; 114 | abs_info[_axes_number] = absinfo; 115 | _axes_number++; 116 | } 117 | } 118 | } 119 | 120 | ~LinuxRawGamepad () { 121 | Posix.close (fd); 122 | remove_event_source (); 123 | } 124 | 125 | private bool poll_events () { 126 | while (dev.has_event_pending () > 0) 127 | handle_evdev_event (); 128 | 129 | return true; 130 | } 131 | 132 | private void handle_evdev_event () { 133 | int rc; 134 | Linux.Input.Event ev; 135 | rc = dev.next_event (Libevdev.ReadFlag.NORMAL, out ev); 136 | if (rc == 0) { 137 | int code = ev.code; 138 | switch (ev.type) { 139 | case Linux.Input.EV_KEY: 140 | if (code >= Linux.Input.BTN_MISC) { 141 | button_event (key_map[code - Linux.Input.BTN_MISC], (bool) ev.value); 142 | } 143 | break; 144 | case Linux.Input.EV_ABS: 145 | switch (code) { 146 | case Linux.Input.ABS_HAT0X: 147 | case Linux.Input.ABS_HAT0Y: 148 | case Linux.Input.ABS_HAT1X: 149 | case Linux.Input.ABS_HAT1Y: 150 | case Linux.Input.ABS_HAT2X: 151 | case Linux.Input.ABS_HAT2Y: 152 | case Linux.Input.ABS_HAT3X: 153 | case Linux.Input.ABS_HAT3Y: 154 | code -= Linux.Input.ABS_HAT0X; 155 | dpad_event (code / 2, code % 2, ev.value); 156 | break; 157 | default: 158 | var axis = abs_map[code]; 159 | axis_event (axis, (double) ev.value / abs_info[axis].maximum); 160 | break; 161 | } 162 | break; 163 | } 164 | } 165 | } 166 | 167 | private void handle_gudev_event (string action, GUdev.Device gudev_dev) { 168 | if (action == "remove" && gudev_dev.get_device_file () == identifier) { 169 | remove_event_source (); 170 | unplugged (); 171 | } 172 | } 173 | 174 | private void remove_event_source () { 175 | if (event_source_id == null) 176 | return; 177 | 178 | Source.remove (event_source_id); 179 | event_source_id = null; 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /src/Services/libgamepad/gamepad-monitor.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Megh Parikh 3 | * 4 | * This file is part of LibGamepad. 5 | * 6 | * LibGamepad is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * LibGamepad is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with Foobar. If not, see . 18 | */ 19 | 20 | /** 21 | * This class provides a way to the client to monitor gamepads 22 | * 23 | * The client interfaces with this class primarily 24 | */ 25 | public class LibGamepad.GamepadMonitor : Object { 26 | /** 27 | * Emitted when a gamepad is plugged in 28 | * @param gamepad The gamepad 29 | */ 30 | public signal void gamepad_plugged (Gamepad gamepad); 31 | 32 | /** 33 | * Emitted when a gamepad is unplugged 34 | * @param identifier The identifier of the unplugged gamepad 35 | * @param guid The guid of the unplugged gamepad 36 | * @param name The name of the unplugged gamepad 37 | */ 38 | public signal void gamepad_unplugged (string identifier, string guid, string? name); 39 | 40 | public delegate void GamepadCallback (Gamepad gamepad); 41 | 42 | private static HashTable identifier_to_raw_gamepad; 43 | private static HashTable guid_to_raw_name; 44 | 45 | /** 46 | * The number of plugged in gamepads 47 | */ 48 | public uint gamepads_number { get; private set; default = 0; } 49 | 50 | private RawGamepadMonitor raw_gamepad_monitor; 51 | 52 | public GamepadMonitor () { 53 | init_static_if_not (); 54 | 55 | raw_gamepad_monitor = new LinuxRawGamepadMonitor (); 56 | 57 | raw_gamepad_monitor.gamepad_plugged.connect (on_raw_gamepad_plugged); 58 | raw_gamepad_monitor.gamepad_unplugged.connect (on_raw_gamepad_unplugged); 59 | 60 | raw_gamepad_monitor.foreach_gamepad ((raw_gamepad) => { 61 | add_gamepad (raw_gamepad); 62 | }); 63 | 64 | } 65 | 66 | /** 67 | * This static function returns a raw gamepad given a guid. It can be used 68 | * for creating interfaces for remappable-controls. 69 | * @param identifier The identifier of the raw gamepad that you want 70 | */ 71 | public static RawGamepad? get_raw_gamepad (string identifier) { 72 | init_static_if_not (); 73 | 74 | if (identifier == null) 75 | return null; 76 | else 77 | return identifier_to_raw_gamepad.get (identifier); 78 | } 79 | 80 | private static void init_static_if_not () { 81 | if (identifier_to_raw_gamepad == null) 82 | identifier_to_raw_gamepad = new HashTable (str_hash, str_equal); 83 | if (guid_to_raw_name == null) 84 | guid_to_raw_name = new HashTable (str_hash, str_equal); 85 | } 86 | 87 | /** 88 | * This function allows to iterate over all gamepads 89 | * @param callback The callback 90 | */ 91 | public void foreach_gamepad (GamepadCallback callback) { 92 | identifier_to_raw_gamepad.foreach ((identifier, raw_gamepad) => { 93 | callback (new Gamepad (raw_gamepad)); 94 | }); 95 | } 96 | 97 | private void add_gamepad (RawGamepad raw_gamepad) { 98 | gamepads_number++; 99 | identifier_to_raw_gamepad.replace (raw_gamepad.identifier, raw_gamepad); 100 | guid_to_raw_name.replace (raw_gamepad.guid.to_string (), raw_gamepad.name); 101 | } 102 | 103 | private void on_raw_gamepad_plugged (RawGamepad raw_gamepad) { 104 | add_gamepad (raw_gamepad); 105 | gamepad_plugged (new Gamepad (raw_gamepad)); 106 | } 107 | 108 | private void on_raw_gamepad_unplugged (string identifier) { 109 | var raw_gamepad = identifier_to_raw_gamepad.get (identifier); 110 | if (raw_gamepad == null) 111 | return; 112 | gamepads_number--; 113 | guid_to_raw_name.remove (raw_gamepad.guid.to_string ()); 114 | gamepad_unplugged (raw_gamepad.identifier, raw_gamepad.guid, raw_gamepad.name); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/Services/libgamepad/gamepad.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Felipe Escoto 3 | * 2016 Megh Parikh 4 | * 5 | * 6 | * This file is part of LibGamepad. 7 | * 8 | * LibGamepad is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU Lesser General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * LibGamepad is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public License 19 | * along with Foobar. If not, see . 20 | */ 21 | 22 | /** 23 | * This class represents a simplified gamepad 24 | * 25 | * The client interfaces with this class primarily 26 | */ 27 | public class LibGamepad.Gamepad : Object { 28 | /** 29 | * Emitted when a button is pressed 30 | * @param button The button pressed 31 | */ 32 | public signal void button_event (int button); 33 | 34 | /** 35 | * Emitted when the gamepad is unplugged 36 | */ 37 | public signal void unplugged (); 38 | 39 | 40 | /** 41 | * The raw name reported by the driver 42 | */ 43 | public string? raw_name { get; private set; } 44 | 45 | /** 46 | * The guid 47 | */ 48 | public string? guid { get; private set; } 49 | 50 | /** 51 | * The raw gamepad behind this gamepad 52 | */ 53 | public RawGamepad raw_gamepad { get; private set; } 54 | 55 | public Gamepad (RawGamepad raw_gamepad) { 56 | this.raw_gamepad = raw_gamepad; 57 | raw_name = raw_gamepad.name; 58 | guid = raw_gamepad.guid; 59 | 60 | raw_gamepad.button_event.connect (on_raw_button_event); 61 | //raw_gamepad.axis_event.connect (on_raw_axis_event); 62 | //raw_gamepad.dpad_event.connect (on_raw_dpad_event); 63 | 64 | raw_gamepad.unplugged.connect (() => unplugged ()); 65 | } 66 | 67 | Gee.HashSet pressed_buttons = new Gee.HashSet(); 68 | private void on_raw_button_event (int button, bool value) { 69 | if (value && !pressed_buttons.contains (button)) { 70 | pressed_buttons.add (button); 71 | debug ("Raw button pressed event: %d", button); 72 | button_event (button); 73 | } else if (!value) { 74 | pressed_buttons.remove (button); 75 | debug ("Raw button released event: %d", button); 76 | } 77 | } 78 | /* 79 | private void on_raw_axis_event (int axis, double value) { 80 | debug ("On raw axis event: %d %s", axis, value.to_string ()); 81 | 82 | //mapping.get_axis_mapping (axis, out type, out output_axis, out output_button); 83 | //emit_event (type, output_axis, output_button, value); 84 | } 85 | 86 | private void on_raw_dpad_event (int dpad_index, int axis, int value) { 87 | InputType type; 88 | StandardGamepadAxis output_axis; 89 | StandardGamepadButton output_button; 90 | 91 | mapping.get_dpad_mapping (dpad_index, axis, value, out type, out output_axis, out output_button); 92 | emit_event (type, output_axis, output_button, value.abs ()); 93 | } 94 | 95 | private void emit_event (InputType type, StandardGamepadAxis axis, StandardGamepadButton button, double value) { 96 | switch (type) { 97 | case InputType.AXIS: 98 | axis_event (axis, value); 99 | break; 100 | case InputType.BUTTON: 101 | button_event (button, (bool) value); 102 | break; 103 | }*/ 104 | 105 | } 106 | -------------------------------------------------------------------------------- /src/Services/libgamepad/helpers.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Megh Parikh 3 | * 4 | * This file is part of LibGamepad. 5 | * 6 | * LibGamepad is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * LibGamepad is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with Foobar. If not, see . 18 | */ 19 | 20 | namespace LibGamepad { 21 | private const int GUID_LENGTH = 8; 22 | 23 | private string uint16s_to_hex_string (uint16[] data) 24 | requires (data.length == GUID_LENGTH) 25 | { 26 | const string k_rgchHexToASCII = "0123456789abcdef"; 27 | 28 | var builder = new StringBuilder (); 29 | for (var i = 0; i < GUID_LENGTH; i++) { 30 | uint8 c = (uint8) data[i]; 31 | builder.append_unichar (k_rgchHexToASCII[c >> 4]); 32 | builder.append_unichar (k_rgchHexToASCII[c & 0x0F]); 33 | 34 | c = (uint8) (data[i] >> 8); 35 | builder.append_unichar (k_rgchHexToASCII[c >> 4]); 36 | builder.append_unichar (k_rgchHexToASCII[c & 0x0F]); 37 | } 38 | return builder.str; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Services/libgamepad/input-type.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Megh Parikh 3 | * 4 | * This file is part of LibGamepad. 5 | * 6 | * LibGamepad is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * LibGamepad is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with Foobar. If not, see . 18 | */ 19 | 20 | public enum LibGamepad.InputType { 21 | AXIS, 22 | BUTTON, 23 | INVALID; 24 | 25 | public static uint length () { 26 | return InputType.INVALID + 1; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Services/libgamepad/libgamepad.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Megh Parikh 3 | * 4 | * This file is part of LibGamepad. 5 | * 6 | * LibGamepad is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * LibGamepad is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with Foobar. If not, see . 18 | */ 19 | 20 | // Just a blank file so that meson names the generated vapi and header file 21 | // 'libgamepad'. Manually naming them so using vala_args did do that but didnot 22 | // work with declare_dependency, so this simple hack 23 | -------------------------------------------------------------------------------- /src/Services/libgamepad/raw-gamepad-interface.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Megh Parikh 3 | * 4 | * This file is part of LibGamepad. 5 | * 6 | * LibGamepad is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * LibGamepad is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with Foobar. If not, see . 18 | */ 19 | 20 | /** 21 | * This is one of the interfaces that needs to be implemented by the driver. 22 | * 23 | * This interface represents a gamepad and deals with handling events that are 24 | * emitted by a gamepad and also provide properties like name and guid along 25 | * with number of buttons, axes and dpads. 26 | * 27 | * The constructor takes a identifier as a parameter. 28 | * @see RawGamepadMonitor 29 | */ 30 | public interface LibGamepad.RawGamepad : Object { 31 | /** 32 | * Emitted when a button is pressed/released 33 | * @param code The button code from 0 to buttons_number 34 | * @param value True if pressed, False if released 35 | */ 36 | public abstract signal void button_event (int code, bool value); 37 | 38 | /** 39 | * Emitted when an axis's value changes 40 | * @param axis The axis number from 0 to axes_number 41 | * @param value The value of the axis ranging from -1 to 1 42 | */ 43 | public abstract signal void axis_event (int axis, double value); 44 | 45 | /** 46 | * Emitted when a dpad's axis's value changes 47 | * @param dpad The dpad number from 0 to 48 | * @param axis The axis: 0 for X, 1 for Y 49 | * @param value The value of the axis ranging from -1 to 1 50 | */ 51 | public abstract signal void dpad_event (int dpad, int axis, int value); 52 | 53 | /** 54 | * Emitted when the gamepad is unplugged 55 | */ 56 | public abstract signal void unplugged (); 57 | 58 | public abstract string identifier { get; } 59 | public abstract string name { get; } 60 | public abstract string guid { get; } 61 | 62 | /** 63 | * Number of axes of the gamepad 64 | */ 65 | public abstract uint8 axes_number { get; } 66 | 67 | /** 68 | * Number of buttons of the gamepad 69 | */ 70 | public abstract uint8 buttons_number { get; } 71 | 72 | /** 73 | * Number of dpads of the gamepad` 74 | */ 75 | public abstract uint8 dpads_number { get; } 76 | } 77 | -------------------------------------------------------------------------------- /src/Services/libgamepad/raw-gamepad-monitor-interface.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Megh Parikh 3 | * 4 | * This file is part of LibGamepad. 5 | * 6 | * LibGamepad is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * LibGamepad is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with Foobar. If not, see . 18 | */ 19 | 20 | /** 21 | * This is one of the interfaces that needs to be implemented by the driver. 22 | * 23 | * This interface deals with handling events related to plugging and unplugging 24 | * of gamepads and also provides a method to iterate through all the plugged in 25 | * gamepads. An identifier is a string that is easily understood by the driver 26 | * and may depend on other factors, i.e. it may not be unique for the gamepad. 27 | */ 28 | public interface LibGamepad.RawGamepadMonitor : Object { 29 | /** 30 | * This signal should be emmited when a gamepad is plugged in. 31 | * @param raw_gamepad The raw gamepad 32 | */ 33 | public abstract signal void gamepad_plugged (RawGamepad raw_gamepad); 34 | 35 | /** 36 | * This signal should be emitted when a gamepad is unplugged 37 | * 38 | * If an identifier which is not passed with gamepad_plugged even once is passed, 39 | * then it is ignored. Drivers may use this to their benefit 40 | * 41 | * @param identifier The identifier of the unplugged gamepad 42 | */ 43 | public abstract signal void gamepad_unplugged (string identifier); 44 | 45 | public delegate void RawGamepadCallback (RawGamepad raw_gamepad); 46 | 47 | /** 48 | * This function allows to iterate over all gamepads 49 | * @param callback The callback 50 | */ 51 | public abstract void foreach_gamepad (RawGamepadCallback callback); 52 | } 53 | -------------------------------------------------------------------------------- /src/Services/libgamepad/standard-gamepad-axis.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Megh Parikh 3 | * 4 | * This file is part of LibGamepad. 5 | * 6 | * LibGamepad is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * LibGamepad is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with Foobar. If not, see . 18 | */ 19 | 20 | // This file is part of GNOME Games. License: GPLv3 21 | 22 | public enum LibGamepad.StandardGamepadAxis { 23 | /** 24 | * The horizontal axis of the left stick. 25 | * 26 | * Negative is left, positive is right. 27 | */ 28 | LEFT_X, 29 | 30 | /** 31 | * The vertical axis of the left stick. 32 | * 33 | * Negative is up, positive is down. 34 | */ 35 | LEFT_Y, 36 | 37 | /** 38 | * The horizontal axis of the right stick. 39 | * 40 | * Negative is left, positive is right. 41 | */ 42 | RIGHT_X, 43 | 44 | /** 45 | * The vertical axis of the right stick. 46 | * 47 | * Negative is up, positive is down. 48 | */ 49 | RIGHT_Y, 50 | } 51 | -------------------------------------------------------------------------------- /src/Services/libgamepad/standard-gamepad-button.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Megh Parikh 3 | * 4 | * This file is part of LibGamepad. 5 | * 6 | * LibGamepad is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * LibGamepad is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with Foobar. If not, see . 18 | */ 19 | 20 | // This file is part of GNOME Games. License: GPLv3 21 | 22 | public enum LibGamepad.StandardGamepadButton { 23 | /** 24 | * The button at the bottom of the action pad. 25 | */ 26 | A, 27 | 28 | /** 29 | * The button at the right of the action pad. 30 | */ 31 | B, 32 | 33 | /** 34 | * The button at the left of the action pad. 35 | */ 36 | X, 37 | 38 | /** 39 | * The button at the top of the action pad. 40 | */ 41 | Y, 42 | 43 | /** 44 | * The button at the left of the top of the gamepad. 45 | */ 46 | SHOULDER_L, 47 | 48 | /** 49 | * The button at the right of the top of the gamepad. 50 | */ 51 | SHOULDER_R, 52 | 53 | /** 54 | * The trigger at the left of the top of the gamepad. 55 | */ 56 | TRIGGER_L, 57 | 58 | /** 59 | * The trigger at the right of the top of the gamepad. 60 | */ 61 | TRIGGER_R, 62 | 63 | /** 64 | * The button at the left of the menu pad. 65 | */ 66 | SELECT, 67 | 68 | /** 69 | * The button at the right of the menu pad. 70 | */ 71 | START, 72 | 73 | /** 74 | * The button under the left stick. 75 | */ 76 | STICK_L, 77 | 78 | /** 79 | * The button under the right stick. 80 | */ 81 | STICK_R, 82 | 83 | /** 84 | * The button at the top of the directional pad. 85 | */ 86 | DPAD_UP, 87 | 88 | /** 89 | * The button at the bottom of the directional pad. 90 | */ 91 | DPAD_DOWN, 92 | 93 | /** 94 | * The button at the left of the directional pad. 95 | */ 96 | DPAD_LEFT, 97 | 98 | /** 99 | * The button at the right of the directional pad. 100 | */ 101 | DPAD_RIGHT, 102 | 103 | /** 104 | * The button at the center of the menu pad. 105 | */ 106 | HOME, 107 | 108 | /** 109 | * An unknown button 110 | */ 111 | UNKNOWN, 112 | } 113 | -------------------------------------------------------------------------------- /src/Tests/Canvas/CanvasTest.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Felipe Escoto 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 3 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 | * Boston, MA 02111-1307, USA. 18 | * 19 | * Authored by: Felipe Escoto 20 | */ 21 | 22 | void add_tests () { 23 | Test.add_func ("/Canvas/initial", () => { 24 | var item = 25 | load_test ("""{"background-color":"blue", "background-pattern":"pattern" } """); 26 | 27 | item.background_color = "red"; 28 | item.background_pattern = "pattern2"; 29 | saving_test (item); 30 | }); 31 | } 32 | 33 | Spice.Canvas load_test (string raw) { 34 | var json = Spice.Utils.get_json (raw); 35 | var item = new Spice.Canvas (Spice.Application.get_active_spice_window (), json); 36 | 37 | assert (item.background_color == "blue"); 38 | assert (item.background_pattern == "pattern"); 39 | 40 | return item; 41 | } 42 | 43 | void saving_test (Spice.Canvas item) { 44 | var json = Spice.Utils.get_json ("{%s}".printf (item.serialise ())); 45 | 46 | assert (json.get_string_member ("background-color") == "red"); 47 | assert (json.get_string_member ("background-pattern") == "pattern2"); 48 | } 49 | 50 | int main (string[] args) { 51 | Gtk.init (ref args); 52 | Test.init (ref args); 53 | 54 | add_tests (); 55 | return Test.run (); 56 | } 57 | -------------------------------------------------------------------------------- /src/Tests/Canvas/MockedCanvasItem.vala: -------------------------------------------------------------------------------- 1 | public abstract class Spice.CanvasItem : Gtk.EventBox { 2 | public signal void clicked (); 3 | protected signal void un_select (); 4 | 5 | public Json.Object? save_data { get; construct; } 6 | public Canvas canvas { get; set; } 7 | protected Gtk.Grid? grid = null; 8 | 9 | public CanvasItem (Canvas canvas, Json.Object save_data) { 10 | Object (canvas: _canvas, save_data: _save_data); 11 | } 12 | 13 | public void load_data () { 14 | load_item_data (); 15 | } 16 | 17 | public string serialise () { 18 | return "{%s}".printf (serialise_item ()); 19 | } 20 | 21 | protected abstract string serialise_item (); 22 | protected virtual void load_item_data () {} 23 | public new virtual void style () {} 24 | } 25 | -------------------------------------------------------------------------------- /src/Tests/Canvas/TestCommon.vala: -------------------------------------------------------------------------------- 1 | public class Spice.Utils { 2 | public static string last_style = ""; 3 | public static void set_style (Gtk.Widget widget, string str) { 4 | last_style = str; 5 | } 6 | 7 | public static void set_cursor (string type) {} 8 | 9 | public static Json.Object get_json (string data) { 10 | try { 11 | var parser = new Json.Parser (); 12 | parser.load_from_data (data); 13 | 14 | return parser.get_root ().get_object (); 15 | } catch (Error e) { 16 | error ("Invalid json: %s", data); 17 | } 18 | } 19 | } 20 | 21 | namespace Spice { 22 | public Spice.Window window; 23 | } 24 | 25 | public class Spice.Widgets.CanvasToolbar : Gtk.Box { 26 | public static string PATTERNS_DIR = ""; 27 | } 28 | 29 | public class Spice.Application { 30 | public static Spice.Window get_active_spice_window () { 31 | return new Spice.Window (); 32 | } 33 | } 34 | 35 | public class Spice.Window : Gtk.Window { 36 | public bool is_presenting { get; set; default = false; } 37 | public Spice.Services.HistoryManager history_manager { get; set; } 38 | 39 | public Window () { 40 | history_manager = new Spice.Services.HistoryManager (); 41 | } 42 | 43 | static construct { 44 | window = new Spice.Window (); 45 | } 46 | } 47 | 48 | public class Spice.Services.HistoryManager : Object { 49 | public const uint MAX_SIZE = 50; 50 | 51 | public signal void action_called (Spice.CanvasItem? item); 52 | 53 | public signal void undo_changed (bool is_empty); 54 | public signal void redo_changed (bool is_empty); 55 | 56 | public class HistoryAction : Object { 57 | public HistoryAction () {} 58 | 59 | public HistoryAction.item_changed (I item, string property) {} 60 | public HistoryAction.item_moved (I item, Spice.Canvas? canvas = null, bool? value = null) {} 61 | public HistoryAction.depth_changed (I item, Spice.Canvas canvas, bool value) {} 62 | } 63 | 64 | public HistoryManager () { 65 | 66 | } 67 | 68 | public void add_undoable_action (Object a, Value? b = null) { 69 | 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/Tests/Canvas/meson.build: -------------------------------------------------------------------------------- 1 | canvas_test_exec = executable( 2 | 'CanvasTests', 3 | 'CanvasTest.vala', 4 | 'TestCommon.vala', 5 | 6 | meson.source_root() / 'src' / 'Widgets' / 'CanvasItems' / 'Grabber.vala', 7 | meson.source_root() / 'src' / 'Widgets' / 'CanvasItems' / 'CanvasItem.vala', 8 | meson.source_root() / 'src' / 'Widgets' / 'Canvas.vala', 9 | 10 | dependencies : deps, 11 | install: false 12 | ) 13 | 14 | test ('CanvasTests', canvas_test_exec) 15 | -------------------------------------------------------------------------------- /src/Tests/ColorButton/TestCommon.vala: -------------------------------------------------------------------------------- 1 | public class Spice.Utils { 2 | public static string last_style = ""; 3 | public static void set_style (Gtk.Widget widget, string str) { 4 | last_style = str; 5 | } 6 | 7 | public static Json.Object get_json (string data) { 8 | try { 9 | var parser = new Json.Parser (); 10 | parser.load_from_data (data); 11 | 12 | return parser.get_root ().get_object (); 13 | } catch (Error e) { 14 | error ("Invalid json"); 15 | } 16 | } 17 | } 18 | 19 | public class Spice.Canvas : Object { 20 | public signal void ratio_changed (double ratio); 21 | public double current_ratio { get; set; default = 2.0;} 22 | } 23 | -------------------------------------------------------------------------------- /src/Tests/ColorButton/meson.build: -------------------------------------------------------------------------------- 1 | color_button_test_exec = executable( 2 | 'ColorButtonTests', 3 | 'ColorButtonTest.vala', 4 | 'TestCommon.vala', 5 | 6 | meson.source_root() / 'src' / 'Widgets' / 'ColorPicker' / 'ColorButton.vala', 7 | meson.source_root() / 'src' / 'Widgets' / 'ColorPicker' / 'ColorChooser.vala', 8 | meson.source_root() / 'src' / 'Widgets' / 'ColorPicker' / 'Gradient.vala', 9 | meson.source_root() / 'src' / 'Widgets' / 'ColorPicker' / 'GradientEditor.vala', 10 | meson.source_root() / 'src' / 'Widgets' / 'ColorPicker' / 'PickerWindow.vala', 11 | 12 | dependencies : deps, 13 | install: false 14 | ) 15 | 16 | test ('ColorButtonTests', color_button_test_exec) 17 | -------------------------------------------------------------------------------- /src/Tests/ColorItem/ColorItemTest.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Felipe Escoto 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 3 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 | * Boston, MA 02111-1307, USA. 18 | * 19 | * Authored by: Felipe Escoto 20 | */ 21 | 22 | void add_tests () { 23 | Test.add_func ("/ColorItem/InitialVersion", () => { 24 | var item = load_test ("""{ "type": "color", "background_color": "blue" } """); 25 | 26 | assert (item.border_radius == 0); 27 | item.border_radius = 8; 28 | 29 | saving_test (item); 30 | }); 31 | 32 | Test.add_func ("/ColorItem/V2", () => { 33 | var item = load_test ("""{ "type": "color", "background_color": "blue", "border-radius": 8 } """); 34 | 35 | assert (item.border_radius == 8); 36 | 37 | saving_test (item); 38 | }); 39 | } 40 | 41 | Spice.ColorItem load_test (string raw) { 42 | var json = Spice.Utils.get_json (raw); 43 | var item = new Spice.ColorItem (new Spice.Canvas (), json); 44 | 45 | assert (item.background_color == "blue"); 46 | 47 | return item; 48 | } 49 | 50 | void saving_test (Spice.ColorItem item) { 51 | var json = Spice.Utils.get_json (item.serialise ()); 52 | 53 | assert (json.get_string_member ("type") == "color"); 54 | assert (json.get_string_member ("background_color") == "blue"); 55 | assert (json.get_int_member ("border-radius") == 8); 56 | } 57 | 58 | 59 | int main (string[] args) { 60 | Gtk.init (ref args); 61 | Test.init (ref args); 62 | 63 | add_tests (); 64 | return Test.run (); 65 | } 66 | -------------------------------------------------------------------------------- /src/Tests/ColorItem/MockedCanvasItem.vala: -------------------------------------------------------------------------------- 1 | public abstract class Spice.CanvasItem : Gtk.EventBox { 2 | public signal void clicked (); 3 | protected signal void un_select (); 4 | 5 | public Json.Object? save_data { get; construct; } 6 | public Canvas canvas { get; set; } 7 | protected Gtk.Grid? grid = null; 8 | 9 | protected CanvasItem (Canvas canvas, Json.Object save_data) { 10 | Object (canvas: _canvas, save_data: _save_data); 11 | } 12 | 13 | public void load_data () { 14 | load_item_data (); 15 | } 16 | 17 | public string serialise () { 18 | return "{%s}".printf (serialise_item ()); 19 | } 20 | 21 | protected abstract string serialise_item (); 22 | protected virtual void load_item_data () {} 23 | public new virtual void style () {} 24 | } 25 | -------------------------------------------------------------------------------- /src/Tests/ColorItem/TestCommon.vala: -------------------------------------------------------------------------------- 1 | public class Spice.Utils { 2 | public static string last_style = ""; 3 | public static void set_style (Gtk.Widget widget, string str) { 4 | last_style = str; 5 | } 6 | 7 | public static Json.Object get_json (string data) { 8 | try { 9 | var parser = new Json.Parser (); 10 | parser.load_from_data (data); 11 | 12 | return parser.get_root ().get_object (); 13 | } catch (Error e) { 14 | error ("Invalid json"); 15 | } 16 | } 17 | } 18 | 19 | public class Spice.Canvas : Object { 20 | public signal void ratio_changed (double ratio); 21 | public double current_ratio { get; set; default = 2.0;} 22 | } 23 | 24 | public class Spice.Services.HistoryManager : Object { 25 | public const uint MAX_SIZE = 50; 26 | 27 | public signal void action_called (Spice.CanvasItem? item); 28 | 29 | public signal void undo_changed (bool is_empty); 30 | public signal void redo_changed (bool is_empty); 31 | 32 | public class HistoryAction : Object { 33 | public HistoryAction () {} 34 | 35 | public HistoryAction.item_changed (I item, string property) {} 36 | } 37 | 38 | public HistoryManager () { 39 | 40 | } 41 | 42 | public static HistoryManager get_instance () { 43 | return new HistoryManager (); 44 | } 45 | 46 | public void add_undoable_action (Object a, Value b) { 47 | 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Tests/ColorItem/meson.build: -------------------------------------------------------------------------------- 1 | color_item_test_exec = executable( 2 | 'ColorItemTests', 3 | 'ColorItemTest.vala', 4 | 'MockedCanvasItem.vala', 5 | 'TestCommon.vala', 6 | 7 | meson.source_root() / 'src' / 'Widgets' / 'CanvasItems' / 'ColorItem.vala', 8 | 9 | dependencies : deps, 10 | install: false 11 | ) 12 | 13 | test ('ColorItemTests', color_item_test_exec) 14 | -------------------------------------------------------------------------------- /src/Tests/ImageItem/ImageItemTest.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Felipe Escoto 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 3 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 | * Boston, MA 02111-1307, USA. 18 | * 19 | * Authored by: Felipe Escoto 20 | */ 21 | 22 | void add_tests () { 23 | Test.add_func ("/ImageItem/InitialVersion", () => { 24 | var item = load_test ("""{ "type":"image", "image":"file:///home/test/OldImage.jpg" } """); 25 | saving_test (item); 26 | 27 | Spice.ImageHandler.cleanup (); 28 | }); 29 | 30 | Test.add_func ("/ImageItem/V2", () => { 31 | var item = load_test ("""{ "type":"image", "image":"jpg", "image-data":"Base64Data:/home/test/OldImage.jpg" } """); 32 | saving_test (item); 33 | 34 | Spice.ImageHandler.cleanup (); 35 | }); 36 | } 37 | 38 | Spice.ImageItem load_test (string raw) { 39 | var json = Spice.Utils.get_json (raw); 40 | var item = new Spice.ImageItem (new Spice.Canvas (), json); 41 | 42 | assert ("Base64Data:/home/test/OldImage.jpg" == Spice.ImageHandler.base64_image); 43 | 44 | return item; 45 | } 46 | 47 | void saving_test (Spice.ImageItem item) { 48 | var json = Spice.Utils.get_json (item.serialise ()); 49 | 50 | assert (json.get_string_member ("type") == "image"); 51 | assert (json.get_string_member ("image") == "jpg"); 52 | assert (json.get_string_member ("image-data") == "Base64Data:/home/test/OldImage.jpg"); 53 | } 54 | 55 | int main (string[] args) { 56 | Gtk.init (ref args); 57 | Test.init (ref args); 58 | 59 | add_tests (); 60 | return Test.run (); 61 | } 62 | 63 | public class Spice.ImageHandler : Object { 64 | const string FILENAME = "/spice-up-%s-img-%u.%s"; 65 | 66 | public signal void file_changed (); 67 | 68 | public bool valid = false; 69 | public static string? base64_image = null; 70 | 71 | public string image_extension { get; private set; } 72 | 73 | private string url_ = ""; 74 | public string url { 75 | get { 76 | return url_; 77 | } set { 78 | url_ = value; 79 | file_changed (); 80 | } 81 | } 82 | 83 | public static void cleanup () { 84 | base64_image = null; 85 | } 86 | 87 | public ImageHandler.from_data (string _extension, string _base64_data) { 88 | image_extension = _extension != "" ? _extension : "png"; 89 | base64_image = _base64_data; 90 | url = data_to_file (_base64_data); 91 | } 92 | 93 | public ImageHandler.from_file (File file) { 94 | image_extension = get_extension (file.get_basename ()); 95 | data_from_filename (file.get_path ()); 96 | url = data_to_file (base64_image); 97 | } 98 | 99 | public string serialize () { 100 | return """"image":"%s", "image-data":"%s" """.printf (image_extension, base64_image); 101 | } 102 | 103 | private string get_extension (string filename) { 104 | return "jpg"; 105 | } 106 | 107 | private void data_from_filename (string path) { 108 | base64_image = "Base64Data:" + path; 109 | } 110 | 111 | private string data_to_file (string data) { 112 | return "data.file"; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/Tests/ImageItem/MockedCanvasItem.vala: -------------------------------------------------------------------------------- 1 | public abstract class Spice.CanvasItem : Gtk.EventBox { 2 | public signal void clicked (); 3 | protected signal void un_select (); 4 | 5 | public Json.Object? save_data { get; construct; } 6 | public Canvas canvas { get; set; } 7 | protected Gtk.Grid? grid = null; 8 | 9 | protected CanvasItem (Canvas canvas, Json.Object save_data) { 10 | Object (canvas: _canvas, save_data: _save_data); 11 | } 12 | 13 | public void load_data () { 14 | load_item_data (); 15 | } 16 | 17 | public string serialise () { 18 | return "{%s}".printf (serialise_item ()); 19 | } 20 | 21 | protected abstract string serialise_item (); 22 | protected virtual void load_item_data () {} 23 | public new virtual void style () {} 24 | } 25 | -------------------------------------------------------------------------------- /src/Tests/ImageItem/TestCommon.vala: -------------------------------------------------------------------------------- 1 | public class Spice.Utils { 2 | public static string last_style = ""; 3 | public static void set_style (Gtk.Widget widget, string str) { 4 | last_style = str; 5 | } 6 | 7 | public static Json.Object get_json (string data) { 8 | try { 9 | var parser = new Json.Parser (); 10 | parser.load_from_data (data); 11 | 12 | return parser.get_root ().get_object (); 13 | } catch (Error e) { 14 | error ("Invalid json"); 15 | } 16 | } 17 | } 18 | 19 | public class Spice.Canvas : Object { 20 | public signal void ratio_changed (double ratio); 21 | public double current_ratio { get; set; default = 2.0;} 22 | } 23 | 24 | public class Spice.Services.HistoryManager : Object { 25 | public const uint MAX_SIZE = 50; 26 | 27 | public signal void action_called (Spice.CanvasItem? item); 28 | 29 | public signal void undo_changed (bool is_empty); 30 | public signal void redo_changed (bool is_empty); 31 | 32 | public class HistoryAction : Object { 33 | public HistoryAction () {} 34 | 35 | public HistoryAction.item_changed (I item, string property) {} 36 | } 37 | 38 | public HistoryManager () { 39 | 40 | } 41 | 42 | public static HistoryManager get_instance () { 43 | return new HistoryManager (); 44 | } 45 | 46 | public void add_undoable_action (Object a, Value b) { 47 | 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Tests/ImageItem/meson.build: -------------------------------------------------------------------------------- 1 | image_item_test_exec = executable( 2 | 'ImageItemTests', 3 | 'ImageItemTest.vala', 4 | 'MockedCanvasItem.vala', 5 | 'TestCommon.vala', 6 | 7 | meson.source_root() / 'src' / 'Widgets' / 'CanvasItems' / 'ImageItem.vala', 8 | 9 | dependencies : deps, 10 | install: false 11 | ) 12 | 13 | test ('ImageItemTests', image_item_test_exec) 14 | -------------------------------------------------------------------------------- /src/Tests/TextItem/MockedCanvasItem.vala: -------------------------------------------------------------------------------- 1 | public abstract class Spice.CanvasItem : Gtk.EventBox { 2 | public signal void clicked (); 3 | protected signal void un_select (); 4 | 5 | public Json.Object? save_data { get; construct; } 6 | public Canvas canvas { get; set; } 7 | protected Gtk.Grid? grid = null; 8 | 9 | protected CanvasItem (Canvas canvas, Json.Object save_data) { 10 | Object (canvas: _canvas, save_data: _save_data); 11 | } 12 | 13 | public void load_data () { 14 | load_item_data (); 15 | } 16 | 17 | public string serialise () { 18 | return "{%s}".printf (serialise_item ()); 19 | } 20 | 21 | protected abstract string serialise_item (); 22 | protected virtual void load_item_data () {} 23 | public new virtual void style () {} 24 | } 25 | -------------------------------------------------------------------------------- /src/Tests/TextItem/TestCommon.vala: -------------------------------------------------------------------------------- 1 | public class Spice.Utils { 2 | public static string last_style = ""; 3 | public static void set_style (Gtk.Widget widget, string str) { 4 | last_style = str; 5 | } 6 | 7 | public static Json.Object get_json (string data) { 8 | try { 9 | var parser = new Json.Parser (); 10 | parser.load_from_data (data); 11 | 12 | return parser.get_root ().get_object (); 13 | } catch (Error e) { 14 | error ("Invalid json: %s", data); 15 | } 16 | } 17 | } 18 | 19 | public class Spice.Canvas : Object { 20 | public signal void ratio_changed (double ratio); 21 | public double current_ratio { get; set; default = 2.0;} 22 | 23 | public Spice.Window window = new Spice.Window (); 24 | } 25 | 26 | public class Spice.Window : Gtk.Window { 27 | public bool is_presenting { get; set; default = false; } 28 | public Spice.Services.HistoryManager history_manager { get; set; } 29 | 30 | public Window () { 31 | history_manager = new Spice.Services.HistoryManager (); 32 | } 33 | } 34 | 35 | public class Spice.Services.HistoryManager : Object { 36 | public const uint MAX_SIZE = 50; 37 | 38 | public signal void action_called (Spice.CanvasItem? item); 39 | 40 | public signal void undo_changed (bool is_empty); 41 | public signal void redo_changed (bool is_empty); 42 | 43 | public class HistoryAction : Object { 44 | public HistoryAction () {} 45 | 46 | public HistoryAction.item_changed (I item, string property) {} 47 | public HistoryAction.item_moved (I item, Spice.Canvas? canvas = null, bool? value = null) {} 48 | public HistoryAction.depth_changed (I item, Spice.Canvas canvas, bool value) {} 49 | } 50 | 51 | public HistoryManager () { 52 | 53 | } 54 | 55 | public void add_undoable_action (Object a, Value? b = null) { 56 | 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Tests/TextItem/TextItemTest.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Felipe Escoto 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 3 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 | * Boston, MA 02111-1307, USA. 18 | * 19 | * Authored by: Felipe Escoto 20 | */ 21 | 22 | const string RGBA = "rgba(255,0,25,0.65432)"; 23 | 24 | void add_tests () { 25 | 26 | Test.add_func ("/TextItem/initial", () => { 27 | var item = 28 | load_test ("""{"type":"text", 29 | "text": "The Title", 30 | "font": "raleway", 31 | "color": "#fff", 32 | "font-size": 50 } 33 | """); 34 | 35 | assert (item.align == 1); 36 | saving_test (item); 37 | }); 38 | 39 | Test.add_func ("/TextItem/With-FontStyle", () => { 40 | var item = 41 | load_test ("""{"type":"text", 42 | "text": "The Title", 43 | "font": "raleway", 44 | "color": "#fff", 45 | "font-size": 50, 46 | "font-style":"Regular"} 47 | """); 48 | saving_test (item); 49 | }); 50 | 51 | Test.add_func ("/TextItem/WithJustification", () => { 52 | var item = 53 | load_test ("""{"type":"text", 54 | "text": "The Title", 55 | "font": "raleway", 56 | "color": "#fff", 57 | "font-size": 50, 58 | "font-style":"Regular", 59 | "justification": 1 } 60 | """); 61 | saving_test (item); 62 | }); 63 | 64 | Test.add_func ("/TextItem/WithBase64Text", () => { 65 | var item = 66 | load_test ("""{"type":"text", 67 | "text": "", 68 | "text-data" : "VGhlIFRpdGxl", 69 | "font": "raleway", 70 | "color": "#fff", 71 | "font-size": 50, 72 | "font-style":"Regular", 73 | "justification": 1 } 74 | """); 75 | saving_test (item); 76 | }); 77 | 78 | Test.add_func ("/TextItem/RGBAColor", () => { 79 | var item = 80 | load_test ("""{"type":"text", 81 | "text": "", 82 | "text-data" : "VGhlIFRpdGxl", 83 | "font": "raleway", 84 | "color": "rgba(255,0,25,0.65432)", 85 | "font-size": 50, 86 | "font-style":"Regular", 87 | "justification": 1 } 88 | """, RGBA); 89 | 90 | saving_test (item, RGBA); 91 | }); 92 | 93 | Test.add_func ("/TextItem/VerticalAlignment", () => { 94 | var item = 95 | load_test ("""{"type":"text", 96 | "text": "", 97 | "text-data" : "VGhlIFRpdGxl", 98 | "font": "raleway", 99 | "color": "rgba(255,0,25,0.65432)", 100 | "font-size": 50, 101 | "font-style":"Regular", 102 | "justification": 1, 103 | "align": 2} 104 | """, RGBA); 105 | 106 | assert (item.align == 2); 107 | 108 | saving_test (item, RGBA, 2); 109 | }); 110 | } 111 | 112 | Spice.TextItem load_test (string raw, string color = "#fff") { 113 | var json = Spice.Utils.get_json (raw); 114 | var item = new Spice.TextItem (new Spice.Canvas (), json); 115 | 116 | assert (item.text == "The Title"); 117 | assert (item.font_color == color); 118 | assert (item.font_size == 50); 119 | assert (item.font_style == "Regular"); 120 | assert (item.justification == 1); 121 | 122 | return item; 123 | } 124 | 125 | void saving_test (Spice.TextItem item, string color = "#fff", int align = 1) { 126 | var json = Spice.Utils.get_json (item.serialise ()); 127 | assert (json.get_string_member ("text") == ""); 128 | assert (json.get_string_member ("text-data") == "VGhlIFRpdGxl"); 129 | assert (json.get_string_member ("font") == "raleway"); 130 | assert (json.get_string_member ("color") == color); 131 | assert (json.get_int_member ("font-size") == 50); 132 | assert (json.get_string_member ("font-style") == "Regular"); 133 | assert (json.get_int_member ("justification") == 1); 134 | assert (json.get_int_member ("align") == align); 135 | } 136 | 137 | int main (string[] args) { 138 | Gtk.init (ref args); 139 | Test.init (ref args); 140 | 141 | add_tests (); 142 | return Test.run (); 143 | } 144 | -------------------------------------------------------------------------------- /src/Tests/TextItem/meson.build: -------------------------------------------------------------------------------- 1 | text_item_test_exec = executable( 2 | 'TextItemTests', 3 | 'TextItemTest.vala', 4 | 'MockedCanvasItem.vala', 5 | 'TestCommon.vala', 6 | 7 | meson.source_root() / 'src' / 'Widgets' / 'CanvasItems' / 'TextItem.vala', 8 | 9 | dependencies : deps, 10 | install: false 11 | ) 12 | 13 | test ('TextItemTests', text_item_test_exec) 14 | -------------------------------------------------------------------------------- /src/Tests/meson.build: -------------------------------------------------------------------------------- 1 | subdir('Canvas') 2 | subdir('ColorButton') 3 | subdir('ColorItem') 4 | subdir('ImageItem') 5 | subdir('TextItem') 6 | -------------------------------------------------------------------------------- /src/Widgets/CanvasItems/ColorItem.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Felipe Escoto (https://github.com/Philip-Scott/Spice-up) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 | * Boston, MA 02111-1307, USA. 18 | * 19 | * Authored by: Felipe Escoto 20 | */ 21 | 22 | public class Spice.ColorItem : Spice.CanvasItem { 23 | public string background_color {get; set; default = "linear-gradient(to bottom, #e00 0%, #e00 100%);"; } 24 | public int border_radius {get; set; default = 0; } 25 | 26 | const string TEXT_STYLE_CSS = """ 27 | .colored { 28 | background: %s; 29 | border-radius: %d%; 30 | } 31 | """; 32 | 33 | public ColorItem (Canvas? _canvas, Json.Object? _save_data = null) { 34 | Object (canvas: _canvas, save_data: _save_data); 35 | load_data (); 36 | 37 | if (canvas != null) style (); 38 | } 39 | 40 | protected override string serialise_item () { 41 | string data = """ "type": "color", "background_color": "%s", "border-radius": %d """.printf (background_color, border_radius); 42 | 43 | return data; 44 | } 45 | 46 | protected override void load_item_data () { 47 | background_color = save_data.get_string_member ("background_color"); 48 | 49 | if (save_data.has_member ("border-radius")) { 50 | border_radius = (int) save_data.get_int_member ("border-radius"); 51 | } 52 | } 53 | 54 | public override void style () { 55 | Utils.set_style (this, TEXT_STYLE_CSS.printf (background_color, border_radius)); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Widgets/CanvasItems/Grabber.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Felipe Escoto (https://github.com/Philip-Scott/Spice-up) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 | * Boston, MA 02111-1307, USA. 18 | * 19 | * Authored by: Felipe Escoto 20 | */ 21 | 22 | public class Spice.Grabber : Gtk.Button { 23 | public signal void grabbed (Gdk.EventButton event, int id); 24 | public signal void grabbed_motion (Gdk.EventMotion event); 25 | public signal void grabbed_stoped (Gdk.EventButton event); 26 | 27 | private int id; 28 | 29 | public bool make_visible { 30 | set { 31 | visible = value; 32 | no_show_all = !value; 33 | show_all (); 34 | } 35 | } 36 | 37 | public Grabber (int id) { 38 | this.id = id; 39 | events |= Gdk.EventMask.BUTTON_PRESS_MASK; 40 | events |= Gdk.EventMask.BUTTON_RELEASE_MASK; 41 | events |= Gdk.EventMask.POINTER_MOTION_MASK; 42 | 43 | get_style_context ().remove_class ("button"); 44 | get_style_context ().add_class ("flat"); 45 | get_style_context ().add_class ("padding-none"); 46 | 47 | var image = new Gtk.Image.from_resource ("/com/github/philip-scott/spice-up/drag.svg"); 48 | this.add (image); 49 | 50 | make_visible = false; 51 | } 52 | 53 | public override bool draw (Cairo.Context ctx) { 54 | if (Spice.Application.get_active_spice_window ().is_presenting || Canvas.drawing_preview) return false; 55 | 56 | return base.draw (ctx); 57 | } 58 | 59 | 60 | public override bool button_press_event (Gdk.EventButton event) { 61 | grabbed (event, id); 62 | return true; 63 | } 64 | 65 | public override bool button_release_event (Gdk.EventButton event) { 66 | grabbed_stoped (event); 67 | return true; 68 | } 69 | 70 | public override bool motion_notify_event (Gdk.EventMotion event) { 71 | grabbed_motion (event); 72 | return true; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/Widgets/CanvasItems/ImageItem.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Felipe Escoto (https://github.com/Philip-Scott/Spice-up) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 | * Boston, MA 02111-1307, USA. 18 | * 19 | * Authored by: Felipe Escoto 20 | */ 21 | 22 | public class Spice.ImageItem : Spice.CanvasItem { 23 | public ImageHandler image { get; private set; } 24 | 25 | const string IMAGE_STYLE_CSS = """ 26 | .colored { 27 | background-color: transparent; 28 | background-image: url("%s"); 29 | background-position: center; 30 | background-size: contain; 31 | background-repeat: no-repeat; 32 | border: none; 33 | } 34 | """; 35 | 36 | const string IMAGE_MISSING_CSS = """ 37 | .colored { 38 | border: 4px dashed #000000; 39 | border-color: #c92e34; 40 | }"""; 41 | 42 | public string extension { 43 | get { 44 | return image.image_extension; 45 | } 46 | } 47 | 48 | public string url { 49 | get { 50 | return image.url; 51 | } 52 | } 53 | 54 | public ImageItem (Canvas? _canvas, Json.Object? _save_data = null) { 55 | Object (canvas: _canvas, save_data: _save_data); 56 | 57 | load_data (); 58 | 59 | if (canvas != null) style (); 60 | } 61 | 62 | public ImageItem.from_file (Canvas? _canvas, File file) { 63 | Object (canvas: _canvas, save_data: null); 64 | 65 | this.image = new ImageHandler.from_file (file); 66 | connect_image (); 67 | 68 | if (canvas != null) style (); 69 | } 70 | 71 | public ImageItem.from_data (Canvas? _canvas, string base64_image, string extension) { 72 | Object (canvas: _canvas, save_data: null); 73 | 74 | this.image = new ImageHandler.from_data (extension, base64_image); 75 | connect_image (); 76 | 77 | if (canvas != null) style (); 78 | } 79 | 80 | protected override void load_item_data () { 81 | string? base64_image = null; 82 | 83 | if (save_data.has_member ("image-data")) { 84 | base64_image = save_data.get_string_member ("image-data"); 85 | } 86 | 87 | if (base64_image != null && base64_image != "") { 88 | var extension = save_data.get_string_member ("image"); 89 | image = new ImageHandler.from_data (extension, base64_image); 90 | } else { 91 | var tmp_uri = save_data.get_string_member ("image"); 92 | image = new ImageHandler.from_file (File.new_for_uri (tmp_uri)); 93 | } 94 | 95 | connect_image (); 96 | } 97 | 98 | protected override string serialise_item () { 99 | return """"type":"image", %s""".printf (image.serialize ()); 100 | } 101 | 102 | public override void style () { 103 | if (image.valid) { 104 | Utils.set_style (this, IMAGE_STYLE_CSS.printf (image.url)); 105 | } else { 106 | unstyle (); 107 | } 108 | } 109 | 110 | private void unstyle () { 111 | Utils.set_style (this, IMAGE_MISSING_CSS); 112 | } 113 | 114 | private void connect_image () { 115 | image.file_changed.connect (() => { 116 | unstyle (); 117 | style (); 118 | }); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/Widgets/ColorPicker/ColorButton.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Felipe Escoto (https://github.com/Philip-Scott/Spice-up) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 | * Boston, MA 02111-1307, USA. 18 | * 19 | * Authored by: Felipe Escoto 20 | */ 21 | 22 | protected class Spice.ColorButton : Gtk.Button { 23 | protected Gtk.EventBox surface; 24 | protected Gtk.EventBox checkered_bg; 25 | 26 | public string _color = "none"; 27 | public string color { 28 | get { 29 | return _color; 30 | } set { 31 | if (value != "") { 32 | _color = value; 33 | style (); 34 | } 35 | } 36 | } 37 | 38 | public ColorButton (string color) { 39 | Object (color: color); 40 | } 41 | 42 | construct { 43 | surface = new Gtk.EventBox (); 44 | surface.set_size_request (24, 24); 45 | surface.get_style_context ().add_class ("colored"); 46 | get_style_context ().add_class ("color-button"); 47 | Utils.set_style (this, STYLE_CSS); 48 | 49 | checkered_bg = new Gtk.EventBox (); 50 | checkered_bg.get_style_context ().add_class ("checkered"); 51 | Utils.set_style (checkered_bg, CHECKERED_CSS); 52 | 53 | can_focus = false; 54 | add (checkered_bg); 55 | checkered_bg.add (surface); 56 | } 57 | 58 | public void set_size (int x, int y) { 59 | surface.set_size_request (x, y); 60 | } 61 | 62 | public new void style () { 63 | Utils.set_style (surface, SURFACE_STYLE_CSS.printf (_color)); 64 | } 65 | 66 | private const string STYLE_CSS = """ 67 | .color-button.flat { 68 | border: none; 69 | padding: 0; 70 | } 71 | """; 72 | 73 | private const string CHECKERED_CSS = """ 74 | .checkered { 75 | background-image: url('resource:///com/github/philip-scott/spice-up/patterns/ps-neutral.png'); 76 | } 77 | """; 78 | 79 | private const string SURFACE_STYLE_CSS = """ 80 | .colored { 81 | background: %s; 82 | } 83 | 84 | .color-button:active .colored { 85 | opacity: 0.9; 86 | } 87 | 88 | .color-button:focus .colored { 89 | border: 1px solid black; 90 | } 91 | """; 92 | } -------------------------------------------------------------------------------- /src/Widgets/ColorPicker/Gradient.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Felipe Escoto (https://github.com/Philip-Scott/Spice-up) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 | * Boston, MA 02111-1307, USA. 18 | * 19 | * Authored by: Felipe Escoto 20 | */ 21 | 22 | public class Spice.Gradient : Object { 23 | public List steps; 24 | public static Regex color_regex; 25 | public static Regex dir_regex; 26 | 27 | public string direction = "to bottom"; 28 | 29 | static construct { 30 | try { 31 | color_regex = new Regex ( 32 | "(" + // Color Group 33 | """#[a-zA-Z0-9]{6}|""" + // #?????? 34 | """#[a-zA-Z0-9]{3}|""" + // #??? 35 | """rgb\(\s*[0-9]{1,3}\s*,\s*[0-9]{1,3}\s*,\s*[0-9]{1,3}\s*\)|""" + // rgb(?,?,?) 36 | """rgba\(\s*[0-9]{1,3}\s*,\s*[0-9]{1,3}\s*,\s*[0-9]{1,3}\s*,\s*[0-9\.]{1,}\s*\)""" + // rgba(?,?,?,?) 37 | ")" + 38 | """(\s[0-9]{1,}%)?""" // Percent 39 | , 0); 40 | 41 | dir_regex = new Regex ("""gradient\(([a-z0-9\s]{1,}),""", 0); 42 | 43 | } catch (Error e) { 44 | error ("Regex failed: %s", e.message); 45 | } 46 | } 47 | 48 | public Gradient () {} 49 | 50 | public void parse (string gradient) { 51 | steps = new List(); 52 | 53 | if (!gradient.contains ("gradient")) { 54 | steps.append (new GradientStep (gradient, "0%")); 55 | steps.append (new GradientStep (gradient, "100%")); 56 | return; 57 | } 58 | 59 | MatchInfo mi; 60 | if (color_regex.match (gradient, 0 , out mi)) { 61 | int pos_start = 0, pos_end = 0; 62 | 63 | try { 64 | do { 65 | mi.fetch_pos (0, out pos_start, out pos_end); 66 | if (pos_start == pos_end) { 67 | break; 68 | } 69 | var step_color = mi.fetch (1); 70 | var step_percent = mi.fetch (2) != null ? mi.fetch (2) : ""; 71 | 72 | var step = new GradientStep (step_color, step_percent); 73 | steps.append (step); 74 | } while (mi.next ()); 75 | } catch (Error e) { 76 | warning ("Could not find gradient steps: %s", e.message); 77 | return; 78 | } 79 | } 80 | 81 | if (dir_regex.match (gradient, 0 , out mi)) { 82 | int pos_start = 0, pos_end = 0; 83 | 84 | mi.fetch_pos (0, out pos_start, out pos_end); 85 | if (pos_start != pos_end) { 86 | direction = mi.fetch (1); 87 | } 88 | } 89 | } 90 | 91 | public string to_string (bool force_down) { 92 | string colors = ""; 93 | 94 | steps.sort ((_a, _b) => { 95 | var a = int.parse (_a.percent.replace ("%", "")); 96 | var b = int.parse (_b.percent.replace ("%", "")); 97 | return (int) (a > b) - (int) (a < b); 98 | }); 99 | 100 | steps.foreach ((step) => { 101 | colors += ", %s".printf (step.to_string ()); 102 | }); 103 | 104 | string result; 105 | if (force_down) { 106 | result = @"linear-gradient(to bottom$colors)"; 107 | } else { 108 | result = @"linear-gradient($direction$colors)"; 109 | } 110 | 111 | return result; 112 | } 113 | 114 | public GradientStep get_color (int nth) { 115 | return steps.nth_data (nth); 116 | } 117 | 118 | public class GradientStep : Object { 119 | public GradientStep (string _color, string _percent) { 120 | this.color = _color.strip (); 121 | this.percent = _percent.strip (); 122 | } 123 | 124 | public string color { get; set; } 125 | public string percent { get; set; } 126 | 127 | public string to_string () { 128 | return @"$color $percent".strip (); 129 | } 130 | 131 | public bool equals (GradientStep step) { 132 | return this.to_string () == step.to_string (); 133 | } 134 | } 135 | } -------------------------------------------------------------------------------- /src/Widgets/DynamicToolbar.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Felipe Escoto (https://github.com/Philip-Scott/Spice-up) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 | * Boston, MA 02111-1307, USA. 18 | * 19 | * Authored by: Felipe Escoto 20 | */ 21 | 22 | public class Spice.DynamicToolbar : Gtk.Box { 23 | private string TEXT = "text"; 24 | private string IMAGE = "image"; 25 | private string SHAPE = "shape"; 26 | private string CANVAS = "canvas"; 27 | 28 | private SlideManager manager; 29 | private Gtk.Stack stack; 30 | 31 | private Spice.Widgets.Toolbar text_bar; 32 | private Spice.Widgets.Toolbar shape_bar; 33 | private Spice.Widgets.Toolbar image_bar; 34 | private Spice.Widgets.Toolbar canvas_bar; 35 | private Spice.Widgets.Toolbar common_bar; 36 | 37 | public DynamicToolbar (SlideManager slide_manager) { 38 | manager = slide_manager; 39 | 40 | valign = Gtk.Align.START; 41 | 42 | stack = new Gtk.Stack (); 43 | stack.transition_type = Gtk.StackTransitionType.SLIDE_DOWN; 44 | stack.transition_duration = 300; 45 | 46 | get_style_context ().add_class ("toolbar"); 47 | get_style_context ().add_class ("spice-dynamic-toolbar"); 48 | 49 | text_bar = new Spice.Widgets.TextToolbar (slide_manager); 50 | shape_bar = new Spice.Widgets.ShapeToolbar (slide_manager); 51 | image_bar = new Spice.Widgets.ImageToolbar (slide_manager); 52 | canvas_bar = new Spice.Widgets.CanvasToolbar (slide_manager); 53 | common_bar = new Spice.Widgets.CommonToolbar (slide_manager); 54 | 55 | stack.add_named (text_bar, TEXT); 56 | stack.add_named (shape_bar, SHAPE); 57 | stack.add_named (image_bar, IMAGE); 58 | stack.add_named (canvas_bar, CANVAS); 59 | 60 | this.add (stack); 61 | this.add (common_bar); 62 | 63 | slide_manager.window.history_manager.action_called.connect ((i) => { 64 | item_selected (i); 65 | }); 66 | } 67 | 68 | public void item_selected (Spice.CanvasItem? item, bool new_item = false) { 69 | if (item == null) { 70 | stack.set_visible_child_name (CANVAS); 71 | canvas_bar.select_item (item, manager.making_new_slide); 72 | } else if (item is TextItem) { 73 | stack.set_visible_child_name (TEXT); 74 | text_bar.select_item (item, new_item); 75 | } else if (item is ColorItem) { 76 | stack.set_visible_child_name (SHAPE); 77 | shape_bar.select_item (item, new_item); 78 | } else if (item is ImageItem) { 79 | stack.set_visible_child_name (IMAGE); 80 | image_bar.select_item (item, new_item); 81 | } 82 | 83 | common_bar.select_item (item, new_item); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/Widgets/Library/Library.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Felipe Escoto (https://github.com/Philip-Scott/Spice-up) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 | * Boston, MA 02111-1307, USA. 18 | * 19 | * Authored by: Felipe Escoto 20 | */ 21 | 22 | public class Spice.Widgets.Library.Library : Gtk.ScrolledWindow { 23 | private const string RESOURCE_PATH = "resource:///com/github/philip-scott/spice-up/templates/%s"; 24 | private const string TEMPLATES[] = {"Black.spice", "White.spice", "Green.spice", "Spice-Up.spice", "Paper.spice", "Colorful.spice", "Landscape.spice"}; 25 | 26 | public signal void item_selected (string data); 27 | public signal void file_selected (File file); 28 | 29 | private Gtk.FlowBox item_box; 30 | 31 | public Library (string[] files) { 32 | var existing_files = new Array (); 33 | foreach (var path in files) { 34 | var file = File.new_for_path (path); 35 | if (file.query_exists ()) { 36 | add_file (file, true); 37 | existing_files.append_val (path); 38 | } 39 | } 40 | 41 | item_box.max_children_per_line = 2; 42 | item_box.min_children_per_line = 2; 43 | settings.last_files = existing_files.data; 44 | 45 | item_box.child_activated.connect ((child) => { 46 | file_selected ((child as LibraryItem).file); 47 | }); 48 | } 49 | 50 | public Library.for_templates () { 51 | foreach (var file_path in TEMPLATES) { 52 | var file = File.new_for_uri (RESOURCE_PATH.printf (file_path)); 53 | 54 | add_file (file, false); 55 | } 56 | 57 | item_box.min_children_per_line = 2; 58 | 59 | item_box.child_activated.connect ((child) => { 60 | var library_item = child as LibraryItem; 61 | if (library_item == null) return; 62 | 63 | item_selected (library_item.data); 64 | }); 65 | } 66 | 67 | construct { 68 | hscrollbar_policy = Gtk.PolicyType.NEVER; 69 | 70 | item_box = new Gtk.FlowBox (); 71 | 72 | item_box.valign = Gtk.Align.START; 73 | item_box.margin = 12; 74 | item_box.expand = false; 75 | 76 | add (item_box); 77 | } 78 | 79 | public void add_file (File file, bool real_file) { 80 | if (!file.query_exists ()) return; 81 | 82 | var item = new LibraryItem (file, real_file); 83 | item_box.add (item); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/Widgets/PresenterNotes.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Felipe Escoto (https://github.com/Philip-Scott/Spice-up) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 | * Boston, MA 02111-1307, USA. 18 | * 19 | * Authored by: Felipe Escoto 20 | */ 21 | 22 | public class Spice.PresenterNotes : Gtk.Revealer { 23 | public signal void text_changed (string text); 24 | 25 | public Gtk.TextView notes_area {get; construct; } 26 | 27 | private bool setting_text = false; 28 | 29 | public bool notes_focus { 30 | get { 31 | return notes_area.has_focus; 32 | } 33 | } 34 | 35 | construct { 36 | var grid = new Gtk.Grid (); 37 | grid.orientation = Gtk.Orientation.VERTICAL; 38 | 39 | notes_area = new Gtk.TextView (); 40 | notes_area.set_wrap_mode (Gtk.WrapMode.WORD); 41 | notes_area.left_margin = 6; 42 | notes_area.get_style_context ().add_class ("h3"); 43 | notes_area.get_style_context ().add_class ("h4"); 44 | 45 | notes_area.buffer.changed.connect (() => { 46 | if (!setting_text) { 47 | text_changed (notes_area.buffer.text); 48 | } 49 | }); 50 | 51 | var notes_scrolled = new Gtk.ScrolledWindow (null, null); 52 | notes_scrolled.min_content_height = 150; 53 | notes_scrolled.hexpand = true; 54 | notes_scrolled.add (notes_area); 55 | 56 | grid.add (new Gtk.Separator (Gtk.Orientation.HORIZONTAL)); 57 | grid.add (notes_scrolled); 58 | 59 | add (grid); 60 | show_all (); 61 | } 62 | 63 | public void focus_notes () { 64 | notes_area.grab_focus (); 65 | } 66 | 67 | public void set_text (string text) { 68 | setting_text = true; 69 | notes_area.buffer.text = text; 70 | setting_text = false; 71 | } 72 | } -------------------------------------------------------------------------------- /src/Widgets/SlideWidget.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 Felipe Escoto (https://github.com/Philip-Scott/Spice-up) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 | * Boston, MA 02111-1307, USA. 18 | * 19 | * Authored by: Felipe Escoto 20 | */ 21 | 22 | public class Spice.SlideWidget : Gtk.EventBox { 23 | public signal void settings_requested (); 24 | 25 | public Gdk.Pixbuf pixbuf { 26 | set { 27 | this.image.set_from_pixbuf (value); 28 | } 29 | } 30 | 31 | public bool show_button = true; 32 | 33 | private Gtk.Overlay overlay; 34 | private Gtk.Image image; 35 | public Gtk.Revealer settings_revealer; 36 | 37 | public Spice.SlideWidget.from_slide (Slide slide) { 38 | this.overlay.add (slide.preview); 39 | slide.preview.get_style_context ().add_class ("card"); 40 | } 41 | 42 | public SlideWidget () { 43 | image = new Gtk.Image (); 44 | image.get_style_context ().add_class ("card"); 45 | overlay.add (image); 46 | } 47 | 48 | construct { 49 | events |= Gdk.EventMask.ENTER_NOTIFY_MASK & Gdk.EventMask.LEAVE_NOTIFY_MASK; 50 | 51 | overlay = new Gtk.Overlay (); 52 | overlay.margin = 9; 53 | 54 | var settings_button = new Gtk.Button.from_icon_name ("document-properties-symbolic", Gtk.IconSize.BUTTON); 55 | settings_button.events |= Gdk.EventMask.ENTER_NOTIFY_MASK & Gdk.EventMask.LEAVE_NOTIFY_MASK; 56 | settings_button.get_style_context ().add_class ("flat"); 57 | settings_button.get_style_context ().add_class ("icon-shadow"); 58 | settings_button.can_focus = false; 59 | 60 | settings_revealer = new Gtk.Revealer (); 61 | settings_revealer.set_transition_duration (500); 62 | settings_revealer.set_transition_type (Gtk.RevealerTransitionType.CROSSFADE); 63 | settings_revealer.halign = Gtk.Align.START; 64 | settings_revealer.valign = Gtk.Align.START; 65 | settings_revealer.add (settings_button); 66 | 67 | add (overlay); 68 | overlay.add_overlay (settings_revealer); 69 | 70 | settings_button.clicked.connect (() => {settings_requested ();}); 71 | 72 | settings_button.enter_notify_event.connect ((event) => { 73 | settings_revealer.set_reveal_child (this.show_button); 74 | return false; 75 | }); 76 | 77 | enter_notify_event.connect ((event) => { 78 | settings_revealer.set_reveal_child (this.show_button); 79 | return false; 80 | }); 81 | 82 | leave_notify_event.connect ((event) => { 83 | settings_revealer.set_reveal_child (false); 84 | return false; 85 | }); 86 | } 87 | } -------------------------------------------------------------------------------- /src/Widgets/Toolbars/CanvasBar.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Felipe Escoto (https://github.com/Philip-Scott/Spice-up) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 | * Boston, MA 02111-1307, USA. 18 | * 19 | * Authored by: Felipe Escoto 20 | */ 21 | 22 | public class Spice.Widgets.CanvasToolbar : Spice.Widgets.Toolbar { 23 | public const string PATTERNS_DIR = "resource:///com/github/philip-scott/spice-up/patterns/"; 24 | 25 | private Spice.ColorChooser canvas_gradient_background; 26 | private Spice.EntryCombo canvas_pattern; 27 | private Spice.EntryCombo transition; 28 | private unowned SlideManager manager; 29 | 30 | public CanvasToolbar (SlideManager slide_manager) { 31 | this.manager = slide_manager; 32 | } 33 | 34 | construct { 35 | canvas_gradient_background = new Spice.ColorChooser.with_gradient (false); 36 | canvas_gradient_background.set_tooltip_text (_("Background color")); 37 | 38 | canvas_gradient_background.color_picked.connect ((s) => { 39 | if (selecting) return; 40 | var action = new Spice.Services.HistoryManager.HistoryAction.canvas_changed (this.manager.current_slide.canvas, "background-color"); 41 | manager.window.history_manager.add_undoable_action (action); 42 | update_properties (); 43 | }); 44 | 45 | canvas_pattern = new Spice.EntryCombo (true, true); 46 | canvas_pattern.set_tooltip_text (_("Background pattern")); 47 | canvas_pattern.editable = false; 48 | 49 | canvas_pattern.add_entry (PATTERNS_DIR + "3px-tile.png", _("3px tile")); 50 | canvas_pattern.add_entry (PATTERNS_DIR + "45-degree-fabric-dark.png", _("Fabric dark")); 51 | canvas_pattern.add_entry (PATTERNS_DIR + "45-degree-fabric-light.png", _("Fabric light")); 52 | canvas_pattern.add_entry (PATTERNS_DIR + "batthern.png", _("Batthern")); 53 | canvas_pattern.add_entry (PATTERNS_DIR + "beige-paper.png", _("Beige paper")); 54 | canvas_pattern.add_entry (PATTERNS_DIR + "black-linen.png", _("Black linen")); 55 | canvas_pattern.add_entry (PATTERNS_DIR + "bright-squares.png", _("Bright squares")); 56 | canvas_pattern.add_entry (PATTERNS_DIR + "diamond-upholstery.png", _("Diamond Upholstery")); 57 | canvas_pattern.add_entry (PATTERNS_DIR + "flowers.png", _("Flowers")); 58 | canvas_pattern.add_entry (PATTERNS_DIR + "hexellence.png", _("Hexellence")); 59 | canvas_pattern.add_entry (PATTERNS_DIR + "gplay.png", _("Gplay")); 60 | canvas_pattern.add_entry (PATTERNS_DIR + "inspiration-geometry.png", _("Geometry")); 61 | canvas_pattern.add_entry (PATTERNS_DIR + "dark-geometric.png", _("Dark geometric")); 62 | canvas_pattern.add_entry (PATTERNS_DIR + "light-wool.png", _("Light wool")); 63 | canvas_pattern.add_entry (PATTERNS_DIR + "ps-neutral.png", _("Neutral squares")); 64 | canvas_pattern.add_entry (PATTERNS_DIR + "silver-scales.png", _("Silver scales")); 65 | canvas_pattern.add_entry (PATTERNS_DIR + "subtle-freckles.png", _("Subtle grid")); 66 | canvas_pattern.add_entry (PATTERNS_DIR + "subtle-grey.png", _("Subtle squares")); 67 | canvas_pattern.add_entry (PATTERNS_DIR + "xv.png", _("XV")); 68 | canvas_pattern.add_entry ("", _(" None")); 69 | 70 | canvas_pattern.activated.connect (() => { 71 | var action = new Spice.Services.HistoryManager.HistoryAction.canvas_changed (this.manager.current_slide.canvas, "background-pattern"); 72 | manager.window.history_manager.add_undoable_action (action); 73 | update_properties (); 74 | }); 75 | 76 | transition = new Spice.EntryCombo (true, false); 77 | transition.set_tooltip_text (_("Transition")); 78 | transition.editable = false; 79 | 80 | transition.add_entry (((int) Gtk.StackTransitionType.NONE).to_string (), _("No Transition")); 81 | transition.add_entry (((int) Gtk.StackTransitionType.CROSSFADE).to_string (), _("Crossfade")); 82 | transition.add_entry (((int) Gtk.StackTransitionType.SLIDE_RIGHT).to_string (), _("Slide right")); 83 | transition.add_entry (((int) Gtk.StackTransitionType.SLIDE_LEFT).to_string (), _("Slide left")); 84 | transition.add_entry (((int) Gtk.StackTransitionType.SLIDE_UP).to_string (), _("Slide up")); 85 | transition.add_entry (((int) Gtk.StackTransitionType.SLIDE_DOWN).to_string (), _("Slide down")); 86 | transition.add_entry (((int) Gtk.StackTransitionType.OVER_UP).to_string (), _("Cover up")); 87 | transition.add_entry (((int) Gtk.StackTransitionType.OVER_DOWN).to_string (), _("Cover down")); 88 | transition.add_entry (((int) Gtk.StackTransitionType.OVER_LEFT).to_string (), _("Cover left")); 89 | transition.add_entry (((int) Gtk.StackTransitionType.OVER_RIGHT).to_string (), _("Cover right")); 90 | transition.add_entry (((int) Gtk.StackTransitionType.UNDER_UP).to_string (), _("Uncover up")); 91 | transition.add_entry (((int) Gtk.StackTransitionType.UNDER_DOWN).to_string (), _("Uncover down")); 92 | transition.add_entry (((int) Gtk.StackTransitionType.UNDER_LEFT).to_string (), _("Uncover left")); 93 | transition.add_entry (((int) Gtk.StackTransitionType.UNDER_RIGHT).to_string (), _("Uncover right")); 94 | 95 | transition.activated.connect (() => { 96 | var action = new Spice.Services.HistoryManager.HistoryAction.canvas_changed (this.manager.current_slide, "transition"); 97 | manager.window.history_manager.add_undoable_action (action); 98 | update_properties (); 99 | }); 100 | 101 | add (canvas_gradient_background); 102 | add (canvas_pattern); 103 | add (transition); 104 | } 105 | 106 | protected override void item_selected (Spice.CanvasItem? item, bool new_item = false) { 107 | if (new_item) { 108 | update_properties (); 109 | return; 110 | } 111 | 112 | transition.text = ((int) manager.current_slide.transition).to_string (); 113 | canvas_gradient_background.color = manager.current_slide.canvas.background_color; 114 | canvas_pattern.text = manager.current_slide.canvas.background_pattern; 115 | } 116 | 117 | public override void update_properties () { 118 | manager.current_slide.transition = (Gtk.StackTransitionType) int.parse (transition.text); 119 | manager.current_slide.canvas.background_pattern = canvas_pattern.text; 120 | manager.current_slide.canvas.background_color = canvas_gradient_background.color; 121 | manager.current_slide.canvas.style (); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/Widgets/Toolbars/CommonBar.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Felipe Escoto (https://github.com/Philip-Scott/Spice-up) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 | * Boston, MA 02111-1307, USA. 18 | * 19 | * Authored by: Felipe Escoto 20 | */ 21 | 22 | public class Spice.Widgets.CommonToolbar : Spice.Widgets.Toolbar { 23 | public SlideManager manager { get; construct; } 24 | private Gtk.Button to_top; 25 | private Gtk.Button to_bottom; 26 | private Gtk.Button delete_button; 27 | private Gtk.Button clone_button; 28 | 29 | public CommonToolbar (SlideManager slide_manager) { 30 | Object (manager: slide_manager); 31 | } 32 | 33 | construct { 34 | hexpand = true; 35 | halign = Gtk.Align.END; 36 | 37 | delete_button = new Gtk.Button.from_icon_name ("edit-delete-symbolic", Gtk.IconSize.MENU); 38 | delete_button.set_tooltip_markup (Utils.get_accel_tooltip (Window.ACTION_DELETE, _("Delete"))); 39 | delete_button.get_style_context ().add_class (Gtk.STYLE_CLASS_RAISED); 40 | 41 | delete_button.clicked.connect (manager.window.delete_object); 42 | 43 | clone_button = new Gtk.Button.from_icon_name ("edit-copy-symbolic", Gtk.IconSize.MENU); 44 | clone_button.get_style_context ().add_class (Gtk.STYLE_CLASS_RAISED); 45 | clone_button.set_tooltip_markup (Utils.get_accel_tooltip (Window.ACTION_CLONE, _("Clone"))); 46 | 47 | clone_button.clicked.connect (() => { 48 | if (this.item != null) { 49 | Clipboard.duplicate (this.manager, this.item); 50 | } else { 51 | Clipboard.duplicate (this.manager, this.manager.current_slide); 52 | } 53 | }); 54 | 55 | to_top = new Gtk.Button.from_icon_name ("selection-raise-symbolic", Gtk.IconSize.MENU); 56 | to_top.get_style_context ().add_class (Gtk.STYLE_CLASS_RAISED); 57 | to_top.set_tooltip_markup (Utils.get_accel_tooltip (Window.ACTION_BRING_FWD, _("Bring forward"))); 58 | 59 | to_bottom = new Gtk.Button.from_icon_name ("selection-lower-symbolic", Gtk.IconSize.MENU); 60 | to_bottom.get_style_context ().add_class (Gtk.STYLE_CLASS_RAISED); 61 | to_bottom.set_tooltip_markup (Utils.get_accel_tooltip (Window.ACTION_BRING_BWD, _("Send backward"))); 62 | 63 | var position_grid = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); 64 | position_grid.get_style_context ().add_class ("linked"); 65 | position_grid.add (to_top); 66 | position_grid.add (to_bottom); 67 | 68 | to_top.clicked.connect (this.manager.window.action_bring_fwd); 69 | to_bottom.clicked.connect (this.manager.window.action_send_bwd); 70 | 71 | add (position_grid); 72 | add (clone_button); 73 | add (delete_button); 74 | } 75 | 76 | protected override void item_selected (Spice.CanvasItem? item, bool new_item = false) { 77 | 78 | } 79 | 80 | public override void update_properties () { 81 | 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/Widgets/Toolbars/ImageBar.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Felipe Escoto (https://github.com/Philip-Scott/Spice-up) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 | * Boston, MA 02111-1307, USA. 18 | * 19 | * Authored by: Felipe Escoto 20 | */ 21 | 22 | public class Spice.Widgets.ImageToolbar : Spice.Widgets.Toolbar { 23 | private Gtk.Button open_with; 24 | private Gtk.Button replace_image; 25 | 26 | private unowned SlideManager manager; 27 | 28 | public ImageToolbar (SlideManager slide_manager) { 29 | this.manager = slide_manager; 30 | } 31 | 32 | construct { 33 | open_with = new Gtk.Button (); 34 | open_with.add (new Gtk.Image.from_icon_name ("applications-graphics-symbolic", Gtk.IconSize.MENU)); 35 | open_with.set_tooltip_text (_("Edit image with…")); 36 | open_with.get_style_context ().add_class (Gtk.STYLE_CLASS_RAISED); 37 | open_with.get_style_context ().add_class ("image-button"); 38 | 39 | open_with.clicked.connect (() => { 40 | var image_item = (ImageItem) item; 41 | var file = File.new_for_path (image_item.url); 42 | 43 | try { 44 | Gtk.show_uri_on_window(Application.get_active_spice_window (), file.get_uri (), Gdk.CURRENT_TIME); 45 | } catch (Error e) { 46 | warning ("Could not launch open with portal %s", e.message); 47 | return; 48 | } 49 | }); 50 | 51 | replace_image = new Gtk.Button (); 52 | replace_image.add (new Gtk.Image.from_icon_name ("document-new-symbolic", Gtk.IconSize.MENU)); 53 | replace_image.set_tooltip_text (_("Replace Image…")); 54 | replace_image.get_style_context ().add_class (Gtk.STYLE_CLASS_RAISED); 55 | replace_image.get_style_context ().add_class ("image-button"); 56 | 57 | replace_image.clicked.connect (() => { 58 | var file = Spice.Services.FileManager.open_image (); 59 | 60 | if (file != null) { 61 | var image_item = (ImageItem) item; 62 | image_item.image.replace (file); 63 | } 64 | }); 65 | 66 | add (open_with); 67 | add (replace_image); 68 | } 69 | 70 | protected override void item_selected (Spice.CanvasItem? _item, bool new_item = false) {} 71 | 72 | public override void update_properties () {} 73 | } 74 | -------------------------------------------------------------------------------- /src/Widgets/Toolbars/ShapeBar.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Felipe Escoto (https://github.com/Philip-Scott/Spice-up) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 | * Boston, MA 02111-1307, USA. 18 | * 19 | * Authored by: Felipe Escoto 20 | */ 21 | 22 | public class Spice.Widgets.ShapeToolbar : Spice.Widgets.Toolbar { 23 | private Spice.ColorChooser background_color_button; 24 | private Gtk.Scale border_radius; 25 | 26 | private unowned SlideManager manager; 27 | 28 | public ShapeToolbar (SlideManager slide_manager) { 29 | this.manager = slide_manager; 30 | } 31 | 32 | construct { 33 | border_radius = new Gtk.Scale.with_range (Gtk.Orientation.HORIZONTAL, 0.0, 50.0, 1); 34 | border_radius.get_style_context ().add_class ("spice-scale"); 35 | border_radius.add_mark (0.0, Gtk.PositionType.BOTTOM, _("Square")); 36 | border_radius.add_mark (50.0, Gtk.PositionType.BOTTOM, _("Circle")); 37 | border_radius.width_request = 200; 38 | border_radius.draw_value = false; 39 | border_radius.margin = 12; 40 | 41 | var border_radius_button = new Gtk.Button.from_icon_name ("applications-engineering-symbolic", Gtk.IconSize.MENU); 42 | border_radius_button.get_style_context ().add_class (Gtk.STYLE_CLASS_RAISED); 43 | border_radius_button.set_tooltip_text (_("Roundness")); 44 | 45 | var border_radius_popover = new Gtk.Popover (border_radius_button); 46 | border_radius_popover.position = Gtk.PositionType.BOTTOM; 47 | 48 | border_radius_popover.add (border_radius); 49 | 50 | border_radius_button.clicked.connect (() => { 51 | border_radius_popover.show (); 52 | border_radius_popover.show_all (); 53 | }); 54 | 55 | border_radius.value_changed.connect (() => { 56 | var action = new Spice.Services.HistoryManager.HistoryAction.item_changed (this.item as ColorItem, "border-radius"); 57 | manager.window.history_manager.add_undoable_action (action); 58 | update_properties (); 59 | }); 60 | 61 | background_color_button = new Spice.ColorChooser.with_gradient (); 62 | background_color_button.set_tooltip_text (_("Shape color")); 63 | 64 | background_color_button.color_picked.connect ((color) => { 65 | var action = new Spice.Services.HistoryManager.HistoryAction.item_changed (this.item as ColorItem, "background-color"); 66 | manager.window.history_manager.add_undoable_action (action); 67 | update_properties (); 68 | }); 69 | 70 | add (background_color_button); 71 | add (border_radius_button); 72 | } 73 | 74 | protected override void item_selected (Spice.CanvasItem? _item, bool new_item = false) { 75 | if (new_item) { 76 | update_properties (); 77 | return; 78 | } 79 | var item = _item as ColorItem; 80 | 81 | background_color_button.color = item.background_color; 82 | border_radius.set_value (item.border_radius); 83 | } 84 | 85 | public override void update_properties () { 86 | ColorItem color = (ColorItem) item; 87 | color.background_color = background_color_button.color; 88 | 89 | color.border_radius = (int) border_radius.get_value (); 90 | 91 | item.style (); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/Widgets/Toolbars/Toolbar.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Felipe Escoto (https://github.com/Philip-Scott/Spice-up) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 | * Boston, MA 02111-1307, USA. 18 | * 19 | * Authored by: Felipe Escoto 20 | */ 21 | 22 | public abstract class Spice.Widgets.Toolbar : Gtk.Box { 23 | protected bool init = false; 24 | protected bool selecting = false; 25 | protected Spice.CanvasItem? item; 26 | 27 | construct { 28 | orientation = Gtk.Orientation.HORIZONTAL; 29 | spacing = 12; 30 | border_width = 6; 31 | } 32 | 33 | public void select_item (Spice.CanvasItem? item_, bool new_item = false) { 34 | selecting = true; 35 | item = item_; 36 | item_selected (item_, new_item && init); 37 | selecting = false; 38 | init = true; 39 | } 40 | 41 | protected abstract void item_selected (Spice.CanvasItem? item, bool new_item = false); 42 | 43 | public abstract void update_properties (); 44 | } 45 | -------------------------------------------------------------------------------- /src/Widgets/Welcome.vala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018 Felipe Escoto (https://github.com/Philip-Scott/Spice-up) 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public 15 | * License along with this program; if not, write to the 16 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 | * Boston, MA 02111-1307, USA. 18 | * 19 | * Authored by: Felipe Escoto 20 | */ 21 | 22 | public class Spice.Welcome : Gtk.Box { 23 | private const string TEMPLATES_URL = "https://spice-up-dev.azurewebsites.net/api/get-templates"; 24 | 25 | public signal void open_file (File file); 26 | 27 | private Granite.Widgets.Welcome welcome; 28 | private Spice.Widgets.Library.Library? library = null; 29 | private Spice.Widgets.Library.Library? templates = null; 30 | private Gtk.Separator separator; 31 | private Gtk.Stack welcome_stack; 32 | 33 | public Welcome () { 34 | orientation = Gtk.Orientation.HORIZONTAL; 35 | get_style_context ().add_class ("view"); 36 | 37 | width_request = 950; 38 | height_request = 500; 39 | 40 | welcome = new Granite.Widgets.Welcome ("Spice-Up", _("Make a Simple Presentation")); 41 | welcome.hexpand = true; 42 | 43 | welcome.append ("document-new", _("New Presentation"), _("Create a new presentation")); 44 | welcome.append ("folder-open", _("Open File"), _("Open a saved presentation")); 45 | 46 | separator = new Gtk.Separator (Gtk.Orientation.VERTICAL); 47 | 48 | welcome_stack = new Gtk.Stack (); 49 | welcome_stack.add_named (welcome, "welcome"); 50 | welcome_stack.set_visible_child (welcome); 51 | 52 | add (welcome_stack); 53 | add (separator); 54 | 55 | welcome.activated.connect ((index) => { 56 | switch (index) { 57 | case 0: 58 | show_templates (); 59 | break; 60 | case 1: 61 | var file = Spice.Services.FileManager.open_presentation (); 62 | if (file != null) open_file (file); 63 | break; 64 | } 65 | }); 66 | } 67 | 68 | public void show_templates () { 69 | if (templates == null) { 70 | templates = new Spice.Widgets.Library.Library.for_templates (); 71 | welcome_stack.add_named (templates, "templates"); 72 | welcome_stack.show_all (); 73 | 74 | templates.item_selected.connect ((data) => { 75 | var file = Spice.Services.FileManager.new_presentation (data); 76 | if (file != null) { 77 | open_file (file); 78 | } 79 | }); 80 | } 81 | 82 | welcome_stack.set_visible_child_full ("templates", Gtk.StackTransitionType.SLIDE_RIGHT); 83 | } 84 | 85 | public void reload () { 86 | var files = settings.last_files; 87 | welcome_stack.set_visible_child_full ("welcome", Gtk.StackTransitionType.NONE); 88 | 89 | if (library != null) { 90 | remove (library); 91 | library.destroy (); 92 | library = null; 93 | } 94 | 95 | if (files.length > 0 && Granite.Services.System.history_is_enabled ()) { 96 | library = new Spice.Widgets.Library.Library (files); 97 | add (library); 98 | 99 | library.file_selected.connect ((file) => { 100 | open_file (file); 101 | }); 102 | 103 | separator.visible = true; 104 | separator.no_show_all = false; 105 | 106 | this.show_all (); 107 | } else { 108 | separator.visible = false; 109 | separator.no_show_all = true; 110 | } 111 | } 112 | } -------------------------------------------------------------------------------- /src/config.vala.in: -------------------------------------------------------------------------------- 1 | namespace Constants { 2 | public const string GETTEXT_PACKAGE = @GETTEXT_PACKAGE@; 3 | } 4 | -------------------------------------------------------------------------------- /src/meson.build: -------------------------------------------------------------------------------- 1 | config_data = configuration_data() 2 | config_data.set_quoted('GETTEXT_PACKAGE', meson.project_name()) 3 | config_file = configure_file( 4 | input: 'config.vala.in', 5 | output: '@BASENAME@', 6 | configuration: config_data 7 | ) 8 | 9 | vala_files = [ 10 | 'Application.vala', 11 | 'Window.vala', 12 | 13 | 'Services' / 'Clipboard.vala', 14 | 'Services' / 'Settings.vala', 15 | 'Services' / 'Slide.vala', 16 | 'Services' / 'SlideManager.vala', 17 | 'Services' / 'FileManager.vala', 18 | 'Services' / 'HistoryManager.vala', 19 | 'Services' / 'ImageHandler.vala', 20 | 'Services' / 'Utils.vala', 21 | 'Services' / 'GamepadSlideController.vala', 22 | 23 | 'Widgets' / 'Canvas.vala', 24 | 'Widgets' / 'EntryCombo.vala', 25 | 'Widgets' / 'Headerbar.vala', 26 | 'Widgets' / 'SlideList.vala', 27 | 'Widgets' / 'DynamicToolbar.vala', 28 | 'Widgets' / 'Welcome.vala', 29 | 'Widgets' / 'SlideWidget.vala', 30 | 'Widgets' / 'PresenterView.vala', 31 | 'Widgets' / 'PresenterNotes.vala', 32 | 33 | 'Widgets' / 'ColorPicker' / 'ColorButton.vala', 34 | 'Widgets' / 'ColorPicker' / 'ColorChooser.vala', 35 | 'Widgets' / 'ColorPicker' / 'Gradient.vala', 36 | 'Widgets' / 'ColorPicker' / 'GradientEditor.vala', 37 | 'Widgets' / 'ColorPicker' / 'PickerWindow.vala', 38 | 39 | 'Widgets' / 'CanvasItems' / 'CanvasItem.vala', 40 | 'Widgets' / 'CanvasItems' / 'TextItem.vala', 41 | 'Widgets' / 'CanvasItems' / 'ColorItem.vala', 42 | 'Widgets' / 'CanvasItems' / 'ImageItem.vala', 43 | 'Widgets' / 'CanvasItems' / 'Grabber.vala', 44 | 45 | 'Widgets' / 'Toolbars' / 'CanvasBar.vala', 46 | 'Widgets' / 'Toolbars' / 'CommonBar.vala', 47 | 'Widgets' / 'Toolbars' / 'ImageBar.vala', 48 | 'Widgets' / 'Toolbars' / 'ShapeBar.vala', 49 | 'Widgets' / 'Toolbars' / 'TextBar.vala', 50 | 'Widgets' / 'Toolbars' / 'Toolbar.vala', 51 | 52 | 'Widgets' / 'Library' / 'LibraryItem.vala', 53 | 'Widgets' / 'Library' / 'Library.vala', 54 | 55 | # LibGamepad 56 | 'Services' / 'libgamepad' / 'libgamepad.vala', 57 | 'Services' / 'libgamepad' / 'gamepad-monitor.vala', 58 | 'Services' / 'libgamepad' / 'gamepad.vala', 59 | 'Services' / 'libgamepad' / 'helpers.vala', 60 | 'Services' / 'libgamepad' / 'input-type.vala', 61 | 'Services' / 'libgamepad' / 'raw-gamepad-interface.vala', 62 | 'Services' / 'libgamepad' / 'raw-gamepad-monitor-interface.vala', 63 | 'Services' / 'libgamepad' / 'standard-gamepad-axis.vala', 64 | 'Services' / 'libgamepad' / 'standard-gamepad-button.vala', 65 | 66 | 'Services' / 'libgamepad' / 'drivers' / 'linux' / 'guid-helpers.vala', 67 | 'Services' / 'libgamepad' / 'drivers' / 'linux' / 'raw-gamepad.vala', 68 | 'Services' / 'libgamepad' / 'drivers' / 'linux' / 'raw-gamepad-monitor.vala' 69 | ] 70 | 71 | deps = [ 72 | evdev_dep, 73 | gee_dep, 74 | glib_dep, 75 | gobject_dep, 76 | granite_dep, 77 | gtk_dep, 78 | gudev_dep, 79 | json_glib_dep, 80 | soup_dep, 81 | ] 82 | 83 | executable( 84 | meson.project_name(), 85 | config_file, 86 | gresource, 87 | vala_files, 88 | dependencies: deps, 89 | install: true 90 | ) 91 | 92 | subdir('Tests') 93 | -------------------------------------------------------------------------------- /vapi/libevdev.vapi: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Megh Parikh 3 | * 4 | * This file is part of LibGamepad. 5 | * 6 | * LibGamepad is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * LibGamepad is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with Foobar. If not, see . 18 | */ 19 | 20 | [CCode (cheader_filename = "libevdev/libevdev.h")] 21 | namespace Libevdev { 22 | 23 | [CCode (cname = "libevdev_read_flag", cprefix = "LIBEVDEV_READ_FLAG_", has_type_id = false)] 24 | [Flags] 25 | public enum ReadFlag { 26 | SYNC, 27 | NORMAL, 28 | FORCE_SYNC, 29 | BLOCKING 30 | } 31 | 32 | [CCode (cname = "struct libevdev", cprefix = "libevdev_", free_function = "libevdev_free")] 33 | [Compact] 34 | public class Evdev { 35 | [CCode (cname = "libevdev_new")] 36 | public Evdev (); 37 | 38 | public int get_fd (); 39 | public int set_fd (int fd); 40 | 41 | public string name { get; set; } 42 | 43 | public int id_bustype { get; set; } 44 | public int id_vendor { get; set; } 45 | public int id_product { get; set; } 46 | public int id_version { get; set; } 47 | 48 | public unowned Linux.Input.AbsInfo? get_abs_info (uint code); 49 | public bool has_event_code (uint type, uint code); 50 | public int has_event_pending (); 51 | public int next_event (uint flags, out Linux.Input.Event ev); 52 | 53 | public static unowned string event_code_get_name(uint type, uint code); 54 | } 55 | 56 | } 57 | --------------------------------------------------------------------------------